fix(agent): keep the tripping correction and explain the restart-bound exit
When the redirect cap trips, the correction that cancelled the final attempt is still sitting in _pending_redirect; finalize_turn's clear_interrupt() would drop it silently. Drain it into the steer slot so it rides result["pending_steer"] and becomes the next user turn on every surface that already honours that key. Both new exit reasons get a turn-completion explanation so the user sees why the turn stopped instead of an empty reply.
This commit is contained in:
@@ -41,6 +41,16 @@ _EXIT_REASON_EXPLANATIONS: Dict[str, str] = {
|
||||
"the request was interrupted mid-call before a reply was "
|
||||
"received. Send `continue` to retry."
|
||||
),
|
||||
"redirect_restart_limit_exceeded": (
|
||||
"the request was cancelled by a new correction on every attempt, "
|
||||
"so the turn stopped instead of retrying forever. Your last "
|
||||
"correction is queued as the next message."
|
||||
),
|
||||
"rebuilt_restart_limit_exceeded": (
|
||||
"every provider in the fallback chain kept failing over, so the "
|
||||
"turn stopped instead of retrying forever. Send `continue` or "
|
||||
"switch provider."
|
||||
),
|
||||
"budget_exhausted": (
|
||||
"the per-turn iteration/cost budget was exhausted before a "
|
||||
"final answer. Send `continue` to keep going."
|
||||
|
||||
@@ -423,6 +423,11 @@ def apply_retry_restarts(
|
||||
"refunding the iteration budget indefinitely.",
|
||||
max_retries,
|
||||
)
|
||||
# The correction that tripped the cap was never applied; hand it back as the
|
||||
# next user turn (result["pending_steer"]) instead of losing it to clear_interrupt().
|
||||
_unapplied = agent._drain_pending_redirect()
|
||||
if _unapplied:
|
||||
agent.steer(_unapplied)
|
||||
return _verdict("break")
|
||||
# Cancelled request produced no valid assistant item: reuse the same logical
|
||||
# iteration after the outer loop appends partial context + correction.
|
||||
|
||||
Reference in New Issue
Block a user