From 3dd53f97bd284b6dd97b2d6729b005ea644f0f97 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 23:47:18 +0000 Subject: [PATCH] feat: Include gen_ai.conversation.id in OTEL spans This change adds the `gen_ai.conversation.id` attribute to the OpenTelemetry spans for LLM calls, tool calls, and merged tool calls. This allows for better linking of messages within a conversation in AI evaluation platforms. The `gen_ai.conversation.id` attribute is populated with the existing session ID. This addresses the issue where each message in a conversation was not linked together when using the OTEL integration. --- internal/llminternal/base_flow.go | 4 ++-- internal/telemetry/telemetry.go | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/internal/llminternal/base_flow.go b/internal/llminternal/base_flow.go index 15937e23a..6f92d305f 100644 --- a/internal/llminternal/base_flow.go +++ b/internal/llminternal/base_flow.go @@ -406,7 +406,7 @@ func (f *Flow) handleFunctionCalls(ctx agent.InvocationContext, toolsDict map[st ev.Author = ctx.Agent().Name() ev.Branch = ctx.Branch() ev.Actions = *toolCtx.Actions() - telemetry.TraceToolCall(spans, curTool, fnCall.Args, ev) + telemetry.TraceToolCall(spans, ctx, curTool, fnCall.Args, ev) fnResponseEvents = append(fnResponseEvents, ev) } mergedEvent, err := mergeParallelFunctionResponseEvents(fnResponseEvents) @@ -415,7 +415,7 @@ func (f *Flow) handleFunctionCalls(ctx agent.InvocationContext, toolsDict map[st } // this is needed for debug traces of parallel calls spans := telemetry.StartTrace(ctx, "execute_tool (merged)") - telemetry.TraceMergedToolCalls(spans, mergedEvent) + telemetry.TraceMergedToolCalls(spans, ctx, mergedEvent) return mergedEvent, nil } diff --git a/internal/telemetry/telemetry.go b/internal/telemetry/telemetry.go index cc3f65c03..142c5d72b 100644 --- a/internal/telemetry/telemetry.go +++ b/internal/telemetry/telemetry.go @@ -58,6 +58,7 @@ const ( genAiToolCallID = "gen_ai.tool.call.id" genAiSystemName = "gen_ai.system" genAiRequestModelName = "gen_ai.request.model" + genAiConversationID = "gen_ai.conversation.id" gcpVertexAgentLLMRequestName = "gcp.vertex.agent.llm_request" gcpVertexAgentToolCallArgsName = "gcp.vertex.agent.tool_call_args" @@ -118,12 +119,13 @@ func StartTrace(ctx context.Context, traceName string) []trace.Span { } // TraceMergedToolCalls traces the tool execution events. -func TraceMergedToolCalls(spans []trace.Span, fnResponseEvent *session.Event) { +func TraceMergedToolCalls(spans []trace.Span, agentCtx agent.InvocationContext, fnResponseEvent *session.Event) { if fnResponseEvent == nil { return } for _, span := range spans { attributes := []attribute.KeyValue{ + attribute.String(genAiConversationID, agentCtx.Session().ID()), attribute.String(genAiOperationName, executeToolName), attribute.String(genAiToolName, mergeToolName), attribute.String(genAiToolDescription, mergeToolName), @@ -141,12 +143,13 @@ func TraceMergedToolCalls(spans []trace.Span, fnResponseEvent *session.Event) { } // TraceToolCall traces the tool execution events. -func TraceToolCall(spans []trace.Span, tool tool.Tool, fnArgs map[string]any, fnResponseEvent *session.Event) { +func TraceToolCall(spans []trace.Span, agentCtx agent.InvocationContext, tool tool.Tool, fnArgs map[string]any, fnResponseEvent *session.Event) { if fnResponseEvent == nil { return } for _, span := range spans { attributes := []attribute.KeyValue{ + attribute.String(genAiConversationID, agentCtx.Session().ID()), attribute.String(genAiOperationName, executeToolName), attribute.String(genAiToolName, tool.Name()), attribute.String(genAiToolDescription, tool.Description()), @@ -195,6 +198,7 @@ func TraceLLMCall(spans []trace.Span, agentCtx agent.InvocationContext, llmReque attribute.String(genAiRequestModelName, llmRequest.Model), attribute.String(gcpVertexAgentInvocationID, event.InvocationID), attribute.String(gcpVertexAgentSessionID, agentCtx.Session().ID()), + attribute.String(genAiConversationID, agentCtx.Session().ID()), attribute.String(gcpVertexAgentEventID, event.ID), attribute.String(gcpVertexAgentLLMRequestName, safeSerialize(llmRequestToTrace(llmRequest))), attribute.String(gcpVertexAgentLLMResponseName, safeSerialize(event.LLMResponse)),