fix(provider): derive variants from reasoning metadata (#36624)

This commit is contained in:
Aiden Cline
2026-07-13 01:21:59 -05:00
committed by GitHub
parent f47684787a
commit a8062ea314
8 changed files with 534 additions and 175 deletions
@@ -562,6 +562,45 @@ it.instance(
},
)
it.instance(
"model config preserves explicitly empty models.dev variants",
Effect.gen(function* () {
yield* set("OPENAI_API_KEY", "test-api-key")
const providers = yield* list
const model = providers[ProviderV2.ID.openai].models["custom-gpt-chat"]
expect(model.name).toBe("Custom GPT Chat")
expect(model.variants).toEqual({})
}),
{
config: {
provider: {
openai: { models: { "custom-gpt-chat": { id: "gpt-5-chat-latest", name: "Custom GPT Chat" } } },
},
},
},
)
it.instance(
"model config regenerates variants when overriding the provider package",
Effect.gen(function* () {
yield* set("ANTHROPIC_API_KEY", "test-api-key")
const providers = yield* list
const model = providers[ProviderV2.ID.anthropic].models["claude-sonnet-4-6"]
expect(model.variants?.low).toEqual({ reasoningEffort: "low" })
expect(model.variants?.max).toBeUndefined()
}),
{
config: {
provider: {
anthropic: {
npm: "@ai-sdk/openai-compatible",
models: { "claude-sonnet-4-6": { name: "Claude via OpenAI" } },
},
},
},
},
)
it.instance(
"disabled_providers prevents loading even with env var",
Effect.gen(function* () {
@@ -1426,52 +1465,60 @@ test("models.dev normalization fills required response fields", () => {
expect(model.release_date).toBe("")
})
test("models.dev reasoning options normalize to known shapes", () => {
const provider = Provider.fromModelsDevProvider({
id: "openai",
name: "OpenAI",
test("models.dev reasoning options replace generated variants and unsupported options fall back", () => {
const provider = {
id: "reasoning",
name: "Reasoning",
env: [],
npm: "@ai-sdk/openai",
models: {
reasoner: {
id: "reasoner",
name: "Reasoner",
reasoning: true,
reasoning_options: [
{ type: "future_control", value: true },
{ type: "effort", values: ["high", null, 42] },
{ type: "toggle" },
{ type: "budget_tokens", min: 1024, max: "invalid" },
],
limit: { context: 128_000, output: 16_000 },
},
},
} as unknown as ModelsDev.Provider)
expect(provider.models.reasoner.reasoning_options).toEqual([
{ type: "effort", values: ["high", null] },
{ type: "toggle" },
{ type: "budget_tokens", min: 1024 },
])
})
test("models.dev models without reasoning options normalize to an empty list", () => {
const provider = Provider.fromModelsDevProvider({
id: "openai",
name: "OpenAI",
env: [],
npm: "@ai-sdk/openai",
models: {
reasoner: {
explicit: {
id: "gpt-5.4",
name: "Reasoner",
name: "Explicit",
reasoning: true,
limit: { context: 128_000, output: 16_000 },
reasoning_options: [{ type: "effort", values: ["low"] }],
limit: { context: 128_000, output: 64_000 },
},
empty: {
id: "gpt-5.4",
name: "Empty",
reasoning: true,
reasoning_options: [],
limit: { context: 128_000, output: 64_000 },
},
fallback: {
id: "gpt-5.4",
name: "Fallback",
reasoning: true,
reasoning_options: [{ type: "toggle" }],
limit: { context: 128_000, output: 64_000 },
},
override: {
id: "gemini-3-pro",
name: "Override",
reasoning: true,
reasoning_options: [{ type: "effort", values: ["high"] }],
provider: { npm: "@ai-sdk/google" },
limit: { context: 128_000, output: 64_000 },
experimental: { modes: { fast: {} } },
},
},
} as unknown as ModelsDev.Provider)
} as unknown as ModelsDev.Provider
expect(provider.models.reasoner.reasoning_options).toEqual([])
const models = Provider.fromModelsDevProvider(provider).models
expect(models.explicit.variants).toEqual({
low: {
reasoningEffort: "low",
reasoningSummary: "auto",
include: ["reasoning.encrypted_content"],
},
})
expect(models.empty.variants).toEqual({})
expect(Object.keys(models.fallback.variants ?? {})).toEqual(["none", "low", "medium", "high", "xhigh"])
expect(models.override.variants).toEqual({
high: { thinkingConfig: { includeThoughts: true, thinkingLevel: "high" } },
})
expect(models["gemini-3-pro-fast"].variants).toEqual(models.override.variants)
})
test("public provider info omits invalid models", () => {