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.
Quickstart
Install agent-observability-sdk (Node) and point your agent at the dashboard. Covers the agent-transport path (observability auto-emits) and where to go for raw LiveKit workers.
Vitest reporter
Stream Vitest eval results into the dashboard. Every vitest run becomes one eval_run; every it(...) becomes an eval_case with events, judgments, and failure detail.