evals(v4): wire OTEL transport into runEvals - #2759
Open
miguelg719 wants to merge 1 commit into
Open
Conversation
|
Contributor
There was a problem hiding this comment.
3 issues found across 1 file
Confidence score: 3/5
- In
packages/evals/framework/runner.ts, the OTEL + LangSmith-only path can route throughtracedSpanwithNOOP_SPAN, so task-root spans are never created and span propagation can silently fail; this risks losing end-to-end eval trace visibility in that configuration—ensure the gated task-roottracedSpanstill creates a real span whenBRAINTRUST_API_KEYis absent. - In
packages/evals/framework/runner.ts(runEvals/shutdownTracing), repeated runs in the same process can drop all spans on the second invocation because tracing is shut down but not fully reset for reinit; this creates a concrete regression for long-lived runners—clear/reset tracing state during shutdown so subsequent runs reinitialize cleanly. - In
packages/evals/framework/runner.ts, the newcapForSpantruncation andtraceThreadIdpath-sanitization paths lack focused tests, which raises regression risk around byte-cap trimming and safe thread-id formatting—add targeted unit coverage for the cap budget, tail-trim behavior, non-log fallback, and path-safe output.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/evals/framework/runner.ts">
<violation number="1" location="packages/evals/framework/runner.ts:299">
P3: The new `capForSpan` truncation and `traceThreadId` path-sanitization logic ships without unit tests. Add focused tests covering the byte-budget cap, tail-trim halving of logs, the non-log fallback, and the path-safe thread-id regex so the behavior is encoded and future regressions are caught.</violation>
<violation number="2" location="packages/evals/framework/runner.ts:474">
P2: When OTEL transport is active but `BRAINTRUST_API_KEY` is unset (the LangSmith-only case), `tracedSpan` from braintrust.ts returns `fn(NOOP_SPAN)`, so the gated task-root `tracedSpan` never creates a real span and `span?.log({ output: capForSpan(...) })` is a no-op. The task-root span and its payload are therefore silently lost, defeating this PR's OTEL wiring. Create the task-root span via the tracer directly (as `withHarnessAgentSpan` in otel.ts does with `getTracer().startActiveSpan`) rather than reusing the Braintrust-key-gated `tracedSpan`.</violation>
<violation number="3" location="packages/evals/framework/runner.ts:582">
P2: When `runEvals` runs more than once in the same process with OTEL transport, the second run never reinitializes tracing and drops spans. `runEvals` now always shuts tracing down, but `shutdownTracing` does not clear the `providerRegistered` guard that `buildTracerProvider` uses to skip initialization. Reset that guard during shutdown (or remove the guard check) so later runs can register a new provider.</violation>
</file>
Architecture diagram
sequenceDiagram
participant Runner as runEvals (runner.ts)
participant OTel as OTel Transport (otel.ts)
participant Braintrust as Braintrust SDK (braintrust.ts)
participant Tasks as Task Execution Loop
participant Env as Environment Config
Note over Runner,Env: NEW: OTel tracing integration in eval pipeline
Runner->>Env: resolveTraceTransport()
Env-->>Runner: traceTransport ("otel" | other)
Runner->>Runner: Determine braintrustProjectName (CI + core-only logic)
alt traceTransport === "otel"
Runner->>OTel: buildTracerProvider({ braintrustParent: "project_name:<name>" })
OTel-->>Runner: Tracer provider ready
end
Runner->>Braintrust: loadBraintrust()
Braintrust-->>Runner: Eval, flush
loop For each testcase/task
Runner->>Tasks: executeTask(input, resolvedTask, options)
alt traceTransport === "otel"
Tasks->>Runner: Task result (raw)
Runner->>Tasks: tracedSpan(callback, spanMetadata)
Note over Runner,Tasks: NEW: Wrap each task execution in OTel span
Tasks->>Runner: result (r)
Runner->>Runner: capForSpan({_success, error?, metrics?, logs?})
Note over Runner: CHANGED: Enforce 2MB UTF-8 payload cap with tail-trimming
Runner->>Tasks: span.log({output: cappedResult, metadata: {...}})
Note over Runner,Tasks: metadata includes experiment_name, thread_id (path-safe + collision-resistant), model, task
end
Tasks-->>Runner: Final result
Runner->>Runner: Track pass/fail counts
Runner->>Runner: options.onProgress(...)
end
alt traceTransport === "otel"
Runner->>OTel: shutdownTracing()
Note over Runner,OTel: CHANGED: Guaranteed shutdown in finally block
OTel-->>Runner: Tracing stopped
end
Runner-->>Runner: Return summary (passed, failed, total, results)
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
miguelg719
force-pushed
the
miguelgonzalez/evals-v4-otel-runner
branch
from
August 17, 2026 19:46
534f083 to
d0434a3
Compare
miguelg719
force-pushed
the
miguelgonzalez/evals-v4-otel-runner
branch
from
August 17, 2026 20:03
d0434a3 to
5237c12
Compare
miguelg719
force-pushed
the
miguelgonzalez/evals-v4-otel-runner
branch
from
August 17, 2026 21:03
5237c12 to
6521db3
Compare
miguelg719
force-pushed
the
miguelgonzalez/evals-v4-otel-runner
branch
from
August 17, 2026 22:05
6521db3 to
7aecc75
Compare
miguelg719
force-pushed
the
miguelgonzalez/evals-v4-otel-runner
branch
from
August 17, 2026 22:07
7aecc75 to
d40a0ed
Compare
miguelg719
force-pushed
the
miguelgonzalez/evals-v4-otel-runner
branch
from
August 17, 2026 22:34
d40a0ed to
fdad0fd
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Stack 3/6. Wires the provider into the run loop.
What
buildTracerProvider/shutdownTracingin a try/finally (otel only).tracedSpancarryingcapForSpan(TaskResult)(UTF-8 byte cap, tail-trim) + path-safe, collision-resistantthread_id.writeExperimentLink/persist gate) left byte-identical; native task path unchanged.Testing
typecheck + unit + build green.
Base: #2758
Summary by cubic
Adds OpenTelemetry tracing to
runEvalswhen the trace transport isotel, creating a task‑root span per task. Previously tasks had no tracing; non‑OTel runs and Braintrust logging remain unchanged.resolveTraceTransport() === "otel"; callbuildTracerProvider({ braintrustParent: "project_name:<project>" })and alwaysshutdownTracing()in afinally.executeTaskintracedSpan(name = task, type = "task", event carries{ input: { task, model } }); span logs a cappedoutputsubset (_success,error,metrics,logs) and metadata (experiment_name, path‑safe collision‑resistantthread_id,model,task).capForSpan(2 MB UTF‑8 cap): tail‑trimslogsby halving to keep the trailing slice, then dropslogs; if still too large or not serializable, replace with a minimal{ _truncated }.thread_idas<sanitized experimentName>-<base36 timestamp>-<uuid8>for URL‑safe, collision‑resistant threads.capForSpaninpackages/evals/tests/framework/capforspan.test.ts.Written for commit fdad0fd. Summary will update on new commits.