fix(compression): detect semantic no-op results

This commit is contained in:
Jan-Stefan Janetzky 2026-07-20 00:07:10 +00:00 committed by Teknium
parent 75af6dc57c
commit 766c617e83
2 changed files with 45 additions and 4 deletions

View file

@ -28,6 +28,7 @@ these paths see no behavioural change.
from __future__ import annotations
import copy
import inspect
import logging
import os
@ -1055,6 +1056,7 @@ def compress_context(
engine_name,
)
messages_before_compression = copy.deepcopy(messages)
compressed = compress_fn(messages, **compress_kwargs)
except BaseException:
# ANY exception after lock acquisition — memory hook, capability
@ -1097,10 +1099,13 @@ def compress_context(
finally:
_release_lock()
# A compressor that returns the exact input object made no structural
# progress. Do not rotate/rewrite the session or arm post-compression
# deferral in that case; its own anti-thrash counter records the no-op.
if compressed is messages:
# Compare against the pre-dispatch semantic state, not object identity:
# legacy/plugin engines may return an equal copy for a no-op, or mutate
# the live list while returning an unchanged snapshot. Neither case may
# rotate or rewrite the session.
if compressed == messages_before_compression:
if messages != messages_before_compression:
messages[:] = copy.deepcopy(messages_before_compression)
logger.info(
"Compression made no progress (session=%s) — skipping boundary rewrite.",
agent.session_id or "none",

View file

@ -371,6 +371,42 @@ def test_empty_compression_result_does_not_rotate_session(tmp_path: Path) -> Non
assert db.get_session(parent_sid)["end_reason"] is None
@pytest.mark.parametrize("in_place", [False, True])
def test_equal_copy_compression_result_does_not_rewrite_session(
tmp_path: Path,
in_place: bool,
) -> None:
db = SessionDB(db_path=tmp_path / "state.db")
parent_sid = f"EQUAL_COPY_NOOP_{in_place}"
db.create_session(parent_sid, source="cli")
agent = _build_agent_with_db(db, parent_sid)
setattr(agent, "compression_in_place", in_place)
messages = [{"role": "user", "content": f"m{i}"} for i in range(20)]
compressor = getattr(agent, "context_compressor")
compressor.compress.side_effect = lambda incoming, **_kw: list(incoming)
with patch.object(
db,
"archive_and_compact",
wraps=db.archive_and_compact,
) as archive_and_compact:
returned, _sp = agent._compress_context(
messages,
"sys",
approx_tokens=120_000,
)
assert returned is messages
assert getattr(agent, "session_id") == parent_sid
assert _count_children(db, parent_sid) == 0
parent = db.get_session(parent_sid)
assert parent is not None
assert parent["end_reason"] is None
assert db.get_compression_lock_holder(parent_sid) is None
archive_and_compact.assert_not_called()
def test_lock_refresh_keeps_owner_live_past_initial_ttl(tmp_path: Path, monkeypatch) -> None:
"""The owning compression call must keep its lease alive while it runs."""
real_try_acquire = SessionDB.try_acquire_compression_lock