Uses
tuner-core plus one observer per role in your pipeline. Not on Python? See Direct API.Prerequisites
- Tuner Active Account
- Configured Agent with provider “Custom API” in Tuner
- Python ≥ 3.10 and a custom voice stack you control
The mental model
1
Create one TunerSession per call
tuner-core is the backbone. The session holds your call’s identity — call_id, workspace, and agent mapping — and coordinates everything else.2
Attach one observer per role
STT, LLM, and TTS each have their own package. Attach only the roles your stack has; each is independent.
3
flush() at call end
The session assembles what the observers captured into a single timeline and sends it to Tuner via the Create Call API. One network call, at the end.
Step 1: Install
tuner-core provides TunerSession and TunerConfig. Provider SDKs sit behind extras so you only pull in what you use. Other combinations are in Mix and match below.
Step 2: Set your credentials
TunerConfig.from_env() reads these from the environment:
Step 3: Create a session per call
OneTunerSession at the start of each call. The model names are used for cost calculation. Keep call_id stable across retries so ingestion stays idempotent.
TunerConfig.from_env() also takes extra_metadata={...} to attach arbitrary key-value data to the call record, and sip_call_id=... to link a simulated call back to its simulation run — see Simulation SIP setup.
Step 4: Attach observers
STT — Deepgram
LiveOptions must set utterance_end_ms and vad_events=True, or you’ll see calls with no user turns. Speechmatics, custom providers, and what each adapter captures: Speech-to-Text.
LLM — LangGraph
TTS — Cartesia
Step 5: Flush at call end
flush() is the only network call the libraries make. Put it in a finally block so the call reaches Tuner even when the connection drops or your loop raises:
Mix and match
Missing an adapter for one of your providers? Extend the base adapter for that role — see Custom providers on the Speech-to-Text and Text-to-Speech pages.
Troubleshooting
Calls don't appear in Tuner
Calls don't appear in Tuner
- Verify
TUNER_AGENT_IDis the Agent Remote ID from Agent Settings → Agent Connection. - Confirm
TUNER_WORKSPACE_IDis correct. - Confirm
session.flush()actually ran — put it in afinallyblock so exceptions don’t skip it.
What’s next?
Speech-to-Text
Deepgram and Speechmatics adapters, options, custom providers.
Text-to-Speech
Cartesia over WebSocket or SSE, word-level interruption capture.
LangChain / LangGraph
Node transitions, tool calls, and LLM latency in your timeline.
Review your first call
What Tuner does with the data once it lands.