fix(acp): wire stream_delta_callback for real-time ACP text delta streaming - #13842
fix(acp): wire stream_delta_callback for real-time ACP text delta streaming#13842Git-on-my-level wants to merge 1 commit into
Conversation
…eaming Root cause: ACP turns emit partial session/update progress (thinking spinners, tool events) then go silent for the entire duration of run_conversation() because stream_delta_callback was never wired in the ACP adapter. The LLM's streamed text deltas were silently discarded since _fire_stream_delta() only dispatches to stream_delta_callback and _stream_callback — neither of which ACP set. Fix: Add make_stream_delta_cb() factory that forwards each text delta to conn.session_update() as an agent_message_chunk, and wire it as agent.stream_delta_callback in prompt(). This gives ACP clients (CAR/PMA/VS Code) real-time token-by-token progress during LLM streaming, eliminating the multi-minute silent gap before final prompt_return delivery. Also suppresses the final_response session_update when stream_delta_cb is active to avoid sending duplicate text to clients that append incremental chunks (P1 from automated review). Fixes #9
|
I have verified this solution by inspecting the code changes and running the new test suite. The fix introduces to forward live LLM text deltas to ACP clients as updates, enabling real-time token-by-token streaming. It correctly suppresses the final when streaming is active to prevent duplicate text delivery. The new unit tests confirm the callback emits chunks for non-empty text and ignores empty strings, while the server tests verify the suppression logic. This significantly improves the responsiveness of ACP integrations in VS Code, Zed, and JetBrains IDEs. Tested and confirmed. ✅ |
|
Thanks for identifying the ACP streaming gap. This is an automated hermes-sweeper review; current
Closing as implemented on main. |
Root Cause
ACP turns emit partial
session/updateprogress (thinking spinners, tool start/complete events, interim commentary), then go silent for the entire duration ofrun_conversation()before the final output arrives viaprompt_returninstead of a streamed terminal lifecycle event.Why:
stream_delta_callbackwas never wired in the ACP adapterThe ACP adapter (
acp_adapter/server.py) sets several callbacks onAIAgent:run_agent.py?thinking_callbacktool_progress_callbackstep_callbackinterim_assistant_callback_emit_interim_assistant_message)message_callbackstream_delta_callback_fire_stream_delta)The critical gap:
_fire_stream_delta()(line 5211 inrun_agent.py) is the method that fires for every LLM streaming token. It only dispatches tostream_delta_callbackand_stream_callback. Since ACP sets neither, every text delta from the LLM is silently discarded.CAR's
completion_source="prompt_return"(notstream_terminal_event) confirms no timely terminal lifecycle signal was received — it only got the final result through the RPC return path, ~30 minutes after the last progress update.Fix
make_stream_delta_cb()factory inacp_adapter/events.pythat forwards each text delta toconn.session_update()as anagent_message_chunkagent.stream_delta_callbackin theprompt()methodFiles Changed
acp_adapter/events.py— newmake_stream_delta_cb()factory (+17 lines)acp_adapter/server.py— wire callback inprompt()(+4 lines)tests/acp/test_events.py—TestStreamDeltaCallbackclass (+28 lines)tests/acp/test_server.py— integration testtest_prompt_wires_stream_delta_callback(+30 lines)Fixes #9