diff --git a/agent/conversation_compression.py b/agent/conversation_compression.py index 22decb591a2..0cf9d364c24 100644 --- a/agent/conversation_compression.py +++ b/agent/conversation_compression.py @@ -1098,7 +1098,11 @@ def _compress_context_via_codex_app_server( approx_tokens=approx_tokens, force=True, ) - if getattr(result, "token_usage_last", None): + # An empty usage report must consume the pending post-compaction verdict + # rather than leaving preflight deferral armed until some unrelated later + # Codex turn supplies usage. Minimal external test engines may not expose + # the ContextEngine update hook; preserve their existing bookkeeping. + if hasattr(agent.context_compressor, "update_from_response"): _record_codex_app_server_usage(agent, result) except Exception: logger.debug("codex compaction bookkeeping failed", exc_info=True) diff --git a/tests/run_agent/test_codex_app_server_compaction.py b/tests/run_agent/test_codex_app_server_compaction.py index 4bd5e8431dd..e5e7d668e74 100644 --- a/tests/run_agent/test_codex_app_server_compaction.py +++ b/tests/run_agent/test_codex_app_server_compaction.py @@ -102,6 +102,8 @@ def test_codex_app_server_manual_compression_routes_to_codex_thread(): assert agent._codex_session.calls == 1 assert agent.context_compressor.compression_count == 1 assert agent.context_compressor.last_compression_rough_tokens == 100000 + # This minimal fake compressor does not implement update_from_response(), + # so the runtime preserves its existing pending-usage bookkeeping here. assert agent.context_compressor.last_prompt_tokens == -1 assert agent.context_compressor.last_completion_tokens == 0 assert agent.context_compressor.awaiting_real_usage_after_compression is True