Description
When OpenCode sends a session/request_permission request to an ACP client, it simultaneously (in the same message batch) sends a tool_call_update notification transitioning the same tool call to status: "in_progress". This happens before the client has responded to the permission request.
Per the ACP spec:
pending: "The tool call hasn't started running yet because the input is either streaming or awaiting approval"
in_progress: "The tool call is currently running"
The premature in_progress update causes ACP clients (e.g. agent-shell) to overwrite the permission dialog UI with a regular status display, making it impossible for the user to approve or reject the permission. The tool call then hangs indefinitely.
This affects all permission types — both external_directory and bash permissions exhibit the same behavior.
ACP log showing the race (same toolCallId):
① tool_call → status: "pending", title: "write", kind: "edit"
② request_permission → status: "pending", title: "external_directory", kind: "other" (id: 2, awaiting response)
③ tool_call_update → status: "in_progress", title: "write", kind: "edit" (arrives before client responds to ②)
Raw JSON showing ② and ③ arriving in the same TCP read (same batch):
{"jsonrpc":"2.0","id":2,"method":"session/request_permission","params":{"sessionId":"...","toolCall":{"toolCallId":"toolu_01Pi2R6Ko5TVVAX9SsWw1qe2","status":"pending","title":"external_directory","rawInput":{"filepath":"/tmp/dummy-test-primary.txt","parentDir":"/tmp"},"kind":"other","locations":[]},"options":[{"optionId":"once","kind":"allow_once","name":"Allow once"},{"optionId":"always","kind":"allow_always","name":"Always allow"},{"optionId":"reject","kind":"reject_once","name":"Reject"}]}}
{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"...","update":{"sessionUpdate":"tool_call_update","toolCallId":"toolu_01Pi2R6Ko5TVVAX9SsWw1qe2","status":"in_progress","kind":"edit","title":"write","locations":[{"path":"/tmp/dummy-test-primary.txt"}],"rawInput":{"filePath":"/tmp/dummy-test-primary.txt","content":"hello from primary agent\n"}}}}
Same pattern for bash permission:
{"jsonrpc":"2.0","id":1,"method":"session/request_permission","params":{"sessionId":"...","toolCall":{"toolCallId":"toolu_016wFeFwJnkF5i8CzbknBbaz","status":"pending","title":"bash","rawInput":{},"kind":"execute","locations":[]},"options":[...]}}
{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"...","update":{"sessionUpdate":"tool_call_update","toolCallId":"toolu_016wFeFwJnkF5i8CzbknBbaz","status":"in_progress","kind":"execute","title":"bash","locations":[],"rawInput":{"command":"opencode --version 2>/dev/null || which opencode 2>/dev/null","description":"Get OpenCode version"}}}}
Expected behavior
The tool call should remain status: "pending" until the ACP client responds to session/request_permission. Only after receiving the permission response with allow_once/allow_always should the status transition to in_progress.
Impact
This confuses ACP clients (e.g. agent-shell) — the permission dialog gets overwritten before the user can respond, causing the tool call to hang indefinitely.
Environment
macOS, Emacs 30.2 (agent-shell via ACP), OpenCode v1.2.6
Description
When OpenCode sends a
session/request_permissionrequest to an ACP client, it simultaneously (in the same message batch) sends atool_call_updatenotification transitioning the same tool call tostatus: "in_progress". This happens before the client has responded to the permission request.Per the ACP spec:
pending: "The tool call hasn't started running yet because the input is either streaming or awaiting approval"in_progress: "The tool call is currently running"The premature
in_progressupdate causes ACP clients (e.g. agent-shell) to overwrite the permission dialog UI with a regular status display, making it impossible for the user to approve or reject the permission. The tool call then hangs indefinitely.This affects all permission types — both
external_directoryandbashpermissions exhibit the same behavior.ACP log showing the race (same
toolCallId):Raw JSON showing ② and ③ arriving in the same TCP read (same batch):
{"jsonrpc":"2.0","id":2,"method":"session/request_permission","params":{"sessionId":"...","toolCall":{"toolCallId":"toolu_01Pi2R6Ko5TVVAX9SsWw1qe2","status":"pending","title":"external_directory","rawInput":{"filepath":"/tmp/dummy-test-primary.txt","parentDir":"/tmp"},"kind":"other","locations":[]},"options":[{"optionId":"once","kind":"allow_once","name":"Allow once"},{"optionId":"always","kind":"allow_always","name":"Always allow"},{"optionId":"reject","kind":"reject_once","name":"Reject"}]}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"...","update":{"sessionUpdate":"tool_call_update","toolCallId":"toolu_01Pi2R6Ko5TVVAX9SsWw1qe2","status":"in_progress","kind":"edit","title":"write","locations":[{"path":"/tmp/dummy-test-primary.txt"}],"rawInput":{"filePath":"/tmp/dummy-test-primary.txt","content":"hello from primary agent\n"}}}}Same pattern for
bashpermission:{"jsonrpc":"2.0","id":1,"method":"session/request_permission","params":{"sessionId":"...","toolCall":{"toolCallId":"toolu_016wFeFwJnkF5i8CzbknBbaz","status":"pending","title":"bash","rawInput":{},"kind":"execute","locations":[]},"options":[...]}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"...","update":{"sessionUpdate":"tool_call_update","toolCallId":"toolu_016wFeFwJnkF5i8CzbknBbaz","status":"in_progress","kind":"execute","title":"bash","locations":[],"rawInput":{"command":"opencode --version 2>/dev/null || which opencode 2>/dev/null","description":"Get OpenCode version"}}}}Expected behavior
The tool call should remain
status: "pending"until the ACP client responds tosession/request_permission. Only after receiving the permission response withallow_once/allow_alwaysshould the status transition toin_progress.Impact
This confuses ACP clients (e.g. agent-shell) — the permission dialog gets overwritten before the user can respond, causing the tool call to hang indefinitely.
Environment
macOS, Emacs 30.2 (agent-shell via ACP), OpenCode v1.2.6