Skip to content

feat: OTEL GenAI semantic conventions + Braintrust.Sdk.Extensions.AI package#42

Open
Brendan Gooden (brendangooden) wants to merge 2 commits into
braintrustdata:mainfrom
brendangooden:feat/otel-genai-conventions-and-extensions-ai
Open

feat: OTEL GenAI semantic conventions + Braintrust.Sdk.Extensions.AI package#42
Brendan Gooden (brendangooden) wants to merge 2 commits into
braintrustdata:mainfrom
brendangooden:feat/otel-genai-conventions-and-extensions-ai

Conversation

@brendangooden
Copy link
Copy Markdown
Contributor

@brendangooden Brendan Gooden (brendangooden) commented Apr 13, 2026

Summary

  • Add gen_ai.tool.* OTEL attributes to execute_tool spans across AgentFramework and new Extensions.AI packages
  • Add gen_ai.* OTEL attributes to raw SDK packages (OpenAI, Anthropic) where no framework-level OTEL instrumentation exists
  • New Braintrust.Sdk.Extensions.AI package for instrumenting any IChatClient implementation

Architectural Rationale

Separation of concerns: Braintrust vs M.E.AI

Responsibility Owner Rationale
Standard gen_ai.* chat span attributes M.E.AI UseOpenTelemetry() Already ships 20+ gen_ai.* attrs per semconv v1.40
braintrust.* dashboard attributes Braintrust SDK Braintrust backend requires these for dashboard rendering (input/output panels, span typing, metrics, project routing)
execute_tool child spans with gen_ai.tool.* Braintrust SDK (for now) M.E.AI has this on main (post 10.4.0) but it's unreleased. Braintrust fills the gap for current 10.4.x users
Raw SDK instrumentation (OpenAI/Anthropic) Braintrust SDK No framework-level OTEL for raw SDK ChatClient/IMessageService

Why braintrust.* attributes are needed

The Braintrust backend specifically parses braintrust.* attributes to render the dashboard:

  • braintrust.parent — routes spans to the correct project (without it, spans are dropped)
  • braintrust.input_json / braintrust.output_json — renders Input/Output panels in span detail
  • braintrust.span_attributes — identifies span type for UI grouping
  • braintrust.metrics.* — renders token counts and timing metrics

M.E.AI's gen_ai.* spans arrive at Braintrust but render as empty/untyped without corresponding braintrust.* attributes. See issue #43 for a proposal to have the backend consume gen_ai.* natively.

M.E.AI execute_tool spans — timeline note

dotnet/extensions main branch already has execute_tool spans in FunctionInvocationProcessor.cs (added March 11, 2026), but this is unreleased (post v10.4.0 tag). When the next M.E.AI release ships:

  • UseBraintrustFunctionTracing() becomes redundant for IChatClient users getting execute_tool spans natively
  • Braintrust should consider deprecating function tracing middleware for IChatClient and updating docs to recommend M.E.AI's native tool spans
  • Function tracing will still be needed for raw OpenAI/Anthropic SDK users

Recommended pipeline for IChatClient users

var client = new ChatClientBuilder(innerClient)
    .UseOpenTelemetry()              // standard gen_ai.* attrs (from M.E.AI)
    .UseBraintrustTracing()          // braintrust.* attrs (for dashboard)
    .UseBraintrustFunctionTracing()  // execute_tool spans (until M.E.AI ships native support)
    .Build();

Changes

1. OTEL GenAI tool span attributes (AgentFramework)

Added to BraintrustFunctionMiddleware execute_tool spans:

  • gen_ai.operation.name = "execute_tool"
  • gen_ai.tool.name
  • gen_ai.tool.call.arguments (alongside braintrust.input_json)
  • gen_ai.tool.call.result (alongside braintrust.output_json)

2. OTEL GenAI attributes on raw SDK packages

OpenAI (InstrumentedChatClient): gen_ai.operation.name, gen_ai.provider.name, gen_ai.input/output.messages, gen_ai.usage.input/output_tokens

