From 48a3e977227db9832b966dc89a797c43aea48b36 Mon Sep 17 00:00:00 2001 From: yashvanthange Date: Sat, 22 Aug 2026 12:37:56 +0530 Subject: [PATCH 1/2] .NET: expose OpenTelemetryAgent.DefaultSourceName The default ActivitySource name lives on the internal OpenTelemetryConsts class, so consumers cannot reference it when configuring a TracerProvider and must hardcode the literal "Experimental.Microsoft.Agents.AI" instead. ADR 0003 documents AgentOpenTelemetryConsts.DefaultSourceName for this, a type that no longer exists after the rename in #356. Expose the source name as a public const on OpenTelemetryAgent, the type that emits the spans, rather than making the whole constants class public. That keeps the gen_ai.* attribute keys internal, matching the Microsoft.Extensions.AI precedent, while making the documented AddSource call compile. Update the ADR snippet to the constant that now exists. --- .../0003-agent-opentelemetry-instrumentation.md | 2 +- dotnet/src/Microsoft.Agents.AI/OpenTelemetryAgent.cs | 10 ++++++++++ .../OpenTelemetryAgentTests.cs | 10 ++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/decisions/0003-agent-opentelemetry-instrumentation.md b/docs/decisions/0003-agent-opentelemetry-instrumentation.md index 863387b5cbd..61d4d2f0803 100644 --- a/docs/decisions/0003-agent-opentelemetry-instrumentation.md +++ b/docs/decisions/0003-agent-opentelemetry-instrumentation.md @@ -127,7 +127,7 @@ The implementation is validated through: ```csharp // Create TracerProvider using var tracerProvider = Sdk.CreateTracerProviderBuilder() - .AddSource(AgentOpenTelemetryConsts.DefaultSourceName) + .AddSource(OpenTelemetryAgent.DefaultSourceName) .AddConsoleExporter() .Build(); diff --git a/dotnet/src/Microsoft.Agents.AI/OpenTelemetryAgent.cs b/dotnet/src/Microsoft.Agents.AI/OpenTelemetryAgent.cs index 90c0ec59ebb..877fea103d1 100644 --- a/dotnet/src/Microsoft.Agents.AI/OpenTelemetryAgent.cs +++ b/dotnet/src/Microsoft.Agents.AI/OpenTelemetryAgent.cs @@ -41,6 +41,16 @@ public sealed class OpenTelemetryAgent : DelegatingAIAgent, IDisposable // inner agent not directly but rather via OpenTelemetryChatClient, which wraps a ForwardingChatClient that in turn // calls back into the inner agent. + /// + /// The default name used by when no source name + /// is supplied to the constructor. + /// + /// + /// Pass this value to the tracing pipeline (for example, TracerProviderBuilder.AddSource) to subscribe to + /// the spans emitted by agents that use the default source name, instead of hardcoding the literal name. + /// + public const string DefaultSourceName = OpenTelemetryConsts.DefaultSourceName; + /// The providing the bulk of the telemetry. private readonly OpenTelemetryChatClient _otelClient; /// The provider name extracted from . diff --git a/dotnet/tests/Microsoft.Agents.AI.UnitTests/OpenTelemetryAgentTests.cs b/dotnet/tests/Microsoft.Agents.AI.UnitTests/OpenTelemetryAgentTests.cs index 79e3418b862..9686fc3beef 100644 --- a/dotnet/tests/Microsoft.Agents.AI.UnitTests/OpenTelemetryAgentTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.UnitTests/OpenTelemetryAgentTests.cs @@ -873,6 +873,16 @@ public async Task AutoWireChatClient_UserFactoryAddsOwnOTel_CoexistsWithBelowFic Assert.Equal(2, activities.Count(a => string.Equals(a.GetTagItem("gen_ai.operation.name") as string, "chat", StringComparison.Ordinal))); } + [Fact] + public void DefaultSourceName_MatchesSourceOfEmittedActivities() + { + // Callers pass this constant to TracerProviderBuilder.AddSource, so it must stay in sync with the + // source name the agent actually emits spans under; comparing against the literal guards the rename. + + // Arrange & Act & Assert + Assert.Equal("Experimental.Microsoft.Agents.AI", OpenTelemetryAgent.DefaultSourceName); + } + [Theory] [InlineData(null)] [InlineData("")] From e9d0aa352bcd731fcd069e8dec1ce46d2b5bf813 Mon Sep 17 00:00:00 2001 From: yashvanthange Date: Sat, 22 Aug 2026 13:15:12 +0530 Subject: [PATCH 2/2] .NET: read DefaultSourceName at run time instead of inlining it A public const is baked into each consumer assembly at compile time, so a consumer built against one package version would keep subscribing to the old literal after upgrading to a version that changed the source name, and would silently stop receiving spans. That is the exact failure this API is meant to remove, so expose the value as a static property that is read at run time. Rename the test to describe what it actually asserts and point at the test that verifies emitted activities use the same source name. --- dotnet/src/Microsoft.Agents.AI/OpenTelemetryAgent.cs | 10 ++++++---- .../OpenTelemetryAgentTests.cs | 7 ++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/dotnet/src/Microsoft.Agents.AI/OpenTelemetryAgent.cs b/dotnet/src/Microsoft.Agents.AI/OpenTelemetryAgent.cs index 877fea103d1..c88b0086870 100644 --- a/dotnet/src/Microsoft.Agents.AI/OpenTelemetryAgent.cs +++ b/dotnet/src/Microsoft.Agents.AI/OpenTelemetryAgent.cs @@ -42,14 +42,16 @@ public sealed class OpenTelemetryAgent : DelegatingAIAgent, IDisposable // calls back into the inner agent. /// - /// The default name used by when no source name - /// is supplied to the constructor. + /// Gets the default name used by when no source + /// name is supplied to the constructor. /// /// /// Pass this value to the tracing pipeline (for example, TracerProviderBuilder.AddSource) to subscribe to - /// the spans emitted by agents that use the default source name, instead of hardcoding the literal name. + /// the spans emitted by agents that use the default source name, instead of hardcoding the literal name. This is + /// a property rather than a constant so that the value is read at run time: a consumer that upgrades the package + /// picks up the current source name without recompiling. /// - public const string DefaultSourceName = OpenTelemetryConsts.DefaultSourceName; + public static string DefaultSourceName => OpenTelemetryConsts.DefaultSourceName; /// The providing the bulk of the telemetry. private readonly OpenTelemetryChatClient _otelClient; diff --git a/dotnet/tests/Microsoft.Agents.AI.UnitTests/OpenTelemetryAgentTests.cs b/dotnet/tests/Microsoft.Agents.AI.UnitTests/OpenTelemetryAgentTests.cs index 9686fc3beef..e6a1c67077a 100644 --- a/dotnet/tests/Microsoft.Agents.AI.UnitTests/OpenTelemetryAgentTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.UnitTests/OpenTelemetryAgentTests.cs @@ -874,10 +874,11 @@ public async Task AutoWireChatClient_UserFactoryAddsOwnOTel_CoexistsWithBelowFic } [Fact] - public void DefaultSourceName_MatchesSourceOfEmittedActivities() + public void DefaultSourceName_ReturnsDocumentedSourceName() { - // Callers pass this constant to TracerProviderBuilder.AddSource, so it must stay in sync with the - // source name the agent actually emits spans under; comparing against the literal guards the rename. + // Callers pass this to TracerProviderBuilder.AddSource, so it must stay in sync with the source name the + // agent emits spans under, which Ctor_NullOrWhitespaceSourceName_AutoWiredChatClientUsesDefaultSource_Async + // pins to the same literal. Comparing against the literal here guards a rename of the internal constant. // Arrange & Act & Assert Assert.Equal("Experimental.Microsoft.Agents.AI", OpenTelemetryAgent.DefaultSourceName);