Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion docs-site/src/content/docs/reference/adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,10 @@ configuration that names the old id is rewritten at startup.
with manual protobuf framing in `devin/cloud-direct/wire.ts`; the ordinary `buildRequest` /
`parseStream` path is disabled.
- Live model discovery via `GetCascadeModelConfigs`; the static seed is filtered against the
account's live roster so models not on the plan drop out instead of failing at request time.
account's live roster so models not on the plan drop out instead of failing at request time. Each
model's effort control uses the variants exposed by that account; the static fallback ladder is
used only before discovery or when discovery fails. An explicit per-model ladder remains an
operator override.
- Tool definitions are encoded in the request and tool-call events are decoded from the response
stream. Cognition enforces a per-tool-description length limit (6,998 chars) and an exact-phrase
blocklist; the adapter sanitizes known triggers and truncates over-long descriptions before
Expand Down
51 changes: 40 additions & 11 deletions src/codex/catalog/provider-fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,37 @@ export function applyProviderConfigHints(
};
}

/** Build a Devin row without letting its degraded provider fallback replace live account evidence. */
export function buildDevinLiveCatalogEntry(
name: string,
prov: OcxProviderConfig,
id: string,
liveWindow: number | undefined,
liveEfforts: string[] | undefined,
providerCap?: number,
metadataModelIdCaseFold?: boolean,
effectiveAlias?: string | null,
): CatalogModel {
const hinted = catalogHintsFromProviderConfig(
name,
prov,
id,
providerCap,
metadataModelIdCaseFold,
effectiveAlias,
);
const modelEfforts = modelRecordValue(prov.modelReasoningEfforts, id);
return {
id,
provider: name,
...(liveWindow ? { contextWindow: liveWindow } : {}),
...hinted,
// A per-model setting is an operator override. The provider-wide value is
// only a degraded-mode fallback, so live account evidence supersedes it.
...(liveEfforts?.length && modelEfforts === undefined ? { reasoningEfforts: liveEfforts } : {}),
Comment on lines +904 to +906

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clear the fallback when discovery exposes no ladder

When a successful account catalog exposes zero or only one reasoning variant for a base model, fetchDevinUsableModels intentionally omits that model from efforts because there is no useful control. Here, an undefined/empty liveEfforts skips the final spread and leaves hinted.reasoningEfforts set to the provider-wide fallback, so the live result advertises choices the account did not expose. Successful discovery should explicitly suppress the fallback for this case.

Useful? React with 👍 / 👎.

Comment on lines +898 to +906

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor noReasoningModels before applying live efforts

Checking only modelReasoningEfforts misses the existing per-model noReasoningModels override: catalogHintsFromProviderConfig correctly produces reasoningEfforts: [] for such a model, but this final spread replaces it with the discovered ladder. A Devin model explicitly configured to reject reasoning therefore regains an effort picker after successful discovery; the previous hints-last ordering preserved that configuration. Treat this explicit disable as authoritative as well.

AGENTS.md reference: src/AGENTS.md:L10-L10

Useful? React with 👍 / 👎.

};
}

