#13804: fix: prevent steer during tool execution to avoid tool_use/tool_result mismatch (#13704)
agents
Cluster:
Error Handling in Agent Tools
## Problem
When a long-running exec command is in progress and a queued subagent announcement is delivered, `queueEmbeddedPiMessage` injects the message via `steer` into the active session. This inserts a user message between `tool_use` and `tool_result`, breaking Anthropic's strict pairing requirement and causing API rejection:
```
invalid_request_error: messages.59: `tool_use` ids were found without `tool_result` blocks immediately after: call_52523385.
```
## Root Cause
`queueEmbeddedPiMessage` only checks `isStreaming()` and `isCompacting()` before injecting messages, but doesn't check whether tools are currently executing. When a tool (e.g., exec) is running, the session has an outstanding `tool_use` waiting for its `tool_result`. Injecting a user message at this point breaks the pairing.
## Fix
Added `isToolRunning` check to `EmbeddedPiQueueHandle` and `queueEmbeddedPiMessage`. When tools are executing, `queueEmbeddedPiMessage` returns `false`, causing the caller to fall through to the queue path (`enqueueAnnounce`), which delivers the message after the current tool loop completes.
The implementation leverages the existing `toolMetaById` map in the subscription state, which already tracks in-flight tools (entries added on `tool_execution_start`, removed on `tool_execution_end`). No new state is needed — just a new accessor `isToolRunning()` that checks `toolMetaById.size > 0`.
### Changes
- **`src/agents/pi-embedded-runner/runs.ts`**: Added optional `isToolRunning` to `EmbeddedPiQueueHandle` type; added guard in `queueEmbeddedPiMessage` that returns `false` when tools are running
- **`src/agents/pi-embedded-runner/run/attempt.ts`**: Wired `subscription.isToolRunning()` into the `queueHandle`
- **`src/agents/pi-embedded-subscribe.ts`**: Exposed `isToolRunning()` from subscription return, backed by `state.toolMetaById.size > 0`
Closes #13704
Most Similar PRs
#7760: fix(agents): resolve message ordering conflict during tool execution
by aryan877 · 2026-02-03
71.0%
#6582: fix(steer): prevent cross-thread reply contamination in queue mode
by NSEvent · 2026-02-01
69.5%
#13282: fix(agents): instruct agent not to retry lost tool results
by thebtf · 2026-02-10
67.6%
#9171: Fix: Route tool result deliveries through BlockReplyPipeline for pr...
by vishaltandale00 · 2026-02-04
67.5%
#21195: fix: suppress orphaned tool_use/tool_result errors after session co...
by ruslansychov-git · 2026-02-19
67.1%
#20538: fix: handle orphaned tool_result errors gracefully instead of leaki...
by echoVic · 2026-02-19
66.6%
#16275: fix(agents): prevent rapid-fire duplicate messages during tool exec...
by heyhudson · 2026-02-14
66.1%
#3362: fix: auto-repair and retry on orphan tool_result errors
by samhotchkiss · 2026-01-28
65.5%
#10261: fix(agents): prevent exec tool errors from leaking to channels (#9651)
by nu-gui · 2026-02-06
65.4%
#22205: fix: expose resolvedTo as currentChannelId so sub-agents inherit th...
by Galygious · 2026-02-20
65.4%