version: 2 compiles a package onto unmute-core, the library that holds the
voice-agent behaviour LiveKit and Pipecat share. The model picks what to do. Code says
the lines that must be exact: read-backs, offers and receipts.
Every key of version 1 keeps its name and spelling. This page
lists what version 2 adds, what it reads differently, and what it does not compile yet.
How a package compiles
- You write
agent.yaml, aStateclass instate.py, and typed tool handlers. unmute compilewritesagent.json, the package’s data in the library’s own names.spec.pybuilds the library’s objects fromagent.jsonwhen the agent starts. A broken package fails then, never during a call.agent.py(LiveKit) orbot.py(Pipecat) builds the pipeline around them.speech.pyholds any speech model that is not SLNG’s.
Tools
A local tool names its Python function. Its input and output types come from the function’s signature, so a local tool file has noinput: or output:.
tools/find_slots.yaml
string
file.py:function. Its signature is the tool’s input, its return type the output.list of key: path
State values the result saves, on any result.
+ appends, ? allows absent.list of when and say
Lines code says when the result matches
when. A field matches any value listed.string
file.py:function run first. It returns an outcome to refuse, or None to go on.Result fields the model never reads. Code can still save and say them.
boolean
Run the tool once its
announce: line has played, like a goodbye before hanging up.input: and output: as JSON Schema, and takes no replies: or
precheck:. Its URL is the url_env variable plus path. A knowledge tool and the
end_call builtin work as in version 1.
Lines read only State
Every line code speaks, and every prompt, reads State:{{state.x}} and
{{state.x.y}}, plus {{call.x}} for what the call carries. A line never reads
{{input.x}} or {{result.x}}. Save the value to State first, and the compiler
rewrites the line to read it where it comes from.
Steps
agent.yaml
list of string
Code reads the change back. The tool runs on the caller’s yes.
list of string
Code says it when the tool succeeds, and the step ends.
list of when and say
Lines code says for a step tool’s result, before the tool’s own.
tool, arguments and say
A tool code runs as the step opens, with State values, and its
say:.listen
The step waits for the caller instead of asking a model first.
key: input.path
Saves the closing tool’s input, so a read-back can say it.
list of string
Handoff tools the step offers too.
arguments:, State values the agent passes as it starts the
group. mode: record makes each step save what the caller confirmed.
Other keys
value and agents
Starts the call on the agent a State value names, read after the prefetch.
string
Refuses the call when that lookup finds nothing, with this line.
list of key: value
State values the handoff sets as the call moves.
tool and arguments
A tool of the next agent’s, run in code as it takes the call.
agent.yaml
language:, and its timezone is the clock
prefetch’s timezone:. Code says dates in them.
Models
escalations: transfer the caller on a phone line. A browser session needs no phone
route variable to start. tracing: compiles langfuse.
Twilio and SLNG read version 2
Thetwilio and slng targets read version: 2 too, but they run it with their own
runtimes and without unmute-core. They refuse these keys at compile time, and the error
says to remove them or compile to livekit or pipecat:
- tool file keys
assign,replies,precheck,hiddenandannounce_wait; - a task’s
repliesandopens_with, and a taskfinishrule withconfirm; entry_by;- prefetch
refuse_call; - a handoff’s
savesoropens_with.
finish rule with say is refused on Twilio only. SLNG speaks the line itself.
Each target refuses more of its own: see Twilio
and SLNG.
Not compiled yet
Test a package
A package with ascenarios/ folder runs whole calls on the real model:
examples/salon-concierge
for every key on this page in one agent.