Anthropic (InstrumentedMessageService): same attributes

These raw SDKs have no framework-level OTEL instrumentation, so Braintrust emits both namespaces.

3. New Braintrust.Sdk.Extensions.AI package

Instruments any IChatClient (OpenAI, Azure, Ollama) via M.E.AI middleware:

  • BraintrustChatClient — delegating IChatClient (sync + streaming), emits braintrust.* only
  • BraintrustFunctionMiddleware — execute_tool spans with gen_ai.tool.* + braintrust.*
  • Extension methods: UseBraintrustTracing, UseBraintrustFunctionTracing, UseAllBraintrustTracing
  • No dependency on Microsoft.Agents.AI

Package selection guide

Package Use When
Braintrust.Sdk.Extensions.AI (new) Any IChatClient provider (OpenAI/Azure/Ollama via adapter)
Braintrust.Sdk.AgentFramework Agent Framework ChatClientAgent orchestration
Braintrust.Sdk.OpenAI Raw OpenAI ChatClient (non-IChatClient)
Braintrust.Sdk.Anthropic Raw Anthropic IMessageService

Test plan

  • AgentFramework tests: 16 passed (new gen_ai.tool.* assertions on function spans)
  • OpenAI tests: 9 passed (new gen_ai.* assertions)
  • Anthropic tests: 7 passed (new gen_ai.* assertions)
  • Extensions.AI tests: 6 passed (new package)
  • Core SDK tests: 105 passed (no regressions)
  • ExtensionsAIInstrumentation example builds
  • Verify traces render correctly in Braintrust dashboard

🤖 Generated with Claude Code

@brendangooden Brendan Gooden (brendangooden) force-pushed the feat/otel-genai-conventions-and-extensions-ai branch from 0b1f122 to a074fa7 Compare April 13, 2026 22:53
@socket-security
Copy link
Copy Markdown

socket-security Bot commented Apr 13, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedmicrosoft.extensions.ai.openai@​10.4.110010090100100
Addedmicrosoft.net.test.sdk@​17.12.010010090100100
Addedxunit@​2.9.310010090100100
Addedxunit.runner.visualstudio@​3.0.110010090100100

View full report

Add gen_ai.* attributes where Braintrust fills gaps no framework covers:

- Function/tool spans: gen_ai.operation.name ("execute_tool"),
  gen_ai.tool.name, gen_ai.tool.call.arguments, gen_ai.tool.call.result
  (M.E.AI's UseOpenTelemetry() does not emit dedicated execute_tool spans)

- OpenAI raw SDK: gen_ai.operation.name, gen_ai.provider.name,
  gen_ai.input/output.messages, gen_ai.usage.input/output_tokens
  (no framework-level OTEL instrumentation for raw ChatClient)

- Anthropic raw SDK: same gen_ai.* attributes
  (no framework-level OTEL instrumentation for raw IMessageService)

IChatClient chat/agent spans intentionally omit gen_ai.* — users should
stack UseOpenTelemetry() from M.E.AI for standard OTEL GenAI attributes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…mentation

New package that instruments any IChatClient implementation via
Microsoft.Extensions.AI middleware pattern. Works with OpenAI,
Azure OpenAI, Ollama, and any other IChatClient provider.

Emits only braintrust.* attributes on chat/LLM spans (users should
stack UseOpenTelemetry() for standard gen_ai.* attributes). Emits
gen_ai.tool.* on execute_tool spans — the gap M.E.AI doesn't cover.

Includes:
- BraintrustChatClient: delegating IChatClient with LLM tracing
- BraintrustFunctionMiddleware: tool/function call tracing
- Extension methods: UseBraintrustTracing, UseBraintrustFunctionTracing,
  UseAllBraintrustTracing
- Full test suite (6 tests)
- Example project (ExtensionsAIInstrumentation)
- Updated README with package selection guidance

Also adds SkipVersionVerification property to Directory.Build.targets.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant