Skip to content

[bot] AgentFramework: IEmbeddingGenerator calls are not instrumented #73

Description

@braintrust-bot

Summary

Braintrust.Sdk.AgentFramework instruments IChatClient calls via BraintrustChatClientMiddleware (a DelegatingChatClient subclass) and exposes ChatClientBuilder.UseBraintrustLLMTracing() / UseBraintrustTracing() extension methods. However, the package provides no equivalent middleware for IEmbeddingGenerator<TInput, TEmbedding>, which is the parallel Microsoft.Extensions.AI abstraction for vector embedding generation. All embedding generation calls made through the M.E.AI abstraction layer produce zero Braintrust spans.

What is missing

Microsoft.Extensions.AI (v10.4.1, the version used by this repo) provides a full middleware pipeline for IEmbeddingGenerator<TInput, TEmbedding> that directly mirrors the IChatClient middleware pattern:

IChatClient surface (✅ instrumented) IEmbeddingGenerator surface (❌ not instrumented)
DelegatingChatClient DelegatingEmbeddingGenerator<TInput, TEmbedding>
ChatClientBuilder.Use(...) EmbeddingGeneratorBuilder<TInput, TEmbedding>.Use(...)
ChatClientBuilder.UseBraintrustLLMTracing(...) (missing) EmbeddingGeneratorBuilder<TInput, TEmbedding>.UseBraintrustEmbeddingTracing(...)

The core instrumentation method that needs to be overridden is:

Task<GeneratedEmbeddings<TEmbedding>> GenerateAsync(
    IEnumerable<TInput> values,
    EmbeddingGenerationOptions? options = null,
    CancellationToken cancellationToken = default)

A Braintrust embedding generator middleware would create a span around each GenerateAsync call and capture:

  • Input text values (when captureMessageContent = true)
  • Response model ID from EmbeddingGeneratorMetadata
  • Token usage (input tokens and total tokens — the OpenAI embeddings API returns these)
  • Duration / time_to_first_token equivalent

The pattern for implementing this is documented by Microsoft and directly parallels how BraintrustChatClientMiddleware wraps IChatClient:

// Example of what the middleware would look like
internal sealed class BraintrustEmbeddingGeneratorMiddleware<TInput, TEmbedding>
    : DelegatingEmbeddingGenerator<TInput, TEmbedding>
    where TEmbedding : Embedding
{
    public override async Task<GeneratedEmbeddings<TEmbedding>> GenerateAsync(
        IEnumerable<TInput> values,
        EmbeddingGenerationOptions? options = null,
        CancellationToken cancellationToken = default)
    {
        using var activity = _activitySource.StartActivity("Embedding Generation", ActivityKind.Client);
        // ... span tagging and delegation
    }
}

Impact

Users who generate embeddings through the M.E.AI abstraction layer — which is the recommended cross-provider approach, and is implemented by OpenAI (Microsoft.Extensions.AI.OpenAI), OllamaSharp, Azure OpenAI, and others — get no trace visibility. This is a common RAG and semantic search pattern.

The existing BraintrustAgentFramework integration instruments chat calls but silently ignores all embedding calls, creating blind spots in traces for applications that combine both.

Braintrust docs status

not_found — the Braintrust C# SDK integrations page lists the Microsoft Agent Framework integration but mentions only chat client tracing. No documentation confirms or denies IEmbeddingGenerator instrumentation support.

Upstream sources

Local files inspected

  • src/Braintrust.Sdk.AgentFramework/BraintrustAgentFramework.cs — exposes UseBraintrustLLMTracing, UseBraintrustFunctionTracing, UseBraintrustTracing for ChatClientBuilder and WithBraintrustAgentTracing for AIAgent; no embedding generator extension methods
  • src/Braintrust.Sdk.AgentFramework/BraintrustChatClientMiddleware.cs — reference implementation of DelegatingChatClient that could be mirrored for DelegatingEmbeddingGenerator
  • src/Braintrust.Sdk.AgentFramework/SpanTagHelper.cs — shared span helpers; SetTokenMetrics would be usable for embedding token counts
  • src/Braintrust.Sdk.AgentFramework/Braintrust.Sdk.AgentFramework.csprojMicrosoft.Extensions.AI v10.4.1 (includes DelegatingEmbeddingGenerator and EmbeddingGeneratorBuilder)

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