Agent Observability
SDKsNode

Raw LiveKit

Instrument a raw-LiveKit Node worker. initObservability emits the tag bundle the server expects so session reports are parented correctly on the dashboard.

agent-transport's AudioStreamServer wires observability internally. When you drive LiveKit Agents directly with server.rtcSession(...), call initObservability to emit the tag bundle (agentId, accountId, agentName, transport) the server's ingest path expects.

Minimal worker

import { initObservability } from "agent-observability-sdk/livekit";
import { AgentServer } from "@livekit/agents";

const server = new AgentServer();

server.rtcSession({ agentName: "support-bot" }, async (ctx) => {
  initObservability(ctx.tagger, {
    agentId: "9c2f7e3d-…",
    agentName: "support-bot",
    accountId: "acct-7",
    transport: "text",
    goals: [
      { name: "identity-check", description: "Confirm the caller's identity before account changes" },
      { name: "order-resolution", description: "Resolve the order issue or open a support ticket" },
    ],
  });
  // …your usual AgentSession.start(...) wiring
});

Conversation goals

The goals option declares task outcomes the server's goal analyzer judges after each session — no judging code in the agent, just data. Each entry is a { name, description } object — both fields required:

initObservability(ctx.tagger, {
  agentId: "9c2f7e3d-…",
  goals: [
    // name + description — the description is what the LLM judge evaluates
    { name: "identity-check", description: "Confirm the caller's identity before account changes" },
    // descriptions may contain colons; names may not
    { name: "escalation-policy", description: "Escalate only after: two failed resolution attempts" },
  ],
});

A bad goal throws before any tag is emitted:

  • names are the goal's stable identity — non-empty, unique within the call, and colon-free (the wire format goal:<name>:<description> splits at the first colon).
  • descriptions are required free text. Phrase them as observable conversation behavior — the judge only sees the transcript (guidance).

Verdicts (met/unmet, reasoning, what went wrong) land on the agent's Conversation Goals tab once the server has OPENAI_API_KEY set.

Running on agent-transport (bootstrap wired internally)? Call addGoalTags(tagger, goals) instead — same goal validation, no second bootstrap, no upload-URL check.

URL resolution

initObservability throws if LIVEKIT_OBSERVABILITY_URL (or the fallback AGENT_OBSERVABILITY_URL) is unset — there's no point continuing if the session report has nowhere to go. Use ensureObservabilityUrl() directly for a non-fatal, warn-only contract.

No judges yet

Unlike the Python SDK, the Node SDK ships no judges — LiveKit Node Agents 1.3.0 has no Judge API. End-of-call judging lands on the Node side once LiveKit catches up. Run judges from your test suite via the Vitest reporter in the meantime.

On this page