From 49a02e2b956f64554b28546d43238add5d74096c Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 30 Jun 2026 17:09:17 -0500 Subject: [PATCH] fix(provider): prefer gemini 2.5 reasoning budgets --- packages/opencode/src/provider/transform.ts | 41 ++++++++++++++----- .../opencode/test/provider/transform.test.ts | 23 ++++++++++- 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index 04d14248b1..f505a328f6 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -577,6 +577,14 @@ function googleThinkingLevelVariants() { ) } +function googleThinkingBudgetVariants(budget: ReasoningBudgetOption, model: Provider.Model) { + return reasoningBudgetVariants( + budget, + (thinkingBudget) => ({ thinkingConfig: { includeThoughts: true, thinkingBudget } }), + model.limit.output, + ) +} + function openAIReasoningEffortVariants() { return Object.fromEntries( OPENAI_EFFORTS.map((effort) => [ @@ -615,6 +623,25 @@ function reasoningBudgetVariants( } } +function gemini25BudgetVariants(model: Provider.Model, budget: ReasoningBudgetOption) { + // Gemini 2.5 uses numeric thinking budgets in the Google SDK; thinkingLevel is for Gemini 3. + if (!idIncludes(model, "gemini-2.5") && !idIncludes(model, "gemini-2-5")) return undefined + + switch (model.api.npm) { + case "@ai-sdk/gateway": + if (idIncludes(model, "google")) return googleThinkingBudgetVariants(budget, model) + return undefined + + case "@ai-sdk/google": + case "@ai-sdk/google-vertex": + return googleThinkingBudgetVariants(budget, model) + + case "@jerome-benoit/sap-ai-provider-v2": + return wrapInSapModelParams(googleThinkingBudgetVariants(budget, model)) + } + return undefined +} + function anthropicAdaptiveFromOptions(effort: ReasoningEffortOption) { return effort.values.includes("max") } @@ -732,6 +759,8 @@ function reasoningOptionVariants(model: Provider.Model): Record ({ thinkingConfig: { includeThoughts: true, thinkingBudget } }), - model.limit.output, - ) + return googleThinkingBudgetVariants(budget, model) } break @@ -787,11 +812,7 @@ function reasoningOptionVariants(model: Provider.Model): Record ({ thinkingConfig: { includeThoughts: true, thinkingBudget } }), - model.limit.output, - ) + return googleThinkingBudgetVariants(budget, model) case "@jerome-benoit/sap-ai-provider-v2": if (model.api.id.includes("anthropic")) { diff --git a/packages/opencode/test/provider/transform.test.ts b/packages/opencode/test/provider/transform.test.ts index d1230dd6e7..62e8074d0a 100644 --- a/packages/opencode/test/provider/transform.test.ts +++ b/packages/opencode/test/provider/transform.test.ts @@ -3220,7 +3220,10 @@ describe("ProviderTransform.variants", () => { url: "https://gateway.ai", npm: "@ai-sdk/gateway", }, - reasoning_options: [{ type: "budget_tokens", min: 128, max: 32768 }], + reasoning_options: [ + { type: "effort", values: ["minimal", "low", "medium", "high"] }, + { type: "budget_tokens", min: 128, max: 32768 }, + ], }), ) expect(Object.keys(result)).toEqual(["high", "max"]) @@ -3769,7 +3772,10 @@ describe("ProviderTransform.variants", () => { npm: provider.name, }, reasoning_options: testCase.expectedMax - ? [{ type: "budget_tokens", max: testCase.expectedMax.thinkingConfig.thinkingBudget }] + ? [ + { type: "effort", values: ["minimal", "low", "medium", "high"] }, + { type: "budget_tokens", max: testCase.expectedMax.thinkingConfig.thinkingBudget }, + ] : [{ type: "effort", values: testCase.efforts }], }), ) @@ -3866,6 +3872,19 @@ describe("ProviderTransform.variants", () => { }, }) }) + + test("uses reasoning_options budget tokens for Gemini 2.5 variants", () => { + const result = ProviderTransform.variants( + sapModel("gemini-2.5-pro", [ + { type: "effort", values: ["minimal", "low", "medium", "high"] }, + { type: "budget_tokens", min: 128, max: 32768 }, + ]), + ) + expect(result).toEqual({ + high: { modelParams: { thinkingConfig: { includeThoughts: true, thinkingBudget: 16_000 } } }, + max: { modelParams: { thinkingConfig: { includeThoughts: true, thinkingBudget: 32_768 } } }, + }) + }) }) describe("ai-gateway-provider (cloudflare-ai-gateway)", () => {