feat(openai): complete gpt-5.6 E2E — codex catalog + 272K compaction auto-raise

Close the remaining end-to-end gaps so the full gpt-5.6 family (sol/
terra/luna + their -pro high-effort modes, 6 slugs) works on every
surface a user can reach them through:

- agent/auxiliary_client.py: the Codex OAuth backend hard-caps context
  at 272K for gpt-5.6 exactly as it does for 5.4/5.5, but the default
  50% compaction trigger would summarize at ~136K and waste half the
  usable window. Extend the existing _is_codex_gpt54_or_gpt55 chokepoint
  (single enforced predicate feeding _compression_threshold_for_model)
  to match gpt-5.6* on the openai-codex route so those sessions get the
  same 0.85 auto-raise. Direct-API/OpenRouter routes (full 1.05M window)
  are unaffected; the historical codex_gpt55_autoraise opt-out still
  applies. The one-time notice banner is model-dynamic and already
  renders the correct slug/cap.
- hermes_cli/config.py, agent/agent_init.py: refresh the autoraise
  comments/notice to mention the 5.6 family.
- hermes_cli/codex_models.py: add the -pro variants to DEFAULT_CODEX_MODELS
  + forward-compat so ChatGPT-OAuth (openai-codex) Pro users see the full
  family in /model, not just the base tiers.

Supersedes the earlier commit's note that 5.6 was intentionally kept out
of the codex catalog: the slugs are confirmed routable (OpenRouter live
+ codex backend), so they belong there like every other codex-capable
gpt-5.x slug.

E2E verified across all 6 slugs: direct-API ctx 1.05M, codex ctx 272K,
pricing reachable from openai + openai-api routes, codex compaction
override 0.85 (and None on direct-API + when opted out), present in
openai-api picker + codex catalog, /model gpt resolves to sol on both
native routes. Guard tests added for the compaction route matrix.
This commit is contained in:
Kshitij Kapoor 2026-07-10 00:26:28 +05:30 committed by kshitij
parent 5da7b23d6f
commit 4af484d3dd
5 changed files with 98 additions and 31 deletions

View file

