- What it gives you - what goes wrong without it
- Quickstart - an agent on a realtime model
- What is supported - features by framework and model kind
- How a fixed line is said - lines with no TTS
- Instructions and values - what the model reads
- Handoffs - keep the whole conversation
- What is refused - and the words you will see
- Turn detection - set in your own code
- On Pipecat - extra wiring
- What is not here - gaps
- Where to go next
What it gives you
Quickstart
RealtimeModel is the session’s LLM. On Pipecat, OpenAI’s realtime service takes the place of STT, LLM and TTS. The full examples are examples/minimal/livekit/realtime.py and examples/minimal/pipecat/realtime.py.
What is supported
A live model is one that fixes its instructions when the session starts. On LiveKit that is anyRealtimeModel whose capabilities say mutable_instructions=False, like OpenAI’s GPT-Live. On Pipecat it is OpenAILiveLLMService.
How a fixed line is said
- The library has fixed lines: the greeting, an idle nudge, the failure line, the goodbye of
end_call_tool, a handoff’s line, and the lines a transfer says once it is over. - With a TTS on the call, as in a half cascade, the TTS says them. Nothing changes from a cascade call.
- A realtime model with no TTS beside it speaks itself. LiveKit’s
session.saywould raise, and Pipecat’sTTSSpeakFramewould play nothing. - So the model is told to say the line: “Say this to the caller now, in these words as far as you can: …”. This text is
SAY_LINEinunmute_core.realtime. - The line is a reply of the model’s own. It joins the model’s conversation.
ToolReply line either, even with a TTS after it. A tool’s result starts the model’s own reply there, and a second spoken line would talk over it. The model reads the result and words its reply. See Save a result and speak it.
Instructions and values
The model reads one text: the prompt, filled, then the notes of the tools on events, then the values block withsave_values. The values block is a system message that lists the State values. A cascade request sends the notes and the values as messages of their own. A realtime model has no requests, so they follow the prompt. realtime_instructions builds that text.
- The
prompthooks run on the prompt before it is filled, as on a cascade call. See Hooks. - After each save, the model gets the instructions again: LiveKit’s
update_instructions, or Pipecat’sLLMUpdateSettingsFrame. A value a background prefetch saves arrives the same way. - Each caller message runs the call’s tools on events. The model answers that message meanwhile and nothing waits for them. Their notes reach the model with the next instructions. See The call’s life.
- A live model gets the instructions once. On LiveKit that is as the agent starts. On Pipecat it is as
UnmuteFlowsorattach_realtimeis set up. A value saved later never reaches it, prefetch included, and neither do the notes of tools on events. - A plain Pipecat pipeline without
UnmuteFlowsgets the same withattach_realtime, before the pipeline runs.
attach_realtime
Runs OpenAI’s realtime or live service as the agent on Pipecat. Await it before the pipeline runs. It refuses what the model cannot do, then queues the filled instructions on the service.LLMService[Any]
required
The call’s realtime or live service.
PipelineWorker
required
The call’s worker. Its end stops following the state.
str
required
The agent’s prompt, placeholders still in it.
CallState | None
default:"None"
The call state the placeholders read.
CallHooks | None
default:"None"
The call’s hooks. Its
prompt hooks and the notes of its tools on events apply.bool
default:"False"
The agent has the
save_values tool. Its values follow the prompt.Mapping[str, str] | None
default:"None"
Value name to the task that saves it, for the values block.
Handoffs
A realtime model keeps the whole conversation on its own server. A handoff keeps it too. The Handoffs page covers handoffs in general.- Pass
HandoffContext(history="full"). Any other history is refused, because the library cannot reshape what the model holds. Tool calls must stay in, which is the default. - The model says the handoff’s line first.
- The next agent’s instructions and tools replace the first agent’s, on the same connection.
- The next agent speaks first.
What is refused and why
Each refusal has the same words on both frameworks.UnmuteFlows refuses when it is built. UnmuteAgent refuses as it enters the session, and closes the session, because the agent would run without what was refused. Each message names what to remove or what to run instead.
- Tasks. A step needs its own history and a finish check. Both are requests the library sends, and a realtime model has none.
before_model,wrap_modelandafter_modelhooks. No model request passes through the library, so they would never run. Theprompthooks do run.save_valueson a live model. Its instructions are fixed.- A handoff on a live model, or one without
history="full". See above.
Turn detection
Turn detection is part of building the model, so it stays in your code. These are the settings for OpenAI’s models. On LiveKit,ServerVad and SemanticVad come from openai.types.realtime.realtime_audio_input_turn_detection.
When the model decides the turn, some turn-taking settings do nothing:
endpointing(),vad_params()andsmart_turn_params(). The model’s own VAD sets the pace.interruption(enabled=False)on LiveKit. It raises when the session starts, because LiveKit cannot stop the model from being cut off.- Pipecat’s interruption strategies, like
Backchannels. They act on local VAD frames, and the server cancels its reply itself.
On Pipecat
- Pass the service to
open_call(llm=...), withUnmuteFlowstoo, and toIdleNudgeObserver(llm=...). They then say the greeting, the failure line and the nudges through the model. Left out, these lines becomeTTSSpeakFrames that nothing plays, and nothing reports it. - Any other realtime service, like Gemini Live, is taken for a cascade LLM. Its fixed lines are not said.
- A greeting goes to the model as a developer message. Pipecat drops a first system message when the service has its own instructions.
- When the caller speaks first,
open_callgives the service its context and tools at once. Without that, Pipecat sets the conversation up in the middle of the caller’s first turn. It sends the turn again as a “previously saved conversation”, asks for a second reply, and the model gets its tools only then. - A live service opens its session on a first request. When the caller speaks first,
open_callstill sends one. - A line said while the model replies waits for the reply to end. The server refuses a second reply while one runs.
TelemetryObserverrecords onellmspan per reply. Pipecat starts a realtime reply twice, and starts none for a reply that only calls a tool. The observer handles both.
What is not here
- Gemini Live, Nova Sonic, Ultravox, Grok and Inworld on Pipecat. Their services take instructions, tools and replies in other ways. On LiveKit any
RealtimeModelworks. - The SLNG Context Router. It has no realtime endpoint.
- Building the model. Its voice, its turn detection and its transcription stay in your code.
Where to go next
Handoffs
Give the call to another agent.
Turn taking
Pace, interruption and idle nudges on a cascade call.
The model call
The plug point a realtime model does not use.
How Unmute builds realtime agents
The compiler side, on the Unmute tab.