Skip to content

Commit 49d2dd8

Browse files
authored
fix(provider): honor reasoning option semantics (anomalyco#37519)
1 parent 0df2f62 commit 49d2dd8

3 files changed

Lines changed: 30 additions & 11 deletions

File tree

packages/opencode/src/provider/transform.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,7 +1586,7 @@ export function reasoningVariants(model: ModelsDev.Model, target: Provider.Model
15861586
if (options.length === 0) return {}
15871587

15881588
const effort = options.find((option) => option.type === "effort")
1589-
if (effort) return nonEmptyVariants(effortVariants(target, effort.values))
1589+
if (effort) return effortVariants(target, effort.values)
15901590

15911591
const toggle = options.some((option) => option.type === "toggle")
15921592
const budget = options.find((option) => option.type === "budget_tokens")
@@ -1651,7 +1651,7 @@ function reasoningEffort(model: Provider.Model, effort: string) {
16511651
return { reasoning: { effort } }
16521652
case "@ai-sdk/anthropic":
16531653
case "@ai-sdk/google-vertex/anthropic":
1654-
return anthropicEffort(model, effort)
1654+
return anthropicEffort(model, effort) ?? { effort }
16551655
case "@ai-sdk/google":
16561656
case "@ai-sdk/google-vertex":
16571657
return { thinkingConfig: { includeThoughts: true, thinkingLevel: effort } }

packages/opencode/test/provider/provider.test.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1477,7 +1477,7 @@ test("models.dev normalization fills required response fields", () => {
14771477
expect(model.release_date).toBe("")
14781478
})
14791479

1480-
test("models.dev reasoning options replace generated variants and unsupported options fall back", () => {
1480+
test("models.dev reasoning options replace generated variants and unsupported toggles fall back", () => {
14811481
const provider = {
14821482
id: "reasoning",
14831483
name: "Reasoning",
@@ -1514,6 +1514,14 @@ test("models.dev reasoning options replace generated variants and unsupported op
15141514
limit: { context: 128_000, output: 64_000 },
15151515
experimental: { modes: { fast: {} } },
15161516
},
1517+
anthropicCompatible: {
1518+
id: "k3",
1519+
name: "Anthropic Compatible",
1520+
reasoning: true,
1521+
reasoning_options: [{ type: "effort", values: ["max"] }],
1522+
provider: { npm: "@ai-sdk/anthropic" },
1523+
limit: { context: 1_048_576, output: 131_072 },
1524+
},
15171525
},
15181526
} as unknown as ModelsDev.Provider
15191527

@@ -1530,6 +1538,7 @@ test("models.dev reasoning options replace generated variants and unsupported op
15301538
expect(models.override.variants).toEqual({
15311539
high: { thinkingConfig: { includeThoughts: true, thinkingLevel: "high" } },
15321540
})
1541+
expect(models.anthropicCompatible.variants).toEqual({ max: { effort: "max" } })
15331542
expect(models["gemini-3-pro-fast"].variants).toEqual(models.override.variants)
15341543
})
15351544

packages/opencode/test/provider/transform.test.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3103,13 +3103,20 @@ describe("ProviderTransform.reasoningVariants", () => {
31033103
).toEqual({ high: { effort: "high" } })
31043104
})
31053105

3106-
test("leaves legacy Anthropic effort options to budget fallback", () => {
3106+
test("uses explicit effort metadata for Anthropic-compatible models", () => {
31073107
expect(
31083108
ProviderTransform.reasoningVariants(
31093109
model([{ type: "effort", values: ["high"] }]),
31103110
target("@ai-sdk/anthropic", "claude-sonnet-4"),
31113111
),
3112-
).toBeUndefined()
3112+
).toEqual({ high: { effort: "high" } })
3113+
3114+
expect(
3115+
ProviderTransform.reasoningVariants(
3116+
model([{ type: "effort", values: ["max"] }]),
3117+
target("@ai-sdk/anthropic", "k3"),
3118+
),
3119+
).toEqual({ max: { effort: "max" } })
31133120
})
31143121

31153122
test("uses adaptive reasoning config for Anthropic models on Bedrock", () => {
@@ -3129,13 +3136,13 @@ describe("ProviderTransform.reasoningVariants", () => {
31293136
})
31303137
})
31313138

3132-
test("leaves legacy Anthropic Bedrock effort options to budget fallback", () => {
3139+
test("does not replace unsupported Anthropic Bedrock effort options with token budgets", () => {
31333140
expect(
31343141
ProviderTransform.reasoningVariants(
31353142
model([{ type: "effort", values: ["high"] }]),
31363143
target("@ai-sdk/amazon-bedrock", "anthropic.claude-sonnet-4-v1:0"),
31373144
),
3138-
).toBeUndefined()
3145+
).toEqual({})
31393146
})
31403147

31413148
test.each([
@@ -3256,10 +3263,13 @@ describe("ProviderTransform.reasoningVariants", () => {
32563263
})
32573264
})
32583265

3259-
test("leaves unsupported options for heuristic fallback", () => {
3266+
test("does not replace unsupported effort options with heuristic variants", () => {
32603267
expect(
32613268
ProviderTransform.reasoningVariants(model([{ type: "effort", values: ["high"] }]), target("@ai-sdk/perplexity")),
3262-
).toBeUndefined()
3269+
).toEqual({})
3270+
})
3271+
3272+
test("leaves unsupported toggle options for heuristic fallback", () => {
32633273
expect(ProviderTransform.reasoningVariants(model([{ type: "toggle" }]), target("@ai-sdk/openai"))).toBeUndefined()
32643274
})
32653275

@@ -3275,15 +3285,15 @@ describe("ProviderTransform.reasoningVariants", () => {
32753285
})
32763286
expect(
32773287
ProviderTransform.reasoningVariants(effort, target("@ai-sdk/github-copilot", "gemini-3-pro")),
3278-
).toBeUndefined()
3288+
).toEqual({})
32793289
})
32803290

32813291
test.each(["@ai-sdk/cohere", "@ai-sdk/perplexity", "@ai-sdk/vercel", "@ai-sdk/alibaba", "gitlab-ai-provider"])(
32823292
"does not invent effort controls for %s",
32833293
(npm) => {
32843294
expect(
32853295
ProviderTransform.reasoningVariants(model([{ type: "effort", values: ["high"] }]), target(npm)),
3286-
).toBeUndefined()
3296+
).toEqual({})
32873297
},
32883298
)
32893299
})

0 commit comments

Comments
 (0)