feat(eval): introduce new reporter API#264
feat(eval): introduce new reporter API#264Abhijeet Prasad (AbhiPrasad) wants to merge 7 commits into
Conversation
1. Overall architectureflowchart LR
User["User / CI"] --> CLI["bt eval"]
CLI -->|starts subprocess| Runner["Bundled JS or Python runner"]
Runner --> SDK["Installed Braintrust SDK"]
SDK --> Eval["Eval execution"]
Eval --> SDKManager["SDK ReporterManager"]
SDKManager --> Bridge["bt bridge reporter"]
Bridge -->|Canonical events over SSE| CLIManager["bt ReporterManager"]
CLIManager --> Fancy["fancy / verbose / dot"]
CLIManager --> Machine["jsonl / events"]
CLIManager --> Artifact["junit"]
CLIManager --> CI["github-actions"]
Fancy --> STDERR["stderr"]
Machine --> STDOUT["stdout"]
Artifact --> FILE["results.xml"]
CI --> STDERR
The key change is that eval execution produces one structured event stream. Every output format consumes that stream instead of implementing its own eval logic. 2. A normal
|
|
Latest downloadable build artifacts for this PR commit
Available artifact names
|
AI Summary
Summary
This change introduces a unified reporter system for
bt eval. Eval execution now produces a canonical lifecycle event stream that can be consumed by terminal, machine-readable, artifact, and devserver reporters without coupling rendering behavior to execution logic.User-facing impact
Selectable reporters
bt evalnow supports repeatable reporter selection:Equivalent environment configuration is available through:
Explicit
--reporterflags replace the default reporter set. Reporters can be composed as long as no more than one claims stdout.Existing defaults remain familiar
Existing commands retain their intended behavior:
bt evaluses thefancyreporter.bt eval --verboseuses the verbose terminal reporter.bt eval --jsonlproduces JSONL summaries on stdout while retaining human-facing progress and errors on stderr.--listremains an execution mode rather than a reporter.Reliable machine-readable output
User code printing to stdout no longer corrupts
--jsonloutput. Under--jsonl, captured user console output is routed to stderr, leaving stdout as parseable JSONL.The new
eventsreporter exposes the full canonical lifecycle as NDJSON for integrations and custom tooling.New CI reporters
The reporter API enables CI-focused output:
dotrenders compact per-case status.junitwrites JUnit XML and requires--output-file.github-actionsemits escaped workflow annotations.Case-oriented reporters require real per-case results. When used with an older Braintrust SDK that only exposes aggregate progress, they fail with an actionable upgrade message rather than inventing incomplete case data.
Deprecations and compatibility
There are no CLI deprecations.
--jsonland--verboseremain supported as permanent convenience aliases. Existing eval files and runner configuration continue to work.The runner decoder supports both:
processing,start,progress,summary,error, anddonevocabulary through a legacy adapter.Older SDKs therefore continue to work with
fancy,verbose, and summary reporters. Only reporters requiring full case fidelity need an SDK upgrade.Migration story
Existing CLI users
No migration is required. Existing commands retain their defaults, with one intentional improvement:
--jsonlnow guarantees clean stdout.Users can adopt explicit reporters incrementally:
SDK compatibility
The bundled JavaScript and Python runners now emit the canonical protocol. They feature-detect available case information:
Devserver clients
Legacy devserver SSE remains the default and is byte-compatible for existing browser clients.
Clients can opt into canonical events by sending:
x-bt-stream-fmt: canonicalThis allows the playground and other clients to migrate independently without breaking older versions.
Why the new API is better
One lifecycle across every output format
All reporters consume the same structured lifecycle:
Errors, console messages, progress totals, and case deltas are modeled as structured side-channel events. Terminal output, JSONL, JUnit, GitHub annotations, and devserver SSE no longer maintain separate interpretations of an eval run.
Stable identity instead of name-based correlation
Events carry
runId,evalId, andcaseId. Reporters no longer need to correlate progress and summaries using display names, which were not guaranteed to match.Case IDs use root span IDs when available, creating a direct link between reporter output and trace data.
Better separation of concerns
Execution policy, output format, and verbosity are now independent:
fancyorverbose.Adding a new output format no longer requires modifying eval execution or the devserver.
Safer composition
A shared terminal facade coordinates persistent lines and live progress regions. This prevents multiple reporters from tearing terminal output.
The manager also:
run:end.Efficient streaming
Large case inputs and outputs remain in the SDK process. Live
case:deltaevents are emitted only when an installed reporter advertises interest, avoiding unnecessary serialization and process-boundary traffic.