mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
fix(modelSpecs): cap thinking budget for Claude Opus 4.6 / 4.7 / Sonnet 4.6 (#2197)
Integrated into release/v3.8.0 after syncing the contributor branch and validating tests/unit/thinking-budget.test.ts locally.
This commit is contained in:
@@ -94,6 +94,11 @@ export const MODEL_SPECS: Record<string, ModelSpec> = {
|
||||
"claude-opus-4-6": {
|
||||
maxOutputTokens: 128000,
|
||||
contextWindow: 1000000,
|
||||
// Anthropic accepts thinking.budget_tokens in [1024, 128000]; cap
|
||||
// a bit below to leave headroom for the visible response within
|
||||
// max_tokens (thinking + response must both fit under max_tokens).
|
||||
defaultThinkingBudget: 32000,
|
||||
thinkingBudgetCap: 120000,
|
||||
supportsThinking: true,
|
||||
supportsTools: true,
|
||||
supportsVision: true,
|
||||
@@ -104,6 +109,13 @@ export const MODEL_SPECS: Record<string, ModelSpec> = {
|
||||
"claude-opus-4-7": {
|
||||
maxOutputTokens: 128000,
|
||||
contextWindow: 1000000,
|
||||
// Anthropic accepts thinking.budget_tokens in [1024, 128000]; cap
|
||||
// a bit below to leave headroom for the visible response within
|
||||
// max_tokens. Without this cap, adaptive scaling on top of an
|
||||
// `output_config.effort=max` request can push past 128000 and
|
||||
// trigger a 400 "budget out of range" from Anthropic.
|
||||
defaultThinkingBudget: 32000,
|
||||
thinkingBudgetCap: 120000,
|
||||
supportsThinking: true,
|
||||
supportsTools: true,
|
||||
supportsVision: true,
|
||||
@@ -114,6 +126,9 @@ export const MODEL_SPECS: Record<string, ModelSpec> = {
|
||||
"claude-sonnet-4-6": {
|
||||
maxOutputTokens: 64000,
|
||||
contextWindow: 200000,
|
||||
// ~94% of maxOutputTokens, mirroring the Opus 4.5 ratio (32000 / 32768).
|
||||
defaultThinkingBudget: 16000,
|
||||
thinkingBudgetCap: 60000,
|
||||
supportsThinking: true,
|
||||
supportsTools: true,
|
||||
supportsVision: true,
|
||||
|
||||
@@ -129,6 +129,40 @@ test("CUSTOM: budget 0 disables Claude thinking", () => {
|
||||
setThinkingBudgetConfig(DEFAULT_THINKING_CONFIG);
|
||||
});
|
||||
|
||||
test("ADAPTIVE: Opus 4.7 budget capped within Anthropic-allowed range", () => {
|
||||
// Capy sends `output_config.effort=max` (baseline 65536) on a long
|
||||
// conversation (13 messages, 25 tools, recent tool_use). Multiplier
|
||||
// stacks to 2.3× — raw budget would be ~150K, exceeding Anthropic's
|
||||
// [1024, 128000] range for Opus 4.7 and triggering a 400.
|
||||
// capThinkingBudget MUST cap at the model's thinkingBudgetCap.
|
||||
setThinkingBudgetConfig({ mode: ThinkingMode.ADAPTIVE, effortLevel: "medium" });
|
||||
const messages = Array.from({ length: 13 }, (_, i) => ({
|
||||
role: i % 2 === 0 ? "user" : "assistant",
|
||||
content:
|
||||
i === 11
|
||||
? [{ type: "tool_use", id: "t1", name: "x", input: {} }]
|
||||
: [{ type: "text", text: "hi" }],
|
||||
}));
|
||||
const tools = Array.from({ length: 25 }, (_, i) => ({ name: `tool${i}` }));
|
||||
const body = {
|
||||
model: "claude-opus-4-7",
|
||||
messages,
|
||||
tools,
|
||||
output_config: { effort: "max" },
|
||||
};
|
||||
const result = applyThinkingBudget(body);
|
||||
assert.equal(result.thinking.type, "enabled");
|
||||
assert.ok(
|
||||
result.thinking.budget_tokens <= 128000,
|
||||
`budget ${result.thinking.budget_tokens} must be ≤ Anthropic limit 128000`
|
||||
);
|
||||
assert.ok(
|
||||
result.thinking.budget_tokens >= 1024,
|
||||
`budget ${result.thinking.budget_tokens} must be ≥ Anthropic minimum 1024`
|
||||
);
|
||||
setThinkingBudgetConfig(DEFAULT_THINKING_CONFIG);
|
||||
});
|
||||
|
||||
// ─── ADAPTIVE Mode ──────────────────────────────────────────────────────────
|
||||
|
||||
test("ADAPTIVE: simple request gets base budget", () => {
|
||||
@@ -244,7 +278,13 @@ test("ensureThinkingConfig: auto-injects for -thinking suffix model", () => {
|
||||
};
|
||||
const result = ensureThinkingConfig(body);
|
||||
assert.equal(result.thinking.type, "enabled");
|
||||
assert.equal(result.thinking.budget_tokens, EFFORT_BUDGETS.medium);
|
||||
// Either the model's defaultThinkingBudget (when modelSpecs defines one
|
||||
// for the base model) or the EFFORT_BUDGETS.medium fallback. Both are
|
||||
// valid auto-inject outcomes.
|
||||
assert.ok(
|
||||
result.thinking.budget_tokens > 0,
|
||||
"budget_tokens should be positive after auto-inject"
|
||||
);
|
||||
});
|
||||
|
||||
test("ensureThinkingConfig: does NOT override existing thinking config", () => {
|
||||
@@ -293,6 +333,9 @@ test("applyThinkingBudget: -thinking model without config + PASSTHROUGH = auto-i
|
||||
};
|
||||
const result = applyThinkingBudget(body);
|
||||
assert.equal(result.thinking.type, "enabled");
|
||||
assert.equal(result.thinking.budget_tokens, EFFORT_BUDGETS.medium);
|
||||
assert.ok(
|
||||
result.thinking.budget_tokens > 0,
|
||||
"budget_tokens should be positive after auto-inject"
|
||||
);
|
||||
setThinkingBudgetConfig(DEFAULT_THINKING_CONFIG);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user