diff --git a/pkg/providers/model_ref.go b/pkg/providers/model_ref.go index d0e6e51a0..bfcd8b162 100644 --- a/pkg/providers/model_ref.go +++ b/pkg/providers/model_ref.go @@ -19,12 +19,12 @@ func ParseModelRef(raw string, defaultProvider string) *ModelRef { if idx := strings.Index(raw, "/"); idx > 0 { prefix := strings.TrimSpace(raw[:idx]) + model := strings.TrimSpace(raw[idx+1:]) + if model == "" { + return nil + } if isKnownProviderPrefix(prefix) { provider := NormalizeProvider(prefix) - model := strings.TrimSpace(raw[idx+1:]) - if model == "" { - return nil - } return &ModelRef{Provider: provider, Model: model} } } @@ -35,17 +35,42 @@ func ParseModelRef(raw string, defaultProvider string) *ModelRef { } } +var knownProviderPrefixes = map[string]struct{}{ + "openai": {}, + "anthropic": {}, + "openrouter": {}, + "groq": {}, + "zhipu": {}, + "gemini": {}, + "nvidia": {}, + "ollama": {}, + "moonshot": {}, + "shengsuanyun": {}, + "deepseek": {}, + "cerebras": {}, + "volcengine": {}, + "vllm": {}, + "qwen-portal": {}, + "mistral": {}, + "antigravity": {}, + "claude-cli": {}, + "claudecli": {}, + "claude-code": {}, + "claudecode": {}, + "codex-cli": {}, + "codexcli": {}, + "codex-code": {}, + "github-copilot": {}, + "github_copilot": {}, + "copilot": {}, + "zai": {}, + "opencode": {}, + "kimi-coding": {}, +} + func isKnownProviderPrefix(prefix string) bool { - switch NormalizeProvider(prefix) { - case "openai", "anthropic", "openrouter", "groq", "zhipu", "gemini", - "nvidia", "ollama", "moonshot", "shengsuanyun", "deepseek", "cerebras", - "volcengine", "vllm", "qwen-portal", "mistral", "antigravity", - "claude-cli", "claudecli", "codex-cli", "codexcli", "github-copilot", - "github_copilot", "copilot", "zai", "opencode", "kimi-coding": - return true - default: - return false - } + _, ok := knownProviderPrefixes[NormalizeProvider(prefix)] + return ok } // NormalizeProvider normalizes provider identifiers to canonical form. diff --git a/pkg/providers/model_ref_test.go b/pkg/providers/model_ref_test.go index df00e2975..8bc82e906 100644 --- a/pkg/providers/model_ref_test.go +++ b/pkg/providers/model_ref_test.go @@ -149,3 +149,47 @@ func TestParseModelRef_UnknownPrefixUsesDefaultProvider(t *testing.T) { t.Errorf("model = %q, want stepfun/step-3.5-flash:free", ref.Model) } } + +func TestParseModelRef_KnownAliasPrefixes(t *testing.T) { + tests := []struct { + raw string + wantProvider string + wantModel string + }{ + { + raw: "claude-code/claude-sonnet-4.6", + wantProvider: "claude-code", + wantModel: "claude-sonnet-4.6", + }, + { + raw: "claudecode/claude-sonnet-4.6", + wantProvider: "claudecode", + wantModel: "claude-sonnet-4.6", + }, + { + raw: "codex-code/codex", + wantProvider: "codex-code", + wantModel: "codex", + }, + } + + for _, tt := range tests { + ref := ParseModelRef(tt.raw, "openai") + if ref == nil { + t.Fatalf("ParseModelRef(%q) returned nil", tt.raw) + } + if ref.Provider != tt.wantProvider { + t.Errorf("ParseModelRef(%q) provider = %q, want %q", tt.raw, ref.Provider, tt.wantProvider) + } + if ref.Model != tt.wantModel { + t.Errorf("ParseModelRef(%q) model = %q, want %q", tt.raw, ref.Model, tt.wantModel) + } + } +} + +func TestParseModelRef_UnknownPrefixEmptyModelAfterSlash(t *testing.T) { + ref := ParseModelRef("foo/", "openrouter") + if ref != nil { + t.Errorf("expected nil for unknown prefix with empty model, got %+v", ref) + } +}