With fx acp in ask mode, a sub-agent that needs tool approval never finishes. fx moves the child to awaiting_approval, but never sends the ACP client a session/request_permission, or anything else. The parent's subagent tool call stays in_progress, and session/prompt never returns. The only way out is cancelling the turn.
Repro
fx 0.0.14. The code path is unchanged on main at e71a663b.
- Set
"permission_mode": "ask"in~/.fx/settings.json. - Create a workspace containing a
package.jsonand atsconfig.json. - Run the attached probe:
node acp-subagent-probe.mjs <path-to-fx> <workspace> out.ndjson. It:- sends
initializeandsession/new; - prompts "Spawn 2 subagents, one to read package.json and one to read tsconfig.json";
- approves any
session/request_permissionwithallow_once; - logs every frame.
- sends
- One child finishes in about 6 s: its
tool_call_updateiscompleted. The other's tool call staysin_progress. No permission request or other frame follows, and the prompt never returns; the probe gives up after 240 s. - The session's
subagent/children.jsonshows that child with"phase":"awaiting_approval"and"permission_mode":"ask".
It happened every time: three of three runs, from this probe, from T3 Code, and from T3 Code's replay recorder. In auto mode, the same prompt completes.
Where it seems to come from
runSubagentChildruns the child with the parent's tool context.- When the child needs approval,
TurnContext.registerApprovalmoves it toawaiting_approvaland registers the request in the sub-agent approval registry. - Only the terminal app drains that registry, via
pendingApprovalRequest/resolveApprovalininput_approval_runtime.zigandapp_worker_runtime.zig. Nothing undersrc/acpcalls either function, so over ACP the request is never shown to the user and never resolved.
Expected
The child's approval reaches the client as a session/request_permission on the parent session, ideally saying which sub-agent asks, and the client's answer resolves it. If fx can't route it, the child should fail rather than wait forever.
Attachments
- fx-0.0.14-acp-subagent-supervised.ndjson: every ACP frame from the probe run, with home paths replaced and the host's skill list omitted. The last frames are the stuck call's
in_progressand the other call'scompleted. - acp-subagent-probe.mjs: the probe client.
- children.json: the session's sub-agent state after the hang.
Found while adding fx to T3 Code (pingdotgg/t3code#18277). T3 Code shows fx sub-agents in their own threads, and for now tells users to switch to Auto when delegating.
For the approval-routing fix, a deterministic regression could put two children in awaiting_approval at once, reject one request, and approve the other. Assert that each answer resolves only its originating child and that the rejected child's tool produces no side effect.
A second case can cancel the parent while a permission request is outstanding, then deliver a late allow_once response. The late response should not restart the cancelled child, and session/prompt should settle with the defined cancellation result. This would cover request correlation and lifecycle cleanup alongside the reported missing request_permission frame. I haven't rerun the attached probe.