export function catalogHintsFromProviderConfig(
name: string,
prov: OcxProviderConfig,
Expand Down Expand Up @@ -1735,18 +1766,16 @@ async function fetchProviderModelsWithAuth(
// chose.
const result = liveResult.models.map((id) => {
const liveWindow = liveResult.contextWindows[id];
return {
return buildDevinLiveCatalogEntry(
name,
prov,
id,
provider: name,
...(liveWindow ? { contextWindow: liveWindow } : {}),
// The account catalog names the effort variants each base model has, so
// its ladder is measured rather than assumed. Without this the entry
// inherits the generic routed ladder and offers rungs the model rounds
// away, and every client that keys an effort control off this field —
// the Pi-shaped exports — renders no control at all.
...(liveResult.efforts[id]?.length ? { reasoningEfforts: liveResult.efforts[id] } : {}),
...catalogHintsFromProviderConfig(name, prov, id, contextCap, metadataModelIdCaseFold, captured.effectiveAlias),
} as CatalogModel;
liveWindow,
liveResult.efforts[id],
Comment on lines +1769 to +1774

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve live ladders on cached Devin reads

When a later catalog gather hits cachedDevin, the cached rows are passed through applyConfigHintsToCachedModels, whose configuredReasoningEfforts call reapplies prov.reasoningEfforts and overwrites the account ladder stored by this new builder. Consequently, only the first return after discovery preserves the measured rungs; ordinary reads during the cache TTL advertise the degraded provider-wide ladder again. The cached path needs the same Devin-specific precedence handling.

Useful? React with 👍 / 👎.

contextCap,
metadataModelIdCaseFold,
captured.effectiveAlias,
);
});
const forCache = withConfiguredRetention(result, { retainComboTargets: false });
if (!setCached(name, forCache, Date.now(), cacheGeneration)) {
Expand Down
4 changes: 4 additions & 0 deletions structure/catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,3 +336,7 @@ Exact [model input declarations](config.md#explicit-per-model-capability-declara
## Renamed destination reasoning metadata

`src/providers/derive.ts` fills missing reasoning tables for renamed providers accepted by the existing fixed-key destination matcher. Model entries are cloned and explicit user entries (including empty arrays) win. Provider-wide effort defaults fill only when undefined; Command Code unknown models therefore keep the registry's empty picker policy unless overridden. Identity, transport and other capability axes are unchanged. The gathered row drives client exports; this metadata contract does not prove arbitrary gateway routing.

## Devin live effort authority

`src/codex/catalog/provider-fetch.ts` treats the reasoning ladder measured from an authenticated Devin account catalog as authoritative over the registry's provider-wide degraded-mode fallback. An explicit `modelReasoningEfforts` entry remains authoritative over discovery. Static model-specific and provider-wide ladders continue to supply signed-out and failed-discovery rows only.
2 changes: 2 additions & 0 deletions structure/codex-home.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,5 @@ Pool quota producers and account commands follow the [bounded raw-observation co
The account history response can include a [low-confidence effective capacity estimate](providers/openai-tiers.md#observed-effective-token-capacity); usage normalization retains local-answer provenance so local responses cannot supply samples.

Codex pool settings and their consumers follow the [reset-first ordering contract](providers/openai-tiers.md#reset-first-account-ordering), including independent-quota fallback and preserved affinity.

Materialized Devin rows preserve the [live account effort ladder](catalog.md#devin-live-effort-authority) rather than replacing it with degraded-mode catalog defaults.
2 changes: 2 additions & 0 deletions structure/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,5 @@ Display-name validation retains prototype-shaped model IDs as data; reviewer-tar
`modelCapabilities` on `src/types/provider.ts` stores exact model-ID entries with optional inputModalities, contextTier and video.processing axes. `src/config/provider-validation.ts` strictly validates writes and merges PATCH axes without sharing live objects; null map/model/axis/processing tombstones delete, while empty PATCH objects do nothing. Complete POST/PUT replacements reject tombstones. File reads retain valid axes; malformed explicit modalities restrict to text with a diagnostic. The two catalog writers receive explicit config and gather fingerprints include the map. This storage contract alone does not activate a context tier, advertise a larger window or enable video processing.

The text-only consumer reads exact inputModalities declarations before legacy hints. CLI add/edit `--text-only` targets one model and preserves sibling declarations; `src/vision/eligibility.ts` routes declared text-only models into existing image-description or explicit-omission handling. Positive routed image declarations override stale candidate metadata, while native catalog authority retains its existing legacy policy.

For Devin, explicit per-model effort configuration retains precedence while provider-wide defaults yield to [live account evidence](catalog.md#devin-live-effort-authority).
2 changes: 1 addition & 1 deletion structure/gui-and-management-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ Live sideband admission and its bounded upstream handshake follow the [runtime c
Dashboard overview polling observes authorization failures independently of stalled or rejected peer requests, cancels remaining child requests after a decisive result, and exposes resource-level deadline failures without rewriting them as authentication failures.

The [explicit model-capability contract](config.md#explicit-per-model-capability-declarations) preserves operator declarations through provider storage and catalog capture; it does not infer upstream capability or change this surface's routing behavior.

Exact [model input declarations](config.md#explicit-per-model-capability-declarations) now feed text-only eligibility and catalog hints; existing image-description/omission handling consumes them before the main upstream send.

The raw provider editor round-trips `autoReviewModel` and `autoReviewModelOverrides` through editor-owned DTO fields. POST/PATCH/PUT share validation; PUT copies schema-normalized values into the persisted and live candidate before adoption. Canonical `openai` rejects these fields, including clear forms. Field-masked writes (PATCH, editor PUT, reload) pin every registry-seed key and ignore operator overlays the seed never defines, most commonly `selectedModels`; POST keeps the exact-key comparison. Canonical `openai` still rejects `allowPrivateNetwork`, which must not short-circuit destination DNS checks on the ChatGPT forward row. Existing authentication, origin checks and stale-baseline protection still govern the writes. See [reviewer projection](catalog.md#provider-scoped-approval-reviewer).
Management and exported client model rows display Devin's [live account effort ladder](catalog.md#devin-live-effort-authority) when discovery succeeds.
2 changes: 2 additions & 0 deletions structure/ops/docs-and-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,3 +375,5 @@ Exact [model input declarations](../config.md#explicit-per-model-capability-decl
Provider-scoped approval reviewer settings are projected by the [catalog owner](../catalog.md#provider-scoped-approval-reviewer); this surface retains its existing routing, transport and account-selection behavior.

Renamed fixed-key providers receive [missing reasoning metadata](../catalog.md#renamed-destination-reasoning-metadata) during derivation; explicit per-model entries and provider defaults retain precedence.

Catalog publication carries Devin's [live account effort ladder](../catalog.md#devin-live-effort-authority) through generated client artifacts.
2 changes: 2 additions & 0 deletions structure/providers/openai-tiers.md
Original file line number Diff line number Diff line change
Expand Up @@ -518,3 +518,5 @@ The history read API reports a median effective token estimate and interval samp
Live bindings obey the existing cache-affinity release policy: with `pool.cacheAffinity`, threshold crossing alone retains a healthy account. Manual preference, scoped health and shared-cursor guards remain authoritative. Independent `spark`/`reserve` quota scopes resolve reset-first to existing quota selection because shared reset timestamps do not describe those windows. The configured value stays unchanged.

The Codex parser in `src/oauth/pool-kernel.ts` is reexported by the compatibility facade and used by both `/api/pool/settings` and the legacy Codex settings route. Generic and Anthropic parsers reject reset-first. The dashboard offers it only for Codex; API, CLI and translated guides preserve the same contract.

Non-OpenAI Devin catalog rows use the shared [live effort authority](../catalog.md#devin-live-effort-authority); this does not change OpenAI tier or pool selection.
2 changes: 2 additions & 0 deletions structure/runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,3 +350,5 @@ Exact [model input declarations](config.md#explicit-per-model-capability-declara
Provider-scoped approval reviewer settings are projected by the [catalog owner](catalog.md#provider-scoped-approval-reviewer); this surface retains its existing routing, transport and account-selection behavior.

Renamed fixed-key providers receive [missing reasoning metadata](catalog.md#renamed-destination-reasoning-metadata) during derivation; explicit per-model entries and provider defaults retain precedence.

Devin catalog routing follows the [live effort authority](catalog.md#devin-live-effort-authority); request transport behavior is unchanged.
2 changes: 2 additions & 0 deletions structure/subagents.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,3 +371,5 @@ Exact [model input declarations](config.md#explicit-per-model-capability-declara
Provider-scoped approval reviewer settings are projected by the [catalog owner](catalog.md#provider-scoped-approval-reviewer); this surface retains its existing routing, transport and account-selection behavior.

Renamed fixed-key providers receive [missing reasoning metadata](catalog.md#renamed-destination-reasoning-metadata) during derivation; explicit per-model entries and provider defaults retain precedence.

Devin subagent choices consume the final [live account effort ladder](catalog.md#devin-live-effort-authority), subject to explicit per-model configuration.
31 changes: 31 additions & 0 deletions tests/providers/devin-effort-ladder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
sortDevinRungs,
} from "../../src/adapters/devin/live-models";
import { PROVIDER_REGISTRY } from "../../src/providers/registry";
import { providerConfigSeed } from "../../src/providers/derive";
import { buildDevinLiveCatalogEntry } from "../../src/codex/catalog/provider-fetch";

const devinRow = () => PROVIDER_REGISTRY.find(row => row.id === "devin")!;

Expand Down Expand Up @@ -39,6 +41,35 @@ describe("devin reasoning rungs come from the catalog suffixes", () => {
});

describe("devin advertises a ladder instead of inheriting the generic one", () => {
test("live account rungs supersede the degraded provider fallback", () => {
const provider = providerConfigSeed(devinRow());
const model = buildDevinLiveCatalogEntry(
"devin",
provider,
"account-model",
200_000,
["low", "high"],
);

expect(model.reasoningEfforts).toEqual(["low", "high"]);
});

test("an explicit per-model ladder still overrides live account rungs", () => {
const provider = {
...providerConfigSeed(devinRow()),
modelReasoningEfforts: { "account-model": ["medium", "max"] },
};
const model = buildDevinLiveCatalogEntry(
"devin",
provider,
"account-model",
undefined,
["low", "high"],
);

expect(model.reasoningEfforts).toEqual(["medium", "max"]);
});

test("the provider row carries both fields", () => {
// modelReasoningEfforts drives the Codex picker; reasoningEfforts is what the
// Pi-shaped client exports read. Without them the row inherited the routed
Expand Down
Loading