Summary
The BraintrustStream streaming aggregator only handles OpenAI Chat Completions chunk format (choices[].delta). Anthropic's Messages streaming API uses a structurally different SSE event protocol (message_start, content_block_delta, message_delta, etc.) that the aggregator cannot parse. All Anthropic streaming chunks are silently discarded, producing an empty aggregated result.
What is missing
Anthropic's Messages streaming API emits typed SSE events:
message_start — contains the initial Message object with usage.input_tokens
content_block_start — opens a content block (text, tool_use, or thinking)
content_block_delta — incremental content: text_delta.text, input_json_delta.partial_json, or thinking_delta.thinking
content_block_stop — closes a content block
message_delta — final stop_reason and cumulative usage.output_tokens
message_stop — stream termination
These events have no choices array and no delta sub-field inside choices. The current aggregation path in BraintrustStream::aggregate() (src/stream.rs:727-807) parses each chunk as a StreamChunk expecting choices: Vec<StreamChoice>. Anthropic events fail deserialization and hit the Err(_) => continue fallback at line 740-741, silently dropping all data.
This means:
- Text content from
content_block_delta events is lost
- Tool use arguments streamed via
input_json_delta are lost
- Extended thinking content from
thinking_delta events is lost
- Usage metrics from
message_start and message_delta are lost
- Stop reason from
message_delta is lost
Braintrust's other SDKs handle Anthropic streaming via dedicated wrappers:
- TypeScript:
wrapAnthropic
- Python:
wrap_anthropic
- Go: tracing middleware
- Ruby:
Braintrust::Trace::Anthropic.wrap
- Java/C#: interceptors/extensions
All of these capture streamed Anthropic responses including content, tool use, and usage metrics.
This is distinct from existing issues:
Braintrust docs status
Braintrust documents Anthropic streaming support across all non-Rust SDKs: "Braintrust handles streaming, metric collection (including cached tokens), and other details." Status: supported in Braintrust platform via other SDK wrappers, not instrumented in this Rust SDK.
Upstream sources
Local files inspected
src/stream.rs — StreamChunk struct (line 639-647) only has model, choices, usage fields; StreamChoice/StreamDelta (lines 651-664) expect OpenAI format; aggregate() (lines 727-807) parses only choices[].delta; error fallback at line 740-741 silently skips unparseable chunks
src/extractors.rs — extract_anthropic_usage() handles the non-streaming Anthropic response format correctly, but is not invoked during streaming aggregation
src/lib.rs — wrap_stream_with_span is exported as the primary streaming instrumentation surface
Summary
The
BraintrustStreamstreaming aggregator only handles OpenAI Chat Completions chunk format (choices[].delta). Anthropic's Messages streaming API uses a structurally different SSE event protocol (message_start,content_block_delta,message_delta, etc.) that the aggregator cannot parse. All Anthropic streaming chunks are silently discarded, producing an empty aggregated result.What is missing
Anthropic's Messages streaming API emits typed SSE events:
message_start— contains the initialMessageobject withusage.input_tokenscontent_block_start— opens a content block (text, tool_use, or thinking)content_block_delta— incremental content:text_delta.text,input_json_delta.partial_json, orthinking_delta.thinkingcontent_block_stop— closes a content blockmessage_delta— finalstop_reasonand cumulativeusage.output_tokensmessage_stop— stream terminationThese events have no
choicesarray and nodeltasub-field insidechoices. The current aggregation path inBraintrustStream::aggregate()(src/stream.rs:727-807) parses each chunk as aStreamChunkexpectingchoices: Vec<StreamChoice>. Anthropic events fail deserialization and hit theErr(_) => continuefallback at line 740-741, silently dropping all data.This means:
content_block_deltaevents is lostinput_json_deltaare lostthinking_deltaevents is lostmessage_startandmessage_deltaare lostmessage_deltais lostBraintrust's other SDKs handle Anthropic streaming via dedicated wrappers:
wrapAnthropicwrap_anthropicBraintrust::Trace::Anthropic.wrapAll of these capture streamed Anthropic responses including content, tool use, and usage metrics.
This is distinct from existing issues:
Braintrust docs status
Braintrust documents Anthropic streaming support across all non-Rust SDKs: "Braintrust handles streaming, metric collection (including cached tokens), and other details." Status: supported in Braintrust platform via other SDK wrappers, not instrumented in this Rust SDK.
Upstream sources
message_start,content_block_start,content_block_delta,content_block_stop,message_delta,message_stop,ping,errorLocal files inspected
src/stream.rs—StreamChunkstruct (line 639-647) only hasmodel,choices,usagefields;StreamChoice/StreamDelta(lines 651-664) expect OpenAI format;aggregate()(lines 727-807) parses onlychoices[].delta; error fallback at line 740-741 silently skips unparseable chunkssrc/extractors.rs—extract_anthropic_usage()handles the non-streaming Anthropic response format correctly, but is not invoked during streaming aggregationsrc/lib.rs—wrap_stream_with_spanis exported as the primary streaming instrumentation surface