package registry import ( "encoding/json" "reflect" "strings" "testing" ) func TestCodexConfigurationUpdateCapability(t *testing.T) { // Counterexample: present in every tier without support_configuration_update. const incapableModelID = "gpt-5.6-luna" for _, tier := range []struct { name string models func() []*ModelInfo capable []string }{ {name: "free", models: GetCodexFreeModels, capable: []string{"gpt-6-luna"}}, {name: "team", models: GetCodexTeamModels, capable: []string{"gpt-6-astra", "gpt-6-sol", "gpt-6-luna"}}, {name: "plus", models: GetCodexPlusModels, capable: []string{"gpt-6-astra", "gpt-6-sol", "gpt-6-luna"}}, {name: "pro", models: GetCodexProModels, capable: []string{"gpt-6-astra", "gpt-6-sol", "gpt-6-luna"}}, } { t.Run(tier.name, func(t *testing.T) { byID := make(map[string]*ModelInfo) for _, info := range tier.models() { if info != nil { byID[info.ID] = info } } for _, id := range append([]string{incapableModelID}, tier.capable...) { info := byID[id] if info == nil { t.Errorf("%s is missing", id) continue } want := id != incapableModelID if info.SupportConfigurationUpdate != want { t.Errorf("%s configuration_update = %v, want %v", id, info.SupportConfigurationUpdate, want) } if cloned := cloneModelInfo(info); cloned.SupportConfigurationUpdate != want { t.Errorf("%s clone configuration_update = %v, want %v", id, cloned.SupportConfigurationUpdate, want) } raw, errMarshal := json.Marshal(info) if errMarshal != nil { t.Fatal(errMarshal) } if strings.Contains(string(raw), "support_configuration_update") || strings.Contains(string(raw), "SupportConfigurationUpdate") { t.Errorf("%s exposed configuration_update capability: %s", id, raw) } } }) } for _, tt := range []struct { name string raw string want bool }{ {name: "true", raw: `{"id":"test","support_configuration_update":true}`, want: true}, {name: "false", raw: `{"id":"test","support_configuration_update":false}`}, {name: "absent", raw: `{"id":"test"}`}, } { t.Run(tt.name, func(t *testing.T) { info := ModelInfo{SupportConfigurationUpdate: true} if errUnmarshal := json.Unmarshal([]byte(tt.raw), &info); errUnmarshal != nil { t.Fatal(errUnmarshal) } if info.SupportConfigurationUpdate != tt.want { t.Errorf("capability = %v, want %v", info.SupportConfigurationUpdate, tt.want) } }) } } func TestGetStaticModelDefinitionsByChannelSupportsGeminiInteractions(t *testing.T) { models := GetStaticModelDefinitionsByChannel("gemini-interactions") if len(models) == 0 { t.Fatal("GetStaticModelDefinitionsByChannel(gemini-interactions) returned no models") } } func TestGetStaticModelDefinitionsByChannelSupportsKimiAndKimiAI(t *testing.T) { for _, channel := range []string{"kimi", "kimi-ai", "kimi.ai", "kimi.com"} { models := GetStaticModelDefinitionsByChannel(channel) if len(models) == 0 { t.Fatalf("GetStaticModelDefinitionsByChannel(%s) returned no models", channel) } } } func TestModelOverrideHeadersFromEmbeddedModels(t *testing.T) { const wantUA = "codex-tui/0.154.0 (Mac OS 26.5.2; arm64) iTerm.app/3.6.11 (codex-tui; 0.154.0)" got := ModelOverrideHeaders("gpt-5.6-luna") if got == nil { t.Fatal("ModelOverrideHeaders(gpt-5.6-luna) = nil, want headers") } if got["user-agent"] != wantUA { t.Fatalf("user-agent = %q, want %q", got["user-agent"], wantUA) } if got := ModelOverrideHeaders("gpt-5.4"); got != nil { t.Fatalf("ModelOverrideHeaders(gpt-5.4) = %#v, want nil", got) } } func TestGeminiVertexModelsUseFlashLiteReleaseID(t *testing.T) { const releaseID = "gemini-3.1-flash-lite" const previewID = releaseID + "-preview" for _, model := range GetGeminiVertexModels() { if model == nil { continue } if model.ID == previewID { t.Fatalf("Vertex model ID = %q, want release ID %q", model.ID, releaseID) } if model.ID == releaseID { return } } t.Fatalf("Vertex models do not contain %q", releaseID) } func TestWithXAIBuiltinsIncludesImage20(t *testing.T) { models := WithXAIBuiltins(nil) for _, model := range models { if model != nil && model.ID == xaiBuiltinImage20ModelID { if model.Created != 1786060800 { t.Fatalf("created = %d, want 1786060800 (2026-08-07)", model.Created) } return } } t.Fatalf("expected xAI builtin model %s", xaiBuiltinImage20ModelID) } func TestWithXAIBuiltinsIncludesSpeechModels(t *testing.T) { models := WithXAIBuiltins(nil) found := map[string]*ModelInfo{} for _, model := range models { if model == nil { continue } if model.ID == xaiBuiltinSpeechModelID || model.ID == xaiBuiltinSpeechVoiceModelID { found[model.ID] = model } } for _, id := range []string{xaiBuiltinSpeechModelID, xaiBuiltinSpeechVoiceModelID} { model := found[id] if model == nil { t.Fatalf("expected xAI builtin model %s", id) } if model.OwnedBy != "xai" || model.Type != "xai" { t.Fatalf("%s owned_by/type = %s/%s, want xai/xai", id, model.OwnedBy, model.Type) } } } func TestWithXAIBuiltinsIncludesVideo15GAAndPreviewAlias(t *testing.T) { models := WithXAIBuiltins(nil) foundGA := false foundPreviewAlias := false for _, model := range models { if model == nil { continue } if model.ID == xaiBuiltinVideo15ModelID { foundGA = true } if model.ID == xaiBuiltinVideo15PreviewID { foundPreviewAlias = true } } if !foundGA { t.Fatalf("expected xAI builtin model %s", xaiBuiltinVideo15ModelID) } if !foundPreviewAlias { t.Fatalf("expected xAI builtin compatibility alias %s", xaiBuiltinVideo15PreviewID) } } func TestGetXAIModelsPreservesVideo15LiteAfterCatalogRefresh(t *testing.T) { const liteID = "grok-imagine-video-1.5-lite" original := getModels() t.Cleanup(func() { modelsCatalogStore.mu.Lock() modelsCatalogStore.data = original modelsCatalogStore.mu.Unlock() }) refreshed := *original remoteModel := &ModelInfo{ID: "refreshed-xai-model", OwnedBy: "xai", Type: "xai", DisplayName: "Refreshed model"} refreshed.XAI = []*ModelInfo{remoteModel} payload, err := json.Marshal(&refreshed) if err != nil { t.Fatal(err) } if _, err := publishCatalogBytes(payload); err != nil { t.Fatalf("publish catalog without Lite: %v", err) } models := GetXAIModels() foundLite, foundRemote := false, false for _, model := range models { if model.ID == liteID { foundLite = true if model.OwnedBy != "xai" || model.Type != "xai" || !reflect.DeepEqual(model.SupportedInputModalities, []string{"text", "image"}) || !reflect.DeepEqual(model.SupportedOutputModalities, []string{"video"}) { t.Fatalf("Lite lost xAI video capabilities after catalog refresh: %#v", model) } } if model.ID == remoteModel.ID { foundRemote = true if !reflect.DeepEqual(model, remoteModel) { t.Fatalf("refreshed model = %#v, want %#v", model, remoteModel) } } } if !foundLite || !foundRemote { t.Fatalf("catalog lost Lite or refreshed model: Lite=%v, refreshed=%v", foundLite, foundRemote) } const clientID = "test-xai-lite-catalog-refresh" registryRef := GetGlobalRegistry() registryRef.RegisterClient(clientID, "xai", models) t.Cleanup(func() { registryRef.UnregisterClient(clientID) }) if !registryRef.ClientSupportsModel(clientID, liteID) { t.Fatal("xAI credential registration lost Lite support after catalog refresh") } if providers := registryRef.GetModelProviders(liteID); !reflect.DeepEqual(providers, []string{"xai"}) { t.Fatalf("Lite providers = %v, want [xai]", providers) } } func TestWithXAIBuiltinsReplacesVideo15LiteWithoutMutatingCatalog(t *testing.T) { const liteID = "grok-imagine-video-1.5-lite" stale := &ModelInfo{ID: liteID, DisplayName: "Stale Lite", SupportedInputModalities: []string{"text"}} duplicate := &ModelInfo{ID: " GROK-IMAGINE-VIDEO-1.5-LITE ", DisplayName: "Duplicate Lite"} custom := &ModelInfo{ID: "custom-xai-model", DisplayName: "Custom model"} input := []*ModelInfo{stale, custom, duplicate} for range 2 { models := WithXAIBuiltins(input) liteCount := 0 foundCustom := false for _, model := range models { if strings.EqualFold(strings.TrimSpace(model.ID), liteID) { liteCount++ if model.ID != liteID || model.DisplayName != "Grok Imagine Video 1.5 Lite" || !reflect.DeepEqual(model.SupportedInputModalities, []string{"text", "image"}) { t.Fatalf("Lite builtin did not replace stale metadata: %#v", model) } model.SupportedInputModalities[0] = "mutated" } if model.ID == custom.ID { foundCustom = reflect.DeepEqual(model, custom) } } if liteCount != 1 || !foundCustom { t.Fatalf("Lite count = %d, custom preserved = %v, want 1 and true", liteCount, foundCustom) } } if input[0] != stale || input[1] != custom || input[2] != duplicate || stale.DisplayName != "Stale Lite" || !reflect.DeepEqual(stale.SupportedInputModalities, []string{"text"}) || duplicate.ID != " GROK-IMAGINE-VIDEO-1.5-LITE " || duplicate.DisplayName != "Duplicate Lite" { t.Fatal("builtin merge mutated the input catalog") } } func TestAntigravityWebSearchModelForRequiresRequestedModelCapability(t *testing.T) { registryRef := GetGlobalRegistry() registryRef.RegisterClient("test-antigravity-websearch-route", "antigravity", []*ModelInfo{ {ID: "gemini-route-test"}, {ID: "gemini-web-search-test", SupportsWebSearch: true}, }) registryRef.RegisterClient("test-gemini-websearch-route", "gemini", []*ModelInfo{ {ID: "gemini-cross-provider-route"}, {ID: "gemini-cross-provider-search", SupportsWebSearch: true}, }) t.Cleanup(func() { registryRef.UnregisterClient("test-antigravity-websearch-route") registryRef.UnregisterClient("test-gemini-websearch-route") }) if got := AntigravityWebSearchModelFor("gemini-route-test"); got != "" { t.Fatalf("route model without web search support should not get fallback model, got %q", got) } if got := AntigravityWebSearchModelFor("gemini-route-test(high)"); got != "" { t.Fatalf("suffix route model without web search support should not get fallback model, got %q", got) } if got := AntigravityWebSearchModelFor("gemini-web-search-test"); got != "gemini-web-search-test" { t.Fatalf("AntigravityWebSearchModelFor capable model = %q, want itself", got) } if got := AntigravityWebSearchModelFor("gemini-cross-provider-route"); got != "" { t.Fatalf("cross-provider model should not get Antigravity web search model, got %q", got) } if got := AntigravityWebSearchModelFor("unknown-model"); got != "" { t.Fatalf("unknown model should not get Antigravity web search model, got %q", got) } } func TestValidateModelsCatalog_Meta(t *testing.T) { valid := &staticModelsJSON{ Meta: []*ModelInfo{ {ID: "muse-spark-1.3"}, }, } if err := validateModelsCatalog(valid); err != nil { t.Fatalf("expected valid Meta catalog to pass, got: %v", err) } withNull := &staticModelsJSON{ Meta: []*ModelInfo{nil}, } if err := validateModelsCatalog(withNull); err == nil { t.Fatal("expected error for Meta section with null model, got nil") } withEmptyID := &staticModelsJSON{ Meta: []*ModelInfo{{ID: " "}}, } if err := validateModelsCatalog(withEmptyID); err == nil { t.Fatal("expected error for Meta section with empty model id, got nil") } withDuplicate := &staticModelsJSON{ Meta: []*ModelInfo{ {ID: "muse-spark-1.3"}, {ID: "muse-spark-1.3"}, }, } if err := validateModelsCatalog(withDuplicate); err == nil { t.Fatal("expected error for Meta section with duplicate model id, got nil") } } func TestWithCodexBuiltinsIncludesImage25And26Models(t *testing.T) { models := WithCodexBuiltins(nil) expectedModels := map[string]string{ "gpt-image-2.5-flare": "GPT Image 2.5 Flare", "gpt-image-2.5-sunburst": "GPT Image 2.5 Sunburst", "gpt-image-2.5": "GPT Image 2.5", "gpt-image-2.6-flare": "GPT Image 2.6 Flare", "gpt-image-2.6-sunburst": "GPT Image 2.6 Sunburst", "gpt-image-2.6": "GPT Image 2.6", } found := make(map[string]*ModelInfo) for _, model := range models { if model != nil { if _, ok := expectedModels[model.ID]; ok { found[model.ID] = model } } } for id, wantDisplayName := range expectedModels { model, ok := found[id] if !ok { t.Fatalf("expected builtin model %s in WithCodexBuiltins", id) } if model.DisplayName != wantDisplayName { t.Errorf("model %s DisplayName = %q, want %q", id, model.DisplayName, wantDisplayName) } if model.Object != "model" { t.Errorf("model %s Object = %q, want model", id, model.Object) } if model.OwnedBy != "openai" { t.Errorf("model %s OwnedBy = %q, want openai", id, model.OwnedBy) } if model.Type != "openai" { t.Errorf("model %s Type = %q, want openai", id, model.Type) } if model.Version != id { t.Errorf("model %s Version = %q, want %q", id, model.Version, id) } if model.Created != 1704067200 { t.Errorf("model %s Created = %d, want 1704067200", id, model.Created) } } } func TestGetDevinModelsFallback(t *testing.T) { devinModels := GetDevinModels() if len(devinModels) == 0 { t.Fatal("GetDevinModels() returned empty list") } foundSWE2 := false foundFable := false foundGemini38 := false foundGrok46 := false foundDeepSeekV4Flash := false foundDeepSeekV41Flash := false for _, m := range devinModels { if m != nil && m.ID == "devin/swe-2" { foundSWE2 = true if m.Type != "devin" { t.Errorf("devin/swe-2 Type = %q, want devin", m.Type) } } if m != nil && m.ID == "devin/claude-fable-5-1" { foundFable = true } if m != nil && m.ID == "devin/gemini-3-8-flash" { foundGemini38 = true if m.OwnedBy != "google" { t.Errorf("devin/gemini-3-8-flash OwnedBy = %q, want google", m.OwnedBy) } } if m != nil && m.ID == "devin/grok-4-6" { foundGrok46 = true if m.OwnedBy != "xai" { t.Errorf("devin/grok-4-6 OwnedBy = %q, want xai", m.OwnedBy) } } if m != nil && m.ID == "devin/deepseek-v4-flash" { foundDeepSeekV4Flash = true if m.OwnedBy != "deepseek" { t.Errorf("devin/deepseek-v4-flash OwnedBy = %q, want deepseek", m.OwnedBy) } } if m != nil && m.ID == "devin/deepseek-v4-1-flash-1017" { foundDeepSeekV41Flash = true if m.OwnedBy != "deepseek" { t.Errorf("devin/deepseek-v4-1-flash-1017 OwnedBy = %q, want deepseek", m.OwnedBy) } } } if !foundSWE2 { t.Error("expected devin/swe-2 in GetDevinModels()") } if !foundFable { t.Error("expected devin/claude-fable-5-1 in GetDevinModels()") } if !foundGemini38 { t.Error("expected devin/gemini-3-8-flash in GetDevinModels()") } if !foundGrok46 { t.Error("expected devin/grok-4-6 in GetDevinModels()") } if !foundDeepSeekV4Flash { t.Error("expected devin/deepseek-v4-flash in GetDevinModels()") } if !foundDeepSeekV41Flash { t.Error("expected devin/deepseek-v4-1-flash-1017 in GetDevinModels()") } byChannel := GetStaticModelDefinitionsByChannel("devin") if len(byChannel) == 0 { t.Fatal("GetStaticModelDefinitionsByChannel(\"devin\") returned empty list") } info := LookupStaticModelInfo("devin/swe-2") if info == nil { t.Fatal("LookupStaticModelInfo(\"devin/swe-2\") = nil, want valid model") } if info.DisplayName != "SWE-2" { t.Errorf("info.DisplayName = %q, want SWE-2", info.DisplayName) } }