feat(evals): wire opt-in OTEL transport (EVAL_TRACE_TRANSPORT=otel; native unchanged) - #2353
Conversation
|
There was a problem hiding this comment.
All reported issues were addressed across 4 files
Confidence score: 5/5
- Safe to merge after the addressed issues were fixed.
Architecture diagram
sequenceDiagram
participant CLI as CLI / Signal Handler
participant Runner as runner.ts
participant Braintrust as braintrust.ts (tracedSpan)
participant OTEL as @opentelemetry/api (OtelSpan)
participant AISDK as AISdkClientWrapped
participant BraintrustAPI as Braintrust Backend
participant OTELExporter as OTEL Exporter
Note over CLI,OTELExporter: OTEL Transport (EVAL_TRACE_TRANSPORT=otel)
Runner->>Runner: resolveTraceTransport() => "otel"
Runner->>OTEL: buildTracerProvider()
OTEL-->>Runner: provider ready
Runner->>Braintrust: tracedSpan(fn, options)
alt EVAL_TRACE_TRANSPORT equals otel
Braintrust->>OTEL: getTracer().startActiveSpan(name)
OTEL-->>Braintrust: active OtelSpan
Braintrust->>OTEL: setAttribute(type, input.*)
Braintrust->>fn: call with OTEL adapter
fn->>AISDK: createChatCompletion()
AISDK->>AISDK: loadAISDK() (no wrapAISDK)
AISDK->>AISDK: pass experimental_telemetry block
Note over AISDK: generates OTEL spans for generateObject/generateText
AISDK-->>fn: response
fn->>Braintrust: adapter.log({output, scores, metadata, ...})
Braintrust->>OTEL: setAttribute(metadata.*, metrics.*)
Braintrust->>OTEL: addEvent("scores", ...)
Braintrust->>OTEL: addEvent("output", ...)
alt error in fn
Braintrust->>OTEL: setStatus(ERROR)
Braintrust->>OTEL: recordException(error)
Braintrust-->>Runner: throw error
else success
Braintrust->>OTEL: span.end()
Braintrust-->>Runner: return result
end
Runner->>Braintrust: flush() (Braintrust log)
Braintrust->>BraintrustAPI: send logs
Runner->>OTEL: shutdownTracing()
OTEL->>OTELExporter: export final spans
OTEL-->>Runner: done
else native (default)
Braintrust->>Braintrust: hasBraintrustApiKey()
alt has key
Braintrust->>BraintrustAPI: create Braintrust span
Braintrust-->>fn: Braintrust adapter
fn->>Braintrust: adapter.log(...)
Braintrust->>BraintrustAPI: log output/scores
else no key
Braintrust-->>fn: NOOP_SPAN
end
Braintrust-->>Runner: return result
end
Note over CLI,Runner: Signal teardown
CLI->>CLI: handleSignal(SIGINT)
CLI->>OTEL: shutdownTracing()
OTEL->>OTELExporter: final flush
CLI->>CLI: process.exit(code)
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
c9a9f41 to
7e05a8a
Compare
7e05a8a to
a138f7e
Compare
…unchanged) Reconciled with main's refactored runEvals: OTEL provider init/shutdown wraps the eval body in try/finally while preserving the run-scoped trajectory-group stamping and writeExperimentLink cross-link.
a138f7e to
51cf53e
Compare
|
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. |
why
Turns the OTEL fan-out on behind an opt-in flag. The native (default) path stays byte-identical — no keys/flags means today's behavior exactly.
what changed
framework/braintrust.ts:tracedSpangains an otel branch — opens an OTEL active span, adaptsspan.log({output,scores,metrics,metadata})→setAttribute/addEvent; native +NOOP_SPANbranches untouched, signature unchanged (verifier/runner call sites need zero edits)lib/AISdkClientWrapped.ts:EVAL_TRACE_TRANSPORT=otel→experimental_telemetry(nowrapAISDK); native path verbatimframework/runner.ts: provider init at run start;shutdownTracing()after the Braintrust flushcli.ts: best-effort flush on signal teardowntest plan
braintrust-optional/braintrust-runner-nologpass unchanged (native invariant)EVAL_TRACE_TRANSPORT=otel LANGSMITH_TRACING=truedual-backend run (env: browserbase) — spans land in both UIs;.trajectories/identical to nativeStack 3/5 · base: #2352
Summary by cubic
Adds an opt-in OpenTelemetry transport for eval traces via
EVAL_TRACE_TRANSPORT=otel. Default Braintrust tracing is unchanged; OTEL now emits input/output and metadata attributes that LangSmith reads.New Features
framework/braintrust.ts:tracedSpanadds an OTEL path that maps inputs/metadata/metrics to attributes, outputs to attributes, and scores to events; records errors; native path untouched.framework/runner.ts: builds the OTEL tracer provider at run start with a parentproject_name:<braintrustProjectName>when enabled.lib/AISdkClientWrapped.ts: whenEVAL_TRACE_TRANSPORT=otel, call the SDK directly and passexperimental_telemetryfor bothgenerateObjectandgenerateText; native wrapping otherwise.Bug Fixes
framework/braintrust.ts: emitinput.value/output.valueattributes (mirrored tobraintrust.input_json/braintrust.output_json), move metadata tolangsmith.metadata.*, and setlangsmith.span.kindso LangSmith shows inputs/outputs correctly.framework/runner.ts: always callshutdownTracing()in afinallyblock, preserving run-scoped trajectory-group stamping andwriteExperimentLinkcross-linking;cli.tsalso triggers best-effortshutdownTracing()on signal teardown.Written for commit 51cf53e. Summary will update on new commits.