From 6a9f606b53b7086fe1d8da5729f9e7f1315bdbd5 Mon Sep 17 00:00:00 2001 From: Shariq Riaz Date: Thu, 5 Jun 2025 20:49:16 +0500 Subject: [PATCH 01/13] feat: add gemini-2.5-pro-preview-06-05 to Gemini and Vertex providers and UI, identical to 05-06 --- packages/types/src/providers/gemini.ts | 24 +++++++++++++++++++ packages/types/src/providers/vertex.ts | 8 +++++++ .../src/components/settings/ModelInfoView.tsx | 3 ++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/packages/types/src/providers/gemini.ts b/packages/types/src/providers/gemini.ts index 2ddf594704..09e1eb5077 100644 --- a/packages/types/src/providers/gemini.ts +++ b/packages/types/src/providers/gemini.ts @@ -104,6 +104,30 @@ export const geminiModels = { }, ], }, + "gemini-2.5-pro-preview-06-05": { + maxTokens: 65_535, + contextWindow: 1_048_576, + supportsImages: true, + supportsPromptCache: true, + inputPrice: 2.5, // This is the pricing for prompts above 200k tokens. + outputPrice: 15, + cacheReadsPrice: 0.625, + cacheWritesPrice: 4.5, + tiers: [ + { + contextWindow: 200_000, + inputPrice: 1.25, + outputPrice: 10, + cacheReadsPrice: 0.31, + }, + { + contextWindow: Infinity, + inputPrice: 2.5, + outputPrice: 15, + cacheReadsPrice: 0.625, + }, + ], + }, "gemini-2.0-flash-001": { maxTokens: 8192, contextWindow: 1_048_576, diff --git a/packages/types/src/providers/vertex.ts b/packages/types/src/providers/vertex.ts index 11aa1aaa4a..e0169bc008 100644 --- a/packages/types/src/providers/vertex.ts +++ b/packages/types/src/providers/vertex.ts @@ -60,6 +60,14 @@ export const vertexModels = { inputPrice: 2.5, outputPrice: 15, }, + "gemini-2.5-pro-preview-06-05": { + maxTokens: 65_535, + contextWindow: 1_048_576, + supportsImages: true, + supportsPromptCache: true, + inputPrice: 2.5, + outputPrice: 15, + }, "gemini-2.5-pro-exp-03-25": { maxTokens: 65_535, contextWindow: 1_048_576, diff --git a/webview-ui/src/components/settings/ModelInfoView.tsx b/webview-ui/src/components/settings/ModelInfoView.tsx index d940e66d42..9b3291d303 100644 --- a/webview-ui/src/components/settings/ModelInfoView.tsx +++ b/webview-ui/src/components/settings/ModelInfoView.tsx @@ -74,7 +74,8 @@ export const ModelInfoView = ({ apiProvider === "gemini" && ( {selectedModelId === "gemini-2.5-pro-preview-03-25" || - selectedModelId === "gemini-2.5-pro-preview-05-06" + selectedModelId === "gemini-2.5-pro-preview-05-06" || + selectedModelId === "gemini-2.5-pro-preview-06-05" ? t("settings:modelInfo.gemini.billingEstimate") : t("settings:modelInfo.gemini.freeRequests", { count: selectedModelId && selectedModelId.includes("flash") ? 15 : 2, From b5c3ac980a7c9a0b0cea3798836ea9f2beaa95f7 Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Thu, 5 Jun 2025 13:06:51 -0500 Subject: [PATCH 02/13] feat: add thinking variant for gemini-2.5-pro-preview-06-05 --- packages/types/src/providers/gemini.ts | 27 +++++++++++++++++++ packages/types/src/providers/vertex.ts | 11 ++++++++ .../src/components/settings/ModelInfoView.tsx | 3 ++- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/packages/types/src/providers/gemini.ts b/packages/types/src/providers/gemini.ts index 09e1eb5077..ea587c9a77 100644 --- a/packages/types/src/providers/gemini.ts +++ b/packages/types/src/providers/gemini.ts @@ -104,6 +104,33 @@ export const geminiModels = { }, ], }, + "gemini-2.5-pro-preview-06-05:thinking": { + maxTokens: 65_535, + contextWindow: 1_048_576, + supportsImages: true, + supportsPromptCache: true, + inputPrice: 2.5, // This is the pricing for prompts above 200k tokens. + outputPrice: 3.5, // Thinking models have a different output price + cacheReadsPrice: 0.625, + cacheWritesPrice: 4.5, + maxThinkingTokens: 32_768, + supportsReasoningBudget: true, + requiredReasoningBudget: true, + tiers: [ + { + contextWindow: 200_000, + inputPrice: 1.25, + outputPrice: 10, + cacheReadsPrice: 0.31, + }, + { + contextWindow: Infinity, + inputPrice: 2.5, + outputPrice: 15, + cacheReadsPrice: 0.625, + }, + ], + }, "gemini-2.5-pro-preview-06-05": { maxTokens: 65_535, contextWindow: 1_048_576, diff --git a/packages/types/src/providers/vertex.ts b/packages/types/src/providers/vertex.ts index e0169bc008..4ddde25866 100644 --- a/packages/types/src/providers/vertex.ts +++ b/packages/types/src/providers/vertex.ts @@ -60,6 +60,17 @@ export const vertexModels = { inputPrice: 2.5, outputPrice: 15, }, + "gemini-2.5-pro-preview-06-05:thinking": { + maxTokens: 65_535, + contextWindow: 1_048_576, + supportsImages: true, + supportsPromptCache: true, + inputPrice: 2.5, + outputPrice: 15, + maxThinkingTokens: 32_768, + supportsReasoningBudget: true, + requiredReasoningBudget: true, + }, "gemini-2.5-pro-preview-06-05": { maxTokens: 65_535, contextWindow: 1_048_576, diff --git a/webview-ui/src/components/settings/ModelInfoView.tsx b/webview-ui/src/components/settings/ModelInfoView.tsx index 9b3291d303..4ea3adf3f6 100644 --- a/webview-ui/src/components/settings/ModelInfoView.tsx +++ b/webview-ui/src/components/settings/ModelInfoView.tsx @@ -75,7 +75,8 @@ export const ModelInfoView = ({ {selectedModelId === "gemini-2.5-pro-preview-03-25" || selectedModelId === "gemini-2.5-pro-preview-05-06" || - selectedModelId === "gemini-2.5-pro-preview-06-05" + selectedModelId === "gemini-2.5-pro-preview-06-05" || + selectedModelId === "gemini-2.5-pro-preview-06-05:thinking" ? t("settings:modelInfo.gemini.billingEstimate") : t("settings:modelInfo.gemini.freeRequests", { count: selectedModelId && selectedModelId.includes("flash") ? 15 : 2, From 9032e614a377289acdb9a6b5d57e74b2f186a4fd Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Thu, 5 Jun 2025 13:13:21 -0500 Subject: [PATCH 03/13] feat: add gemini-2.5-pro-preview-06-05 support to OpenRouter --- packages/types/src/providers/openrouter.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/types/src/providers/openrouter.ts b/packages/types/src/providers/openrouter.ts index 5d6edd844c..581b66b229 100644 --- a/packages/types/src/providers/openrouter.ts +++ b/packages/types/src/providers/openrouter.ts @@ -40,6 +40,8 @@ export const OPEN_ROUTER_PROMPT_CACHING_MODELS = new Set([ "anthropic/claude-sonnet-4", "anthropic/claude-opus-4", "google/gemini-2.5-pro-preview", + "google/gemini-2.5-pro-preview-06-05", + "google/gemini-2.5-pro-preview-06-05:thinking", "google/gemini-2.5-flash-preview", "google/gemini-2.5-flash-preview:thinking", "google/gemini-2.5-flash-preview-05-20", @@ -65,11 +67,14 @@ export const OPEN_ROUTER_REASONING_BUDGET_MODELS = new Set([ "anthropic/claude-3.7-sonnet:thinking", "anthropic/claude-opus-4", "anthropic/claude-sonnet-4", + "google/gemini-2.5-pro-preview-06-05", + "google/gemini-2.5-pro-preview-06-05:thinking", "google/gemini-2.5-flash-preview-05-20", "google/gemini-2.5-flash-preview-05-20:thinking", ]) export const OPEN_ROUTER_REQUIRED_REASONING_BUDGET_MODELS = new Set([ "anthropic/claude-3.7-sonnet:thinking", + "google/gemini-2.5-pro-preview-06-05:thinking", "google/gemini-2.5-flash-preview-05-20:thinking", ]) From 2b43292c007a1532af7ce302c95f4179bc22f0f4 Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Thu, 5 Jun 2025 13:35:09 -0500 Subject: [PATCH 04/13] fix: update gemini-2.5-pro-preview model references in OpenRouter --- packages/types/src/providers/openrouter.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/types/src/providers/openrouter.ts b/packages/types/src/providers/openrouter.ts index 581b66b229..b1ea8e61be 100644 --- a/packages/types/src/providers/openrouter.ts +++ b/packages/types/src/providers/openrouter.ts @@ -40,8 +40,8 @@ export const OPEN_ROUTER_PROMPT_CACHING_MODELS = new Set([ "anthropic/claude-sonnet-4", "anthropic/claude-opus-4", "google/gemini-2.5-pro-preview", - "google/gemini-2.5-pro-preview-06-05", - "google/gemini-2.5-pro-preview-06-05:thinking", + "google/gemini-2.5-pro-preview:thinking", + "google/gemini-2.5-pro-preview-05-06", "google/gemini-2.5-flash-preview", "google/gemini-2.5-flash-preview:thinking", "google/gemini-2.5-flash-preview-05-20", @@ -67,14 +67,14 @@ export const OPEN_ROUTER_REASONING_BUDGET_MODELS = new Set([ "anthropic/claude-3.7-sonnet:thinking", "anthropic/claude-opus-4", "anthropic/claude-sonnet-4", - "google/gemini-2.5-pro-preview-06-05", - "google/gemini-2.5-pro-preview-06-05:thinking", + "google/gemini-2.5-pro-preview", + "google/gemini-2.5-pro-preview:thinking", "google/gemini-2.5-flash-preview-05-20", "google/gemini-2.5-flash-preview-05-20:thinking", ]) export const OPEN_ROUTER_REQUIRED_REASONING_BUDGET_MODELS = new Set([ "anthropic/claude-3.7-sonnet:thinking", - "google/gemini-2.5-pro-preview-06-05:thinking", + "google/gemini-2.5-pro-preview:thinking", "google/gemini-2.5-flash-preview-05-20:thinking", ]) From 3b26b07c732cde19c4d2cc119b91dd40a1e02782 Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Thu, 5 Jun 2025 14:07:42 -0500 Subject: [PATCH 05/13] fix: tests --- packages/types/src/providers/openrouter.ts | 4 ---- src/api/providers/fetchers/__tests__/openrouter.spec.ts | 6 ++++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/types/src/providers/openrouter.ts b/packages/types/src/providers/openrouter.ts index b1ea8e61be..88fb3f5238 100644 --- a/packages/types/src/providers/openrouter.ts +++ b/packages/types/src/providers/openrouter.ts @@ -40,8 +40,6 @@ export const OPEN_ROUTER_PROMPT_CACHING_MODELS = new Set([ "anthropic/claude-sonnet-4", "anthropic/claude-opus-4", "google/gemini-2.5-pro-preview", - "google/gemini-2.5-pro-preview:thinking", - "google/gemini-2.5-pro-preview-05-06", "google/gemini-2.5-flash-preview", "google/gemini-2.5-flash-preview:thinking", "google/gemini-2.5-flash-preview-05-20", @@ -68,13 +66,11 @@ export const OPEN_ROUTER_REASONING_BUDGET_MODELS = new Set([ "anthropic/claude-opus-4", "anthropic/claude-sonnet-4", "google/gemini-2.5-pro-preview", - "google/gemini-2.5-pro-preview:thinking", "google/gemini-2.5-flash-preview-05-20", "google/gemini-2.5-flash-preview-05-20:thinking", ]) export const OPEN_ROUTER_REQUIRED_REASONING_BUDGET_MODELS = new Set([ "anthropic/claude-3.7-sonnet:thinking", - "google/gemini-2.5-pro-preview:thinking", "google/gemini-2.5-flash-preview-05-20:thinking", ]) diff --git a/src/api/providers/fetchers/__tests__/openrouter.spec.ts b/src/api/providers/fetchers/__tests__/openrouter.spec.ts index 010a8a9fa2..1efe150ab0 100644 --- a/src/api/providers/fetchers/__tests__/openrouter.spec.ts +++ b/src/api/providers/fetchers/__tests__/openrouter.spec.ts @@ -185,10 +185,11 @@ describe("OpenRouter API", () => { expect(endpoints).toEqual({ Google: { - maxTokens: 0, + maxTokens: 65535, contextWindow: 1048576, supportsImages: true, supportsPromptCache: true, + supportsReasoningBudget: true, inputPrice: 1.25, outputPrice: 10, cacheWritesPrice: 1.625, @@ -198,10 +199,11 @@ describe("OpenRouter API", () => { supportedParameters: undefined, }, "Google AI Studio": { - maxTokens: 0, + maxTokens: 65536, contextWindow: 1048576, supportsImages: true, supportsPromptCache: true, + supportsReasoningBudget: true, inputPrice: 1.25, outputPrice: 10, cacheWritesPrice: 1.625, From 5a7e8f0273e399487817d5edd9d0d9ea5c004463 Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Thu, 5 Jun 2025 14:23:20 -0500 Subject: [PATCH 06/13] feat: enhance reasoning handling in Gemini and Vertex handlers --- src/api/providers/gemini.ts | 25 +++++++++++++++++++++++-- src/api/providers/vertex.ts | 2 +- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/api/providers/gemini.ts b/src/api/providers/gemini.ts index 5addc07a92..c0bbb87e79 100644 --- a/src/api/providers/gemini.ts +++ b/src/api/providers/gemini.ts @@ -81,7 +81,28 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl let lastUsageMetadata: GenerateContentResponseUsageMetadata | undefined for await (const chunk of result) { - if (chunk.text) { + // Process candidates and their parts to separate thoughts from content + if (chunk.candidates && chunk.candidates.length > 0) { + const candidate = chunk.candidates[0] + if (candidate.content && candidate.content.parts) { + for (const part of candidate.content.parts) { + if (part.thought) { + // This is a thinking/reasoning part + if (part.text) { + yield { type: "reasoning", text: part.text } + } + } else { + // This is regular content + if (part.text) { + yield { type: "text", text: part.text } + } + } + } + } + } + + // Fallback to the original text property if no candidates structure + else if (chunk.text) { yield { type: "text", text: chunk.text } } @@ -121,7 +142,7 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl id, info, thinkingConfig: this.options.modelMaxThinkingTokens - ? { thinkingBudget: this.options.modelMaxThinkingTokens } + ? { thinkingBudget: this.options.modelMaxThinkingTokens, includeThoughts: true } : undefined, maxOutputTokens: this.options.modelMaxTokens ?? info.maxTokens ?? undefined, } diff --git a/src/api/providers/vertex.ts b/src/api/providers/vertex.ts index fdd51e0666..0100b28e6e 100644 --- a/src/api/providers/vertex.ts +++ b/src/api/providers/vertex.ts @@ -24,7 +24,7 @@ export class VertexHandler extends GeminiHandler implements SingleCompletionHand id, info, thinkingConfig: this.options.modelMaxThinkingTokens - ? { thinkingBudget: this.options.modelMaxThinkingTokens } + ? { thinkingBudget: this.options.modelMaxThinkingTokens, includeThoughts: true } : undefined, maxOutputTokens: this.options.modelMaxTokens ?? info.maxTokens ?? undefined, } From 3c06d8f4a5567ebb18fdd384017bb2a516a64974 Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Thu, 5 Jun 2025 14:42:35 -0500 Subject: [PATCH 07/13] feat: add google/gemini-2.5-pro-preview to required reasoning budget models --- packages/types/src/providers/openrouter.ts | 1 + src/api/providers/fetchers/__tests__/openrouter.spec.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/packages/types/src/providers/openrouter.ts b/packages/types/src/providers/openrouter.ts index 88fb3f5238..3c0e4ee6d8 100644 --- a/packages/types/src/providers/openrouter.ts +++ b/packages/types/src/providers/openrouter.ts @@ -72,5 +72,6 @@ export const OPEN_ROUTER_REASONING_BUDGET_MODELS = new Set([ export const OPEN_ROUTER_REQUIRED_REASONING_BUDGET_MODELS = new Set([ "anthropic/claude-3.7-sonnet:thinking", + "google/gemini-2.5-pro-preview", "google/gemini-2.5-flash-preview-05-20:thinking", ]) diff --git a/src/api/providers/fetchers/__tests__/openrouter.spec.ts b/src/api/providers/fetchers/__tests__/openrouter.spec.ts index 1efe150ab0..da7cca1c8f 100644 --- a/src/api/providers/fetchers/__tests__/openrouter.spec.ts +++ b/src/api/providers/fetchers/__tests__/openrouter.spec.ts @@ -190,6 +190,7 @@ describe("OpenRouter API", () => { supportsImages: true, supportsPromptCache: true, supportsReasoningBudget: true, + requiredReasoningBudget: true, inputPrice: 1.25, outputPrice: 10, cacheWritesPrice: 1.625, @@ -204,6 +205,7 @@ describe("OpenRouter API", () => { supportsImages: true, supportsPromptCache: true, supportsReasoningBudget: true, + requiredReasoningBudget: true, inputPrice: 1.25, outputPrice: 10, cacheWritesPrice: 1.625, From 8d6478cc6a2b0cdb8854c2d42acc340ce7f20b5e Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Thu, 5 Jun 2025 14:42:54 -0500 Subject: [PATCH 08/13] fix: refactor thinkingConfig assignment for consistency in Gemini and Vertex handlers --- src/api/providers/gemini.ts | 9 ++++++--- src/api/providers/vertex.ts | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/api/providers/gemini.ts b/src/api/providers/gemini.ts index c0bbb87e79..1f878a7446 100644 --- a/src/api/providers/gemini.ts +++ b/src/api/providers/gemini.ts @@ -141,9 +141,12 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl return { id, info, - thinkingConfig: this.options.modelMaxThinkingTokens - ? { thinkingBudget: this.options.modelMaxThinkingTokens, includeThoughts: true } - : undefined, + thinkingConfig: { + ...(this.options.modelMaxThinkingTokens && { + thinkingBudget: this.options.modelMaxThinkingTokens, + }), + includeThoughts: true, + }, maxOutputTokens: this.options.modelMaxTokens ?? info.maxTokens ?? undefined, } } diff --git a/src/api/providers/vertex.ts b/src/api/providers/vertex.ts index 0100b28e6e..9fad19dfb6 100644 --- a/src/api/providers/vertex.ts +++ b/src/api/providers/vertex.ts @@ -23,9 +23,12 @@ export class VertexHandler extends GeminiHandler implements SingleCompletionHand return { id, info, - thinkingConfig: this.options.modelMaxThinkingTokens - ? { thinkingBudget: this.options.modelMaxThinkingTokens, includeThoughts: true } - : undefined, + thinkingConfig: { + ...(this.options.modelMaxThinkingTokens && { + thinkingBudget: this.options.modelMaxThinkingTokens, + }), + includeThoughts: true, + }, maxOutputTokens: this.options.modelMaxTokens ?? info.maxTokens ?? undefined, } } From 826a41fc378ebafe5f9f4a721856759ba8f4a814 Mon Sep 17 00:00:00 2001 From: cte Date: Thu, 5 Jun 2025 13:49:07 -0700 Subject: [PATCH 09/13] Fix Gemini reasoning --- packages/types/src/providers/gemini.ts | 29 +----------- packages/types/src/providers/openrouter.ts | 21 +++++---- packages/types/src/providers/vertex.ts | 11 +---- .../fetchers/__tests__/openrouter.spec.ts | 2 - src/api/providers/gemini.ts | 44 ++++++------------- src/api/transform/model-params.ts | 30 ++++++++++--- src/api/transform/reasoning.ts | 12 +++++ .../src/components/settings/ModelInfoView.tsx | 5 +-- 8 files changed, 65 insertions(+), 89 deletions(-) diff --git a/packages/types/src/providers/gemini.ts b/packages/types/src/providers/gemini.ts index ea587c9a77..c8668ff40a 100644 --- a/packages/types/src/providers/gemini.ts +++ b/packages/types/src/providers/gemini.ts @@ -104,33 +104,6 @@ export const geminiModels = { }, ], }, - "gemini-2.5-pro-preview-06-05:thinking": { - maxTokens: 65_535, - contextWindow: 1_048_576, - supportsImages: true, - supportsPromptCache: true, - inputPrice: 2.5, // This is the pricing for prompts above 200k tokens. - outputPrice: 3.5, // Thinking models have a different output price - cacheReadsPrice: 0.625, - cacheWritesPrice: 4.5, - maxThinkingTokens: 32_768, - supportsReasoningBudget: true, - requiredReasoningBudget: true, - tiers: [ - { - contextWindow: 200_000, - inputPrice: 1.25, - outputPrice: 10, - cacheReadsPrice: 0.31, - }, - { - contextWindow: Infinity, - inputPrice: 2.5, - outputPrice: 15, - cacheReadsPrice: 0.625, - }, - ], - }, "gemini-2.5-pro-preview-06-05": { maxTokens: 65_535, contextWindow: 1_048_576, @@ -140,6 +113,8 @@ export const geminiModels = { outputPrice: 15, cacheReadsPrice: 0.625, cacheWritesPrice: 4.5, + maxThinkingTokens: 32_768, + supportsReasoningBudget: true, tiers: [ { contextWindow: 200_000, diff --git a/packages/types/src/providers/openrouter.ts b/packages/types/src/providers/openrouter.ts index 3c0e4ee6d8..f0a802c824 100644 --- a/packages/types/src/providers/openrouter.ts +++ b/packages/types/src/providers/openrouter.ts @@ -60,18 +60,23 @@ export const OPEN_ROUTER_COMPUTER_USE_MODELS = new Set([ "anthropic/claude-opus-4", ]) +// When we first launched these models we didn't have support for +// enabling/disabling the reasoning budget for hybrid models. Now that we +// do support this we should give users the option to enable/disable it +// whenever possible. However these particular (virtual) model ids with the +// `:thinking` suffix always require the reasoning budget to be enabled, so +// for backwards compatibility we should still require it. +// We should *not* be adding new models to this set. +export const OPEN_ROUTER_REQUIRED_REASONING_BUDGET_MODELS = new Set([ + "anthropic/claude-3.7-sonnet:thinking", + "google/gemini-2.5-flash-preview-05-20:thinking", +]) + export const OPEN_ROUTER_REASONING_BUDGET_MODELS = new Set([ + ...OPEN_ROUTER_REQUIRED_REASONING_BUDGET_MODELS, "anthropic/claude-3.7-sonnet:beta", - "anthropic/claude-3.7-sonnet:thinking", "anthropic/claude-opus-4", "anthropic/claude-sonnet-4", "google/gemini-2.5-pro-preview", "google/gemini-2.5-flash-preview-05-20", - "google/gemini-2.5-flash-preview-05-20:thinking", -]) - -export const OPEN_ROUTER_REQUIRED_REASONING_BUDGET_MODELS = new Set([ - "anthropic/claude-3.7-sonnet:thinking", - "google/gemini-2.5-pro-preview", - "google/gemini-2.5-flash-preview-05-20:thinking", ]) diff --git a/packages/types/src/providers/vertex.ts b/packages/types/src/providers/vertex.ts index 4ddde25866..1c6643b6eb 100644 --- a/packages/types/src/providers/vertex.ts +++ b/packages/types/src/providers/vertex.ts @@ -60,7 +60,7 @@ export const vertexModels = { inputPrice: 2.5, outputPrice: 15, }, - "gemini-2.5-pro-preview-06-05:thinking": { + "gemini-2.5-pro-preview-06-05": { maxTokens: 65_535, contextWindow: 1_048_576, supportsImages: true, @@ -69,15 +69,6 @@ export const vertexModels = { outputPrice: 15, maxThinkingTokens: 32_768, supportsReasoningBudget: true, - requiredReasoningBudget: true, - }, - "gemini-2.5-pro-preview-06-05": { - maxTokens: 65_535, - contextWindow: 1_048_576, - supportsImages: true, - supportsPromptCache: true, - inputPrice: 2.5, - outputPrice: 15, }, "gemini-2.5-pro-exp-03-25": { maxTokens: 65_535, diff --git a/src/api/providers/fetchers/__tests__/openrouter.spec.ts b/src/api/providers/fetchers/__tests__/openrouter.spec.ts index da7cca1c8f..1efe150ab0 100644 --- a/src/api/providers/fetchers/__tests__/openrouter.spec.ts +++ b/src/api/providers/fetchers/__tests__/openrouter.spec.ts @@ -190,7 +190,6 @@ describe("OpenRouter API", () => { supportsImages: true, supportsPromptCache: true, supportsReasoningBudget: true, - requiredReasoningBudget: true, inputPrice: 1.25, outputPrice: 10, cacheWritesPrice: 1.625, @@ -205,7 +204,6 @@ describe("OpenRouter API", () => { supportsImages: true, supportsPromptCache: true, supportsReasoningBudget: true, - requiredReasoningBudget: true, inputPrice: 1.25, outputPrice: 10, cacheWritesPrice: 1.625, diff --git a/src/api/providers/gemini.ts b/src/api/providers/gemini.ts index 1f878a7446..6765c8676d 100644 --- a/src/api/providers/gemini.ts +++ b/src/api/providers/gemini.ts @@ -14,6 +14,7 @@ import { safeJsonParse } from "../../shared/safeJsonParse" import { convertAnthropicContentToGemini, convertAnthropicMessageToGemini } from "../transform/gemini-format" import type { ApiStream } from "../transform/stream" +import { getModelParams } from "../transform/model-params" import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index" import { BaseProvider } from "./base-provider" @@ -62,7 +63,7 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl messages: Anthropic.Messages.MessageParam[], metadata?: ApiHandlerCreateMessageMetadata, ): ApiStream { - const { id: model, thinkingConfig, maxOutputTokens, info } = this.getModel() + const { id: model, info, reasoning: thinkingConfig, maxTokens } = this.getModel() const contents = messages.map(convertAnthropicMessageToGemini) @@ -70,7 +71,7 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl systemInstruction, httpOptions: this.options.googleGeminiBaseUrl ? { baseUrl: this.options.googleGeminiBaseUrl } : undefined, thinkingConfig, - maxOutputTokens, + maxOutputTokens: this.options.modelMaxTokens ?? maxTokens ?? undefined, temperature: this.options.modelTemperature ?? 0, } @@ -129,35 +130,16 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl } override getModel() { - let id = this.options.apiModelId ?? geminiDefaultModelId - let info: ModelInfo = geminiModels[id as GeminiModelId] - - if (id?.endsWith(":thinking")) { - id = id.slice(0, -":thinking".length) - - if (geminiModels[id as GeminiModelId]) { - info = geminiModels[id as GeminiModelId] - - return { - id, - info, - thinkingConfig: { - ...(this.options.modelMaxThinkingTokens && { - thinkingBudget: this.options.modelMaxThinkingTokens, - }), - includeThoughts: true, - }, - maxOutputTokens: this.options.modelMaxTokens ?? info.maxTokens ?? undefined, - } - } - } - - if (!info) { - id = geminiDefaultModelId - info = geminiModels[geminiDefaultModelId] - } - - return { id, info } + const modelId = this.options.apiModelId + let id = modelId && modelId in geminiModels ? (modelId as GeminiModelId) : geminiDefaultModelId + const info: ModelInfo = geminiModels[id] + const params = getModelParams({ format: "gemini", modelId: id, model: info, settings: this.options }) + + // The `:thinking` suffix indicates that the model is a "Hybrid" + // reasoning model and that reasoning is required to be enabled. + // The actual model ID honored by Gemini's API does not have this + // suffix. + return { id: id.endsWith(":thinking") ? id.replace(":thinking", "") : id, info, ...params } } async completePrompt(prompt: string): Promise { diff --git a/src/api/transform/model-params.ts b/src/api/transform/model-params.ts index d9a2c749ca..9f33afbb96 100644 --- a/src/api/transform/model-params.ts +++ b/src/api/transform/model-params.ts @@ -5,13 +5,17 @@ import { shouldUseReasoningBudget, shouldUseReasoningEffort } from "../../shared import { type AnthropicReasoningParams, type OpenAiReasoningParams, + type GeminiReasoningParams, type OpenRouterReasoningParams, getAnthropicReasoning, getOpenAiReasoning, + getGeminiReasoning, getOpenRouterReasoning, } from "./reasoning" -type GetModelParamsOptions = { +type Format = "anthropic" | "openai" | "gemini" | "openrouter" + +type GetModelParamsOptions = { format: T modelId: string model: ModelInfo @@ -26,14 +30,19 @@ type BaseModelParams = { reasoningBudget: number | undefined } +type AnthropicModelParams = { + format: "anthropic" + reasoning: AnthropicReasoningParams | undefined +} & BaseModelParams + type OpenAiModelParams = { format: "openai" reasoning: OpenAiReasoningParams | undefined } & BaseModelParams -type AnthropicModelParams = { - format: "anthropic" - reasoning: AnthropicReasoningParams | undefined +type GeminiModelParams = { + format: "gemini" + reasoning: GeminiReasoningParams | undefined } & BaseModelParams type OpenRouterModelParams = { @@ -41,11 +50,12 @@ type OpenRouterModelParams = { reasoning: OpenRouterReasoningParams | undefined } & BaseModelParams -export type ModelParams = OpenAiModelParams | AnthropicModelParams | OpenRouterModelParams +export type ModelParams = AnthropicModelParams | OpenAiModelParams | GeminiModelParams | OpenRouterModelParams // Function overloads for specific return types -export function getModelParams(options: GetModelParamsOptions<"openai">): OpenAiModelParams export function getModelParams(options: GetModelParamsOptions<"anthropic">): AnthropicModelParams +export function getModelParams(options: GetModelParamsOptions<"openai">): OpenAiModelParams +export function getModelParams(options: GetModelParamsOptions<"gemini">): GeminiModelParams export function getModelParams(options: GetModelParamsOptions<"openrouter">): OpenRouterModelParams export function getModelParams({ format, @@ -53,7 +63,7 @@ export function getModelParams({ model, settings, defaultTemperature = 0, -}: GetModelParamsOptions<"openai" | "anthropic" | "openrouter">): ModelParams { +}: GetModelParamsOptions): ModelParams { const { modelMaxTokens: customMaxTokens, modelMaxThinkingTokens: customMaxThinkingTokens, @@ -121,6 +131,12 @@ export function getModelParams({ ...params, reasoning: getOpenAiReasoning({ model, reasoningBudget, reasoningEffort, settings }), } + } else if (format === "gemini") { + return { + format, + ...params, + reasoning: getGeminiReasoning({ model, reasoningBudget, reasoningEffort, settings }), + } } else { // Special case for o1-pro, which doesn't support temperature. // Note that OpenRouter's `supported_parameters` field includes diff --git a/src/api/transform/reasoning.ts b/src/api/transform/reasoning.ts index 9887f1137a..a173c59b19 100644 --- a/src/api/transform/reasoning.ts +++ b/src/api/transform/reasoning.ts @@ -1,5 +1,6 @@ import { BetaThinkingConfigParam } from "@anthropic-ai/sdk/resources/beta" import OpenAI from "openai" +import type { GenerateContentConfig } from "@google/genai" import type { ModelInfo, ProviderSettings } from "@roo-code/types" @@ -17,6 +18,8 @@ export type AnthropicReasoningParams = BetaThinkingConfigParam export type OpenAiReasoningParams = { reasoning_effort: OpenAI.Chat.ChatCompletionCreateParams["reasoning_effort"] } +export type GeminiReasoningParams = GenerateContentConfig["thinkingConfig"] + export type GetModelReasoningOptions = { model: ModelInfo reasoningBudget: number | undefined @@ -49,3 +52,12 @@ export const getOpenAiReasoning = ({ settings, }: GetModelReasoningOptions): OpenAiReasoningParams | undefined => shouldUseReasoningEffort({ model, settings }) ? { reasoning_effort: reasoningEffort } : undefined + +export const getGeminiReasoning = ({ + model, + reasoningBudget, + settings, +}: GetModelReasoningOptions): GeminiReasoningParams | undefined => + shouldUseReasoningBudget({ model, settings }) + ? { thinkingBudget: reasoningBudget!, includeThoughts: true } + : undefined diff --git a/webview-ui/src/components/settings/ModelInfoView.tsx b/webview-ui/src/components/settings/ModelInfoView.tsx index 4ea3adf3f6..8078b03acd 100644 --- a/webview-ui/src/components/settings/ModelInfoView.tsx +++ b/webview-ui/src/components/settings/ModelInfoView.tsx @@ -73,10 +73,7 @@ export const ModelInfoView = ({ ), apiProvider === "gemini" && ( - {selectedModelId === "gemini-2.5-pro-preview-03-25" || - selectedModelId === "gemini-2.5-pro-preview-05-06" || - selectedModelId === "gemini-2.5-pro-preview-06-05" || - selectedModelId === "gemini-2.5-pro-preview-06-05:thinking" + {selectedModelId.includes("pro-preview") ? t("settings:modelInfo.gemini.billingEstimate") : t("settings:modelInfo.gemini.freeRequests", { count: selectedModelId && selectedModelId.includes("flash") ? 15 : 2, From 5a99bd35a78241131e74c6dbd2de57d7bb051e52 Mon Sep 17 00:00:00 2001 From: cte Date: Thu, 5 Jun 2025 13:51:50 -0700 Subject: [PATCH 10/13] Fix tsc error --- src/api/providers/vertex.ts | 41 +++++++++++-------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/src/api/providers/vertex.ts b/src/api/providers/vertex.ts index 9fad19dfb6..2c077d97b7 100644 --- a/src/api/providers/vertex.ts +++ b/src/api/providers/vertex.ts @@ -2,6 +2,8 @@ import { type ModelInfo, type VertexModelId, vertexDefaultModelId, vertexModels import type { ApiHandlerOptions } from "../../shared/api" +import { getModelParams } from "../transform/model-params" + import { GeminiHandler } from "./gemini" import { SingleCompletionHandler } from "../index" @@ -11,34 +13,15 @@ export class VertexHandler extends GeminiHandler implements SingleCompletionHand } override getModel() { - let id = this.options.apiModelId ?? vertexDefaultModelId - let info: ModelInfo = vertexModels[id as VertexModelId] - - if (id?.endsWith(":thinking")) { - id = id.slice(0, -":thinking".length) as VertexModelId - - if (vertexModels[id as VertexModelId]) { - info = vertexModels[id as VertexModelId] - - return { - id, - info, - thinkingConfig: { - ...(this.options.modelMaxThinkingTokens && { - thinkingBudget: this.options.modelMaxThinkingTokens, - }), - includeThoughts: true, - }, - maxOutputTokens: this.options.modelMaxTokens ?? info.maxTokens ?? undefined, - } - } - } - - if (!info) { - id = vertexDefaultModelId - info = vertexModels[vertexDefaultModelId] - } - - return { id, info } + const modelId = this.options.apiModelId + let id = modelId && modelId in vertexModels ? (modelId as VertexModelId) : vertexDefaultModelId + const info: ModelInfo = vertexModels[id] + const params = getModelParams({ format: "gemini", modelId: id, model: info, settings: this.options }) + + // The `:thinking` suffix indicates that the model is a "Hybrid" + // reasoning model and that reasoning is required to be enabled. + // The actual model ID honored by Gemini's API does not have this + // suffix. + return { id: id.endsWith(":thinking") ? id.replace(":thinking", "") : id, info, ...params } } } From 0eab7f09875bc0c1dcadb57b519b5685c65e19f7 Mon Sep 17 00:00:00 2001 From: cte Date: Thu, 5 Jun 2025 13:53:58 -0700 Subject: [PATCH 11/13] Fix tsc error --- packages/types/src/providers/openrouter.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/types/src/providers/openrouter.ts b/packages/types/src/providers/openrouter.ts index f0a802c824..08ffceb1e2 100644 --- a/packages/types/src/providers/openrouter.ts +++ b/packages/types/src/providers/openrouter.ts @@ -73,10 +73,13 @@ export const OPEN_ROUTER_REQUIRED_REASONING_BUDGET_MODELS = new Set([ ]) export const OPEN_ROUTER_REASONING_BUDGET_MODELS = new Set([ - ...OPEN_ROUTER_REQUIRED_REASONING_BUDGET_MODELS, "anthropic/claude-3.7-sonnet:beta", "anthropic/claude-opus-4", "anthropic/claude-sonnet-4", "google/gemini-2.5-pro-preview", "google/gemini-2.5-flash-preview-05-20", + // Also include the models that require the reasoning budget to be enabled + // even though `OPEN_ROUTER_REQUIRED_REASONING_BUDGET_MODELS` takes precedence. + "anthropic/claude-3.7-sonnet:thinking", + "google/gemini-2.5-flash-preview-05-20:thinking", ]) From b5e82df93a0fc65f45e68dea735fb0d3af25ad27 Mon Sep 17 00:00:00 2001 From: cte Date: Thu, 5 Jun 2025 14:34:26 -0700 Subject: [PATCH 12/13] Hack to exclude thinking tokens by default --- src/api/providers/openrouter.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/api/providers/openrouter.ts b/src/api/providers/openrouter.ts index c0656735e7..31300b868b 100644 --- a/src/api/providers/openrouter.ts +++ b/src/api/providers/openrouter.ts @@ -74,6 +74,15 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH let { id: modelId, maxTokens, temperature, topP, reasoning } = model + // OpenRouter sends reasoning tokens by default for Gemini 2.5 Pro + // Preview even if you don't request them. This is not the default for + // other providers (including Gemini), so we need to explicitly disable + // i We should generalize this using the logic in `getModelParams`, but + // this is easier for now. + if (modelId === "google/gemini-2.5-pro-preview" && typeof reasoning === "undefined") { + reasoning = { exclude: true } + } + // Convert Anthropic messages to OpenAI format. let openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [ { role: "system", content: systemPrompt }, From 936300a56f02f255f06249201cedc1cde2ff9ef5 Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Thu, 5 Jun 2025 16:38:55 -0500 Subject: [PATCH 13/13] feat: add global region to VERTEX_REGIONS --- packages/types/src/providers/vertex.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/types/src/providers/vertex.ts b/packages/types/src/providers/vertex.ts index 1c6643b6eb..028d308923 100644 --- a/packages/types/src/providers/vertex.ts +++ b/packages/types/src/providers/vertex.ts @@ -227,6 +227,7 @@ export const vertexModels = { } as const satisfies Record export const VERTEX_REGIONS = [ + { value: "global", label: "global" }, { value: "us-east5", label: "us-east5" }, { value: "us-central1", label: "us-central1" }, { value: "europe-west1", label: "europe-west1" },