Skip to content

fix(oauth): send client_version when listing ChatGPT models - #1251

Merged
vastsa merged 5 commits into
vastsa:mainfrom
initH271:fix/codex-models-client-version
Sep 30, 2026
Merged

vastsa merged 5 commits into
vastsa:mainfrom
initH271:fix/codex-models-client-version

Conversation

@initH271

Copy link
Copy Markdown
Contributor

fix(oauth): send client_version when listing ChatGPT models

Fixes #1249

Problem

For a signed-in ChatGPT Plus/Pro account (openai-codex), Electron main reads
the account's model list from GET {base}/codex/models
(apps/desktop/electron/main/vendor-live-models.ts). That endpoint now requires
a client_version query parameter. Without it, the endpoint returns:

HTTP 400  ('query','client_version') Field required

The failure is swallowed: the account list falls back to the pinned pi-ai
catalog, so a model the account already offers (for example gpt-6.1-sol)
never reaches the provider row, and session launch rejects it locally with
MODEL_NOT_CONFIGURED. The vendor account model list failed warning logged
only the status code, so the log never showed why the request failed.

Verified by hand with the same account: adding ?client_version=0.159.2 returns
200 and the list includes gpt-6.1-sol. The originator header makes no
difference.

Changes

  1. Send client_version (vendor-live-models.ts): the Codex request is now
    GET {base}/codex/models?client_version=<CODEX_MODELS_CLIENT_VERSION>.
    • pi-ai 0.87.1 never calls this endpoint and has no Codex client version to
      reuse (it only sends originator: pi and its own User-Agent). The new
      constant therefore pins the official Codex CLI version that was verified to
      list the current models (0.159.2).
    • The value may also affect which models the list returns (not verified).
      The doc comment on the constant says to keep it at a current Codex CLI
      release and to try a newer value if an account model is missing.
  2. Diagnosable failures (vendor-live-models.ts, oauth.ts): a non-2xx
    response now throws VendorModelListError carrying status and
    responseExcerpt. The excerpt is a single line of at most 300 characters.
    Before it leaves the module, it drops the request's own Authorization /
    x-api-key value, any Bearer/Basic credential, and any JWT-shaped
    string. The logger's own redaction still runs after that. The
    vendor account model list failed warning now includes status and
    responseExcerpt. The error message itself is unchanged.
  3. Spec: docs/spec/03-runtime/11-provider-model-system.md and its zh-CN
    counterpart now document the client_version parameter and the failure log
    excerpt.

No IPC, persisted-data, default or permission change. The fallback to pi-ai
behaves as before.

Tests

  • apps/desktop/test/vendor-live-models.test.mjs
    • The Codex request URL carries client_version equal to the constant.
    • A 400 body keeps client_version / Field required in the excerpt. The
      raw token, its payload segment and an unrelated JWT are removed, and the
      excerpt is truncated.
    • An empty error body produces no excerpt.
  • apps/desktop/test/vendor-oauth-login.test.mjs
    • User path: a ChatGPT login against a fake endpoint that returns 400 without
      client_version (as the real one does) now yields a row with
      gpt-6.1-sol and a usable binding.
    • A failed list logs status: 400 and the excerpt, and the serialized log
      does not contain the access token.
  • Baseline: with the pre-fix vendor-live-models.ts and oauth.ts, the new
    tests fail (3 failures). With the fix, they pass.

Validation

Command Result
pnpm build:js pass
pnpm --filter @pi-desktop/desktop typecheck pass
pnpm lint pass
pnpm --filter @pi-desktop/desktop test 3270 / 3270 pass
pnpm docs:check pass (534 pages)
pnpm check:agent-policy, git diff --check pass
E2E NOT RUN. The change sits behind a live ChatGPT account endpoint that the E2E harness does not reach. It is covered by the user-path test above, which uses a fake fetch.

Risks

  • CODEX_MODELS_CLIENT_VERSION must be bumped by hand. If it goes stale, the
    request may still succeed but could omit newer models. Those then fall back
    to the pinned catalog, as they did before this fix.
  • The error excerpt comes from an upstream response. Credential removal is
    best-effort beyond the request's own token, and the logger redaction runs on
    top of it.

initH271 and others added 5 commits September 30, 2026 13:14
ChatGPT's GET /codex/models now rejects a request without the
client_version query parameter (HTTP 400, "client_version Field
required"). The account model list silently fell back to the pinned
pi-ai catalog, so a model the account already offers, such as
gpt-6.1-sol, could not be selected and session launch refused it with
MODEL_NOT_CONFIGURED.

pi-ai never calls this endpoint and has no Codex client version to
reuse, so pin the Codex CLI version verified to list the current
models in one documented constant. The endpoint also hides models
whose minimum client version is newer, so the constant is bumped when
an account model goes missing.
The vendor account model-list warning recorded only the HTTP status, so
the /codex/models contract change (a new required query parameter)
looked like an unexplained 400 and went unnoticed while the account
list quietly fell back to the pinned catalog.

Keep a short single-line excerpt of the error body on the thrown error
and log it with the status. The request's own Authorization / API key
value, bearer credentials and JWT-shaped strings are removed before the
excerpt leaves the module, in addition to the logger's own redaction.
@vastsa
vastsa merged commit 0012706 into vastsa:main Sep 30, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] ChatGPT account model list returns 400: /codex/models now requires client_version

2 participants