fix(codex): drop dead model slugs that HTTP 400 on ChatGPT Pro (#33424)

DEFAULT_CODEX_MODELS shipped three slugs that the chatgpt.com Codex
backend rejects with HTTP 400 'The <slug> model is not supported when
using Codex with a ChatGPT account.' on every account tested live:

  gpt-5.2-codex
  gpt-5.1-codex-max
  gpt-5.1-codex-mini

Live verified against https://chatgpt.com/backend-api/codex/models
which returns gpt-5.5, gpt-5.4, gpt-5.4-mini, gpt-5.3-codex,
gpt-5.3-codex-spark, gpt-5.2 for ChatGPT Pro accounts.

When _fetch_models_from_api fell back to DEFAULT_CODEX_MODELS (offline
first-run, transient API failure) the picker surfaced these dead slugs
and crashed on selection. The forward-compat synthesis table chained
them downstream too.

If OpenAI re-enables them on the OAuth-backed Codex backend, live
discovery will pick them up automatically — the defaults list is only
consulted when live discovery is unavailable.

Test fixture pivoted to use gpt-5.3-codex (templated by 4 entries) as
the synthesis driver so the forward-compat test still exercises the
synthesis path.
This commit is contained in:
Teknium 2026-05-27 12:16:15 -07:00 committed by GitHub
parent 5deb384b53
commit e8955f222c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 21 additions and 10 deletions

View file

@ -29,21 +29,29 @@ DEFAULT_CODEX_MODELS: List[str] = [
# curated fallback so Pro users still see Spark in `/model` when live
# discovery is unavailable (offline first run, transient API failure).
"gpt-5.3-codex-spark",
"gpt-5.2-codex",
"gpt-5.1-codex-max",
"gpt-5.1-codex-mini",
# NOTE: gpt-5.2-codex / gpt-5.1-codex-max / gpt-5.1-codex-mini were
# previously listed here but the chatgpt.com Codex backend returns
# HTTP 400 "The '<model>' model is not supported when using Codex with
# a ChatGPT account." for all three on every ChatGPT Pro account we've
# tested (verified live 2026-05-27). Keeping them in the fallback list
# leaked dead slugs into /model when live discovery was unavailable
# (transient API failure, first-run before refresh) and surfaced HTTP 400
# crashes on selection. The Codex CLI public catalog still references
# these slugs, which is why they survived previously — but those entries
# describe the public OpenAI API, not the OAuth-backed Codex backend
# Hermes uses. Removed here. If OpenAI re-enables them on Codex backend,
# live discovery will pick them up automatically via _fetch_models_from_api.
]
_FORWARD_COMPAT_TEMPLATE_MODELS: List[tuple[str, tuple[str, ...]]] = [
("gpt-5.5", ("gpt-5.4", "gpt-5.4-mini", "gpt-5.3-codex")),
("gpt-5.4-mini", ("gpt-5.3-codex", "gpt-5.2-codex")),
("gpt-5.4", ("gpt-5.3-codex", "gpt-5.2-codex")),
("gpt-5.3-codex", ("gpt-5.2-codex",)),
("gpt-5.4-mini", ("gpt-5.3-codex",)),
("gpt-5.4", ("gpt-5.3-codex",)),
# Surface Spark whenever any compatible Codex template is present so
# accounts hitting the live endpoint with an older lineup still see
# Spark in the picker. Backend gates real availability by ChatGPT Pro
# entitlement; Hermes does not.
("gpt-5.3-codex-spark", ("gpt-5.3-codex", "gpt-5.2-codex")),
("gpt-5.3-codex-spark", ("gpt-5.3-codex",)),
]

View file

@ -60,16 +60,19 @@ def test_get_codex_model_ids_falls_back_to_curated_defaults(tmp_path, monkeypatc
def test_get_codex_model_ids_adds_forward_compat_models_from_templates(monkeypatch):
monkeypatch.setattr(
"hermes_cli.codex_models._fetch_models_from_api",
lambda access_token: ["gpt-5.2-codex"],
lambda access_token: ["gpt-5.3-codex"],
)
models = get_codex_model_ids(access_token="codex-access-token")
# When live discovery only returns gpt-5.3-codex, forward-compat synthesis
# should surface gpt-5.5, gpt-5.4, gpt-5.4-mini, and gpt-5.3-codex-spark
# (each is templated off gpt-5.3-codex).
assert models == [
"gpt-5.2-codex",
"gpt-5.3-codex",
"gpt-5.5",
"gpt-5.4-mini",
"gpt-5.4",
"gpt-5.3-codex",
"gpt-5.3-codex-spark",
]