Skip to content

[bot] OpenAI fallback-path instrumentation missing reasoning_effort from request metadata #65

Description

@braintrust-bot

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.csTagActivityFromApiObjects() (lines 271–294): explicit metadata fields; ReasoningEffortLevel is absent
  • src/Braintrust.Sdk.OpenAI/InstrumentedChatClient.csTagActivityFromBaggage() (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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions