LiveKit
Is Parlot a fit for your LiveKit Agents? What you get, how instrumentation works, and how to add it.
You already ship LiveKit Agents. Parlot’s MIT parlotize()
adds session debugging beside your agent: turns, handoffs, latency, and audio evidence for each
call.
Install and env setup: Quick Start. Shared product model: Concepts.
What you get in Parlot
- Session + transcript — who said what, turn timeline, close reason
- Multi-agent handoffs / agent chain — routing across agents in one call
- Pipeline waterfall (Timeline stage chart) — large language model (LLM), text-to-speech (TTS), tools, and speech-to-text (STT) timing when LiveKit pipeline spans are present
- Usage — tokens, tool counts
- Session audio — LiveKit Room Composite recording → replay when you open the session
- Export per session — download transcript + recording (and optionally traces / logs / metadata) from the session UI for compliance, reviews, or offline analysis
- Same debugger if you nest LangGraph — see the LangGraph guide
How instrumentation works
Two layers feed Parlot:
- Events (semantic) — AgentSession events commit the conversation. When the agent
transitions
initializing → listening(agent_state_changed), Parlot creates oneparlot.session. Committed messages becomeparlot.turn/ handoffs;closeends with a normalized close reason. This is the episode record (transcript, usage, handoffs), with or without pipeline spans. - OpenTelemetry spans (pipeline) — LiveKit’s internal spans (
llm_*,tts_*,function_tool,realtime_inference, …) are enriched, renamed to the shared GenAI / voice vocabulary, and stripped oflk.*keys before OpenTelemetry Protocol (OTLP) export. Native turn spans contribute latency ontoparlot.turn, then are dropped from export. Pipeline spans unlock the Timeline waterfall and turn latency histograms.
With LiveKit Agents 1.8+, LiveKit
stamps OpenTelemetry GenAI attributes on those spans (gen_ai.input.messages,
gen_ai.output.messages, gen_ai.system_instructions, canonical
gen_ai.provider.name values such as openai / aws.bedrock / gcp.gen_ai). Parlot prefers
those attributes when present, maps utterance text onto the conversation contract
(turn.user_text / turn.agent_text), and keeps Agents 1.7 lk.pii.* (and legacy lk.*)
readers as a fallback. Cached prompt tokens use gen_ai.usage.cache_read.input_tokens (or
gen_ai.usage.input_cached_tokens); that count is a subset of gen_ai.usage.input_tokens —
do not add the two. Realtime model turns export as chat {model} with
gen_ai.operation.name=generate_content.
Recording is a separate path: after the session starts, the agent requests an upload grant
and starts Room Composite egress (audio-only Ogg Vorbis). Session telemetry is sent on its own;
opening the session in Parlot confirms the audio object and sets audio_available.
Shared span layers, identity, errors, and capture policies: Concepts.
Examples under examples/livekit/ target livekit-agents>=1.8; the instrumentation package
requires livekit-agents>=1.7.
Add it to an existing agent
Two required steps for full behavior:
- Call
parlotize("…")before constructingAgentSession. - Call
await ctx.connect()beforesession.start().
from parlot.instrumentation.livekit import parlotize
parlotize("my-agent", version="0.1.0")
from livekit.agents import AgentSession, JobContext
async def entrypoint(ctx: JobContext):
await ctx.connect()
session = AgentSession(...)
await session.start(agent=..., room=ctx.room)parlotize() registers an OTLP TracerProvider with livekit.agents.telemetry, installs
AgentSession event hooks, and (when recording is enabled) starts Room Composite recording after
the session starts. Pass a stable deployment id; use version= for a real deployment label
(otherwise Parlot stamps "unknown").
If you need the first agent greeting on the session recording, pass await_recording=True
(with await ctx.connect() before session.start()). That waits for recording to start before
connect returns and may add a little latency; leave it off for the lowest time-to-first-speech.
parlotize("my-agent", version="0.1.0", await_recording=True)Environment: PARLOT_ENDPOINT, PARLOT_API_KEY — see Environment Variables.
Recording, session logs, and generative AI content capture are on by default for new tenants;
configure in Settings or via parlotize(...) kwargs — see
Concepts → Recording vs telemetry. LiveKit
recording also needs agent LIVEKIT_* credentials with roomRecord.
parlotize() options: Interactive API Reference
(LiveKit-only kwargs include record, await_recording, auto_escalate_sip, …). Package
overview: Python SDK Reference.
Named worker dispatch (agent_name)
LiveKit’s agent_name (which jobs are eligible for which rooms) is separate from Parlot’s
parlotize("…") / session.agent_id (canonical product identity on telemetry).
Prefer an explicit name on the RTC session entrypoint:
from livekit.agents import AgentServer, JobContext
server = AgentServer()
@server.rtc_session(agent_name="healthcare")
async def entrypoint(ctx: JobContext):
await ctx.connect()
...Give the worker an explicit name so only matching rooms get this agent. Paths such as LiveKit
WarmTransferTask open a second room for briefing; an unnamed worker can be auto-dispatched
there and create a second Parlot session for the same caller journey. Keep playground,
Session Initiation Protocol (SIP) dispatch rules, and lk dispatch aligned with the same name.
See the healthcare example
for a full WarmTransferTask setup.
Human escalation
Semantics and role vocabulary live in Concepts → Human escalation. Import helpers from the LiveKit package:
from parlot.instrumentation.livekit import record_human_rep, human_escalation
record_human_rep("support_rep_jane", label="Jane")
# Or wrap a dial / transfer:
# with human_escalation(label="L2 Support Queue"):
# await session.dial(sip_uri)For SIP warm transfer auto-detect, set parlotize("my-agent", auto_escalate_sip=True) and a
named agent_name so the briefing room stays on one Parlot session. Or match participant
metadata with escalation_metadata_match={...}.
Next
- Quick Start
- Concepts
- Examples:
examples/livekit/ - Python SDK Reference · Interactive API Reference
- Nesting LangGraph inside a voice agent? LangGraph guide
