otel-livekit-style

LiveKit Agents OpenTelemetry style: entrypoint/session lifecycle spans, shutdown callbacks, session metrics, and LLM turn token counters.

Skill file

Preview skill file
---
name: otel-livekit-style
description: "LiveKit Agents OpenTelemetry style: entrypoint/session lifecycle spans, shutdown callbacks, session metrics, and LLM turn token counters."
---

# OTel LiveKit Style

LiveKit session lifecycle begins in `entrypoint(ctx)` and cleanup ends in
`ctx.add_shutdown_callback(on_shutdown)`.

## Whole-Session Span

It is okay for a `voice.session` span to end in `on_shutdown`, because the
operation crosses a framework callback boundary. Make it active while child
work is registered and started.

```python
async def entrypoint(ctx: agents.JobContext) -> None:
    await ctx.connect()
    started_at = asyncio.get_running_loop().time()
    session_span = tracer.start_span(
        "voice.session",
        attributes={
            "tenant.id": tenant_id,
            "user.id": user_id,
            "voice.room_name": room_name,
        },
    )

    with trace.use_span(session_span, end_on_exit=False):
        voice_sessions_started.add(1, {
            "tenant.id": tenant_id,
            "voice.room_name.present": room_name != "unknown",
        })

        async def on_shutdown() -> None:
            duration_ms = int((asyncio.get_running_loop().time() - started_at) * 1000)
            session_span.set_attribute("voice.duration_ms", duration_ms)
            voice_session_duration.record(duration_ms, {
                "tenant.id": tenant_id,
                "voice.disconnect_reason": disconnect_reason,
                "outcome": "success",
            })
            session_span.end()

        ctx.add_shutdown_callback(on_shutdown)
        await _deliver_initial_greeting(...)
```

Do not replace this with a short `voice.session.end` span inside shutdown.

## Bounded Session Work

Bounded operations still get their own decorators.

```python
@tracer.start_as_current_span("voice.deliver_initial_greeting")
async def _deliver_initial_greeting(...):
    ...
```

## Session Metrics

Use both:

- `voice.sessions.started` counter at entrypoint start
- `voice.session.duration_ms` histogram in shutdown

Add product metrics for important voice events, e.g.
`voice.greetings.delivered`.

## Smoke Checks

For a minimal LiveKit fixture, a good smoke path imports the agent and executes
one tiny instrumented function or starts a span/log record with a local OTLP
endpoint. Checking that tracer/meter objects are non-None is not enough.

## LLM Turns

Every LLM provider/call site in the voice agent needs:

- span around the call
- token counters (`llm.tokens.input`, `llm.tokens.output`)
- tenant/provider/model/use case/call site/outcome attributes

Do not add `llm.cost_usd` metrics; Superlog estimates cost centrally from
provider/model/token data.

Name the span for the product operation, not the provider transport call.
For example, prefer `llm.voice_response` or `llm.generate_copy` over
`llm.anthropic.messages.create`.

```python
attrs = {
    "tenant.id": tenant_id,
    "llm.provider": "anthropic",
    "llm.model": model,
    "llm.use_case": "voice.initial_greeting",
    "llm.call_site": "_call_mug_copy_llm",
    "outcome": "success",
}
llm_tokens_input.add(input_tokens, attrs)
llm_tokens_output.add(output_tokens, attrs)
```

Source

Creator's repository · superloglabs/skills

View on GitHub

Security

Security checks in progress
Results will appear here once audits complete
What this skill can do
Reads your filesConnects to the internetRuns code on your machine
Checked by 3 independent security firms
Does it try to trick the AI?Not yet checkedPending · Gen Agent Trust Hub
Does it sneak in hidden code?Not yet checkedPending · Socket
Does it have known bugs?Not yet checkedPending · Snyk