Skip to content

fix(voice): propagate caller's OTel context through AgentSession#1244

Open
mrniket wants to merge 1 commit intolivekit:mainfrom
lottiehq-oss:fix/otel-context-propagation
Open

fix(voice): propagate caller's OTel context through AgentSession#1244
mrniket wants to merge 1 commit intolivekit:mainfrom
lottiehq-oss:fix/otel-context-propagation

Conversation

@mrniket
Copy link
Copy Markdown
Contributor

@mrniket mrniket commented Apr 14, 2026

Summary

  • AgentSession now honours the active OpenTelemetry context when creating
    its agent_session span, so spans the caller started before session.start()
    become proper parents. Fixes feat: Add trace context propagation API for Node.js SDK (parity with Python) #924.
  • Added a comment to setupCloudTracer clarifying that tracerProvider.register()
    uses set-once semantics in the OTel API — it won't clobber a user's existing
    context manager or tracer provider if they've already called NodeSDK.start().

Test plan

  • New unit test agents/src/telemetry/traces.test.ts verifying that
    DynamicTracer.startSpan inherits the active OTel context when no
    explicit context is passed — the contract the fix depends on.
  • Manually verified on LiveKit Cloud with a downstream Langfuse integration.
  • pnpm test, pnpm lint, pnpm format:check all pass.

Honour otelContext.active() when starting the agent_session span and
when building rootSpanContext, so spans the caller created before
session.start() become parents of LiveKit spans. Stop calling
tracerProvider.register() in setupCloudTracer to avoid replacing the
global AsyncLocalStorageContextManager.

Fixes livekit#924
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 14, 2026

⚠️ No Changeset found

Latest commit: be9728a

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@mrniket mrniket marked this pull request as ready for review April 14, 2026 10:49
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

});
tracerProvider.register();

// Don't call tracerProvider.register() — it would replace the global context manager.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Removing tracerProvider.register() from setupCloudTracer breaks async context propagation for cloud traces

The removal of tracerProvider.register() at agents/src/telemetry/traces.ts:261 means no AsyncHooksContextManager is set up for LiveKit Cloud users. NodeTracerProvider.register() was the only call that replaced the default NoopContextManager with a real context manager capable of propagating context across async boundaries.

Without a real context manager, otelContext.active() always returns ROOT_CONTEXT and otelContext.with() doesn't propagate context to async continuations. This breaks span parent-child hierarchies throughout the pipeline:

Affected call sites that rely on implicit context propagation
  • agents/src/voice/generation.ts:541: const currentContext = otelContext.active() — intended to capture agent_turn context for llm_node, but now gets ROOT_CONTEXT
  • agents/src/voice/generation.ts:707: Same issue for tts_node spans
  • agents/src/voice/generation.ts:1061-1063: function_tool spans have no explicit context, become orphaned root spans
  • agents/src/voice/agent_session.ts:841: otelContext.with(this.rootSpanContext, runWithContext) — async runWithContext won't see the session context
  • agents/src/voice/agent_session.ts:1109: otelContext.with(this.rootSpanContext, async () => ...) — same issue in closeImpl

In the typical cloud flow, setupCloudTracer (called from job.ts:385 via initRecording) is the only place that previously set up the context manager. Users don't register their own provider in this path. The result is that cloud trace dashboards will show flat, unrelated root spans instead of properly nested trace trees.

Prompt for agents
The removal of tracerProvider.register() was intended to avoid replacing a user's existing global context manager. However, it also prevents setting up ANY context manager when no user provider is registered (the common cloud case). The fix should conditionally set up a context manager when one isn't already active, without replacing the global tracer provider. One approach: check if a real context manager is already registered (e.g., by testing otelContext.active() behavior or checking a flag), and if not, explicitly create and enable an AsyncLocalStorageContextManager via context.setGlobalContextManager() without calling the full register(). Another approach: call register() only if no global tracer provider is already set. The key constraint is: don't clobber an existing user-provided context manager, but DO set one up if none exists. Relevant files: agents/src/telemetry/traces.ts (setupCloudTracer function, around line 257-262).
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

resource,
spanProcessors: [new MetadataSpanProcessor(metadata), new BatchSpanProcessor(spanExporter)],
});
tracerProvider.register();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should delete this line; otherwise the cloud tracing will no longer work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Add trace context propagation API for Node.js SDK (parity with Python)

2 participants