You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Tool calls that outlive their turn have no protocol expression #1847
ToolCallStatus gives pending | in_progress | completed | failed, and long-running work reports via successive tool_call_update notifications. That covers a tool call running within a turn. Two adjacent cases appear to have no expression, and I'd like to know whether they're considered in scope.
1. Backgrounded vs foreground-blocking
in_progress covers both "the agent is blocked inside this tool" and "the agent moved on and this is running in the background".
Harnesses do distinguish these. Claude Code exposes is_backgrounded on tool results, and a background_tasks[] summary whose documented purpose is to "distinguish 'session is done' from 'session is paused waiting for background work to wake it'". It also auto-backgrounds a command that exceeds its timeout, so a tool call can become backgrounded without the agent ever requesting it.
A client rendering an ACP session currently can't tell whether the agent is stuck or waiting, and an orchestrator can't tell whether silence means progress or a wedge.
2. A tool call settling after its turn ends
When backgrounded work completes after prompt() returns, its tool_call_update arrives outside the turn that created it. I can't find a statement about whether that's permitted.
This interacts with #554, which proposes a turn_complete signal meaning all session/update notifications for a turn have been delivered. If backgrounded tool calls may still emit updates after the turn, that signal needs qualifying, or backgrounded calls need to be explicitly excluded from it. Both can't be unconditionally true.
Asking rather than proposing
Not proposing a shape. The questions are:
Are these in scope for the protocol, or intentionally left to implementations?
Is the intended modelling that a backgrounded tool call simply remains in_progress indefinitely, including across turn boundaries?
Happy to write this up as an RFD if the answer to the first is yes.
Client implementer here, on Windows and macOS, currently on protocol v1 since v2 is still behind unstable_protocol_v2 in the Rust SDK. Reading the v2 RFDs rather than running them, part of this looks already answered there, which would narrow what is left open.
On case 2: the v2 prompt RFD changes the lifecycle so a prompt request lasts until the user message is inserted rather than until the end of the turn, and it names background tasks, and agents that send updates before or after a turn, as a reason for the change. The v2 overview changelog also has, on 2026-07-20, "Clarified that idle means ready for a new prompt while background updates may continue". Read together, that seems to say a late tool_call_update is permitted and that it belongs to the session rather than to a turn. If that reading is right, case 2 is settled for v2, and what remains is what turn_complete covers in v1, which is #554.
On case 1 I cannot find anything in v2 that distinguishes "the agent is blocked inside this tool" from "the agent moved on and this is running in the background". As far as I can tell that is still unexpressed.
A data point for whether it belongs in the protocol. We hit case 1 mostly through dev servers. An agent that ran npm run dev as a terminal command produced a tool call that never settles. It stays in_progress for the life of the server, the client cannot show it as anything other than a command taking a very long time, and there is no way to tell a wedged command from a healthy one.
We solved it outside ACP. Agents get a tool of ours that asks the client to start the server, and the call returns immediately with a url, a port and a pid. The server then belongs to the client, with its own log, its own row in the UI, and a record of which agent asked for it. Stopping it is a user action rather than a side effect of a turn ending.
That works, but the cost is a capability no other ACP client has, and agents have to be told it exists. Which is the argument for case 1 being in scope: left to implementations, each client invents its own non-portable answer, and agents cannot rely on any of them.
I think v2's entity based updates and lack of updates being so closely tied to a turn help here, so I am going to close, but let me know if v2 does not solve your concerns
Activity
savvasioakeim commentedon Sep 29, 2026
Client implementer here, on Windows and macOS, currently on protocol v1 since v2 is still behind
unstable_protocol_v2in the Rust SDK. Reading the v2 RFDs rather than running them, part of this looks already answered there, which would narrow what is left open.On case 2: the v2 prompt RFD changes the lifecycle so a prompt request lasts until the user message is inserted rather than until the end of the turn, and it names background tasks, and agents that send updates before or after a turn, as a reason for the change. The v2 overview changelog also has, on 2026-07-20, "Clarified that
idlemeans ready for a new prompt while background updates may continue". Read together, that seems to say a latetool_call_updateis permitted and that it belongs to the session rather than to a turn. If that reading is right, case 2 is settled for v2, and what remains is whatturn_completecovers in v1, which is #554.On case 1 I cannot find anything in v2 that distinguishes "the agent is blocked inside this tool" from "the agent moved on and this is running in the background". As far as I can tell that is still unexpressed.
A data point for whether it belongs in the protocol. We hit case 1 mostly through dev servers. An agent that ran
npm run devas a terminal command produced a tool call that never settles. It staysin_progressfor the life of the server, the client cannot show it as anything other than a command taking a very long time, and there is no way to tell a wedged command from a healthy one.We solved it outside ACP. Agents get a tool of ours that asks the client to start the server, and the call returns immediately with a url, a port and a pid. The server then belongs to the client, with its own log, its own row in the UI, and a record of which agent asked for it. Stopping it is a user action rather than a side effect of a turn ending.
That works, but the cost is a capability no other ACP client has, and agents have to be told it exists. Which is the argument for case 1 being in scope: left to implementations, each client invents its own non-portable answer, and agents cannot rely on any of them.
benbrandt commentedon Oct 16, 2026
I think v2's entity based updates and lack of updates being so closely tied to a turn help here, so I am going to close, but let me know if v2 does not solve your concerns