refactor(agent): leave the API-interrupt tail close to the finalizer
handle_api_interrupt exits via break into finalize_turn, whose _close_transcript_tail already closes the tail with the same final_response, so its own close was a duplicate; the scaffold strip stays (the partial-text row must follow the tool row). The scaffolding drop no longer returns a flag nobody reads, and the give-up test relies on the autouse backoff stub in tests/agent/conftest.py instead of re-stubbing it.
This commit is contained in:
@@ -364,19 +364,16 @@ class SessionPersistenceMixin:
|
||||
self._session_db.flush_token_counts()
|
||||
note_turn_persisted(self)
|
||||
|
||||
def _drop_trailing_empty_response_scaffolding(self, messages: List[Dict]) -> bool:
|
||||
"""Pop empty-response retry scaffolding from the tail; True when any was present. The
|
||||
def _drop_trailing_empty_response_scaffolding(self, messages: List[Dict]) -> None:
|
||||
"""Pop empty-response retry scaffolding from the tail. The
|
||||
assistant(tool_calls) / tool rows before it stay: they were saved before the tools ran, so
|
||||
dropping them from the live history only makes the model repeat a side effect the durable
|
||||
transcript already records."""
|
||||
def tail(*keys: str) -> bool:
|
||||
return bool(messages) and isinstance(messages[-1], dict) and any(messages[-1].get(k) for k in keys)
|
||||
|
||||
dropped_scaffolding = False
|
||||
while tail("_empty_recovery_synthetic", "_empty_terminal_sentinel"):
|
||||
messages.pop()
|
||||
dropped_scaffolding = True
|
||||
return dropped_scaffolding
|
||||
|
||||
_repair_message_sequence = _forward("agent.agent_runtime_helpers", "repair_message_sequence")
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ from typing import Any, Dict, Optional
|
||||
from agent.error_classifier import FailoverReason
|
||||
from agent.agent_runtime_helpers import _INTERRUPTED_PLACEHOLDER
|
||||
from agent.message_metadata import append_message
|
||||
from agent.message_sanitization import close_interrupted_tool_sequence
|
||||
from agent.repetition_guard import REPETITION_LOOP_INTERRUPTED, is_runaway_repetition
|
||||
from agent.turn_failure_copy import site_copy, stamp_failure
|
||||
|
||||
@@ -189,8 +188,8 @@ def handle_api_interrupt(
|
||||
agent._vprint(f"{agent.log_prefix}⚡ Interrupted during API call.", force=True)
|
||||
interrupted = True
|
||||
# A Stop during the empty-response nudge request leaves the synthetic assistant+nudge
|
||||
# pair after an executed tool result; strip it so the row appended below (or the close)
|
||||
# follows the tool row, and this exit owner records its own reason.
|
||||
# pair after an executed tool result; strip it so the row appended below follows the tool
|
||||
# row (the finalizer then closes the tail with this exit's own reason).
|
||||
agent._drop_trailing_empty_response_scaffolding(messages)
|
||||
_partial = agent._strip_think_blocks(
|
||||
getattr(agent, "_current_streamed_assistant_text", "") or ""
|
||||
@@ -209,7 +208,6 @@ def handle_api_interrupt(
|
||||
final_response = _partial
|
||||
else:
|
||||
final_response = f"{INTERRUPT_WAITING_FOR_MODEL_PREFIX}{api_elapsed:.1f}s elapsed)."
|
||||
close_interrupted_tool_sequence(messages, final_response)
|
||||
agent._persist_session(messages, conversation_history)
|
||||
return ApiInterruptVerdict("break", thinking_spinner, interrupted, final_response)
|
||||
|
||||
|
||||
@@ -197,9 +197,6 @@ def real_loop(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("no_proxy", "")
|
||||
monkeypatch.setattr("agent.title_generator.maybe_auto_title", lambda *a, **k: None)
|
||||
monkeypatch.setattr("agent.title_generator.start_title_upgrade", lambda *a, **k: None)
|
||||
# The first empty response backs off 5-7.5 s for real; the give-up path is reached via the
|
||||
# deterministic-empty guard, not the wait (``turn_empty_response`` imports this lazily).
|
||||
monkeypatch.setattr("agent.retry_utils.jittered_backoff", lambda *a, **k: 0.0)
|
||||
monkeypatch.chdir(tmp_path)
|
||||
db = SessionDB(db_path=tmp_path / "state.db")
|
||||
sid = "sess-empty-exit"
|
||||
|
||||
@@ -33,7 +33,7 @@ def test_drop_scaffolding_keeps_executed_tool_pair():
|
||||
"_empty_terminal_sentinel": True},
|
||||
]
|
||||
|
||||
assert AIAgent._drop_trailing_empty_response_scaffolding(agent, messages) is True
|
||||
AIAgent._drop_trailing_empty_response_scaffolding(agent, messages)
|
||||
assert messages == executed
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user