Repository navigation
Description
Before submitting
- I searched existing issues and did not find a duplicate. (Related: [Bug]: ACP (GitHub Copilot CLI): agent self-continuation after background subagents is invisible, and session/load replay leaks into the next turn as stale "running" subagents #29211 is the same gap for Copilot CLI, [Bug]: Imported ACP sessions never show history or root-session output outside a T3 turn #22015 covers dropped root-session output outside a T3 turn, and Allow local ACP providers (or an API) to post assistant messages into a thread after the turn has settled #28026 asked for post-settle messages from local ACP providers. This report is Factory Droid specific, with a wire capture and a concrete flavor-level cause.)
- I included enough detail to reproduce or investigate the problem.
Area
apps/server (packages/provider-acp AcpAdapterV2, packages/provider-acp-registry flavor for factory-droid)
Steps to reproduce
- Add the ACP Registry provider "Factory Droid" (
factory-droid, Droid 1.6.0,droid exec --output-format acp-daemon) and start a thread. - Send:
Launch ONE Task subagent (subagent_type explorer) in the background whose job is: run "sleep 20; ls /tmp | head -3" and report the output. After launching it, end your turn immediately with the single word: waiting. - The run finishes with "waiting".
session/promptreturnedend_turn, and the thread shows as completed. - Wait about 30 seconds. Droid wakes the main agent by itself when the subagent finishes and writes a final answer.
I first hit this in a normal thread where the main agent delegated a read-only lookup to a custom subagent (~/.factory/droids) through Task. Task returned "Task launched in background", the main agent said it was waiting, and the turn ended. The prompt above reproduces the same sequence with a built-in subagent.
Expected behavior
The subagent result and the main agent's follow-up answer show up in the thread, as a continuation run the way the post-settle continuation path already does for Grok.
Actual behavior
The thread stops at "waiting". The follow-up answer is never shown, and nothing in the thread indicates that work is still going on. The only way to read it is to open Droid's own session file, ~/.factory/sessions/<cwd>/<session-id>.jsonl.
Droid side (works as designed). Droid's log for the affected session (droid-log-single.log) shows it starting a new agent run on its own: Starting agent run {"hasInput":false}, then Emitting CREATE_MESSAGE notification {"messageId":"task-completion:<uuid>","role":"system"}, then an assistant message. The session jsonl contains the full follow-up reply, with an agent_turn_outcome whose turnId is task-completion:<uuid>.
T3 side. In a real thread the T3 timeline had 7 items and ended with the "launched in the background" assistant message. logs/provider/events.<threadId>.log ends with session/prompt succeeded and has nothing after it.
Wire capture. I ran droid exec --output-format acp-daemon directly with a small JSON-RPC client (the same Droid build T3 launches, protocolVersion 1) and the prompt above. Times are seconds since start; file paths in the output are shortened.
15.04 session/update agent_message_chunk "waiting"
15.10 <- response id=3 {"stopReason":"end_turn"} # T3 settles the turn here
40.51 session/update tool_call_update toolCallId=toolu_01YH… name=Task status=completed
rawOutput.text = "The command ran and exited with code 0. Output, verbatim: ..."
44.01 session/update usage_update
44.29 session/update agent_message_chunk "后台子任务已完成,`sleep 20; ls /tmp | head -3` 的退出码为 0。…"
Both late updates arrive on the root session with no session/prompt in flight. There is no user_message_chunk and no state_update, since Droid speaks protocolVersion 1.
Cause. In makeAcpAdapterV2, once the turn has settled, activeTurn is null and handleSessionUpdate takes the context === null branch. There, bufferPostSettleWake returns early because postSettleContinuationEnabled is flavor.enablePostSettleContinuation === true && continuationRequests !== undefined. Only the Grok flavor sets it. The factory-droid flavor in provider-acp-registry sets neither enablePostSettleContinuation nor followAgentWorkState. (followAgentWorkState needs protocolVersion === 2, and Droid reports 1, so it cannot be the fix here.) The late tool_call_update and agent_message_chunk are then only written to the adapter's in-memory loaded-history snapshot (appendLoadedHistory / snapshot) and never reach the projection or a new run.
Impact
Major degradation or frequent failure. The user sees a finished thread, while the real answer sits in a session they cannot see in T3. Any thread where Droid delegates to a background subagent and ends its turn is affected. On my machine 6 Droid sessions contain such task-completion: continuation turns.
Version or commit
T3 Code (Beta) 0.1.7, Factory Droid 1.6.0 (ACP Registry factory-droid), model claude-sonnet-5-5.
Environment
macOS 15 (darwin 24.6.0), desktop app, provider instance acpRegistry_factory_droid.
The same user also sees similar behavior on Windows 11 with the same T3 Code version (0.1.7). The Windows symptoms have not been checked against the wire capture above, so they are not confirmed to be the same cause. The analysis and capture in this issue come from macOS.
Logs or stack traces
# logs/provider/events.<threadId>.log — last entries
03:32:46.151 session/prompt started
03:32:56.895 session/prompt succeeded
# (nothing after this)
# Droid log, same session
03:33:52.532 JSON-RPC processing user message
03:33:52.534 Starting agent run {"hasInput":false}
03:33:52.564 Emitting CREATE_MESSAGE notification {"messageId":"task-completion:…","role":"system"}
03:34:00.585 Emitting CREATE_MESSAGE notification {"role":"assistant"}
03:34:00.668 Agent run complete
Workaround
Read the last assistant message of the Droid session file (~/.factory/sessions/<cwd>/<session-id>.jsonl).
Suggested fix (verified locally)
In packages/provider-acp-registry/src/server/adapter.ts, set both of these on the factory-droid flavor:
enablePostSettleContinuation: true: buffers the late root-sessiontool_call_update (completed)andagent_message_chunkand opens a continuation turn.deferFinalizeForBackgroundWork: true: without it the continuation turn never finishes, because the deferred finalize is only scheduled when this flag is on.
I built T3 from source with this change and ran it against a real Droid 1.6.0. The thread then shows the full follow-up assistant message after the background Task finishes, and the run ends as completed. A regression test in AcpRegistryAdapterV2.test.ts fails without the change and passes with it. A fuller fix would also track the Task tool as background work (extractBackgroundTaskId, extractSubagentUpdate from _meta.subagent_session_info, rawOutput) so the UI shows the subagent as running meanwhile.
I can open a PR with this change if the direction is acceptable.
Activity