docs/examples/realtime-handoff.md
Realtime speech-to-speech models are great conversationalists, but they don't produce structured
output. This example shows the robust pattern: let the realtime model run the live conversation,
then hand its message history to a normal
[Agent.run()][pydantic_ai.agent.AbstractAgent.run] with output_type to extract a typed result.
Because a realtime session records the same
[ModelMessage][pydantic_ai.messages.ModelMessage] history a text agent produces, the handoff is
just passing [session.all_messages()][pydantic_ai.realtime.RealtimeSession.all_messages] along —
realtime and non-realtime runs are peers that interoperate through message history.
Demonstrates:
The example models a short support call: a caller describes a problem to the realtime voice agent,
then the accumulated conversation is handed to a text agent that distills it into a typed
SupportTicket. The caller's side is driven with text turns so the example runs without a
microphone — a real app would stream microphone audio with
[send_audio()][pydantic_ai.realtime.RealtimeSession.send_audio] instead (see the
voice assistant example).
The handoff only runs after every scripted caller turn receives a
[RealtimeTurnCompleteEvent][pydantic_ai.realtime.RealtimeTurnCompleteEvent]. If the realtime connection ends
early, the example raises an error rather than creating a ticket from a partial call.
Both the realtime gpt-realtime model and the text triage agent run on OpenAI, so you'll need an
OpenAI API key set via OPENAI_API_KEY.
With dependencies installed and environment variables set, run:
python/uv-run -m pydantic_ai_examples.realtime_handoff
snippet {path="/examples/pydantic_ai_examples/realtime_handoff.py"}