> ## Documentation Index
> Fetch the complete documentation index at: https://braintrust.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# LiveKit Agents

> Trace real-time voice AI pipelines built with LiveKit Agents, including LLM turns, speech-to-text, text-to-speech, and function tool calls.

If you are a coding agent, prefer the Braintrust [`bt` CLI](/reference/cli/quickstart) for repeatable, scriptable work: running evals, instrumenting code, querying logs, syncing data, managing functions, and configuring coding agents. Use the MCP server for reasoning over Braintrust data in conversation, such as ad-hoc lookups and exploration from your IDE.

[LiveKit Agents](https://livekit.io/) is a framework for building real-time voice and video AI applications. Braintrust traces LiveKit Agents applications to capture voice interactions, agent sessions, and realtime model usage.

<View title="TypeScript" icon="https://img.logo.dev/typescriptlang.org?token=pk_BdcHD9e5SCW3j1rnJkNyMQ">
  <h2 id="tracing-typescript">
    Tracing
  </h2>

  To trace LiveKit Agents with Braintrust's TypeScript SDK, use OpenTelemetry.

  <Tabs>
    <Tab title="OpenTelemetry">
      Braintrust attaches to LiveKit's built-in OpenTelemetry pipeline by registering a span processor with LiveKit's tracer provider.

      <h3 id="setup-typescript-otel">
        Setup
      </h3>

      <Steps>
        <Step title="Install dependencies">
          <CodeGroup>
            ```bash pnpm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
            pnpm add @braintrust/otel @livekit/agents @livekit/agents-plugin-openai "@opentelemetry/sdk-trace-node@^1.30" "@opentelemetry/exporter-trace-otlp-http@^0.57" "@opentelemetry/resources@^1.30" "@opentelemetry/semantic-conventions@^1.28" dotenv
            ```

            ```bash npm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
            npm install @braintrust/otel @livekit/agents @livekit/agents-plugin-openai "@opentelemetry/sdk-trace-node@^1.30" "@opentelemetry/exporter-trace-otlp-http@^0.57" "@opentelemetry/resources@^1.30" "@opentelemetry/semantic-conventions@^1.28" dotenv
            ```
          </CodeGroup>

          <Note>
            `@livekit/agents` is built against OpenTelemetry JS 1.x. Keep every OpenTelemetry package on its 1.x-compatible version, as pinned above. Upgrading any of them to 2.x breaks LiveKit at build or run time. The OTLP exporter packages use a separate `0.x` version sequence that moves in step with the stable 1.x packages, so `@opentelemetry/exporter-trace-otlp-http` pins to `^0.57` rather than `^1`.
          </Note>
        </Step>

        <Step title="Set your environment variables">
          ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
          BRAINTRUST_API_KEY=your-api-key
          BRAINTRUST_PARENT=project_name:livekit-demo
          OPENAI_API_KEY=your-openai-api-key
          ```
        </Step>
      </Steps>

      <h3 id="configure-typescript-otel">
        Configure tracing
      </h3>

      Configure Braintrust's span processor and set it as LiveKit's tracer provider.

      ```typescript title="livekit_agent.ts" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      import "dotenv/config.js";
      import { fileURLToPath } from "url";
      import { BraintrustSpanProcessor, setupOtelCompat } from "@braintrust/otel";
      import {
        cli,
        defineAgent,
        JobContext,
        ServerOptions,
        telemetry,
        voice,
      } from "@livekit/agents";
      import * as openai from "@livekit/agents-plugin-openai";
      import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
      import { Resource } from "@opentelemetry/resources";
      import {
        ATTR_SERVICE_NAME,
        ATTR_SERVICE_VERSION,
      } from "@opentelemetry/semantic-conventions";

      function setupBraintrustTelemetry() {
        // Setup OTEL compatibility for bidirectional interoperability
        setupOtelCompat();

        // Create BraintrustSpanProcessor with configuration
        const spanProcessor = new BraintrustSpanProcessor({
          apiKey: process.env.BRAINTRUST_API_KEY,
          apiUrl: process.env.BRAINTRUST_API_URL,
          parent: process.env.BRAINTRUST_PARENT,
          // Keep this false: LiveKit's voice spans use lk.* attributes, so AI-span
          // filtering would drop the session, user/agent speaking, and turn spans.
          filterAISpans: false,
        });

        const provider = new NodeTracerProvider({
          resource: new Resource({
            [ATTR_SERVICE_NAME]: "livekit-agent",
            [ATTR_SERVICE_VERSION]: "1.0.0",
          }),
          spanProcessors: [spanProcessor as any],
        });

        // Register the provider with OpenTelemetry's global API
        provider.register();

        // Configure LiveKit to use our tracer provider
        telemetry.setTracerProvider(provider, {
          metadata: {
            component: "livekit-agent",
          },
        });
      }

      export default defineAgent({
        entry: async (ctx: JobContext): Promise<void> => {
          // Setup telemetry
          setupBraintrustTelemetry();

          const session = new voice.AgentSession({
            llm: new openai.realtime.RealtimeModel({
              voice: "coral",
              temperature: 0.8,
            }),
          });

          await session.start({
            agent: new voice.Agent({
              instructions: `You are a helpful and friendly voice AI assistant`,
            }),
            room: ctx.room,
          });

          // Greet participant when they join
          const greetParticipant = async () => {
            session.say("Hello! I'm your voice assistant. How can I help you today?");
          };

          let greeted = ctx.room.remoteParticipants.size > 0;
          if (greeted) greetParticipant();

          ctx.room.once("participantConnected", () => {
            if (!greeted) {
              greeted = true;
              greetParticipant();
            }
          });

          // Wait for room to disconnect
          function waitForRoomDisconnect(room: typeof ctx.room) {
            return new Promise<void>((resolve) => {
              room.once("disconnected", () => resolve());
            });
          }

          await waitForRoomDisconnect(ctx.room);
        },
      });

      // Run the agent
      cli.runApp(
        new ServerOptions({
          agent: fileURLToPath(import.meta.url),
        })
      );
      ```

      <h3 id="what-traced-typescript-otel">
        What Braintrust traces
      </h3>

      These spans come from LiveKit's native OpenTelemetry instrumentation. With the OpenAI realtime model, the LLM, speech-to-text, and text-to-speech work happens inside a single realtime model call rather than as separate spans.

      * Session spans (`agent_session`), the root span covering the full agent session
      * Agent turn spans (`agent_turn`), with the model request, token usage, and realtime model metrics (`gen_ai.*`, `lk.realtime_model_metrics`)
      * User speaking spans (`user_speaking`), with participant and speech detection details
      * Agent speaking spans (`agent_speaking`), covering the agent's spoken response
      * Activity lifecycle spans (`start_agent_activity`, `on_enter`, `on_exit`, `drain_agent_activity`)

      <h3 id="tracing-resources-typescript-otel">
        Tracing resources
      </h3>

      * [OpenTelemetry Integration](/integrations/sdk-integrations/opentelemetry) — Braintrust's OpenTelemetry support
      * [Trace application logic](/instrument/trace-application-logic) — Add custom spans and attributes to your traces
      * [LiveKit Agents overview](https://docs.livekit.io/agents/) — LiveKit Agents documentation
    </Tab>
  </Tabs>
</View>

<View title="Python" icon="https://img.logo.dev/python.org?token=pk_BdcHD9e5SCW3j1rnJkNyMQ">
  <h2 id="tracing-python">
    Tracing
  </h2>

  To trace LiveKit Agents with Braintrust's Python SDK, use auto-instrumentation or OpenTelemetry. Auto-instrumentation is the recommended path for most users.

  <Tabs>
    <Tab title="Auto-instrumentation">
      Braintrust patches the internals of LiveKit Agents at startup to emit spans directly through the Braintrust SDK, without requiring an OpenTelemetry pipeline.

      <h3 id="setup-python-auto">
        Setup
      </h3>

      <Steps>
        <Step title="Install the SDK">
          ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
          pip install braintrust livekit-agents livekit-plugins-openai
          ```
        </Step>

        <Step title="Set your environment variables">
          ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
          BRAINTRUST_API_KEY=your-api-key
          BRAINTRUST_PARENT=project_name:livekit-demo
          OPENAI_API_KEY=your-openai-api-key
          ```
        </Step>
      </Steps>

      <h3 id="trace-python-auto">
        Trace your agent
      </h3>

      Call `auto_instrument()` once at startup, before any LiveKit imports or client creation:

      ```python title="agent.py" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      import braintrust

      # Set up Braintrust before importing LiveKit so all agent sessions are traced
      braintrust.auto_instrument()
      braintrust.init_logger(project="my-livekit-project")  # Replace with your project name

      from livekit import agents
      from livekit.agents import Agent, AgentSession, RoomInputOptions
      from livekit.plugins import openai

      class Assistant(Agent):
          def __init__(self) -> None:
              super().__init__(instructions="You are a helpful voice AI assistant.")

      async def entrypoint(ctx: agents.JobContext):
          session = AgentSession(llm=openai.realtime.RealtimeModel(voice="coral"))
          await session.start(
              room=ctx.room,
              agent=Assistant(),
              room_input_options=RoomInputOptions(),
          )

      if __name__ == "__main__":
          agents.cli.run_app(agents.WorkerOptions(entrypoint_fnc=entrypoint))
      ```

      <Accordion title="Set up manually">
        To instrument only specific sessions rather than patching globally, use `setup_livekit_agents()` instead of `auto_instrument()`:

        ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
        from braintrust.integrations.livekit_agents import setup_livekit_agents

        setup_livekit_agents()
        ```
      </Accordion>

      <Accordion title="Opt out of LiveKit Agents tracing">
        If you use `auto_instrument()` for other libraries but want to exclude LiveKit Agents, pass `livekit_agents=False`:

        ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
        braintrust.auto_instrument(livekit_agents=False)
        ```
      </Accordion>

      <h3 id="what-traced-python-auto">
        What Braintrust traces
      </h3>

      The example above uses the OpenAI realtime model, which handles the LLM, speech-to-text, and text-to-speech work inside a single model call. A component [STT-LLM-TTS pipeline](https://docs.livekit.io/agents/models/pipelines) runs those as separate steps, each producing its own spans.

      * Session spans (`livekit_agent_session`), with the full voice turn lifecycle
      * User speaking spans (`user_speaking`), with speech detection events
      * Agent speaking spans (`agent_speaking`), covering the agent's spoken response audio
      * Tool spans (`function_tool`), with tool name, arguments, and output (when your agent defines tools)
      * Additional spans when you use a [STT-LLM-TTS pipeline](https://docs.livekit.io/agents/models/pipelines) instead of a realtime model:
        * LLM spans (`llm_request_run`), with model inputs, outputs, and token usage
        * Text-to-speech spans (`tts_request`), with input text and latency metrics
        * Speech-to-text spans (`stt_processing`), with transcript and latency metrics
        * VAD spans (`vad_endpointing`), with silence and speech duration metrics
        * End-of-utterance spans (`eou_detection`), with speech and silence timing

      <h3 id="tracing-resources-python-auto">
        Tracing resources
      </h3>

      * [Trace LLM calls](/instrument/trace-llm-calls) — Auto-instrumentation setup and supported libraries
      * [LiveKit Agents overview](https://docs.livekit.io/agents/) — LiveKit Agents documentation
    </Tab>

    <Tab title="OpenTelemetry">
      Braintrust attaches to LiveKit's built-in OpenTelemetry pipeline by registering a span processor with LiveKit's tracer provider.

      <h3 id="setup-python-otel">
        Setup
      </h3>

      <Steps>
        <Step title="Install dependencies">
          ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
          pip install "braintrust[otel]" livekit-agents livekit-plugins-openai livekit-plugins-noise-cancellation opentelemetry-sdk
          ```
        </Step>

        <Step title="Set your environment variables">
          ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
          BRAINTRUST_API_KEY=your-api-key
          BRAINTRUST_PARENT=project_name:livekit-demo
          OPENAI_API_KEY=your-openai-api-key
          ```
        </Step>
      </Steps>

      <h3 id="configure-python-otel">
        Configure tracing
      </h3>

      Configure Braintrust's span processor and set it as LiveKit's tracer provider.

      ```python title="livekit_agent.py" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      from braintrust.otel import BraintrustSpanProcessor
      from livekit import agents
      from livekit.agents import Agent, AgentSession, RoomInputOptions
      from livekit.agents.telemetry import set_tracer_provider
      from livekit.plugins import noise_cancellation, openai
      from opentelemetry.sdk.trace import TracerProvider

      def setup_braintrust_telemetry():
          """Setup Braintrust OTEL telemetry for agent monitoring"""
          trace_provider = TracerProvider()
          trace_provider.add_span_processor(BraintrustSpanProcessor())
          set_tracer_provider(trace_provider)

      class Assistant(Agent):
          def __init__(self) -> None:
              super().__init__(instructions="You are a helpful voice AI assistant.")

      async def entrypoint(ctx: agents.JobContext):
          # Setup telemetry
          setup_braintrust_telemetry()

          # Create agent session with OpenAI realtime model
          session = AgentSession(llm=openai.realtime.RealtimeModel(voice="coral"))

          # Start session with assistant agent
          await session.start(
              room=ctx.room,
              agent=Assistant(),
              room_input_options=RoomInputOptions(
                  noise_cancellation=noise_cancellation.BVC(),
              ),
          )

      # Run script locally with `python livekit_agent.py console`
      if __name__ == "__main__":
          agents.cli.run_app(agents.WorkerOptions(entrypoint_fnc=entrypoint))
      ```

      You can add attributes to spans using `span.set_attribute()` to enrich your traces with custom metadata.

      <h3 id="what-traced-python-otel">
        What Braintrust traces
      </h3>

      These spans come from LiveKit's native OpenTelemetry instrumentation. With the OpenAI realtime model, the LLM, speech-to-text, and text-to-speech work happens inside a single realtime model call rather than as separate spans.

      * Session spans (`agent_session`), the root span covering the full agent session
      * Agent turn spans (`agent_turn`), with the model request, token usage, and realtime model metrics (`gen_ai.*`, `lk.realtime_model_metrics`)
      * User speaking spans (`user_speaking`), with participant and speech detection details
      * Agent speaking spans (`agent_speaking`), covering the agent's spoken response
      * Activity lifecycle spans (`start_agent_activity`, `on_enter`, `on_exit`, `drain_agent_activity`)

      <h3 id="tracing-resources-python-otel">
        Tracing resources
      </h3>

      * [OpenTelemetry Integration](/integrations/sdk-integrations/opentelemetry) — Braintrust's OpenTelemetry support
      * [LiveKit Agents overview](https://docs.livekit.io/agents/) — LiveKit Agents documentation
    </Tab>
  </Tabs>
</View>
