fix(compression): refresh gateway activity during compaction

Refresh the agent activity tracker while context compression is blocked in the auxiliary summarizer so gateway watchdogs do not report inactivity during long compactions.

Add regression coverage for successful heartbeats, exception cleanup, touch failures, and strict-signature compressor fallback.

(cherry picked from commit c09e58b7709cc60c5b454701f0ecf840e759222f)
This commit is contained in:
WeiYusc 2026-07-06 00:59:53 +08:00 • committed by Teknium
parent ea0fd393db
commit 928bcdde24
3 changed files with 259 additions and 1 deletions

View file

@ -1,5 +1,8 @@
import time
from types import SimpleNamespace
import pytest
from agent.codex_runtime import _record_codex_app_server_compaction
from agent.conversation_compression import COMPACTION_STATUS, compress_context
from agent.transports.codex_app_server_session import TurnResult
@ -19,6 +22,26 @@ class FakeCodexSession:
self.closed = True
class SlowCodexSession(FakeCodexSession):
def __init__(self, result, touch_calls):
super().__init__(result)
self.touch_calls = touch_calls
def compact_thread(self):
self.calls += 1
_wait_for_touch(self.touch_calls, "context compression in progress")
return self.result
def _wait_for_touch(touch_calls, desc, timeout=1.0):
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
if desc in touch_calls:
return
time.sleep(0.01)
pytest.fail(f"timed out waiting for touch {desc!r}; saw {touch_calls!r}")
class DummyAgent:
def __init__(
self,
@ -43,6 +66,11 @@ class DummyAgent:
self.warnings = []
self.events = []
self.built_prompts = []
self.touch_calls = []
self._compression_activity_heartbeat_interval = 0.1
def _touch_activity(self, desc):
self.touch_calls.append(desc)
def _emit_status(self, message):
self.statuses.append(message)
@ -79,6 +107,33 @@ def test_codex_app_server_native_auto_mode_leaves_thread_compaction_to_codex():
assert agent.events == []
def test_codex_app_server_compaction_heartbeat_refreshes_activity_while_waiting():
agent = DummyAgent(
TurnResult(thread_id="thread-1", turn_id="compact-turn-1")
)
agent._codex_session = SlowCodexSession(
agent._codex_session.result,
agent.touch_calls,
)
messages = [{"role": "user", "content": "hi"}]
returned, prompt = compress_context(
agent,
messages,
"system",
approx_tokens=100000,
task_id="test",
force=True,
)
assert returned is messages
assert prompt == "cached prompt"
assert agent._codex_session.calls == 1
assert "context compression started" in agent.touch_calls
assert "context compression in progress" in agent.touch_calls
assert agent.touch_calls[-1] == "context compression completed"
def test_codex_app_server_manual_compression_routes_to_codex_thread():
agent = DummyAgent(
TurnResult(thread_id="thread-1", turn_id="compact-turn-1")
@ -162,6 +217,8 @@ def test_codex_app_server_compression_failure_preserves_bookkeeping():
assert agent.context_compressor.compression_count == 0
assert agent.context_compressor.last_prompt_tokens == 123
assert agent.warnings
assert agent.touch_calls[0] == "context compression started"
assert agent.touch_calls[-1] == "context compression failed"
def test_codex_app_server_native_compaction_notice_emits_status_and_event():