Summary
The BraintrustStream streaming aggregator only extracts model from OpenAI Chat Completions streaming chunks, silently dropping service_tier and system_fingerprint. These are documented fields on every ChatCompletionChunk object. The StreamMetadata type already has an extra: HashMap<String, Value> that could hold these values, but the aggregation logic always passes an empty map.
What is missing
OpenAI Chat Completions streaming chunks include these fields alongside model:
{
"id": "chatcmpl-abc123",
"object": "chat.completion.chunk",
"created": 1694268190,
"model": "gpt-4o",
"service_tier": "scale",
"system_fingerprint": "fp_44709d6fcb",
"choices": [...]
}
Currently in the SDK:
-
StreamChunk (src/stream.rs:687-694) only deserializes three fields — model, choices, and usage. The service_tier, system_fingerprint, id, and created fields are silently discarded during serde deserialization.
-
aggregate() (src/stream.rs:983) creates metadata with an always-empty extra map:
let metadata = StreamMetadata::new(model, HashMap::new());
The StreamMetadata type already supports extra fields via its extra: HashMap<String, Value>, but the aggregation logic never populates it.
Why these fields matter
service_tier ("default" | "scale" | "flex") — determines which pricing tier processed the request. Scale tier is ~2x the cost of default; flex tier is ~50% cheaper. Without this field, cost attribution in Braintrust spans may use incorrect pricing assumptions. This is especially relevant as OpenAI's newer flex tier becomes more widely used.
system_fingerprint (string) — identifies the backend configuration the model ran with. Used alongside the seed parameter to detect when backend changes affect determinism. Important for reproducibility analysis and debugging behavior regressions.
Braintrust docs status
unclear — Braintrust's OpenAI integration page documents automatic token metrics capture but does not explicitly mention service_tier or system_fingerprint capture from streaming responses. The tracing guide states that "Model parameters (model name, temperature, etc.)" and "Token usage and costs" are captured, but does not enumerate response-level metadata fields.
Upstream sources
Relationship to existing issues
Local files inspected
src/stream.rs:687-694 — StreamChunk struct only has model, choices, usage fields
src/stream.rs:983 — aggregate() always creates StreamMetadata::new(model, HashMap::new())
src/stream.rs:488-535 — StreamMetadata struct has extra: HashMap<String, Value> that could hold these values
src/stream.rs:840-1009 — full aggregate() function; no code path reads service_tier, system_fingerprint, id, or created from chunks
Summary
The
BraintrustStreamstreaming aggregator only extractsmodelfrom OpenAI Chat Completions streaming chunks, silently droppingservice_tierandsystem_fingerprint. These are documented fields on everyChatCompletionChunkobject. TheStreamMetadatatype already has anextra: HashMap<String, Value>that could hold these values, but the aggregation logic always passes an empty map.What is missing
OpenAI Chat Completions streaming chunks include these fields alongside
model:{ "id": "chatcmpl-abc123", "object": "chat.completion.chunk", "created": 1694268190, "model": "gpt-4o", "service_tier": "scale", "system_fingerprint": "fp_44709d6fcb", "choices": [...] }Currently in the SDK:
StreamChunk(src/stream.rs:687-694) only deserializes three fields —model,choices, andusage. Theservice_tier,system_fingerprint,id, andcreatedfields are silently discarded during serde deserialization.aggregate()(src/stream.rs:983) creates metadata with an always-empty extra map:The
StreamMetadatatype already supports extra fields via itsextra: HashMap<String, Value>, but the aggregation logic never populates it.Why these fields matter
service_tier("default"|"scale"|"flex") — determines which pricing tier processed the request. Scale tier is ~2x the cost of default; flex tier is ~50% cheaper. Without this field, cost attribution in Braintrust spans may use incorrect pricing assumptions. This is especially relevant as OpenAI's newerflextier becomes more widely used.system_fingerprint(string) — identifies the backend configuration the model ran with. Used alongside theseedparameter to detect when backend changes affect determinism. Important for reproducibility analysis and debugging behavior regressions.Braintrust docs status
unclear — Braintrust's OpenAI integration page documents automatic token metrics capture but does not explicitly mention
service_tierorsystem_fingerprintcapture from streaming responses. The tracing guide states that "Model parameters (model name, temperature, etc.)" and "Token usage and costs" are captured, but does not enumerate response-level metadata fields.wrapOpenAI/wrap_openaiautomatic tracingUpstream sources
ChatCompletionChunktype in Python SDK definesservice_tierandsystem_fingerprint: https://github.com/openai/openai-python/blob/main/src/openai/types/chat/chat_completion_chunk.pyservice_tierparameter and response field): https://developers.openai.com/api/reference/resources/chat/subresources/completions/methods/createRelationship to existing issues
service_tierandinference_geo): [bot] Anthropic usage extractor drops service_tier and inference_geo execution metadata #45 covers the Anthropic non-streaming usage extractor dropping string metadata from theusageobject. This issue is about the OpenAI streaming aggregator dropping chunk-level response metadata — a different provider, different API surface (streaming aggregator vs. non-streaming extractor), and different field locations (response root vs. usage sub-object).choices.Local files inspected
src/stream.rs:687-694—StreamChunkstruct only hasmodel,choices,usagefieldssrc/stream.rs:983—aggregate()always createsStreamMetadata::new(model, HashMap::new())src/stream.rs:488-535—StreamMetadatastruct hasextra: HashMap<String, Value>that could hold these valuessrc/stream.rs:840-1009— fullaggregate()function; no code path readsservice_tier,system_fingerprint,id, orcreatedfrom chunks