Open, content, close
A streamed item is opened by its*_START event, extended by zero or more
content events, and closed by its *_END event, all matched by the item’s
identifier (messageId for messages, toolCallId for tool calls).
- A producer MUST NOT open an item whose identifier is already open.
- A producer MUST NOT send a content or end event for an identifier that is not open.
- Every item a producer opens MUST be closed before the run finishes.
delta. Deltas concatenate in arrival order to
form the item’s value.
Interleaving
Messages, tool calls, reasoning messages and steps are independent. A producer MAY interleave them freely — a tool call MAY open while a message is still streaming — provided each item respects its own open/close discipline. Standalone events (STATE_SNAPSHOT, STATE_DELTA, MESSAGES_SNAPSHOT,
ACTIVITY_SNAPSHOT, ACTIVITY_DELTA, CUSTOM, RAW,
REASONING_ENCRYPTED_VALUE) open and close no items of their own, and MAY
appear anywhere within an open run. In the chunked form, some of them do end
an open chunk stream — arriving is what tells the consumer the shorthand can
no longer continue — as Closing a chunk stream
lists.
The chunked form
TEXT_MESSAGE_CHUNK, TOOL_CALL_CHUNK and REASONING_MESSAGE_CHUNK are a
compact spelling of the triad. A consumer MUST expand them into the
start/content/end form before verification and before application code, so
every rule of the triad applies to the expanded events. Where expansion sits
relative to enforcement and middleware is specified in the
processing model; the invariant that holds on
every path is that a chunk is judged as the event it is — whichever stage
meets a malformed chunk first rejects it rather than repairs it.
The two spellings do not mix within one item. An item opened by a chunk is
continued and closed in chunk form — its *_END is synthesized, never sent —
and an item opened by a *_START is continued and closed explicitly. An
explicit event carrying an identifier a chunk stream is assembling is not a
continuation of it: it ends the shorthand, as
Closing a chunk stream describes, and what follows
is judged by the triad rules — which makes mixing the forms within one item a
malformed sequence a producer MUST NOT emit.
The first chunk
The first chunk of an item carries what opening it requires; later chunks MAY omit those fields and continue what is already open.- The first
TEXT_MESSAGE_CHUNKfor a message MUST carrymessageId. It MAY carryrole; an absent role meansassistant, exactly as onTEXT_MESSAGE_START. - The first
REASONING_MESSAGE_CHUNKfor a message MUST carrymessageId. - The first
TOOL_CALL_CHUNKfor a call MUST carry bothtoolCallIdandtoolCallName.
Continuation chunks
- A later chunk that carries an identifier MUST carry the same identifier it is continuing. A chunk that names a different identifier opens a new item, and the previous one closes first.
- A continuation chunk MAY repeat a field its opener established —
roleornameon a text message,toolCallNameorparentMessageIdon a tool call — but only with the same value. A consumer MUST treat a conflicting repeat as a protocol violation. This includes a value conflicting with one the opener established by omission: a message opened without a role is anassistantmessage, and a later chunk claiming another role contradicts it.
The conflicting-repeat rule is the same judgment the
subagent attribution rules pass on a
continuation that disagrees with its opener about
subagentRunId: the
producer has said two incompatible things about one item, and there is no
correct way to choose between them.Closing a chunk stream
The chunked form has no explicit end event, so the consumer synthesizes the*_END when the stream can no longer continue:
- when a chunk opens a different item in the same lane;
- when a message, tool-call, step, state, custom or reasoning event arrives in
the item’s lane — with four exceptions that stand aside from assembly and
close nothing:
RAW,ACTIVITY_SNAPSHOT,ACTIVITY_DELTA,REASONING_ENCRYPTED_VALUE(andSUBAGENT_STARTED, which opens a new lane rather than touching this one); - when a run-level event arrives —
RUN_STARTED,RUN_FINISHED,RUN_ERRORorMESSAGES_SNAPSHOT— which closes every lane, or when the subagent the item is attributed to terminates, which closes that subagent’s lane.
Chunk metadata
A chunk’smetadata applies to the events synthesized from that chunk, and
merges into the item under the
metadata rules. A continuation chunk that
carries only metadata — a final chunk reporting usage and a finish reason — is
legal: it adds no content, and its metadata still reaches the item it
continues.