Skip to content

Events

Every action during a session — user input, LLM responses, tool calls, lifecycle transitions — emits an event. The event log is the source of truth for session state; the SSE stream is a live tail of that log.

For why the platform is shaped this way, see Events as the primary store. For the full catalog of event types and payloads, see the Event Reference.

CategoryExamplesDescription
Inputinput.messageUser messages submitted to the session
Outputoutput.message.started, output.message.delta, output.message.completedAgent response lifecycle
Turnturn.started, turn.completed, turn.failed, turn.cancelledTurn lifecycle
Thinkingreason.thinking.*Extended thinking content (Claude, GPT-5.x, o-series)
Atomreason.*, act.*, tool.*Internal execution phases
LLMllm.generationFull LLM API call details
Sessionsession.started, session.activated, session.idledSession state changes
Subagentsubagent.*Subagent lifecycle
{
"id": "event_01933b5a00007000800000000000001",
"type": "turn.completed",
"ts": "2024-01-15T10:30:00.000Z",
"session_id": "session_01933b5a00007000800000000000002",
"sequence": 42,
"context": {
"turn_id": "turn_...",
"input_message_id": "message_...",
"trace_id": "turn_...",
"span_id": "abc123",
"parent_span_id": "def456"
},
"data": { /* type-specific payload */ }
}
FieldTypeDescription
idstringUnique event ID (UUIDv7)
typestringEvent type in dot notation
tsstringISO 8601 with millisecond precision
session_idstringSession this event belongs to
sequenceintegerMonotonic per-session sequence (ordering source of truth)
contextobjectCorrelation IDs for tracing
dataobjectEvent-specific payload

Ordering is by sequence, not ts. Two events with the same wall-clock time still have a strict order.

Long-running operations follow a lifecycle:

turn.started → turn.completed
↘ turn.failed
↘ turn.cancelled

These boundaries are what your UI uses to manage state and surface errors.

Streaming content uses delta events with accumulated state:

{
"type": "output.message.delta",
"data": {
"turn_id": "turn_...",
"delta": "Hello",
"accumulated": "Hello"
}
}

Deltas are batched at ~100ms to reduce volume.

Events follow a defined contract. Consumers must tolerate evolution:

ChangeAllowed
New event typesyes
New optional fieldsyes
New enum valuesyes
Removing or retyping fieldsno

Your deserializer should ignore unknown fields, ignore unknown event types, and treat optional fields as optional.