Skip to content

Chat Streaming ​

QDash translates the Agent Runtime's NDJSON event stream into Server-Sent Events (SSE) consumed by the chat UI.

Responsibility Boundary ​

The Agent Runtime owns model and tool execution. pi_chat_service.py owns the HTTP bridge, keepalive handling, event translation, evaluation recording, and the final block response. The browser hook owns SSE parsing and live transcript state.

text
Agent Runtime NDJSON
        ↓
src/qdash/api/services/pi_chat_service.py
        ↓
QDash SSE endpoint
        ↓
ui/src/hooks/useCopilotChat.ts

Event Translation ​

Runtime eventSSE eventUI purpose
text_deltadeltaAppend assistant text.
thinking_deltathinkingShow live reasoning progress.
tool_drafttool_draftOpen a tool row while the model is still writing the call (index: the call's position in the message).
tool_args_deltatool_args_deltaAppend text to one argument (path, such as ["content"]) of the call being written; the chat shows code as it is typed.
tool_starttool_start, statusThe call runs: the drafted row gets its validated arguments and progress.
tool_endtool_end, statusComplete the tool row and attach figures, evaluation details, or a workspace tool's output and exit_code.
chartIncluded in final resultRender a collected chart.
askIncluded in final resultRender a question card.
approvalIncluded in final resultRender an approval card.
editIncluded in final resultRender a proposed change from propose_code_edit, with Apply and Discard. The proposal's pagePath, flowName, and chipId must match the open editor before applying.
donestatus, resultFinish the turn with renderable blocks.
errorerrorStop the stream with a user-visible failure.
pingSSE commentKeep idle proxy connections open.

Malformed runtime events become an error event. A completed turn with no renderable text, chart, question, or approval also becomes an error so the UI does not appear to hang.

Durable Turns and Cancellation ​

Closing the browser stream does not cancel work in the Agent Runtime. The Stop action calls the separate cancellation path for the active turn. Request IDs let a retry recover an answer that the runtime already committed.

The runtime sends keepalives while a tool is quiet. The API converts them to SSE comments, which preserve the connection without creating transcript entries.

Change and Test Streaming ​

Update agent-runtime/src/events.ts when the runtime event contract changes. Update src/qdash/api/services/pi_chat_service.py when the SSE contract or translation changes, then update ui/src/hooks/useCopilotChat.ts and its tests for browser behavior.

Run:

bash
uv run pytest tests/qdash/copilot/test_pi_chat_service.py -v
cd ui && bun run test:run src/hooks/__tests__/useCopilotChat.test.tsx
task ci-agent-runtime

Run the complete task test-ui suite when event rendering changes.

Released under the Apache 2.0 License.