fix(steer): drain /steer between individual tool calls, not at batch end (#12959)

Previously, /steer text was only injected after an entire tool batch
completed (_execute_tool_calls_sequential/concurrent returned). If the
batch had a long-running tool (delegate_task, terminal build), the
steer waited for ALL tools to finish before landing — functionally
identical to /queue from the user's perspective.

Now _apply_pending_steer_to_tool_results() is called after EACH
individual tool result is appended to messages, in both the sequential
and concurrent paths. A steer arriving during Tool 1 lands in Tool 1's
result before Tool 2 starts executing.

Also handles leftover steers in the gateway: if a steer arrives during
the final API call (no tool batch to drain into), it's now delivered as
the next user turn instead of being silently dropped.

Fixes user report from Utku.
This commit is contained in:
Teknium 2026-04-20 03:08:04 -07:00 committed by GitHub
parent 22efc81cd7
commit eba7c869bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 21 additions and 0 deletions

View file

@ -10384,6 +10384,16 @@ class GatewayRunner:
pending = pending_event.text or _build_media_placeholder(pending_event)
logger.debug("Processing queued message after agent completion: '%s...'", pending[:40])
# Leftover /steer: if a steer arrived after the last tool batch
# (e.g. during the final API call), the agent couldn't inject it
# and returned it in result["pending_steer"]. Deliver it as the
# next user turn so it isn't silently dropped.
if result and not pending and not pending_event:
_leftover_steer = result.get("pending_steer")
if _leftover_steer:
pending = _leftover_steer
logger.debug("Delivering leftover /steer as next turn: '%s...'", pending[:40])
# Safety net: if the pending text is a slash command (e.g. "/stop",
# "/new"), discard it — commands should never be passed to the agent
# as user input. The primary fix is in base.py (commands bypass the