POST /chat streams the agent’s response as Server-Sent Events (AG-UI protocol frames). The
adapter is responsible only for the wire mechanics — headers first, frames verbatim, backpressure
honored, teardown on disconnect. The event semantics live in the
AG-UI chat reference.
What the adapter writes
On a chat request the adapter:- Flushes headers immediately (
X-Accel-Buffering: no,Cache-Control: no-cache, the AG-UI content type) so the browser starts receiving events before the first token. - Writes each frame verbatim —
data: ...\n\npayload lines from the runtime, plus: heartbeatcomment lines on the runtime’s heartbeat cadence (default 15s) to keep intermediaries from timing the connection out. - Honors backpressure — if
res.write()returnsfalse, it waits for the socket’sdrainevent before writing the next frame, so a slow client can’t balloon memory. - Unsubscribes on disconnect — if the client hangs up mid-stream, the adapter calls
iterator.return()on the runtime subscription immediately. No zombie pumps, no leaked timers.
EventSource / fetch-stream:
Reconnect & resume
ThePOST /chat response carries an x-persona-run-id header. If the connection drops, the
client can reattach to the same run and keep receiving the tail of the stream:
runGraceMs (default 5 minutes) in-process. Because
resume state lives in the runtime instance’s memory, route all chat traffic for a given user to
the same instance (sticky sessions) until multi-instance resume ships — see the
Reconnect & resume reference for the full mechanics and the honest
limitation.
Binary streams
File downloads (GET /files/:id) and any other kind: 'binary' response stream through the same
writer, chunk by chunk, without buffering the whole file.
Disconnect teardown, in detail
The adapter registers aclose handler on the response that calls return() on the runtime’s
subscription iterator. Because the runtime’s subscriptions return a fresh iterator per
[Symbol.asyncIterator]() call, the adapter pins the loop to the single iterator it holds — so
return() always cancels the exact subscription being consumed. A mid-stream disconnect therefore
stops the upstream run within one event loop tick.
After a normal completion (or after the close teardown), the close listener is removed — there
are no lingering listeners across requests.
Example: live token streaming
data: {...} — the messages/partial events carry token deltas; the
terminal messages/complete event ends the run. See the
AG-UI event reference for the full event taxonomy.