Stream conversation events
Opens a Server-Sent Events stream of a conversation’s live turn activity, emitting named events (agent token, tool, and final event kinds, plus stale when the client has lagged and done when the turn closes) each carrying a JSON data payload and an incrementing id sequence. Resume after a disconnect with the standard Last-Event-ID header or the since_seq query parameter; the optional scope parameter narrows the detail level (and is clamped to the caller’s token scope), and view=admin lets an admin attach to a conversation they do not participate in. The caller must have access to the conversation, otherwise 404 is returned.
Server-Sent Events
This endpoint is a long-lived Server-Sent Events (SSE) stream, not a one-shot JSON response. Open it with an SSE client and keep it open — it emits one event per agent or platform update until you disconnect.: ping / : idle) is sent periodically as a keepalive so proxies don’t drop the connection — ignore it.
Event shape
Each event has anevent: name, a monotonic id: cursor, and a single-line JSON data: payload:
Common events
event: | data | Meaning |
|---|---|---|
text_delta | { text } | A chunk of the assistant’s reply — append it. |
status | { message } | Progress caption. |
agent_active | { hint } | Drive a typing indicator. hint is diagnostic — don’t render it as user-facing text. |
tool_call | { id, name, scope, args_summary, args_digest } | The agent invoked a tool. |
tool_result | { id, is_error, summary } | The matching tool call finished. |
token_usage | { model, input_tokens, output_tokens, cost_usd, … } | Usage and cost for the turn. |
final | { text, duration_ms } | Terminal for the turn — the reply is complete. |
error | { message, recoverable } | Terminal for the turn — it failed. |
final/error end a turn, not the stream — the next message produces the next batch. New event: names may be added over time; ignore ones you don’t recognize (standard SSE behavior).
Reconnecting
id: is an opaque, incrementing sequence. On reconnect, send the last one you saw as the Last-Event-ID header and the server replays the events you missed from the conversation journal. (EventSource sets Last-Event-ID automatically on auto-reconnect; on a fresh attach where you can’t set the header, pass ?since_seq=<id> instead.) An optional ?scope= query parameter narrows which events you receive.
POST to Post a message (returns immediately) and read the result off this stream.Authorizations
Personal Access Token. Send as Authorization: Bearer hq_pat_....
Path Parameters
Conversation id
Query Parameters
Self-downgrade only. user strips diagnostic + accounting
fields; admin / integrator and absent default to the
trusted full vocabulary. Unknown values do NOT elevate -- see
[crate::stream_scope::Scope::from_query]. Auth-derived
scope replaces this in #729.
Explicit "I've already seen up to seq N" cursor for fresh
attaches. The standard EventSource API doesn't let JS set
Last-Event-ID on the initial request -- only on automatic
reconnects -- so Studio passes its journal high-water mark
here to avoid a race where events emitted between the journal
fetch and the SSE subscribe vanish into the gap.
?view=admin opts a tenant admin into attaching to a
conv stream they don't participate in. Non-admins are
silently downgraded. Audited per-attach so admin tail
reads of someone else's conv are observable.
Response
Server-Sent Events for the conversation's turn. Each frame is a named event (the agent token/tool/final event kinds, plus stale when the client lagged and done when the turn closes) carrying a JSON data payload and an id: sequence. Resume after a drop with the standard Last-Event-ID header, or pass ?since_seq= on a fresh attach. Native EventSource (cookie auth) and fetch-stream (Bearer PAT) both work.