fix(agent): re-anchor after post-tool compression
This commit is contained in:
@@ -22,7 +22,7 @@ from agent.conversation_compression import (
|
||||
from agent.turn_context import _review_fork_first_request_pending
|
||||
from agent.turn_context_compaction import (
|
||||
_apply_grown_window, _blocked_compress_reason, _clear_overflow_warn, _refund_api_call,
|
||||
_reset_retry_state_after_compaction,
|
||||
_reanchor, _reset_retry_state_after_compaction,
|
||||
)
|
||||
|
||||
logger = logging.getLogger("agent.conversation_loop")
|
||||
@@ -238,13 +238,14 @@ class PostToolCompressionVerdict:
|
||||
compression_attempts: int
|
||||
final_response: Any
|
||||
turn_exit_reason: Any
|
||||
current_turn_user_idx: int
|
||||
|
||||
|
||||
def compress_after_tool_results(
|
||||
agent: Any, *, messages: List[Dict[str, Any]], system_message: Any, user_message: Any,
|
||||
active_system_prompt: Any, conversation_history: Any, compression_attempts: int,
|
||||
max_compression_attempts: int, effective_task_id: Any, final_response: Any,
|
||||
turn_exit_reason: Any,
|
||||
turn_exit_reason: Any, current_turn_user_idx: int,
|
||||
) -> PostToolCompressionVerdict:
|
||||
"""Post-tool-call compression decision. Pressure comes from API-reported
|
||||
``prompt_tokens`` (a tight lower bound; thinking models inflate completion tokens),
|
||||
@@ -263,6 +264,7 @@ def compress_after_tool_results(
|
||||
end_turn=end_turn, messages=messages, active_system_prompt=active_system_prompt,
|
||||
conversation_history=conversation_history, compression_attempts=compression_attempts,
|
||||
final_response=final_response, turn_exit_reason=turn_exit_reason,
|
||||
current_turn_user_idx=current_turn_user_idx,
|
||||
)
|
||||
|
||||
_compressor = agent.context_compressor
|
||||
@@ -355,6 +357,7 @@ def compress_after_tool_results(
|
||||
final_response = _HANDOFF_SKIP_FINAL_RESPONSE
|
||||
turn_exit_reason = "compaction_handoff_not_actionable"
|
||||
return _verdict(True)
|
||||
current_turn_user_idx = _reanchor(agent, messages, user_message)
|
||||
elif agent.compression_enabled:
|
||||
# Over threshold but compression blocked (cooldown/anti-thrash): deduped
|
||||
# warning so context can't silently overflow. ``attempts_spent`` names the
|
||||
|
||||
@@ -39,6 +39,7 @@ class ToolRoundVerdict:
|
||||
failed: Any
|
||||
_turn_exit_reason: Any
|
||||
truncated_tool_call_retries: Any
|
||||
current_turn_user_idx: Any
|
||||
result: Optional[Dict[str, Any]] = None
|
||||
|
||||
|
||||
@@ -47,7 +48,7 @@ def run_tool_round(
|
||||
conversation_history: Any, api_call_count: Any, effective_task_id: Any, user_message: Any,
|
||||
system_message: Any, active_system_prompt: Any, compression_attempts: Any,
|
||||
max_compression_attempts: Any, final_response: Any, failed: Any, _turn_exit_reason: Any,
|
||||
truncated_tool_call_retries: Any,
|
||||
truncated_tool_call_retries: Any, current_turn_user_idx: Any,
|
||||
) -> ToolRoundVerdict:
|
||||
"""Execute one tool round in the exact original order. Persist-before-execute is a
|
||||
durability invariant: resume must see the executed block if a destructive tool restarts
|
||||
@@ -60,7 +61,8 @@ def run_tool_round(
|
||||
action=action, messages=messages, conversation_history=conversation_history,
|
||||
active_system_prompt=active_system_prompt, compression_attempts=compression_attempts,
|
||||
final_response=final_response, failed=failed, _turn_exit_reason=_turn_exit_reason,
|
||||
truncated_tool_call_retries=truncated_tool_call_retries, result=result,
|
||||
truncated_tool_call_retries=truncated_tool_call_retries,
|
||||
current_turn_user_idx=current_turn_user_idx, result=result,
|
||||
)
|
||||
|
||||
if not agent.quiet_mode:
|
||||
@@ -191,6 +193,7 @@ def run_tool_round(
|
||||
compression_attempts=compression_attempts,
|
||||
max_compression_attempts=max_compression_attempts, effective_task_id=effective_task_id,
|
||||
final_response=final_response, turn_exit_reason=_turn_exit_reason,
|
||||
current_turn_user_idx=current_turn_user_idx,
|
||||
)
|
||||
messages = _ptc.messages
|
||||
active_system_prompt = _ptc.active_system_prompt
|
||||
@@ -198,6 +201,7 @@ def run_tool_round(
|
||||
compression_attempts = _ptc.compression_attempts
|
||||
final_response = _ptc.final_response
|
||||
_turn_exit_reason = _ptc.turn_exit_reason
|
||||
current_turn_user_idx = _ptc.current_turn_user_idx
|
||||
if _ptc.end_turn:
|
||||
return _verdict("break")
|
||||
|
||||
|
||||
56
tests/agent/test_post_tool_compression_turn_boundary.py
Normal file
56
tests/agent/test_post_tool_compression_turn_boundary.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from types import SimpleNamespace
|
||||
|
||||
from agent.turn_preflight import compress_after_tool_results
|
||||
|
||||
|
||||
def test_post_tool_compression_reanchors_the_active_user_boundary(monkeypatch):
|
||||
compressed = [
|
||||
{"role": "user", "content": "compressed history"},
|
||||
{"role": "user", "content": "current ask"},
|
||||
{"role": "assistant", "tool_calls": [{"id": "2"}]},
|
||||
{"role": "tool", "content": "fresh result", "tool_call_id": "2"},
|
||||
]
|
||||
|
||||
class Compressor:
|
||||
last_prompt_tokens = 100
|
||||
threshold_tokens = 50
|
||||
|
||||
@staticmethod
|
||||
def should_compress(_tokens):
|
||||
return True
|
||||
|
||||
agent = SimpleNamespace(
|
||||
context_compressor=Compressor(),
|
||||
compression_enabled=True,
|
||||
_clear_context_overflow_warn=lambda: None,
|
||||
_safe_print=lambda *_args: None,
|
||||
_compress_context=lambda *_args, **_kwargs: (compressed, "system"),
|
||||
_persist_user_message_idx=4,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"agent.turn_preflight.conversation_history_after_compression",
|
||||
lambda _agent, _messages, _history: [],
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"agent.conversation_loop._should_skip_model_call_for_reference_handoff",
|
||||
lambda _messages, _user_message: False,
|
||||
)
|
||||
|
||||
verdict = compress_after_tool_results(
|
||||
agent,
|
||||
messages=[{"role": "user", "content": "current ask"}],
|
||||
system_message="system",
|
||||
user_message="current ask",
|
||||
active_system_prompt="system",
|
||||
conversation_history=[],
|
||||
compression_attempts=0,
|
||||
max_compression_attempts=1,
|
||||
effective_task_id="task",
|
||||
final_response="",
|
||||
turn_exit_reason=None,
|
||||
current_turn_user_idx=0,
|
||||
)
|
||||
|
||||
assert verdict.messages is compressed
|
||||
assert verdict.current_turn_user_idx == 1
|
||||
assert agent._persist_user_message_idx == 1
|
||||
Reference in New Issue
Block a user