Skip to content

feat(evals): add OTEL tracer-provider module + deps (unwired) - #2352

Closed
miguelg719 wants to merge 1 commit into
miguelgonzalez/evals-langsmith-gatingfrom
miguelgonzalez/evals-otel-provider
Closed

feat(evals): add OTEL tracer-provider module + deps (unwired)#2352
miguelg719 wants to merge 1 commit into
miguelgonzalez/evals-langsmith-gatingfrom
miguelgonzalez/evals-otel-provider

Conversation

@miguelg719

@miguelg719 miguelg719 commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

why

The fan-out core for the opt-in OTEL transport: one NodeTracerProvider whose span processors route eval traces to Braintrust and LangSmith, each gated on its own key. Unwired — imported by nothing yet.

what changed

  • framework/otel.ts (new): buildTracerProvider() (memoized; null unless EVAL_TRACE_TRANSPORT=otel; per-backend gated processors), getTracer(), null-safe shutdownTracing() (forceFlush+shutdown, 10s timeout)
  • @opentelemetry/{api,sdk-trace-base,sdk-trace-node} deps
  • tests/framework/otel.test.ts (new): native→null; both keys→2 processors; each alone→1

test plan

  • Unit suite 362/362 (incl. the 4 new otel cases)
  • Module unimported → no behavior change

Stack 2/5 · base: #2351


Summary by cubic

Adds an opt-in OpenTelemetry tracer provider for evals that can fan out spans to Braintrust and/or LangSmith. The module is added but not wired yet; provider state is bundle-safe, and shutdown continues even if forceFlush fails.

  • New Features

    • New framework/otel.ts with buildTracerProvider(); returns null unless EVAL_TRACE_TRANSPORT=otel and uses a globalThis Symbol-keyed state to avoid duplicate providers in the bundled CLI.
    • Span processors: Braintrust when BRAINTRUST_API_KEY is set (supports BRAINTRUST_OTEL_PARENT, BRAINTRUST_OTEL_URL, or braintrustParent override; defaults parent to project_name:stagehand-dev or project_name:stagehand in CI) and LangSmith when LANGSMITH_API_KEY is set and LANGSMITH_TRACING=true.
    • getTracer(), shutdownTracing() (10s timeout), and resetTracingStateForTests() for clearing shared state in tests; tests cover native mode, single/dual-backend setups, parent override, bundle-safe state, and shutdown behavior. .env.example documents Braintrust OTEL overrides.
  • Dependencies

    • Added @opentelemetry/api, @opentelemetry/exporter-trace-otlp-proto, @opentelemetry/sdk-trace-base, @opentelemetry/sdk-trace-node.

Written for commit d692cd9. Summary will update on new commits.

Review in cubic

@changeset-bot

changeset-bot Bot commented Jul 13, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: d692cd9

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

@cubic-dev-ai cubic-dev-ai Bot left a comment

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.

All reported issues were addressed across 5 files

Confidence score: 5/5

  • Safe to merge after the addressed issues were fixed.
Architecture diagram
sequenceDiagram
    participant Caller as Eval Runner (future)
    participant Builder as buildTracerProvider()
    participant Init as initializeTracerProvider()
    participant Env as Environment Variables
    participant BTExporter as OTLPTraceExporter (Braintrust)
    participant LSExporter as LangSmithOTLPTraceExporter
    participant Provider as NodeTracerProvider

    Note over Caller,Provider: NEW: OTEL Tracer Provider Initialization

    Caller->>Builder: buildTracerProvider()
    Builder->>Env: EVAL_TRACE_TRANSPORT
    alt Transport != "otel"
        Env-->>Builder: "native" or other
        Builder-->>Caller: null (no-op)
    else Transport == "otel"
        Env-->>Builder: "otel"
        Builder->>Init: initializeTracerProvider() (memoized)
        Init->>Env: BRAINTRUST_API_KEY?
        alt Key set
            Env-->>Init: key present
            Init->>Env: BRAINTRUST_OTEL_URL? else default url
            Init->>Env: BRAINTRUST_OTEL_PARENT? else project_name:stagehand-dev (or stagehand in CI)
            Init->>BTExporter: new OTLPTraceExporter(url, headers)
            BTExporter-->>Init: exporter instance
            Init->>Init: create BatchSpanProcessor(exporter)
        else Key missing
            Env-->>Init: no key
        end
        Init->>Env: LANGSMITH_API_KEY && LANGSMITH_TRACING=="true"?
        alt Both set
            Env-->>Init: keys set
            Init->>LSExporter: new LangSmithOTLPTraceExporter()
            LSExporter-->>Init: exporter instance
            Init->>Init: create BatchSpanProcessor(exporter)
        else Missing
            Env-->>Init: not set
        end
        alt spanProcessors.length > 0
            Init->>Provider: new NodeTracerProvider({ spanProcessors })
            Provider->>Provider: register() (global)
            Provider-->>Init: provider instance
            Init-->>Builder: provider
        else No processors
            Init-->>Builder: null
        end
        Builder-->>Caller: provider or null
    end

    Note over Caller,Provider: Shutdown flow

    Caller->>Builder: shutdownTracing()
    Builder->>Env: EVAL_TRACE_TRANSPORT == "otel"?
    alt Not otel or provider null
        Builder-->>Caller: return (no-op)
    else Valid provider
        Builder->>Provider: forceFlush()
        Provider-->>Builder: ok
        Builder->>Provider: shutdown()
        Provider-->>Builder: ok
        Builder->>Builder: reset provider to null
        Builder-->>Caller: done
    end

    Note over Caller,Provider: Tracer retrieval

    Caller->>Builder: getTracer()
    alt provider exists
        Provider-->>Builder: tracer from provider
    else No provider
        Builder-->>Caller: ProxyTracerProvider noop tracer
    end
    Builder-->>Caller: Tracer
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/evals/framework/otel.ts Outdated
@miguelg719
miguelg719 force-pushed the miguelgonzalez/evals-otel-provider branch from 840c0e5 to 3055aa4 Compare July 13, 2026 19:32

@cubic-dev-ai cubic-dev-ai Bot left a comment

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.

All reported issues were addressed across 9 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/evals/.rubric-cache/onlineMind2Web/fb7b4f784cfde003e2548fdf4e8d6b4f.json Outdated
Comment thread packages/evals/.rubric-cache/webvoyager/Allrecipes--1.json Outdated
Comment thread packages/evals/framework/otel.ts
@miguelg719
miguelg719 force-pushed the miguelgonzalez/evals-otel-provider branch from d04c712 to b4a8994 Compare July 20, 2026 22:08
Wire the OTEL provider's test-reset through the exported
resetTracingStateForTests() helper instead of hand-deleting the
globalThis slot (addresses review: dead export).
@miguelg719
miguelg719 force-pushed the miguelgonzalez/evals-otel-provider branch from b4a8994 to d692cd9 Compare July 31, 2026 00:22
@miguelg719

Copy link
Copy Markdown
Collaborator Author

Superseded by the Stagehand 4.0 retarget stack (#2757#2762). Main moved to the 4.0 monorepo restructure (packages/core → packages/sdk-ts; evals package restructured), so this 3.x-era diff no longer applies. The OTEL/LangSmith tracing work — plus native-span capture via 4.0's global tracer and claude_code/codex agent spans — is reimplemented additively on 4.0 in the new stack.

@miguelg719 miguelg719 closed this Aug 17, 2026
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.

1 participant