package config import "testing" type mockModelAliasReader map[string]string func (m mockModelAliasReader) ModelAliases() map[string]string { return m } func TestResolveModelDirectDeepSeek(t *testing.T) { got, ok := ResolveModel(nil, "deepseek-v4-flash") if !ok || got != "deepseek-v4-flash" { t.Fatalf("expected deepseek-v4-flash, got ok=%v model=%q", ok, got) } } func TestResolveModelDirectDeepSeekNoThinking(t *testing.T) { got, ok := ResolveModel(nil, "deepseek-v4-flash-nothinking") if !ok || got != "deepseek-v4-flash-nothinking" { t.Fatalf("expected deepseek-v4-flash-nothinking, got ok=%v model=%q", ok, got) } } func TestResolveModelAlias(t *testing.T) { got, ok := ResolveModel(nil, "gpt-4.1") if !ok || got != "deepseek-v4-flash" { t.Fatalf("expected alias gpt-4.1 -> deepseek-v4-flash, got ok=%v model=%q", ok, got) } } func TestResolveLatestOpenAIAlias(t *testing.T) { got, ok := ResolveModel(nil, "gpt-5.5") if !ok || got != "deepseek-v4-flash" { t.Fatalf("expected alias gpt-5.5 -> deepseek-v4-flash, got ok=%v model=%q", ok, got) } } func TestResolveLatestClaudeAlias(t *testing.T) { got, ok := ResolveModel(nil, "claude-sonnet-4-6") if !ok || got != "deepseek-v4-flash" { t.Fatalf("expected alias claude-sonnet-4-6 -> deepseek-v4-flash, got ok=%v model=%q", ok, got) } } func TestResolveLatestClaudeAliasNoThinking(t *testing.T) { got, ok := ResolveModel(nil, "claude-sonnet-4-6-nothinking") if !ok || got != "deepseek-v4-flash-nothinking" { t.Fatalf("expected alias claude-sonnet-4-6-nothinking -> deepseek-v4-flash-nothinking, got ok=%v model=%q", ok, got) } } func TestResolveExpandedHistoricalAliases(t *testing.T) { cases := []struct { name string model string want string }{ {name: "openai old chatgpt", model: "chatgpt-4o", want: "deepseek-v4-flash"}, {name: "openai codex max", model: "gpt-5.1-codex-max", want: "deepseek-v4-pro"}, {name: "openai deep research", model: "o3-deep-research", want: "deepseek-v4-pro-search"}, {name: "openai historical reasoning", model: "o1-preview", want: "deepseek-v4-pro"}, {name: "claude latest historical", model: "claude-3-5-sonnet-latest", want: "deepseek-v4-flash"}, {name: "claude historical opus", model: "claude-3-opus-20240229", want: "deepseek-v4-pro"}, {name: "claude historical haiku", model: "claude-3-haiku-20240307", want: "deepseek-v4-flash"}, {name: "gemini latest alias", model: "gemini-flash-latest", want: "deepseek-v4-flash"}, {name: "gemini historical pro", model: "gemini-1.5-pro", want: "deepseek-v4-pro"}, {name: "gemini vision legacy", model: "gemini-pro-vision", want: "deepseek-v4-vision"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { got, ok := ResolveModel(nil, tc.model) if !ok || got != tc.want { t.Fatalf("expected alias %s -> %s, got ok=%v model=%q", tc.model, tc.want, ok, got) } }) } } func TestResolveModelHeuristicReasoner(t *testing.T) { got, ok := ResolveModel(nil, "o3-super") if !ok || got != "deepseek-v4-pro" { t.Fatalf("expected heuristic reasoner, got ok=%v model=%q", ok, got) } } func TestResolveModelHeuristicReasonerNoThinking(t *testing.T) { got, ok := ResolveModel(nil, "o3-super-nothinking") if !ok || got != "deepseek-v4-pro-nothinking" { t.Fatalf("expected heuristic reasoner nothinking, got ok=%v model=%q", ok, got) } } func TestResolveModelUnknown(t *testing.T) { _, ok := ResolveModel(nil, "totally-custom-model") if ok { t.Fatal("expected unknown model to fail resolve") } } func TestResolveModelRejectsLegacyDeepSeekIDs(t *testing.T) { legacyModels := []string{ "deepseek-chat", "deepseek-reasoner", "deepseek-chat-search", "deepseek-reasoner-search", "deepseek-expert-chat", "deepseek-expert-reasoner", "deepseek-vision-chat", } for _, model := range legacyModels { if got, ok := ResolveModel(nil, model); ok { t.Fatalf("expected legacy model %q to be rejected, got %q", model, got) } } } func TestResolveModelRejectsRetiredHistoricalModels(t *testing.T) { retiredModels := []string{ "claude-2.1", "claude-instant-1.2", "gpt-3.5-turbo", } for _, model := range retiredModels { if got, ok := ResolveModel(nil, model); ok { t.Fatalf("expected retired model %q to be rejected, got %q", model, got) } } } func TestResolveModelDirectDeepSeekExpert(t *testing.T) { got, ok := ResolveModel(nil, "deepseek-v4-pro") if !ok || got != "deepseek-v4-pro" { t.Fatalf("expected deepseek-v4-pro, got ok=%v model=%q", ok, got) } } func TestResolveModelCustomAliasToExpert(t *testing.T) { got, ok := ResolveModel(mockModelAliasReader{ "my-expert-model": "deepseek-v4-pro-search", }, "my-expert-model") if !ok || got != "deepseek-v4-pro-search" { t.Fatalf("expected alias -> deepseek-v4-pro-search, got ok=%v model=%q", ok, got) } } func TestResolveModelCustomAliasToVision(t *testing.T) { got, ok := ResolveModel(mockModelAliasReader{ "my-vision-model": "deepseek-v4-vision", }, "my-vision-model") if !ok || got != "deepseek-v4-vision" { t.Fatalf("expected alias -> deepseek-v4-vision, got ok=%v model=%q", ok, got) } } func TestResolveModelHeuristicVisionIgnoresSearchSuffix(t *testing.T) { got, ok := ResolveModel(nil, "gemini-vision-search") if !ok || got != "deepseek-v4-vision" { t.Fatalf("expected heuristic vision alias to resolve without search variant, got ok=%v model=%q", ok, got) } } func TestClaudeModelsResponsePaginationFields(t *testing.T) { resp := ClaudeModelsResponse() if _, ok := resp["first_id"]; !ok { t.Fatalf("expected first_id in response: %#v", resp) } if _, ok := resp["last_id"]; !ok { t.Fatalf("expected last_id in response: %#v", resp) } if _, ok := resp["has_more"]; !ok { t.Fatalf("expected has_more in response: %#v", resp) } }