Get Started

Concepts

What Parlot instruments and how sessions, turns, and agents relate.

Why Parlot

Parlot treats production voice agents as event systems first and traces second. OpenTelemetry spans are the durable audit log. The platform turns those spans into sessions, turns, interaction graphs, and goal evaluations.

Packages

PackageRole
parlot-coreSemantic conventions (GenAI v1.41 + Conversation Contract + voice), base processor, shared provider helpers
parlot-instrumentation-livekitLiveKit Agents OTel instrumentation, egress hooks, platform refs
parlot-instrumentation-langgraphLangGraph / LangChain parlotize() via global callbacks

Contract helpers (record_human_rep, set_session_metadata, add_platform_ref, …) live in parlot.core. Framework packages re-export them for convenience — prefer those re-exports in agent code. See the Python API Reference and Interactive API Docs.

Shared span vocabulary

All adapters export the same three layers:

  1. Conversation Contractparlot.session, parlot.turn, parlot.session.close, parlot.agent.handoff
  2. OTel GenAI (semconv v1.41.0) — invoke_agent, chat, execute_tool {name}, invoke_workflow
  3. Voicetts, stt, eou_detection, amd

Vendor span and attribute maps live in each framework guide. See LangGraph and LiveKit.

Session and agent identity

  • A session is one bounded interaction (a call / job).
  • Today LiveKit voice sets conversation_id equal to session_id (1:1) as a placeholder until multi-session conversations are modeled.
  • parlotize("…", version=...) stamps deployment identity used by the Parlot Agents portfolio. agent_id is required.
  • Version: pass parlotize(version=...); if omitted, gen_ai.agent.version is "unknown".

Parlot stamps framework-agnostic session attributes on parlot.session:

AttributeMeaning
session.agent_idCanonical deployment identity
session.agent_frameworkAdapter name (e.g. "livekit")
session.agent_framework_raw_idVendor job / run id
session.agent_chainDeployment id plus runtime routing
gen_ai.agent.versionAgent deployment version

Each framework guide documents how those attributes are sourced from the vendor runtime.

Recording vs telemetry

  • Telemetry (turns, handoffs, close, usage) always goes over OTLP to PARLOT_ENDPOINT.
  • Audio recording is framework-specific and on by default for new tenants (Settings → Recording allowlist *). On LiveKit it uses Room Composite Egress to R2; opening the session confirms upload via R2 HEAD reconcile. Telemetry does not depend on recording confirmation. Clear the allowlist or use parlotize(record=False) to disable.
  • Application logs (Python logging only — not print()) are captured on by default during an active session and shown on the session Logs tab. They export as OTLP Logs (POST /v1/logs, protobuf) with session.id on each record. Policy mirrors recording (Settings → Logs + parlotize(capture_logs=…); fallback on). Treat log content like stdout for PII.
  • Generative AI content (LLM/tool bodies) is a separate policy — see Generative AI content capture.

See the LiveKit guide for egress, policy, and troubleshooting.

Generative AI content capture

GenAI here means generative AI in general (any LLM/tool stack), not a specific vendor.

This policy is shared across adapters (LiveKit, LangGraph, and future frameworks). It controls whether message bodies and tool request/response payloads are attached to GenAI spans.

ModeBehavior
On (default)Emit generative AI message event bodies and tool input/output payloads
OffOmit those bodies; still emit span structure, timings, token/usage metrics, tool names/error flags, and contract turn text (turn.user_text / turn.agent_text)

Not in scope: audio recording, session application logs, or instruction excerpts.

Precedence (same ladder as recording/logs; fallback is on):

job metadata capture_genai_contentparlotize(capture_genai_content=…) → Settings → Generative AI (bootstrap) → on

  • UI: Parlot → Settings → Generative AI / agent Settings tab — globs (default *) and per-agent toggles. Empty globs turns capture off org-wide for new agents.
  • Code: parlotize(capture_genai_content=True|False) overrides bootstrap for the process.
  • Dispatch: job metadata { "capture_genai_content": true|false } (where the framework supports job metadata).

Resolved at span emit time from bootstrap so per-agent Settings toggles apply; restart is not required for new jobs after Settings changes (already-running processes keep their bootstrap cache until restart).

Human escalation

Human takeover (SIP bridge, warm transfer, supervisor barge-in) is not the same as AI sub-agent routing. Internal AI handoffs use normal sub-agents and do not mark a session escalated. Human escalation must be signaled explicitly.

When a live rep takes over, register them as a human_rep participant. Parlot marks the session as escalated and renders human_rep as a distinct participant in the interaction graph.

SignalWhen to use
record_human_rep(participant_id)Explicit call when you know the rep identity
human_escalation() context managerWrap a dial/transfer so the next participant who joins is stamped automatically

agent.transfer.reason=human_escalation on handoff spans is an optional analytics signal for why a transfer happened. It is not used for escalation detection today.

Role vocabulary

turn.participant_roleMeaning
userCaller / end user
agentAI worker
human_repLive human who took over the session

Explicit call

from parlot.core import record_human_rep

# Or: from parlot.instrumentation.livekit import record_human_rep
record_human_rep("support_rep_jane", label="Jane")

This stamps the rep on the live session (works even if the rep never speaks) and registers the participant so future turns use turn.participant_role=human_rep.

Framework adapters may add auto-detect paths (for example LiveKit SIP warm transfer). See LiveKit → Human escalation.

Custom metadata and external references

Use these helpers to attach your own data to a live Parlot session.

Custom session metadata

set_session_metadata stamps key/value pairs under the reserved session.metadata.* namespace. Values appear on the session in Parlot (Overview → Custom metadata).

from parlot.core import set_session_metadata

# Or: from parlot.instrumentation.livekit import set_session_metadata
set_session_metadata(order_id="12345", crm_ticket="TKT-9")

Notes:

  • Call after the session has started. Values set with no active session are ignored.
  • Keys are normalized to session.metadata.<name> (do not invent a different prefix).
  • Values are stored as strings. Prefer short identifiers and labels; avoid transcripts or PII that should stay out of session attributes.
  • Turn-level custom metadata is not supported yet.

For a single key:

from parlot.core import set_session_attribute

set_session_attribute("retry_count", 2)

External references (searchable IDs)

add_platform_ref attaches a searchable external ID to the session (for example a CRM ticket or your own call ID). Paste that value into Parlot session search / resolve to open the matching session.

from parlot.core import add_platform_ref

# Or: from parlot.instrumentation.livekit import add_platform_ref
add_platform_ref("crm_ticket", "TKT-9")

Framework adapters stamp their own room / job IDs as platform.ref.* during session bootstrap. Use add_platform_ref for your own identifiers. Optional framework= defaults to "custom":

add_platform_ref("order_id", "ORD-100", framework="shopify")

Errors in the session waterfall

Failed LLM and tool work is surfaced in spans_agent.error_flag at ingest. Turn-level has_error in session detail is derived at query time: any child operational span under that turn’s trace_id with error_flag = true.

You do not need a separate turn attribute — fix provider credentials or tool logic locally; Parlot shows the failed span in the waterfall once OTLP reaches the collector. Framework guides document which vendor signals map into error_flag.

On this page