Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,13 @@ private static void AddToolDetails(
Dictionary<string, object?> attributes,
ToolCallDetails toolCallDetails)
{
var (toolName, arguments, toolCallId, description, toolType, endpoint) = toolCallDetails;
var (toolName, arguments, toolCallId, description, toolType, endpoint, toolServerName) = toolCallDetails;
AddIfNotNull(attributes, OpenTelemetryConstants.GenAiToolNameKey, toolName);
AddIfNotNull(attributes, OpenTelemetryConstants.GenAiToolArgumentsKey, arguments);
AddIfNotNull(attributes, OpenTelemetryConstants.GenAiToolCallIdKey, toolCallId);
AddIfNotNull(attributes, OpenTelemetryConstants.GenAiToolDescriptionKey, description);
AddIfNotNull(attributes, OpenTelemetryConstants.GenAiToolTypeKey, toolType);
AddIfNotNull(attributes, OpenTelemetryConstants.GenAiToolServerNameKey, toolServerName);
if (endpoint != null)
{
AddIfNotNull(attributes, OpenTelemetryConstants.ServerAddressKey, endpoint.Host);
Expand Down
18 changes: 15 additions & 3 deletions src/Observability/Runtime/Tracing/Contracts/ToolCallDetails.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,23 @@ public sealed class ToolCallDetails : IEquatable<ToolCallDetails>
/// <param name="description">Optional description of the tool call.</param>
/// <param name="toolType">Optional type classification for the tool.</param>
/// <param name="endpoint">Optional endpoint for remote tool execution.</param>
/// <param name="toolServerName">Optional server name for the tool.</param>
public ToolCallDetails(
string toolName,
string? arguments,
string? toolCallId = null,
string? description = null,
string? toolType = null,
Uri? endpoint = null)
Uri? endpoint = null,
string? toolServerName = null)
{
ToolName = toolName;
Arguments = arguments;
ToolCallId = toolCallId;
Description = description;
ToolType = toolType;
Endpoint = endpoint;
ToolServerName = toolServerName;
}

/// <summary>
Expand Down Expand Up @@ -66,6 +69,11 @@ public ToolCallDetails(
/// </summary>
public Uri? Endpoint { get; }

/// <summary>
/// Gets the server name associated with the tool, when provided.
/// </summary>
public string? ToolServerName { get; }

/// <summary>
/// Deconstructs this instance into individual tool call components.
/// </summary>
Expand All @@ -75,14 +83,16 @@ public ToolCallDetails(
/// <param name="description">Receives the human-readable description.</param>
/// <param name="toolType">Receives the type hint.</param>
/// <param name="endpoint">Receives the endpoint.</param>
public void Deconstruct(out string toolName, out string? arguments, out string? toolCallId, out string? description, out string? toolType, out Uri? endpoint)
/// <param name="toolServerName">Receives the tool server name.</param>
public void Deconstruct(out string toolName, out string? arguments, out string? toolCallId, out string? description, out string? toolType, out Uri? endpoint, out string? toolServerName)
{
toolName = ToolName;
arguments = Arguments;
toolCallId = ToolCallId;
description = Description;
toolType = ToolType;
endpoint = Endpoint;
toolServerName = ToolServerName;
}

/// <inheritdoc/>
Expand All @@ -98,7 +108,8 @@ public bool Equals(ToolCallDetails? other)
string.Equals(ToolCallId, other.ToolCallId, StringComparison.Ordinal) &&
string.Equals(Description, other.Description, StringComparison.Ordinal) &&
string.Equals(ToolType, other.ToolType, StringComparison.Ordinal) &&
EqualityComparer<Uri?>.Default.Equals(Endpoint, other.Endpoint);
EqualityComparer<Uri?>.Default.Equals(Endpoint, other.Endpoint) &&
string.Equals(ToolServerName, other.ToolServerName, StringComparison.Ordinal);
}

/// <inheritdoc/>
Expand All @@ -119,6 +130,7 @@ public override int GetHashCode()
hash = (hash * 31) + (Description != null ? StringComparer.Ordinal.GetHashCode(Description) : 0);
hash = (hash * 31) + (ToolType != null ? StringComparer.Ordinal.GetHashCode(ToolType) : 0);
hash = (hash * 31) + EqualityComparer<Uri?>.Default.GetHashCode(Endpoint);
hash = (hash * 31) + (ToolServerName != null ? StringComparer.Ordinal.GetHashCode(ToolServerName) : 0);
return hash;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,13 @@ private ExecuteToolScope(ToolCallDetails details, AgentDetails agentDetails, Ten
conversationId: conversationId,
sourceMetadata: sourceMetadata)
{
var (toolName, arguments, toolCallId, description, toolType, endpoint) = details;
var (toolName, arguments, toolCallId, description, toolType, endpoint, toolServerName) = details;
SetTagMaybe(OpenTelemetryConstants.GenAiToolNameKey, toolName);
SetTagMaybe(OpenTelemetryConstants.GenAiToolArgumentsKey, arguments);
SetTagMaybe(OpenTelemetryConstants.GenAiToolTypeKey, toolType);
SetTagMaybe(OpenTelemetryConstants.GenAiToolCallIdKey, toolCallId);
SetTagMaybe(OpenTelemetryConstants.GenAiToolDescriptionKey, description);
SetTagMaybe(OpenTelemetryConstants.GenAiToolServerNameKey, toolServerName);
SetTagMaybe(OpenTelemetryConstants.ThreatDiagnosticsSummaryKey, threatDiagnosticsSummary?.ToJson());

if (endpoint !=null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ public enum OperationNames
/// The GenAI tool type key.
/// </summary>
public const string GenAiToolTypeKey = "gen_ai.tool.type";

/// <summary>
/// The GenAI tool server name key.
/// </summary>
public const string GenAiToolServerNameKey = "gen_ai.tool.server.name";
#endregion

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ public async Task AddTracing_And_ExecuteToolScope_ExporterMakesExpectedRequest()
toolCallId: "call-456",
description: "Test tool call description",
toolType: "custom-type",
endpoint: endpoint);
endpoint: endpoint,
toolServerName: "test-tool-server");

var expectedThreatDiagnosticsSummary = new ThreatDiagnosticsSummary(
blockAction: false,
Expand Down Expand Up @@ -190,6 +191,7 @@ public async Task AddTracing_And_ExecuteToolScope_ExporterMakesExpectedRequest()
this.GetAttribute(attributes, "gen_ai.tool.call.id").Should().Be(toolCallDetails.ToolCallId);
this.GetAttribute(attributes, "gen_ai.tool.description").Should().Be(toolCallDetails.Description);
this.GetAttribute(attributes, "gen_ai.tool.type").Should().Be(toolCallDetails.ToolType);
this.GetAttribute(attributes, "gen_ai.tool.server.name").Should().Be(toolCallDetails.ToolServerName);
this.GetAttribute(attributes, "server.address").Should().Be(endpoint.Host);
this.GetAttribute(attributes, "server.port").Should().Be(endpoint.Port.ToString());
this.GetAttribute(attributes, "gen_ai.event.content").Should().Be("Tool response content");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public void Build_WithFullToolDetails_IncludesAllToolAttributes()
{
// Arrange
var endpoint = new Uri("https://example.com:7071");
var toolDetails = new ToolCallDetails("toolB", "{b:2}", "call-123", "Test tool", "function", endpoint);
var toolDetails = new ToolCallDetails("toolB", "{b:2}", "call-123", "Test tool", "function", endpoint, "my-tool-server");
var agent = new AgentDetails("agent-2", "AgentTwo", "Desc", agentAUID: "auid", agentUPN: "upn@example.com", agentBlueprintId: "bp-1");
var tenant = new TenantDetails(Guid.NewGuid());
var conversationId = "conv-full";
Expand All @@ -64,6 +64,7 @@ public void Build_WithFullToolDetails_IncludesAllToolAttributes()
attrs.Should().ContainKey(OpenTelemetryConstants.GenAiToolCallIdKey).WhoseValue.Should().Be("call-123");
attrs.Should().ContainKey(OpenTelemetryConstants.GenAiToolDescriptionKey).WhoseValue.Should().Be("Test tool");
attrs.Should().ContainKey(OpenTelemetryConstants.GenAiToolTypeKey).WhoseValue.Should().Be("function");
attrs.Should().ContainKey(OpenTelemetryConstants.GenAiToolServerNameKey).WhoseValue.Should().Be("my-tool-server");
attrs.Should().ContainKey(OpenTelemetryConstants.ServerAddressKey).WhoseValue.Should().Be("example.com");
attrs.Should().ContainKey(OpenTelemetryConstants.ServerPortKey).WhoseValue.Should().Be(7071);
attrs.Should().ContainKey(OpenTelemetryConstants.GenAiAgentAUIDKey).WhoseValue.Should().Be("auid");
Expand Down Expand Up @@ -153,6 +154,7 @@ public void Build_WithNullOptionalParameters_OmitsThoseAttributes()
data.Attributes.Should().NotContainKey(OpenTelemetryConstants.GenAiToolCallIdKey);
data.Attributes.Should().NotContainKey(OpenTelemetryConstants.GenAiToolDescriptionKey);
data.Attributes.Should().NotContainKey(OpenTelemetryConstants.GenAiToolTypeKey);
data.Attributes.Should().NotContainKey(OpenTelemetryConstants.GenAiToolServerNameKey);
data.Attributes.Should().ContainKey(OpenTelemetryConstants.GenAiConversationIdKey).WhoseValue.Should().Be(conversationId);
data.Attributes.Should().NotContainKey(OpenTelemetryConstants.GenAiEventContent);
}
Expand Down Expand Up @@ -201,7 +203,7 @@ public void Build_WithAllParameters_SetsAllExpectedAttributes()
{
// Arrange
var endpoint = new Uri("https://example.org:6060");
var toolDetails = new ToolCallDetails("toolJ", "{x:1}", "call-999", "Full tool", "extension", endpoint);
var toolDetails = new ToolCallDetails("toolJ", "{x:1}", "call-999", "Full tool", "extension", endpoint, "full-tool-server");
var agent = new AgentDetails("agent-10", "AgentTen", "Desc", agentAUID: "auid10", agentUPN: "upn10@example.com", agentBlueprintId: "bp-10");
var tenant = new TenantDetails(Guid.NewGuid());
var conversationId = "conv-all";
Expand All @@ -228,6 +230,7 @@ public void Build_WithAllParameters_SetsAllExpectedAttributes()
attrs.Should().ContainKey(OpenTelemetryConstants.GenAiToolCallIdKey);
attrs.Should().ContainKey(OpenTelemetryConstants.GenAiToolDescriptionKey);
attrs.Should().ContainKey(OpenTelemetryConstants.GenAiToolTypeKey);
attrs.Should().ContainKey(OpenTelemetryConstants.GenAiToolServerNameKey).WhoseValue.Should().Be("full-tool-server");
attrs.Should().ContainKey(OpenTelemetryConstants.GenAiConversationIdKey);
attrs.Should().ContainKey(OpenTelemetryConstants.GenAiEventContent);
data.StartTime.Should().Be(start);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,4 +207,26 @@ public void RecordThreatDiagnosticsSummary_SetsTagCorrectly()
tagValue.Should().Contain("\"reason\":\"Blocked due to policy violation.\"");
tagValue.Should().Contain("data-loss-prevention");
}

[TestMethod]
public void Start_ToolServerName_IsSetCorrectly()
{
// Arrange
const string expectedToolServerName = "test-tool-server";
var toolCallDetails = new ToolCallDetails(
toolName: "TestTool",
arguments: "args",
toolServerName: expectedToolServerName);
var agentDetails = Util.GetAgentDetails();
var tenantDetails = Util.GetTenantDetails();

// Act
var activity = ListenForActivity(() =>
{
using var scope = ExecuteToolScope.Start(toolCallDetails, agentDetails, tenantDetails);
});

// Assert
activity.ShouldHaveTag(OpenTelemetryConstants.GenAiToolServerNameKey, expectedToolServerName);
}
}
Loading