examples/salon-concierge declares
outbound: false, and every other package is browser only. So the snippets and
commands below are a worked example named my-agent, an agent that calls a
customer about an appointment. Everything in them is authorable as shown; there
is just no package in the repository to run them against.
On this page:
- Declare the direction -
channels:, key by key, for an agent that dials - One route per target - a connection file per target, key by key
- Place a call - where the request comes from on each route
- Give the call its values -
call_startvariables, and--varlocally - Values the route supplies - what the runtime fills in, and which routes fill it
Declare the direction
agent.yaml
outbound: true, this target has no outbound capability at all: no
route reads a destination number for it.
Every key a channel takes
A telephony channel writes both directions, whichever one it uses.realtime_audio | telephony
required
telephony is a phone call. realtime_audio is the browser channel, and it
takes none of the keys below.true | false
required
Whether this agent answers calls.
false on an agent that only dials.true | false
required
Whether this agent places calls. It is also what a warm transfer needs, since
a warm transfer dials its destination.
list of control names
What the route has to support:
cold_transfer, warm_transfer,
dtmf_send, dtmf_receive, hold, hangup, voicemail_detection,
ivr_navigation. A route that cannot do one is refused when you validate.hangup | leave_message
What the agent does when it reaches a voicemail box. It needs
outbound: true and a route that detects voicemail, which today is LiveKit
sip.One route per target
Dialling out is the carrier’s job, so each target needs a connection that can reach your carrier account. An agent on both targets rides two different mechanisms, so it needs two connection files holding the same three names:transport:. from_number is the caller identity
the person you dial sees. Neither target says anything else about the route.
Every key a connection takes
sip | connector | cloud-websocket | daily-sip
required
The mechanism that carries the call. Every one of the four can dial out. The
target’s provider decides which of them it accepts.
twilio | telnyx | plivo
required
The carrier account that places the call. Telnyx and Plivo dial out through
the LiveKit
sip route only.route key to environment variable name
Which variable holds each of the route’s account values. Dialling out always
needs
from_number, plus either account_sid and auth_token or the SIP
trio, depending on the route. Which environment keys a route
accepts
has the set per route. The names on the right are yours, and every one is
UPPER_SNAKE.connections/<name>.yaml for the whole file.
Place a call
A phone call reaches an agent that is deployed, so placing one is the deployed platform’s job, not a local command. Compilemy-agent, deploy it
to the target’s platform, and use the Place an outbound call section of
the generated build/<target>/README.md. It prints the exact request for
your route, with the trunk, project, and agent names already filled in:
- Pipecat
cloud-websocketplaces the call with one request to Twilio’s own API, carrying markup that names the deployed agent. - Pipecat
daily-sipplaces it with one request to the Pipecat Cloud dial-out endpoint, through the trunk your carrier setup created. - LiveKit
sipand LiveKitconnectorplace it by dispatching this agent to a new room with job metadata, and the worker dials with the carrier’s trunk settings inline.
Give the call its values
An outbound call usually knows things before it starts: who is being called, about what. Declare them ascall_start variables:
agent.yaml
--var supplies them:
build/<target>/README.md prints the exact
spelling for its platform.
That is the whole relationship: --var is the local stand in for the dispatch
payload. Same names, same types, same variables.
Values are checked against the declared type, and an undeclared name is refused
rather than quietly ignored.
Every key a variable takes
type expression
required
What the value is, written as one line: a built-in such as
string, a
Literal[...] set, a list[...], or a shape you declared. The type
grammar has all of them.call_start | conversation | a system call fact
Where the value comes from.
call_start is the dispatch payload, which
--var stands in for. conversation is a value the model records mid-call.
The eight system facts are listed below. Left out, a task’s assign: fills
it.a value of the declared type
What the value is before anything supplies one. Required on a
call_start
variable when the channel is also inbound, because an inbound call carries no
dispatch payload.step name
The step that has to hear the caller agree before anything acts on this
value. Until then it renders in that step’s prompt and nowhere else. See
confirm:.string
What the value is, for a reader and for the model. Required on a
source: conversation variable, because the model reads it to know what to
record.Values the route supplies
Some variables are filled in by the runtime, not by you:to_number, from_number, direction, call_id,
stream_id, session_id, carrier, and connection. Seeding one with
--var is refused, because the runtime owns it.
Which routes supply them, and in which direction, differs per fact. Both
LiveKit routes supply every system source, on both directions. The two
Pipecat Twilio routes supply a smaller set: pipecat cloud-websocket fills
to_number on an outbound call, which is exactly the dialed_number example
above, while pipecat daily-sip supplies no to_number at all. A route that
does not grant a fact refuses the declaration at validation, rather than
leaving an empty string at call time. The full grid
in the pre-fetch reference has every fact, route and direction.
Declaring the fact as a prefetch: entry instead keeps one package compiling
on every route. Where the route supplies nothing, the entry is skipped and the
variable keeps its default, rather than the package being refused. Where it
works covers that shape, under “The number an
outbound call carries”, and what a cloud-websocket call has to carry for it
to arrive.
Where to go next
Inbound calls
Take a real call, once the route is deployed.
Get your Twilio details
Which console value fills which name.
Variables reference
Types, sources, and where each value can be used.