# NousResearch/hermes-agent · Route compression warning to TUI via status emit

## Open now

- Nothing open on GitHub.

These issues and PRs address a bug where the compression count warning (indicating accuracy degradation) is silently lost and never displayed in the TUI. The fix routes this warning through the _emit_status mechanism so it reaches the user interface.

## TL;DR

- 3 member(s): 0 open issue(s), 1 closed issue(s), 0 open PR(s), 1 merged PR(s), 1 PR(s) closed without merging.
- A fix was merged to main in PR #50302. Verify it addresses your case.
- **Recommended:** read PR #50302 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `unresolved`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_SPANNING`): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
- Pairwise link density `0.67`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #36908: TUI: compression count warning (accuracy degrade) is silently swallowed

## Prior & competing PRs

- **#50302: fix(agent): route repeated-compression warning through _emit_status (#36908)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `agent/conversation_compression.py`, `tests/agent/test_compression_count_warning_36908.py`
  - fix hunks:
  - `agent/conversation_compression.py`

    ```diff
    @@ -719,14 +719,20 @@ def _release_lock() -> None:
         except Exception as _me_err:
             logger.debug("memory manager on_session_switch (compression): %s", _me_err)
     
    -    # Warn on repeated compressions (quality degrades with each pass)
    +    # Warn on repeated compressions (quality degrades with each pass).
    +    # Route through _emit_status (like the other compression warnings above)
    +    # so the warning reaches the TUI / Telegram / Discord via status_callback,
    +    # not just CLI stdout. _emit_status still _vprints for the CLI, and
    +    # storing it on _compression_warning lets replay_compression_warning
    +    # re-deliver it once a late-bound gateway status_callback is wired (#36908).
         _cc = agent.context_compressor.compression_count
         if _cc >= 2:
    -        agent._vprint(
    +        _cc_msg = (
                 f"{agent.log_prefix}⚠️  Session compressed {_cc} times — "
    -            f"accuracy may degrade. Consider /new to start fresh.",
    -            force=True,
    +            f"accuracy may degrade. Consider /new to start fresh."
             )
    +        agent._compression_warning = _cc_msg
    +        agent._emit_status(_cc_msg)
     
         # Emit session:compress event so hooks (e.g. MemPalace sync) can ingest
         # the completed old session before its details are lost. In in-place mode
    ```
  - `tests/agent/test_compression_count_warning_36908.py`

    ```diff
    @@ -0,0 +1,87 @@
    +"""Regression for #36908: the repeated-compression warning must reach the
    +TUI / gateway, not just CLI stdout.
    +
    +When a session is compressed >= 2 times, ``compress_context`` warns that
    +accuracy may degrade. That warning used to go through ``_vprint`` (stdout
    +only), so the Ink TUI / Telegram / Discord never saw it — unlike the two
    +other compression warnings in the same module, which route through
    +``_emit_status`` (and store ``_compression_warning`` for late-bound
    +gateway replay). This pins the warning onto the gateway-aware channel.
    +"""
    +
    +from __future__ import annotations
    +
    +import os
    +from pathlib import Path
    +from unittest.mock import MagicMock, patch
    +
    +from hermes_state import SessionDB
    +
    +
    +def _build_agent_with_db(db: SessionDB, session_id: str, compression_count: int):
    +    with patch.dict(os.environ, {"OPENROUTER_API_KEY": "[redacted:secret-assignment]"}):
    +        from run_agent import AIAgent
    +
    +        agent = AIAgent(
    +            api_key="[redacted:secret-assignment]",
    +            base_url="https://openrouter.ai/api/v1",
    +            model="test/model",
    +            quiet_mode=True,
    +            session_db=db,
    +            session_id=session_id,
    +            skip_context_files=True,
    +            skip_memory=True,
    +        )
    +
    +    compressor = MagicMock()
    +    compressor.compress.return_value = [
    +        {"role": "user", "content": "[CONTEXT COMPACTION] summary"},
    +        {"role": "user", "content": "tail"},
    +    ]
    +    compressor.compression_count = compression_count
    +    compressor.last_prompt_tokens = 0
    +    compressor.last_completion_tokens = 0
    +    compressor._last_summary_error = None
    +    compressor._last_compress_aborted = False
    +    compressor._last_aux_model_failure_model = None
    +    compressor._last_aux_model_failure_error = None
    +    agent.context_compressor = compressor
    +    return agent
    +
    +
    +def test_repeated_compression_warning_routed_through_emit_status(tmp_path: Path) -> None:
    +    db = SessionDB(db_path=tmp_path / "state.db")
    +    sid = "PARENT_36908"
    +    db.create_session(sid, source="cli")
    +
    +    # compression_count == 2 → the "compressed N times" warning should fire.
    +    agent = _build_agent_with_db(db, sid, compression_count=2)
    +
    +    emitted: list[str] = []
    +    agent._emit_status = lambda message: emitted.append(message)
    +
    +    messages = [{"role": "user", "content": f"m{i}"} for i in range(20)]
    +    agent._compress_context(messages, "sys", approx_tokens=[redacted:secret-assignment]
    +
    +    # The warning reached the gateway-aware channel...
    +    assert any("compressed 2 times" in m.lower() for m in emitted), (
    +        f"repeated-compression warning not emitted via _emit_status: {emitted}"
    +    )
    +    # ...and was stored for late-bound gateway status_callback replay.
    +    assert "compressed 2 times" in (getattr(agent, "_compression_warning", "") or "").lower()
    +
    +
    +def test_no_warning_below_threshold(tmp_path: Path) -> None:
    +    db = SessionDB(db_path=tmp_path / "state.db")
    +    sid = "PARENT_36908_ONCE"
    +    db.create_session(sid, source="cli")
    +
    +    # compression_count == 1 → no repeated-compression warning.
    +    agent = _build_agent_with_db(db, sid, compression_count=1)
    +    emitted: list[str] = []
    +    agent._emit_status = lambda message: emitted.append(message)
    +
    +    messages = [{"role": "user", "content": f"m{i}"} for i in range(20)]
    +    agent._compress_context(messages, "sys", approx_tokens=[redacted:secret-assignment]
    +
    +    assert not any("compressed" in m.lower() and "times" in m.lower() for m in emitted)
    ```
- **#36922: fix(agent): route compression count warning through _emit_status for TUI delivery**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `#50302`

## Fix status

- Merged to main in PR #50302 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-06-21`.
- Subsystem: `agent`
