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 | Meaning |
|---|---|
PartStartEvent | A speech, text, or tool part started. |
PartDeltaEvent | Incremental speech audio/transcript or text content, and speech timestamps. |
PartEndEvent | A finalized part; retained speech audio appears here, not at part start. |
FunctionToolCallEvent | A local function tool began executing. |
FunctionToolResultEvent | A local function tool produced a result — a return, a failure, or a retry. |
DeferredToolRequestsEvent | A tool call was deferred (e.g. needs approval); emitted before any inline capability handler runs. |
DeferredToolResultsEvent | An inline capability handler resolved the deferred requests; the results go through normal tool processing. |
EnqueuedMessagesEvent | Enqueued content was delivered into session history. |
CustomEvent / CapabilityEvent | A tool or capability hook emitted an application or capability event. |
RealtimeInputSpeechStartEvent | The provider detected that the user started speaking, when the profile declares emits_input_speech_events. |
RealtimeInputSpeechEndEvent | The provider detected the end of user speech, when the profile declares emits_input_speech_events. |
RealtimeResponseInterruptedEvent | The provider reported an interrupted model response. |
RealtimeInputTranscriptionErrorEvent | One user turn could not be transcribed; the session remains usable. |
RealtimeOutputSpeechStartEvent / RealtimeOutputSpeechEndEvent | The model became, or stopped being, audible. These are emitted on a gpt-realtime or Azure OpenAI WebRTC sideband, where the provider owns audio playback. |
RealtimeTurnCompleteEvent | The exchange is over: the model gave every reply it owed (or, after a failure, never will), and no tool remains active. |
RealtimeSessionReconnectEvent | The connection was automatically re-established. |
RealtimeSessionErrorEvent | A 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.
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.
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.
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.