Summary
When using the WithBraintrust() extension method (the fallback instrumentation path — no BraintrustPipelineTransport injected), ChatCompletionOptions.ReasoningEffortLevel is not captured in braintrust.metadata. This is the primary execution-configuration parameter for OpenAI's o-series reasoning models (o1, o3, o3-mini, o4-mini), and its absence makes it impossible to understand or compare reasoning budget usage from Braintrust traces on this path.
What is missing
InstrumentedChatClient.TagActivityFromApiObjects() (lines 271–294) builds the braintrust.metadata tag from explicit ChatCompletionOptions properties:
if (options.Temperature.HasValue) metadata["temperature"] = options.Temperature.Value;
if (options.MaxOutputTokenCount.HasValue) metadata["max_tokens"] = options.MaxOutputTokenCount.Value;
if (options.TopP.HasValue) metadata["top_p"] = options.TopP.Value;
if (options.FrequencyPenalty.HasValue) metadata["frequency_penalty"] = options.FrequencyPenalty.Value;
if (options.PresencePenalty.HasValue) metadata["presence_penalty"] = options.PresencePenalty.Value;
if (options.StopSequences?.Count > 0) metadata["stop"] = options.StopSequences;
if (!string.IsNullOrEmpty(options.EndUserId)) metadata["user"] = options.EndUserId;
if (options.Tools?.Count > 0) metadata["tools"] = options.Tools;
if (options.ToolChoice != null) metadata["tool_choice"] = options.ToolChoice;
if (options.ResponseFormat != null) metadata["response_format"] = options.ResponseFormat;
// Missing: options.ReasoningEffortLevel → metadata["reasoning_effort"]
ChatCompletionOptions.ReasoningEffortLevel (type ChatReasoningEffortLevel?, wire name reasoning_effort) is available in the OpenAI .NET SDK v2.9.1 (used by this repo) but is absent from this list.
Which path is affected
| Path |
reasoning_effort captured? |
BraintrustOpenAI.WrapOpenAI() (primary path — BraintrustPipelineTransport active) |
✅ captured via raw JSON; TagActivityFromBaggage copies all non-messages request fields into metadata |
client.WithBraintrust() / OpenAITelemetry.Wrap() (fallback path — no transport) |
❌ missing; TagActivityFromApiObjects does not read ReasoningEffortLevel |
Users who adopt the extension-method path (e.g., integrating with an existing OpenAIClient) will produce spans where the reasoning effort level is invisible in traces for all o-series model calls.
Impact
ReasoningEffortLevel is the main knob for controlling reasoning token consumption on o1, o3, o3-mini, and o4-mini — directly affecting both latency and cost. Without it in metadata:
Braintrust docs status
The Braintrust OpenAI integration page at https://www.braintrust.dev/docs/integrations/ai-providers/openai does not enumerate the full set of captured request parameters. The pattern in this repo clearly intends to capture all significant generation parameters in metadata (temperature, max_tokens, tools, response_format, etc.), making the omission of reasoning_effort inconsistent. Status: unclear (not explicitly documented as captured or excluded).
Upstream sources
- OpenAI Reasoning models guide: https://platform.openai.com/docs/guides/reasoning — documents
reasoning_effort as the primary configuration parameter for o-series models; valid values are "low", "medium", "high", "none"
- OpenAI .NET SDK CHANGELOG: v2.9.0 entry references
ChatReasoningEffortLevel.None addition, confirming the property predates v2.9.1
- OpenAI .NET SDK:
ChatCompletionOptions.ReasoningEffortLevel property of type ChatReasoningEffortLevel?; wire-format name is reasoning_effort
Local files inspected
src/Braintrust.Sdk.OpenAI/InstrumentedChatClient.cs — TagActivityFromApiObjects() (lines 271–294): explicit metadata fields; ReasoningEffortLevel is absent
src/Braintrust.Sdk.OpenAI/InstrumentedChatClient.cs — TagActivityFromBaggage() (lines 175–185): captures all request fields from raw JSON, so the primary path is unaffected
src/Braintrust.Sdk.OpenAI/BraintrustOpenAI.cs — documents both instrumentation paths (factory method vs. extension method)
src/Braintrust.Sdk.OpenAI/Braintrust.Sdk.OpenAI.csproj — confirms OpenAI SDK v2.9.1 dependency
tests/Braintrust.Sdk.OpenAI.Tests/BraintrustOpenAITest.cs — no test coverage for o-series / ReasoningEffortLevel scenarios
Summary
When using the
WithBraintrust()extension method (the fallback instrumentation path — noBraintrustPipelineTransportinjected),ChatCompletionOptions.ReasoningEffortLevelis not captured inbraintrust.metadata. This is the primary execution-configuration parameter for OpenAI's o-series reasoning models (o1, o3, o3-mini, o4-mini), and its absence makes it impossible to understand or compare reasoning budget usage from Braintrust traces on this path.What is missing
InstrumentedChatClient.TagActivityFromApiObjects()(lines 271–294) builds thebraintrust.metadatatag from explicitChatCompletionOptionsproperties:ChatCompletionOptions.ReasoningEffortLevel(typeChatReasoningEffortLevel?, wire namereasoning_effort) is available in the OpenAI .NET SDK v2.9.1 (used by this repo) but is absent from this list.Which path is affected
reasoning_effortcaptured?BraintrustOpenAI.WrapOpenAI()(primary path —BraintrustPipelineTransportactive)TagActivityFromBaggagecopies all non-messagesrequest fields into metadataclient.WithBraintrust()/OpenAITelemetry.Wrap()(fallback path — no transport)TagActivityFromApiObjectsdoes not readReasoningEffortLevelUsers who adopt the extension-method path (e.g., integrating with an existing
OpenAIClient) will produce spans where the reasoning effort level is invisible in traces for all o-series model calls.Impact
ReasoningEffortLevelis the main knob for controlling reasoning token consumption on o1, o3, o3-mini, and o4-mini — directly affecting both latency and cost. Without it in metadata:reasoning_tokensgap is tracked in issue [bot] OpenAI instrumentation missing extended token usage details (cached_tokens, reasoning_tokens) #53; this is the complementary request-side gap).Braintrust docs status
The Braintrust OpenAI integration page at https://www.braintrust.dev/docs/integrations/ai-providers/openai does not enumerate the full set of captured request parameters. The pattern in this repo clearly intends to capture all significant generation parameters in metadata (temperature, max_tokens, tools, response_format, etc.), making the omission of
reasoning_effortinconsistent. Status: unclear (not explicitly documented as captured or excluded).Upstream sources
reasoning_effortas the primary configuration parameter for o-series models; valid values are"low","medium","high","none"ChatReasoningEffortLevel.Noneaddition, confirming the property predates v2.9.1ChatCompletionOptions.ReasoningEffortLevelproperty of typeChatReasoningEffortLevel?; wire-format name isreasoning_effortLocal files inspected
src/Braintrust.Sdk.OpenAI/InstrumentedChatClient.cs—TagActivityFromApiObjects()(lines 271–294): explicit metadata fields;ReasoningEffortLevelis absentsrc/Braintrust.Sdk.OpenAI/InstrumentedChatClient.cs—TagActivityFromBaggage()(lines 175–185): captures all request fields from raw JSON, so the primary path is unaffectedsrc/Braintrust.Sdk.OpenAI/BraintrustOpenAI.cs— documents both instrumentation paths (factory method vs. extension method)src/Braintrust.Sdk.OpenAI/Braintrust.Sdk.OpenAI.csproj— confirms OpenAI SDK v2.9.1 dependencytests/Braintrust.Sdk.OpenAI.Tests/BraintrustOpenAITest.cs— no test coverage for o-series /ReasoningEffortLevelscenarios