Skip to main content
The events agent.stream() emits, their order and their versioning. For how to consume a stream, see Streaming.

Event schema (version 1)

Every event has these fields: The event types and their extra fields: Optional fields are left out when they have no value. They are never undefined, so JSON.parse(JSON.stringify(event)) returns an equal object.

Ordering guarantees

  • run.start is first and run.done is last, each exactly once.
  • Each step.start is followed by exactly one step.done with the same step, before the next step.start. Everything a step does happens between the two.
  • Inside a step: compaction.start / compaction.done (if the request was compacted, before the model call), provider.retry / provider.fallback events (if the model call fails), then text.delta events, then text.done, then the tool events.
  • Tool calls of one step run in parallel (see toolConcurrency): tool.start events come in the model’s call order and tool.done / tool.error events in completion order. Match them by toolCallId.
  • input.queued comes when run.enqueue() is called (after run.start, even for input queued before the run got going), so it can fall inside a step. Its input.applied comes between the step.done of the step that was running and the next step.start, which carries the step it names.
  • input.steered comes when run.steer() is called. With mode: 'immediate' the running step ends next with step.done ('steered', no text events from its aborted call), then input.applied and the next step.start.
  • When a call needs approval, the calls before it run and report, then approval.requested, step.done ('awaiting-approval') and run.done ('awaiting-approval') follow. Calls after it never start.
  • When a guardrail blocks, guardrail.tripped comes just before the end: for an input guardrail right after run.start (no step starts); for an output or tool guardrail inside the step, followed by step.done and run.done ('guardrail'). A blocked output has no text.done; calls after a blocked tool call never start.
A text-only run:
A run with one tool call:

TypeScript

AgentEvent is a discriminated union: narrowing on event.type gives the payload. Each event type is exported too (TextDeltaEvent, ToolDoneEvent, RunDoneEvent, …), and AgentEventOf<'tool.done'> picks one by name.

Versioning

v changes only when an existing event changes incompatibly (a field removed, renamed or retyped). New event types and new optional fields can be added without changing v, so ignore event types you do not know.