Payloads
Real-time streaming is not enabled on accounts yet. See the overview for what to do instead.
What lands on each node: incremental chunks, the run status a composer keys off, and the finalized message.
Two writers feed these nodes, and they do not agree on casing.
streaming/…is assembled by hand and issnake_case(run_id,started_at).conversations/…is the protojson encoding of the underlying event, so it iscamelCase(runId,eventContext) — the same convention as API responses.
Do not carry a key from one example to the other.
Streaming Chunks
Listen on streaming/{conversationId}/{messageSequence}. Each write replaces the whole node, so you receive the accumulated chunks array plus a meta object every time.
{
"meta": {
"run_id": "64403669-5989-4ec3-ad9c-d84223f9679f",
"status": "streaming", // "streaming" | "complete" | "error"
"started_at": "2026-04-23T22:43:44.700Z"
},
"chunks": [
{ "content": "I can ", "type": "STREAM_CHUNK_TYPE_TEXT", "timestamp": "2026-04-23T22:43:44.712Z" },
{ "content": "help ", "type": "STREAM_CHUNK_TYPE_TEXT", "timestamp": "2026-04-23T22:43:44.809Z" },
{ "content": "with…", "type": "STREAM_CHUNK_TYPE_TEXT", "timestamp": "2026-04-23T22:43:44.907Z" }
]
}
Chunk fields
| Field | Meaning |
|---|---|
content | The token text (or reasoning/tool-call fragment) for this chunk |
type | STREAM_CHUNK_TYPE_TEXT, STREAM_CHUNK_TYPE_REASONING, or STREAM_CHUNK_TYPE_TOOL_CALL |
timestamp | Server time the chunk was written |
tool_call | Present only on tool-call chunks — see below |
A chunk carries no terminal marker of its own: completion lives on meta, never on
the chunk. A STREAM_CHUNK_TYPE_TOOL_CALL chunk adds a tool_call object with the
fragment of the call assembled so far:
{
"content": "",
"type": "STREAM_CHUNK_TYPE_TOOL_CALL",
"timestamp": "2026-04-23T22:43:45.104Z",
"tool_call": {
"index": 0,
"id": "call_abc123",
"name": "get_weather",
"arguments_delta": "{\"ci"
}
}
arguments_delta is a fragment, not valid JSON on its own — concatenate the deltas
for a given index across chunks before parsing.
The chunks array is indexed by position and may contain gaps (nulls) mid-stream as writes arrive out of order — always render by accumulating non-null entries in order, don't assume the array is dense.
Filter chunk types for display: render STREAM_CHUNK_TYPE_TEXT into the message bubble; treat STREAM_CHUNK_TYPE_REASONING and STREAM_CHUNK_TYPE_TOOL_CALL separately (or hide them). When reasoning is enabled, reasoning chunks arrive first, then text chunks.
The meta node
meta is written twice. On the first chunk it carries run_id, status: "streaming"
and started_at. When the stream ends it is updated in place:
{
"run_id": "64403669-5989-4ec3-ad9c-d84223f9679f",
"status": "complete", // "error" when finish_reason is "error"
"started_at": "2026-04-23T22:43:44.700Z",
"finished_at": "2026-04-23T22:43:46.219Z",
"finish_reason": "stop", // "stop" | "tool_calls" | "length" | "error"
"usage": {
"prompt_tokens": 812,
"completion_tokens": 47,
"total_tokens": 859
}
}
error_message is added only when finish_reason is "error", and usage only when
the provider reported it. Keys that do not apply are absent, not null — read them
with a default.
Detecting completion
A stream is done when any of these is true — check meta.status first, it is authoritative:
meta.status == "complete"(or"error"), ormeta.finish_reasonis present, orconversations/{conversationId}/statusreturns to a non-generatingstate.
The finalized message landing under conversations/{conversationId}/messages also
back-fills meta.status to "complete", so a client that missed the final chunk still
converges.
Conversation Status
Listen on conversations/{conversationId}/status for a single last-write-wins node that tracks what the conversation is doing. Use it to drive a busy indicator and to de-duplicate out-of-order writes via seq.
This node is the whole ConversationStatusChangedEvent, protojson-encoded — hence
camelCase, and hence the eventContext envelope alongside the fields you care about.
{
"eventContext": { "correlationId": "…", "eventId": "…", "callerKey": "conv_abc" },
"state": "CONVERSATION_ACTIVITY_STATE_GENERATING",
"runId": "64403669-5989-4ec3-ad9c-d84223f9679f",
"seq": "7", // int64 as string
"since": "2026-04-23T22:43:44.712Z"
}
state value | Meaning |
|---|---|
CONVERSATION_ACTIVITY_STATE_IDLE | Nothing running — safe to send the next message |
CONVERSATION_ACTIVITY_STATE_QUEUED | Generation accepted, not started yet |
CONVERSATION_ACTIVITY_STATE_GENERATING | Model is producing tokens |
CONVERSATION_ACTIVITY_STATE_EXECUTING_TOOLS | Running tool calls |
CONVERSATION_ACTIVITY_STATE_COMPACTING | Compacting context |
CONVERSATION_ACTIVITY_STATE_ERROR | Last run failed — see error |
error appears only in the ERROR state, as { "code": "…", "message": "…" }.
Finalized Messages
Once a turn settles the full message is written under
conversations/{conversationId}/messages, keyed by the message's sequence so a
re-delivery overwrites rather than duplicates. This node is protojson-encoded —
camelCase:
{
"eventContext": { "correlationId": "…", "eventId": "…", "emittedAt": "…" },
"message": {
"role": "ROLE_ASSISTANT",
"content": [ { "type": "CONTENT_PART_TYPE_TEXT", "content": "I can assist you with…" } ],
"generatedBy": "64403669-5989-4ec3-ad9c-d84223f9679f",
"sequence": "8",
"model": "anthropic/claude-sonnet-4",
"toolCalls": [
{ "id": "call_abc123", "name": "get_weather", "status": "TOOL_EXECUTION_STATUS_SUCCESS",
"argumentsJson": "{\"city\":\"NYC\"}" }
]
}
}
Sibling nodes under the same conversation follow the same encoding:
| Node | Written on | Contains |
|---|---|---|
conversations/{id}/messages | Every message appended or upserted | The full message, keyed by sequence |
conversations/{id}/runs/{runId} | Generation start and finish | runId, status, loopCount, durationMs, usage, error |
conversations/{id}/activity | Tool call start and finish | toolCall, executionTimeMs |
conversations/{id}/status | Every lifecycle transition | See above |
conversations/{id}/queue | Pending user queue changes | pending, the whole queue in order |
conversations/{id}/compaction | Context compaction lifecycle | Compaction progress and outcome |