Browse Source

Merge pull request #1200 from RooVetGit/cte/thinking-tweaks

Thinking settings tweaks
Chris Estreich 10 months ago
parent
commit
ebe294bec1

+ 5 - 0
.changeset/swift-kings-attack.md

@@ -0,0 +1,5 @@
+---
+"roo-cline": patch
+---
+
+Pass "thinking" params to OpenRouter

+ 12 - 11
src/api/providers/anthropic.ts

@@ -14,8 +14,6 @@ import { ApiStream } from "../transform/stream"
 
 const ANTHROPIC_DEFAULT_TEMPERATURE = 0
 
-const THINKING_MODELS = ["claude-3-7-sonnet-20250219"]
-
 export class AnthropicHandler implements ApiHandler, SingleCompletionHandler {
 	private options: ApiHandlerOptions
 	private client: Anthropic
@@ -32,16 +30,19 @@ export class AnthropicHandler implements ApiHandler, SingleCompletionHandler {
 	async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
 		let stream: AnthropicStream<Anthropic.Messages.RawMessageStreamEvent>
 		const cacheControl: CacheControlEphemeral = { type: "ephemeral" }
-		const modelId = this.getModel().id
-		const maxTokens = this.getModel().info.maxTokens || 8192
+		let { id: modelId, info: modelInfo } = this.getModel()
+		const maxTokens = modelInfo.maxTokens || 8192
 		let temperature = this.options.modelTemperature ?? ANTHROPIC_DEFAULT_TEMPERATURE
 		let thinking: BetaThinkingConfigParam | undefined = undefined
 
-		if (THINKING_MODELS.includes(modelId)) {
-			thinking = this.options.anthropicThinking
-				? { type: "enabled", budget_tokens: this.options.anthropicThinking }
-				: { type: "disabled" }
-
+		// Anthropic "Thinking" models require a temperature of 1.0.
+		if (modelId === "claude-3-7-sonnet-20250219:thinking") {
+			// The `:thinking` variant is a virtual identifier for the
+			// `claude-3-7-sonnet-20250219` model with a thinking budget.
+			// We can handle this more elegantly in the future.
+			modelId = "claude-3-7-sonnet-20250219"
+			const budgetTokens = this.options.anthropicThinking ?? Math.max(maxTokens * 0.8, 1024)
+			thinking = { type: "enabled", budget_tokens: budgetTokens }
 			temperature = 1.0
 		}
 
@@ -114,8 +115,8 @@ export class AnthropicHandler implements ApiHandler, SingleCompletionHandler {
 			default: {
 				stream = (await this.client.messages.create({
 					model: modelId,
-					max_tokens: this.getModel().info.maxTokens || 8192,
-					temperature: this.options.modelTemperature ?? ANTHROPIC_DEFAULT_TEMPERATURE,
+					max_tokens: maxTokens,
+					temperature,
 					system: [{ text: systemPrompt, type: "text" }],
 					messages,
 					// tools,

+ 8 - 2
src/api/providers/openrouter.ts

@@ -1,4 +1,5 @@
 import { Anthropic } from "@anthropic-ai/sdk"
+import { BetaThinkingConfigParam } from "@anthropic-ai/sdk/resources/beta"
 import axios from "axios"
 import OpenAI from "openai"
 import delay from "delay"
@@ -17,6 +18,7 @@ const OPENROUTER_DEFAULT_TEMPERATURE = 0
 type OpenRouterChatCompletionParams = OpenAI.Chat.ChatCompletionCreateParams & {
 	transforms?: string[]
 	include_reasoning?: boolean
+	thinking?: BetaThinkingConfigParam
 }
 
 // Add custom interface for OpenRouter usage chunk.
@@ -57,7 +59,7 @@ export class OpenRouterHandler implements ApiHandler, SingleCompletionHandler {
 		// prompt caching: https://openrouter.ai/docs/prompt-caching
 		// this is specifically for claude models (some models may 'support prompt caching' automatically without this)
 		switch (true) {
-			case this.getModel().id.startsWith("anthropic/"):
+			case modelId.startsWith("anthropic/"):
 				openAiMessages[0] = {
 					role: "system",
 					content: [
@@ -107,9 +109,12 @@ export class OpenRouterHandler implements ApiHandler, SingleCompletionHandler {
 		}
 
 		let temperature = this.options.modelTemperature ?? defaultTemperature
+		let thinking: BetaThinkingConfigParam | undefined = undefined
 
-		// Anthropic "Thinking" models require a temperature of 1.0.
 		if (modelInfo.thinking) {
+			const maxTokens = modelInfo.maxTokens || 8192
+			const budgetTokens = this.options.anthropicThinking ?? Math.max(maxTokens * 0.8, 1024)
+			thinking = { type: "enabled", budget_tokens: budgetTokens }
 			temperature = 1.0
 		}
 
@@ -120,6 +125,7 @@ export class OpenRouterHandler implements ApiHandler, SingleCompletionHandler {
 			model: modelId,
 			max_tokens: modelInfo.maxTokens,
 			temperature,
+			thinking, // OpenRouter is temporarily supporting this.
 			top_p: topP,
 			messages: openAiMessages,
 			stream: true,

+ 13 - 1
src/shared/api.ts

@@ -103,7 +103,7 @@ export const THINKING_BUDGET = {
 export type AnthropicModelId = keyof typeof anthropicModels
 export const anthropicDefaultModelId: AnthropicModelId = "claude-3-7-sonnet-20250219"
 export const anthropicModels = {
-	"claude-3-7-sonnet-20250219": {
+	"claude-3-7-sonnet-20250219:thinking": {
 		maxTokens: 16384,
 		contextWindow: 200_000,
 		supportsImages: true,
@@ -115,6 +115,18 @@ export const anthropicModels = {
 		cacheReadsPrice: 0.3, // $0.30 per million tokens
 		thinking: true,
 	},
+	"claude-3-7-sonnet-20250219": {
+		maxTokens: 16384,
+		contextWindow: 200_000,
+		supportsImages: true,
+		supportsComputerUse: true,
+		supportsPromptCache: true,
+		inputPrice: 3.0, // $3 per million input tokens
+		outputPrice: 15.0, // $15 per million output tokens
+		cacheWritesPrice: 3.75, // $3.75 per million tokens
+		cacheReadsPrice: 0.3, // $0.30 per million tokens
+		thinking: false,
+	},
 	"claude-3-5-sonnet-20241022": {
 		maxTokens: 8192,
 		contextWindow: 200_000,

+ 16 - 34
webview-ui/src/components/settings/ApiOptions.tsx

@@ -73,7 +73,7 @@ const ApiOptions = ({
 	const [openRouterBaseUrlSelected, setOpenRouterBaseUrlSelected] = useState(!!apiConfiguration?.openRouterBaseUrl)
 	const [isDescriptionExpanded, setIsDescriptionExpanded] = useState(false)
 
-	const anthropicThinkingBudget = apiConfiguration?.anthropicThinking
+	const anthropicThinkingBudget = apiConfiguration?.anthropicThinking ?? THINKING_BUDGET.default
 
 	const noTransform = <T,>(value: T) => value
 	const inputEventTransform = <E,>(event: E) => (event as { target: HTMLInputElement })?.target?.value as any
@@ -1272,39 +1272,21 @@ const ApiOptions = ({
 				)}
 
 			{selectedModelInfo && selectedModelInfo.thinking && (
-				<div className="flex flex-col gap-2 mt-2">
-					<Checkbox
-						checked={!!anthropicThinkingBudget}
-						onChange={(checked) =>
-							setApiConfigurationField(
-								"anthropicThinking",
-								checked
-									? Math.min(
-											THINKING_BUDGET.default,
-											selectedModelInfo.maxTokens ?? THINKING_BUDGET.default,
-										)
-									: undefined,
-							)
-						}>
-						Thinking?
-					</Checkbox>
-					{anthropicThinkingBudget && (
-						<>
-							<div className="text-muted-foreground text-sm">
-								Number of tokens Claude is allowed to use for its internal reasoning process.
-							</div>
-							<div className="flex items-center gap-2">
-								<Slider
-									min={THINKING_BUDGET.min}
-									max={(selectedModelInfo.maxTokens ?? THINKING_BUDGET.default) - 1}
-									step={THINKING_BUDGET.step}
-									value={[anthropicThinkingBudget]}
-									onValueChange={(value) => setApiConfigurationField("anthropicThinking", value[0])}
-								/>
-								<div className="w-12">{anthropicThinkingBudget}</div>
-							</div>
-						</>
-					)}
+				<div className="flex flex-col gap-1 mt-2">
+					<div className="font-medium">Thinking Budget</div>
+					<div className="flex items-center gap-1">
+						<Slider
+							min={THINKING_BUDGET.min}
+							max={(selectedModelInfo.maxTokens ?? THINKING_BUDGET.default) - 1}
+							step={THINKING_BUDGET.step}
+							value={[anthropicThinkingBudget]}
+							onValueChange={(value) => setApiConfigurationField("anthropicThinking", value[0])}
+						/>
+						<div className="w-12 text-sm text-center">{anthropicThinkingBudget}</div>
+					</div>
+					<div className="text-muted-foreground text-sm">
+						Number of tokens Claude is allowed to use for its internal reasoning process.
+					</div>
 				</div>
 			)}