From f2d4cf4f760fb1309466d2c52a4b32556fb407d7 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Sun, 31 May 2026 06:03:01 -0700 Subject: [PATCH] fix(cli): clamp post-compression token sentinel in status bar (#35858) The status bar read context_compressor.last_prompt_tokens directly with an 'or 0' guard that only catches 0/None. Right after a compression the compressor parks last_prompt_tokens at the -1 sentinel (awaiting_real_usage_after_compression) until the next API call reports real usage. -1 is truthy, so it sailed through and rendered as '-1/200K' and '-1%' for that one transitional turn. Clamp negative token/context-length values to 0 in the status-bar snapshot so the gap reads as empty context until real usage arrives. --- cli.py | 9 +++++++++ tests/cli/test_cli_status_bar.py | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/cli.py b/cli.py index 1e8229be4..e6bd71674 100644 --- a/cli.py +++ b/cli.py @@ -3577,8 +3577,17 @@ class HermesCLI: compressor = getattr(agent, "context_compressor", None) if compressor: + # last_prompt_tokens is parked at the -1 sentinel right after a + # compression, until the next real API call reports a prompt count + # (awaiting_real_usage_after_compression). The status bar must not + # render that sentinel verbatim — it produced "-1/200K" / "-1%". + # Clamp it to 0 so the one transitional turn reads as empty context. context_tokens = getattr(compressor, "last_prompt_tokens", 0) or 0 + if context_tokens < 0: + context_tokens = 0 context_length = getattr(compressor, "context_length", 0) or 0 + if context_length < 0: + context_length = 0 snapshot["context_tokens"] = context_tokens snapshot["context_length"] = context_length or None snapshot["compressions"] = getattr(compressor, "compression_count", 0) or 0 diff --git a/tests/cli/test_cli_status_bar.py b/tests/cli/test_cli_status_bar.py index f62287f62..47a78c570 100644 --- a/tests/cli/test_cli_status_bar.py +++ b/tests/cli/test_cli_status_bar.py @@ -81,6 +81,29 @@ class TestCLIStatusBar: assert "$0.06" not in text # cost hidden by default assert "15m" in text + def test_post_compression_sentinel_does_not_render_negative(self): + """Right after a compression, last_prompt_tokens is parked at the -1 + sentinel until the next API call reports real usage. The status bar + must clamp it to 0 instead of rendering "-1/200K" / "-1%". + """ + cli_obj = _attach_agent( + _make_cli(), + prompt_tokens=10_230, + completion_tokens=2_220, + total_tokens=12_450, + api_calls=7, + context_tokens=-1, + context_length=200_000, + ) + + snapshot = cli_obj._get_status_bar_snapshot() + assert snapshot["context_tokens"] == 0 + assert snapshot["context_percent"] == 0 + + text = cli_obj._build_status_bar_text(width=120) + assert "-1" not in text + assert "0/200K" in text + def test_input_height_counts_wide_characters_using_cell_width(self): cli_obj = _make_cli()