mirror of
https://github.com/coder/coder.git
synced 2026-10-16 14:48:56 +08:00
fix(aibridge/intercept/messages): treat Bedrock Opus 5, Haiku 5.5, Fable 5, and Mythos 5 as adaptive-only (#30692)
Bedrock rejects `thinking.type: "enabled"` with `budget_tokens` for Claude Opus 5, Haiku 5.5, Fable 5, and Mythos 5 ([AWS adaptive thinking docs](https://docs.aws.amazon.com/bedrock/latest/userguide/claude-messages-adaptive-thinking.html)). AI Gateway didn't recognize these models as adaptive-only, so it rewrote adaptive thinking to the `enabled` shape and stripped `output_config.effort`. That broke reasoning effort for all of them. `bedrockModelRequiresAdaptiveThinking` now matches `anthropic.claude-opus-5` (which also covers Opus 5.5, the same way `anthropic.claude-sonnet-5` covers Sonnet 5.5), `anthropic.claude-haiku-5-5`, `anthropic.claude-fable-5`, and `anthropic.claude-mythos-5` (the last two also cover their 5.1 releases). Mythos Preview accepts both thinking modes, so it isn't matched. Each model group has two commits: the first adds test cases that pin the current broken behavior, and the second applies the fix and flips the test expectations, so the behavior change shows up in the test diff. Fixes AIGOV-704 <details> <summary>Decision log</summary> - This is the same class of bug as #25335 (Opus 4.7), #26691 (Opus 4.8), #27339 (Sonnet 5) and #29762 (Opus 5.5). Each time, a new model was missing from the substring allowlist. This PR follows the same minimal pattern. Moving capability detection into the model catalog is left as a follow-up. - Chatd's `anthropicReasoningEffort` maps effort `none` to `low` only for Opus 5.5 and Sonnet 5.5, and is intentionally unchanged. Per the Anthropic and AWS docs, Opus 5 and Haiku 5.5 still accept `thinking: {type: "disabled"}` at effort `high` or below, so sending `none` (which becomes `disabled`) is valid for them. - Adaptive-only models also get `output_config.format` stripped. That matches the docs: structured outputs aren't available for Haiku 5.5 on Bedrock. </details> > [!NOTE] > Generated by Coder Agents on behalf of @dannykopping.
This commit is contained in:
@@ -724,14 +724,19 @@ func bedrockModelSupportsAdaptiveThinking(model string) bool {
|
||||
|
||||
// bedrockModelRequiresAdaptiveThinking returns true if the given Bedrock model
|
||||
// ID only supports the "adaptive" thinking type and rejects the legacy
|
||||
// "enabled" + budget_tokens shape with a 400.
|
||||
// "enabled" + budget_tokens shape with a 400. The Opus 5, Sonnet 5, Fable 5,
|
||||
// and Mythos 5 prefixes also match their point releases.
|
||||
//
|
||||
// See https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-opus-4-7.html
|
||||
// and https://docs.aws.amazon.com/bedrock/latest/userguide/claude-messages-adaptive-thinking.html
|
||||
func bedrockModelRequiresAdaptiveThinking(model string) bool {
|
||||
return strings.Contains(model, "anthropic.claude-opus-4-7") ||
|
||||
strings.Contains(model, "anthropic.claude-opus-4-8") ||
|
||||
strings.Contains(model, "anthropic.claude-opus-5-5") ||
|
||||
strings.Contains(model, "anthropic.claude-sonnet-5")
|
||||
strings.Contains(model, "anthropic.claude-opus-5") ||
|
||||
strings.Contains(model, "anthropic.claude-sonnet-5") ||
|
||||
strings.Contains(model, "anthropic.claude-haiku-5-5") ||
|
||||
strings.Contains(model, "anthropic.claude-fable-5") ||
|
||||
strings.Contains(model, "anthropic.claude-mythos-5")
|
||||
}
|
||||
|
||||
// filterBedrockBetaFlags removes unsupported beta flags from the Anthropic-Beta
|
||||
|
||||
@@ -970,6 +970,62 @@ func TestAugmentRequestForBedrock_AdaptiveThinking(t *testing.T) {
|
||||
expectEffort: "low",
|
||||
expectKeptFields: []string{"output_config"},
|
||||
},
|
||||
{
|
||||
name: "opus_5_model_with_enabled_thinking_is_converted_to_adaptive_and_drops_budget",
|
||||
bedrockModel: "anthropic.claude-opus-5",
|
||||
requestBody: `{"max_tokens":10000,"thinking":{"type":"enabled","budget_tokens":5000}}`,
|
||||
expectThinkingType: "adaptive",
|
||||
},
|
||||
{
|
||||
name: "global_opus_5_model_keeps_adaptive_thinking_and_output_config_effort",
|
||||
bedrockModel: "global.anthropic.claude-opus-5",
|
||||
requestBody: `{"max_tokens":10000,"thinking":{"type":"adaptive"},"output_config":{"effort":"medium"}}`,
|
||||
expectThinkingType: "adaptive",
|
||||
expectEffort: "medium",
|
||||
expectKeptFields: []string{"output_config"},
|
||||
},
|
||||
{
|
||||
name: "haiku_5_5_model_with_enabled_thinking_is_converted_to_adaptive_and_drops_budget",
|
||||
bedrockModel: "anthropic.claude-haiku-5-5",
|
||||
requestBody: `{"max_tokens":10000,"thinking":{"type":"enabled","budget_tokens":5000}}`,
|
||||
expectThinkingType: "adaptive",
|
||||
},
|
||||
{
|
||||
name: "regional_haiku_5_5_model_keeps_adaptive_thinking_and_output_config_effort",
|
||||
bedrockModel: "us.anthropic.claude-haiku-5-5",
|
||||
requestBody: `{"max_tokens":10000,"thinking":{"type":"adaptive"},"output_config":{"effort":"low"}}`,
|
||||
expectThinkingType: "adaptive",
|
||||
expectEffort: "low",
|
||||
expectKeptFields: []string{"output_config"},
|
||||
},
|
||||
{
|
||||
name: "fable_5_model_with_enabled_thinking_is_converted_to_adaptive_and_drops_budget",
|
||||
bedrockModel: "anthropic.claude-fable-5",
|
||||
requestBody: `{"max_tokens":10000,"thinking":{"type":"enabled","budget_tokens":5000}}`,
|
||||
expectThinkingType: "adaptive",
|
||||
},
|
||||
{
|
||||
name: "global_fable_5_1_model_keeps_adaptive_thinking_and_output_config_effort",
|
||||
bedrockModel: "global.anthropic.claude-fable-5-1",
|
||||
requestBody: `{"max_tokens":10000,"thinking":{"type":"adaptive"},"output_config":{"effort":"high"}}`,
|
||||
expectThinkingType: "adaptive",
|
||||
expectEffort: "high",
|
||||
expectKeptFields: []string{"output_config"},
|
||||
},
|
||||
{
|
||||
name: "mythos_5_model_with_enabled_thinking_is_converted_to_adaptive_and_drops_budget",
|
||||
bedrockModel: "anthropic.claude-mythos-5",
|
||||
requestBody: `{"max_tokens":10000,"thinking":{"type":"enabled","budget_tokens":5000}}`,
|
||||
expectThinkingType: "adaptive",
|
||||
},
|
||||
{
|
||||
name: "global_mythos_5_1_model_keeps_adaptive_thinking_and_output_config_effort",
|
||||
bedrockModel: "global.anthropic.claude-mythos-5-1",
|
||||
requestBody: `{"max_tokens":10000,"thinking":{"type":"adaptive"},"output_config":{"effort":"high"}}`,
|
||||
expectThinkingType: "adaptive",
|
||||
expectEffort: "high",
|
||||
expectKeptFields: []string{"output_config"},
|
||||
},
|
||||
{
|
||||
// Opus 4.7 on Bedrock rejects output_config.format (structured
|
||||
// outputs) with a 400 even though it accepts output_config.effort.
|
||||
|
||||
Reference in New Issue
Block a user