diff --git a/agent/agent_init.py b/agent/agent_init.py index 41ed85e998d..7539d59d35d 100644 --- a/agent/agent_init.py +++ b/agent/agent_init.py @@ -1403,10 +1403,15 @@ def init_agent( # compact at ~136K — half the usable context). Gated by an opt-out config # flag so the user can fall back to the global threshold; when the override # fires we stash a one-time notification (replayed on the first turn) that - # tells the user what changed and how to revert. + # tells the user what changed and how to revert. The notice has its own + # display gate so users can keep the threshold autoraise without getting + # the banner on gateway turns. _codex_gpt55_autoraise = str( _compression_cfg.get("codex_gpt55_autoraise", True) ).lower() in {"true", "1", "yes"} + _codex_gpt55_autoraise_notice = str( + _compression_cfg.get("codex_gpt55_autoraise_notice", True) + ).lower() in {"true", "1", "yes"} agent._compression_threshold_autoraised = None try: from agent.auxiliary_client import ( @@ -1891,7 +1896,7 @@ def init_agent( # gateway users get the same text replayed via _compression_warning on # turn 1 (set below, after the warning slot is initialized). _autoraise = getattr(agent, "_compression_threshold_autoraised", None) - if _autoraise and compression_enabled: + if _autoraise and compression_enabled and _codex_gpt55_autoraise_notice: print(_build_codex_gpt55_autoraise_notice(_autoraise)) # Check immediately so CLI users see the warning at startup. @@ -1902,7 +1907,7 @@ def init_agent( # above only reaches the CLI, so stash the same text here to be replayed # through status_callback on the first turn (Telegram/Discord/Slack/etc.). _autoraise = getattr(agent, "_compression_threshold_autoraised", None) - if _autoraise and compression_enabled: + if _autoraise and compression_enabled and _codex_gpt55_autoraise_notice: agent._compression_warning = _build_codex_gpt55_autoraise_notice(_autoraise) # Lazy feasibility check: deferred to the first turn that approaches the # compression threshold. Running it eagerly here costs ~400ms cold (network diff --git a/hermes_cli/config.py b/hermes_cli/config.py index 797f4d0977e..531d419ab80 100644 --- a/hermes_cli/config.py +++ b/hermes_cli/config.py @@ -1367,6 +1367,10 @@ DEFAULT_CONFIG = { # exact route is affected — gpt-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.5 + # autoraise banner. Set False to keep the + # 85% threshold autoraise but suppress the + # user-facing notice in CLI/gateway output. "in_place": True, # When True, compaction rewrites the message # list and rebuilds the system prompt WITHOUT # rotating the session id — the conversation diff --git a/tests/agent/test_codex_gpt55_autoraise_notice.py b/tests/agent/test_codex_gpt55_autoraise_notice.py new file mode 100644 index 00000000000..46e733a4e11 --- /dev/null +++ b/tests/agent/test_codex_gpt55_autoraise_notice.py @@ -0,0 +1,77 @@ +"""Regression tests for the Codex gpt-5.5 autoraise notice gate.""" + +from __future__ import annotations + +import contextlib +import io +from pathlib import Path + +from hermes_state import SessionDB +from run_agent import AIAgent + + +def _config(*, show_notice: bool) -> dict: + return { + "compression": { + "enabled": True, + "threshold": 0.50, + "target_ratio": 0.20, + "protect_first_n": 3, + "protect_last_n": 20, + "codex_gpt55_autoraise": True, + "codex_gpt55_autoraise_notice": show_notice, + }, + "prompt_caching": {"cache_ttl": "5m"}, + "sessions": {}, + "bedrock": {}, + } + + +def _make_codex_agent(monkeypatch, tmp_path: Path, *, show_notice: bool): + """Construct a real Codex gpt-5.5 agent under an isolated config.""" + from hermes_cli import config as config_mod + + monkeypatch.setattr(config_mod, "load_config", lambda: _config(show_notice=show_notice)) + db = SessionDB(db_path=tmp_path / "state.db") + stdout = io.StringIO() + + with contextlib.redirect_stdout(stdout): + agent = AIAgent( + base_url="https://chatgpt.com/backend-api/codex", + api_key="test-key", + provider="openai-codex", + model="gpt-5.5", + enabled_toolsets=[], + disabled_toolsets=[], + quiet_mode=False, + skip_memory=True, + session_db=db, + session_id="codex-notice-test", + ) + + return agent, stdout.getvalue() + + +def _threshold_ratio(agent: AIAgent) -> float: + compressor = getattr(agent, "context_compressor") + return round(compressor.threshold_tokens / compressor.context_length, 2) + + +def test_codex_gpt55_autoraise_notice_enabled_by_default(monkeypatch, tmp_path): + agent, stdout = _make_codex_agent(monkeypatch, tmp_path, show_notice=True) + + assert _threshold_ratio(agent) == 0.85 + warning = getattr(agent, "_compression_warning") + assert warning is not None + assert "auto-compaction was raised" in warning + assert "auto-compaction was raised" in stdout + + +def test_codex_gpt55_autoraise_notice_can_be_suppressed_without_disabling_autoraise( + monkeypatch, tmp_path +): + agent, stdout = _make_codex_agent(monkeypatch, tmp_path, show_notice=False) + + assert _threshold_ratio(agent) == 0.85 + assert getattr(agent, "_compression_warning") is None + assert "auto-compaction was raised" not in stdout diff --git a/website/docs/developer-guide/context-compression-and-caching.md b/website/docs/developer-guide/context-compression-and-caching.md index 93240a486c0..5ea16474491 100644 --- a/website/docs/developer-guide/context-compression-and-caching.md +++ b/website/docs/developer-guide/context-compression-and-caching.md @@ -85,6 +85,7 @@ compression: target_ratio: 0.20 # How much of threshold to keep as tail (default: 0.20) protect_last_n: 20 # Minimum protected tail messages (default: 20) codex_gpt55_autoraise: true # gpt-5.5 on Codex OAuth: raise trigger to 85% (default: true) + codex_gpt55_autoraise_notice: true # Show the one-time autoraise notice (default: true) # Summarization model/provider configured under auxiliary: auxiliary: @@ -103,6 +104,7 @@ auxiliary: | `protect_last_n` | `20` | ≥1 | Minimum number of recent messages always preserved | | `protect_first_n` | `3` | (hardcoded) | System prompt + first exchange always preserved | | `codex_gpt55_autoraise` | `true` | bool | Raise the trigger to 85% for gpt-5.5 on the ChatGPT Codex OAuth route (see below). Set `false` to keep the global `threshold` | +| `codex_gpt55_autoraise_notice` | `true` | bool | Show the one-time Codex gpt-5.5 autoraise notice. Set `false` to keep the 85% autoraise but suppress the banner | ### Codex gpt-5.5 threshold autoraise @@ -119,6 +121,12 @@ your global `threshold`. To opt back down to the global value: hermes config set compression.codex_gpt55_autoraise false ``` +To keep the 85% autoraise but hide only the one-time notice: + +```bash +hermes config set compression.codex_gpt55_autoraise_notice false +``` + ### Computed Values (for a 200K context model at defaults) ```