Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.usetuner.ai/llms.txt

Use this file to discover all available pages before exploring further.

For an overview of how simulation works, see Introduction to Call Simulation.

How it works

Tuner Simulation (SIP)

    │  SIP INVITE

LiveKit SIP gateway  (your project's sip.livekit.cloud endpoint)

    │  Dispatch rule → creates room, dispatches agent worker

Your agent  (joins room, answers the call)


Tuner LiveKit SDK  (captures transcript, tool calls, latency, cost)
Tuner places the call into your LiveKit SIP inbound trunk. A dispatch rule routes the call into a new room and dispatches your registered agent worker. Your agent’s TunerPlugin then syncs the session back to Tuner, correlated to the simulation by sip.callIDFull.

Prerequisites

  • A LiveKit Cloud project with SIP enabled
  • An agent already integrated with Tuner via the LiveKit SDK
  • tuner-livekit-sdk v0.15 or higher — earlier versions don’t support SIP correlation
  • The agent running with a registered agent_name (see Step 2)
  • LIVEKIT_URL, LIVEKIT_API_KEY, and LIVEKIT_API_SECRET available in your environment

Step 1: Find your SIP gateway URI

In LiveKit Cloud → your project → Telephony → SIP trunks, copy the SIP URI shown at the top of the page. It will look like:
sip:XXXXXXXX.sip.livekit.cloud
Locating your project's SIP URI in the LiveKit SIP trunks page You’ll need the host portion (XXXXXXXX.sip.livekit.cloud) in the next steps.

Step 2: Create an inbound trunk and dispatch rule

You can do this through the LiveKit Cloud UI or by running the provided setup script — both produce the same result. Pick whichever fits your workflow.

Create the inbound trunk

  1. Go to Telephony → SIP trunks → Create new trunk.
  2. Set Trunk direction to Inbound.
  3. Fill in:
    • Trunk name — e.g. tunerTrunk
    • Numbers — leave empty to accept calls for any number, or list specific numbers
    • Allowed addresses0.0.0.0/0 to accept all callers
    Creating a LiveKit inbound SIP trunk
  4. Switch to the JSON editor tab and add authUsername and authPassword fields with values of your choice. This step is required — Tuner uses these credentials to authenticate when placing simulated calls into your trunk, and you’ll enter them in Tuner in Step 4.
    {
      "name": "tunerTrunk",
      "allowedAddresses": [
        "0.0.0.0/0"
      ],
      "authUsername": "<your-username>",
      "authPassword": "<your-password>"
    }
    
    Adding authUsername and authPassword in the JSON editor tab
  5. Click Create.

Create the dispatch rule

  1. Go to Telephony → Dispatch rules → Create new dispatch rule.
  2. Fill in:
    • Rule name — e.g. tunerRule
    • Rule typeIndividual
    • Room prefix — e.g. tuner- (each call gets its own room with this prefix)
  3. Under Agent dispatch, set Agent name to exactly match the agent_name your worker registers with. Without this, the room is created but no worker is dispatched and the call rings until it times out with a 408.
  4. Under Inbound routing → Trunks, select the trunk you created in the previous step.
  5. Click Create. Creating a LiveKit dispatch rule with agent dispatch and trunk selection
Once you’ve created both resources, head back to Telephony → Dispatch rules to confirm the rule appears and shows your agent in the Agents column. If the column is empty, the rule won’t dispatch your worker and calls will time out. The dispatch rules page once your rule is in place

Step 3: Wire SIP correlation into your agent

To connect a simulated call to the corresponding session synced from your agent, Tuner uses sip.callIDFull as a correlation key. LiveKit attaches this value as a participant attribute on the SIP participant, so it can be read directly from the room state — no additional infrastructure required.

Move ctx.connect() to the top of your entrypoint

The SIP participant only becomes visible after the agent joins the room. Call ctx.connect() first, then read the correlation ID, then pass it to TunerPlugin:
async def entrypoint(ctx: JobContext):
    # 1. Connect to the room FIRST so SIP participants are reachable
    await ctx.connect()

    # 2. Extract the SIP correlation ID from the room's remote participants
    sip_correlation_id = _extract_sip_correlation_id(ctx)

    session = AgentSession(...)

    TunerPlugin(
        session,
        ctx,
        sip_correlation_id=sip_correlation_id,
        # ... your other TunerPlugin options
    )

    await session.start(...)
If ctx.connect() runs after you try to read participants, ctx.room.remote_participants will be empty and sip_correlation_id will be None. Simulated calls will still complete, but they won’t be correlated to their Tuner sessions.

Helper: extract the SIP correlation ID

Add this helper to your entrypoint module. It scans the room’s remote participants for the SIP participant and returns its sip.callIDFull attribute.
from livekit import rtc
from livekit.agents import JobContext


def _extract_sip_correlation_id(ctx: JobContext) -> str | None:
    for participant in ctx.room.remote_participants.values():
        if participant.kind != rtc.ParticipantKind.PARTICIPANT_KIND_SIP:
            continue
        attributes = dict(getattr(participant, "attributes", {}) or {})
        sip_call_id_full = attributes.get("sip.callIDFull")
        if isinstance(sip_call_id_full, str) and sip_call_id_full:
            return sip_call_id_full
        return None
    return None
For web calls (no SIP participant), this returns None and TunerPlugin falls back to its normal behaviour.

Step 4: Configure SIP in Tuner

With the inbound trunk and dispatch rule in place, go to Agent Settings → SIP Settings in your Tuner dashboard and enter the credentials you just created:
  • SIP URI — your project’s SIP gateway URI from Step 1 (e.g. sip:XXXXXXXX.sip.livekit.cloud)
  • Username — the authUsername you set on the inbound trunk
  • Password — the authPassword you set on the inbound trunk
Click Test Connection, then Save. A Verified badge appears next to the SIP URI once the connection succeeds. SIP configuration in Tuner

Step 5: Run your first simulation

  1. In Tuner, open Simulations in the sidebar.
  2. Click Run Simulation.
  3. Confirm the SIP target points to your LiveKit agent.
  4. Set the number of calls (5–20).
  5. Adjust the simulation mix (routine vs. pressure).
  6. Click Run.
Configure and launch your simulation Results appear in the Simulations table once calls complete. Click any row for the transcript, latency breakdown, and evaluation results.

Troubleshooting

SymptomCauseFix
Call rings, then 408 timeoutINVITE reaches LiveKit but no agent answersDispatch rule missing agent_name, or it doesn’t match the name your worker registers with. Confirm both match exactly.
Call never connectsINVITE not reaching the right SIP gatewayVerify the SIP URI host matches your project’s gateway under Telephony → SIP trunks.
Authentication rejectedWrong credentials in Tunerauth_username / auth_password in Tuner must match what you set on the inbound trunk.
Calls connect but aren’t correlatedsip_correlation_id is NoneMake sure ctx.connect() runs before _extract_sip_correlation_id(ctx), and that you’re on tuner-livekit-sdk >= 0.15.
”Unverified” in TunerWrong SIP URI or credentialsRe-enter and click Test Connection again. Check for trailing spaces in the URI or password fields.