1313
1414from azure .ai .agents .telemetry import AIAgentsInstrumentor
1515
16+ from azure .ai .agents .models import DeepResearchTool
17+
1618from gen_ai_trace_verifier import GenAiTraceVerifier
1719from memory_trace_exporter import MemoryTraceExporter
1820from test_agents_client_base import TestAgentClientBase
@@ -49,6 +51,17 @@ def cleanup(self):
4951 trace ._TRACER_PROVIDER = None
5052 os .environ .pop (CONTENT_TRACING_ENV_VARIABLE , None )
5153
54+ def _get_deep_research_tool (self , ** kwargs ):
55+ """Get deep research tool."""
56+ bing_conn_id = kwargs .pop ("azure_ai_agents_tests_bing_connection_id" )
57+ deep_research_model = kwargs .pop ("azure_ai_agents_tests_deep_research_model" )
58+
59+ # Create DeepResearchTool
60+ return DeepResearchTool (
61+ bing_grounding_connection_id = bing_conn_id ,
62+ deep_research_model = deep_research_model ,
63+ )
64+
5265 def _check_spans (
5366 self ,
5467 model : str ,
@@ -60,6 +73,7 @@ def _check_spans(
6073 tool_message_attribute_content : str ,
6174 event_contents : List [str ],
6275 run_step_events : Optional [List [List [Dict [str , Any ]]]] = None ,
76+ has_annotations : bool = False ,
6377 ):
6478 """Check the spans for correctness."""
6579 spans = self .exporter .get_spans_by_name ("create_agent my-agent" )
@@ -210,7 +224,7 @@ def _check_spans(
210224 assert events_match == True
211225
212226 spans = self .exporter .get_spans_by_name ("list_messages" )
213- assert len (spans ) = = 2
227+ assert len (spans ) > = 2
214228 span = spans [0 ]
215229 expected_attributes = [
216230 ("gen_ai.system" , "az.ai.agents" ),
@@ -221,7 +235,13 @@ def _check_spans(
221235 attributes_match = GenAiTraceVerifier ().check_span_attributes (span , expected_attributes )
222236 assert attributes_match == True
223237
224- content = '{"content": {"text": {"value": "*"}}, "role": "assistant"}' if recording_enabled else '{"role": "assistant"}'
238+ if recording_enabled :
239+ if has_annotations :
240+ content = '{"content": {"text": {"value": "*", "annotations": "*"}}, "role": "assistant"}'
241+ else :
242+ content = '{"content": {"text": {"value": "*"}}, "role": "assistant"}'
243+ else :
244+ content = '{"role": "assistant"}'
225245 expected_events = [
226246 {
227247 "name" : "gen_ai.assistant.message" ,
@@ -239,7 +259,7 @@ def _check_spans(
239259 events_match = GenAiTraceVerifier ().check_span_events (span , expected_events )
240260 assert events_match == True
241261
242- span = spans [1 ]
262+ span = spans [- 1 ]
243263 attributes_match = GenAiTraceVerifier ().check_span_attributes (span , expected_attributes )
244264 assert attributes_match == True
245265
@@ -260,15 +280,21 @@ def _check_spans(
260280
261281 spans = self .exporter .get_spans_by_name ("list_run_steps" )
262282 if run_step_events :
263- assert len (spans ) == len (run_step_events )
264283 expected_attributes = [
265284 ("gen_ai.system" , "az.ai.agents" ),
266285 ("gen_ai.operation.name" , "list_run_steps" ),
267286 ("server.address" , "" ),
268287 ("gen_ai.thread.id" , "" ),
269288 ("gen_ai.thread.run.id" , "" ),
270289 ]
271- for span , expected_span_events in zip (spans , run_step_events ):
290+ if len (spans ) < 5 :
291+ assert len (spans ) == len (run_step_events )
292+ zip_obj = zip (spans , run_step_events )
293+ else :
294+ assert len (run_step_events ) == 5
295+ # If it is deep research there may be multiple run steps.
296+ zip_obj = zip (spans [:3 ] + spans [- 2 :], run_step_events )
297+ for span , expected_span_events in zip_obj :
272298 attributes_match = GenAiTraceVerifier ().check_span_attributes (span , expected_attributes )
273299 assert attributes_match == True
274300 events_match = GenAiTraceVerifier ().check_span_events (span , expected_span_events )
@@ -411,4 +437,57 @@ def get_expected_mcp_spans(self):
411437 ])
412438 expected_spans .append ([])
413439 return expected_spans
414-
440+
441+ def get_expected_deep_research_spans (self ):
442+ expected_event_content = json .dumps (
443+ {'tool_calls' :
444+ [
445+ {
446+ "id" : "*" ,
447+ "type" : "deep_research" ,
448+ "deep_research" : {
449+ "input" : "*" ,
450+ "output" : "*"
451+ },
452+ }
453+ ]
454+ }
455+ )
456+
457+ expected_spans = [
458+ [
459+ {
460+ "name" : "gen_ai.run_step.message_creation" ,
461+ "attributes" : {
462+ "gen_ai.system" : "az.ai.agents" ,
463+ "gen_ai.thread.id" : "*" ,
464+ "gen_ai.agent.id" : "*" ,
465+ "gen_ai.thread.run.id" : "*" ,
466+ "gen_ai.message.id" : "*" ,
467+ "gen_ai.run_step.status" : "completed" ,
468+ "gen_ai.run_step.start.timestamp" : "*" ,
469+ "gen_ai.run_step.end.timestamp" : "*" ,
470+ "gen_ai.usage.input_tokens" : 0 ,
471+ "gen_ai.usage.output_tokens" : 0 ,
472+ },
473+ },
474+ ]
475+ ] * 4
476+ expected_spans .append ([
477+ {
478+ "name" : "gen_ai.run_step.tool_calls" ,
479+ "attributes" : {
480+ "gen_ai.system" : "az.ai.agents" ,
481+ "gen_ai.thread.id" : "*" ,
482+ "gen_ai.agent.id" : "*" ,
483+ "gen_ai.thread.run.id" : "*" ,
484+ "gen_ai.run_step.status" : "completed" ,
485+ "gen_ai.run_step.start.timestamp" : "*" ,
486+ "gen_ai.run_step.end.timestamp" : "*" ,
487+ "gen_ai.usage.input_tokens" : "+" ,
488+ "gen_ai.usage.output_tokens" : "+" ,
489+ "gen_ai.event.content" : expected_event_content
490+ },
491+ },
492+ ])
493+ return expected_spans
0 commit comments