Agents process input events and yield output events to control the conversation.
What is an Agent?
An Agent controls the input/output event loop. The process method receives events (user speech, call start, etc.) and yields responses.
An Agent can be:
- A class with a
process method
- A function with the same signature
(env, event) -> AsyncIterable[OutputEvent]
How an Agent works:
- Events arrive (user speaks, call starts, button pressed)
- SDK calls
agent.process(env, event)
- Agent yields output events (speech, tool calls, handoffs)
- SDK handles audio, LLM calls, and state management
LlmAgent
Use the built-in LlmAgent which wraps 100+ LLM providers via LiteLLM:
Prompting
system_prompt to define your agent’s personality and introduction for the greeting:
Supported Models
| Provider | Model Examples |
|---|
| Anthropic | anthropic/claude-haiku-4-5-20251001, anthropic/claude-sonnet-4-5 |
| OpenAI | gpt-5.4, gpt-5.2 |
| Google | gemini/gemini-2.5-flash-preview-09-2025, gemini/gemini-3.0-preview |
| And 100+ more via LiteLLM | |
LlmConfig Options
| Option | Type | Description |
|---|
system_prompt | str | The system prompt defining agent behavior |
introduction | Optional[str] | Message sent on call start. None or "" to wait for r |
temperature | Optional[float] | Sampling temperature |
max_tokens | Optional[int] | Maximum tokens per response |
top_p | Optional[float] | Nucleus sampling threshold |
stop | Optional[List[str]] | Stop sequences |
seed | Optional[int] | Random seed for reproducibility |
presence_penalty | Optional[float] | Presence penalty for token generation |
frequency_penalty | Optional[float] | Frequency penalty for token generation |
num_retries | int | Number of retries on failure (default: 2) |
fallbacks | Optional[List[str]] | Fallback models if primary fails |
timeout | Optional[float] | Request timeout in seconds |
reasoning_effort | Optional[str] | none, low, medium, or high. Dependent on provider. |
extra | Dict[str, Any] | Provider-specific options passed through to LiteLLM |
History Management
LlmAgent exposes a history attribute for structured control over the conversation history the LLM sees.
Adding entries:
Replacing history segments:
Per-Turn Overrides
process() accepts keyword arguments that apply to just that turn without mutating the agent:
Only explicitly set LlmConfig fields take effect — unset fields fall through to the agent’s stored config.
To change tools permanently (e.g., enabling end_call after a certain point), modify agent.tools directly instead of using per-turn overrides.
Controlling the Conversational Loop
Use event filters to control when your agent’s process method runs, and which events can interrupt it.
Default Behavior
This means: agent greets on call start, responds when user finishes speaking, and can be interrupted.
Customizing Filters
Return a tuple from get_agent to override defaults:
Common Customizations
More responsive (process partial transcriptions):
This makes your agent start processing before the user finishes speaking, creating a more responsive experience.
Uninterruptible turns:
If you want a single message to complete without being interrupted by the user, mark the output as interruptible=False when sending it with AgentSendText.
Custom logic with functions:
For advanced patterns like guardrails, routing, and agent wrappers, see Advanced Patterns.
Handling Incoming Calls
When a call arrives, you can inspect caller information and configure how your agent responds before it starts.
- A call arrives from a web client or telephony provider
- Your
pre_call_handler receives a CallRequest with caller details
- You return configuration (voice, language) or reject the call
- Your
get_agent function creates an agent using the enriched request
Parsing the CallRequest
Contains information about the incoming call:
| Field | Type | Description |
|---|
call_id | str | Unique identifier for the call |
from_ | str | Caller identifier (phone number or client ID) |
to | str | Called number or agent ID |
agent_call_id | str | Agent call ID for logging/correlation |
metadata | Optional[dict] | Custom data passed from your client application |
agent | AgentConfig | Prompts configured in Playground or via API |
The agent field contains an AgentConfig with:
| Field | Type | Description |
|---|
system_prompt | Optional[str] | System prompt configured in Playground or via the WebSocket API |
introduction | Optional[str] | Introduction message configured in Playground or via the WebSocket API |
Returning a PreCallResult
Use pre_call_handler to set voice, language, or reject calls before your agent starts:
Your client application can pass metadata (user ID, language preference, account tier) in the call request. Your pre_call_handler reads this and configures TTS/STT accordingly.
Configuration Options
TTS Options:
| Option | Type | Description |
|---|
voice_id | string | Voice identifier (UUID) |
model | string | TTS model (sonic-3.5, sonic-3, sonic-turbo) |
language | string | Language code (en, es, hi, etc.) |
pronunciation_dict_id | string | Custom pronunciation dictionary ID |
STT Options:
| Option | Type | Description |
|---|
language | string | Language code for speech recognition |
Rejecting Calls
Return None to reject a call with a 403 status:
Custom Pronunciations
Use a pronunciation dictionary to control how specific words are spoken:
The CallRequest is available in get_agent:
LlmConfig.from_call_request() handles the priority chain automatically:
CallRequest.agent.system_prompt value (if set)
- Your fallback value (if provided)
- SDK default
Using CallRequest lets you iterate on system prompts from the Playground instantly, while code handles the technical configuration and fallback defaults.
Letting The User Speak First
Set introduction to an empty string to wait for the user to speak first:
Custom Agent Function
For advanced use cases, you can build agents from scratch as functions:
Custom Agent Class
Or as classes with state:
Most developers can use LlmAgent with tools rather than building custom agents from scratch! Custom agents are powerful when you need full control over the event processing logic without LLM reasoning.