Skip to content

Events

Iterating a RealtimeSession yields the session’s event stream: content parts, tool activity, turn boundaries, reconnects, and recoverable errors. The high-level stream_audio() and stream_transcripts() views described in Audio, images, and transcripts are derived from this same stream, so most applications iterate the session for control flow and leave media to the views.

If nothing is iterating the session, the session keeps the most recent 512 part delta events (audio, transcript, and text) and the most recent 512 structural events for a late async for; older ones are discarded. Discarding a part’s start discards the rest of that part with it, so a late iterator never receives a delta it cannot attach to a part. A failure parked for the consumer is never discarded.

Event reference

EventMeaning
PartStartEventA speech, text, or tool part started.
PartDeltaEventIncremental speech audio/transcript or text content, and speech timestamps.
PartEndEventA finalized part; retained speech audio appears here, not at part start.
FunctionToolCallEventA local function tool began executing.
FunctionToolResultEventA local function tool produced a result — a return, a failure, or a retry.
DeferredToolRequestsEventA tool call was deferred (e.g. needs approval); emitted before any inline capability handler runs.
DeferredToolResultsEventAn inline capability handler resolved the deferred requests; the results go through normal tool processing.
EnqueuedMessagesEventEnqueued content was delivered into session history.
CustomEvent / CapabilityEventA tool or capability hook emitted an application or capability event.
RealtimeInputSpeechStartEventThe provider detected that the user started speaking, when the profile declares emits_input_speech_events.
RealtimeInputSpeechEndEventThe provider detected the end of user speech, when the profile declares emits_input_speech_events.
RealtimeResponseInterruptedEventThe provider reported an interrupted model response.
RealtimeInputTranscriptionErrorEventOne user turn could not be transcribed; the session remains usable.
RealtimeOutputSpeechStartEvent / RealtimeOutputSpeechEndEventThe model became, or stopped being, audible. These are emitted on a gpt-realtime or Azure OpenAI WebRTC sideband, where the provider owns audio playback.
RealtimeTurnCompleteEventThe exchange is over: the model gave every reply it owed (or, after a failure, never will), and no tool remains active.
RealtimeSessionReconnectEventThe connection was automatically re-established.
RealtimeSessionErrorEventA recoverable provider error occurred; the session remains usable.

A part’s index identifies it for the whole session. A provider can finish an output item after a later item has started, so text of the item’s transcript can arrive after its part ended: the session then streams that part again under the same index, and the new PartStartEvent replaces the part as it ended. Keep parts by index rather than adding one for every PartEndEvent.

Shared and realtime-only events

The first nine rows are AgentStreamEvent members from pydantic_ai.messages — the same events a standard streamed run yields, so event-handling code written for a text agent (rendering parts, logging tool calls) works on a session unchanged. The Realtime* rows are RealtimeSessionEvent members, the part of AgentStreamEvent that only a session emits: speech detection, interruption, turn completion, reconnection, and recoverable errors have no equivalent in a request-response run.

A capability’s event stream hooks see both kinds flow through the same stream; see Capabilities and hooks.

The turn boundary

Use RealtimeTurnCompleteEvent as the exchange boundary. A model can speak, call a tool, and speak again, so receiving speech — or a tool result — does not imply that the turn is done.

The event marks the end of what wait_for_reply() waits for. When a response ends, the session emits it if the model owes nothing more: no reply to anything sent, no answer to a tool’s result, and no response still under way.

Only the response that answers an input settles its reply: a response already under way when the input reached the provider never saw it, so it doesn’t. Text sent while the model is answering therefore usually gets a reply of its own, and the event comes once that reply ends too. How a provider answers such text varies: GPT-Live speaks to it in the reply it is giving (see OpenAI), and some Gemini Live models cut their reply off for it (see Gemini).

A response the user cuts off by speaking ends the exchange, as does a response the provider started on its own (server-side voice activity detection). The user’s transcript can still finish after it.

A tool that raises doesn’t end the exchange: the model is told the call failed, and the event comes once it has answered that. An exchange that fails also ends with the event, once: when a tool’s result would pass a usage limit, or a failed tool’s result can’t be sent, the model never gets what it needs to reply. The event follows the exception in the event stream, or comes as the response still under way ends.

Reading raw audio events

The audio stream is these events under the hood: stream_audio() is a bounded view over the speech part deltas, and most applications should use it. As an advanced alternative, play SpeechPartDelta.audio_chunk from raw PartDeltaEvents. Model audio arrives in full whether or not history retention is enabled. When output audio is retained, the final SpeechPart contains the whole turn again as a WAV snapshot for history; do not play both or the turn will play twice.