fix(providers): avoid /responses for namespaced compat models

Only explicit OpenAI configs now opt into /responses so namespaced compatible backends stay on chat/completions without extra fallback noise.
This commit is contained in:
Equent 2026-03-08 12:22:33 +08:00
parent 1655561ac8
commit 14b7089e62
2 changed files with 8 additions and 8 deletions

View file

@ -423,12 +423,12 @@ func requestTemperature(model string, options map[string]any) (float64, bool) {
// shouldPreferResponses centralizes the opt-in rule so OpenAI-native configs // shouldPreferResponses centralizes the opt-in rule so OpenAI-native configs
// and gpt-5 models can try /responses first while other compat backends keep // and gpt-5 models can try /responses first while other compat backends keep
// their existing chat/completions behavior. // their existing chat/completions behavior even when model IDs are namespaced.
func shouldPreferResponses(rawModel, normalizedModel string, preferOpenAIModels bool) bool { func shouldPreferResponses(rawModel, normalizedModel string, preferOpenAIModels bool) bool {
rawModel = strings.ToLower(strings.TrimSpace(rawModel)) rawModel = strings.ToLower(strings.TrimSpace(rawModel))
normalizedModel = strings.ToLower(strings.TrimSpace(normalizedModel)) normalizedModel = strings.ToLower(strings.TrimSpace(normalizedModel))
return preferOpenAIModels || strings.HasPrefix(rawModel, "openai/") || return preferOpenAIModels ||
strings.HasPrefix(rawModel, "gpt-5") || strings.HasPrefix(rawModel, "gpt-5") ||
strings.HasPrefix(normalizedModel, "gpt-5") strings.HasPrefix(normalizedModel, "gpt-5")
} }

View file

@ -16,7 +16,7 @@ import (
"github.com/sipeed/picoclaw/pkg/providers/protocoltypes" "github.com/sipeed/picoclaw/pkg/providers/protocoltypes"
) )
func TestProviderChat_PrefersResponsesForOpenAIPrefixedModel(t *testing.T) { func TestProviderChat_PrefersResponsesWhenConfigured(t *testing.T) {
var paths []string var paths []string
var responsesBody map[string]any var responsesBody map[string]any
@ -63,12 +63,12 @@ func TestProviderChat_PrefersResponsesForOpenAIPrefixedModel(t *testing.T) {
})) }))
defer server.Close() defer server.Close()
p := NewProvider("key", server.URL, "") p := NewProvider("key", server.URL, "", WithResponsesPreferred())
out, err := p.Chat( out, err := p.Chat(
t.Context(), t.Context(),
[]Message{{Role: "user", Content: "hi"}}, []Message{{Role: "user", Content: "hi"}},
nil, nil,
"openai/gpt-4o", "gpt-4o",
map[string]any{"max_tokens": 256}, map[string]any{"max_tokens": 256},
) )
if err != nil { if err != nil {
@ -81,8 +81,8 @@ func TestProviderChat_PrefersResponsesForOpenAIPrefixedModel(t *testing.T) {
if !reflect.DeepEqual(paths, []string{"/responses"}) { if !reflect.DeepEqual(paths, []string{"/responses"}) {
t.Fatalf("paths = %v, want [/responses]", paths) t.Fatalf("paths = %v, want [/responses]", paths)
} }
if responsesBody["model"] != "openai/gpt-4o" { if responsesBody["model"] != "gpt-4o" {
t.Fatalf("model = %v, want openai/gpt-4o", responsesBody["model"]) t.Fatalf("model = %v, want gpt-4o", responsesBody["model"])
} }
if _, ok := responsesBody["input"]; !ok { if _, ok := responsesBody["input"]; !ok {
t.Fatalf("expected responses request body to contain input") t.Fatalf("expected responses request body to contain input")
@ -496,7 +496,7 @@ func TestProviderChat_DoesNotPreferResponsesForNestedOpenAINamespace(t *testing.
t.Context(), t.Context(),
[]Message{{Role: "user", Content: "hi"}}, []Message{{Role: "user", Content: "hi"}},
nil, nil,
"groq/openai/gpt-oss-120b", "openai/gpt-oss-120b",
nil, nil,
) )
if err != nil { if err != nil {