Files
hermes-agent/tests/agent/test_context_compressor_bench_probe.py
kshitijk4poor 364319d956 fix(compaction): carry the bench probe deadline across rotating compaction
Rotating compaction (compression.in_place: false) calls on_session_start
with boundary_reason="compression"; bind_session_state zeroes
_fallback_probe_at and reloads it from the fresh child row, which has no
model-config key. The fallback streak was carried but the deadline was
not, so the benched summary model was re-benched with a new window on
every rotation and never probed again. Capture the deadline before the
rebind and persist it onto the child row alongside the streak.
2026-10-06 12:03:52 +05:30

55 lines
2.6 KiB
Python

"""The summary-model bench (fallback streak >= 2) and its persisted probe window."""
from unittest.mock import patch
from agent.context_compressor import ContextCompressor
from hermes_state import SessionDB
def _compressor():
with patch("agent.context_compressor.get_model_context_length", return_value=100000):
c = ContextCompressor(model="test/model", threshold_percent=0.85, protect_first_n=2, protect_last_n=2, quiet_mode=True)
_ = c.context_length
return c
def _messages(n_pairs=10):
msgs = [{"role": "system", "content": "system prompt"}]
for i in range(n_pairs):
msgs += [{"role": "user", "content": f"question {i}"}, {"role": "assistant", "content": "short reply"}]
return msgs
def test_bench_probe_deadline_survives_a_compressor_rebuild(tmp_path):
"""The gateway rebuilds the agent on cache eviction: a fresh compressor bound to the same
session must resume the persisted bench window, not restart it (else the probe starves)."""
db = SessionDB(db_path=tmp_path / "state.db")
db.create_session("s1", "cli")
db.set_compression_fallback_streak("s1", 2)
compressor = _compressor()
compressor.bind_session_state(db, "s1")
window = compressor._ANTI_THRASH_RECOVERY_SECONDS
with patch("agent.context_compressor.time.time", return_value=1000.0), \
patch.object(compressor, "_generate_summary", return_value="LLM summary") as mock_gen:
compressor.compress(_messages(), force=False) # benched, arms the window
mock_gen.assert_not_called()
rebuilt = _compressor()
rebuilt.bind_session_state(db, "s1")
with patch("agent.context_compressor.time.time", return_value=1000.0 + window + 1), \
patch.object(rebuilt, "_generate_summary", return_value="LLM summary") as mock_gen:
rebuilt.compress(_messages(), force=False)
mock_gen.assert_called_once()
# Rotating compaction (in_place: false) binds a fresh child row: the deadline must follow it.
with patch("agent.context_compressor.time.time", return_value=2000.0), \
patch.object(rebuilt, "_generate_summary", return_value="LLM summary"):
rebuilt.compress(_messages(), force=False) # benched again, re-arms the window
db.create_session("s2", "cli", parent_session_id="s1")
rebuilt.on_session_start("s2", boundary_reason="compression", old_session_id="s1", session_db=db)
with patch("agent.context_compressor.time.time", return_value=2000.0 + window + 1), \
patch.object(rebuilt, "_generate_summary", return_value="LLM summary") as mock_gen:
rebuilt.compress(_messages(), force=False)
mock_gen.assert_called_once()