From 0959438db8b7ca2b65a56d7d93d3530b67204a9f Mon Sep 17 00:00:00 2001 From: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com> Date: Sat, 1 Mar 2025 01:31:16 -0800 Subject: [PATCH] Add thinking budget slider to OpenRouter --- src/api/providers/anthropic.ts | 2 +- src/api/providers/openrouter.ts | 21 ++++++++++++++- src/core/webview/ClineProvider.ts | 1 + .../settings/OpenRouterModelPicker.tsx | 27 ++++++++++++++----- 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/api/providers/anthropic.ts b/src/api/providers/anthropic.ts index 7c9582145c..93804d99c2 100644 --- a/src/api/providers/anthropic.ts +++ b/src/api/providers/anthropic.ts @@ -47,7 +47,7 @@ export class AnthropicHandler implements ApiHandler { max_tokens: model.info.maxTokens || 8192, // "Thinking isn’t compatible with temperature, top_p, or top_k modifications as well as forced tool use." // (https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking#important-considerations-when-using-extended-thinking) - temperature: reasoningOn ? 1 : 0, + temperature: reasoningOn ? undefined : 0, system: [ { text: systemPrompt, diff --git a/src/api/providers/openrouter.ts b/src/api/providers/openrouter.ts index 971f9fab73..352f4d406c 100644 --- a/src/api/providers/openrouter.ts +++ b/src/api/providers/openrouter.ts @@ -40,6 +40,7 @@ export class OpenRouterHandler implements ApiHandler { switch (model.id) { case "anthropic/claude-3.7-sonnet": case "anthropic/claude-3.7-sonnet:beta": + case "anthropic/claude-3.7-sonnet:thinking": case "anthropic/claude-3-7-sonnet": case "anthropic/claude-3-7-sonnet:beta": case "anthropic/claude-3.5-sonnet": @@ -95,6 +96,7 @@ export class OpenRouterHandler implements ApiHandler { switch (model.id) { case "anthropic/claude-3.7-sonnet": case "anthropic/claude-3.7-sonnet:beta": + case "anthropic/claude-3.7-sonnet:thinking": case "anthropic/claude-3-7-sonnet": case "anthropic/claude-3-7-sonnet:beta": case "anthropic/claude-3.5-sonnet": @@ -109,7 +111,7 @@ export class OpenRouterHandler implements ApiHandler { break } - let temperature = 0 + let temperature: number | undefined = 0 let topP: number | undefined = undefined if (this.getModel().id.startsWith("deepseek/deepseek-r1") || this.getModel().id === "perplexity/sonar-reasoning") { // Recommended values from DeepSeek @@ -118,6 +120,22 @@ export class OpenRouterHandler implements ApiHandler { openAiMessages = convertToR1Format([{ role: "user", content: systemPrompt }, ...messages]) } + let reasoning: { max_tokens: number } | undefined = undefined + switch (model.id) { + case "anthropic/claude-3.7-sonnet": + case "anthropic/claude-3.7-sonnet:beta": + case "anthropic/claude-3.7-sonnet:thinking": + case "anthropic/claude-3-7-sonnet": + case "anthropic/claude-3-7-sonnet:beta": + let budget_tokens = this.options.thinkingBudgetTokens || 0 + const reasoningOn = budget_tokens !== 0 ? true : false + if (reasoningOn) { + temperature = undefined // extended thinking does not support non-1 temperature + reasoning = { max_tokens: budget_tokens } + } + break + } + // Removes messages in the middle when close to context window limit. Should not be applied to models that support prompt caching since it would continuously break the cache. let shouldApplyMiddleOutTransform = !model.info.supportsPromptCache // except for deepseek (which we set supportsPromptCache to true for), where because the context window is so small our truncation algo might miss and we should use openrouter's middle-out transform as a fallback to ensure we don't exceed the context window (FIXME: once we have a more robust token estimator we should not rely on this) @@ -136,6 +154,7 @@ export class OpenRouterHandler implements ApiHandler { transforms: shouldApplyMiddleOutTransform ? ["middle-out"] : undefined, include_reasoning: true, ...(model.id === "openai/o3-mini" ? { reasoning_effort: this.options.o3MiniReasoningEffort || "medium" } : {}), + ...(reasoning ? { reasoning } : {}), }) let genId: string | undefined diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 0295d2f8ab..d0d4c07586 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -1579,6 +1579,7 @@ Here is the project's README to help you get started:\n\n${mcpDetails.readmeCont case "anthropic/claude-3-7-sonnet:beta": case "anthropic/claude-3.7-sonnet": case "anthropic/claude-3.7-sonnet:beta": + case "anthropic/claude-3.7-sonnet:thinking": case "anthropic/claude-3.5-sonnet": case "anthropic/claude-3.5-sonnet:beta": // NOTE: this needs to be synced with api.ts/openrouter default model info diff --git a/webview-ui/src/components/settings/OpenRouterModelPicker.tsx b/webview-ui/src/components/settings/OpenRouterModelPicker.tsx index 5f6020bbfa..5f47939cf1 100644 --- a/webview-ui/src/components/settings/OpenRouterModelPicker.tsx +++ b/webview-ui/src/components/settings/OpenRouterModelPicker.tsx @@ -10,6 +10,7 @@ import { vscode } from "../../utils/vscode" import { highlight } from "../history/HistoryView" import { ModelInfoView, normalizeApiConfiguration } from "./ApiOptions" import { CODE_BLOCK_BG_COLOR } from "../common/CodeBlock" +import ThinkingBudgetSlider from "./ThinkingBudgetSlider" export interface OpenRouterModelPickerProps { isPopup?: boolean @@ -135,6 +136,13 @@ const OpenRouterModelPicker: React.FC = ({ isPopup } } }, [selectedIndex]) + const showBudgetSlider = useMemo(() => { + return ( + selectedModelId?.toLowerCase().includes("claude-3-7-sonnet") || + selectedModelId?.toLowerCase().includes("claude-3.7-sonnet") + ) + }, [selectedModelId]) + return (