fix(provider): normalize openrouter model slugs in async spawn
Fix OpenRouter model normalization for nested transport-prefixed model slugs. PicoClaw could forward raw values like openrouter/minimax/minimax-m2.5 directly to OpenRouter on async spawn/subagent paths, which causes 400 invalid model ID. This change normalizes nested OpenRouter-prefixed slugs to the provider-accepted <vendor>/<model> form before the API call, while preserving special cases like openrouter/auto and openrouter/free. - Strip leading openrouter/ segment when remaining value is a nested path - Preserve openrouter/auto and openrouter/free shorthand values - Add regression tests for nested OpenRouter model refs Fixes #1678
This commit is contained in:
parent
cefa140bd2
commit
7ec8cb866c
2 changed files with 64 additions and 10 deletions
|
|
@ -182,6 +182,9 @@ func normalizeModel(model, apiBase string) string {
|
|||
}
|
||||
|
||||
if strings.Contains(strings.ToLower(apiBase), "openrouter.ai") {
|
||||
if strings.EqualFold(before, "openrouter") && strings.Contains(after, "/") {
|
||||
return after
|
||||
}
|
||||
return model
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -561,17 +561,68 @@ func TestProviderChat_AcceptsNumericOptionTypes(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNormalizeModel_UsesAPIBase(t *testing.T) {
|
||||
if got := normalizeModel("deepseek/deepseek-chat", "https://api.deepseek.com/v1"); got != "deepseek-chat" {
|
||||
t.Fatalf("normalizeModel(deepseek) = %q, want %q", got, "deepseek-chat")
|
||||
tests := []struct {
|
||||
name string
|
||||
model string
|
||||
apiBase string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "strips deepseek transport prefix",
|
||||
model: "deepseek/deepseek-chat",
|
||||
apiBase: "https://api.deepseek.com/v1",
|
||||
want: "deepseek-chat",
|
||||
},
|
||||
{
|
||||
name: "preserves openrouter auto shorthand",
|
||||
model: "openrouter/auto",
|
||||
apiBase: "https://openrouter.ai/api/v1",
|
||||
want: "openrouter/auto",
|
||||
},
|
||||
{
|
||||
name: "preserves openrouter free shorthand",
|
||||
model: "openrouter/free",
|
||||
apiBase: "https://openrouter.ai/api/v1",
|
||||
want: "openrouter/free",
|
||||
},
|
||||
{
|
||||
name: "strips openrouter transport prefix for nested vendor model",
|
||||
model: "openrouter/openai/gpt-5.4",
|
||||
apiBase: "https://openrouter.ai/api/v1",
|
||||
want: "openai/gpt-5.4",
|
||||
},
|
||||
{
|
||||
name: "strips openrouter transport prefix for any nested provider path",
|
||||
model: "openrouter/stepfun/step-3.5-flash:free",
|
||||
apiBase: "https://openrouter.ai/api/v1",
|
||||
want: "stepfun/step-3.5-flash:free",
|
||||
},
|
||||
{
|
||||
name: "strips openrouter transport prefix for other nested vendor model",
|
||||
model: "openrouter/minimax/minimax-m2.5",
|
||||
apiBase: "https://openrouter.ai/api/v1",
|
||||
want: "minimax/minimax-m2.5",
|
||||
},
|
||||
{
|
||||
name: "strips vivgrid transport prefix",
|
||||
model: "vivgrid/managed",
|
||||
apiBase: "https://api.vivgrid.com/v1",
|
||||
want: "managed",
|
||||
},
|
||||
{
|
||||
name: "strips vivgrid auto alias",
|
||||
model: "vivgrid/auto",
|
||||
apiBase: "https://api.vivgrid.com/v1",
|
||||
want: "auto",
|
||||
},
|
||||
}
|
||||
if got := normalizeModel("openrouter/auto", "https://openrouter.ai/api/v1"); got != "openrouter/auto" {
|
||||
t.Fatalf("normalizeModel(openrouter) = %q, want %q", got, "openrouter/auto")
|
||||
}
|
||||
if got := normalizeModel("vivgrid/managed", "https://api.vivgrid.com/v1"); got != "managed" {
|
||||
t.Fatalf("normalizeModel(vivgrid) = %q, want %q", got, "managed")
|
||||
}
|
||||
if got := normalizeModel("vivgrid/auto", "https://api.vivgrid.com/v1"); got != "auto" {
|
||||
t.Fatalf("normalizeModel(vivgrid auto) = %q, want %q", got, "auto")
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := normalizeModel(tt.model, tt.apiBase); got != tt.want {
|
||||
t.Fatalf("normalizeModel(%q, %q) = %q, want %q", tt.model, tt.apiBase, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue