Skip to content

Commit f239ad7

Browse files
committed
🤖 fix: enable visible reasoning for Opus 4.5 with configurable effort
Opus 4.5 now supports all thinking levels with proper effort mapping: - off: effort='low', no thinking (fast, cheap, no visible reasoning) - low: effort='low', thinking enabled (visible reasoning, budget-conscious) - medium: effort='medium', thinking enabled - high: effort='high', thinking enabled Previously Opus 4.5 only passed the effort parameter without the thinking parameter, which meant no visible reasoning traces were returned. Also removed the policy restriction that prevented 'off' for Opus 4.5 - users can now disable visible reasoning while still getting efficient responses via effort='low'. _Generated with mux_ Change-Id: I05239192b38babf22c7ca980d9380da718608be2 Signed-off-by: Thomas Kosiewski <tk@coder.com>
1 parent f8e7690 commit f239ad7

File tree

4 files changed

+33
-23
lines changed

4 files changed

+33
-23
lines changed

src/browser/utils/thinking/policy.ts

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ export type ThinkingPolicy = readonly ThinkingLevel[];
2525
*
2626
* Rules:
2727
* - openai:gpt-5-pro → ["high"] (only supported level)
28-
* - anthropic:claude-opus-4-5 → ["low", "medium", "high"] (effort parameter only)
2928
* - gemini-3 → ["low", "high"] (thinking level only)
3029
* - default → ["off", "low", "medium", "high"] (all levels selectable)
3130
*
@@ -39,12 +38,6 @@ export function getThinkingPolicyForModel(modelString: string): ThinkingPolicy {
3938
return ["high"];
4039
}
4140

