Repository navigation
ACP: session/prompt response is held until an async bash shell exits, so clients appear stuck #5293
Description
Describe the bug
In ACP mode (copilot --acp), when the agent starts a shell with the bash tool in mode: "async", the session/prompt response is withheld until that shell exits, even though the agent's foreground work finished long before. If the async shell is a dev server or another long-running process, the prompt never completes. ACP clients have no other end-of-turn signal on protocol v1, so they show the session as busy indefinitely.
The same prompt with detach: true (bash args {"mode":"async","detach":true}) behaves as expected: session/prompt returns end_turn as soon as the foreground work ends, and the later shell-completion wake (system.notification → read_bash → new turn) still happens.
This makes ACP clients look stuck. It was reported downstream in T3 Code: pingdotgg/t3code#27301
Affected version
1.0.105
Steps to reproduce the behavior
- Start
copilot --acpand sendinitialize(protocolVersion 1; optionally subscribe to raw events withclientCapabilities._meta["github.com/copilot"].events = ["assistant.turn_end", "session.usage_checkpoint", "system.notification"]). session/new, thensession/promptwith: Use the bash tool with mode "async" (NOT detached) to runsleep 25, do not wait or read its output, then immediately reply with just the word ok. Do nothing else. Allow the permission request.- Note when the
session/promptresponse arrives. - Repeat asking for
detach: truefor comparison, and check the bash arguments in~/.copilot/session-state/<sessionId>/events.jsonl: the bug needs{"mode":"async","detach":false}or nodetachfield.
Observed (seconds from start):
async, not detached ({"mode":"async"}):
3.22 tool_call bash "sleep 25"
3.94 sessionEvent assistant.turn_end
3.94 sessionEvent session.usage_checkpoint <- foreground work done, "ok" already sent
28.27 sessionEvent system.notification <- shell completed
28.27 tool_call read_bash
29.41 sessionEvent assistant.turn_end
29.42 session/prompt response {"stopReason":"end_turn"} <- held ~25 s
async + detach ({"mode":"async","detach":true}):
4.18 tool_call bash "sleep 25"
5.17 sessionEvent assistant.turn_end
5.18 sessionEvent session.usage_checkpoint
5.18 session/prompt response {"stopReason":"end_turn"} <- immediate
29.87 sessionEvent system.notification <- wake still delivered
In a real session the agent started a local dev server with mode: "async". The client showed the session as busy for about 10 minutes after the agent finished. The response to the next prompt came 0.5 s after I killed the dev server. Sending session/cancel also releases the held prompt without killing the async shell.
Expected behavior
session/prompt should resolve with end_turn when the agent's foreground work ends, as it does for detached shells, even if an async shell started in that prompt is still running. If async shells must keep the prompt open by design, please provide a documented signal that foreground work has ended, such as ACP state_update idle (protocol v2) or a documented sessionEvent, so clients can show the session as idle with background work running.
Additional context
- macOS 27.0.1, arm64
- Client: ACP over stdio (T3 Code; also reproduced with a minimal standalone JSON-RPC client)
- Models: claude-sonnet-5.5 (repro), gpt-6.1-sol (original session)
Also reproduced inside T3 Code with {"command":"sleep 90","mode":"async","detach":false}: the agent replied "ok" and emitted session.usage_checkpoint 4.3 s after the prompt, but the session/prompt response arrived 100 s after the prompt, only after the shell exited and the agent ran a second internal turn.
Activity