@ -77,8 +77,8 @@ def _build_codex_gpt5_autoraise_notice(autoraise: Dict[str, Any]) -> str:
include the exact opt-back-out command.
"""
model = str(autoraise.get("model") or "gpt-5.4/5.5").strip().lower().rsplit("/", 1)[-1]
# gpt-5.3-codex-spark has a native 128K window; the gpt-5.4/5.5 family is
# capped at 272K by the Codex OAuth backend.
# gpt-5.3-codex-spark has a native 128K window; the gpt-5.4/5.5/5.6 family
# is capped at 272K by the Codex OAuth backend.
cap = "128K" if model.startswith("gpt-5.3-codex-spark") else "272K"
from_pct = int(round(autoraise["from"] * 100))
to_pct = int(round(autoraise["to"] * 100))

View file

@ -314,15 +314,18 @@ def _is_arcee_trinity_thinking(model: Optional[str]) -> bool:
return bare == "trinity-large-thinking"
# Context window enforced by ChatGPT's Codex OAuth backend for gpt-5.4/5.5.
# The raw OpenAI API and OpenRouter expose 1.05M for the same slug, but the
# Codex backend hard-caps at 272K (verified live: a ~330K-token request to
# Context window enforced by ChatGPT's Codex OAuth backend for the
# gpt-5.4 / gpt-5.5 / gpt-5.6 families. The raw OpenAI API and OpenRouter
# expose 1.05M for the same slugs, but the Codex backend hard-caps at 272K
# (verified live for 5.4/5.5: a ~330K-token request to
# chatgpt.com/backend-api/codex/responses is rejected with
# ``context_length_exceeded`` while ~250K succeeds). With a 272K ceiling the
# default 50% compaction trigger fires at ~136K — wasteful, since the model
# can hold far more raw context before summarization actually buys anything.
# We raise the trigger to 85% (~231K) on this exact route so Codex gpt-5.4/
# gpt-5.5 sessions use the window they actually have.
# ``context_length_exceeded`` while ~250K succeeds; gpt-5.6 shares the same
# 272K Codex cap — see _CODEX_OAUTH_CONTEXT_FALLBACK in model_metadata.py).
# With a 272K ceiling the default 50% compaction trigger fires at ~136K —
# wasteful, since the model can hold far more raw context before
# summarization actually buys anything. We raise the trigger to 85% (~231K)
# on this exact route so Codex gpt-5.4 / gpt-5.5 / gpt-5.6 sessions use the
# window they actually have.
_CODEX_GPT54_GPT55_COMPACTION_THRESHOLD = 0.85
# gpt-5.3-codex-spark is Codex-OAuth-only (ChatGPT Pro entitlement) with a
@ -336,14 +339,16 @@ _CODEX_SPARK_COMPACTION_THRESHOLD = 0.70
def _is_codex_gpt54_or_gpt55(model: Optional[str], provider: Optional[str] = None) -> bool:
"""True for gpt-5.4 / gpt-5.5 on the ChatGPT Codex OAuth backend.
"""True for gpt-5.4 / gpt-5.5 / gpt-5.6 on the ChatGPT Codex OAuth backend.
Matches only the Codex OAuth route (provider ``openai-codex``), not the
direct OpenAI API, OpenRouter, or GitHub Copilot paths those expose a
larger context window for the same slug and must keep the user's default
compaction threshold. ``gpt-5.4-pro`` / ``gpt-5.5-pro`` and dated snapshots
are matched via prefix so the override tracks both 272K-capped families
without re-listing every variant.
compaction threshold. ``-pro`` variants and dated snapshots are matched
via prefix so the override tracks every 272K-capped family (5.4, 5.5,
5.6 sol/terra/luna incl. their ``-pro`` modes) without re-listing every
variant. (Name kept for backward compatibility with the
``compression.codex_gpt55_autoraise`` config key.)
"""
prov = (provider or "").strip().lower()
if prov != "openai-codex":
@ -356,6 +361,9 @@ def _is_codex_gpt54_or_gpt55(model: Optional[str], provider: Optional[str] = Non
or bare == "gpt-5.5"
or bare.startswith("gpt-5.5-")
or bare.startswith("gpt-5.5.")
or bare == "gpt-5.6"
or bare.startswith("gpt-5.6-")
or bare.startswith("gpt-5.6.")
)
@ -410,11 +418,12 @@ def _compression_threshold_for_model(
Per-model/route overrides:
- Arcee Trinity Large Thinking 0.75 (preserve reasoning context).
- gpt-5.4 / gpt-5.5 on the Codex OAuth route 0.85, because Codex caps
both families at 272K and the default 50% trigger would compact at
~136K. Gated by ``allow_codex_gpt55_autoraise`` (historical config-key
name kept for backward compatibility) so the user can opt back down to
the global default (the caller passes the config flag through here).
- gpt-5.4 / gpt-5.5 / gpt-5.6 on the Codex OAuth route 0.85, because
Codex caps all three families at 272K and the default 50% trigger
would compact at ~136K. Gated by ``allow_codex_gpt55_autoraise``
(historical config-key name kept for backward compatibility) so the
user can opt back down to the global default (the caller passes the
config flag through here).
- gpt-5.3-codex-spark on the Codex OAuth route 0.70, because the model
has a native 128K window and the default 50% trigger would compact at
~64K wasting half the usable context. Not gated by the gpt-5.5

View file

@ -12,10 +12,14 @@ import os
logger = logging.getLogger(__name__)
DEFAULT_CODEX_MODELS: List[str] = [
# GPT-5.6 series (Sol/Terra/Luna) — GA 2026-07-09 (previewed 2026-06-26).
# GPT-5.6 series (Sol/Terra/Luna + -pro high-effort modes) — GA 2026-07-09
# (previewed 2026-06-26).
"gpt-5.6-sol",
"gpt-5.6-sol-pro",
"gpt-5.6-terra",
"gpt-5.6-terra-pro",
"gpt-5.6-luna",
"gpt-5.6-luna-pro",
"gpt-5.5",
"gpt-5.4-mini",
"gpt-5.4",
@ -49,8 +53,11 @@ DEFAULT_CODEX_MODELS: List[str] = [
_FORWARD_COMPAT_TEMPLATE_MODELS: List[tuple[str, tuple[str, ...]]] = [
("gpt-5.6-sol", ("gpt-5.5", "gpt-5.4")),
("gpt-5.6-sol-pro", ("gpt-5.5", "gpt-5.4")),
("gpt-5.6-terra", ("gpt-5.5", "gpt-5.4")),
("gpt-5.6-terra-pro", ("gpt-5.5", "gpt-5.4")),
("gpt-5.6-luna", ("gpt-5.5", "gpt-5.4")),
("gpt-5.6-luna-pro", ("gpt-5.5", "gpt-5.4")),
("gpt-5.5", ("gpt-5.4", "gpt-5.4-mini", "gpt-5.3-codex")),
("gpt-5.4-mini", ("gpt-5.3-codex",)),
("gpt-5.4", ("gpt-5.3-codex",)),

View file

@ -1423,17 +1423,18 @@ DEFAULT_CONFIG = {
# True if you'd rather pause than silently lose
# context turns when your aux model is flaky.
"codex_gpt55_autoraise": True, # Historical key name kept for compatibility.
# When True, gpt-5.4 / gpt-5.5 on the ChatGPT Codex
# OAuth route raise their compaction trigger to 85%
# (vs the global `threshold` above). Codex hard-caps
# both families at a 272K window, so the default 50%
# would compact at ~136K and waste half the usable
# context. Set to False to opt back down to the global
# threshold (e.g. 0.50) for those Codex sessions.
# Only this exact route is affected — gpt-5.4 / 5.5
# on OpenAI's direct API, OpenRouter, and Copilot keep
# the global threshold regardless.
"codex_gpt55_autoraise_notice": True, # Display the one-time Codex gpt-5.4/5.5
# When True, gpt-5.4 / gpt-5.5 / gpt-5.6 on the
# ChatGPT Codex OAuth route raise their compaction
# trigger to 85% (vs the global `threshold` above).
# Codex hard-caps these families at a 272K window, so
# the default 50% would compact at ~136K and waste half
# the usable context. Set to False to opt back down to
# the global threshold (e.g. 0.50) for those Codex
# sessions. Only this exact route is affected —
# gpt-5.4 / 5.5 / 5.6 on OpenAI's direct API,
# OpenRouter, and Copilot keep the global threshold
# regardless.
"codex_gpt55_autoraise_notice": True, # Display the one-time Codex gpt-5.4/5.5/5.6
# autoraise banner. Set False to keep the
# 85% threshold autoraise but suppress the
# user-facing notice in CLI/gateway output.

View file

@ -81,3 +81,53 @@ class TestGpt56PricingRoute:
_OFFICIAL_DOCS_PRICING[("openai", f"{base}-pro")]
is _OFFICIAL_DOCS_PRICING[("openai", base)]
), base
class TestGpt56CodexCompaction:
"""Codex OAuth caps the whole gpt-5.6 family at 272K, same as 5.4/5.5, so
the compaction auto-raise (0.85) must fire for every 5.6 variant on the
openai-codex route and NOT on the direct-API/OpenRouter routes."""
def test_autoraise_applies_to_all_56_on_codex(self):
from agent.auxiliary_client import _compression_threshold_for_model
for slug in (
"gpt-5.6-sol",
"gpt-5.6-sol-pro",
"gpt-5.6-terra",
"gpt-5.6-terra-pro",
"gpt-5.6-luna",
"gpt-5.6-luna-pro",
):
assert (
_compression_threshold_for_model(slug, provider="openai-codex")
== 0.85
), slug
def test_no_autoraise_on_direct_api_route(self):
from agent.auxiliary_client import _compression_threshold_for_model
# Direct OpenAI API / OpenRouter expose the full 1.05M window, so the
# 272K-cap override must NOT apply there.
assert (
_compression_threshold_for_model("gpt-5.6-sol", provider="openai")
is None
)
assert (
_compression_threshold_for_model(
"openai/gpt-5.6-sol", provider="openrouter"
)
is None
)
def test_autoraise_respects_opt_out(self):
from agent.auxiliary_client import _compression_threshold_for_model
assert (
_compression_threshold_for_model(
"gpt-5.6-sol",
provider="openai-codex",
allow_codex_gpt55_autoraise=False,
)
is None
)