Streaming Events
agent.query() returns an async generator of SDK messages.
for await (const message of agent.query("What is 2+2?")) { switch (message.type) { case "system": console.log("session", message.session_id); break; case "stream_event": console.log("raw stream event", message.event); break; case "assistant": console.log("assistant message", message.message); break; case "user": console.log("tool result", message.tool_use_result); break; case "result": console.log("final", message.result); break; }}Message types
Section titled “Message types”| Type | Description |
|---|---|
system |
Session initialization metadata. |
stream_event |
Raw provider stream events, emitted when streaming is enabled. |
assistant |
Assistant message after model assembly. |
user |
Tool result message sent back to the model. |
result |
Final success, API error, abort, or max-turn result. |
Delivery timing
Section titled “Delivery timing”stream_event messages arrive while the model is still responding rather than in a burst after the turn ends, so they can drive incremental UI directly. assistant arrives once the model response for that turn is assembled, and user arrives after the whole tool batch has finished.
The SDK produces the next event only after the consumer takes the current one. Slow work inside the for await body delays later events without dropping or reordering them, so keep expensive handling off the loop itself.
Per-event guarantees
Section titled “Per-event guarantees”The event stream is built for live UI. These guarantees are part of the public contract:
- The prompt is not echoed.
agent.query("...")never yields auserevent containing your prompt; the prompt goes into the internal history only. If you need the full transcript — the prompt, tool results, and messages injected by a team runtime — subscribe a ContextTracer instead. Itsuser_message/assistant_messageevents record everything; the event stream does not. assistantfires once per model turn, after that turn’s response is fully assembled.messageis anAssistantModelMessage:contentholds text andtool_useblocks,stopReasonsays why the model stopped, andproviderResponseId/modelcarry provider metadata when the model client reports them.userappears only after a whole tool batch has finished executing — one event per batch, never one per tool.message.contentis alwaysToolResultBlock[].tool_use_resultis a convenience view over the same results: with a single tool it is that result’scontent(string | ContentBlock[]); with several tools it is the array of result blocks. The first tool error, if any, is also surfaced onerror, and an aborted batch still yields auserevent witherrorset.resultis the terminal event, emitted exactly once per query.subtypeis"success"for a normal end,"interrupted"whenAgent.interrupt()ends the query cleanly (completed turns stay in history andis_errorremainsfalse), or one of"error","error_max_turns","error_abort","error_timeout". Even on success, checkstop_reasonfor"max_tokens"— the text may be a truncated fragment.