Merge pull request #2982 from loafoe/fix/bedrock-opus48-temperature

fix(bedrock): drop temperature for models that deprecate it (Opus 4.8)
This commit is contained in:
Mauro 2026-06-01 13:02:18 +02:00 committed by GitHub
commit 1cfa781925
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 71 additions and 6 deletions

View file

@ -143,7 +143,22 @@ type converseParams struct {
toolConfig *types.ToolConfiguration toolConfig *types.ToolConfiguration
} }
func buildConverseParams(messages []Message, tools []ToolDefinition, options map[string]any) converseParams { // modelDeprecatesTemperature reports whether the given Bedrock model rejects the
// temperature inference parameter. Newer Claude models (Opus 4.8 and later) treat
// temperature as deprecated and return a ValidationException if it is supplied:
//
// ValidationException: The model returned the following errors:
// temperature is deprecated for this model.
//
// The match is intentionally loose: Bedrock model IDs and inference-profile ARNs
// embed the model name (e.g. "us.anthropic.claude-opus-4-8-20260514-v1:0"), so a
// substring check covers both bare IDs and region-prefixed inference profiles.
func modelDeprecatesTemperature(model string) bool {
m := strings.ToLower(model)
return strings.Contains(m, "claude-opus-4-8")
}
func buildConverseParams(messages []Message, tools []ToolDefinition, model string, options map[string]any) converseParams {
bedrockMessages, systemPrompts := convertMessages(messages) bedrockMessages, systemPrompts := convertMessages(messages)
var inferenceConfig *types.InferenceConfiguration var inferenceConfig *types.InferenceConfiguration
@ -159,10 +174,14 @@ func buildConverseParams(messages []Message, tools []ToolDefinition, options map
} }
if temp, ok := common.AsFloat(options["temperature"]); ok { if temp, ok := common.AsFloat(options["temperature"]); ok {
if inferenceConfig == nil { if modelDeprecatesTemperature(model) {
inferenceConfig = &types.InferenceConfiguration{} log.Printf("bedrock: temperature dropped because model %q no longer supports it", model)
} else {
if inferenceConfig == nil {
inferenceConfig = &types.InferenceConfiguration{}
}
inferenceConfig.Temperature = aws.Float32(float32(temp))
} }
inferenceConfig.Temperature = aws.Float32(float32(temp))
} }
var toolConfig *types.ToolConfiguration var toolConfig *types.ToolConfiguration
@ -199,7 +218,7 @@ func (p *Provider) Chat(
defer cancel() defer cancel()
} }
params := buildConverseParams(messages, tools, options) params := buildConverseParams(messages, tools, model, options)
input := &bedrockruntime.ConverseInput{ input := &bedrockruntime.ConverseInput{
ModelId: aws.String(model), ModelId: aws.String(model),
Messages: params.messages, Messages: params.messages,
@ -242,7 +261,7 @@ func (p *Provider) ChatStream(
} }
} }
params := buildConverseParams(messages, tools, options) params := buildConverseParams(messages, tools, model, options)
input := &bedrockruntime.ConverseStreamInput{ input := &bedrockruntime.ConverseStreamInput{
ModelId: aws.String(model), ModelId: aws.String(model),
Messages: params.messages, Messages: params.messages,

View file

@ -875,3 +875,49 @@ func TestParseStreamResponse_StopReasons(t *testing.T) {
}) })
} }
} }
func TestModelDeprecatesTemperature(t *testing.T) {
tests := []struct {
name string
model string
want bool
}{
{"opus 4.8 bare id", "claude-opus-4-8-20260514-v1:0", true},
{"opus 4.8 inference profile", "us.anthropic.claude-opus-4-8-20260514-v1:0", true},
{"opus 4.8 mixed case", "US.Anthropic.Claude-Opus-4-8", true},
{"opus 4.7 unaffected", "us.anthropic.claude-opus-4-7-20250101-v1:0", false},
{"sonnet unaffected", "us.anthropic.claude-sonnet-4-6", false},
{"empty", "", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, modelDeprecatesTemperature(tt.model))
})
}
}
func TestBuildConverseParams_DropsTemperatureForDeprecatedModel(t *testing.T) {
options := map[string]any{
"temperature": 0.7,
"max_tokens": 1024,
}
params := buildConverseParams(nil, nil, "us.anthropic.claude-opus-4-8-20260514-v1:0", options)
require.NotNil(t, params.inferenceConfig, "max_tokens should still populate inference config")
assert.Nil(t, params.inferenceConfig.Temperature, "temperature must be omitted for opus 4.8")
require.NotNil(t, params.inferenceConfig.MaxTokens)
assert.Equal(t, int32(1024), *params.inferenceConfig.MaxTokens)
}
func TestBuildConverseParams_KeepsTemperatureForSupportedModel(t *testing.T) {
options := map[string]any{
"temperature": 0.7,
}
params := buildConverseParams(nil, nil, "us.anthropic.claude-opus-4-7-20250101-v1:0", options)
require.NotNil(t, params.inferenceConfig)
require.NotNil(t, params.inferenceConfig.Temperature)
assert.InDelta(t, 0.7, float64(*params.inferenceConfig.Temperature), 0.0001)
}