DialogAdapter, assign it to ctx.session.dialog_machine, and Unpod handles
the rest of the call - telephony, speech-to-text, text-to-speech, audio
transport. Your Agent stays
text-in/text-out.
If you don’t have an agent yet, start with the
Quickstart instead - it builds the minimal brain
first.
Install
Write your entrypoint
The entrypoint is an async function called once per call. Set your agent onctx.session.dialog_machine and call await ctx.session.run().
AgentRunner requires UNPOD_API_KEY in your environment, and the
agent_id you pass must match your Speech Pipe’s agent_id - see
IDs You’ll Meet. The
Setup Checklist lists
every variable.Streaming is the hot path
This is the single most important thing on this page. During a live call,session.run() calls your adapter’s stream() on
every user turn and pipes tokens straight to the voice bridge for synthesis.
turn() is never called by the framework during live calls.
The bundled adapters differ here - check the table below before choosing:
OpenAIAdapter, AnthropicAdapter, and LangChainAdapter stream real tokens
from their providers; HTTPAdapter cannot stream (one HTTP round-trip, one
chunk), so expect a latency penalty proportional to your response length.
The DialogAdapter protocol
Any object with these three methods is a valid brain - no base class required (the protocol is runtime-checkable):DialogMachine or LLMAgent
directly to ctx.session.dialog_machine wraps it in a SuperDialogAdapter
for you. Anything else must satisfy the protocol above, or the setter raises
TypeError.
Supported adapters
| Adapter | Import | Real streaming | Use when |
|---|---|---|---|
OpenAIAdapter | unpod.adapters.openai | Yes | OpenAI AsyncOpenAI client - gpt-4o, gpt-4o-mini, etc. |
AnthropicAdapter | unpod.adapters.anthropic | Yes | Anthropic AsyncAnthropic client - Claude models |
LangChainAdapter | unpod.adapters.langchain | Yes | LangChain chain with .ainvoke() / .astream() |
SuperDialogAdapter | unpod.adapters.superdialog | Yes | superdialog DialogMachine / LLMAgent - or assign directly, auto-wrapped |
HTTPAdapter | unpod.adapters.http | No - single chunk | Remote agent API (any language); accepts the latency trade-off |
MCPAdapter | unpod.adapters.mcp | Preview | Interface defined; full MCP orchestration is not implemented yet (unpod[mcp]) |
| Custom | Implement the protocol | Up to you | Any Python object with turn, stream, assist |
OpenAI
Anthropic (Claude)
Model name formats differ by layer: direct adapters take the provider’s raw
model name (
claude-haiku-4-5-20251001, gpt-4o-mini); superdialog brains
take a provider/model URI (anthropic/claude-haiku-4-5). Both are correct
in their context.LangChain
LangChainAdapter expects your chain to accept {"messages": [...]} as input
by default. This works with ChatPromptTemplate | ChatModel chains. The
adapter keeps conversation history across turns and streams via .astream().
If your chain uses a different input key, pass input_key:
HTTP endpoint
HTTPAdapter lets you keep your agent in any language behind an HTTP API.
Each user turn becomes one POST:
Using session controls
Inside your entrypoint you can react to call events and control the call:call_start, user_turn, agent_turn, user_partial,
interruption, call_end, error (the registry also accepts tool_call,
tool_result, silence, and metric). See
Session for the full control surface.
Writing a custom adapter
Implement the three protocol methods - no base class required:Next steps
Setup Checklist
One-time resource provisioning: agent, number, voice profile
Session Controls
say(), transfer(), recording controls during live calls
SuperDialog
State machine framework for structured conversation flows
SuperDialog + Voice
Plug a DialogMachine directly into your AgentRunner session