42-
// Claude Opus 4.5 only supports effort parameter: low, medium, high (no "off")
43-
// Match "anthropic:" followed by "claude-opus-4-5" with optional version suffix
44-
if (modelString.includes("opus-4-5")) {
45-
return ["low", "medium", "high"];
46-
}
47-
4841
// Gemini 3 Pro only supports "low" and "high" reasoning levels
4942
if (modelString.includes("gemini-3")) {
5043
return ["low", "high"];
@@ -59,8 +52,7 @@ export function getThinkingPolicyForModel(modelString: string): ThinkingPolicy {
5952
*
6053
* Fallback strategy:
6154
* 1. If requested level is allowed, use it
62-
* 2. For Opus 4.5: prefer "high" (best experience for reasoning model)
63-
* 3. Otherwise: prefer "medium" if allowed, else use first allowed level
55+
* 2. Otherwise: prefer "medium" if allowed, else use first allowed level
6456
*/
6557
export function enforceThinkingPolicy(
6658
modelString: string,
@@ -72,11 +64,6 @@ export function enforceThinkingPolicy(
7264
return requested;
7365
}
7466

75-
// Special case: Opus 4.5 defaults to "high" for best experience
76-
if (modelString.includes("opus-4-5") && allowed.includes("high")) {
77-
return "high";
78-
}
79-
8067
// Fallback: prefer "medium" if allowed, else use first allowed level
8168
return allowed.includes("medium") ? "medium" : allowed[0];
8269
}

src/common/types/thinking.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ export const ANTHROPIC_THINKING_BUDGETS: Record<ThinkingLevel, number> = {
4242
*
4343
* @see https://www.anthropic.com/news/claude-opus-4-5
4444
*/
45-
export const ANTHROPIC_EFFORT: Record<ThinkingLevel, "low" | "medium" | "high" | undefined> = {
46-
off: undefined,
45+
export const ANTHROPIC_EFFORT: Record<ThinkingLevel, "low" | "medium" | "high"> = {
46+
off: "low",
4747
low: "low",
4848
medium: "medium",
4949
high: "high",

src/common/utils/ai/providerOptions.test.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,37 +23,46 @@ void mock.module("@/browser/utils/thinking/policy", () => ({
2323

2424
describe("buildProviderOptions - Anthropic", () => {
2525
describe("Opus 4.5 (effort parameter)", () => {
26-
test("should use effort parameter for claude-opus-4-5", () => {
26+
test("should use effort and thinking parameters for claude-opus-4-5", () => {
2727
const result = buildProviderOptions("anthropic:claude-opus-4-5", "medium");
2828

2929
expect(result).toEqual({
3030
anthropic: {
3131
disableParallelToolUse: false,
3232
sendReasoning: true,
33+
thinking: {
34+
type: "enabled",
35+
budgetTokens: 10000, // ANTHROPIC_THINKING_BUDGETS.medium
36+
},
3337
effort: "medium",
3438
},
3539
});
3640
});
3741

38-
test("should use effort parameter for claude-opus-4-5-20251101", () => {
42+
test("should use effort and thinking parameters for claude-opus-4-5-20251101", () => {
3943
const result = buildProviderOptions("anthropic:claude-opus-4-5-20251101", "high");
4044

4145
expect(result).toEqual({
4246
anthropic: {
4347
disableParallelToolUse: false,
4448
sendReasoning: true,
49+
thinking: {
50+
type: "enabled",
51+
budgetTokens: 20000, // ANTHROPIC_THINKING_BUDGETS.high
52+
},
4553
effort: "high",
4654
},
4755
});
4856
});
4957

50-
test("should omit effort when thinking is off for Opus 4.5", () => {
58+
test("should use effort 'low' with no thinking when off for Opus 4.5", () => {
5159
const result = buildProviderOptions("anthropic:claude-opus-4-5", "off");
5260

5361
expect(result).toEqual({
5462
anthropic: {
5563
disableParallelToolUse: false,
5664
sendReasoning: true,
65+
effort: "low", // "off" maps to effort: "low" for efficiency
5766
},
5867
});
5968
});

src/common/utils/ai/providerOptions.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,20 +93,34 @@ export function buildProviderOptions(
9393
const isOpus45 = modelName?.includes("opus-4-5") ?? false;
9494

9595
if (isOpus45) {
96-
// Opus 4.5: Use effort parameter for reasoning control
97-
const effort = ANTHROPIC_EFFORT[effectiveThinking];
96+
// Opus 4.5: Use effort parameter AND optionally thinking for visible reasoning
97+
// - "off" or "low" → effort: "low", no thinking (fast, no visible reasoning for off)
98+
// - "low" → effort: "low", thinking enabled (visible reasoning)
99+
// - "medium" → effort: "medium", thinking enabled
100+
// - "high" → effort: "high", thinking enabled
101+
const effortLevel = ANTHROPIC_EFFORT[effectiveThinking];
102+
const budgetTokens = ANTHROPIC_THINKING_BUDGETS[effectiveThinking];
98103
log.debug("buildProviderOptions: Anthropic Opus 4.5 config", {
99-
effort,
104+
effort: effortLevel,
105+
budgetTokens,
100106
thinkingLevel: effectiveThinking,
101107
});
102108

103109
const options: ProviderOptions = {
104110
anthropic: {
105111
disableParallelToolUse: false, // Always enable concurrent tool execution
106112
sendReasoning: true, // Include reasoning traces in requests sent to the model
113+
// Enable thinking to get visible reasoning traces (only when not "off")
114+
// budgetTokens sets the ceiling; effort controls how eagerly tokens are spent
115+
...(budgetTokens > 0 && {
116+
thinking: {
117+
type: "enabled",
118+
budgetTokens,
119+
},
120+
}),
107121
// Use effort parameter (Opus 4.5 only) to control token spend
108122
// SDK auto-adds beta header "effort-2025-11-24" when effort is set
109-
...(effort && { effort }),
123+
effort: effortLevel,
110124
},
111125
};
112126
log.debug("buildProviderOptions: Returning Anthropic Opus 4.5 options", options);

0 commit comments

Comments
 (0)