fix(compressor): skip compression during summary LLM cooldown to prevent CLI freeze
When the summary LLM hits a 429/transient failure, _generate_summary() sets a cooldown and returns None; compress() inserts a static fallback marker and returns. Tokens stay above threshold, so should_compress() kept returning True and every subsequent agent turn re-fired _compress_context() — the CLI appeared frozen until the cooldown expired. Add a cooldown guard to should_compress(): return False while _summary_failure_cooldown_until is in the future. Reuses the existing float; no new state. Manual /compress (force=True) still clears the cooldown first. Fixes #11529
This commit is contained in:
parent
0e4c879a3b
commit
812236bff8
2 changed files with 52 additions and 0 deletions
|
|
@ -16,6 +16,8 @@ The fix adds two safeguards:
|
|||
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
import time
|
||||
|
||||
from agent.context_compressor import ContextCompressor, _CHARS_PER_TOKEN
|
||||
|
||||
|
||||
|
|
@ -248,3 +250,36 @@ class TestAntiThrashing:
|
|||
comp = _make_compressor(config_context_length=96000)
|
||||
comp.last_prompt_tokens = 10_000
|
||||
assert not comp.should_compress(10_000)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Test: summary-LLM cooldown guard in should_compress (#11529)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestCooldownGuard:
|
||||
"""should_compress() must skip compression while the summary LLM is in
|
||||
cooldown, otherwise a 429/transient failure re-fires _compress_context()
|
||||
every turn (inserting a fallback marker repeatedly) and freezes the CLI.
|
||||
"""
|
||||
|
||||
def test_active_cooldown_blocks(self):
|
||||
"""A future cooldown deadline -> should_compress returns False even
|
||||
when tokens are over threshold."""
|
||||
comp = _make_compressor(config_context_length=96000)
|
||||
comp.last_prompt_tokens = 65_000
|
||||
comp._summary_failure_cooldown_until = time.monotonic() + 60
|
||||
assert not comp.should_compress(65_000)
|
||||
|
||||
def test_expired_cooldown_allows(self):
|
||||
"""A past cooldown deadline -> compression resumes normally."""
|
||||
comp = _make_compressor(config_context_length=96000)
|
||||
comp.last_prompt_tokens = 65_000
|
||||
comp._summary_failure_cooldown_until = time.monotonic() - 1
|
||||
assert comp.should_compress(65_000)
|
||||
|
||||
def test_no_cooldown_allows(self):
|
||||
"""The default (no cooldown set) does not block compression."""
|
||||
comp = _make_compressor(config_context_length=96000)
|
||||
comp.last_prompt_tokens = 65_000
|
||||
assert comp._summary_failure_cooldown_until == 0.0
|
||||
assert comp.should_compress(65_000)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue