Skip to content

feat: propagate W3C traceparent on outbound LLM HTTP requests #49037

Closed

Description

@joshreini1

Problem

OpenCode's LLM provider HTTP requests do not carry a W3C traceparent header. When OpenCode is used behind a tracing-capable gateway or proxy (e.g. Snowflake Cortex AI Gateway), the gateway creates server-side spans for each LLM request, but these spans start a new trace because the inbound HTTP request has no trace context. Client-side and server-side spans end up as disjoint traces.

This is related to #46856 (MCP _meta propagation) but covers a different surface: outbound HTTP requests to LLM providers (OpenAI, Anthropic, Azure, Copilot, etc.), not MCP tool calls.

Suggested implementation

OpenCode already has full OTel infrastructure in packages/core/src/observability/otlp.ts: @opentelemetry/api, AsyncLocalStorageContextManager, and the OTLP HTTP trace exporter. The missing piece is injecting the active span context into outbound LLM requests.

Injection point: packages/llm/src/route/executor.ts, in the layer definition (~line 370). Before http.execute(request), inject the traceparent header from the active OTel context:

import { context, propagation } from "@opentelemetry/api"

// In executeOnce, before http.execute:
const carrier: Record<string, string> = {}
propagation.inject(context.active(), carrier)
const traced = Object.entries(carrier).reduce(
  (req, [k, v]) => HttpClientRequest.setHeader(req, k, v),
  request,
)
return yield* http.execute(traced)...

This requires adding @opentelemetry/api as a dependency to the llm package (it's already in the monorepo via packages/core).

Behavior when tracing is not configured: propagation.inject() is a no-op when no propagator is registered (no TracerProvider set up), so no headers are added. Zero behavioral change for users without tracing.

Verified end-to-end

Tested the equivalent fix (W3C traceparent injection via SDK middleware) against a live OTLP-capable gateway. With propagation, the gateway's server span becomes a child of the client's span in a single connected trace:

rag-pipeline (root)
├── retrieve (parent: rag-pipeline)
├── generate (parent: rag-pipeline)
│   └── chat openai-gpt-5.4 [SERVER] (parent: generate)  ← gateway span

Without it, the gateway span is in a separate trace.

Activity

  1. github-actions commented on Sep 14, 2026

    @github-actions
    Contributor

    This issue doesn't fully meet our contributing guidelines.

    What needs to be fixed:

    • Feature requests must use the feature request template, which requires a verification checkbox confirming the feature hasn't been suggested before, and a title prefixed with [FEATURE]:

    Please edit this issue to address the above within 2 hours, or it will be automatically closed.


    This issue might be a duplicate of existing issues. Please check:

    If you believe this was flagged incorrectly, please let a maintainer know.

  2. joshreini1 commented on Sep 14, 2026

    @joshreini1
    Author

    Duplicate of #49038, closing.

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

Metadata

Metadata

Assignees

Labels

needs:complianceThis means the issue will auto-close after 2 hours.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions