-
Notifications
You must be signed in to change notification settings - Fork 190
feat(models): adaptive thinking for Opus 4.6 #2550
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2ad1ec7
930f8c2
3661db4
b981be5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| import { describe, expect, test } from "vitest"; | ||
|
|
||
| import { prepareRequestBody } from "./prepare-request-body.js"; | ||
|
|
||
| interface AdaptiveThinkingBody { | ||
| thinking?: { type: "adaptive" | "enabled"; budget_tokens?: number }; | ||
| output_config?: { | ||
| effort?: "low" | "medium" | "high" | "xhigh" | "max"; | ||
| }; | ||
| } | ||
|
|
||
| // Regression test for adaptive thinking. Anthropic models with | ||
| // `reasoningMode: "adaptive"` (Opus 4.6/4.7/4.8) must build | ||
| // `thinking: { type: "adaptive" }` rather than the legacy | ||
| // `thinking: { type: "enabled", budget_tokens }` form when reasoning is | ||
| // requested, with depth conveyed via `output_config.effort`. | ||
|
|
||
| async function buildAnthropicBody( | ||
| internalModel: string, | ||
| opts: { | ||
| reasoning_effort?: "low" | "medium" | "high" | "xhigh"; | ||
| reasoning_max_tokens?: number; | ||
| }, | ||
| ): Promise<AdaptiveThinkingBody> { | ||
| return (await prepareRequestBody( | ||
| "anthropic", | ||
| internalModel, | ||
| null, | ||
| internalModel, | ||
| [ | ||
| { | ||
| role: "user", | ||
| content: "Explain why the sum of two even numbers is always even.", | ||
| }, | ||
| ], | ||
| false, // stream | ||
| undefined, // temperature | ||
| undefined, // max_tokens | ||
| undefined, // top_p | ||
| undefined, // frequency_penalty | ||
| undefined, // presence_penalty | ||
| undefined, // response_format | ||
| undefined, // tools | ||
| undefined, // tool_choice | ||
| opts.reasoning_effort, // reasoning_effort | ||
| true, // supportsReasoning | ||
| false, // isProd | ||
| 20, // maxImageSizeMB | ||
| null, // userPlan | ||
| undefined, // sensitive_word_check | ||
| undefined, // image_config | ||
| undefined, // effort | ||
| undefined, // imageGenerations | ||
| undefined, // webSearchTool | ||
| opts.reasoning_max_tokens, // reasoning_max_tokens | ||
| )) as AdaptiveThinkingBody; | ||
| } | ||
|
|
||
| describe("prepareRequestBody - adaptive thinking (Opus 4.6/4.7/4.8)", () => { | ||
| for (const model of [ | ||
| "claude-opus-4-6", | ||
| "claude-opus-4-7", | ||
| "claude-opus-4-8", | ||
| ]) { | ||
| test(`${model} builds thinking: { type: "adaptive" } with effort`, async () => { | ||
| const body = await buildAnthropicBody(model, { | ||
| reasoning_effort: "high", | ||
| }); | ||
| expect(body.thinking).toEqual({ type: "adaptive" }); | ||
| expect(body.output_config?.effort).toBe("high"); | ||
| }); | ||
| } | ||
|
|
||
| test("Opus 4.6 routes reasoning.max_tokens to adaptive (drops budget_tokens)", async () => { | ||
| const body = await buildAnthropicBody("claude-opus-4-6", { | ||
| reasoning_max_tokens: 8000, | ||
| }); | ||
| expect(body.thinking).toEqual({ type: "adaptive" }); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -962,7 +962,8 @@ export const anthropicModels = [ | |
| contextSize: 1000000, | ||
| maxOutput: 128000, | ||
| reasoning: true, | ||
| reasoningMaxTokens: true, | ||
| reasoningMode: "adaptive", | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For Anthropic/Vertex Opus 4.6 requests that combine Useful? React with 👍 / 👎. |
||
| reasoningOutput: "omit", | ||
| streaming: true, | ||
| vision: true, | ||
| tools: true, | ||
|
|
@@ -985,7 +986,8 @@ export const anthropicModels = [ | |
| contextSize: 1000000, | ||
| maxOutput: 128000, | ||
| reasoning: true, | ||
| reasoningMaxTokens: true, | ||
| reasoningMode: "adaptive", | ||
| reasoningOutput: "omit", | ||
| streaming: true, | ||
| vision: true, | ||
| tools: true, | ||
|
|
@@ -1003,7 +1005,8 @@ export const anthropicModels = [ | |
| contextSize: 1000000, | ||
| maxOutput: 128000, | ||
| reasoning: true, | ||
| reasoningMaxTokens: true, | ||
| reasoningMode: "adaptive", | ||
| reasoningOutput: "omit", | ||
| streaming: true, | ||
| vision: true, | ||
| tools: true, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adaptive thinking can skip emitting reasoning text, but leaving
reasoningOutputundefined means the model metadata says reasoning output is expected by default (seeProviderModelMappingdocs), and the gateway reasoning e2e checks use that flag. The existing Opus 4.7/4.8 adaptive mappings setreasoningOutput: "omit"for this reason; without the same setting here, 4.6 requests/tests that inspect the metadata can fail whenever the model chooses not to produce a thinking block.Useful? React with 👍 / 👎.