Skip to content

fix(compression): warn the user when compression is blocked but context keeps growing - #69857

Merged
teknium1 merged 5 commits into
mainfrom
salvage/62625-warn-blocked
Jul 23, 2026
Merged

fix(compression): warn the user when compression is blocked but context keeps growing#69857
teknium1 merged 5 commits into
mainfrom
salvage/62625-warn-blocked

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

When a session's context crosses the compression threshold but automatic compression is blocked (summary-LLM cooldown or the anti-thrash breaker), the user now gets a visible, deduped warning telling them to run /new or /compress — instead of the session silently growing until it dies at the hard provider token limit. Root cause: should_compress() returns a bare False on the veto paths and every guard only logger.info'd the skip, so the failure mode was invisible from chat (the warning half of #62708).

Changes

  • agent/context_compressor.py: should_compress_info() returns (bool, reason) (cooldown:<s> / ineffective); on current main's refactored gate it derives the reason from the same in-memory state via a new _compression_block_reason() helper. should_compress() keeps its bool contract.
  • agent/context_engine.py: backward-compatible ABC default should_compress_info()(should_compress(tokens), None) so plugin engines never raise AttributeError (follow-up: the PR's default had no return statement — it returned None and would have crashed tuple-unpacking call sites).
  • run_agent.py: centralized AIAgent._warn_context_overflow_blocked() / _clear_context_overflow_warn() — dedup keys on the block kind so a ticking cooldown doesn't re-fire every turn.
  • agent/turn_context.py + agent/conversation_loop.py: all three automatic-compression guards (preflight, pre-API, post-tool loop compaction) warn when blocked-over-threshold, and every compression path resets the dedup — closing the sweeper-review gap where the block clearing while still over threshold entered the compression branch and skipped the else reset, suppressing the warning forever after.
  • Below-threshold guard (follow-up): the persisted-cooldown branches no longer warn when the estimate is under threshold, and the pre-API guard honors compression.max_attempts instead of a hardcoded 3.
  • agent/conversation_compression.py: warning text is a template constant (CONTEXT_OVERFLOW_BLOCKED_WARNING_TEMPLATE) marked FAILURE-CLASS — deliberately not in ROUTINE_COMPRESSION_STATUS_SAMPLES or the noise regex; wording composes with fix(compression): floor the threshold recommendation at the effective small-context minimum #69332's recomputed-trigger notice (no contradictory threshold advice, just /new / /compress).
  • tests/: PR's suite (tuple shape, both block kinds, dedup, re-fire) + follow-up tests: dedup-reset-while-still-over-threshold, below-threshold cooldown no-warn, plugin-engine ABC default, and noise-filter survival tests that execute the real _TELEGRAM_NOISY_STATUS_RE (fix(gateway): suppress routine pre-API compression chatter on chat platforms #69550-widened) and _prepare_gateway_status_message end-to-end; both reason shapes pinned un-swallowed in VISIBLE_COMPRESSION_MESSAGES.

Validation

Before After
Over threshold, compression blocked bare False, logger.info only — user sees nothing until token-limit death deduped ⚠ warning in chat with /new / /compress guidance
Block clears while still over threshold dedup never reset — warning suppressed forever after first block reset on every compression path; warning re-fires on next block
Plugin engine at the new call sites AttributeError (contract only required should_compress) ABC default returns (should_compress(tokens), None)
Warning vs gateway noise filter unverified against #69550-widened regex pinned un-swallowed on every chat platform

Targeted tests: 630 passed (overflow-warning suite ×19, turn-context ×18, telegram noise filter ×587, plugin engine init ×6); -k 'blocked or overflow_warn or should_compress_info' sweep: 532 passed, 0 failed; sibling compressor suites (rotation state, idle compaction, context compressor, feasibility): 246 passed.

Credit

Salvaged from #62625 by @sl4m3. Addresses the warning half of #62708.

Infographic

blocked-compression-warning

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on 7bf9005

ℹ️ Info

Desktop E2E visual evidence · View test artifacts · View job

1 visual diff.

inline evidence upload failed.

Failed to upload diff-665a0833239e-onboarding-overlay-diff.png with gh image (exit code 1): Error uploading /home/runner/work/_temp/e2e-evidence/diff-665a0833239e-onboarding-overlay-diff.png: step 0 (get upload token): uploadToken not found on repo page — do you have write access to NousResearch/hermes-agent? (or, if NousResearch enforces SAML SSO, authorize at https://github.com/orgs/NousResearch/sso)

@alt-glitch alt-glitch added type/feature New feature or request comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state needs-decision Awaiting maintainer decision before any implementation labels Jul 23, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related: #62625 already proposes blocked-compression warning plumbing for #62708. This patch has additional current-head follow-ups; both solve the same user-visible warning goal, so maintainers should choose or consolidate rather than treat either as a duplicate.

@teknium1
teknium1 force-pushed the salvage/62625-warn-blocked branch from 7a73af2 to b941729 Compare July 23, 2026 14:59
Stanislav and others added 5 commits July 23, 2026 08:28
…ssion is blocked

Previously, when a session crossed the compression threshold but compression
was skipped (summary-LLM cooldown, #11529, or anti-thrashing, #40803), the
model kept accumulating context until it hit the hard provider token limit and
silently stopped answering — with no signal to the user about why.

Changes:
- context_compressor.should_compress_info() returns a (should_compress, reason)
  tuple. reason is 'cooldown:<seconds>' or 'ineffective' when compression is
  needed but blocked. should_compress() keeps its bool contract so existing
  callers (conversation_loop.py) and regression #29335 are unaffected.
- turn_context.build_turn_context() emits a deduped _emit_warning when the
  context is over threshold but compression is blocked, advising /new or
  /compress. Dedup keys on the block *kind* (cooldown/ineffective), not the
  ticking countdown, so a cooldown doesn't re-fire the warning every turn.
- Adds tests/agent/test_turn_context_overflow_warning.py covering the tuple
  shape, both block kinds, dedup, and re-fire-after-clear.
- ContextEngine.should_compress_info() default impl so plugin engines
  (e.g. _StubEngine) don't raise AttributeError at the call site.
- Centralise warning/reset in AIAgent._warn_context_overflow_blocked /
  _clear_context_overflow_warn so turn-context and conversation-loop guards
  share identical dedup logic and reset on the real compression boundary.
- Cover conversation_loop.py pre-API (~L1007) and loop-compaction (~L4774)
  guards, not just the turn-context preflight.
- _FakeAgent mirrors the two helpers; test suite green (219 passed).

Fixes #62708
…ath + noise-filter survival pins

Follow-up fixes for the #62625 salvage:

- Dedup-reset gap (sweeper review): when the block clears while the
  context is STILL over threshold, execution enters the compression
  branch — the PR's 'else' reset never ran, so the warning stayed
  suppressed forever after the first block. _clear_context_overflow_warn()
  now fires on every automatic compression path: turn-context preflight,
  conversation_loop pre-API gate, and the post-tool loop-compaction gate.
- should_compress_info on current main: main refactored should_compress
  into _automatic_compression_blocked()/_locally(); the tuple variant now
  derives its reason from the same in-memory state via
  _compression_block_reason(), keeping cooldown:<s>/ineffective shapes.
- ContextEngine.should_compress_info ABC default now actually returns
  (should_compress(tokens), None) — the PR's default had a docstring but
  no return (returned None, would crash tuple-unpacking call sites).
- Below-threshold guard: the turn-context persisted-cooldown branch and
  the conversation_loop pre-API cooldown branch no longer warn when the
  estimate is under threshold (should_compress_info returns a None
  reason; the preflight pre-check is not a threshold guarantee). The
  pre-API guard also honors compression.max_attempts instead of a
  hardcoded 3, and no longer fabricates a cooldown reason.
- Noise-filter survival (#69550 composition): warning text is now a
  template constant (CONTEXT_OVERFLOW_BLOCKED_WARNING_TEMPLATE) marked
  FAILURE-CLASS, pinned un-swallowed in VISIBLE_COMPRESSION_MESSAGES and
  in new tests that execute the real _TELEGRAM_NOISY_STATUS_RE +
  _prepare_gateway_status_message.
- Contributor mapping for stanislav@local -> sl4m3.
…t doubles

The dedup-reset calls assumed a full AIAgent; gateway/loop test doubles
built via object.__new__ lack _clear_context_overflow_warn and crashed
in build_turn_context (caught by test_api_content_sidecar on CI slice 3).
getattr-guard all four call sites per the established test-double pitfall
pattern (AGENTS.md #17).
…ight

Two composition fixes vs the merged #69865 engine-preflight arm:
1. should_compress_info probe getattr-guarded — minimal compressor
   doubles (SimpleNamespace) and plugin engines lack it; absence means
   no block reason, no warning.
2. Engine maintenance hook stays un-consulted when any skip-branch
   fired (failure cooldown / deferred estimate / codex-native) —
   restoring the #20316 contract the warn-chain restructure broke.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint needs-decision Awaiting maintainer decision before any implementation P3 Low — cosmetic, nice to have sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants