From 149bb478abfc9131e7d05f5e0baa6a1855ef01df Mon Sep 17 00:00:00 2001 From: Rayan Salhab Date: Sun, 2 Aug 2026 09:59:22 +0300 Subject: [PATCH] fix(providers): omit temperature for Claude 5 (#1494) Co-authored-by: cyphercodes --- internal/providers/adapter_anthropic_test.go | 11 ++++++-- internal/providers/anthropic_request.go | 29 +++++++++++++------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/internal/providers/adapter_anthropic_test.go b/internal/providers/adapter_anthropic_test.go index 901b3d5f..f1b90e46 100644 --- a/internal/providers/adapter_anthropic_test.go +++ b/internal/providers/adapter_anthropic_test.go @@ -150,10 +150,16 @@ func TestAnthropicAdapterToRequest_Thinking(t *testing.T) { } } -func TestAnthropicAdapterToRequest_SkipsTemperatureForClaude46(t *testing.T) { +func TestAnthropicAdapterToRequest_SkipsTemperatureForClaude46AndNewer(t *testing.T) { adapter, _ := NewAnthropicAdapter(ProviderConfig{APIKey: "sk-test"}) - for _, model := range []string{"claude-opus-4-6", "claude-sonnet-4-6", "claude-opus-4-7-20260501"} { + for _, model := range []string{ + "claude-opus-4-6", + "claude-sonnet-4-6", + "claude-opus-4-7-20260501", + "claude-opus-5", + "claude-sonnet-5", + } { t.Run(model, func(t *testing.T) { req := ChatRequest{ Model: model, @@ -371,4 +377,3 @@ func TestAnthropicAdapterToRequest_NativeToolIgnored(t *testing.T) { t.Errorf("expected tool name 'web_search', got %v", tool["name"]) } } - diff --git a/internal/providers/anthropic_request.go b/internal/providers/anthropic_request.go index 237ff301..1d61be8a 100644 --- a/internal/providers/anthropic_request.go +++ b/internal/providers/anthropic_request.go @@ -2,6 +2,7 @@ package providers import ( "encoding/json" + "strconv" "strings" ) @@ -242,23 +243,31 @@ func (p *AnthropicProvider) buildRequestBody(model string, req ChatRequest, stre } // anthropicSkipsTemperature reports whether the Messages API rejects sampling -// parameters for this model. Claude Opus/Sonnet 4.6+ and Opus 4.7+ return HTTP -// 400 when temperature (and top_p/top_k) are included; omit them entirely. +// parameters for this model. Claude Opus/Sonnet 4.6+ return HTTP 400 when +// temperature (and top_p/top_k) are included; omit them entirely. func anthropicSkipsTemperature(model string) bool { m := strings.ToLower(model) - for _, family := range []string{"claude-opus-4-", "claude-sonnet-4-"} { + for _, family := range []string{"claude-opus-", "claude-sonnet-"} { after, ok := strings.CutPrefix(m, family) if !ok { continue } - minor := 0 - for _, c := range after { - if c < '0' || c > '9' { - break - } - minor = minor*10 + int(c-'0') + + majorPart, afterMajor, hasMinor := strings.Cut(after, "-") + major, err := strconv.Atoi(majorPart) + if err != nil { + continue } - if minor >= 6 { + if major > 4 { + return true + } + if major < 4 || !hasMinor { + continue + } + + minorPart, _, _ := strings.Cut(afterMajor, "-") + minor, err := strconv.Atoi(minorPart) + if err == nil && minor >= 6 { return true } }