From c696a5fd9cf7ffaf32efec10a4a2a48255217f54 Mon Sep 17 00:00:00 2001 From: kshitijk4poor <82637225+kshitijk4poor@users.noreply.github.com> Date: Fri, 31 Jul 2026 16:10:12 +0530 Subject: [PATCH] fix(agent): harden the finalize-turn micro-compaction gate against duck-typed compressors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tests/run_agent/test_proactive_prune_loop_wiring.py builds agents with a MagicMock compressor; getattr(mock, '_micro_compact_enabled', False) returns a truthy auto-attribute, so the hook called _micro_compact on the mock and spliced its (empty-iterating) return over the transcript — wiping all messages before persist (CI slice 7/8 failure). Gate now requires _micro_compact_enabled is True, a callable _micro_compact, and a non-empty list result before touching messages. Same hardening protects production plugin context engines that don't subclass ContextCompressor. --- agent/turn_finalizer.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/agent/turn_finalizer.py b/agent/turn_finalizer.py index 110a104c46c..5078eed9d3e 100644 --- a/agent/turn_finalizer.py +++ b/agent/turn_finalizer.py @@ -358,13 +358,21 @@ def finalize_turn( if not interrupted and not failed: try: _compressor = getattr(agent, "context_compressor", None) + # Strict `is True` + isinstance gates: plugin context engines + # (and MagicMock compressors in tests) satisfy getattr/duck + # checks with truthy auto-attributes — a bare truthiness check + # here called _micro_compact on a mock and spliced its (empty- + # iterating) return value over the transcript, wiping it. if ( _compressor - and getattr(_compressor, '_micro_compact_enabled', False) + and getattr(_compressor, '_micro_compact_enabled', False) is True + and callable(getattr(_compressor, '_micro_compact', None)) and final_response ): _before = len(messages) - messages[:] = _compressor._micro_compact(messages) or messages + _compacted = _compressor._micro_compact(messages) + if isinstance(_compacted, list) and _compacted: + messages[:] = _compacted _after = len(messages) if _before != _after: logger.info(