From 7b832a0b78ae3e2c54c0eeaf3ff76afcd5bf1ef0 Mon Sep 17 00:00:00 2001 From: 0xmrmasry Date: Sun, 18 Oct 2026 00:47:43 +0300 Subject: [PATCH 1/3] fix: refresh Codex catalog client version --- internal/codexauth/tokens.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/codexauth/tokens.go b/internal/codexauth/tokens.go index 0c4ed00c0c..f6b19e30dd 100644 --- a/internal/codexauth/tokens.go +++ b/internal/codexauth/tokens.go @@ -21,7 +21,7 @@ const ( ClientID = "app_EMoamEEZ73f0CkXaXp7hrann" Sentinel = "chatgpt" Originator = "codex_cli_rs" - clientVersion = "0.144.1" + clientVersion = "0.162.1" ) // signInExpiredError is terminal before the provider's ordinary transport From 3d8f3e4908b1713879ac94b5ee807e117f94ffe4 Mon Sep 17 00:00:00 2001 From: 0xmrmasry Date: Sun, 18 Oct 2026 00:52:50 +0300 Subject: [PATCH 2/3] docs: record Codex catalog version fix for #1870 --- .../unreleased/1870-codex-model-catalog-version.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 docs/changes/unreleased/1870-codex-model-catalog-version.md diff --git a/docs/changes/unreleased/1870-codex-model-catalog-version.md b/docs/changes/unreleased/1870-codex-model-catalog-version.md new file mode 100644 index 0000000000..ec93cfe522 --- /dev/null +++ b/docs/changes/unreleased/1870-codex-model-catalog-version.md @@ -0,0 +1,13 @@ +--- +kind: fixed +title: Codex discovery lists newer models available to the signed-in account +pr: 1870 +surface: [chat, engine] +invalidates: [] +--- + +Update the shared catalog client version from 0.144.1 to 0.162.1. The account +backend gates model visibility by client version, so the older version omitted +newer models even for accounts with access. Direct listing and translated +catalog requests use the same version; account permissions and visibility +filtering are unchanged. From 9adb19248f0a3b05b30c6a71a4ea8014c180fbf7 Mon Sep 17 00:00:00 2001 From: Abir Abbas Date: Tue, 20 Oct 2026 08:53:02 -0400 Subject: [PATCH 3/3] test: cover version-gated Codex discovery through both catalog doors Pin the backend fixture independently of the shared client version so reverting the advertised version hides newer models in both direct and translated listings. Preserve visibility filtering and cached reasoning metadata. Co-Authored-By: Claude Opus 5.5 (1M context) --- internal/codexauth/models_version_test.go | 85 +++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 internal/codexauth/models_version_test.go diff --git a/internal/codexauth/models_version_test.go b/internal/codexauth/models_version_test.go new file mode 100644 index 0000000000..a2b9fd0b56 --- /dev/null +++ b/internal/codexauth/models_version_test.go @@ -0,0 +1,85 @@ +package codexauth + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "strings" + "testing" + "time" + + "github.com/Agent-Field/codeaf/internal/provider" +) + +func TestCatalogVersionExposesNewModelsThroughBothDoors(t *testing.T) { + for _, door := range []string{"direct", "translated"} { + t.Run(door, func(t *testing.T) { + now := time.Unix(1_800_000_000, 0) + dir := t.TempDir() + if err := Save(dir, validTokens(now)); err != nil { + t.Fatal(err) + } + backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet || r.URL.Path != "/models" || + r.Header.Get("Authorization") != "Bearer access-token-secret" || + r.Header.Get("chatgpt-account-id") != "account-one" || + r.Header.Get("originator") != Originator || + r.Header.Get("User-Agent") != provider.DirectUserAgent { + http.Error(w, "unexpected catalog request", http.StatusBadRequest) + return + } + rows := []map[string]any{ + {"slug": "baseline", "visibility": "list"}, + {"slug": "hidden", "visibility": "hide"}, + } + // The backend fixture pins the released version independently of + // clientVersion, so restoring the old advertisement hides the row. + if r.URL.Query().Get("client_version") == "0.162.1" { + rows = append(rows, map[string]any{ + "slug": "new-model", "visibility": "list", "context_window": 272000, + "supported_reasoning_levels": []map[string]string{{"effort": "high"}}, + }) + } + _ = json.NewEncoder(w).Encode(map[string]any{"models": rows}) + })) + defer backend.Close() + options := Options{Backend: backend.URL, HTTPClient: backend.Client(), Now: func() time.Time { return now }} + var ids []string + if door == "direct" { + models, err := List(context.Background(), dir, options) + if err != nil { + t.Fatal(err) + } + for _, model := range models { + ids = append(ids, model.ID) + } + } else { + response, err := ClientWithOptions(dir, options).Get(backend.URL + "/models") + if err != nil { + t.Fatal(err) + } + defer response.Body.Close() + if response.StatusCode != http.StatusOK { + t.Fatalf("catalog status = %d", response.StatusCode) + } + var catalog struct { + Data []struct{ ID string } `json:"data"` + } + if err := json.NewDecoder(response.Body).Decode(&catalog); err != nil { + t.Fatal(err) + } + for _, model := range catalog.Data { + ids = append(ids, model.ID) + } + } + if strings.Join(ids, ",") != "baseline,new-model" { + t.Fatalf("visible models = %v; newer catalog models must be exposed and hidden rows excluded", ids) + } + cached := loadModels(dir) + if len(cached) != 2 || cached[1].ID != "new-model" || cached[1].ContextLength != 272000 || strings.Join(cached[1].ReasoningLevels, ",") != "high" { + t.Fatalf("cached catalog metadata = %+v", cached) + } + }) + } +}