diff --git a/agent/model_metadata.py b/agent/model_metadata.py index a8590b58384..653a90619a5 100644 --- a/agent/model_metadata.py +++ b/agent/model_metadata.py @@ -1108,6 +1108,11 @@ _CODEX_OAUTH_CONTEXT_FALLBACK: Dict[str, int] = { "gpt-5.1-codex-max": 272_000, "gpt-5.1-codex-mini": 272_000, "gpt-5.3-codex": 272_000, + # Spark runs on specialised low-latency hardware and exposes a smaller + # 128k window than other Codex OAuth slugs. Listed explicitly so the + # longest-key-first fallback resolves it correctly — substring match + # on "gpt-5.3-codex" otherwise wins and reports 272k. Availability is + # gated by ChatGPT Pro entitlement on the Codex backend. "gpt-5.3-codex-spark": 128_000, "gpt-5.2-codex": 272_000, "gpt-5.4-mini": 272_000, diff --git a/hermes_cli/codex_models.py b/hermes_cli/codex_models.py index 9e388ef0892..8e50004c2d6 100644 --- a/hermes_cli/codex_models.py +++ b/hermes_cli/codex_models.py @@ -16,6 +16,18 @@ DEFAULT_CODEX_MODELS: List[str] = [ "gpt-5.4-mini", "gpt-5.4", "gpt-5.3-codex", + # gpt-5.3-codex-spark is in research preview and is exposed *only* via + # the Codex CLI / OAuth backend (chatgpt.com/backend-api/codex/models) + # for ChatGPT Pro subscribers. It is NOT available in the public OpenAI + # API, so it intentionally stays out of the "openai" provider catalog + # in hermes_cli/models.py — only the openai-codex (OAuth) provider + # surfaces it. The Codex backend reports ``supported_in_api: false`` for + # this slug; that flag describes API availability, not Codex backend + # availability, so the fetch/cache code paths below intentionally do + # not filter on it. PR #12994 removed this entry on the assumption it + # was unsupported — that was wrong; restored here. Keep it in the + # 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", @@ -27,6 +39,10 @@ _FORWARD_COMPAT_TEMPLATE_MODELS: List[tuple[str, tuple[str, ...]]] = [ ("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",)), + # 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")), ] diff --git a/hermes_cli/model_switch.py b/hermes_cli/model_switch.py index 3a282425dc4..d75aca5cd08 100644 --- a/hermes_cli/model_switch.py +++ b/hermes_cli/model_switch.py @@ -1343,6 +1343,13 @@ def list_authenticated_providers( continue if hermes_slug in {"openai-codex", "copilot", "copilot-acp"}: + # Use live OAuth-backed discovery so the gateway /model picker + # matches what the user's authenticated Codex/Copilot backend + # actually serves — including ChatGPT-Pro-only Codex slugs + # (e.g. gpt-5.3-codex-spark) that aren't in the static curated + # catalog. ``provider_model_ids()`` falls back to the curated + # list when the live endpoint is unreachable, so this is safe + # for unauthenticated and offline cases too. model_ids = provider_model_ids(hermes_slug) # For aws_sdk providers (bedrock), use live discovery so the list # reflects the active region (eu.*, ap.*) not the static us.* list.