diff --git a/src/providers/registry/entries-extended.ts b/src/providers/registry/entries-extended.ts index 2a92a9b832..5cea61a84f 100644 --- a/src/providers/registry/entries-extended.ts +++ b/src/providers/registry/entries-extended.ts @@ -110,6 +110,13 @@ export const PROVIDER_REGISTRY_EXTENDED: readonly ProviderRegistryEntry[] = [ // Baseten says models outside its reasoning table do not support reasoning. Keep // unknown/new live slugs conservative until an official-docs registry refresh proves it. reasoningEfforts: [], + // `text.verbosity` is an OpenAI Responses parameter. Baseten documents its Model + // APIs as Chat Completions compatible, so there is nothing on that wire for it to + // become, and a routed row must not inherit the Codex template's verbosity picker + // (#4630: Codex sent `text: { verbosity: "low" }` and the turn 400'd before any + // model output). Provider-wide rather than per-model because this catalog is live- + // discovered: a slug that arrives tomorrow supports it no more than the seeded ones. + supportsVerbosity: false, modelReasoningEfforts: BASETEN_MODEL_REASONING_EFFORTS, modelReasoningEffortMap: BASETEN_MODEL_REASONING_EFFORT_MAP, modelDefaultReasoningEfforts: BASETEN_MODEL_DEFAULT_REASONING_EFFORTS, diff --git a/tests/codex-integration/catalog-verbosity-default.test.ts b/tests/codex-integration/catalog-verbosity-default.test.ts index 1ed5c8f164..a3224b5b3c 100644 --- a/tests/codex-integration/catalog-verbosity-default.test.ts +++ b/tests/codex-integration/catalog-verbosity-default.test.ts @@ -61,6 +61,60 @@ describe("catalog — default_verbosity is dropped when verbosity is unsupported expect(kiro?.default_verbosity).toBeUndefined(); }); + test("GREEN: a Baseten routed row opts out, defaults included", async () => { + // #4630: Baseten Model APIs are Chat Completions only, so `text.verbosity` + // — a Responses-only parameter — has nowhere to land. Advertising it made + // Codex send `text: { verbosity: "low" }` and the turn 400 before any model + // output. The opt-out is provider-wide because Baseten's catalog is live- + // discovered: a slug that arrives tomorrow supports it no more than this one. + const models = await gatherRoutedModels({ + providers: { + baseten: { + adapter: "openai-chat", + baseUrl: "https://inference.baseten.co/v1", + authMode: "key", + liveModels: false, + models: ["deepseek-ai/DeepSeek-V4.1-Flash"], + }, + }, + }); + const entries = buildCatalogEntries(null, [], models); + const baseten = entries.find(e => e.slug?.startsWith("baseten/")); + + expect(baseten?.support_verbosity).toBe(false); + expect(baseten?.default_verbosity).toBeUndefined(); + }); + + test("GREEN: a slug that only live discovery knows about opts out too", async () => { + // The opt-out is provider-wide precisely because baseten is `liveModels: true`: + // a pinned per-model map would leave tomorrow's discovered id advertising the + // control again. Seeding NO static models and letting discovery supply the slug + // is what makes that claim testable rather than a comment (raised in review of + // #4660 by @coderabbitai and @lidge-jun). + globalThis.fetch = (async (input: RequestInfo | URL) => { + if (!String(input).includes("/models")) return new Response(null, { status: 404 }); + return Response.json({ data: [{ id: "deepseek-ai/DeepSeek-V4.1-Flash" }] }); + }) as typeof fetch; + + const models = await gatherRoutedModels({ + providers: { + baseten: { + adapter: "openai-chat", + baseUrl: "https://inference.baseten.co/v1", + authMode: "key", + apiKey: "test-key", + liveModels: true, + }, + }, + }); + const entries = buildCatalogEntries(null, [], models); + const baseten = entries.find(e => e.slug?.startsWith("baseten/")); + + expect(baseten, "live discovery must have produced a routed baseten row").toBeDefined(); + expect(baseten?.support_verbosity).toBe(false); + expect(baseten?.default_verbosity).toBeUndefined(); + }); + test("CONTROL: rows that never declare a capability keep the permissive default", async () => { const models = await gatherRoutedModels({ providers: {