feat: add claude-opus-4-6 - #2863
Conversation
WalkthroughAdds Claude Opus 4-6 model variants across AWS, Vertex, and Claude channels, adds an OutputConfig passthrough to request DTOs, extends effort-suffix detection for adaptive thinking, and registers cache/model ratio entries for the new variants. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Relay as Relay (claude channel)
participant Handler as ClaudeHandler
participant Upstream as Upstream (AWS/Vertex)
Client->>Relay: Send request (model, maybe effort-suffix, optional output_config)
Relay->>Handler: RequestOpenAI2ClaudeMessage (includes model & OutputConfig)
Handler->>Handler: TrimEffortSuffix -> detect effortLevel?
alt effortLevel and model starts with "claude-opus-4-6"
Handler->>Upstream: Set base model, enable adaptive thinking, set OutputConfig, TopP=0, Temp=1.0
else ThinkingAdapterEnabled & model ends "-thinking"
Handler->>Upstream: Preserve thinking settings / adjust TopP/Temp
end
Upstream-->>Handler: Upstream response
Handler-->>Relay: Normalized response
Relay-->>Client: Return response
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
relay/channel/claude/relay-claude.go (1)
145-174:⚠️ Potential issue | 🟡 Minor
ReasoningEffort/Reasoningblocks can silently revert adaptive thinking to deprecated"enabled"mode.If a request targets
claude-opus-4-6-max(handled at lines 145–153, settingType: "adaptive"), but also carriesReasoningEffortorReasoning, lines 176–210 will overwriteclaudeRequest.ThinkingwithType: "enabled"and a fixedBudgetTokens. On Opus 4.6, type: "enabled" with budget_tokens is still accepted but deprecated, so this would silently downgrade the request.Consider guarding lines 176–210 to skip when adaptive thinking is already configured, e.g.:
if claudeRequest.Thinking == nil || claudeRequest.Thinking.Type != "adaptive" { // existing ReasoningEffort / Reasoning logic }Also applies to: 176-194
🤖 Fix all issues with AI agents
In `@relay/channel/aws/constants.go`:
- Line 19: The map entry for the key "claude-opus-4-6" in
relay/channel/aws/constants.go uses a malformed Bedrock model ID
("anthropic.claude-opus-4-6-v1") missing the snapshot date and the ":0" suffix;
update the value to the full Bedrock ID format
anthropic.claude-opus-4-6-<YYYYMMDD>-v1:0 (replace <YYYYMMDD> with the correct
Claude Opus 4.6 snapshot date) so it matches the pattern used by other entries
(e.g., anthropic.claude-opus-4-1-20250805-v1:0).
In `@relay/claude_handler.go`:
- Around line 54-61: The adaptive-thinking branch that trims the effort suffix
(when reasoning.TrimEffortSuffix returns ok and strings.HasPrefix(request.Model,
"claude-opus-4-6")) fails to reset request.TopP and request.Temperature, which
can propagate non-default values and cause Claude API errors; update that branch
in claude_handler.go (the block that sets request.Model, request.Thinking,
request.OutputConfig and info.UpstreamModelName) to explicitly set request.TopP
= 0 and request.Temperature = 1.0 alongside the existing changes so adaptive
requests use the expected defaults.
In `@setting/reasoning/suffix.go`:
- Line 9: The three callers that invoke TrimEffortSuffix need the same
model-prefix guard used in the Claude handlers: before calling TrimEffortSuffix,
add a check like strings.HasPrefix(model, "claude-opus-4-6") (or the appropriate
provider-specific prefix) so you only strip the new "-max" suffix for Claude
Opus 4.6; update the call sites referenced (the Vertex adaptor call, the Gemini
relay call, and the Gemini adaptor call) to wrap their TrimEffortSuffix(model)
invocation in a conditional that first verifies the model string prefix, using
the existing pattern from the Claude handlers to avoid stripping "-max" from
unrelated models.
🧹 Nitpick comments (2)
relay/claude_handler.go (1)
60-60: Consider usingjson.Marshalinstead of string interpolation for JSON construction.While
effortLevelis currently constrained to the predefined suffix list (safe values), building JSON viafmt.Sprintfis fragile if the suffix set ever expands to include characters requiring escaping.♻️ Safer alternative
- request.OutputConfig = json.RawMessage(fmt.Sprintf(`{"effort":"%s"}`, effortLevel)) + effortConfig, _ := json.Marshal(map[string]string{"effort": effortLevel}) + request.OutputConfig = json.RawMessage(effortConfig)relay/channel/claude/relay-claude.go (1)
145-153: Duplicated adaptive-thinking logic across two files.The adaptive-thinking block is nearly identical in
relay/claude_handler.go(lines 54–61) and here. Different request types make direct extraction non-trivial, but consider a small shared helper (e.g., returning the resolved model name, effort level, and a boolean) to keep the condition and model-prefix check in one place, reducing the risk of the two paths drifting apart (as already evidenced by the missing TopP/Temperature bug inclaude_handler.go).
| "claude-sonnet-4-5-20250929": "anthropic.claude-sonnet-4-5-20250929-v1:0", | ||
| "claude-haiku-4-5-20251001": "anthropic.claude-haiku-4-5-20251001-v1:0", | ||
| "claude-opus-4-5-20251101": "anthropic.claude-opus-4-5-20251101-v1:0", | ||
| "claude-opus-4-6": "anthropic.claude-opus-4-6-v1", |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
AWS Bedrock claude-opus-4-6 model ID format anthropic
💡 Result:
AWS Bedrock Anthropic Claude model IDs use this pattern:
- Base model ID:
anthropic.claude-opus-<major>-<minor>-<YYYYMMDD>-v1:0(e.g.,anthropic.claude-opus-4-1-20250805-v1:0,anthropic.claude-opus-4-5-20251101-v1:0) [2] - Cross‑region inference profile prefixes (when available):
global./us./eu./jp./apac.+ the base model ID (as shown in Anthropic’s Bedrock table) [2]
For Claude Opus 4.6, AWS announced it became available in Bedrock on Feb 5, 2026, but the exact Bedrock model ID string (including the <YYYYMMDD> snapshot) isn’t shown in the public tables I found yet [1][2]. The reliable way to get the exact ID in your region is to list models from Bedrock:
aws bedrock list-foundation-models --by-provider anthropic --query "modelSummaries[*].modelId" --region <your-region>AWS Bedrock model ID is malformed — missing both snapshot date and version suffix.
According to AWS Bedrock documentation, Anthropic Claude model IDs follow the pattern anthropic.claude-opus-<major>-<minor>-<YYYYMMDD>-v1:0. The entry "anthropic.claude-opus-4-6-v1" is missing both the snapshot date (<YYYYMMDD>) and the :0 version suffix. All other Claude models in this map include these components (e.g., anthropic.claude-opus-4-1-20250805-v1:0). The malformed ID will fail API calls to AWS Bedrock. Update to the correct format with the appropriate snapshot date for Claude Opus 4.6.
🤖 Prompt for AI Agents
In `@relay/channel/aws/constants.go` at line 19, The map entry for the key
"claude-opus-4-6" in relay/channel/aws/constants.go uses a malformed Bedrock
model ID ("anthropic.claude-opus-4-6-v1") missing the snapshot date and the ":0"
suffix; update the value to the full Bedrock ID format
anthropic.claude-opus-4-6-<YYYYMMDD>-v1:0 (replace <YYYYMMDD> with the correct
Claude Opus 4.6 snapshot date) so it matches the pattern used by other entries
(e.g., anthropic.claude-opus-4-1-20250805-v1:0).
| if baseModel, effortLevel, ok := reasoning.TrimEffortSuffix(request.Model); ok && effortLevel != "" && | ||
| strings.HasPrefix(request.Model, "claude-opus-4-6") { | ||
| request.Model = baseModel | ||
| request.Thinking = &dto.Thinking{ | ||
| Type: "adaptive", | ||
| } | ||
| request.OutputConfig = json.RawMessage(fmt.Sprintf(`{"effort":"%s"}`, effortLevel)) | ||
| info.UpstreamModelName = request.Model |
There was a problem hiding this comment.
Bug: Missing TopP and Temperature reset for adaptive thinking.
The parallel code in relay/channel/claude/relay-claude.go (lines 152–153) resets TopP = 0 and Temperature = 1.0 for the adaptive thinking branch, matching the existing -thinking branch in this file (lines 77–78). This branch omits those resets, which can cause Claude API errors if the incoming request carries non-default values.
🐛 Proposed fix
if baseModel, effortLevel, ok := reasoning.TrimEffortSuffix(request.Model); ok && effortLevel != "" &&
strings.HasPrefix(request.Model, "claude-opus-4-6") {
request.Model = baseModel
request.Thinking = &dto.Thinking{
Type: "adaptive",
}
request.OutputConfig = json.RawMessage(fmt.Sprintf(`{"effort":"%s"}`, effortLevel))
+ request.TopP = 0
+ request.Temperature = common.GetPointer[float64](1.0)
info.UpstreamModelName = request.Model📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if baseModel, effortLevel, ok := reasoning.TrimEffortSuffix(request.Model); ok && effortLevel != "" && | |
| strings.HasPrefix(request.Model, "claude-opus-4-6") { | |
| request.Model = baseModel | |
| request.Thinking = &dto.Thinking{ | |
| Type: "adaptive", | |
| } | |
| request.OutputConfig = json.RawMessage(fmt.Sprintf(`{"effort":"%s"}`, effortLevel)) | |
| info.UpstreamModelName = request.Model | |
| if baseModel, effortLevel, ok := reasoning.TrimEffortSuffix(request.Model); ok && effortLevel != "" && | |
| strings.HasPrefix(request.Model, "claude-opus-4-6") { | |
| request.Model = baseModel | |
| request.Thinking = &dto.Thinking{ | |
| Type: "adaptive", | |
| } | |
| request.OutputConfig = json.RawMessage(fmt.Sprintf(`{"effort":"%s"}`, effortLevel)) | |
| request.TopP = 0 | |
| request.Temperature = common.GetPointer[float64](1.0) | |
| info.UpstreamModelName = request.Model |
🤖 Prompt for AI Agents
In `@relay/claude_handler.go` around lines 54 - 61, The adaptive-thinking branch
that trims the effort suffix (when reasoning.TrimEffortSuffix returns ok and
strings.HasPrefix(request.Model, "claude-opus-4-6")) fails to reset request.TopP
and request.Temperature, which can propagate non-default values and cause Claude
API errors; update that branch in claude_handler.go (the block that sets
request.Model, request.Thinking, request.OutputConfig and
info.UpstreamModelName) to explicitly set request.TopP = 0 and
request.Temperature = 1.0 alongside the existing changes so adaptive requests
use the expected defaults.
| ) | ||
|
|
||
| var EffortSuffixes = []string{"-high", "-medium", "-low", "-minimal"} | ||
| var EffortSuffixes = []string{"-max", "-high", "-medium", "-low", "-minimal"} |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
rg -n --type=go 'TrimEffortSuffix' -B 5 -A 5Repository: QuantumNous/new-api
Length of output: 5151
Add model-prefix guards to three additional callers of TrimEffortSuffix that lack them.
Adding -max to EffortSuffixes is correct for Claude Opus 4.6, which has four effort levels. However, both Claude handler call sites properly guard with strings.HasPrefix(model, "claude-opus-4-6"), while three other callers do not:
relay/channel/vertex/adaptor.go:219(Vertex)relay/channel/gemini/relay-gemini.go:187(Gemini relay)relay/channel/gemini/adaptor.go:141(Gemini adaptor)
These unguarded sites will now strip -max from any model name ending in -max, risking incorrect behavior for other providers (e.g., hypothetical gpt-4o-max in Gemini). Add model-provider checks similar to the Claude guards.
🤖 Prompt for AI Agents
In `@setting/reasoning/suffix.go` at line 9, The three callers that invoke
TrimEffortSuffix need the same model-prefix guard used in the Claude handlers:
before calling TrimEffortSuffix, add a check like strings.HasPrefix(model,
"claude-opus-4-6") (or the appropriate provider-specific prefix) so you only
strip the new "-max" suffix for Claude Opus 4.6; update the call sites
referenced (the Vertex adaptor call, the Gemini relay call, and the Gemini
adaptor call) to wrap their TrimEffortSuffix(model) invocation in a conditional
that first verifies the model string prefix, using the existing pattern from the
Claude handlers to avoid stripping "-max" from unrelated models.
feat: add claude-opus-4-6
Add:
Based on https://platform.claude.com/docs/en/build-with-claude/adaptive-thinking:
Summary by CodeRabbit
New Features
Performance / Tuning
Behavior