From e89793c54daa1c98ca264e49294fd5ad08234b03 Mon Sep 17 00:00:00 2001 From: seefs001 Date: Fri, 25 Sep 2026 21:25:26 +0800 Subject: [PATCH] fix(codex): include codex-auto-review in model discovery --- core/internal/servicemodel/prober_test.go | 4 ++-- core/internal/subscription/manager_test.go | 2 +- core/internal/subscription/models.go | 21 +++++++++++++++---- core/internal/subscription/models_test.go | 8 +++---- .../subscription/provider_compression_test.go | 2 +- 5 files changed, 25 insertions(+), 12 deletions(-) diff --git a/core/internal/servicemodel/prober_test.go b/core/internal/servicemodel/prober_test.go index df5b385..dc6e9f9 100644 --- a/core/internal/servicemodel/prober_test.go +++ b/core/internal/servicemodel/prober_test.go @@ -295,12 +295,12 @@ func TestProbeServiceUsesConnectedCodexAccountAndRejectsMalformedResponse(t *tes } prober := New(store, manager, nil) models, err := prober.ProbeService(context.Background(), service, contract.ProtocolOpenAIModels) - if err != nil || strings.Join(models, ",") != "gpt-6-astra,gpt-a,gpt-z" { + if err != nil || strings.Join(models, ",") != "codex-auto-review,gpt-6-astra,gpt-a,gpt-z" { t.Fatalf("models=%v err=%v", models, err) } responseBody = `{"models":[]}` empty, err := prober.ProbeService(context.Background(), service, contract.ProtocolOpenAIModels) - if err != nil || len(empty) != 0 { + if err != nil || strings.Join(empty, ",") != "codex-auto-review" { t.Fatalf("empty Codex catalog = %v err=%v", empty, err) } responseBody = `{}` diff --git a/core/internal/subscription/manager_test.go b/core/internal/subscription/manager_test.go index bc47a95..756cc6f 100644 --- a/core/internal/subscription/manager_test.go +++ b/core/internal/subscription/manager_test.go @@ -186,7 +186,7 @@ func TestConnectedAccountModelsAndResponsesPath(t *testing.T) { if err != nil { t.Fatalf("ListModels() = %v", err) } - if len(models.Data) != 1 || models.Data[0].ID != "gpt-5" { + if len(models.Data) != 2 || models.Data[0].ID != "gpt-5" || models.Data[1].ID != "codex-auto-review" { t.Fatalf("models = %#v", models) } body, status, err := manager.Provider().ProbeNonStreamingResponse(context.Background(), liveTokens, "gpt-5") diff --git a/core/internal/subscription/models.go b/core/internal/subscription/models.go index 6243bb6..b608f2b 100644 --- a/core/internal/subscription/models.go +++ b/core/internal/subscription/models.go @@ -84,13 +84,26 @@ func DecodeCodexModels(body []byte) (ModelList, error) { if envelope == nil { return ModelList{}, fmt.Errorf("decode codex models: empty object") } + var list ModelList + var err error if raw, ok := envelope["models"]; ok { - return decodeOfficialCodexModels(raw) + list, err = decodeOfficialCodexModels(raw) + } else if raw, ok := envelope["data"]; ok { + list, err = decodeOpenAICompatibleModels(raw) + } else { + return ModelList{}, fmt.Errorf("decode codex models: missing models or data") } - if raw, ok := envelope["data"]; ok { - return decodeOpenAICompatibleModels(raw) + if err != nil { + return ModelList{}, err } - return ModelList{}, fmt.Errorf("decode codex models: missing models or data") + // Codex's auto-review model may be omitted or hidden in the upstream catalog. + for _, model := range list.Data { + if model.ID == "codex-auto-review" { + return list, nil + } + } + list.Data = append(list.Data, ModelRecord{ID: "codex-auto-review", Object: "model"}) + return list, nil } func decodeOfficialCodexModels(raw json.RawMessage) (ModelList, error) { diff --git a/core/internal/subscription/models_test.go b/core/internal/subscription/models_test.go index d5501fe..62d8a00 100644 --- a/core/internal/subscription/models_test.go +++ b/core/internal/subscription/models_test.go @@ -65,7 +65,7 @@ func TestDecodeCodexModelsOfficialAndCompatibleEnvelopes(t *testing.T) { if err != nil { t.Fatalf("official DecodeCodexModels() = %v", err) } - if got, want := modelIDs(official), "gpt-5,gpt-5-codex,gpt-4.1"; got != want { + if got, want := modelIDs(official), "gpt-5,gpt-5-codex,gpt-4.1,codex-auto-review"; got != want { t.Fatalf("official IDs = %q, want %q", got, want) } @@ -73,16 +73,16 @@ func TestDecodeCodexModelsOfficialAndCompatibleEnvelopes(t *testing.T) { if err != nil { t.Fatalf("compatible DecodeCodexModels() = %v", err) } - if got, want := modelIDs(compatible), "gpt-z,gpt-a"; got != want { + if got, want := modelIDs(compatible), "gpt-z,gpt-a,codex-auto-review"; got != want { t.Fatalf("compatible IDs = %q, want %q", got, want) } emptyOfficial, err := DecodeCodexModels([]byte(`{"models":[]}`)) - if err != nil || emptyOfficial.Data == nil || len(emptyOfficial.Data) != 0 { + if err != nil || modelIDs(emptyOfficial) != "codex-auto-review" { t.Fatalf("empty official = %#v err=%v", emptyOfficial, err) } emptyCompatible, err := DecodeCodexModels([]byte(`{"data":[]}`)) - if err != nil || emptyCompatible.Data == nil || len(emptyCompatible.Data) != 0 { + if err != nil || modelIDs(emptyCompatible) != "codex-auto-review" { t.Fatalf("empty compatible = %#v err=%v", emptyCompatible, err) } } diff --git a/core/internal/subscription/provider_compression_test.go b/core/internal/subscription/provider_compression_test.go index 137d1ae..d32cdd8 100644 --- a/core/internal/subscription/provider_compression_test.go +++ b/core/internal/subscription/provider_compression_test.go @@ -38,7 +38,7 @@ func TestProviderReadsCompressedCatalogAndNormalizesResponseHeaders(t *testing.T provider := NewCodexProvider(accountauth.OAuthConfig{APIBaseURL: upstream.URL, HTTPClient: client}) tokens := accountauth.AccountTokens{AccessToken: "test-token"} models, err := provider.ListModels(context.Background(), tokens) - if err != nil || len(models.Data) != 1 || models.Data[0].ID != "test-model" { + if err != nil || modelIDs(models) != "test-model,codex-auto-review" { t.Fatalf("models = %#v, err = %v", models, err) } body, status, headers, err := provider.CreateResponse(context.Background(), tokens, []byte(`{"input":"test"}`))