Skip to content

Commit 4a533a1

Browse files
Achuth17pandego
authored andcommitted
feat(telemetry): add new gen_ai.agent.version span attribute
Link to Issue or Description of Change 1. Link to an existing issue (if applicable): Closes: #issue_number Related: #issue_number 2. Or, if no issue exists, describe the change: Problem: The agent's specific version wasn't being tracked in our telemetry data, limiting our ability to trace issues to specific agent versions. This change introduces the gen_ai.agent.version attribute to span context, defaulting to an empty string if omitted for backwards compatibility. Solution: We want to capture the specific version of an agent during execution by adding an optional version field to the base agent configurations (BaseAgent, BaseAgentConfig). This solution was chosen because exposing this field directly to OpenTelemetry span attributes (gen_ai.agent.version) ensures the version is automatically recorded alongside other existing metadata (like name and description) during invocation. Defaulting the value to an empty string ensures backwards compatibility without breaking existing agent implementations that do not specify a version. Testing Plan - Added test_trace_agent_invocation_with_version to verify that the gen_ai.agent.version attribute is correctly captured when agent.version is populated. - Updated existing telemetry span tests to ensure gen_ai.agent.version safely defaults to an empty string ('') when no version is provided. Unit Tests: - I have added or updated unit tests for my change. - All unit tests pass locally. Manual End-to-End (E2E) Tests: - Tested on Agent Engine and in a local deployment. Checklist [x] I have read the CONTRIBUTING.md document. [x] I have performed a self-review of my own code. [x] I have commented my code, particularly in hard-to-understand areas. [x] I have added tests that prove my fix is effective or that my feature works. [x] New and existing unit tests pass locally with my changes. [x] I have manually tested my changes end-to-end. [x] Any dependent changes have been merged and published in downstream modules. Additional context Add any other context or screenshots about the feature request here. Co-authored-by: Achuth Narayan Rajagopal <achuthr@google.com> PiperOrigin-RevId: 878835568
1 parent 4e0678a commit 4a533a1

File tree

4 files changed

+46
-0
lines changed

4 files changed

+46
-0
lines changed

