import pytest from agents.items import MessageOutputItem, ToolCallItem from openai.types.responses.response_file_search_tool_call import ( ResponseFileSearchToolCall, Result as FileSearchResult, ) from openai.types.responses.response_function_web_search import ActionSearch, ResponseFunctionWebSearch from openai.types.responses.response_output_message import ResponseOutputMessage, ResponseOutputText from agency_swarm.agent.core import Agent from agency_swarm.messages import MessageFormatter @pytest.mark.asyncio async def test_web_search_results_have_metadata(): """Verify web search results are returned as user messages with metadata.""" agent = Agent(name="MetaAgent", instructions="Test") web_call = ResponseFunctionWebSearch( id="1", action=ActionSearch(query="hello", type="search"), status="completed", type="web_search_call", ) assistant_msg = ResponseOutputMessage( id="m1", content=[ResponseOutputText(annotations=[], text="result", type="output_text")], role="assistant", status="completed", type="message", ) run_items = [ ToolCallItem(agent, web_call), MessageOutputItem(agent, assistant_msg), ] results = MessageFormatter.extract_hosted_tool_results( agent, run_items, caller_agent="Researcher", ) assert results, "Expected hosted tool result" result = results[0] assert result.get("agent") == agent.name assert result.get("callerAgent") == "Researcher" assert "WEB_SEARCH_RESULTS" in result.get("content", "") def test_extract_no_results_returns_empty(): """Ensure empty list is returned when no hosted tool calls present.""" agent = Agent(name="EmptyAgent", instructions="Test") results = MessageFormatter.extract_hosted_tool_results( agent, [], caller_agent="AnyAgent", ) assert results == [] def test_web_search_results_deduplicated(): """Only one synthetic result should be created for multiple assistant messages.""" agent = Agent(name="MetaAgent", instructions="Test") web_call = ResponseFunctionWebSearch( id="1", action=ActionSearch(query="hello", type="search"), status="completed", type="web_search_call", ) assistant_msgs = [ ResponseOutputMessage( id="m1", content=[ResponseOutputText(annotations=[], text="result1", type="output_text")], role="assistant", status="completed", type="message", ), ResponseOutputMessage( id="m2", content=[ResponseOutputText(annotations=[], text="result2", type="output_text")], role="assistant", status="completed", type="message", ), ] run_items = [ToolCallItem(agent, web_call)] + [MessageOutputItem(agent, m) for m in assistant_msgs] results = MessageFormatter.extract_hosted_tool_results(agent, run_items) # type: ignore[arg-type] assert len(results) == 1 assert "result1" in results[0]["content"] assert "result2" not in results[0]["content"] def test_multiple_web_searches_get_distinct_results(): """Each web search should get its own corresponding assistant message content.""" agent = Agent(name="SearchAgent", instructions="Test") # First web search and its result web_call1 = ResponseFunctionWebSearch( id="search_1", action=ActionSearch(query="python", type="search"), status="completed", type="web_search_call", ) assistant_msg1 = ResponseOutputMessage( id="msg_1", content=[ResponseOutputText(annotations=[], text="Python results", type="output_text")], role="assistant", status="completed", type="message", ) # Second web search and its result web_call2 = ResponseFunctionWebSearch( id="search_2", action=ActionSearch(query="javascript", type="search"), status="completed", type="web_search_call", ) assistant_msg2 = ResponseOutputMessage( id="msg_2", content=[ResponseOutputText(annotations=[], text="JavaScript results", type="output_text")], role="assistant", status="completed", type="message", ) # Build run items in order: search1, msg1, search2, msg2 run_items = [ ToolCallItem(agent, web_call1), MessageOutputItem(agent, assistant_msg1), ToolCallItem(agent, web_call2), MessageOutputItem(agent, assistant_msg2), ] results = MessageFormatter.extract_hosted_tool_results(agent, run_items) # Should create two synthetic results assert len(results) == 2, "Expected two results for two web searches" # First result should have Python content assert "search_1" in results[0]["content"] assert "Python results" in results[0]["content"] assert "JavaScript results" not in results[0]["content"] # Second result should have JavaScript content assert "search_2" in results[1]["content"] assert "JavaScript results" in results[1]["content"] assert "Python results" not in results[1]["content"] def test_file_search_results_only_persist_for_executing_agent(): """Ensure hosted tool preservation is only emitted by the agent that ran the tool.""" ceo = Agent(name="CEO", instructions="Test") worker = Agent(name="Worker", instructions="Test") tool_call = ResponseFileSearchToolCall( id="fs_unique", queries=["favorite books"], status="completed", type="file_search_call", results=[ FileSearchResult( file_id="file-1", filename="favorite_books.txt", score=0.9, text="Books list", ) ], ) hosted_run_items = [ToolCallItem(ceo, tool_call)] ceo_results = MessageFormatter.extract_hosted_tool_results( ceo, hosted_run_items, caller_agent="Worker", ) assert ceo_results, "Executing agent should persist hosted tool results" worker_results = MessageFormatter.extract_hosted_tool_results( worker, hosted_run_items, caller_agent="Worker", ) assert worker_results == [], "Non-executing agent must not duplicate hosted tool preservation" def test_web_search_results_only_persist_for_executing_agent(): """Ensure web search preservation is written only by the executing agent.""" ceo = Agent(name="CEO", instructions="Test") worker = Agent(name="Worker", instructions="Test") web_call = ResponseFunctionWebSearch( id="web_unique", action=ActionSearch(query="web search", type="search"), status="completed", type="web_search_call", ) assistant_msg = ResponseOutputMessage( id="web_msg", content=[ResponseOutputText(annotations=[], text="Search content", type="output_text")], role="assistant", status="completed", type="message", ) run_items = [ ToolCallItem(ceo, web_call), MessageOutputItem(ceo, assistant_msg), ] ceo_results = MessageFormatter.extract_hosted_tool_results( ceo, run_items, caller_agent="Worker", ) assert ceo_results, "Executing agent should persist web search results" assert "WEB_SEARCH_RESULTS" in ceo_results[0]["content"] worker_results = MessageFormatter.extract_hosted_tool_results( worker, run_items, caller_agent="Worker", ) assert worker_results == [], "Non-executing agent must not duplicate web search preservation"