fix(core): derive models.dev reasoning variants (#34726)

This commit is contained in:
Aiden Cline 2026-07-02 00:23:46 -05:00 committed by GitHub
commit 140224b0fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 457 additions and 119 deletions

View file

@ -0,0 +1,67 @@
{
"openai": {
"id": "openai",
"name": "OpenAI",
"env": ["OPENAI_API_KEY"],
"npm": "@ai-sdk/openai",
"api": "https://api.openai.com/v1",
"models": {
"gpt-reasoning": {
"id": "gpt-reasoning",
"name": "GPT Reasoning",
"release_date": "2026-01-01",
"attachment": false,
"reasoning": true,
"reasoning_options": [
{ "type": "effort", "values": ["low", "high"] },
{ "type": "budget_tokens", "min": 1024, "max": 64000 },
{ "type": "toggle" }
],
"temperature": true,
"tool_call": true,
"limit": { "context": 128000, "output": 8192 },
"experimental": {
"modes": {
"high": {
"provider": {
"headers": { "x-mode": "high" },
"body": { "service_tier": "priority" }
}
}
}
}
}
}
},
"anthropic": {
"id": "anthropic",
"name": "Anthropic",
"env": ["ANTHROPIC_API_KEY"],
"npm": "@ai-sdk/anthropic",
"api": "https://api.anthropic.com/v1",
"models": {
"claude-budget": {
"id": "claude-budget",
"name": "Claude Budget",
"release_date": "2026-01-01",
"attachment": false,
"reasoning": true,
"reasoning_options": [{ "type": "budget_tokens", "min": 1024, "max": 64000 }],
"temperature": true,
"tool_call": true,
"limit": { "context": 128000, "output": 8192 }
},
"claude-effort": {
"id": "claude-effort",
"name": "Claude Effort",
"release_date": "2026-01-01",
"attachment": false,
"reasoning": true,
"reasoning_options": [{ "type": "effort", "values": ["low"] }],
"temperature": true,
"tool_call": true,
"limit": { "context": 128000, "output": 8192 }
}
}
}
}

View file

@ -288,7 +288,7 @@ function providerInfo(value: ProviderV2.MutableInfo) {
return {
...value,
api: { ...value.api, settings: value.api.settings && { ...value.api.settings } },
request: { headers: { ...value.request.headers }, body: { ...value.request.body } },
request: { settings: { ...value.request.settings }, headers: { ...value.request.headers }, body: { ...value.request.body } },
}
}
@ -303,11 +303,13 @@ function modelInfo(value: ModelV2.Info | ModelV2.MutableInfo) {
},
request: {
...value.request,
settings: { ...value.request.settings },
headers: { ...value.request.headers },
body: { ...value.request.body },
},
variants: value.variants.map((variant) => ({
...variant,
settings: { ...variant.settings },
headers: { ...variant.headers },
body: { ...variant.body },
})),

View file

@ -168,14 +168,14 @@ describe("ModelsDevPlugin", () => {
),
)
it.effect("derives OpenAI reasoning variants from models.dev reasoning options", () =>
it.effect("converts reasoning options into settings variants", () =>
Effect.acquireUseRelease(
Effect.sync(() => {
const previous = {
path: Flag.OPENCODE_MODELS_PATH,
disabled: Flag.OPENCODE_DISABLE_MODELS_FETCH,
}
Flag.OPENCODE_MODELS_PATH = path.join(import.meta.dir, "fixtures", "models-dev.json")
Flag.OPENCODE_MODELS_PATH = path.join(import.meta.dir, "fixtures", "models-dev-reasoning.json")
Flag.OPENCODE_DISABLE_MODELS_FETCH = true
return previous
}),
@ -183,17 +183,6 @@ describe("ModelsDevPlugin", () => {
Effect.gen(function* () {
const catalog = yield* Catalog.Service
const integrations = yield* Integration.Service
yield* catalog.transform((catalog) => {
catalog.model.update(ProviderV2.ID.opencode, ModelV2.ID.make("gpt-5.5"), (model) => {
model.variants = [
{
id: ModelV2.VariantID.make("high"),
headers: { custom: "true" },
body: { custom: true },
},
]
})
})
yield* ModelsDevPlugin.effect(
host({
catalog: catalogHost(catalog),
@ -201,42 +190,67 @@ describe("ModelsDevPlugin", () => {
}),
)
expect((yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("gpt-5.5")))?.variants).toEqual([
{
id: ModelV2.VariantID.make("none"),
headers: {},
body: {
include: ["reasoning.encrypted_content"],
reasoning: { effort: "none", summary: "auto" },
},
},
expect.objectContaining({
id: "low",
body: {
include: ["reasoning.encrypted_content"],
reasoning: { effort: "low", summary: "auto" },
},
}),
expect.objectContaining({
id: "medium",
body: {
include: ["reasoning.encrypted_content"],
reasoning: { effort: "medium", summary: "auto" },
},
}),
expect.objectContaining({
id: "high",
headers: { custom: "true" },
body: { custom: true },
}),
expect.objectContaining({
id: "xhigh",
body: {
include: ["reasoning.encrypted_content"],
reasoning: { effort: "xhigh", summary: "auto" },
},
}),
const model = yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-reasoning"))
expect(model?.variants.map((variant) => variant.id)).toEqual([
ModelV2.VariantID.make("low"),
ModelV2.VariantID.make("high"),
])
expect(model?.variants).toContainEqual({
id: ModelV2.VariantID.make("low"),
settings: {
reasoningEffort: "low",
reasoningSummary: "auto",
include: ["reasoning.encrypted_content"],
},
headers: {},
body: {},
})
expect(model?.variants).toContainEqual({
id: ModelV2.VariantID.make("high"),
settings: {
reasoningEffort: "high",
reasoningSummary: "auto",
include: ["reasoning.encrypted_content"],
},
headers: {},
body: {},
})
const mode = yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-reasoning-high"))
expect(mode).toMatchObject({
id: "gpt-reasoning-high",
name: "GPT Reasoning High",
request: {
headers: { "x-mode": "high" },
body: { service_tier: "priority" },
},
})
expect(mode?.variants.map((variant) => variant.id)).toEqual([
ModelV2.VariantID.make("low"),
ModelV2.VariantID.make("high"),
])
const budgetModel = yield* catalog.model.get(ProviderV2.ID.anthropic, ModelV2.ID.make("claude-budget"))
expect(budgetModel?.variants).toContainEqual({
id: ModelV2.VariantID.make("high"),
settings: { thinking: { type: "enabled", budgetTokens: 16000 } },
headers: {},
body: {},
})
expect(budgetModel?.variants).toContainEqual({
id: ModelV2.VariantID.make("max"),
settings: { thinking: { type: "enabled", budgetTokens: 64000 } },
headers: {},
body: {},
})
const anthropicEffortModel = yield* catalog.model.get(ProviderV2.ID.anthropic, ModelV2.ID.make("claude-effort"))
expect(anthropicEffortModel?.variants).toContainEqual({
id: ModelV2.VariantID.make("low"),
settings: { thinking: { type: "adaptive", display: "summarized" }, effort: "low" },
headers: {},
body: {},
})
}).pipe(Effect.provide(AppNodeBuilder.build(ModelsDev.node))),
(previous) =>
Effect.sync(() => {
@ -245,5 +259,4 @@ describe("ModelsDevPlugin", () => {
}),
),
)
})

View file

@ -142,6 +142,7 @@ describe("OpencodePlugin", () => {
model.variants = [
{
id: ModelV2.VariantID.make("custom"),
settings: {},
headers: { "x-custom": "true" },
body: { custom: true },
},
@ -177,7 +178,7 @@ describe("OpencodePlugin", () => {
url: `${server.url.origin}/v1`,
},
})
expect(provider.request).toEqual({ headers: { "x-org-id": "org" }, body: { custom: "value" } })
expect(provider.request).toEqual({ settings: {}, headers: { "x-org-id": "org" }, body: { custom: "value" } })
expect(yield* (yield* Integration.Service).get(Integration.ID.make("remote"))).toBeUndefined()
const model = required(yield* catalog.model.get(ProviderV2.ID.make("remote"), ModelV2.ID.make("model")))
@ -192,11 +193,13 @@ describe("OpencodePlugin", () => {
expect(model.variants).toEqual([
{
id: ModelV2.VariantID.make("custom"),
settings: {},
headers: { "x-custom": "true" },
body: { custom: true },
},
{
id: ModelV2.VariantID.make("high"),
settings: {},
headers: {},
body: { temperature: 0.2 },
},
@ -359,6 +362,7 @@ describe("OpencodePlugin", () => {
...ProviderV2.Info.empty(ProviderV2.ID.opencode),
api: { type: "aisdk", package: "test-provider" },
request: {
settings: {},
headers: {},
body: { apiKey: "configured" },
},

View file

@ -37,8 +37,8 @@ describe("VariantPlugin", () => {
yield* VariantPlugin.Plugin.effect(host({ catalog: catalogHost(service) }))
expect((yield* service.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("glm-5.2")))?.variants).toEqual([
expect.objectContaining({ id: "high", body: { reasoning_effort: "high" } }),
expect.objectContaining({ id: "max", body: { reasoning_effort: "max" } }),
expect.objectContaining({ id: "high", settings: { reasoningEffort: "high" } }),
expect.objectContaining({ id: "max", settings: { reasoningEffort: "max" } }),
])
}),
)
@ -53,14 +53,14 @@ describe("VariantPlugin", () => {
type: "aisdk",
package: "@ai-sdk/openai-compatible",
}
model.variants = [{ id: ModelV2.VariantID.make("high"), headers: { custom: "true" }, body: {} }]
model.variants = [{ id: ModelV2.VariantID.make("high"), settings: {}, headers: { custom: "true" }, body: {} }]
})
})
yield* VariantPlugin.Plugin.effect(host({ catalog: catalogHost(service) }))
expect((yield* service.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("glm-5.2")))?.variants).toEqual([
expect.objectContaining({ id: "high", headers: { custom: "true" } }),
expect.objectContaining({ id: "max", body: { reasoning_effort: "max" } }),
expect.objectContaining({ id: "max", settings: { reasoningEffort: "max" } }),
])
}),
)