src/google/adk/agents/base_agent.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ class MyAgent(BaseAgent):
115115
Agent name cannot be "user", since it's reserved for end-user's input.
116116
"""
117117

118+
version: str = ''
119+
"""The agent's version.
120+
121+
Version of the agent being invoked. Used to identify the Agent involved in telemetry.
122+
"""
123+
118124
description: str = ''
119125
"""Description about the agent's capability.
120126
@@ -680,6 +686,7 @@ def __create_kwargs(
680686

681687
kwargs: Dict[str, Any] = {
682688
'name': config.name,
689+
'version': config.version,
683690
'description': config.description,
684691
}
685692
if config.sub_agents:

src/google/adk/agents/base_agent_config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ class BaseAgentConfig(BaseModel):
5555

5656
name: str = Field(description='Required. The name of the agent.')
5757

58+
version: str = Field(
59+
default='', description='Optional. The version of the agent.'
60+
)
61+
5862
description: str = Field(
5963
default='', description='Optional. The description of the agent.'
6064
)

src/google/adk/telemetry/tracing.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@
8282

8383
USER_CONTENT_ELIDED = '<elided>'
8484

85+
GEN_AI_AGENT_VERSION = 'gen_ai.agent.version'
86+
8587
# Needed to avoid circular imports
8688
if TYPE_CHECKING:
8789
from ..agents.base_agent import BaseAgent
@@ -155,6 +157,7 @@ def trace_agent_invocation(
155157
span.set_attribute(GEN_AI_AGENT_DESCRIPTION, agent.description)
156158

157159
span.set_attribute(GEN_AI_AGENT_NAME, agent.name)
160+
span.set_attribute(GEN_AI_AGENT_VERSION, agent.version)
158161
span.set_attribute(GEN_AI_CONVERSATION_ID, ctx.session.id)
159162

160163

@@ -455,6 +458,7 @@ def use_generate_content_span(
455458
USER_ID: invocation_context.session.user_id,
456459
'gcp.vertex.agent.event_id': model_response_event.id,
457460
'gcp.vertex.agent.invocation_id': invocation_context.invocation_id,
461+
GEN_AI_AGENT_VERSION: invocation_context.agent.version,
458462
}
459463
if (
460464
_is_gemini_agent(invocation_context.agent)
@@ -489,6 +493,7 @@ async def use_inference_span(
489493
USER_ID: invocation_context.session.user_id,
490494
'gcp.vertex.agent.event_id': model_response_event.id,
491495
'gcp.vertex.agent.invocation_id': invocation_context.invocation_id,
496+
GEN_AI_AGENT_VERSION: invocation_context.agent.version,
492497
}
493498
if (
494499
_is_gemini_agent(invocation_context.agent)

tests/unittests/telemetry/test_spans.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from google.adk.models.llm_response import LlmResponse
2525
from google.adk.sessions.in_memory_session_service import InMemorySessionService
2626
from google.adk.telemetry.tracing import ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS
27+
from google.adk.telemetry.tracing import GEN_AI_AGENT_VERSION
2728
from google.adk.telemetry.tracing import trace_agent_invocation
2829
from google.adk.telemetry.tracing import trace_call_llm
2930
from google.adk.telemetry.tracing import trace_inference_result
@@ -119,6 +120,33 @@ async def test_trace_agent_invocation(mock_span_fixture):
119120
mock.call('gen_ai.operation.name', 'invoke_agent'),
120121
mock.call('gen_ai.agent.description', agent.description),
121122
mock.call('gen_ai.agent.name', agent.name),
123+
mock.call(GEN_AI_AGENT_VERSION, ''),
124+
mock.call(
125+
'gen_ai.conversation.id',
126+
invocation_context.session.id,
127+
),
128+
]
129+
mock_span_fixture.set_attribute.assert_has_calls(
130+
expected_calls, any_order=True
131+
)
132+
assert mock_span_fixture.set_attribute.call_count == len(expected_calls)
133+
134+
135+
@pytest.mark.asyncio
136+
async def test_trace_agent_invocation_with_version(mock_span_fixture):
137+
"""Test trace_agent_invocation sets span attributes correctly when version is provided."""
138+
agent = LlmAgent(name='test_llm_agent', model='gemini-pro')
139+
agent.description = 'Test agent description'
140+
agent.version = '1.0.0'
141+
invocation_context = await _create_invocation_context(agent)
142+
143+
trace_agent_invocation(mock_span_fixture, agent, invocation_context)
144+
145+
expected_calls = [
146+
mock.call('gen_ai.operation.name', 'invoke_agent'),
147+
mock.call('gen_ai.agent.description', agent.description),
148+
mock.call('gen_ai.agent.name', agent.name),
149+
mock.call(GEN_AI_AGENT_VERSION, agent.version),
122150
mock.call(
123151
'gen_ai.conversation.id',
124152
invocation_context.session.id,
@@ -767,6 +795,7 @@ async def test_generate_content_span(
767795

768796
mock_span.set_attributes.assert_called_once_with({
769797
GEN_AI_AGENT_NAME: invocation_context.agent.name,
798+
GEN_AI_AGENT_VERSION: '',
770799
GEN_AI_CONVERSATION_ID: invocation_context.session.id,
771800
USER_ID: invocation_context.session.user_id,
772801
'gcp.vertex.agent.event_id': 'event-123',
@@ -1087,6 +1116,7 @@ async def test_generate_content_span_with_experimental_semconv(
10871116

10881117
mock_span.set_attributes.assert_called_once_with({
10891118
GEN_AI_AGENT_NAME: invocation_context.agent.name,
1119+
GEN_AI_AGENT_VERSION: '',
10901120
GEN_AI_CONVERSATION_ID: invocation_context.session.id,
10911121
USER_ID: invocation_context.session.user_id,
10921122
'gcp.vertex.agent.event_id': 'event-123',

0 commit comments

Comments
 (0)