> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qredence.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Streaming

> The NDJSON turn stream, the SSE replay channel, ring buffers, and the ChatStreamEvent frames Fleet Prime Agent sends to the browser.

The browser receives agent output over two channels that share one frame vocabulary, `ChatStreamEvent`, defined in `web/protocol/src/chat-protocol.ts`.

## Turn stream: NDJSON over POST

`POST /api/chat` runs a turn and streams NDJSON frames back on the response. The first frame is a `start` frame that advertises `adapterCapabilities` (for example `reasoning-summary-v1`), which is how optional features are negotiated: clients that don't recognize a capability simply don't render the corresponding enhancement.

While a turn is active, the NDJSON stream is authoritative; the SSE handler skips frames for a session whose status is `streaming` or `submitted` so nothing renders twice.

## Out-of-turn pushes: SSE with replay

`GET /api/chat/events?sessionId=` opens a Server-Sent Events channel for pushes that happen outside an active turn: `tool-Question` dialog requests, `state` frames from `notify`/`setStatus`, and messages sent by IPython code.

Every dispatched frame lands in a per-session in-memory ring buffer (500 frames) with a monotonically increasing integer `seq`. On reconnect the client sends `Last-Event-ID` and the server replays every frame with a greater sequence number. If the ring buffer overflowed while the client was away, the server emits a `resync-required` state frame and the client rehydrates the session with `GET /api/chat/session`.

Sequence numbers persist in `sessionStorage`, so a page reload resumes the SSE cursor without a server round trip. Sequences are per-session and in-memory; they are not durable across a server restart.

## Frame types

| Frame        | Purpose                                                                                                    |
| ------------ | ---------------------------------------------------------------------------------------------------------- |
| `start`      | Turn started; carries `adapterCapabilities`.                                                               |
| `delta`      | Streamed assistant text.                                                                                   |
| `tool`       | Tool card update; the `ChatToolPart` state moves `input-streaming → output-available` or `output-error`.   |
| `reasoning`  | Controlled reasoning summary presentation. Raw thinking deltas are suppressed from the browser transcript. |
| `plan`       | Plan progress: mode, executing flag, completed/total counts, and plan state.                               |
| `state`      | Session state changes (`agent_start`, `agent_settled`, status text, widgets).                              |
| `queue`      | Steering and follow-up message queues.                                                                     |
| `compaction` | Context compaction started or ended, with reason and summary.                                              |
| `retry`      | Provider retry started or ended.                                                                           |
| `error`      | A typed Fleet error envelope with a code and optional remediation.                                         |
| `done`       | Turn finished; the transcript is finalized.                                                                |

## Tool naming

The event mapper converts engine tool names to PascalCase frame types with special-casing for `IPython` and short acronyms: `tool-IPython`, `tool-Bash`, `tool-Edit`, `tool-Task`, `tool-Question`, `tool-WebSearch`, and so on. Tool renderers in `web/design/src/components` dispatch on `part.type`, and anything without a dedicated card falls back to a generic tool renderer.

## Interactive questions

When the engine asks for input (`confirm`, `select`, `input`), the bridge emits a `tool-Question` frame and registers a pending dialog with a 60-second timeout. The browser answers through `POST /api/chat/question`; aborting a turn also cancels its pending dialogs. Pending dialogs are not persisted across a server restart.
