From 5cc3a69877ac767510374df956238160f2e6700a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 17:02:42 +0000 Subject: [PATCH 1/3] Initial plan From e2278bfc0bd4fc7283a7e71efe76c46e55492f83 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 17:05:29 +0000 Subject: [PATCH 2/3] Add gen_ai.caller.agent.type attribute support (matching Node.js PR #187) Co-authored-by: nikhilNava <211831449+nikhilNava@users.noreply.github.com> --- .../observability/core/invoke_agent_scope.py | 5 +++ .../core/trace_processor/util.py | 1 + .../core/test_invoke_agent_scope.py | 35 +++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/invoke_agent_scope.py b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/invoke_agent_scope.py index 9dc30067..f9bf82ee 100644 --- a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/invoke_agent_scope.py +++ b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/invoke_agent_scope.py @@ -11,6 +11,7 @@ GEN_AI_CALLER_AGENT_ID_KEY, GEN_AI_CALLER_AGENT_NAME_KEY, GEN_AI_CALLER_AGENT_TENANT_ID_KEY, + GEN_AI_CALLER_AGENT_TYPE_KEY, GEN_AI_CALLER_AGENT_UPN_KEY, GEN_AI_CALLER_AGENT_USER_CLIENT_IP, GEN_AI_CALLER_AGENT_USER_ID_KEY, @@ -138,6 +139,10 @@ def __init__( if caller_agent_details: self.set_tag_maybe(GEN_AI_CALLER_AGENT_NAME_KEY, caller_agent_details.agent_name) self.set_tag_maybe(GEN_AI_CALLER_AGENT_ID_KEY, caller_agent_details.agent_id) + self.set_tag_maybe( + GEN_AI_CALLER_AGENT_TYPE_KEY, + caller_agent_details.agent_type.value if caller_agent_details.agent_type else None, + ) self.set_tag_maybe( GEN_AI_CALLER_AGENT_APPLICATION_ID_KEY, caller_agent_details.agent_blueprint_id ) diff --git a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/trace_processor/util.py b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/trace_processor/util.py index d33bcab3..fa50a110 100644 --- a/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/trace_processor/util.py +++ b/libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/trace_processor/util.py @@ -41,6 +41,7 @@ # Caller Agent (A2A) attributes consts.GEN_AI_CALLER_AGENT_ID_KEY, # gen_ai.caller.agent.id consts.GEN_AI_CALLER_AGENT_NAME_KEY, # gen_ai.caller.agent.name + consts.GEN_AI_CALLER_AGENT_TYPE_KEY, # gen_ai.caller.agent.type consts.GEN_AI_CALLER_AGENT_USER_ID_KEY, # gen_ai.caller.agent.userid consts.GEN_AI_CALLER_AGENT_UPN_KEY, # gen_ai.caller.agent.upn consts.GEN_AI_CALLER_AGENT_TENANT_ID_KEY, # gen_ai.caller.agent.tenantid diff --git a/tests/observability/core/test_invoke_agent_scope.py b/tests/observability/core/test_invoke_agent_scope.py index 7541e221..d5b6bed7 100644 --- a/tests/observability/core/test_invoke_agent_scope.py +++ b/tests/observability/core/test_invoke_agent_scope.py @@ -21,12 +21,14 @@ ) from microsoft_agents_a365.observability.core.config import _telemetry_manager from microsoft_agents_a365.observability.core.constants import ( + GEN_AI_CALLER_AGENT_TYPE_KEY, GEN_AI_CALLER_AGENT_USER_CLIENT_IP, GEN_AI_EXECUTION_SOURCE_DESCRIPTION_KEY, GEN_AI_EXECUTION_SOURCE_NAME_KEY, GEN_AI_EXECUTION_TYPE_KEY, GEN_AI_INPUT_MESSAGES_KEY, ) +from microsoft_agents_a365.observability.core.models.agent_type import AgentType from microsoft_agents_a365.observability.core.models.caller_details import CallerDetails from microsoft_agents_a365.observability.core.opentelemetry_scope import OpenTelemetryScope from opentelemetry.sdk.trace.export import SimpleSpanProcessor @@ -94,6 +96,7 @@ def setUpClass(cls): agent_upn="agent@contoso.com", tenant_id="tenant-789", agent_client_ip="192.168.1.100", + agent_type=AgentType.DECLARATIVE_AGENT, ) def setUp(self): @@ -232,6 +235,38 @@ def test_caller_agent_client_ip_in_scope(self): span_attributes[GEN_AI_CALLER_AGENT_USER_CLIENT_IP], "192.168.1.100" ) + def test_caller_agent_type_in_scope(self): + """Test that caller agent type is properly set when creating InvokeAgentScope.""" + # Set up tracer to capture spans + span_exporter = InMemorySpanExporter() + tracer_provider = get_tracer_provider() + tracer_provider.add_span_processor(SimpleSpanProcessor(span_exporter)) + + # Create scope with caller agent details that include agent_type + scope = InvokeAgentScope.start( + invoke_agent_details=self.invoke_details, + tenant_details=self.tenant_details, + caller_agent_details=self.caller_agent_details, # Contains agent_type=AgentType.DECLARATIVE_AGENT + ) + + if scope is not None: + # Verify the caller agent details contain the expected type + self.assertEqual(self.caller_agent_details.agent_type, AgentType.DECLARATIVE_AGENT) + scope.dispose() + + # Verify the agent type is set as a span attribute + finished_spans = span_exporter.get_finished_spans() + if finished_spans: + span = finished_spans[-1] + span_attributes = getattr(span, "attributes", {}) or {} + + # Verify the caller agent type is set as a span attribute + if GEN_AI_CALLER_AGENT_TYPE_KEY in span_attributes: + self.assertEqual( + span_attributes[GEN_AI_CALLER_AGENT_TYPE_KEY], + AgentType.DECLARATIVE_AGENT.value, + ) + if __name__ == "__main__": # Run pytest only on the current file From e59be4d0581d885f60041d33dd2f75a98acb1774 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 17:07:22 +0000 Subject: [PATCH 3/3] Improve test assertions for agent type attribute per code review feedback Co-authored-by: nikhilNava <211831449+nikhilNava@users.noreply.github.com> --- .../core/test_invoke_agent_scope.py | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/tests/observability/core/test_invoke_agent_scope.py b/tests/observability/core/test_invoke_agent_scope.py index d5b6bed7..e6313e5d 100644 --- a/tests/observability/core/test_invoke_agent_scope.py +++ b/tests/observability/core/test_invoke_agent_scope.py @@ -246,26 +246,27 @@ def test_caller_agent_type_in_scope(self): scope = InvokeAgentScope.start( invoke_agent_details=self.invoke_details, tenant_details=self.tenant_details, - caller_agent_details=self.caller_agent_details, # Contains agent_type=AgentType.DECLARATIVE_AGENT + caller_agent_details=self.caller_agent_details, ) - if scope is not None: - # Verify the caller agent details contain the expected type - self.assertEqual(self.caller_agent_details.agent_type, AgentType.DECLARATIVE_AGENT) - scope.dispose() + # Verify scope was created and caller agent details contain the expected type + self.assertIsNotNone(scope) + self.assertEqual(self.caller_agent_details.agent_type, AgentType.DECLARATIVE_AGENT) + scope.dispose() # Verify the agent type is set as a span attribute finished_spans = span_exporter.get_finished_spans() - if finished_spans: - span = finished_spans[-1] - span_attributes = getattr(span, "attributes", {}) or {} + self.assertTrue(len(finished_spans) > 0, "Expected at least one span to be created") - # Verify the caller agent type is set as a span attribute - if GEN_AI_CALLER_AGENT_TYPE_KEY in span_attributes: - self.assertEqual( - span_attributes[GEN_AI_CALLER_AGENT_TYPE_KEY], - AgentType.DECLARATIVE_AGENT.value, - ) + span = finished_spans[-1] + span_attributes = getattr(span, "attributes", {}) or {} + + # Verify the caller agent type is set as a span attribute + self.assertIn(GEN_AI_CALLER_AGENT_TYPE_KEY, span_attributes) + self.assertEqual( + span_attributes[GEN_AI_CALLER_AGENT_TYPE_KEY], + AgentType.DECLARATIVE_AGENT.value, + ) if __name__ == "__main__":