Skip to main content
Glama

mcp-run-python

Official
by pydantic
test_openai_responses.py427 kB
import json import re from dataclasses import replace from typing import Any, cast import pytest from inline_snapshot import snapshot from pydantic import BaseModel from typing_extensions import TypedDict from pydantic_ai import ( BinaryContent, BinaryImage, BuiltinToolCallPart, BuiltinToolReturnPart, DocumentUrl, FilePart, FinalResultEvent, ImageGenerationTool, ImageUrl, ModelRequest, ModelResponse, PartDeltaEvent, PartStartEvent, RetryPromptPart, TextPart, TextPartDelta, ThinkingPart, ThinkingPartDelta, ToolCallPart, ToolCallPartDelta, ToolReturnPart, UnexpectedModelBehavior, UserPromptPart, capture_run_messages, ) from pydantic_ai.agent import Agent from pydantic_ai.builtin_tools import CodeExecutionTool, MCPServerTool, WebSearchTool from pydantic_ai.exceptions import ModelHTTPError, ModelRetry from pydantic_ai.messages import ( BuiltinToolCallEvent, # pyright: ignore[reportDeprecated] BuiltinToolResultEvent, # pyright: ignore[reportDeprecated] ) from pydantic_ai.output import NativeOutput, PromptedOutput, TextOutput, ToolOutput from pydantic_ai.profiles.openai import openai_model_profile from pydantic_ai.tools import ToolDefinition from pydantic_ai.usage import RequestUsage, RunUsage from ..conftest import IsBytes, IsDatetime, IsStr, TestEnv, try_import from .mock_openai import MockOpenAIResponses, get_mock_responses_kwargs, response_message with try_import() as imports_successful: from openai.types.responses.response_output_message import Content, ResponseOutputMessage, ResponseOutputText from openai.types.responses.response_reasoning_item import ResponseReasoningItem, Summary from openai.types.responses.response_usage import ResponseUsage from pydantic_ai.models.anthropic import AnthropicModel, AnthropicModelSettings from pydantic_ai.models.openai import OpenAIResponsesModel, OpenAIResponsesModelSettings from pydantic_ai.providers.anthropic import AnthropicProvider from pydantic_ai.providers.openai import OpenAIProvider pytestmark = [ pytest.mark.skipif(not imports_successful(), reason='openai not installed'), pytest.mark.anyio, pytest.mark.vcr, pytest.mark.filterwarnings( 'ignore:`BuiltinToolCallEvent` is deprecated, look for `PartStartEvent` and `PartDeltaEvent` with `BuiltinToolCallPart` instead.:DeprecationWarning' ), pytest.mark.filterwarnings( 'ignore:`BuiltinToolResultEvent` is deprecated, look for `PartStartEvent` and `PartDeltaEvent` with `BuiltinToolReturnPart` instead.:DeprecationWarning' ), ] def test_openai_responses_model(env: TestEnv): env.set('OPENAI_API_KEY', 'test') model = OpenAIResponsesModel('gpt-4o') assert model.model_name == 'gpt-4o' assert model.system == 'openai' async def test_openai_responses_model_simple_response(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model) result = await agent.run('What is the capital of France?') assert result.output == snapshot('The capital of France is Paris.') async def test_openai_responses_image_detail_vendor_metadata(allow_model_requests: None): c = response_message( [ ResponseOutputMessage( id='output-1', content=cast(list[Content], [ResponseOutputText(text='done', type='output_text', annotations=[])]), role='assistant', status='completed', type='message', ) ] ) mock_client = MockOpenAIResponses.create_mock(c) model = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(openai_client=mock_client)) agent = Agent(model=model) image_url = ImageUrl('https://example.com/image.png', vendor_metadata={'detail': 'high'}) binary_image = BinaryContent(b'\x89PNG', media_type='image/png', vendor_metadata={'detail': 'high'}) result = await agent.run(['Describe these inputs.', image_url, binary_image]) assert result.output == 'done' response_kwargs = get_mock_responses_kwargs(mock_client) image_parts = [ item for message in response_kwargs[0]['input'] if message.get('role') == 'user' for item in message['content'] if item['type'] == 'input_image' ] assert image_parts assert all(part['detail'] == 'high' for part in image_parts) async def test_openai_responses_model_simple_response_with_tool_call(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model) @agent.tool_plain async def get_capital(country: str) -> str: return 'Potato City' result = await agent.run('What is the capital of PotatoLand?') assert result.output == snapshot('The capital of PotatoLand is Potato City.') async def test_openai_responses_output_type(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) class MyOutput(TypedDict): name: str age: int agent = Agent(model=model, output_type=MyOutput) result = await agent.run('Give me the name and age of Brazil, Argentina, and Chile.') assert result.output == snapshot({'name': 'Brazil', 'age': 2023}) async def test_openai_responses_reasoning_effort(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('o3-mini', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model, model_settings=OpenAIResponsesModelSettings(openai_reasoning_effort='low')) result = await agent.run( 'Explain me how to cook uruguayan alfajor. Do not send whitespaces at the end of the lines.' ) assert [line.strip() for line in result.output.splitlines()] == snapshot( [ 'Ingredients for the dough:', '• 300 g cornstarch', '• 200 g flour', '• 150 g powdered sugar', '• 200 g unsalted butter', '• 3 egg yolks', '• Zest of 1 lemon', '• 1 teaspoon vanilla extract', '• A pinch of salt', '', 'Ingredients for the filling (dulce de leche):', '• 400 g dulce de leche', '', 'Optional coating:', '• Powdered sugar for dusting', '• Grated coconut', '• Crushed peanuts or walnuts', '• Melted chocolate', '', 'Steps:', '1. In a bowl, mix together the cornstarch, flour, powdered sugar, and salt.', '2. Add the unsalted butter cut into small pieces. Work it into the dry ingredients until the mixture resembles coarse breadcrumbs.', '3. Incorporate the egg yolks, lemon zest, and vanilla extract. Mix until you obtain a smooth and homogeneous dough.', '4. Wrap the dough in plastic wrap and let it rest in the refrigerator for at least one hour.', '5. Meanwhile, prepare a clean workspace by lightly dusting it with flour.', '6. Roll out the dough on the working surface until it is about 0.5 cm thick.', '7. Use a round cutter (approximately 3-4 cm in diameter) to cut out circles. Re-roll any scraps to maximize the number of cookies.', '8. Arrange the circles on a baking sheet lined with parchment paper.', '9. Preheat the oven to 180°C (350°F) and bake the cookies for about 10-12 minutes until they are lightly golden at the edges. They should remain soft.', '10. Remove the cookies from the oven and allow them to cool completely on a rack.', '11. Once the cookies are cool, spread dulce de leche on the flat side of one cookie and sandwich it with another.', '12. If desired, roll the edges of the alfajores in powdered sugar, grated coconut, crushed nuts, or dip them in melted chocolate.', '13. Allow any coatings to set before serving.', '', 'Enjoy your homemade Uruguayan alfajores!', ] ) async def test_openai_responses_reasoning_generate_summary(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('computer-use-preview', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent( model=model, model_settings=OpenAIResponsesModelSettings( openai_reasoning_summary='concise', openai_truncation='auto', ), ) result = await agent.run('What should I do to cross the street?') assert result.output == snapshot("""\ To cross the street safely, follow these steps: 1. **Use a Crosswalk**: Always use a designated crosswalk or pedestrian crossing whenever available. 2. **Press the Button**: If there is a pedestrian signal button, press it and wait for the signal. 3. **Look Both Ways**: Look left, right, and left again before stepping off the curb. 4. **Wait for the Signal**: Cross only when the pedestrian signal indicates it is safe to do so or when there is a clear gap in traffic. 5. **Stay Alert**: Be mindful of turning vehicles and stay attentive while crossing. 6. **Walk, Don't Run**: Walk across the street; running can increase the risk of falling or not noticing an oncoming vehicle. Always follow local traffic rules and be cautious, even when crossing at a crosswalk. Safety is the priority.\ """) async def test_openai_responses_system_prompt(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model, system_prompt='You are a helpful assistant.') result = await agent.run('What is the capital of France?') assert result.output == snapshot('The capital of France is Paris.') async def test_openai_responses_model_retry(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model) @agent.tool_plain async def get_location(loc_name: str) -> str: if loc_name == 'London': return json.dumps({'lat': 51, 'lng': 0}) else: raise ModelRetry('Wrong location, I only know about "London".') result = await agent.run('What is the location of Londos and London?') assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is the location of Londos and London?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ToolCallPart( tool_name='get_location', args='{"loc_name":"Londos"}', tool_call_id=IsStr(), id='fc_67e547c540648191bc7505ac667e023f0ae6111e84dd5c08', ), ToolCallPart( tool_name='get_location', args='{"loc_name":"London"}', tool_call_id=IsStr(), id='fc_67e547c55c3081919da7a3f7fe81a1030ae6111e84dd5c08', ), ], usage=RequestUsage(details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_67e547c48c9481918c5c4394464ce0c60ae6111e84dd5c08', finish_reason='stop', ), ModelRequest( parts=[ RetryPromptPart( content='Wrong location, I only know about "London".', tool_name='get_location', tool_call_id=IsStr(), timestamp=IsDatetime(), ), ToolReturnPart( tool_name='get_location', content='{"lat": 51, "lng": 0}', tool_call_id=IsStr(), timestamp=IsDatetime(), ), ] ), ModelResponse( parts=[ TextPart( content="""\ It seems "Londos" might be incorrect or unknown. If you meant something else, please clarify. For **London**, it's located at approximately latitude 51° N and longitude 0° W.\ """, id='msg_67e547c615ec81918d6671a184f82a1803a2086afed73b47', ) ], usage=RequestUsage(input_tokens=335, output_tokens=44, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_67e547c5a2f08191802a1f43620f348503a2086afed73b47', finish_reason='stop', ), ] ) @pytest.mark.vcr() async def test_image_as_binary_content_tool_response( allow_model_requests: None, image_content: BinaryContent, openai_api_key: str ): m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(m) @agent.tool_plain async def get_image() -> BinaryContent: return image_content result = await agent.run(['What fruit is in the image you can get from the get_image tool?']) assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content=['What fruit is in the image you can get from the get_image tool?'], timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ToolCallPart( tool_name='get_image', args='{}', tool_call_id=IsStr(), id='fc_681134d47cf48191b3f62e4d28b6c3820fe7a5a4e2123dc3', ) ], usage=RequestUsage(input_tokens=40, output_tokens=11, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_681134d3aa3481919ca581a267db1e510fe7a5a4e2123dc3', finish_reason='stop', ), ModelRequest( parts=[ ToolReturnPart( tool_name='get_image', content='See file 1c8566', tool_call_id='call_FLm3B1f8QAan0KpbUXhNY8bA', timestamp=IsDatetime(), ), UserPromptPart( content=[ 'This is file 1c8566:', image_content, ], timestamp=IsDatetime(), ), ] ), ModelResponse( parts=[ TextPart( content='The fruit in the image is a kiwi.', id='msg_681134d770d881919f3a3148badde27802cbfeaababb040c', ) ], usage=RequestUsage(input_tokens=1185, output_tokens=11, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_681134d53c48819198ce7b89db78dffd02cbfeaababb040c', finish_reason='stop', ), ] ) async def test_image_as_binary_content_input( allow_model_requests: None, image_content: BinaryContent, openai_api_key: str ): m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(m) result = await agent.run(['What fruit is in the image?', image_content]) assert result.output == snapshot('The fruit in the image is a kiwi.') async def test_openai_responses_audio_as_binary_content_input( allow_model_requests: None, audio_content: BinaryContent, openai_api_key: str ): m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(m) with pytest.raises(NotImplementedError): await agent.run(['Whose name is mentioned in the audio?', audio_content]) async def test_openai_responses_document_as_binary_content_input( allow_model_requests: None, document_content: BinaryContent, openai_api_key: str ): m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(m) result = await agent.run(['What is in the document?', document_content]) assert result.output == snapshot('The document contains the text "Dummy PDF file."') async def test_openai_responses_document_url_input(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(m) document_url = DocumentUrl(url='https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf') result = await agent.run(['What is the main content on this document?', document_url]) assert result.output == snapshot( 'The main content of this document is a simple text placeholder: "Dummy PDF file."' ) async def test_openai_responses_text_document_url_input(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(m) text_document_url = DocumentUrl(url='https://example-files.online-convert.com/document/txt/example.txt') result = await agent.run(['What is the main content on this document?', text_document_url]) assert result.output == snapshot( 'The main content of this document is an example of a TXT file type, with an explanation of the use of placeholder names like "John Doe" and "Jane Doe" in legal, medical, and other contexts. It discusses the practice in the U.S. and Canada, mentions equivalent practices in other English-speaking countries, and touches on cultural references. The document also notes that it\'s an example file created by an online conversion tool, with content sourced from Wikipedia under a Creative Commons license.' ) async def test_openai_responses_image_url_input(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(m) result = await agent.run( [ 'hello', ImageUrl(url='https://t3.ftcdn.net/jpg/00/85/79/92/360_F_85799278_0BBGV9OAdQDTLnKwAPBCcg1J7QtiieJY.jpg'), ] ) assert result.output == snapshot("Hello! I see you've shared an image of a potato. How can I assist you today?") async def test_openai_responses_stream(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model) @agent.tool_plain async def get_capital(country: str) -> str: return 'Paris' output_text: list[str] = [] async with agent.run_stream('What is the capital of France?') as result: async for output in result.stream_text(): output_text.append(output) async for response, is_last in result.stream_responses(debounce_by=None): if is_last: assert response == snapshot( ModelResponse( parts=[ TextPart( content='The capital of France is Paris.', id='msg_67e554a28bec8191b56d3e2331eff88006c52f0e511c76ed', ) ], usage=RequestUsage(input_tokens=278, output_tokens=9, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_67e554a21aa88191b65876ac5e5bbe0406c52f0e511c76ed', finish_reason='stop', ) ) assert output_text == snapshot(['The capital of France is Paris.']) async def test_openai_responses_model_http_error(allow_model_requests: None, openai_api_key: str): """Set temperature to -1 to trigger an error, given only values between 0 and 1 are allowed.""" model = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model, model_settings=OpenAIResponsesModelSettings(temperature=-1)) with pytest.raises(ModelHTTPError): async with agent.run_stream('What is the capital of France?'): ... # pragma: lax no cover async def test_openai_responses_model_builtin_tools_web_search(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) settings = OpenAIResponsesModelSettings(openai_builtin_tools=[{'type': 'web_search'}]) agent = Agent(model=model, model_settings=settings) result = await agent.run('Give me the top 3 news in the world today') assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Give me the top 3 news in the world today', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_0e3d55e9502941380068c4aaa4efb081958605d7b31e838366', signature='gAAAAABoxKrgd0uCWxLjgCiIWj3ei9eYp9sdRdHLVNWOpZvOS6TS_8hF6IEgz5acjqUiaGnXfLl3kn78UERavEItdZ-6PupaB2V7M8btQ2v76ZJCPXR5DGvXe3K2y_zrSLC-qbX4ui3hPfGG01qGiftAM7m04zuCdJ33SVDyOasB8uzV7vSqFzM4CkcAeN0jueQtuGDJ9U5Qq9blCXo6Vxx4BVOVPYnCONMQvwJXlbZ7i_s3VmUFFDf2GlNYtkT07Z1Uc5ESVUVDYfVC2qlOWWp2MLh20tbsUMqHPYzO0R7Y1lmwAqNxaT4HIhhlQ0xVer1qBRgUfLn1fGXX0vBb4rN0N_w7c2w-iwY-4XAvhAr-Y3pejueHfepmv76G67cJVQjzgM37wlQFdl_UmDfkVDIxmAE62QjOjPs8TweVPEXUXAK4itTDQiS7M42dS6QzxivPVvzoMkNOjJ58vUy83DCr-Obw8SMfFGB5sd1hGg9enLYiGxN_Qzs9IGegBU4cH1wpCvARmuVP10-CJe0jzSFy0OI76JUgGMVido_cEgrAF5eEOS-3vkel6L07Q9Sl_f8C-ZW04zF40ZIvCZ4RJfRAKr2bfXH6IVNhu528-ilQTCoCeFy_CG6UYlUY2jws_DRuTsAVb6691hPRI8mG28NCPXNGV5h8sVgypbeqWyBNZEnSgqFcNVplAPTxDNqlcFps5bEND4Q0SLSNTZv9vFbRvfyrf-4s3UWqn-SI4QAmGzKRRuTumEpldsTuZgv69Nu2qA7px1ZNu-hN7S0E7ONGDs2fCaUG4X-Xp3j2fizfaTkZpOC_sdTK5e10lIG019zKGngXSrBy_sOWyTIsjiRGdr0Va-RjDw2ruFr3ewQcH5vZ8LgUwTzijfqLqbkF1zgZopHTnz1Gpt42AbZiyP30S9BQuDODD8RmtZQ5oB1NKmISeGkLCJRd6dZKGibFskFFMFr53YvUfVZx4mRpxSjuadceNKPhTVkbGPYE6XrZbChCxDL9aJJ37ctRxf91r9QAXMqeFZR-4HR13_Pp0AyN_H7gqBR2yVuGbXkhs1QwkEhl-6_keNsJYUaRSSf5QN9gRjsuWchWEsTr8AqTbIApGO24a5Rr4GDnZ_6ICYBr-IhUesv0VJKQF3DcNFaOQCLtLTKCC4G4SqURt60V0zkQKWBdUdUGFkxDUN5gtcKrR0F4J5hvZ6OMV3XaP6kpgx62TL_gd9g_QyV8QDFwXuDDrGyXi6l68veZXOElkZ4lpVAjfeXnysK401DRt3vF0z99wUc-QVMjZG0wVZUr5rYHjKKaB2vG85n_onMrddThz2_a1NG_THQZ3L1rprThcQY7FdPtw1JXWfXWeS7ZuOOZCZvjyCrVhevaxTl5UKNbkguqYhNJQfx5X8IkwJWVRObA3QxFD0ZEgW9OKt-v-g_EAsjtftPbeeqaDfPBwqVguYJUEZqPPwcsG2cv8Xu5sCc6h7J8fvwTK-MY847JS5Q5CSDe4GDFvJn4Tk4aIOeGlr-VlrgwOS_yaKd1GogBIDzjh8pXIXXSDP2UkEOd2T0zSoa0u8oewPf8Pwmd7pmVb10Y9tHPgEo44ZQRiyVCe9S36BVjf1iZgTYetfBfq9JJom1Ksz-WUf74sHYfLkUY96lOlSvziyFFmTXxFgssLFgtBuWNaehKeuJ0QiQm2r4jEvX3n7dvUj09tWw_boLWGUJqL5YkxVadlw8wF1KRFJjGIAvEvO7YNoEoyolmS9616ZBvWNlBg54A5DITXEfIMloXVYNmYomoBloM74USiV7AjQE5hPIIqO97dW4btd2zMx9Nbr8G-nZsLgCqrqzDVz0UorAHTgaThtp9BW6VJZJ9q3Ew_z_494P7GNv9ehuK6m3fT-MXIq-t0Bo28YGgGhiFjoYSSYUd1adlHQdPHZCxZojt4-DxgD3iFoWQGc7BBRU3f9rRVRzbDvlHpaLRUQUFXiaB6rQ=', provider_name='openai', ), BuiltinToolCallPart( tool_name='web_search', args={'query': 'top world news September 12, 2025 Reuters', 'type': 'search'}, tool_call_id='ws_0e3d55e9502941380068c4aaab56508195a1effa9583720d20', provider_name='openai', ), BuiltinToolReturnPart( tool_name='web_search', content={'status': 'completed'}, tool_call_id='ws_0e3d55e9502941380068c4aaab56508195a1effa9583720d20', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_0e3d55e9502941380068c4aaaef4b481959dfd7d8031662152', signature='gAAAAABoxKrgnD1AQrb0I2TSTLa6DiSpAwMbkF6gxz_b8tkkns4MZ4Rr6a8ejwmX7aGMoXEgOO2nkuLFeKoQBzQBrfNZIhmCy68QZMQQKZfKBUv1k8OAKzz4A1dO-xNH6xLMS-3cG4ev4zqjQEOBSGoZNKcZMU9L3B0VCvZsBU7S50g7zCcVwEk6H0wx4HO6IuUEOzgqqx8NYHmOkudSv3ikiHn1xhLc1JEzXkupTyRxyw1O81jJEpNzLlEUIFeu0vkAJrlwQzAHeEzxFMMQMoru3pKwnzujgljefGG8RY34jsAc6XcbJSstAa5GnKn24ehA_CQu80ICcibs7LBKsa3oO8wWWHXgDhMCPJn0N322MZcHfH77PhgEr-T1YSIRrSMPXcxoPaptN0O4ceK9BYN4FDRddaR1jXzWdZ3VhYBNbRrQEuO6z0TOWsPmzIlDql1a20jiOteGNQgIX94Af4PB5g_DYWzJW8YVffnhKXJEmU7BmYuctQgyewLj_CoQYfQ9HtGcae6ZElUEP96lo1ID3AW2iMa3iP4C2xULWDVh-8rWf0D2fgS1toexXXCtWbXn8XlYMGWVjq3WX5q16Kq0KyInuCZleABTeFRuzh0MTx1GaYhDTwHxG8BRPYUxz0bHHESz-h_UGmhGu8-a49YdBpLe36_Z1wprXJ82Yg7KvJy68VwKnLeH1Zm56aMHviJl143iZYgiZaVmRBIRExMvnI9LVAT5pv0Y3CdCCSq8Bs2jSbhU0xe26HAqfZZnAsE0LpPAfW1tMCiKzqhtzoKR6yauAYCXP5YtnX6BqFr-J8px6owPJhepjyrSVCObyya7v7_rV81BkYOtLQSwCUUhOjbawgI6XDQ_FK0hye5lFVKckFNM3cVpgRcZymeqx-XoQeoFOR8uLtcXv2DIoo0TfP7RxgBvAvdohv8vZx7xJSXlrYKqLEK1ASQDcc36gIfNQuNXM24WuXForXTO2l_sTeos58eX5FGxWJFDghhrNa_ia1dL7towjcegQzf9LtLjLlnqUGpEte-o23DKKQQEiFfMpLlvGu2cOVwYUuoeOpEBe7QpDbJGdBjq0hOKdakHGl6KwBw6vCkRp_wtW4R7QBuncdYyRT6AJ1_Z_byBP7kH1A2-P6QMVycBVcXlUgc0BzuGlkt51l__O3CM4z-PmI8zR5cL6ZCXoQzG2Yp-OhQ-n-3hgMaCfBGca6J3wP1vgQpR2AF0', provider_name='openai', ), BuiltinToolCallPart( tool_name='web_search', args={'query': 'Nepal protests September 12 2025 Reuters', 'type': 'search'}, tool_call_id='ws_0e3d55e9502941380068c4aab0c534819593df0190332e7aa3', provider_name='openai', ), BuiltinToolReturnPart( tool_name='web_search', content={'status': 'completed'}, tool_call_id='ws_0e3d55e9502941380068c4aab0c534819593df0190332e7aa3', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_0e3d55e9502941380068c4aab3df148195bdec4fe186f23877', signature='gAAAAABoxKrgZN3V5pGaqoIM8EEiFso41O_kxOTWpzAh5Nlj3pqqDjIGrFH2zcmDyURpUmXdExY8L9K6KcwGOAlF6okEgQojeTxysBi4-gDVFNCVfp6c6K4tAtCBrvq5wC2g22Ny1pU2OMyxVU2GCxIIehCZiPQio_7IS8WY_VWkwLOag7bT4FBGn-aVFyoEfDDpIPF-4Zpcal6bAvdjD2hYGl6_-8alwh36ttUkJroo2qG-Mn0LsAWJ7YEzfrHgoPTDF7TB3Mfvvc5M_eP3pzY8O4WhZKMLBSnM92iIt5J3nSJYhRoiwEjaCamIM4vK0cnJR0oX87u_XtGvnNBX93ttrIrXDKK-mh-LIoe_sK1dViFINxk6rJHZvkFK12J6UXMK4me-C3uQ_qGygpw4uYvWhYk7LDR9Zgxfv1OoDg13DCYWWrHX7Oa1ALXPotk1Uw_Tof-Wc_wDqE16Elm1a5TP-ISH45v9W_Xl1IXo7J_jwOlAjkXvrh2a8YNljWQqBFCca-M2hSWvKuX8JuNF_tkI2q2E7jIDNt77jGd2yavqb1W2WoB_s7jqyAWomT91E2gZQtGJa4X2ydeTPQ_oWv2hgdTUynV0nbOKWA6suZixvxVDLLedhYHRnKY6EOtyso9MZav1qhr_DpHExn1_woquJXtS7c3Fe3Rs_YrU6PpRx5_DEVjVKme-3XjLJNclx6NF-rbXYqhXXExqPk-od7n-YMyrYhpfVP8lmLCewwyzVRb1koOEcCqnuhqM9DWyazKAcdvejM7VEM1AEk8ugT02cTiF7CfLefYFsLSYVBM0Ox47Ceh4BOA82jdlf1pZNvGqgHi8kKm9HLVh-yM_DAhD8O5Ub-SCd3bNi8735XPDWVIm6sKMdg1bcgVehz_R4iEBr_pguKfZUJLcckUTI6fitAQ6YSLpLAfRA0nMDBfM6p43jqsSCP8Ovjx58TwAPElgpme4ENBCozS_VaxmqawpfUfvnD60xia57wtSBYr5s1j-FUUjBsFTInjHdKcp0EBd3Pv-mpVE-Yj0MYExbn1upi3RxWN6jwVeYc603HQBjsjqsb-op9Tb0GZxf5Z4DpZ_eeb4IBTWNf3FTLIbsVg18Oyl128Std9CkMGak8iI_dFCvm1ZQQ6u3CyLEwxGsMZnkZl6OhSKDlnHDvRsF0F0OcRtFV5i7j92kMs9_qJ2JLdb5LzdqOBnFfKOcUCXBOflL58PYIav', provider_name='openai', ), BuiltinToolCallPart( tool_name='web_search', args={ 'query': 'UN Security Council condemns attack in Doha September 12 2025 Reuters', 'type': 'search', }, tool_call_id='ws_0e3d55e9502941380068c4aab597f48195ac7021b00e057308', provider_name='openai', ), BuiltinToolReturnPart( tool_name='web_search', content={'status': 'completed'}, tool_call_id='ws_0e3d55e9502941380068c4aab597f48195ac7021b00e057308', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_0e3d55e9502941380068c4aab85e7c81958c4b4ae526792e49', signature='gAAAAABoxKrghWofTkZCzljg86Akl6ch3bNwR70Wz37t6mBpLah1wZ-7U6isPixPCn0t66fA6xKxGX75bmjRu8Gts4cIaYpm78c8n6R44UULYfQoDC9ZEyGgImbQUKoHFU63nSbsjuPTTFtLdLHhEebDE_t6AfqIWBlyZKRqYlXS_8mTZ_NwM5_JgJun1Xz-I3Pb0X5ZgX8RTP_Kh7Kk79PStvg0-qcVoxMtFsK4ZN3fzQBOSUwvkMhglIweiS3s9CpTbtOs0PYqFCOIjKEYZ2-Rt_7SKhOGaWEMuvuWggMLeO_Wkl8HyIHre5JolVFR9M-43XByZXQxrvBxFzzwHubiyCs-WHFicgMyZcAF8e2KR9KdUJxAwQ3acCi3zBc7e5q1jgc8-Csm-vZQJMTyABDu4yuLena6rF777C8jq-naUe5M-bBpiimK1nbpg5YDiwx7-TbZz5eiTpptHL3P6izhgEOXuEvLhlrhxPBKTezDkiwu-wjs0tHguRYbOIMf-3NZGHuYnOcGfC2wJKkE9DmRvbicnChrLqzHmiXWblYhPwsH9wt-QDvrz3tgCH4B3ri9APreQjBmxtZEVGQAtfdm1qpgiDcWqEijrj05rvr4HxbSReCFszZJDYAufNhJSPhuJXl4e7EHRLyVd2uJA264ONj-MxT2WRr4MGzubSXtPd1QJn7IEkCCuPZxbLf9q27DTSpAvS1oZVs1Ad0J4lbRV5tS_sG54JLvpXf4jtYHD-R2CG0vkL1i0273IJroXScLaPELp0iJMn-WzAkbEjjMsX8gmZlV2X06XuvSjry-dh2sU9Yldqw4NHMLM8rpZIfKbsm6w0ub5Icmu19E856R57JM3K3Pjm3fdO3HR-adVsJTAaIusyUVX3SOiTY53-X6UbqBJh5H3WOORqkwW2nGbNur6B_tyRjlegD3CGJzC-A9rNxMWrecALmCEJBwnXxOuvpsGkSgjP8vjnY9JJNj53hxAirHFIxknDMrKt5qlsRHxGlCdN9H7YuTGdTSgPWH_L9C4BtZrr2Qk41osiDCpacMwBeUDwo1YwYWd1SO0DEzm2qGlXSYeuAQ6Fvyc7sZHCkOsl-bINhCuY1aEBOLzXS7kcu0YAIuEZGVp5wUrr2L6YssdrzpzQ_KENFI7LiB2v5CrF1wZN85H2dkwaGciOXznAa0Su1fWD3BUdpyR0h_mVIcHUxmeoCywWbWO-Do3LFu70MMxKmfSzVfL9hlU2B2jo1aqJ5HesWsWbsbslW5FfREayeUzK7hxkrjliDePhN6gkfy0HOYQijPN6dko4TNEeKFO6Q-aw7c4X5IF3WBCYd_IszlLBK-vTX4EX2J5QtaLRfwFgRwz_K2fkOTT64eknQ6R3fFJpgeyLBZ5ut7j2o7xhEuHeE4KPm2T_AJi8yRScMU-ZsDcUZ8IVYAduy2TGov51AM7K2WojgvqWi62AwSLd16eEnd7SUD8fiCwtRN3zTdmh3MenUogxtKG2YL4hUvSN6Ia1STXpfU4ToLvBnPS5FoY2GuOG-EdEAHdKfYsSUZmSauAlQy7sT43STLkDE42lOKWqtSNHOygkGUodv1GNR0sA6CIg_gVAOyUG-o20rMsfANynNokpoKxJBPJScf1Mbivm-7wJFRipf2-Ay4HzXhXZ4RTkpoq2MMC7cZkHkEprUlLshEhCIHF_6sb1Uhqg4E3UPCCNZ-X0epbQ2GmhtaaIt6BCnWz4SccN5qTks5XpQarlyTW1HubLoLjjXmwJ5DImdUGZkitiJw6ermiOFAFhLfhug-XVKBcTBZOG_CHjrR_2j5TPn6FNLHbYpLYS5hkrUWCJy4U_1xebGl3F6VdQDy3LHZehxuKPowPtdYFenqdJ-naK_A2ygjDUdGBoB2-QFaq8ZPTAti5_Ca6LgiZPvzZdGZ712BED-Opges0mwyAhhsgKRvjjztcsiZ21QpfUaSGLS0vO7J-NcRVvCDyBisMRKfRcWk0PFa4LKcqx9_FNU9nqXH1RXYh_WNAJRVLJDR3WzpNzDv7xMcPOYUUx0wuAYAWcGbc3i5mkVRlzRW_WymBibPF_Y9Yf5yt7plmai5dzlg6aoRdrzSwT9Lphrf79QI3LfYzOV4sXmRGEnN1ud0FyfVB4aLHSsc59_eiPswLL-xg8XT0L27IU_Gja0VuE3zBlErtlQB4uPq778Ojs8hucNTD0rjxs2qqA==', provider_name='openai', ), BuiltinToolCallPart( tool_name='web_search', args={ 'query': 'Israel airstrikes Yemen Sanaa September 10 2025 Reuters death toll', 'type': 'search', }, tool_call_id='ws_0e3d55e9502941380068c4aabe83a88195b7a5ec62ec10a26e', provider_name='openai', ), BuiltinToolReturnPart( tool_name='web_search', content={'status': 'completed'}, tool_call_id='ws_0e3d55e9502941380068c4aabe83a88195b7a5ec62ec10a26e', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_0e3d55e9502941380068c4aac1c2e081959628b721b679ddfb', signature='gAAAAABoxKrgINXOfVTRxYfQpc8ZZGXsBHdv43DhHkpUjfExhAS41ACM9vHyRgDNfC9E62QVMWRCWPuz5QX9ks0NtD76PYS8n5bessBYeBtYgbiMtl0piW1gE5dlw-BeKLiijMhIVwytWhF3JTzoxoA60FjPK_sA8mFk6wDCNKDXlaLWsLaECxUwCtdktN9SQnQFgxKNemRKQTyRTNKsurCZSSt0tHyd4lxO0Ei3F2mO3WB4Oq28BeVG7RKlcZ9BmLRdBhFQX5eoLxTBHwC_qgSIGzoVCiyClW1OzFzXzmaCUCm3oUDQjooYIZtQqK1b8FBArzN9seOJ4vuxu2qqdtF-JC1vAi-_9J61EwELhN5gYvld83zGCSPg_asjeKeoA6qnA5RFtYwh5kmMSFo9VzGp9MlCmb4_-L-iux3JKc7Kz-jvF1sXSH7YfKgBvcn8HcOdXGjU-aBJTmdP3hCZSL9ko-NNsUO31667QwMZsQTlVoTCAfWS_xDEI0QgmV2kFReKhKanzMmOToUECPPQHQfofCGxwxjbGllSyhpSZHIdyjXpHBmwFALBflPAfeM8wUbqQbNyWbWTdx4Uz62Z4j0OGfcMpgMlDb6BON8vvpIjmlV-fOqRlzkP97klPBygPKeRyT-UezEN5Vj5t00nmB-cV2kNj1WYmL8-eBuJPs3LOU_4Q3ysb90AxYxRJGOsl74lEBqfUKb6b4JWff9JFv11EVJ-puIpE7MA3DPM4NcgGfDZYyDvLS589wbTVxSngBqEOIOEcAZF5Tae93Drajy_x8fXm9uWc8daMf5kqUeq_vwr-ZqEz5ZBUvhvGPL7xkYfTfn-RrQXBx2JfyDRakf4X4D1W6jaO_LXfExH922e9hQ1vH8VA_GPdOIqL5BTiIeO3qFjDSRxMi94XWPPRm87yStxEjx8bse00Bzi3grZ1c6M5dEUXNaHrnvEdJZECT6lz365_Qbl73_Ma_2CLYZhLhtqZRZ6Tycfpprg7rWxqTftOKq4twUgCzzv7kg0e1f_JM_om5loPP6r4MOeAL9O1p49tWmj1kQt_nmYcX1WFTQOgRuB_h3t6ZeOsDb3-VYjIjK0pvj_X_VArrT2suBVitTBXumnG2dXg_z2k5t4KTbWVe-aaGhije0VNxgPWCcu1RlIxOaz', provider_name='openai', ), BuiltinToolCallPart( tool_name='web_search', args={'query': 'typhoon September 12 2025', 'type': 'search'}, tool_call_id='ws_0e3d55e9502941380068c4aac378308195aca61a302c5ebae6', provider_name='openai', ), BuiltinToolReturnPart( tool_name='web_search', content={'status': 'completed'}, tool_call_id='ws_0e3d55e9502941380068c4aac378308195aca61a302c5ebae6', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_0e3d55e9502941380068c4aac5d2bc8195b79e407fee2673cc', signature='gAAAAABoxKrgkfoWE9D7tW3LtG9Hb8kBR9vHgjhSKvDrW0_FUU34LIByJhhBiwZOr5RfbqX9mBwahQKrIVAev3WGtBfgtJF0kP67CIXXRjA1-RHuY-4QXL_w-t9gttak5Dje2NU5hNyp-LyW0plO7DZwZDkFUgeW5plxMzcAFNTdflBSC_-zYqBFl9p-11YKOslzKYxkfQrDiodarFGFhDOJr97qwo-l4BhSg8jywQwgFOTSrOjJMlZRSrTkHd8CUaSF5rUaLKpY4AZWtpiR71otchA9N-d0AaVwnnzJbe53PXJpe4fGUkmkcZt-ZOcNTQlIpifirDsXln2Sc3jxSM05fteSPKoUeUFIIqbCaZwBPau45DKq54PvkVQ4Fpv8JtfqKEuQtJ6EVlNJALuDlskdxM2H3Z7XJsXkcNCVAKmpA80yYwh3eApMr_cERl2bLS9jJpGt8QN3z1yRe5oCPCNWj2_NTgtzjknxcFy8HdT-pcTzLDOhLJPYyl66psc0Hn8V_GFIFkRBa8tWb7CTLt77a3pW3Ifnxov5ANAaaJLM9gGiH_DgkkuNZMR3dz2sVnHzAG5TxmSQteu-uYQgIYanBH_D2BN24JfBFxckpT0z-kGHbJnL5q_wBeyy7o2puohaH3MNIluzWARcDWaFa1tGkzeZg59woqrrddAdWLRNULpnX9fzr7aAWXr1U5-XkSjyfWa4nmIFtchwPSC-12wHRNFDzdZiUvQDdJ2ENGoIXeYpob_O4Wa5zx4zZj_qHXoQWXLELyEMJZCVADjAjO8uy2gXDxZKcUxyDgi17hIyFtC9Z_4rxDbV_S_JJ68s1qHBZljuH0mrkLU0KXmYi5ZgB_z1CEaz9KkL32FGBt0YXuFoR0LjnrdpOTa9ifWC82ZhDfjz1E4y9FUoGPVl-QYQ5ihDY0LswB1x_FJfvwRLvLRtMeeGqNYEwnkX-XAcVa72acijnRJVxd5WjV5nolIrtq55l941oeun2ThZJZWujP7eMDuQ8SycBOx_6Bz6wECDbnCrfyxypwpVhKSPGuI1IoP_8fCeFDWzZZhD2bTbH2Uw6nzm9SLODQ47GqYlZ6ZtTIgNBlGpiSUrqXhtj9_1hkGZuGv6AE9UAjFNqAWX25db2I2uH1MXdsYRPLZFhYan9G60cozj6N0ekasNkbaAod39JQ7zL6Np2O_qz85s3bcJSS1_aIxW4YFSEv5IYFlztQrhnlyE_gloA8eRntHAinUaGbL9IKTmuj4w74Al1sN7ELITivL6aZ-EM-F7vvFM6Rt4gL0NvlfTYsafoUL99EfBTh3Rfl7pIwOQWXxg_p-51s13BQ1-HWOQxu1lyxbZdJHmhi-tIzk9iyQh1tbkCZJeh_qF-eGH6voxUlcz07gvTckVKR147UPjIrfSm6EO5zXBgva0Zk3nvGFCZshZSau3tLQrAnB7hQ3AAyQT8_6eFBHtsscuApVGtRYIw3vi9decgXmFdvSEg4Iq6JNObTilSq6a3zmUt8fop_M5qYzq-0ctNsXN5lkqi9iB19lLw9EyHNDgClaTAviXWh6aDdbWP-atkQQ82PXBnKJAiP7luW1qf-YVHtKkwNadbMy82CT-dMNu9c-chRSx3g0tdwTex6tgwKMdBRbPWa8NVZreuTy8x2yarHskXhHM21jrexM0pMbk', provider_name='openai', ), BuiltinToolCallPart( tool_name='web_search', args={'query': 'Nepal protests September 12 2025 BBC', 'type': 'search'}, tool_call_id='ws_0e3d55e9502941380068c4aac9b92081958054d2ec8fabe63f', provider_name='openai', ), BuiltinToolReturnPart( tool_name='web_search', content={'status': 'completed'}, tool_call_id='ws_0e3d55e9502941380068c4aac9b92081958054d2ec8fabe63f', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_0e3d55e9502941380068c4aaccad0c8195bc667f0e38c64c2b', signature='gAAAAABoxKrgxBU1Y3g_B0Eo5nVBHYxLC3Lgh2vNx7AcpSm-o7XiHfQvzLqaLvkI-Cc3F15mQexU0OTvx9FePdIKbwkMNm_X_s_K7YazPjZUTQ0TEod2VereH-Ebh6Xjq3bHm7mh5PWWGnY2SqVMCdKGtrXkoMzBraxedlv2-Tz8o0p6SYuyzM8yHecIfkG6Zd40AdZSiDzsnRNg7gA0zCddrDrRcOpeMTzSPw1z74UZtng-_pPeiv-TGCgwdlmBv8RRr2cuQTYE-yhcp6doCMKqemL8ShuIyfJz0KhQPwYE1zM1CB8sFc_TuArJJD3V2U-Bl3o8anIA8X7YclTlzz_N7HROtVI5qFQjSNhSrbxZKUBFDfAayrpQBEOyIRu7J42uAiBmoyms1WG1E2UtO69nx2ELSJs5yheEuVy4cTXyndBJr2sCs8VkVvcX7xvYkfKeChvkAbUfCotc991qAiyVNzhncM2Z31IEXDEDypeo2IFSwAcKuuXgePFFPBiJxmNQAQmErqbSoB3Woe1j5XjAzJ2eY5YEBZ-68GI3B5wmiZOLsPla_L4iBrczHI1iwGASgtMsuHPj5KVzwef093kg9QBlt-7pZHM3yoU1l5DFSJ5C168MdMdNGF3hn0T2Q3teUmJ5khgcKMKz4_ZVUjEDq8bPwp8DiaWlFgTv-Y-I8etik4o35EFmmmZbIZ7tk69xlBrGizm_KlcYWHBQ5BfuNyZDXZ13MKDyn4uyYxRvkHq4z4jPFEiZ3xX79mlNP3-B0T9g8CsqX1G1prKI7lde6oAHcWPFSWqZmM_JxvYXDBbck2DpEpx4xTuE_iJfGnKiNzanqV4EdOXiCTBVLZhMvXj9rAbwnhttvz5WhIeYAdsKEE0M1MUHuSWuWFVtClp6lPKSLtHQCBtE6mpPDyzUuaw6S1DoixZ6f33Sr8DB-EwF_deHRa95kEN9w4i_LqNbl5QQPF_1je6spo-yQTDpHc5wUidI0fBEQzM57rr9XH0F2afZtrQv9HcLfWKVufBTdd7ScpyOaKj70zgqTAq08Te-Yrj9eo3tbDt698U1fKEYW_uqP48ZKmnSNtFzKOoBzkPpKcwA5AQUiFOYH4-iDPDTOH23SYx8vlymoRiK1imCdPwWYI3miMURxPr9-zCHoM7AiB8cnJlD--zk-j1vQqcf3AntIKPwqycSEuJ7MWb9iN5Ybd1YE25_ZiXKJNVg8wnmTueelRdeM-2JVzAQwth1_3gnsemXn5v0uDVNpxvXoRtR1w8L_zQzKzag8kZMvfESnLCAEwYsCcrP-ngO97iKVvUQnII4RUtG_mSPV4V6Ses_cMUVqyHiM_W_frIosY-7dXnlox89-SPWrRwyC1jlGRA_LE1fpPZ2cZU7Gcyzrxp6yBuTCx8BHr9FJvqgbqtAUeYDpr_Sv-RsG8-w4IulSNZLH5Bh8TyvBGDhi8_lUbDCFTS3KI1ZJ8KJwbNLxF4YUI156zkWIN5yU0WDVlwoxpJD0naMPZzR0sQadMuaXEvLXTFm9Gtb667B2cjdzJqbb8z6NkAx3txRRD6EoezoYADq_ZR_LYha0iwv3bHvg4HIblhU_GVhnU-a-lQGQhTJ5Mh4OmrnTGUVD2Is1OVI0EmNscUuaVc7M1_ga5KbOgyff6bYS0ARh3Io5ekKQKkPVyBLgjjKlej4tB-vSEgitDhEJ-PD__ouuFaogm6twZy7hWVn9cgJmt-RHDZ6gOZm4QP8dWqRpuyEAtTpWR2TLTQVgM05hWpDqDL5AvBjAQ_GWkHCvdCvUINyyl5TsyXUcL207shrLUDCpBe_kESpF5dpAVng8_Zfu1dt3c04cCG1eg40e9JcO5iA9-upTrEPIPrXnAKy4vw-vbhQyL1r2jZWRVga9Do2idmzVf-c7yQ_AHGmf62SHGm-qqbljw0sXJe1rdPt2IHxzYXkhxpqqoaUueQk-pXLUvpMFeMcH97sK3toeCO3oiWQPG-nev0B0b__U8ntgI5m9df6n4IA97iS2zSylSY-F-XEJmLM2TKuSEdgAx1EBL_jyRQKB_8PW-0hSQGJLT70SQqDUJexwyrKABkApv3FuSH4FO0rXZ9TGN3GsnJSkIrTrzE2NG4OXK4syrmtBCb8DjsiicvjAvQhcouOM1xMZ89aSG9Psx5HRnViy6M73TIhYmWO71BRNEayMJaOMgUlgpl5alvV1YFBsChL6mxLVAJWUFuv2YPNaaDRqZEXYHWljhwSn24ASetweLc5GhnehdiT4JVJ_nfT3bygPIjEzvvIa7bbJSeL_bcY-qGAgsuR5m70BdjIH6xLmuqn3lEqulh9n6IPaDciryWqRr1OwxZJQ0-x3u6-G1wrbtrhVMK2Z6cyNUX6MvIMz39B_782X4JcLMrVm9Jgt6qzmfbJPnGA_NK3e9dlz6hP_AYoY-Je-IZEtpv4wyXAYE8v7QXsZbf6DetAM2LzGmxkEI647-pwVPQua-L-84L56GoAw9yDeoXxgyxyf40sbaPIiVLgl_3A4Nghl7uOnOX_1VnZL2X85zCkOZbmm5pZbuSeKesBYbX002PN-_P-P5xRv5b8dZzD0utGv4GUuZJXKJPhbpv8cuBUR0BYHKBQkmOzOBxgCFCDtX84VkZcrFwmQHcS7zmjgqEl39UNrqq6NZXW6HZDyi_SSvEYV7eJfJfxnUUF7RJ49RtSbC9n0AkzorBi0mSMnCC_A1zhamNLjT1-tj4E2a1zI9YsBZ8lPv3t7a6U85iMYjl3kCPiAXkRIDVBihBK4ki_OEa4v6kNBEgXNMuFmd1l8O3WTqZRSTLek4yH95V_uE5DQ9NH52pkgrN7QOe0QXxZ0aErqjkSQRbbhFVVRYp2VN7QpvMGZIAtu_mGssA5Id3X1ZsLEU9zGNibIzAmJdBjS98fVj2MsD-4qZmzlWiCGcC5ko2bbpTrFGtr4r3-SNc4UMOa3dsdyrRlnK3o_tbXbPN7c1H44oneAsqWuekfUVFGvCRm3yA0X7njFB2l8tSXkAuophgRUlWnzp4mEMcpFRwEX3WEnK9hPqXEhdirLtC18yupkKYBtIpCIT98zgJNb5TRbfwRplInEG1E8dk4gCbwyXCNu67QEI2NM2yqCHc4P5rWhwTGAl30tmDQ064ba920L9ZV8d6PgpBHZmUxpJ-JUZuYMzXfCFdlBQANdjtuxCy3-Pi0-cO7UEA84WN-keYB-kHck3aPpeTG7-lv3je0N-407H_A1TKUqkSknjlmwVdL3h41bbGmqxFGizNXfq-uCGUD2tWaZ-cdmZZtGXxgEQ2z7_tLur28eS1tlx43y9CKtKPPJruJm_7BljMOCMPnSmOJDI0JnoGpjNRqzKbSuZFTihaQSBo_Vc-NxRpFwM4xJgq3z5eShb_WamKw9uYrjCBEEwYFTW2QjmiQJtM9eVHBuLkfOVa66YZowcCvL8aCccsuPbe7KBMCD21IGzH4nlhfgUKa1cTAUiWjRSgn6SO5Wqahxs7dEf44F5HvPG6XUy9HFOe-d61ZE-tJQsHZgssQWqV1UfPsccqgyWIc2yv9aK4pPpu2lcrlGu8aDZDz7pBD-dPUG_B9XWt5c0CQj4CCnURDATNWqH8J8VvKap6Zn7pBHW_PxNSJ3f0z_l-GjBlx7U4w6XmOMBtJK8lE_Y8CuuQY9dNVnTGMPibCeJt7M_Q9-IYcqhriUh7Q5WkCvDVu8157gIRwwUAvgqsWcD2msXtO9svRkXKxNxYFdW7KolF-y8oxXRPwVJy1bf89pAOa8djb21ovJuJmbvrRzplFGYNj8rGZ2hXenxDoYiKv71LGALVU63mS9q-Y1zfTHCPpA-Rw7oR6T5G_Q35H-elaA_u-vkgh64mQNP5sgc_kpwbVlM0wSl79RcExnmBTpA-kn7B4w_QPwt185WD9jQRjhh3LMQa_crf4nCWLlsYcDCyB07TU0vXQiQ3nynqsX2MstUc2DaiseVG1SO0UEv8oobwLhnSvl3n8zWMWq93NSuISAsaWmqriNhM74aSHw4CVPoO68RSSdNrpxaKGf8kuO9Xy6iLr3VPE_vyMJDq65q42AEvKqP0TCoFUzXA28Tkrg0tsMLsXIhuT5MGtO3O8RpLnthF9vT0lM64jMp9_QSH2BuWYtwgok7xk3gRX5yBQeksAos3c7Jn2bLM9VNrV9dLi7MH_mRl5C64b0Lgj6Zi1USCyyPhL95ZJIvdxLWHSII2RFbL9ToCThKp_cgPZklLAVJXBeIOqG09pIQ==', provider_name='openai', ), TextPart( content=IsStr(), id='msg_0e3d55e9502941380068c4aada6d8c8195b8b6f92edbb53b4f', ), ], usage=RequestUsage( input_tokens=115886, cache_read_tokens=92160, output_tokens=1720, details={'reasoning_tokens': 1472}, ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_0e3d55e9502941380068c4aa9a62f48195a373978ed720ac63', finish_reason='stop', ), ] ) @pytest.mark.vcr() async def test_openai_responses_model_instructions(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(m, instructions='You are a helpful assistant.') result = await agent.run('What is the capital of France?') assert result.all_messages() == snapshot( [ ModelRequest( parts=[UserPromptPart(content='What is the capital of France?', timestamp=IsDatetime())], instructions='You are a helpful assistant.', ), ModelResponse( parts=[ TextPart( content='The capital of France is Paris.', id='msg_67f3fdfe15b881918d7b865e6a5f4fb1003bc73febb56d77', ) ], usage=RequestUsage(input_tokens=24, output_tokens=8, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_67f3fdfd9fa08191a3d5825db81b8df6003bc73febb56d77', finish_reason='stop', ), ] ) async def test_openai_responses_model_web_search_tool(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(m, instructions='You are a helpful assistant.', builtin_tools=[WebSearchTool()]) result = await agent.run('What is the weather in San Francisco today?') assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is the weather in San Francisco today?', timestamp=IsDatetime(), ) ], instructions='You are a helpful assistant.', ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_028829e50fbcad090068c9c82f1b148195863375312bf5dc00', signature='gAAAAABoycg20IcGnesrSxQLRh2yjCjaCx-O9xA4RVYLpo0E7n_6m0T1IUyes5d6U4gDzUNRWbxasFx_3NEhFIuRx4ymcqI_K-nZ6QNsq3V4CgwBbWBXRcBEDVzXSZZ4IoFASBzHpQGbs80RvZkgqmJkk8UzBw0ikt1q9jlUrwMKf1iGdH-S0fIgZn_uEbli1yGWRDryyS2YQWDKNTYuaER_WHVg8DadL6_ltUTwJ9dMzaXyFEenPfuLdDgmba8DP_-WYFMbggATUfdMNfM0O4YqnTmjR5ZnSA6kAbXvnp9sBoC-t8e2mWiCXzvy8iIJozNPo_NE_O1IcMdj1lsaY3__yWzoyLOFCgkrZEnB-_WQNCSx-sVcWWLZO_Tqxw2Afw9sWAvFR6CvTTKdigzDpbmRlvlAJCiOkFQCMrQeEiyGEu0SSfqmx6ptOukfJn4HtQguvigLDWUctpjmNPutwP880S1YwAcd7A-3xp611erVJtYFf6oxGDXKKb63QAff_nZ57-7LdlzSSUr6VaJa5dneGwCgKl-9J3H0Mo-cOns-8ahZOL8Qlpj8Z2vZLS5_JQrNgtmDaaoze13ONE5R84e6fcgHK8eRhBNTULgSD13F59Xx7ww3chlqWeiYfHFwmOkNZp0iNO7RJ-s7crs79n2l6Ppxx5kd4abA0c58k1AZj7avFrexN_t7snuYqCNPsUHMUK_1fSq1toGa7hTVX5b8A56WFSdMlFD51AuzeIzgaEqBtGvq51murGbghqUmOy9g-6_vHz-WOPZeE1M2p13VB1n5fIh3-V7nd9PAXLX1kLLKiS2ox5tODYvkxf6oqjgR56n5KCuWtF9WzCwikaSMN8pwC3ewW6nkkSCPhTBASEJ7BK9a7lDlV60T6gikDbZGHcAfSKDZ5mBBwSBRpDfH3F0MI0Uo4oQ83J63J8a5r3JKy4KVa-5eNsNZsCgxO-7xx_fan1MH9zT85SLwocpvryGSbIDD9itBHK7Yo7REFRV6_U_cdi5RhDpEc13QETSsFT6CaeoL4GAwvJDCrcKjW5u64StH8l-Z4XDAtChG-znHeme6WlJNElY5unp9L-IolqqypTS6lybk7bfUtGPBDeuZp6CD80qFkyd46M16vP1mudv8rMC_ZEdFvCoHDmUg6_KxBxdVbYi-jaXtXYY9D8G6SlfVkeBcNiDCWjsDXSlhE1ibI2pHHN2E-kJLRaHA_Pse0Gknu6ZecQLaUCKWr_mKh3axV9d-pkvxpCcVVakOF08By0bUe8h5ORELsRe5zzMpfbYGaUVhB360OxwqzizyISXmqhW3Q7FHcgZQOCZQVfpuk6ccAYpZwgZbft2YZWqw7_1MyK6TitpdyIwdLFnt2t81JNoJ8zWLveZGpuKABxW6krhjQ0_qJCnLHm03o_D-9BximrLUCs0PbleK5mu4Le8lCCs4eoVjeDHQs4xMm-VtJk_3KMT6EVe4nrb41ddSKX8hH9rh9l2NlPpmPh5UTledwhbtQYdJdQBNFkGei5gpAQ1oHaLkSOYRqrRmy-VIBobxAVBaQWNKcv8CrGx8RIMxrAiU8JoyRsU7Vsobwt1Jboo=', provider_name='openai', ), BuiltinToolCallPart( tool_name='web_search', args={'query': 'weather: San Francisco, CA', 'type': 'search'}, tool_call_id='ws_028829e50fbcad090068c9c8306aec8195ae9451d32175ed69', provider_name='openai', ), BuiltinToolReturnPart( tool_name='web_search', content={'status': 'completed'}, tool_call_id='ws_028829e50fbcad090068c9c8306aec8195ae9451d32175ed69', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_028829e50fbcad090068c9c83115608195bd323499ece67477', signature='gAAAAABoycg2MBei1jlOMd9YfezZ45PArjJAExhzJt4YG36vuQT_e4K6W78Awn6mrJEueCnEAbciBRoPBd8n0YMXbqTiKdgeceqAoZu_UJAVWxgY7tVDlkg4e8BgJ_SrAumbi0yL4Ttwy5yZNU8g1aICCSdjGqfI0cmVbJpXEyCU8Wt4UKV_912jaG62vA6Tlqii0ikc8UItcrgk94TEGpOEQXlG1HXsWyAryCvOMSM2F785Q4Jx2XOrNv4klRPEZGUeIbp4ReTVXVi0JT-cjc6O3gKNxN6vxzUbvPhmcyTa9UogLuCTHjv3KpcIvBOw-_pF3Z02oQE0GaJKBpP4SJLE2yZsIII4uMls7Lw07EuHZjsZoCQRg12dRle6rwba7IeRw0RJWYEp9aavT0Ttrj69dO0e20NpispmeAXLh0xxrRCKcjxAn6c5XtEbJP54_ka1FUSVY4x8IaU_pCKI85fGmHIx-HarXBtWzZO9B5O1K4Pqr3BE7LELTXaMwWQ2SU-RGsvgmDpmUZjwifQ2YgamjIJPt0UcuGWb8BTwssP81XT5mQ2Tsq1YjQmgfzeF28yeb7XhkEaBUNejSou3SuEXZ9aEuSaMz62gzPSpsSrr51QoBJpMBF9Jd7LXuFJwaQV7jP9NJawF9GT-CMWj2IOXgVca7cL_d99IMSR94vNyg8yPzDsncJZ9Dw3HXFsPfdGHtO2FaFUB3RRZAVKoHy7S1NTNfLxdtB-p0eDuu1JbcsgtULWC71E6TbPxg8OguiEgAPTXJviUAed6udruUrSMlZQv-AgRYfxYPPMXLeUIWTTUo6PKICy_PO3U5CF6VBkaNUvCLf317L47FCeEAJNTb9Uj_S67ZqoAnEG0tQG7tVPuN13cy12xO2-8xFQSpO7gg0DzF8vCD1cAcKAvo0FUEnIeXOVHVQxThLHDiXOmB_ZpoT-qJYb88RTLNoAq5oI0ZuZYvPHJ63EhVjaANKwNe4DrfAvoPpf0qWiBOH2vHxnlIJc84pRh33ixB-azK7arhetqwIuLhDo4u9REcD2avxew8rDEOTqb5Tk02hhCKX9drLYCriNdkQh3mrC3KYzOWZ9aebwOR1c-s54KbvGDHAjTNPCLlROf30MmTON3jb-NW15YyzQrVFfV1c-egUiWRwMVE3KeWi4wmicK_QGMZkdyEqZMSzNcgOZMFfUWxdUKxACHY5J_7lUZltrz9JnhsfuM7KMuEW3GMASIP8f8WmR03nleJTi7k21oLtX-xz1gjble9WzSzd5pTz9GrFw4KWatCyrLXtKWw9fAqm_k5HpIJdya9KK3jNve6MirP6jdetIUNIbN3MGkMJ8lfavyTaa6-t4hsQSmyTQn6OKwhK_PA8-KTluNMW-dpqZU2YPFYk_QHYW6EJe_Kw5aOq-zpKR3hGgoHm75Ossr23QERsVgP0LChljPzR4OQlce1GMDtRNqLX0wGu1RO7OdM9R_lqJWMlIaAa5wfvdH5LznaQV1vuGPrfpzGL4mlocKDv8ASvrxA4bm5fWBoqsfzcLu-H8uz069vLDyHgrPNse6W4Ex1BVY6By0K_f7sidbmc1FxwP3ypVv4nX_lncg6RiZzaQTHTxXJFmvVO8_L9XBHJcGkQGpEuEjx2aMTWZGJNxfaO2fKJ8U3XflYVXJkSg5b5ixTHuvDYjCOELs3fTVAy50CuMXMoCEgyZlqZNg_EJXEmz5niLNQnwQPRWUbe3kicaLzJqvZrtrvPOPcTM31Ph2-_dfEOeKNOIE2B0pvMgTaFRck_xOc7s5J2tWAEYszDz6aMXvnvzm1WH9cXYLbgZPyJmMUxeGZ70DdnueVbrNr8VA5bzvjkgjEkhks_BQprXEAZL1lSL2s0O9G8ekgFnt75JBJmSFGT0twl-t1ia1BFkRtMGXLIj91xWJb2GsF6ZN9Uknfm0Akfk1STtRbxFIeBRlwQsix5rQ7EstyhfsBXiBILky2rSfj0UJwH1NjDskXjFxxpy-FEE7KRYwMws9rKKuMQMyURUK-DbLvMmQoxekYvqu7bJfWqxj3lndGwD1sQL78cpVVPVfJeqnlAw7k_xd6QdHg9DwSlGNb4OCYdFWT4xaaltFIJfo6g1Pay7HD8gWTrrgUzHgEWfbJxcKIXs1etHx1lxYVTmm9TFkXshmsbKptL7kAaxBy9JknSsGsh9gZXf3YFkocEj1xa8f8Xcuf3zatefAeFFh1Q629b0Sc-GzfXnu-KfuSyJzAZulrP1IQ0jlOiGP5hKnvzePVL_JZGTNJrJxmtWXejLodY-JzLzUjIeALKtyUsu1ELFtwDxyadPSsFW8qvMeolLcVDysGm8NkmRgLzQTBDGR4AcipdozZmElDRTm5P6JArLlqdZCxXpiOH2x4juPIYUfRrrTT2g6emTXHz_AurjFgYn55G6xv1YGSuM5tNBXc_WP5ya9cdpBIEYj1i05DIMsvUPsNAkt0MIeTiVSPPDMgpT4lLsR1ezwBMx2kQBJI6E7rmH9f3Abn5H6yeKQLZckAAru1SLkVwoDxcTTJZqD3sZt6RhBDuuMWX5ZoB21K-zkE3Tde6caBupWLK-W2eGJSJ_oOaG2YGQxL56irxU6DIVxLuMWUTOVH5vpqeo2RlrGpXu-lJkg3tC69gXlNd55233uIkchhihakwSIxFF1Ka-hcBlKtn0Kz7CXrXam4B0sSWjc9xGRfSOaQ6LiameoozXfhj8r_GSOwoV8EMa2vIBFggFGrPEzaczNkOKBiA-xTQtdEPqmfQNznuZ-B-VX-s0E0Ew2EopP4ljZ4QMW8k6pbNX1aegBBxbxkNc5ugJhBBoSVJeEAC2Lw3iCZUnX_leWUJBp2up09oJtRWlnGG4mLAu7nYsI7blues0ZLZE4C49v2eYBmfkeyq1DBAGXu0RC1qMz5729tzLPUEPYpKS1H7w2iGHQ9P1jBBWAAfFoqgn1lYtBF1ioxL7ry6YMrvCgTlqvVRXB7zmAUlsJdPq-CTWpF79YSco4fAhrDVCmxdS6Y4arD7p26YWk8PioCDt9ranaUi7--wlyh2OTdJPHAUHW2-o5NaXXfhqaIVfCqH1sbVmNwP0BRiAmUlwK7GB_m7dtEztYz1sHl5sXmXEDcFjJtr6uozFDjEA42F48AVuZMlQfQ3eJNSRqHEThYeyzbtCdYZ6J6ntg2XS0uDHISgM4zi1mDeur6-ZCw4rGwUXvB1BWXifFeh2miEGtvRzw3sa1zBKBCGtYtRsl4Iz5Plo9RNN8eQ_vvwmfDk2F-5YWsDZbpJuSXQXy1hjDvyM7TVGj4uL9gxFQ-ZCxFl9cufUeqfEGgHX38mZoJAT2emXbe4A4byFYvWfM-NxjpbNA67ZkOWgcDPtY853Y6dKoBihh49ZAzvmEjmPixKp2rBuNX26jJzhW2OJH91GpsncHGwJ3ajWht88XbKBp4Lb8sNVxYD3hK4c-mB95WYYaUKe5_ugc-PhC4FGu-FYNLYTX2ZxLKpk_T4uEG64zBQ0NbS9y8WWiTojeQ7b4-MBG_j3VJr5Pi0T0meC623J2ldwud3DRBZXB5q5rKgofFF6WqvwhIDi8YLL7CVUJ9aOE57SkUKVrYYD48Cv8Wv9piI2hbTgXwWkCpg_tVROBjl4RYfYVlOBV4pM1G5AK73PXfDGsPdiCxhmxHlvzanAm30eVKIctRaS1xlcBqLp8CUPkgnPDlPVclMagd1CjIlN4igMnFN9gDPOUckrA0-VBlg-EKsHG3o_jNMbsvgfXg8BuApc=', provider_name='openai', ), TextPart( content=IsStr(), id='msg_028829e50fbcad090068c9c8362ef08195a8a69090feef1ac8', ), ], usage=RequestUsage( input_tokens=9299, cache_read_tokens=8448, output_tokens=577, details={'reasoning_tokens': 512} ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_028829e50fbcad090068c9c82e1e0081958ddc581008b39428', finish_reason='stop', ), ] ) messages = result.all_messages() result = await agent.run(user_prompt='how about Mexico City?', message_history=messages) assert result.new_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='how about Mexico City?', timestamp=IsDatetime(), ) ], instructions='You are a helpful assistant.', ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_028829e50fbcad090068c9c83c3bc88195a040e3b9fa2b3ee4', signature='gAAAAABoychCJ5ngp_Es2S-gVyH01AJS0uQK5F4HdAkVFJcXPiZanGRjmEPXNGx45nUyTonk62hht1dZ8siaE7v0SCE-oBFoP3du4UqNqtCmJ_0_EmkXG7sHh3pR_zuS_iEDGae9S_qM-vcVXyqFYbEtEVD9ZimiQGtLEU7WFyQq4UeLuD-U4vRhpFreMCAfen1DkV9txJijEPRL_2cTUGT47rpi2HYyuN1CzYKzRrn2qbHsgDjnPtZ8cY-QGTm5Mm0LHV9GeDh4MmRY5Lgxt0slssKI7vy3OqTWR3OCESp-5VmMR3fbyVNxkeogT9XqPfnl_9maf5jYLv57tVGVRJUEx50QvMJ9V20qbUzIAuMw5d11s8q627IyyFu-bD8QmjGsaBj_wsjdMe6adDF8hzOau3svjuouGf066I73I2euw2NpokdNA8fbI3bAHfqyXpFDADKXg7WL_zYB0eyREbWe3n2mo3KL2sLW2908ScYEvsv9VlAo6q1vByI0wfGmnkqkgBvh04Fe15ljjSkvLy7iRnOFL_CCPakpDcViIOD-yRSDk-MSHpQsK1sP2GgxHHy8jGO2g_ef2bOH4FkcYZK1oJLIUGqhLJI0LurXFnLZ3zcUML01aV0rMFyweQwbdIjpivIGaAg1BUPU1Tc8nCNmZC5aRcbixMzzu21HtW1SWnMziebhKHyN66b5skUXl_RHrCoKhFyJxSJJjxHeuUKHQ5VxvJDJSylZjHvMkX0KQ-Vn78pv-Be5ETRxR2G3Agp-a-iX0zM4HbwVyoF5l5t7g07pTrfEMP0WFJu4_OG_tsy4u53JGMQwQLB_RNYcd2n1yXPCpZYHuq8Vkt6-A7kYHW3wvUmI2cSyZGBNpwt-pL7kqdPaGyqnfhMTDzTS_CTXBBrCjjQg-RsWGu9hYon5iKgHFv-w_qGykzyPtEzZt_VWUrVm0WFOinLqLXTQgiKm0sypDdGRht69Rbfe9WqP3fhFychLwcP22IvDQsh_OenHiF5ytB1XTI90VB4e890QUI2CzsnH-8fFkQT9Bj7ou-MstjIeOQrCwDGAPRnxP8PWoCg3uYk0DuAWuJY0lYq6isqGKc57Lz1bLaGRG3oYpWH0MC6b-D2y7c4cAgOYMhOzYq2ufblZDinvBLrr9TV5jtog21xrBy22o7dbVEgIJ2T2HI2XOmjG-l7qrchcAykaosXQkW3ASIv0OpfG-SSd9UU1_1dOUFzOXGej5UMxZidzQa_dW3XPLCqVqgiDW9HCu_XCmSZo36DY95I2hofXq5mXUHT4qxdZ48y7KGiM6mllFudcdyXu1w8ZGFlU0BfzKDOfbhEJz7MRLuXL6GO0bCHqgFo5WHJrsTNrXuHNNTe2LxPPIpejVl6kvE_1LtHy2jKffOR_BcBCS1c_KLIIbl7U10__OWglq3KpDXuupMa9-fXXSn0Ko8rRybTLQpXIn1D6phbi8hhS93EkaVE-9zZZGBvgcYhPP2fa0XniiexQcX-VDQ==', provider_name='openai', ), BuiltinToolCallPart( tool_name='web_search', args={'query': 'weather: Mexico City, Mexico', 'type': 'search'}, tool_call_id='ws_028829e50fbcad090068c9c83e3a648195a241c1a97eddfee8', provider_name='openai', ), BuiltinToolReturnPart( tool_name='web_search', content={'status': 'completed'}, tool_call_id='ws_028829e50fbcad090068c9c83e3a648195a241c1a97eddfee8', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_028829e50fbcad090068c9c83eeb7c8195ad29c9e8eaf82127', signature='gAAAAABoychC16oV3bX-2fpfsHcxFWoRnoEx69lgG3ff6IIJemlYvbM8OVbf4e41oydklk1kkBbyWg2spj4puPrSV9w19NOknK00NJ170UxqM5jqvtZHcvAAdeBjA9XSyRObTamXE16W3KtXvRvyRBmBpqpC6pQGX15fxxdAESZUV6uUexSQIYZEfCT2q2aRj7YV4kCGXUQoMRvjzFE9YLE4LDNrQykcrIytjZ95hz6czjxsd95qmYtGdjMU-s4BlOvs34pE-d-H7cR3a3cQHI8SkpaQrL7bCOxZk2fYws-t0YBXEsOIRNCpX3uEany3iGgq_8jn-ggeZtwvnA6oRFtIkzpscLaU4kwhlZbYHNI_RinezdR5ByRjwSdc2UHvqoLb4a2rYmHSLLpSmvr1f9UesAz2M5AexJYlk4sDmGhMD5DoiLy05lbnbo86osBDmRpwXhb4F0pSVgPxUEadMvvr_l69Mv_VAhTJdr_iLFn3E15HCLPCFND9TcROgxPzhW7aeDrt8fJPwEZZ4fZ3BAphxP5sOzzmd3-6uwCHLZxB-51ILHGMkBVmGxFSXB3u5mr7TtaDafh7bxWQv2bpLoV3Y5QD1lRvBj6sx95B6J-CWgw0WeOd7jSgHR2Y6nDzD6XAGgg-aEK5Jk3CDGLsSqv6SxYMoY9MvT16syFsNuEki6XDx3cF252VeOHIPNPQiqBB5NRgf0Vx1zAMgAn8EYWarg8bWsJrazh_nSKWmM4gCFFAUK3Tqi2rfbx6eCPlPBYHxX73GdiHrypeAA50pqVySFxXzXgeRKghzGEQetBPzNMPykyUmiDuq3oPc_bliFQu_15-rDhEfmJcfS65DpL-_tLdtTFV4-BeAjVNsdPjX-7I1bTHdZzyuBiMr5sltxKzmHd4fLWLKv_ZsAustyfUmQnO5_reR0T3SwlY2Ytg4wJo96dtx-XUqJxWgZ9tAW8_rhwgejaH2H8zTM2wczgWVXJZxlsIl_U1xY4pSgxosqBq8a5EPrAqJFnpcZqj9ctCImVN5oElb8o4474pOhSeY0qFQgL5iol5d6QB1gNTKugU_rCgAPbHwBAvnONLJ0v3hQXncgcuIJgQw8BjpOgS6KTXLmf-5uH6CyXum-oE3JJy8EMBjvyerecMMQl6dpeJxYHlB6B0RUUzTI5bHFaoJeSGetoKH7t-L2lUwgcL7F84Wf1ZU3EUkCPWl6DdUq99aLfYLWPqd3bQ2JCvWiMVrlwuHZr_8l_N3gCWuy2t43N2nAKBBc3HWoWRJPgHCmkj0MIMdnZBiUD7IXz-b9jO_1ASYT0NhOPc3gqipzP_9lFE0EojjvqUXV1P_OiAX-Cl2cFpn7ACDQpxAGyW0yr-lgffzLI0GA6dP47DMYs0P6dQBD6XJFbvlxigcl_9GURApvAb66ITpFWMeQAJOCGdMMPZF2CahK8Riq9b0RtkSmgmmEL9SUNaMpEJBlk6j41_IdZnxnO4Qm0Fqos6RFKFbwqfxEopy9rVWvkbjFzRS_B7gAc0kH9AbFx0CZ61NZYNVnQcN1qpr0iuJtSGG-DW9EjT56IFtnt_clgrjfFuFj3cwX5ZcKMrN_RTQNgY5QhAPShSXUB4MDstvHgFhBObn-4rDl3TIFJiIgNY9lBz5egE8YZZXg8XxW7nFZpP0fmQD9a0CPdA1BhafzNcvCbReTjddrVeJcHhflTNjy0YiXrXUyJmlmjO1y0opcXkS8R3E-Md73KKEW9wJUOuEFDDr9PAaocHUsvqWPTNb_Lu90knDMKEi_NnlB8SHf2Agg6FkyMo4Z_k-T_51IGYfFJHPuGRZ8-CqK-qI8-6BRIDpnei_UIi2K9ALXGOuYrcG9A4YexW_vPg2qmoVgishgzr-ddFGOuWr_j05j7AKffDc6wqK0PNBTEqpnMKSVICOdOEBcilXsncLhjFm_JmS3JfxaM0Ly83tKhZqjP83hxrL_JvBjBQRuW7LwyYuFbE_8dAysUMI5jYwqPd40mGPALADFca0U1rolFD41tdX6LijA7Wz9JjYpfuphLiXNH5cGqTe4T_ReZAN29DffISVS08dRiQUEnw2-OMBYz_nY2qe1vyEItwYmUe2fjOgec4ClJPdRDXBW0HWVS6ei1sgOOD6FvA0moRFpSJypcEC2R1PiRqN_FEoTXzRsSAPF6pXoQIlgXxudLwitpW5xSZS4v_DZTlGa7GgHnq_dhDRdSw5GzCvqPU3CSlP7GmvxZKA_9WoiHNd6JdOSVJg6x8BGpxDjvJy9T-XB8SIKyNx2ymCVKaEhnNTh9UefBGcEXR32oYiRa6GOLtVLt_7OJ_YOqSU4XB9OEjoWlWisBxCrvnAI6URp-wxVLLkLzAPhX-O1sbjcOkCillvnJWyDbnL12JkI0NsvenYonUdprMbVKcX68KdkkpgmKyMICY7eUKpZfWy32E5stRQFUE1GMZ6wYKGOBFa8a5QiIwIx_4IAU44BZCqBDaV57H9KAlsHhqY0K9PJa2fetDVGb2MKohfcEmF4lAzmHKiu22OINYHBYX1LZulsVrcQUj6zSA7r3GEEP6K6wBmk6i1SuLgf4ze9WC2pyb9zemaZ7dHbb3btZw_xAk5a-RVoNb2hIXfiX9clN3BkMw5V2vbpDHaNM80N8z_3VC5uXkQ_v1543ZFWvxbdvEVHlR8P9JyG_Asts0VrwDnFAo6rTGmPj52GJcmhLVAgZ0KPDrujpGHu9HTV7sO-3KvqxOMHYuKG34GvpjfZzlgV8GzbXtpsRk2E-GJPKLfLN9KIHYMxdfkaWBurYvea7iMYe954Gcwehfvlk83foG1ez6FtysZ2V4eLjg9IcVJVAWucdnUWyIIgYMocgpS6ESkO2wRs6pUz4mg8MT8q-h03BJXmWiJIi-4_3TOhz0owLKMza_1IljVaMAUIHp6Kd9yEPohWQo3uyGulXU-vEsSeSkId_sVxLphe9yuimK3CtzU7FBjewoGhaj9vnTdv5_abDRZ13Glp_b4vpfUrr37CBAX_RwJ_mTqGhbv-mPuFRVD6ESjlg-JrJDCUY605dcyU_0hyvjSFepiHQ4FCEHzL6GNSfR', provider_name='openai', ), TextPart( content='Today (Tuesday, September 16, 2025) in Mexico City: mostly cloudy, around 73°F (23°C) now. High near 74°F (23°C), low around 57°F (14°C) tonight.', id='msg_028829e50fbcad090068c9c8422f108195b9836a498cc32b98', ), ], usage=RequestUsage( input_tokens=9506, cache_read_tokens=8576, output_tokens=439, details={'reasoning_tokens': 384} ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_028829e50fbcad090068c9c83b9fb88195b6b84a32e1fc83c0', finish_reason='stop', ), ] ) async def test_openai_responses_model_web_search_tool_with_user_location( allow_model_requests: None, openai_api_key: str ): m = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent( m, instructions='You are a helpful assistant.', builtin_tools=[WebSearchTool(user_location={'city': 'Utrecht', 'region': 'NL'})], ) result = await agent.run('What is the weather?') assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is the weather?', timestamp=IsDatetime(), ) ], instructions='You are a helpful assistant.', ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_0b385a0fdc82fd920068c4aaf48ec08197be1398090bcf313b', signature='gAAAAABoxKsLzYlqCMk-hnKu6ctqpIydzdi403okaNJo_-bPYc4bxS_ICvnX_bpkqwPT_LEd0bZq6X-3L2XLY0WNvH_0SrcNCc-tByTcFHNFkQnE_K7tiXA9H5-IA_93M-2CqB2GVOASFmCMBMu5KwzsYIYlAb-swkkEzltsf5JEmn1Fx9Dqh5V0hxkZI6cz35VsK0LEJSYpkJjAMcfoax1mXlnTMo7tDQ_eBtoCa_O2IQqdxwPnzAalvnO_F4tlycUBM5JQkGfocppxsh9CQWpr7bZysWq0zGfuUvtuOi1YJkHVlrqdeWJGDZN7bgBuTAHMiuzx68N-ZrNgQ2fvot0aoVYBnBDxJFbr82VJexB-Kuk_Zf3_FVm-MGcQfiMxvwHgEYsnaJBvMA56__KLlc3G4nL91fibIXbh3AZ24p3j1Dl1V3D03LaEdU3x6RF7fF47y5eyaFWyWkmPl1RwiEaYy9Pi7WHuh-6n69ADGYWbv0m4mgvECbmvbBIIkZWr4y0UK0B8hbC-Oqz776Taww73OmchIzgkg09rIz9CfoKcGMXgvzbpIBa4sME5BQ3mQtfIdPLY7uUIwya4o_g5wVy583MQva75jNsR4A6sRVW9SgVEWusMJPHv6NLzHCdWehp6SBcKuovxZayoM4KQrIvUMNlUkrSR-euoBaa_WNc1HeY8ikKolX6emm2LhRzXH5HssCgH0g8GUvWilYx7U-UFSB0r6yoy44_DzsyH85pXN1ivsSU5dGIBQgG7WiN3bfk6oBGSrz4XkBLiHJiBX9ZUe270TeDNfpgjmKO34_k35zviIUd7-kVY4EsJGGijEhjbkInFwhilyH08EdKvYDzrzpKJIHT235drt3eLTKXKEA-g3iW-qOMqH15KPk-slzPNkE8yahWEkLrYsqGsjwdHVXiKF77-i8rwvDWOf-pOs9d3bBxily3t-22D6RsOL6wFYQS6BsuroKdlO3b_0Ju5E2Kq4P3jxtZ8jnG9D2--XEcEB5x9yX_brfdFuFHrF3C4mYVWTrNN3_S9V8zUp4CdIh3EqAuSs_QJPJuN-RNlorK3bwYqOymgNlcezKIqxhWnqtS1vxuxC7msRlJRmzTN_Lg6XuLRNS1uIp8jmx7TcCnDx62ynYn2oGCOCLSspK_T_LVTG6js4Oiw9ZB5A_I3TfDLrtnLRh7pGJnAv9nVnfYd4Y1czSjhPui5LF-FvLOlzWxSu_1Mo56QA1BIerB9lCQsDjPOkLF_XHOFLWGLQANx5nQ2wlbgBNyMcPacQowRyn3NncjfzlSLyaPijEZ0HROyL_Hff5JXCMu5-6muvxQz1TirmbyjBbLjtv93JpXrVvby14mdXdNs97dMATIiqpwF2r0873_dijDKRxIDMZxqFB2ZBaHJc80khjG_NaA_jxv1GEqVWmllBXBz-wUDbUJKtNtI86YmcZboZIA71V416UW94-TXbtyQpGlB8tj_764sn9fKitg3vCqC42mr5Kj_aTzAN34BXLykkFWYl_AfVL5PRbJXc0Uh0GW0xTH8eD0hvqd2Xsr9eCoP0nGM6TBNMCl4T82wOhRy7jelWMpt8LBxAYkw3nAlVVOi2puCoYRaRFWNQnLcO5iYBF8_rg9oX-cUsBFepGGDmoOfwUmWLlYqNZDho3AJ_SL3azAVJz7lqa3vcFubrRMFiGcee6sHj0HJI_2N2mZqBO77kEbXrJ6SiUV0EXX5vrjZGzpU_wZ9G8AUz9Tdgistq8XLVsMC0uZWlbRdqD6-UjmnsJW7XINzH6MnkQwPvbduRKF4ywViUUbKVs5XRVFUQF5gTdVMTK8mIIppJx6fQRfZBju1NuNrdTDjd-5P9_QNBQj89_Y_N1fow_676bSvYrhlrIXVuLGy0-RuWezuqEwenIZ_U5wSTp9remqWzeuolwKnF7xG_QlcxGOgCivkRvqAyDxWiqlBhUtC-oPEQtychFa_W9uLHyBhm4bcSUz9KvOlUTt9fNYgvDWFciGCE7B5iPz2s-lCS-Onq0ZvUiZY5nB63htK1bIMzB5lc4N7XVh6COcSIArGBnXKARHdIenJ9vYBSmB4XBrKOIU6SmNNM4fq3ZFoWIc4gsS8L5LZyhTX_qlmY2L6znek3XT0Z7kjEHs5qQ87_sw9ho2KaqNSjMalbUEp7L0JlU73szrtdpMkmBk3BK0of4Nl_v_CCbmYWW9z_rsNpTpPQgUHNVn1s38DX3cesMqlzlBOky-rpLAj2-sS-Xj6WZWBs_8n0lLFS7FL3IpKzveOXE9eV4zjJSZ0y74b_g7u5US3dT8EgSEeHa_pGOMn3t3J37oz1pZcSufD8vjyG7wtGxYUGn8L9U3zJHN1VdOR9id5VYOo3OLtMjCrSqPO', provider_name='openai', ), BuiltinToolCallPart( tool_name='web_search', args={'query': 'weather: Utrecht, Netherlands', 'type': 'search'}, tool_call_id='ws_0b385a0fdc82fd920068c4aaf7037081978e951ac15bf07978', provider_name='openai', ), BuiltinToolReturnPart( tool_name='web_search', content={'status': 'completed'}, tool_call_id='ws_0b385a0fdc82fd920068c4aaf7037081978e951ac15bf07978', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_0b385a0fdc82fd920068c4aaf877808197aaba6a27b43b39aa', signature='gAAAAABoxKsLhc5YCXvcJidIAJvFyzs2T3IwW0fie9oMN3Nk5fAcAP3apWArzw8DdWjWjR0tn8Fpw_H_xATFGktsCeA5nzkcKvdc0Bbu2bwMo2QUkQZfFcLHqlcNnAcvrw49XpolGFl-mu7hAyP38LGGtjbTBNRh4dHkd-hYZzy3nYd56JQi5GLS_KuxdU78xUW3gNOtAvrseTx1fcY2eseUcNLm8uDi8a_qDw16nFvuY31ZkrmuVCESawkppmxrhGFVg0Y99dgyufnSVXXMKyE89tmXMc60yZiaB1i5cIJQcZMkwupod7yZNGqmr1GtFru5uJq-bJfGx7nAEs50jUcu-rP-_ZbvptkuADDC-bfzFjaeq13wCih8wCXqDWqnGjqIHlFkBM6agn6VKOcuDC18L3caqcH3KEYT4f3TGwg_ZZjsiRDdBC-saqIduaAjjMDqMKx9XpmreRq5BLfC7fPjRykpUcWQQYbQ07J9pe0EW2VhZwoGtd1u96fmz55MzryX4VOWIwDsUTEZAoCzULvVrEBnzFqnfvQwejBxJX2XU4fIlOtT_XpOcI2afolh8KgitzHHpJ8Dr9ELI-Be2KEd6enxmdaPhgYUif2D8ZCVfOoXZEmrFBMQTRyuxtp9H0U3zGamEYuUxRavxkQD77HhmqWOSr1Agm8pWzAN97jxJSxxY4BEnjtrgp1mavtv4G7VHjrpNWrL-smZEWmnCPGKVxP9afrdSZYL-HXKY9yO6__0PR6DdX1o0JvUq1KFPx2dzag4eXDxb56HI5MKNr6J5P8Smmxxwoelx6UXEKw_hyFWMmPUHYD5Yw5dxrXeYmAiomYKFpG0bxVbuAb4_iAVliHkdIsOBcWoix0KLxmS-4RJnikZPMvDwLDWfENZ2sh9_RrQbuMBAgjHwlfWM_tww0ufm_aVdDZ1CULJ5Ki3ZxH_0oIRRyyB-a25q3DARnVzutgo32H9X6qjMb06ExMn--ndCinBglTTGvj1QOIJews6UMrcKj5ZPTc7GyPbHXvdPmPdIrtJ0wCqFj4cgNRuxjiaZDSCqmEQERYyX9Fxu8tY4f7-Fxje6A_zflqrIyhLfzo1iMaoNbba4HNkzRMWba1L1fC8St8MO4ZuZTGs_60FwzSUmBDW4Gl0CcRAdY39BE65uEpKGZeRqDfxvLUelG9YlJTowqN8hzAYShzcPPkgWk_s1AtY0RT_roregPuQ8PQayvHcJzKqnijOIhRA9k6LjF6cnHj90d6fSzTYn8F27rhufLySe56n9SA2WDWhVcjsFEFAcsL461tjiQ5U0mjaFdBQ5H__s09dhp0NzhE35I4q0pzM2KI1YWgLnwlyPFnnfce9bbL81jvbXw8DDC2KfZVOGU-ZDdqIqF0UmwNyBaMYb4SonrG8vrj5bFmCMPSFsEeuDPv_bmD8HRx8536b30RmYD0K38Wf6-UoatMxzgMpgmwsBP6Wh0HCpFeIhjRsJLxYXeoafypcKJPQgKXJwuXVLi4iejXkrbjBdc2Sq2dqIVzzUhULLJSPBYouyjeyVSbYYp9WPoBNWj67uQsX7OUbQN1_qxopsPJdqqQynJIAtULNHjKrDA0GKpyZ3OUV660OkogPAWoxTVevRemwkIJZbr2hXyy0Nx6Xc1Vf9xC0nPclJ6VXapdnjK69bIDHxDUZGCh8UZt6DbcA7azBrugcXlbaMJzoHWkzmusJoTh_2UXRjrS3B33jsxf6LQnUl0s1ETo3Tif868zLvkTEtfo6btbND0FPDFFQrdeVlW4mUWEOJhPeOmwnDeLsafTfRCI_V_xTzgkpQxx7pVZt6mkYZ2qDTE--NhqgFfHPlw-nC4zU6klRdbaO8284QGlbJvHmdsmHi4AtMSWAf-_jegocmaneM1wUquNKoy6hnbkZFul9qV2c-_L077uC4nZYNjRay3lT_3giVH6Ra6WnBovt9ocCYIwSeygVAyqBHxo5EJpfyJhNCtak3bl-CIz2TraYqqUCiB0h1fyxIF7M0uENZKALtwqRVHOtEsN5JVotgv-8YzaBRFs3qvtjQn7eEcw-zrIg5fwMP7tDi8O3TXl6qPVWTCHMa1wkfb7OkfuwXREognLvO-3qdRgxinodvKyHn9XbsUcQMQjPPFMLOs4wpEhTJpcIFPqtR6tArjTT3P-T21mc8B56K1wXfEDvpU64XQ0HnfZWaqS1TbDyfL2i12ddhhnxbCV-0f3lUGnZVsfeGEc4FlST7iqUguhwPGb4mBpjBVFu2dv3DMCIPHew1v92gZH1OJqZJJVDUpu0vvFGTqxHz31LSX6lWa4gn2l6hvkT1e4aXkjHg93iy0ZXMpB0JqJbbWseZY0LDYzpH9noHq626Q9H4ZEKPo_MYBWSS_yH-V2_cN6a4HarqhcRwD9oT1QJ4_4AzWeFIrCZlClYbA-84H1CbBfQjgtRh6zTZLDHM2In2M8mKGyFSfeIhMHIcfPBTpG4flLBmTNrwwbuOP-0ss_bb5gxLeDsgU5xjwfaUzOWXudPJOEorz4t6Oc88MiRH42troV2fun6Uf7e7j1OQSGtTQ1kXf0rroz2ykDfVIXCefX_3io_xJ7ev9dH54CNlARSF6cVpTqzbyLWkA0BJeAVYcX2JW_AT-9VYTOo1Vixja7KtMAmMMk1E08japeGnoAd_a_4-bEfklFTChseUDgZhOt5_XtBiuQdPvJDorSQWQl8VCPKdMATr-EdUiZN54GSM46pdBr6p-Dg7LvB-zBAbTlm_6SET0O0k4RkkHxUCtgRMZQ52aC4brcym771djtWC-BbaR5CefibOoSo-i-BP2Zf-RVaS_MuFar0dT03zXdb0XuC2vuhbVPPF-7gsJez2dufEiU9LBhV3__zTDlFc-rGwwf04Fh5KuleNzr1QNyVPH9GZSS8jZkja6EcRfGn0X-oBr2oRLyxuL5vWgOdPadBOJGjIoRnMhCAxGla_gD_5m0qwF9CtWWv7ugW7YpATe62zE0O1icYDPwaXGovzTOeRDRn4BfJzgzwLRkP3-zOgF_09X41umrq0TCnCujXe-JOhFuIcYx8IxOb_cCcfGRqGXeZYP7z', provider_name='openai', ), TextPart( content=IsStr(), id='msg_0b385a0fdc82fd920068c4ab0996c08197a1adfce3593080f0', ), ], usage=RequestUsage( input_tokens=9463, cache_read_tokens=8320, output_tokens=660, details={'reasoning_tokens': 512} ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_0b385a0fdc82fd920068c4aaf3ced88197a88711e356b032c4', finish_reason='stop', ), ] ) assert result.output == snapshot(IsStr()) async def test_openai_responses_model_web_search_tool_with_invalid_region( allow_model_requests: None, openai_api_key: str ): m = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent( m, instructions='You are a helpful assistant.', builtin_tools=[WebSearchTool(user_location={'city': 'Salvador', 'region': 'BRLO'})], ) result = await agent.run('What is the weather?') assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is the weather?', timestamp=IsDatetime(), ) ], instructions='You are a helpful assistant.', ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_0b4f29854724a3120068c4ab0be6a08191b495f9009b885649', signature='gAAAAABoxKsml4Y3hqqolEa8BSvPr6mIoOyAbWRJz9FeLHoqX03v4b6Kni2j9HxfifAm2cHD_m9-b2nOHcwDPOeJA28LQpl_BfOakn7h4saDElA_yz3WgVfy8ZN_oTLQz2ONqptBxdxCaLMGOADqBJ1tJ93B5s8bsFNZUdGXe382lPpCNX0aKPGxd0e-UBAICRmjGVnKd9cVzB8jhtQWBrITvMOLBvi6bE_TqnpXWf8-rhed78mFVMRweh6zAzukkJPMAjD7QfUAiODvD6oynwU6G04UOJoFTItUsAULPfyAw-YZqRwfcfMxoiLAE0rOOj9V7-eyp_J7DYu2uF16jaOopnrehFDJr-0pIGMFRxMSyFp7Ze7z3gWvcCOB4VwpSFao12nozedMeinybf71wo0750TNXXQ9Uye6qsUxxMamqcNiB02LjCM3nyBQ6FpWa59TD5O5UytT5FPOWSflYEhuiTFknt_JRHbKoeqVTfe_CTeSVlYBtiW8ouhkTHAAVI5lXi_mgvUMHINTYw5MEilzBSPunuMRquopRjt_07YMKuwPDQ8o__s1NlyrDAYKLA0gPzse4tWMkKREcfxuvU948pEJwVN9RuKS-NNXI2KiKKOAtPoXLbflAEtpx9N9PpPdwvz_z3yhF6S1_D_9P8OrSdxd8ldqvnqec75Jwt-a0fuQvRTSC3GsYuhk1Cb1aBvZdBtfcwBd2CXRuDUEdtzbLZ5AUNBy3f0mC3ITHG9aSpuD4GUHQDTjF_10-Qr4Rzygnj4-qubY5ibVxGtHlXkI0QzvGMVf7obhHMNxEQNaJ4k2dKddRJEhrSFWmAVYdWbKiZp-Dwx8veUSlpwMu8kLfGUq64MBQOApf-Srtry0eJAr3cTBqzmUIU5OOPg2C8j9SbAuTLbbcR6XeWizp5fbxdcVipVRqqp_PJptIJhaAUpHaaOB9u1nZbtlKWFJhJbrZzdktth5DNim4ayYBbBX1VAefwCugReld4C6QtB5Q-j_Tt3dug3Jh9TJmkhS8pJE4aHURzbCikFohJHAukZYgMY7wCuLWlahQ8snlIj8kbhPP-l-iH-e0xM2vFDF8rZnfYblnDLZYQBezfiZ4GtvO64SB5apQuRXkxExfZyBd6Kv-WhAxhPGoQdmTXfVEXePJLvbzAJcAXYpmmzt1STxoxR9cnaeLL13fFXZ4DGXe4j68-R7xCC52jfoV-l8JZjI0NDRJ3Mx1R26bp-lnvoertQBs1c18QHVShluHtH5c6V3j4yOMgG6cA2aVM25i6sjhUV3iltijuRv3E19ZlzgVTtrypeCVH7ab0PQ3Qki28mFI9s5M1z1TSuFis1qhHwf3r0kkmjLXIUbXAnfJkcv50tlcweXRTLKs0ZX0nxsxiZptBo95wxqBf4VaqfOY4NUNAWVoZ4AS5oSIgjGfUZtfrLisWmX8NjDWiOiENLmn9fCCq9nxDDsaucnwNhsMZo9jJqJS_99kryMXi0yGX4GManClCTe31Fj5zOrtRIezlEILiTla6fZwvD6vcl8GWO2wuyEY9zsEvfjyuvcU6Ernvw9S5HFPnQ-FnDxNtSTe1A8IHTspfEROnuSNVCMs6j02eFZMbXFKMaVi6LNDD2i7SYn3dMbN7aOfubtjeilMpIZ20U-J3uBUsc0rr8s4b-szDB1lkmiMvRDVY8YKNqH3iJFCToE3OibVwHeaUnMmEHJkIvJvBOX4hSwmAMxjZArusTnlYnLE2raAD707H_Q5JhpWXwtgFPj5ra6HFtOjtbPtDWrDn5_M180klxvF-JxfSxSl6U6y2FYeou36ttPRprWJynfcPSPY_sdrB9ZupHDR5zZy01Uby1J7XXOZt5an91kuHr0qU4bQJsq6AigFQ72C_YxpDNmQXcy5awJDBlXv9SoLiXRcTxpoXgii9alV8MeorRbc23O0fP_O6XKUso-lp-e7Q6bOqzV0c9K3imYUDzM9cqlvEyUGMDLlWzEvVGSwpag1CsLCNQ5bPc31W8hc-2WXrlltP6JZ9gYpcueL5AIud6RUTSJWg4Li6Th4ZGNs5cqh6Nk6oSu07P4Ie2JJ5bt1tAJbE4EupK3NVzUpzYzFdPrQkBY-VQ-klCFq4icnvlpD3pajYv9OoCpo0z8GfsdLeJlefIQ1NejuMg3EwbGRA_OEWn7sJzR2RFCYkt3YIuWRJb2UzIzvWhZsLxr4UpihrsieNKggGBh7nDpOXeAZhS8pGrNSlKjfvWtvmWG9NKXSpx79dNLSkumiD3FsQjk-L1Ov-K5WksY0yJTgc3ipgO2UpN9zolpXhXum9Uy8UeKLlB35cCtte15t_HSogTh2HDkc9SuCq4d3adSdstdXodr9jLbST50cHYn-F9qmkKiqV2nBzxW-9A4BB9WB_tWEoazKWYHtIdmjRm6O9NxvOxYuWIwhMmRf-OE6MHOeH0emhuTFaeuZ4zjbM0T9peRh9shiUw6T1NT0doCgfyRAq1NL1rG7iSc4jxrc5ahP0gN', provider_name='openai', ), BuiltinToolCallPart( tool_name='web_search', args={'query': 'weather: Brazil, Bahia, Salvador', 'type': 'search'}, tool_call_id='ws_0b4f29854724a3120068c4ab0f070c8191b903ff534320cb64', provider_name='openai', ), BuiltinToolReturnPart( tool_name='web_search', content={'status': 'completed'}, tool_call_id='ws_0b4f29854724a3120068c4ab0f070c8191b903ff534320cb64', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_0b4f29854724a3120068c4ab1022f88191b2e3e726df9f635e', signature='gAAAAABoxKsmZCctfduUbipds6REy8FkoOiADLcLER75WMHyO7PtQt26NIhcGkiXReZWucbDdEBRKk7_g9PUuu9g-zEBe6kIQwm4lwjxCGPy-rQdmfJpueznyPJ14Ood-wazqT9a8ab_BMFS7VLonsOjZR_b1gxcx5yO62oLvv1GnZfkEykIgRbGIBSYDWX6I55Sfwkf0JRaiOFgeHoOvQ6f2mdb5UetdJwbIFgRh9Bk-_l6goC-ONyElqvPxrh8zlLxqEhL-KtTVw6TPNW67QeYxekA4vdXseYT4W2oJMcMKp8aIfxYr3-ZWSy81UqGPD2PAfs1DoOYkWMHxt_VnZjLQs0qkO-JBPsWBFWEofZC1GxOIT6gd_dDvExBXkaFdNH7xf0OxsxSMWfyKSXMlq3kmVsDIN3hKImwfZQ171mkFEwgwIBeo4XiY58YJXmzyNXSs3c82gAeGpS8cOQw5shjC449uJZkixSaXmwOKwtm0z1MOVAp17QLGeD_2YVa-DZUy1z6xTqStuZWnwLDOz8HPL_rW3MXGcmC63kWmcTCsFngwR_IArcTd8lsRAXJghnEdOZDYgrU7uc7bbqO8W_PyzPDDnrAbcwo0InMqJ2BZErMXOmy2dEm1jlJPEn23PL26k8r_sKNCZpg-I-q8epjbF225NJ9S8g_vvqLsyCzo-WnHPHaFDMfUhRxU-ylSReCZO3pcjNJXAfmsNiBs3g272BtvNWn7GpDqlJL9aB9Erc79CpLghKKV9JiVRsr79aW-JSzn9gJET3JteU2MMCvRxv3ePPkmZUvQdKOmzZQMwQ8j0FQHd--4qMkXDdAz-lsUjitCKK0z2ES0oSnWOVVPoR5AVIUCSfg-yGwBWhKv6qIkMTsCYaCaR86j_hGlCSxNqYdbMwy7sr6nwqDmqgmcsiNkAVUAUeU7LLXmVfGDR9InNL3lNCICpmcHMd8YJO5A1wFMPHFgfXt3o4CZP1ZSjQjQuQ-Oh2AfLaAYSNbU4y8JDtKPiini_rWIqH1yykwV0Xt__QvQtj600ksUqij_zxbKnZKy_u3Ud5E04bNgTZ0Mq9ihVtPBlcDCtWSsp5U8Sm6JL0ZXV5XaT3CVG3T7Mj-kKs4yHHOLNoR2rKAGPTA6VRzaJDNO4goMeE7aIqWKhFTYMBcKJEGD-B2J2J36iZ2RNGo9JbxmUw4ZPMVaPPulSfpLvDptYEN3LX0D6L4Xu5iaW900EQ_Ym60siMB257NRxfVPb5Sg8hqxGeKKgg6NGa6y-qyVXvqjy4HA-ODvHLbiT2n75fTD_OE2CX1FpLgmpmKkSopjT5G1vv5qtXqdhigDy-l_b9Qxwvbd7XXD72EUVPzDVwMDBZNeJkylcCecaRVJZRnhmOMkGbV4WFrMxjy7eoYrIBQ6zytutBFXNkAb6a6UXdTrlOlzclPP4P81sp3J6BytVSaLJXCIpZ3pAM9aWVzfavRW22R-rIMbmCWT9hq-1ZDfjdglHN7yowAF_rjVGrgl02wsh8IlLKfJreh7ughi9vSk1WMinlsiZfZynp33IfB3ayv00a_huU4oSKXstf1KaeQ1Z8L-ReCdPRwDYaLbP1ZT7BQAbXKgIjUsLdSiU3MmW8FVBdevLQq8AUUKsXxfQLS4TsjMYTNZ_8LkMcVeuwTDQTBYkBdyTl7jawXy2jujxDJe5mK3ZvvS_70sWokuPXkCApVFkJpNRDdcvBuoLG3g_KZ7dA0oQW9QHkKpd_-FEuUZFnL6-ZhjR7pe-EmR6gqJbuQVs19N2qho2pnNEe21WqAN-anBb4H7QN2V1ODJkW6vDDRH5sV8Ya7YYUScSI3TUASWH3MWapL1_-lRiXtVIM9Q8leFFIO_qkr8DFXoDOHp29HNa3gpQkjOqAFqX0VLg1Ub6X6C-kUbXWMcYIUoKNvQx5-Yhy5Lo0N6izxdE4Zw6U6Lfu90rA2DWeQ5-iae79H9yUy74jZw3bclkJFzGkydXWIP4OkKnDPemIKmsh28ovmfgtz_gJ99SlQDBmI6paH6P8wmHd7QvDQkMBnuACOnTnTud_MqdNUR4-qtcnPoNkFPXoTfYJNDDBkxvaEIXylqKK0wPf9aBsICsvB0N96nPpQTYuV2YHfIr8PagOi8wWC9ceUmDib8fMq3xgClujOcXOPk2Hh4Xuslecn315m-SoLjRg-dIdmTjuIyT9CrSdXMto5Jp7vcPTsRPebw41Tf4iR78BOTuGhbe_B7_WDm5FH10EptF1e3GZ0eO--VdgqLY3T3ivuoxtXIkTvDHvLHqNwFJIvH4ULUAIx3UGqJwE84_OqGwKBRT4UuQRm5wwZUZ0teyzOQx0cp7aKhsOkBzKY8jVFMmTBKin52ioD1inMiyBUYICYwYUngdYRmE5Qx7qzqB6Mg5CSW_7TaXuZFNVuVnitQp5uw2RrOlookLqyKYIQhruNjaUAvvDnhhIrTjh_Bi7f-wv7znhbJDE7YWy_zC_ufQj9VfxJcz6eXKu3fXr4EKlLayk2nwO5BkwaijetPdBNs4SOroEo6WfvFgVtbt-c6kkEfY5abo5zK6OPVHrpBVyew-A53SA0bQNptBVMNkZDiPczaviF3H3fnkMQH59RhIhMV9knjfCbAhP5BTmBFyFIXjX_ErOJgb3RtUObwjnifMNwN2hIE_-eMqk8K-jxMrT7xNoojwqcCgmzcY5w8hbmA77xW4ZnlBuTZORjFhppokfhLPcoVCcbt1AEWLc3oFYhquugqG9WZbS_7p_pI8C_zB4Q4x8MTn7lO9RZFufBeI9iTm6JP95asBuEafpQxP91ZAhfiU93UybWsoaKQb78PvjqwwK2D-LRumK6ftSMU3LNn1MBmiFowwzOLPxrkN4dzqF89rXEXJCuqS3jl9fEwKOdCvhpXyVRN6Kx5VBxSrY8KO9ItwWkrjHF4cWCTRVNePbw92TzRnzgLB4aEZ9T5TkIvdNgOyCQYSaOZ1TMSgO3a-i03avh9KisZcyt-gUbD11-EJmt_KOSeK5o-Jn3GmUKnZJJX9hKCOWCmN00qv8DzYCfIO9Bd6kfOXAqJJ0RFDHn6a4VHv4NrZNyXQWrX12_V3H4oHVZhDurhlhhak-6xoSC6KWeHFFlU39xzKx-2BfggTfghpTj4x8WiObhHvg7I6OY67vzfyRtJoA4muFzqq0c-RJ1QMvOXLGDEMJMSmuXxT0GOux0GvkB6VB4snKw5ZWdzTdm-maT6LBL9POZ8f2psW9CtE9tuzs1EfrBS9SHn9s_B6NHRCahEwwaIRFePU0v9mT3hhQoq_CawOykzNVGAPPAKyA8PNZr5GGmdmV7v0fWppgHUZA_sQPbq0XuxgoQFLJttwnCEf_mkS1zPYMYBv16U9G-kZQ25-rdHBFyZG-Wa6nBCSk7lm6ZNkDKSN7L-lBAVgpPgzDvXlCHaklZmQXwtNnBSPOZ3yO2-MBcDmSyoDbXpdM0zYZhMCyv0vMf2mKhEP91a2xD4tsp-Og6gAo0AXgk6Ge_be4zhMaUxm_NdPGg65mkaSaOZqCuevYVh0En18B7x2erzzUAMuJoo5C8ab1yLVGZSKNda3z8j40JeqcaYLN-yS4RaGaNdva_pmCq0dXYadIjaoivy4TqnHig9uJtboQqBevHPq2xXdsSutQOyEEexxjYbEz1USu25bTvog4tJs5okxNWDnL_0vBXZTpYCGdVo2WcMJgwqNBp-CPoZjMxCQ9IM6iS3KKETc9U46ksBbN95ZSeRUoUUtO_i0AoBsxE9A4NFbK9Uox2RGcJxOlC9HM2n5D6LmOyIO5KaYl16sfmURTRlcNpgTYAvat5HbfDYMFrH9EgSxu0y735-2wvZSuD0credILM3XFTyBmM7-278If-6-QaDX7zV9JxJaXrXx92T-srNH2Z5DLBOJDkl7oo1lVGKcFAmEgHjnkT_rPt8DvU4tlh0eI8HzSe7B35oA02GJE17hiWk-_VOUG2zNaOaesGK437EOzcCcc1dMZAtN206qPtzDZsNPhQNEBUx9Ta_jPG6waGpwihNxVfhwVvrR0zFUy1IspR9B1ONXttsi7nQ0YAtDSJaBuUgwwtYk2KL4QqRAixv_KSma8mOfuxs0th-sTyFGQ5f77q71ZcLUeYqVqrsjcDsh0K9pDvj4-KXcQXgd6EzY8zfh7VvXOHIr2aHBcHk1tw9zjYAR19sP87lo7YdVNrYlB09IkCICT9N1RSWJHUsszCvP0oBSmdNPfelx1CvHlClrc2qNGcyalsF8hc4wnG3mrYIC0rb4sHLc6Xp47g7vWnXH1ud169K4dB5YwnLam08lPwSYJwqculJw5d_L2egSoNIdYGvlvH-4prN6EkkyiqmZCHXYSNoKorU-ce7cRpc6mbxxU6CLCS_1FhlgfG_mZFP-KAZ3b-lQVdimYcudQeCgtjaydeAcUP4raEP_Wa3bhMB-GK90eskPs0cZgeRDvwohATR8ynHvxFCAeoiQcL-3bQgdOhZxY6r8dn6HF3RWWaeA6o4xS0XTlxecl4rOXs4nJAvn3jGZ4VmU9qkYcoVBW44IkLnbx0q07n4rRiurI4596rknVRJwbeb--_d9l9gSqn_ZwIHHyO4tk9np7I8yMTGp0j3ea_GbKrss2_8gU-XDU57ihgCQyOrAcyyfljyHTE6m-upNK0glJ-2m9r0ktOToCN-6ve4H3trSNvRL26rmH_WV8d-gwsF76cPYdlCZu46pC3Ib_R4sHUeBjg39ilY0IxUTOsLz-34NuMeKKnaViX68pZw1XzMLb7ZJOYhe0AKKO4Yrrkwpwlqvbpgd369PENtcqdakdbn44wKOfp49d9czQYQcYlRK3L08MhGsHXuDTlUcqqEYSDpwM_D2__AicfRazviJzdWQQMNJHA_0COIuhQ4c0dbPOOZqCMM9BxQe69fNlTfZEpFL2Axh_6-TqEXdqU8CO2fYScvQfuXZ2AMbmit46qlhUJMj5082R_XYNwIR_b-QMqm0e6aI_vZRVw8MwdJHG73Z_u4whBIR36VHrrK1qUYLxC2pYyLOwHlPEYlyN7HlTs6i_iJ9z4TQuK_mk_b1bc4-1XfgQUU8ZfjYPNoQNII_Dtym-9k7Ukv-pU5Nk1lItlLk07wiCcKMlui8Y-23K9mb03O38x9ZhN051SusVM9ItehAp684sy-kb6MymRW0LsXXIPdRc9LxI85RZ3aANfAtMaHbRov2jpVvZT4OQhTQIJLg3656y_NG32DJvFQoBLEgfFCTKYQgpKWmbxj1gRsVDrdk8EBF3rz1ohyUfxqyrHSYM39YGs2bnk9TkvaOaHOluV_ZoY-qIDysJ_p1eKxJVdpF2VCxZ1ctwuKCbVx6pl6XLuN-g2KaJnpgxVcVbrnxsgLrh5OGeDuXiBFYeLYaF09wFBHTHF0naw63TgB8jy61c5r7_y4DVAiicoSJ3B8SJxEmB5qgXVse_vwmKOxvULXcgU9XLaONbYYIUulkSNOSK_x_xWnVRL7yWHj9xMjWTvBXgVcux1CmehPPQ7dGhooXgzCoipDZ_y_sRl43wYZiaqG7Nl79ciyfdwi6xKUb0CgLQp1D2Q90bHKRUV1Y1IdcIUl-atTUcMGYDyLKmYQQ0BWvqXeaZtHra_yDzoIlB7rR9Hg9agchVJsUA46egTwwvlHdiYPIxJidKAQFgpDospYReegQxCIZHg_PI0FPVfXBfNR2Vc8fIrXiNwzPi4jvj83YmDTvTJ1xBLYDao7QzDQUjkpl09EnP4UoGlvFYlrXH0Ev1sWz_svhFVAduqJzHke7BW5b7gYipmIqQCvPgehCMuD8-NkaEAtE613V6BLPTu51IPtkvFoS_zSRCkLnspDFVTeDToBKQlN0-u1LlMF9f1dQDPxBE8ZLacKFP2F6lezHhikzuoJTyfCzF0xT4nn8alqzDzRV3K0wAl_4NKjhwSHz9i8MRxPo1WEfO8Xpt1aKa6WIbZ2rr5ayhX3H4ASPQ7UDoMNrRZP82lcAerRb_j7wyL57W6oE7VetxnmbexD15h_7LukUqUNSSgg6D0zxX2C23EhpBaQ7Bw4Va_costesVZBuYwEig3VR5Y-9WvmN0CuaeE1oZkXJ5zBCBgO5F_hIESxHP9zx9Z4fs7fswQDJHaick1xpSSZNDbBghUqlswGvI4TTtUWGPc5R1mf9dLQDF6j5wTo1kycMpfXIUF6hVqZRlKHgP4DRetOCsAgb_WMW0b_GCVyK8JyeZsTSXN547g8Q6WMRYikbZDP25hglrI5hU03GLf3m2WLJAd4eKB5e1nlDhIqAGn289gdttwfe8rUzB5BhdSZ6BcaWAEVp64EHYFmtco1aBleXa0RVlSDS6gt7U7ozAp0YxkBW7YlqXxfM8A8y-Dn8LkKewv5p7q7yL5Bkun5Cy7rZ_FPQ_4ktHUr_RzqpQbgSgtXwOSyCfoDKqIPNg4AhjaI33nD93HuRQeV_mhxYwXN5GNTq-7SxkulMwTSgg7b2UhmOSu87pX_FMk5nFaglzYzHKpoZA3QuNxwHzTVInF8Ufu6fAIOPT5fEuhfilDU3uxCkpC-us4yeLwm8e36ICJZFfcqa5dXHkFezEXPKvFbhpVgjTO-TI2EH_vb4QcYNQxtQGWUqFcuQ7IaIgYChVS7ifjkPc65wR9ffjTEEqFAt6e-_mviI4ltyiTLTNTWY68JV64SnjeMQ9qR9gPYmefUp_E_LyOdwfetRYKBJ81jAMz2piWNoJHwHbFjBxeZj8iZ34TnirgvWRltUi20aN09b8TN_IbFNPFjkI1UwshqMwLY9GXT4eq0QaIdvhW9CE90--KNVjGvqyRLodo0gsGTpmTcoTPDgF_AuaeDlaBrbAnW-pFr1HOV5YqUGja5_vkDvi9mdKooFrlSau-Dt1HmZf81izJ8odFR-tHl0u-wT66G0aEkk1DS81IXvSLLNAQlIpj5FoZYx2RPFWyw1WBlY8iSa4r6HyN5YKW9taJ7ljUliA8KClax8VM282lqYL5Fd-wtYu5Iceez8jGGj4cZ7JetWp6X-wjLHeo6SDUGjNO7k7h3ODmCRnIKJZVtbx6qJEVX1u8J9mIAXEjdArqa_7YiUBTuka0W7IxVXZUx9R96h5f', provider_name='openai', ), TextPart( content=IsStr(), id='msg_0b4f29854724a3120068c4ab22122081918f25e06f1368274e', ), ], usage=RequestUsage( input_tokens=9939, cache_read_tokens=8320, output_tokens=1610, details={'reasoning_tokens': 1344} ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_0b4f29854724a3120068c4ab0b660081919707b95b47552782', finish_reason='stop', ), ] ) async def test_openai_responses_model_web_search_tool_stream(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent( m, instructions='You are a helpful assistant.', builtin_tools=[WebSearchTool()], model_settings=OpenAIResponsesModelSettings(openai_include_web_search_sources=True), ) event_parts: list[Any] = [] async with agent.iter(user_prompt='What is the weather in San Francisco today?') as agent_run: async for node in agent_run: if Agent.is_model_request_node(node) or Agent.is_call_tools_node(node): async with node.stream(agent_run.ctx) as request_stream: async for event in request_stream: event_parts.append(event) assert agent_run.result is not None messages = agent_run.result.all_messages() assert messages == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is the weather in San Francisco today?', timestamp=IsDatetime(), ) ], instructions='You are a helpful assistant.', ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_00a60507bf41223d0068c9d2fc927081a088e0b920cdfe3866', signature='gAAAAABoydMADQ6HaJB8mYQXlwd-4MrCfzmKqMHXUnSAXWV3huK1UrU1h3Do3pbK4bcD4BAvNiHTH-Pn27MGZDP_53IhKj_vB0egVf6Z_Y2uFPtzmyasYtTzrTkGSfAMR0xfI4wJk99aatk3UyLPNE7EO_vWYzN6CSX5ifJNNcmY3ArW1A7XnmsnMSBys05PsWqLMHZOUFuBvM2W37QUW6QOfBXZy0TamoO5UknNUfZb_TwvSnMEDpa-lXyDn4VuzfxreEGVHGdSyz5oLN0nBr3KwHIfxMRZIf9gi9-hKCnxX7i-ZktNIfTgd_WEmNKlaPO-qjKHPlO_XPKbEfpBdMv5b2P9BIC20ZG3m6qnEc4OqafWZa1iC2szi4eKOEa6neh2ltVLsLS3MlurF4sO-EHQT4O9t-zJ-738mZsOgjsI9rTrLm_aTAJrntSSWRLcP6PI6_ILHyeAl_aN4svtnwQJZhv4_Qf62q70SZQ5fSfqoqfO1YHLcXq6Op99iH3CfAhOjH-NcgThFLpT4-VLYABl8wiWBTsWzdndZoPmvMLEOaEGJOcM6_922FC0Q-fUio3psm_pLcElaG-XIkyn4oNuk6OJQonFE-Bm6WS_1I9sMF0ncSD4gH1Ey-5y2Ayxi3Kb3XWjFvs1RKW17KFXj8sthF3vY5WHUeRKA14WtN-cHsi4lXBFYJmn2FiD3CmV-_4ErzXH8sIMJrDDsqfCoiSbHwih25INTTIj7KAPL2QtIpU6A8zbzQIK-GOKqb0n4wGeOIyf7J4C2-5jhmlF2a6HUApFXZsRcD8e3X1WqSjdTdnRu_0GzDuHhPghRQJ3DHfGwDvoZy6UK55zb2MaxpNyMHT149sMwUWkCVg0BruxnOUfziuURWhT-VJWzv5mr3Z765TFB1PfHJhznKPFiZN0MTStVtqKQlOe8nkwLevCgZY4oT1Mysg7YJhcWtkquKILXe-y6luJBHzUy_aFAgFliUbcrOhkoBk5olAbSz8Y4sSz5vWugYA1kwlIofnRm4sPcvoIXgUD_SGGI3QNsQyRWQEhf7G5mNRrxmLhZZLXAcBAzkw10nEjRfew2Fri7bdvyzJ1OS_af9fHmeqCZG5ievKIX6keUkIYQo_qm4FQFkXZSl9lMHsUSF-di4F6ws31vM0zVLMmH52u12Z3SZhvAFzIV5Vtyt_IfrMV3ANMqVF4SmS4k2qUlv1KuPQVgqGCVHvfeE1oSyYgYF6oFX8ThXNB79wxvi4Oo8fWEZLzZMFH9QEr2c7sOWHYWk-wUMP1auXTQNExEVz22pBxueZGZhRyLdpcA12v8o6vJkVuBj-2eR8GRI7P6InJdQAO9TIBhM7NtJU2NUpeP_84js3RTBVktqBT74nWPaHIddGMSfW2aGmFJovvshhxGMLtN_6XMh4wRKW0IE_-Rfbhk8_-xHKI5McYI048N_TMYOS8KqPPAmGVklRGqPZ5xXMNvQEVweThDTYTo3NoAsS0fN2yMmSwrjRYBHsgYMtil4pd6ddp8dvF_XSJUkW0nF8t6ciI_k47sug3gyw4usqspWxY9Hwbzb4OFzzrgtO_7Ll6lFFFUx2oHy8AO9sJ97Y3Fg6luuew7ZRDzA_4XMrT7mNW6YuT-o2DunaZw-jvQezNHjPN2WhaTS7fkisyhFSFTMBYE-H4psfj_sizutv-LjwbumTcX2mnYE9SZhVr8dL0c7sgwHP1831RxTSSl3ql_obE3ICDooyuM8PYE56Jx0HOOGbEeJd3w91SzNHPG_3SQfXszrZlw4BGWrEUHBbtVY2ZEnsyGNAx6vKO8lz9D-6yZ618foDJSH-Ilk56a5rhr0beWjSd9mYMsr3zpVz6HcpTLYGEgHfPxpT2eaYaC1H_znw7y1eMKamwudYmtz_azX5LrOtwc0p-pXH-kdoNe248pSz9qsmHcXA41fuj2weKQNrmBcghwtfM95B060tnmebJ_B_KkLXL4cNF-hZqi0wAHrHYrZ_WM0Dy90AFH-b7iiWuWz5M1EhZXo179iEdybM-1PgccFJ0zvOqODl7FNxSgWVyNS1k9R42aZx2PzFAfAbBtJ-KVMhUayAvGLNmi35EAT0G6FK65VBEe7A6zPFqzrrAiG8dy3Z0I0253WzIblHPNMpmxI_ca5tIx3u8Za6Nu9rx8mi0CY2jsRSKnqb7RZvLuB78Uj32lb_9jbq5_gL9_y7Bt7U7i7FospyqMFzEYQLvdyrtfNrfY0rB4zr4Mo0tDn_4YOD_d_nP5axUh9_ruqXZ_d3eVdNmlITjQZj8ALe1EfidP8a-Dl62t6STVv8d2y8v9-jy3J7wReLJbJ6gDDnygJllY7NrIVXSjR45FXiCDnpaRonu--I_0b_LRJFOoJUJX0S9YMaXAkKyHSEj-UWjiuk8cIBNcXxwlxnqqNMezvvV113MAOEbfHygDnphzjzZQxteAVbSy0ucGDR2FPi30d6z51NxGnXNS_sM7wnjBMNp4Li0hhttOp6PgvDKPSMAcgUtKLFKE8iWQAvERoUVxw5Et20hNTNXf_0sXOyh0bF0URPGDxSYz9uZI6-nlwVlo1aobdEnn7STSq2_tuTDIrQyfBGZzhv8OB0H3cj9mBs=', provider_name='openai', ), BuiltinToolCallPart( tool_name='web_search', args={'query': 'weather: San Francisco, CA', 'type': 'search'}, tool_call_id='ws_00a60507bf41223d0068c9d30021d081a0962d80d50c12e317', provider_name='openai', ), BuiltinToolReturnPart( tool_name='web_search', content={ 'sources': [{'type': 'api', 'url': None, 'name': 'oai-weather'}], 'status': 'completed', }, tool_call_id='ws_00a60507bf41223d0068c9d30021d081a0962d80d50c12e317', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_00a60507bf41223d0068c9d300b23481a0b77a03d911213220', signature='gAAAAABoydMLww_4DcIPiCy5zW1t-Dtx57JodsdP9YkyDCvY9r0nBfoD-bwcBl8FfcFxRuq5nK5ndf90J6Xdxmvl9kGVbCUYSFaOd-kWeE4tgwXM8BwwE3jVs6ZMG3BdiWyXS3alnUO5jcE6kuXeun1LufAdZ6rWtJl3zSmqPycnTh9zoQ4cBBxLDq_qcVS1fgU4WjsWgjCZw6ZWRPWwZk8hywmU7ykCLH7SXItM4oH1m_GCEounJAS8YR4ajUh5KAdN6a1wngfGnXhYdzov98yiNLP6Nrkgr--K4vMTTqWXLTcR6fbWgkijanIeKmfSErCjMT6k5TrAbkFx0rgblHbdQii7zj8seV1BWZse92_k4sltxfc5Ocpyho1YSHhgxyGL7g442xMUEibjPCv6kwPMcW9yGu9wPMWsfPYCXpBbG6kQibQPNFJ_bEubwBRaqdSDq93Aqr1YkTYBja7Tewn8UfzZ8YYaGe5y_K4ZD47lfvDp019dOdXmOuZGC1ECRrMqKzSFYVG1CFY1VhjGdPmzobDoMcpZcLn25s1pg6lnNqNQwOk_IA4MvUcCU5HHD5YjmFkEy5-i_iRoDVu5coK0zyEMvPJ_h10y_ByszcfzS9e0ht5CSilckkFdxTBkZ5epp0YIg1e-PrZ790P-I35Ucquam9OXyULV1Y5bn9ohZa93Tv0JZRxUeTDG72_28xRj8tkJaBAZjoCC7VICw39KVmz-ZkuVN6IIX1WdNzyC4d808-2Tz4UZaU42-wxEWDnSDMD7iZu1Bi9fKKwAYBJt_OcEsJwpW63ZaUSG2PVFfm7a3wRcSMxMTUTTJB7L1Keu1hmNepif5tavn3P35nSq28D_IJyAqAgX7ZyROk2bJqjzSE4A0MddqAoBFFqKBi68n49KH09vDtDXIoh8jVWuIgowgVGr8pN3kuhLI9cir4Pr_WES0tPD7yWHPTzrD7OIJCfQbr_4Y4dEza4ixNi0RTADWzMUZBfr7bvwIsgvg6ZNuQlx_d71Go5VDsT2KI8H8AldiRvNWoLyYTFGyK9Kot97YsS5sEmSYgNAH48NU7pgnM0jNDQU1G39nTNFEjL_ziDwjDT5g3jm4S_gbQfwx-XFT3Pv-JYR-E71AqR--Lg71OsASq49rrlULfl5OENfiT-NB6x8MqnfUI6NpcCsOWLp8XfRbgqmZFutLIi43pcnxEe3cXHLWGF77qJXP6dFb-G5Ide7n9tAOoEgfsVu7hCDPEQ_xrIYRdc2DzDPUMCtXBai24E0AnQF8kxsEtlDW_YmAgGNTl9Gx0tFSGdDuUCsNx__c7v-_LOMWycXUKmH3iEr_su83oGIMapNp2PnLccN4iOxspdZQq0C6WBaR6SrdnGzK-0KwRPRoyKDLNWS8zfluR5bIgKlqd3Sbv_7eL-WO4LQXMvdKP3KS-DBt1HbA-gmyFW03iX2smPQbtVmRLWi1vG329R_07-tHMJSO9OQy6_6aiyO8Rgpbl_CHa1Q9BEkI2csonayDJRPvEXBPuk9-NPUP4VLNPB7npWBLlAqes5ZmhagnC7srTL0fFiLGLJiAxWo1f0BBiIlXjwqHdlgBjTw0KryCnEU8Ic8ATzrqEXXhs-FTBCcWInf3Bt5bzUhy20g7cTtYP-VCbsku-lXQ6wceWrfQVFtjKKICD8I4g9QusAIAvgCUm7J2rR3TLkzwOKngdTFPGQrQ1TYzlkA7q_Ew1uZpaPRckMaEioZYC6Sv_B0rgW0nyBJ0GLrB3AUN60hDrOFntyFHp0FM-Zh1SY-GKGBwZwVetOzM0ZAJ-NreFg1XVgyLTYDNjUrYJjRhr_JARsZ5t0pU4_yI6dPqM5jKO5_k4UpZspfQon6d2-NlWX0EDmz6G4CMTx0TScehYHrQZtPzpVnivc8h_pmXV3jO5GLzNeLWoB70SDPTETo1Of4txiEUaC2komu5B7MN9aR4c7VBOTv1NIjoiZcrd1HFACzZ7r1qAE-G38j1f1YhfZ0_TiMmtfR1cqjAKcFkyRM7rZMyMvvnsH7NFq59gFgWZt0dy0aAdw03XWXFNT67lrw58OYC3NcVozH4SKlmleu7TfjHNWSnJVjJ66riLn9DZWVxPeTk4zuISZn0yyaoXcdW8OMn_mJ9vP-8L1wElMyxKbtBRz-0cW7MshmJ3YXmHWDKbnqETSbDMtqcN_QyRJovopwlptJ8VzL7biuURRFw-l63Kc9vKP72Z-QWOUIPLB4q4nX4yb-IV0mkWFxIUlfv5Cze2anf7zDFyGzeU9xG0onfhJE4HFKcoUT8MzfrHZ0dDZtnEYeL5Xem3GuHpwEVGCxRE_J1joTmJfeWxSVnr2Vey9gaPmXCyRrdKS75v9xSXJFfHvcOO8Qp35Dzk-yFqL3dSOJfOEwDZbEf6QnV7VU1EhJvW4XmRS-wsRLMLCYcLrOx96NHEwb2h2l6gNfbCVJoQrMhMg68qBPnoSYLhML2ho7hWkSNZFy61yX5I-oEJV5XdtjFcBkyurmUD6uYTkJSqXyxLexQiPbT-uv49Yp9cAfFBG23sC9lUQ=', provider_name='openai', ), TextPart( content='San Francisco weather today (Tuesday, September 16, 2025): Mostly sunny and pleasant. Current conditions around 71°F; expected high near 73°F and low around 58°F. A light jacket is useful for the cooler evening. ', id='msg_00a60507bf41223d0068c9d30b055481a0b0ee28a021919c94', ), ], usage=RequestUsage( input_tokens=9463, cache_read_tokens=8320, output_tokens=582, details={'reasoning_tokens': 512}, ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_00a60507bf41223d0068c9d2fbf93481a0ba2a7796ae2cab4c', finish_reason='stop', ), ] ) assert event_parts == snapshot( [ PartStartEvent( index=0, part=ThinkingPart( content='', id='rs_00a60507bf41223d0068c9d2fc927081a088e0b920cdfe3866', signature='gAAAAABoydMADQ6HaJB8mYQXlwd-4MrCfzmKqMHXUnSAXWV3huK1UrU1h3Do3pbK4bcD4BAvNiHTH-Pn27MGZDP_53IhKj_vB0egVf6Z_Y2uFPtzmyasYtTzrTkGSfAMR0xfI4wJk99aatk3UyLPNE7EO_vWYzN6CSX5ifJNNcmY3ArW1A7XnmsnMSBys05PsWqLMHZOUFuBvM2W37QUW6QOfBXZy0TamoO5UknNUfZb_TwvSnMEDpa-lXyDn4VuzfxreEGVHGdSyz5oLN0nBr3KwHIfxMRZIf9gi9-hKCnxX7i-ZktNIfTgd_WEmNKlaPO-qjKHPlO_XPKbEfpBdMv5b2P9BIC20ZG3m6qnEc4OqafWZa1iC2szi4eKOEa6neh2ltVLsLS3MlurF4sO-EHQT4O9t-zJ-738mZsOgjsI9rTrLm_aTAJrntSSWRLcP6PI6_ILHyeAl_aN4svtnwQJZhv4_Qf62q70SZQ5fSfqoqfO1YHLcXq6Op99iH3CfAhOjH-NcgThFLpT4-VLYABl8wiWBTsWzdndZoPmvMLEOaEGJOcM6_922FC0Q-fUio3psm_pLcElaG-XIkyn4oNuk6OJQonFE-Bm6WS_1I9sMF0ncSD4gH1Ey-5y2Ayxi3Kb3XWjFvs1RKW17KFXj8sthF3vY5WHUeRKA14WtN-cHsi4lXBFYJmn2FiD3CmV-_4ErzXH8sIMJrDDsqfCoiSbHwih25INTTIj7KAPL2QtIpU6A8zbzQIK-GOKqb0n4wGeOIyf7J4C2-5jhmlF2a6HUApFXZsRcD8e3X1WqSjdTdnRu_0GzDuHhPghRQJ3DHfGwDvoZy6UK55zb2MaxpNyMHT149sMwUWkCVg0BruxnOUfziuURWhT-VJWzv5mr3Z765TFB1PfHJhznKPFiZN0MTStVtqKQlOe8nkwLevCgZY4oT1Mysg7YJhcWtkquKILXe-y6luJBHzUy_aFAgFliUbcrOhkoBk5olAbSz8Y4sSz5vWugYA1kwlIofnRm4sPcvoIXgUD_SGGI3QNsQyRWQEhf7G5mNRrxmLhZZLXAcBAzkw10nEjRfew2Fri7bdvyzJ1OS_af9fHmeqCZG5ievKIX6keUkIYQo_qm4FQFkXZSl9lMHsUSF-di4F6ws31vM0zVLMmH52u12Z3SZhvAFzIV5Vtyt_IfrMV3ANMqVF4SmS4k2qUlv1KuPQVgqGCVHvfeE1oSyYgYF6oFX8ThXNB79wxvi4Oo8fWEZLzZMFH9QEr2c7sOWHYWk-wUMP1auXTQNExEVz22pBxueZGZhRyLdpcA12v8o6vJkVuBj-2eR8GRI7P6InJdQAO9TIBhM7NtJU2NUpeP_84js3RTBVktqBT74nWPaHIddGMSfW2aGmFJovvshhxGMLtN_6XMh4wRKW0IE_-Rfbhk8_-xHKI5McYI048N_TMYOS8KqPPAmGVklRGqPZ5xXMNvQEVweThDTYTo3NoAsS0fN2yMmSwrjRYBHsgYMtil4pd6ddp8dvF_XSJUkW0nF8t6ciI_k47sug3gyw4usqspWxY9Hwbzb4OFzzrgtO_7Ll6lFFFUx2oHy8AO9sJ97Y3Fg6luuew7ZRDzA_4XMrT7mNW6YuT-o2DunaZw-jvQezNHjPN2WhaTS7fkisyhFSFTMBYE-H4psfj_sizutv-LjwbumTcX2mnYE9SZhVr8dL0c7sgwHP1831RxTSSl3ql_obE3ICDooyuM8PYE56Jx0HOOGbEeJd3w91SzNHPG_3SQfXszrZlw4BGWrEUHBbtVY2ZEnsyGNAx6vKO8lz9D-6yZ618foDJSH-Ilk56a5rhr0beWjSd9mYMsr3zpVz6HcpTLYGEgHfPxpT2eaYaC1H_znw7y1eMKamwudYmtz_azX5LrOtwc0p-pXH-kdoNe248pSz9qsmHcXA41fuj2weKQNrmBcghwtfM95B060tnmebJ_B_KkLXL4cNF-hZqi0wAHrHYrZ_WM0Dy90AFH-b7iiWuWz5M1EhZXo179iEdybM-1PgccFJ0zvOqODl7FNxSgWVyNS1k9R42aZx2PzFAfAbBtJ-KVMhUayAvGLNmi35EAT0G6FK65VBEe7A6zPFqzrrAiG8dy3Z0I0253WzIblHPNMpmxI_ca5tIx3u8Za6Nu9rx8mi0CY2jsRSKnqb7RZvLuB78Uj32lb_9jbq5_gL9_y7Bt7U7i7FospyqMFzEYQLvdyrtfNrfY0rB4zr4Mo0tDn_4YOD_d_nP5axUh9_ruqXZ_d3eVdNmlITjQZj8ALe1EfidP8a-Dl62t6STVv8d2y8v9-jy3J7wReLJbJ6gDDnygJllY7NrIVXSjR45FXiCDnpaRonu--I_0b_LRJFOoJUJX0S9YMaXAkKyHSEj-UWjiuk8cIBNcXxwlxnqqNMezvvV113MAOEbfHygDnphzjzZQxteAVbSy0ucGDR2FPi30d6z51NxGnXNS_sM7wnjBMNp4Li0hhttOp6PgvDKPSMAcgUtKLFKE8iWQAvERoUVxw5Et20hNTNXf_0sXOyh0bF0URPGDxSYz9uZI6-nlwVlo1aobdEnn7STSq2_tuTDIrQyfBGZzhv8OB0H3cj9mBs=', provider_name='openai', ), ), PartStartEvent( index=1, part=BuiltinToolCallPart( tool_name='web_search', tool_call_id='ws_00a60507bf41223d0068c9d30021d081a0962d80d50c12e317', provider_name='openai', ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta={'query': 'weather: San Francisco, CA', 'type': 'search'}, tool_call_id='ws_00a60507bf41223d0068c9d30021d081a0962d80d50c12e317', ), ), PartStartEvent( index=2, part=BuiltinToolReturnPart( tool_name='web_search', content={'sources': [{'type': 'api', 'url': None, 'name': 'oai-weather'}], 'status': 'completed'}, tool_call_id='ws_00a60507bf41223d0068c9d30021d081a0962d80d50c12e317', timestamp=IsDatetime(), provider_name='openai', ), ), PartStartEvent( index=3, part=ThinkingPart( content='', id='rs_00a60507bf41223d0068c9d300b23481a0b77a03d911213220', signature='gAAAAABoydMLww_4DcIPiCy5zW1t-Dtx57JodsdP9YkyDCvY9r0nBfoD-bwcBl8FfcFxRuq5nK5ndf90J6Xdxmvl9kGVbCUYSFaOd-kWeE4tgwXM8BwwE3jVs6ZMG3BdiWyXS3alnUO5jcE6kuXeun1LufAdZ6rWtJl3zSmqPycnTh9zoQ4cBBxLDq_qcVS1fgU4WjsWgjCZw6ZWRPWwZk8hywmU7ykCLH7SXItM4oH1m_GCEounJAS8YR4ajUh5KAdN6a1wngfGnXhYdzov98yiNLP6Nrkgr--K4vMTTqWXLTcR6fbWgkijanIeKmfSErCjMT6k5TrAbkFx0rgblHbdQii7zj8seV1BWZse92_k4sltxfc5Ocpyho1YSHhgxyGL7g442xMUEibjPCv6kwPMcW9yGu9wPMWsfPYCXpBbG6kQibQPNFJ_bEubwBRaqdSDq93Aqr1YkTYBja7Tewn8UfzZ8YYaGe5y_K4ZD47lfvDp019dOdXmOuZGC1ECRrMqKzSFYVG1CFY1VhjGdPmzobDoMcpZcLn25s1pg6lnNqNQwOk_IA4MvUcCU5HHD5YjmFkEy5-i_iRoDVu5coK0zyEMvPJ_h10y_ByszcfzS9e0ht5CSilckkFdxTBkZ5epp0YIg1e-PrZ790P-I35Ucquam9OXyULV1Y5bn9ohZa93Tv0JZRxUeTDG72_28xRj8tkJaBAZjoCC7VICw39KVmz-ZkuVN6IIX1WdNzyC4d808-2Tz4UZaU42-wxEWDnSDMD7iZu1Bi9fKKwAYBJt_OcEsJwpW63ZaUSG2PVFfm7a3wRcSMxMTUTTJB7L1Keu1hmNepif5tavn3P35nSq28D_IJyAqAgX7ZyROk2bJqjzSE4A0MddqAoBFFqKBi68n49KH09vDtDXIoh8jVWuIgowgVGr8pN3kuhLI9cir4Pr_WES0tPD7yWHPTzrD7OIJCfQbr_4Y4dEza4ixNi0RTADWzMUZBfr7bvwIsgvg6ZNuQlx_d71Go5VDsT2KI8H8AldiRvNWoLyYTFGyK9Kot97YsS5sEmSYgNAH48NU7pgnM0jNDQU1G39nTNFEjL_ziDwjDT5g3jm4S_gbQfwx-XFT3Pv-JYR-E71AqR--Lg71OsASq49rrlULfl5OENfiT-NB6x8MqnfUI6NpcCsOWLp8XfRbgqmZFutLIi43pcnxEe3cXHLWGF77qJXP6dFb-G5Ide7n9tAOoEgfsVu7hCDPEQ_xrIYRdc2DzDPUMCtXBai24E0AnQF8kxsEtlDW_YmAgGNTl9Gx0tFSGdDuUCsNx__c7v-_LOMWycXUKmH3iEr_su83oGIMapNp2PnLccN4iOxspdZQq0C6WBaR6SrdnGzK-0KwRPRoyKDLNWS8zfluR5bIgKlqd3Sbv_7eL-WO4LQXMvdKP3KS-DBt1HbA-gmyFW03iX2smPQbtVmRLWi1vG329R_07-tHMJSO9OQy6_6aiyO8Rgpbl_CHa1Q9BEkI2csonayDJRPvEXBPuk9-NPUP4VLNPB7npWBLlAqes5ZmhagnC7srTL0fFiLGLJiAxWo1f0BBiIlXjwqHdlgBjTw0KryCnEU8Ic8ATzrqEXXhs-FTBCcWInf3Bt5bzUhy20g7cTtYP-VCbsku-lXQ6wceWrfQVFtjKKICD8I4g9QusAIAvgCUm7J2rR3TLkzwOKngdTFPGQrQ1TYzlkA7q_Ew1uZpaPRckMaEioZYC6Sv_B0rgW0nyBJ0GLrB3AUN60hDrOFntyFHp0FM-Zh1SY-GKGBwZwVetOzM0ZAJ-NreFg1XVgyLTYDNjUrYJjRhr_JARsZ5t0pU4_yI6dPqM5jKO5_k4UpZspfQon6d2-NlWX0EDmz6G4CMTx0TScehYHrQZtPzpVnivc8h_pmXV3jO5GLzNeLWoB70SDPTETo1Of4txiEUaC2komu5B7MN9aR4c7VBOTv1NIjoiZcrd1HFACzZ7r1qAE-G38j1f1YhfZ0_TiMmtfR1cqjAKcFkyRM7rZMyMvvnsH7NFq59gFgWZt0dy0aAdw03XWXFNT67lrw58OYC3NcVozH4SKlmleu7TfjHNWSnJVjJ66riLn9DZWVxPeTk4zuISZn0yyaoXcdW8OMn_mJ9vP-8L1wElMyxKbtBRz-0cW7MshmJ3YXmHWDKbnqETSbDMtqcN_QyRJovopwlptJ8VzL7biuURRFw-l63Kc9vKP72Z-QWOUIPLB4q4nX4yb-IV0mkWFxIUlfv5Cze2anf7zDFyGzeU9xG0onfhJE4HFKcoUT8MzfrHZ0dDZtnEYeL5Xem3GuHpwEVGCxRE_J1joTmJfeWxSVnr2Vey9gaPmXCyRrdKS75v9xSXJFfHvcOO8Qp35Dzk-yFqL3dSOJfOEwDZbEf6QnV7VU1EhJvW4XmRS-wsRLMLCYcLrOx96NHEwb2h2l6gNfbCVJoQrMhMg68qBPnoSYLhML2ho7hWkSNZFy61yX5I-oEJV5XdtjFcBkyurmUD6uYTkJSqXyxLexQiPbT-uv49Yp9cAfFBG23sC9lUQ=', provider_name='openai', ), ), PartStartEvent( index=4, part=TextPart(content='San Francisco', id='msg_00a60507bf41223d0068c9d30b055481a0b0ee28a021919c94'), ), FinalResultEvent(tool_name=None, tool_call_id=None), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' weather')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' today')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' (')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='Tuesday')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=',')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' September')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' ')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='16')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=',')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' ')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='202')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='5')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='):')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' Mostly')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' sunny')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' and')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' pleasant')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='.')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' Current')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' conditions')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' around')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' ')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='71')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='°F')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=';')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' expected')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' high')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' near')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' ')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='73')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='°F')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' and')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' low')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' around')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' ')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='58')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='°F')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='.')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' A light jacket')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' is useful')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' for the')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' cooler evening')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='. ')), BuiltinToolCallEvent( # pyright: ignore[reportDeprecated] part=BuiltinToolCallPart( tool_name='web_search', args={'query': 'weather: San Francisco, CA', 'type': 'search'}, tool_call_id='ws_00a60507bf41223d0068c9d30021d081a0962d80d50c12e317', provider_name='openai', ) ), BuiltinToolResultEvent( # pyright: ignore[reportDeprecated] result=BuiltinToolReturnPart( tool_name='web_search', content={'sources': [{'type': 'api', 'url': None, 'name': 'oai-weather'}], 'status': 'completed'}, tool_call_id='ws_00a60507bf41223d0068c9d30021d081a0962d80d50c12e317', timestamp=IsDatetime(), provider_name='openai', ) ), ] ) result = await agent.run(user_prompt='how about Mexico City?', message_history=messages) assert result.new_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='how about Mexico City?', timestamp=IsDatetime(), ) ], instructions='You are a helpful assistant.', ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_00a60507bf41223d0068c9d316accc81a096fd539b77c931cd', signature='gAAAAABoydMovnl5STyQJfKyyT-LV6102tn7M3ppFZHklPnA1LWETYbnDdCSLgeh1OqOXicuil2GTd-peiKj033k_NL0ZF5mCymWY-g5qoovU8OauQyb2uR9zmLe-cjghlOuiIJjiZC1_DCbwY1MHObzuME-Hn5WiSlfTTcdKfZqaQpzIKVKgbx6cSDDyS5j29ClLw-M6GQUDVDsjkclLEcc8pdoAwvuWDoARgMYXwcS-7Ajl46_9oA92RP-64VjrO6Wxzz9HjKcnBTcSDUcyJxsdolHq6G0TjZFwECg4RWvzcpijO53OF58a4_SfgUqbupni7o-tMzITyF1lwE5Xq9fluUFHXmbH0QCrk_7lGRjeiFqY9tTv_VKbNeHSVj5obUnA5HyAYb5jEqgy9M-CgdN1DJeODMTq3Ncu1y81_p7sXqxpbh1c-2eHkGj6yMFjO-dF9LpX_GUZZgAoPXN-J0k3_6VFWc6FjwOGbPU_weslCBpBnS0USfiif9y8nzH2xg0VrHCUEliBOkN-QLqq68edZOBAmYgG8iRDx-yG762TzOBri-0EdFHGWnMij_onb0y4f0UOXD-qSqHvBj8WKasOSRkBpJmIkDViKXYab3nhOtUb4Y3jNhSh6KYEW1QETK9oOMc1zd0Osk-z0QBLQdGtMuFiR00Bs1M_E4T0lMYEsFRqQ8TZmM5-hmrAkBVx3u1f9-ccBZE0ANOiNWH-G75LozwgZhYrOwbuDSnG3wq2M0L7F1mkseg5lOGKgyaxkaifO6WyS6JCHMwDZUF4gZKyHItg3x3PACmTdUy_Wda55J5oIFklWtjFGbU-dY7vr8wvyF0Q0jEeMp8tFvMpGOGTVlydMBq6SCWrZAz8uDoMRxuNLecaHj3bSQHbfeC3hs8uKCLOMr0X_ZCQ8ATXSSjjml3onzNvqChlsspKcwtEKKSwHNTMUJbY6cyy45EQdYhbKg75k-ZL7Y6BXMRjCc5CJd-4uuD8_cXHi4ikmkpHmgZLHcQPOdFflXeDlpYVTF9-Hyblg4SsxvLX9Vp5h4T4J_RcalfwPsIAwIEn8RSutJyMAIm0tYsEzq5i4usmLMxyEBbekCgP5DlHbeWvj3B8h0WoPE7C4cA1m29A_7bRDcJiL06D2T13r9zh17W7UYucDtTcJF7dtKHJTFK_C9m6wW-rHhXi1CgTFU8acDLYGK_VhZhQmTD7tM5JX7IEw_yokWzqyZzWFHmN4mgvAn3imeOXliVLY2YxD7I8-6xAgez6tVyX6plXIpE4KL-GLnFXyqORwIhH4F4EvEm6AcurW8pPWBXXVOY8Ml25-3D1tSu6sQ4PFzgvE5FWiwkBUpLSKwBjZqfg3_aG3NQe4exExztofsCD1l12US7OTx76h7utifDiu_FuzSZHOq0sM0kWfsrzoaPW79T7CT0Ew97HqEJTvYvhkdmzgtA-57zYK-8kc2bUTmTNdl_nUovO-xRhvwamIjMTzgqo3FXjLAtj4QZYWIHInkGj8GIxLluow315yWxARpfTehrpgvwYbd-tJ0UFyCZ1J0RwXQ8QmBu7UV-qPxj88d8cuY9sn8xba3kFCLifxlohEOupJcDDNHjta5eunNYoE127ap0Pv5KdJHWaOUcpScrXz3dIEXBlax12ySZNkghKGgGqYzOyQBKvkAgcV2rHaUQjuAkEbV3uQuE7iG3413fqfRVyAOKHKv3ig0jUM2DqBfhK9Tmxdbh-5VI5H5r5dgw3GmTQtSZVd0Q3mIMCeghrfHeCW4Ms1lRjcwEbn1Uyffs7KylhabOdqmiRTUPavLgKZmSrh7q0Vrkmb3s-nZEcfnVL6o2OpuQrdm83K-aI0Pvnsf9V9U_qoW1HWf61ENQUhnMECD2P70EsSmXLnQ_7f3v4Nyw-MCWCPpdzJvCh0TrpcTpY4WcflgbkNxm9xorCEiTlnEaeGSYj0MDcNm8sJYZbWzNQoNmbj58XS4IgnfCIYcoyu6PTceMcE7o_w50MPC3LcMTzZWKSYnGA7xDrvfeD7boqfj-Xd37SDYSTp9OAifiwiTXZyl7FqVTk1Y-1RCYTvIPPpnhXedT4ehYPRL9_fYmTgVISPLK8IQyNHpme86nG1-0FOJoitzwOa94MICeNKJArYvZ4Kj9WlP5-cTjP6zoDlaYxXXuln6DRmOnqL5CDVqf3f-7Dg-n8ARgNFwaAuvLXhCxuuRdcnNN5gx1z5vnvusq2sMCZx-eRqaGQsRoAoWo1VsrW5bwPGHwZN9Ip97KeORMAV8ExDttxjS4DXO-nB5fVZ2KToAsglOjLfvoXi7ArwK4Du3u7N_kzERB8lVT25jOltMdhOISXCGzY-ORQr6WhS_fgM8s8wHJSAtEl2w5VaFku57kEgWmfmasDNz5O1iMlqKOzVGpd9qNUtWaqYDK9DIxaL-O1pQGbzzuCsq332tez68SMNdbjNaf5RS3MHgAKHmI0I2RaGdBcaXjlap3sEMANG7keCNYSrtU-vfoMfb708dt2Ux2dDktmtSMFwZyzbOnGOshGhxsW5O98Uo-I-PZLsHSj4ZJSD5yIayNiuf8bZ0_REJ-9I-5xdfyUDstO7xj4IRjwwnsF9Td8CUycBKxr4gsttwfOoo04LVLOg7mDbK1GtoLEP2e-nXBHsFsOObaW3bOTx7TZwQf5DLggHsEfqdArl1-MqhRllSJNFtBLV3T8bRIvDl-YCV_LYjvWqRvo0RsR3oxrrPGwHM5ROy0WdfHixv2t5voksrS40VJI-KVXqgvF4ixUTMCjpL_pKpBq3pVZEnsJc4yZgK-C-sz72NZNKFHZviJhcdPDuwd4dX7oiI9X2KbnRfoo67xMqTuQCryLeiF7FpFoBHIjH2OhMzk2HbJR5YK9Q8blsWHpAdy', provider_name='openai', ), BuiltinToolCallPart( tool_name='web_search', args={'query': 'weather: Mexico City, Mexico', 'type': 'search'}, tool_call_id='ws_00a60507bf41223d0068c9d31b6aec81a09d9e568afa7b59aa', provider_name='openai', ), BuiltinToolReturnPart( tool_name='web_search', content={ 'sources': [{'type': 'api', 'url': None, 'name': 'oai-weather'}], 'status': 'completed', }, tool_call_id='ws_00a60507bf41223d0068c9d31b6aec81a09d9e568afa7b59aa', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_00a60507bf41223d0068c9d31c935881a0b835341209f6ac8b', signature='gAAAAABoydMoKoctyyCO6gsPILkjEnvCX0VL-9Gqk9qAmNEdWKNRPvxRIBVCxX4hGZ4m5fZJmuSIjjrA-nU-cUj_XIsARJsJywo2ka8IDmGRF8m7lm5atgcSJQjytRVpIA6s7sz0Sw3iAKrjtQcbymz2sUViTiOn7OqUStKtW0h98UIubdU6d19hu3iDwNddCuAC4QDy8cg3qJhjq9QTtovoBwFpibBJ12ISJqoPLSs43YvWK26o-evCMfzVbkuqJ7Gqie14gZ0oQChxGj7-bopeml1MCaDAz0EUxD5EDfjSdgjB_JABqF13kTTFdAVJu8gY1WgjFt0m1CONQGlM2oQA7cywjU7NnGWSNOqZp_NSDeTBYsKykAmyJP_lTzIDhhG37GBW7PwvBwuUYbvPcMmsRR9FDXxcMeVcpZPmaDjXhRAkJ-Am48Xz676pYl5Sx732-Pv9w503O66ARt6jwQYB4ZW5GgJAnqoqugbmJoGfOV4TaF0glOfKB5XPNQx--_hARpmXuQX3M_Xg1zLa6n7xGmf9pv__Gnhk3V0OlEnTD5HPZzc13F2hKX1PZ8E4ykq4843ZHDV3vpc5WsNCp6C6Cq8STXq58_QAU8P9vpqEP8khnYt3EJTjzbweiqVrMj6cSoUS9C32z8dFcA0rQrTmt_tEMTaoTN1Q5nTboSm0jX1arXqGh3RhcDkqddBDLfI6PdTVulEPVnBkmZJmCFqdfm_aD9FCSCVJdKE5pktBFqtmGFRJ6RVeGbc_YB6XG9najhjXNhhXIpy176CIPLZbeXkxcgsJQBdDGm4PpUePHZAGKxOpFCNv7kZMyGcsd-Ye-envhfdGhJ5dMOqRq-1KtjopdvNFfmxASkrT8f33YFj6n07fXOOfY02pTl9Dyv7fp0gk_3DR6zKFZRwv-Y3u0sTjQTkk7xTZsuEb0iP_zpqMNcj834fq4FZFvmhJ_siVVOQUPMaP0OFJnYFTteQR8S8JXud4Er1jEZlVojHugyJ3K4yMoj5c16jIQLaFn1_Jk1G97LCO-WZjSxpDD5niEXmYEoC1cw5zweUE7MjkzG1cBU2Wgjw_K0zt0Ko9DxYMDDDS-ZphpCJFPKBiX7pDcpKDpkQnDkEpzIIyDQ3mEKoKvYAXLveKuhOnNnVpUVN28hvW5_QfhD3C1WEBTzz2-dfxLpiS_MHI9NVUZdIue_ThGAM8TFY9MqDrTfAMRMD_mdQHW8XE_QdxighLLuG56AqufuA4CutwifYdbMiAE_mWtApqG4U6dx8cMnmIxnN_lrerv3IQR9_rk6vgPG-MfyJ0drDmSaJGMKyBexYau6sCzyMZYzFO-YgPDa0Yz4DYwhjTnGqtoMSE94ciYiJWZV473WIcyvJ8lE2mQD735nf1OKk7FHsai2mmQzk6NHyyEvvltkTPN8ply0fqmxLksng1bKD43zkHjnP_wUU5uInfAPIGMtIXuwJJXUziMTFRcCawC0KcUUP1J9GK9nrIMeO2B-yM5GXwfvMq3TiI4VFHD9Dav18T5BufMsjIY6uOUuWKNHSOpSQ6VHoql3k7fh2NVGOWqq3juBo2P3BNwXpP6mPr_6diYK4ciukrh4MiUd3pkLZnaW_iv4XYoq0Wix4ENU4zI1kMj5ObFAQOEbeoqdC6u4I5MIOXU6Pep-kaFl6P3yb37Ce95GyPq6xx8q4G29DK6Rx9Qowha8x9BIphuSL01Z6snFTewQW9rqAP7GyEltkso456vXzay08wtzG0dGpxoCIc87mAhx7-ulTj1Wti0qekLhsavem7GPfNKqso4CPsiXMxtTBBoIHk0xAvXcpZcw33pY_71-SHpMafrMrkS-Rp2T6YztbX2u_Nx__O8NAD2V0T0l69gR4S0khT_z-rttSPuCfx0-C4_hz7mCjVPMlLGDzxahOxG25Z9LHst6NPvlfg0xxX5rQ80XAS9GtLJ5uKMEwMxoGCatV3VL2zT2M0SpNiZKLZpH2tHfm0j_2dFcsLWN0a9MAooVZQ1Rlnq_7r0QrAPqcca_Y1Q7Jlzx2dgiEylYfFzNlNU2JTtinZg25gq3A7WayuWE5iBV5dhPijkcgEQbDETKg0eRa584q_cd68Rlm7qYeID3pc8gAbZ4zdqz6SfcQqoZS_EN43Z4Mc-t_HKN-9BwgXFNfvzbLoNekhoCiTrcEUikzXjVKqTbcuczAtH-uie_bfQkwfljFn7J8t7A3SeP961mvpx7iE-yJ4HXTeFhJI2TlBm4JB3OKMCoJSFdEiHjx82bX7TEPvq9g940TgPaooWUD2mEJ_f9ByY84L4EywrGFhtj-DxA1igkbWnCgWlxEquBcvmkRHkbTylkJz6kyz-_-5EPUEJLHqGsDHgotxYWXsxCalzDktH_GivrkeTYqhy1SikEJw93-X5SPMLD7EdQUS_K3XIe9p4T9lpn__zs_tCqssrun7ZQEpY9ULoYiMn2ENU9rK4IYpDoV0beXs4Xa24nj3qgrzbuzbLeKKbm8Y8RxNStogi4E4pK_difBVb_1oTIxfPrLnAJibQ8H-Tb9v20L2Zd3RWXtKi46-XJizKe9r-_JI2HmZ4QM2JOaBhHdybeBrwnu1Z36WhPk4m7YyK8-0K-kIPd-mW_ZF29tHBVhLifqPOq7D3HkJbnBH--KJum-F3v5LLqmeBN-3LWv6bk9-jqQNum9pm2WHtUkOMvH3zw0h8yiBjK3Qov7XHAP9dKHKs3B1eVqiVFGNbuB3Ss07ZzXQrSxgNFP2z64-HtdLJdsSXu3BGc7BqFrnF1tUVeu-KDXKXxJ0SFYaxnLqThuQ4b8CUXYWd8fnhCbhu3OE9Pd2aKWr-4bj73DTDcHLnYmy53mgNKtItsJBfA7m5Dzf6WKREmictNl5nMUWWlEay0nvE6so39zkRlc7wihRthJTEMDbMUdARJw7o1F8JBUPY3cIJchDnq0ZiGkrCA-OyPx-rkxbrQq9usJoTT7XUZNVZ5u7mXH8dY6uY4opcJmV02W2eJms-VtTxgkXuh_HLz_VPmCRMGfACFMwigpShdnr_j3T70ixy80FLcY6ILu1EbuZeLeqo4L8Z5fznYZ1', provider_name='openai', ), TextPart( content='Mexico City weather today (Tuesday, September 16, 2025): Cloudy. Current around 73°F; high near 74°F and low around 56°F. Showers return midweek. ', id='msg_00a60507bf41223d0068c9d326034881a0bb60d6d5d39347bd', ), ], usage=RequestUsage( input_tokens=9703, cache_read_tokens=8576, output_tokens=638, details={'reasoning_tokens': 576}, ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_00a60507bf41223d0068c9d31574d881a090c232646860a771', finish_reason='stop', ), ] ) def test_model_profile_strict_not_supported(): my_tool = ToolDefinition( name='my_tool', description='This is my tool', parameters_json_schema={'type': 'object', 'title': 'Result', 'properties': {'spam': {'type': 'number'}}}, strict=True, ) m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key='foobar')) tool_param = m._map_tool_definition(my_tool) # type: ignore[reportPrivateUsage] assert tool_param == snapshot( { 'name': 'my_tool', 'parameters': {'type': 'object', 'title': 'Result', 'properties': {'spam': {'type': 'number'}}}, 'type': 'function', 'description': 'This is my tool', 'strict': True, } ) # Some models don't support strict tool definitions m = OpenAIResponsesModel( 'gpt-4o', provider=OpenAIProvider(api_key='foobar'), profile=replace(openai_model_profile('gpt-4o'), openai_supports_strict_tool_definition=False), ) tool_param = m._map_tool_definition(my_tool) # type: ignore[reportPrivateUsage] assert tool_param == snapshot( { 'name': 'my_tool', 'parameters': {'type': 'object', 'title': 'Result', 'properties': {'spam': {'type': 'number'}}}, 'type': 'function', 'description': 'This is my tool', 'strict': False, } ) @pytest.mark.vcr() async def test_reasoning_model_with_temperature(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('o3-mini', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(m, model_settings=OpenAIResponsesModelSettings(temperature=0.5)) result = await agent.run('What is the capital of Mexico?') assert result.output == snapshot( 'The capital of Mexico is Mexico City. It serves as the political, cultural, and economic heart of the country and is one of the largest metropolitan areas in the world.' ) @pytest.mark.vcr() async def test_tool_output(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) class CityLocation(BaseModel): city: str country: str agent = Agent(m, output_type=ToolOutput(CityLocation)) @agent.tool_plain async def get_user_country() -> str: return 'Mexico' result = await agent.run('What is the largest city in the user country?') assert result.output == snapshot(CityLocation(city='Mexico City', country='Mexico')) assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is the largest city in the user country?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ToolCallPart( tool_name='get_user_country', args='{}', tool_call_id=IsStr(), id='fc_68477f0bb8e4819cba6d781e174d77f8001fd29e2d5573f7', ) ], usage=RequestUsage(input_tokens=62, output_tokens=12, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68477f0b40a8819cb8d55594bc2c232a001fd29e2d5573f7', finish_reason='stop', ), ModelRequest( parts=[ ToolReturnPart( tool_name='get_user_country', content='Mexico', tool_call_id='call_ZWkVhdUjupo528U9dqgFeRkH', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ToolCallPart( tool_name='final_result', args='{"city":"Mexico City","country":"Mexico"}', tool_call_id='call_iFBd0zULhSZRR908DfH73VwN', id='fc_68477f0c91cc819e8024e7e633f0f09401dc81d4bc91f560', ) ], usage=RequestUsage(input_tokens=85, output_tokens=20, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68477f0bfda8819ea65458cd7cc389b801dc81d4bc91f560', finish_reason='stop', ), ModelRequest( parts=[ ToolReturnPart( tool_name='final_result', content='Final result processed.', tool_call_id='call_iFBd0zULhSZRR908DfH73VwN', timestamp=IsDatetime(), ) ] ), ] ) @pytest.mark.vcr() async def test_text_output_function(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) def upcase(text: str) -> str: return text.upper() agent = Agent(m, output_type=TextOutput(upcase)) @agent.tool_plain async def get_user_country() -> str: return 'Mexico' result = await agent.run('What is the largest city in the user country?') assert result.output == snapshot('THE LARGEST CITY IN MEXICO IS MEXICO CITY.') assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is the largest city in the user country?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ToolCallPart( tool_name='get_user_country', args='{}', tool_call_id='call_aTJhYjzmixZaVGqwl5gn2Ncr', id='fc_68477f0dff5c819ea17a1ffbaea621e00356a60c98816d6a', ) ], usage=RequestUsage(input_tokens=36, output_tokens=12, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68477f0d9494819ea4f123bba707c9ee0356a60c98816d6a', finish_reason='stop', ), ModelRequest( parts=[ ToolReturnPart( tool_name='get_user_country', content='Mexico', tool_call_id='call_aTJhYjzmixZaVGqwl5gn2Ncr', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ TextPart( content='The largest city in Mexico is Mexico City.', id='msg_68477f0ebf54819d88a44fa87aadaff503434b607c02582d', ) ], usage=RequestUsage(input_tokens=59, output_tokens=11, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68477f0e2b28819d9c828ef4ee526d6a03434b607c02582d', finish_reason='stop', ), ] ) @pytest.mark.vcr() async def test_native_output(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) class CityLocation(BaseModel): """A city and its country.""" city: str country: str agent = Agent(m, output_type=NativeOutput(CityLocation)) @agent.tool_plain async def get_user_country() -> str: return 'Mexico' result = await agent.run('What is the largest city in the user country?') assert result.output == snapshot(CityLocation(city='Mexico City', country='Mexico')) assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is the largest city in the user country?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ToolCallPart( tool_name='get_user_country', args='{}', tool_call_id=IsStr(), id='fc_68477f0fa7c081a19a525f7c6f180f310b8591d9001d2329', ) ], usage=RequestUsage(input_tokens=66, output_tokens=12, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68477f0f220081a1a621d6bcdc7f31a50b8591d9001d2329', finish_reason='stop', ), ModelRequest( parts=[ ToolReturnPart( tool_name='get_user_country', content='Mexico', tool_call_id='call_tTAThu8l2S9hNky2krdwijGP', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ TextPart( content='{"city":"Mexico City","country":"Mexico"}', id='msg_68477f10846c81929f1e833b0785e6f3020197534e39cc1f', ) ], usage=RequestUsage(input_tokens=89, output_tokens=16, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68477f0fde708192989000a62809c6e5020197534e39cc1f', finish_reason='stop', ), ] ) @pytest.mark.vcr() async def test_native_output_multiple(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) class CityLocation(BaseModel): city: str country: str class CountryLanguage(BaseModel): country: str language: str agent = Agent(m, output_type=NativeOutput([CityLocation, CountryLanguage])) @agent.tool_plain async def get_user_country() -> str: return 'Mexico' result = await agent.run('What is the largest city in the user country?') assert result.output == snapshot(CityLocation(city='Mexico City', country='Mexico')) assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is the largest city in the user country?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ToolCallPart( tool_name='get_user_country', args='{}', tool_call_id=IsStr(), id='fc_68477f1168a081a3981e847cd94275080dd57d732903c563', ) ], usage=RequestUsage(input_tokens=153, output_tokens=12, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68477f10f2d081a39b3438f413b3bafc0dd57d732903c563', finish_reason='stop', ), ModelRequest( parts=[ ToolReturnPart( tool_name='get_user_country', content='Mexico', tool_call_id='call_UaLahjOtaM2tTyYZLxTCbOaP', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ TextPart( content='{"result":{"kind":"CityLocation","data":{"city":"Mexico City","country":"Mexico"}}}', id='msg_68477f1235b8819d898adc64709c7ebf061ad97e2eef7871', ) ], usage=RequestUsage(input_tokens=176, output_tokens=26, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68477f119830819da162aa6e10552035061ad97e2eef7871', finish_reason='stop', ), ] ) @pytest.mark.vcr() async def test_prompted_output(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) class CityLocation(BaseModel): city: str country: str agent = Agent(m, output_type=PromptedOutput(CityLocation)) @agent.tool_plain async def get_user_country() -> str: return 'Mexico' result = await agent.run('What is the largest city in the user country?') assert result.output == snapshot(CityLocation(city='Mexico City', country='Mexico')) assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is the largest city in the user country?', timestamp=IsDatetime(), ) ], instructions="""\ Always respond with a JSON object that's compatible with this schema: {"properties": {"city": {"type": "string"}, "country": {"type": "string"}}, "required": ["city", "country"], "title": "CityLocation", "type": "object"} Don't include any text or Markdown fencing before or after.\ """, ), ModelResponse( parts=[ ToolCallPart( tool_name='get_user_country', args='{}', tool_call_id=IsStr(), id='fc_68482f1b0ff081a1b37b9170ee740d1e02f8ef7f2fb42b50', ) ], usage=RequestUsage(input_tokens=107, output_tokens=12, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68482f12d63881a1830201ed101ecfbf02f8ef7f2fb42b50', finish_reason='stop', ), ModelRequest( parts=[ ToolReturnPart( tool_name='get_user_country', content='Mexico', tool_call_id='call_FrlL4M0CbAy8Dhv4VqF1Shom', timestamp=IsDatetime(), ) ], instructions="""\ Always respond with a JSON object that's compatible with this schema: {"properties": {"city": {"type": "string"}, "country": {"type": "string"}}, "required": ["city", "country"], "title": "CityLocation", "type": "object"} Don't include any text or Markdown fencing before or after.\ """, ), ModelResponse( parts=[ TextPart( content='{"city":"Mexico City","country":"Mexico"}', id='msg_68482f1c159081918a2405f458009a6a044fdb7d019d4115', ) ], usage=RequestUsage(input_tokens=130, output_tokens=12, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68482f1b556081918d64c9088a470bf0044fdb7d019d4115', finish_reason='stop', ), ] ) @pytest.mark.vcr() async def test_prompted_output_multiple(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) class CityLocation(BaseModel): city: str country: str class CountryLanguage(BaseModel): country: str language: str agent = Agent(m, output_type=PromptedOutput([CityLocation, CountryLanguage])) @agent.tool_plain async def get_user_country() -> str: return 'Mexico' result = await agent.run('What is the largest city in the user country?') assert result.output == snapshot(CityLocation(city='Mexico City', country='Mexico')) assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is the largest city in the user country?', timestamp=IsDatetime(), ) ], instructions="""\ Always respond with a JSON object that's compatible with this schema: {"type": "object", "properties": {"result": {"anyOf": [{"type": "object", "properties": {"kind": {"type": "string", "const": "CityLocation"}, "data": {"properties": {"city": {"type": "string"}, "country": {"type": "string"}}, "required": ["city", "country"], "type": "object"}}, "required": ["kind", "data"], "additionalProperties": false, "title": "CityLocation"}, {"type": "object", "properties": {"kind": {"type": "string", "const": "CountryLanguage"}, "data": {"properties": {"country": {"type": "string"}, "language": {"type": "string"}}, "required": ["country", "language"], "type": "object"}}, "required": ["kind", "data"], "additionalProperties": false, "title": "CountryLanguage"}]}}, "required": ["result"], "additionalProperties": false} Don't include any text or Markdown fencing before or after.\ """, ), ModelResponse( parts=[ ToolCallPart( tool_name='get_user_country', args='{}', tool_call_id=IsStr(), id='fc_68482f2889d481a199caa61de7ccb62c08e79646fe74d5ee', ) ], usage=RequestUsage(input_tokens=283, output_tokens=12, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68482f1d38e081a1ac828acda978aa6b08e79646fe74d5ee', finish_reason='stop', ), ModelRequest( parts=[ ToolReturnPart( tool_name='get_user_country', content='Mexico', tool_call_id='call_my4OyoVXRT0m7bLWmsxcaCQI', timestamp=IsDatetime(), ) ], instructions="""\ Always respond with a JSON object that's compatible with this schema: {"type": "object", "properties": {"result": {"anyOf": [{"type": "object", "properties": {"kind": {"type": "string", "const": "CityLocation"}, "data": {"properties": {"city": {"type": "string"}, "country": {"type": "string"}}, "required": ["city", "country"], "type": "object"}}, "required": ["kind", "data"], "additionalProperties": false, "title": "CityLocation"}, {"type": "object", "properties": {"kind": {"type": "string", "const": "CountryLanguage"}, "data": {"properties": {"country": {"type": "string"}, "language": {"type": "string"}}, "required": ["country", "language"], "type": "object"}}, "required": ["kind", "data"], "additionalProperties": false, "title": "CountryLanguage"}]}}, "required": ["result"], "additionalProperties": false} Don't include any text or Markdown fencing before or after.\ """, ), ModelResponse( parts=[ TextPart( content='{"result":{"kind":"CityLocation","data":{"city":"Mexico City","country":"Mexico"}}}', id='msg_68482f296bfc81a18665547d4008ab2c06b4ab2d00d03024', ) ], usage=RequestUsage(input_tokens=306, output_tokens=22, details={'reasoning_tokens': 0}), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68482f28c1b081a1ae73cbbee012ee4906b4ab2d00d03024', finish_reason='stop', ), ] ) @pytest.mark.vcr() async def test_openai_responses_verbosity(allow_model_requests: None, openai_api_key: str): """Test that verbosity setting is properly passed to the OpenAI API""" # Following GPT-5 + verbosity documentation pattern provider = OpenAIProvider( api_key=openai_api_key, base_url='https://api.openai.com/v1', # Explicitly set base URL ) model = OpenAIResponsesModel('gpt-5', provider=provider) agent = Agent(model=model, model_settings=OpenAIResponsesModelSettings(openai_text_verbosity='low')) result = await agent.run('What is 2+2?') assert result.output == snapshot('4') @pytest.mark.vcr() async def test_openai_previous_response_id(allow_model_requests: None, openai_api_key: str): """Test if previous responses are detected via previous_response_id in settings""" model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model) result = await agent.run('The secret key is sesame') settings = OpenAIResponsesModelSettings(openai_previous_response_id=result.all_messages()[-1].provider_response_id) # type: ignore result = await agent.run('What is the secret code?', model_settings=settings) assert result.output == snapshot('sesame') @pytest.mark.vcr() async def test_openai_previous_response_id_auto_mode(allow_model_requests: None, openai_api_key: str): """Test if invalid previous response id is ignored when history contains non-OpenAI responses""" history = [ ModelRequest( parts=[ UserPromptPart( content='The first secret key is sesame', ), ], ), ModelResponse( parts=[ TextPart(content='Open sesame! What would you like to unlock?'), ], model_name='gpt-5', provider_name='openai', provider_response_id='resp_68b9bd97025c8195b443af591ca2345c08cb6072affe6099', ), ModelRequest( parts=[ UserPromptPart( content='The second secret key is olives', ), ], ), ModelResponse( parts=[ TextPart(content='Understood'), ], model_name='gpt-5', provider_name='openai', provider_response_id='resp_68b9bda81f5c8197a5a51a20a9f4150a000497db2a4c777b', ), ] model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model) settings = OpenAIResponsesModelSettings(openai_previous_response_id='auto') result = await agent.run('what is the first secret key', message_history=history, model_settings=settings) assert result.output == snapshot('sesame') async def test_openai_previous_response_id_mixed_model_history(allow_model_requests: None, openai_api_key: str): """Test if invalid previous response id is ignored when history contains non-OpenAI responses""" history = [ ModelRequest( parts=[ UserPromptPart( content='The first secret key is sesame', ), ], ), ModelResponse( parts=[ TextPart(content='Open sesame! What would you like to unlock?'), ], model_name='claude-3-5-sonnet-latest', provider_name='anthropic', provider_response_id='msg_01XUQuedGz9gusk4xZm4gWJj', ), ModelRequest( parts=[ UserPromptPart( content='what is the first secret key?', ), ], ), ] model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) previous_response_id, messages = model._get_previous_response_id_and_new_messages(history) # type: ignore assert not previous_response_id assert messages == snapshot( [ ModelRequest(parts=[UserPromptPart(content='The first secret key is sesame', timestamp=IsDatetime())]), ModelResponse( parts=[TextPart(content='Open sesame! What would you like to unlock?')], usage=RequestUsage(), model_name='claude-3-5-sonnet-latest', timestamp=IsDatetime(), provider_name='anthropic', provider_response_id='msg_01XUQuedGz9gusk4xZm4gWJj', ), ModelRequest(parts=[UserPromptPart(content='what is the first secret key?', timestamp=IsDatetime())]), ] ) async def test_openai_previous_response_id_same_model_history(allow_model_requests: None, openai_api_key: str): """Test if message history is trimmed when model responses are from same model""" history = [ ModelRequest( parts=[ UserPromptPart( content='The first secret key is sesame', ), ], ), ModelResponse( parts=[ TextPart(content='Open sesame! What would you like to unlock?'), ], model_name='gpt-5', provider_name='openai', provider_response_id='resp_68b9bd97025c8195b443af591ca2345c08cb6072affe6099', ), ModelRequest( parts=[ UserPromptPart( content='The second secret key is olives', ), ], ), ModelResponse( parts=[ TextPart(content='Understood'), ], model_name='gpt-5', provider_name='openai', provider_response_id='resp_68b9bda81f5c8197a5a51a20a9f4150a000497db2a4c777b', ), ModelRequest( parts=[ UserPromptPart( content='what is the first secret key?', ), ], ), ] model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) previous_response_id, messages = model._get_previous_response_id_and_new_messages(history) # type: ignore assert previous_response_id == 'resp_68b9bda81f5c8197a5a51a20a9f4150a000497db2a4c777b' assert messages == snapshot( [ ModelRequest(parts=[UserPromptPart(content='what is the first secret key?', timestamp=IsDatetime())]), ] ) async def test_openai_responses_usage_without_tokens_details(allow_model_requests: None): c = response_message( [ ResponseOutputMessage( id='123', content=cast(list[Content], [ResponseOutputText(text='4', type='output_text', annotations=[])]), role='assistant', status='completed', type='message', ) ], # Intentionally use model_construct so that input_tokens_details and output_tokens_details will not be set. usage=ResponseUsage.model_construct(input_tokens=14, output_tokens=1, total_tokens=15), ) mock_client = MockOpenAIResponses.create_mock(c) model = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(openai_client=mock_client)) agent = Agent(model=model) result = await agent.run('What is 2+2?') assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is 2+2?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[TextPart(content='4', id='123')], usage=RequestUsage(input_tokens=14, output_tokens=1, details={'reasoning_tokens': 0}), model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', provider_response_id='123', ), ] ) assert result.usage() == snapshot( RunUsage(input_tokens=14, output_tokens=1, details={'reasoning_tokens': 0}, requests=1) ) async def test_openai_responses_model_thinking_part(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) settings = OpenAIResponsesModelSettings(openai_reasoning_effort='high', openai_reasoning_summary='detailed') agent = Agent(m, model_settings=settings) result = await agent.run('How do I cross the street?') assert result.all_messages() == snapshot( [ ModelRequest(parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())]), ModelResponse( parts=[ ThinkingPart( content=IsStr(), id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de', signature=IsStr(), provider_name='openai', ), ThinkingPart(content=IsStr(), id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de'), ThinkingPart(content=IsStr(), id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de'), ThinkingPart(content=IsStr(), id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de'), ThinkingPart(content=IsStr(), id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de'), ThinkingPart(content=IsStr(), id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de'), TextPart( content=IsStr(), id='msg_68c42cb1aaec819cb992bd92a8c7766007460311b0c8d3de', ), ], usage=RequestUsage(input_tokens=13, output_tokens=2199, details={'reasoning_tokens': 1920}), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68c42c902794819cb9335264c342f65407460311b0c8d3de', finish_reason='stop', ), ] ) result = await agent.run( 'Considering the way to cross the street, analogously, how do I cross the river?', message_history=result.all_messages(), ) assert result.new_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Considering the way to cross the street, analogously, how do I cross the river?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content=IsStr(), id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de', signature=IsStr(), provider_name='openai', ), ThinkingPart(content=IsStr(), id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de'), ThinkingPart(content=IsStr(), id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de'), ThinkingPart(content=IsStr(), id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de'), ThinkingPart(content=IsStr(), id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de'), TextPart( content=IsStr(), id='msg_68c42cd36134819c800463490961f7df07460311b0c8d3de', ), ], usage=RequestUsage(input_tokens=314, output_tokens=2737, details={'reasoning_tokens': 2112}), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68c42cb3d520819c9d28b07036e9059507460311b0c8d3de', finish_reason='stop', ), ] ) async def test_openai_responses_thinking_part_from_other_model( allow_model_requests: None, anthropic_api_key: str, openai_api_key: str ): m = AnthropicModel( 'claude-sonnet-4-0', provider=AnthropicProvider(api_key=anthropic_api_key), settings=AnthropicModelSettings(anthropic_thinking={'type': 'enabled', 'budget_tokens': 1024}), ) agent = Agent(m) result = await agent.run('How do I cross the street?') assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='How do I cross the street?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content=IsStr(), signature=IsStr(), provider_name='anthropic', ), TextPart(content=IsStr()), ], usage=RequestUsage( input_tokens=42, output_tokens=291, details={ 'cache_creation_input_tokens': 0, 'cache_read_input_tokens': 0, 'input_tokens': 42, 'output_tokens': 291, }, ), model_name='claude-sonnet-4-20250514', timestamp=IsDatetime(), provider_name='anthropic', provider_details={'finish_reason': 'end_turn'}, provider_response_id='msg_0114iHK2ditgTf1N8FWomc4E', finish_reason='stop', ), ] ) result = await agent.run( 'Considering the way to cross the street, analogously, how do I cross the river?', model=OpenAIResponsesModel( 'gpt-5', provider=OpenAIProvider(api_key=openai_api_key), settings=OpenAIResponsesModelSettings(openai_reasoning_effort='high', openai_reasoning_summary='detailed'), ), message_history=result.all_messages(), ) assert result.new_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Considering the way to cross the street, analogously, how do I cross the river?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content=IsStr(), id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc', signature=IsStr(), provider_name='openai', ), ThinkingPart(content=IsStr(), id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc'), ThinkingPart(content=IsStr(), id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc'), ThinkingPart(content=IsStr(), id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc'), ThinkingPart(content=IsStr(), id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc'), ThinkingPart(content=IsStr(), id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc'), TextPart(content=IsStr(), id='msg_68c42d0b5e5c819385352dde1f447d910ad492c7955fc6fc'), ], usage=RequestUsage(input_tokens=306, output_tokens=3134, details={'reasoning_tokens': 2496}), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68c42ce277ac8193ba08881bcefabaf70ad492c7955fc6fc', finish_reason='stop', ), ] ) async def test_openai_responses_thinking_part_iter(allow_model_requests: None, openai_api_key: str): provider = OpenAIProvider(api_key=openai_api_key) responses_model = OpenAIResponsesModel('o3-mini', provider=provider) settings = OpenAIResponsesModelSettings(openai_reasoning_effort='high', openai_reasoning_summary='detailed') agent = Agent(responses_model, model_settings=settings) async with agent.iter(user_prompt='How do I cross the street?') as agent_run: async for node in agent_run: if Agent.is_model_request_node(node) or Agent.is_call_tools_node(node): async with node.stream(agent_run.ctx) as request_stream: async for _ in request_stream: pass assert agent_run.result is not None assert agent_run.result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='How do I cross the street?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content=IsStr(), id='rs_68c42d1d0878819d8266007cd3d1402c08fbf9b1584184ff', signature='gAAAAABoxC0m_QWpOlSt8wyPk_gtnjiI4mNLOryYlNXO-6rrVeIqBYDDAyMVg2_ldboZvfhW8baVbpki29gkTAyNygTr7L8gF1XK0hFovoa23ZYJKvuOnyLIJF-rXCsbDG7YdMYhi3bm82pMFVQxNK4r5muWCQcHmyJ2S1YtBoJtF_D1Ah7GpW2ACvJWsGikb3neAOnI-RsmUxCRu-cew7rVWfSj8jFKs8RGNQRvDaUzVniaMXJxVW9T5C7Ytzi852MF1PfVq0U-aNBzZBtAdwQcbn5KZtGkYLYTChmCi2hMrh5-lg9CgS8pqqY9-jv2EQvKHIumdv6oLiW8K59Zvo8zGxYoqT--osfjfS0vPZhTHiSX4qCkK30YNJrWHKJ95Hpe23fnPBL0nEQE5l6XdhsyY7TwMom016P3dgWwgP5AtWmQ30zeXDs=', provider_name='openai', ), ThinkingPart( content=IsStr(), id='rs_68c42d1d0878819d8266007cd3d1402c08fbf9b1584184ff', ), ThinkingPart( content=IsStr(), id='rs_68c42d1d0878819d8266007cd3d1402c08fbf9b1584184ff', ), ThinkingPart( content=IsStr(), id='rs_68c42d1d0878819d8266007cd3d1402c08fbf9b1584184ff', ), TextPart( content=IsStr(), id='msg_68c42d26866c819da8d5c606621c911608fbf9b1584184ff', ), ], usage=RequestUsage(input_tokens=13, output_tokens=1680, details={'reasoning_tokens': 1408}), model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68c42d0fb418819dbfa579f69406b49508fbf9b1584184ff', finish_reason='stop', ), ] ) async def test_openai_responses_thinking_with_tool_calls(allow_model_requests: None, openai_api_key: str): provider = OpenAIProvider(api_key=openai_api_key) m = OpenAIResponsesModel( model_name='gpt-5', provider=provider, settings=OpenAIResponsesModelSettings(openai_reasoning_summary='detailed', openai_reasoning_effort='low'), ) agent = Agent(model=m) @agent.instructions def system_prompt(): return ( 'You are a helpful assistant that uses planning. You MUST use the update_plan tool and continually ' "update it as you make progress against the user's prompt" ) @agent.tool_plain def update_plan(plan: str) -> str: return 'plan updated' prompt = ( 'Compose a 12-line poem where the first letters of the odd-numbered lines form the name "SAMIRA" ' 'and the first letters of the even-numbered lines spell out "DAWOOD." Additionally, the first letter ' 'of each word in every line should create the capital of a country' ) result = await agent.run(prompt) assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Compose a 12-line poem where the first letters of the odd-numbered lines form the name "SAMIRA" and the first letters of the even-numbered lines spell out "DAWOOD." Additionally, the first letter of each word in every line should create the capital of a country', timestamp=IsDatetime(), ) ], instructions="You are a helpful assistant that uses planning. You MUST use the update_plan tool and continually update it as you make progress against the user's prompt", ), ModelResponse( parts=[ ThinkingPart( content=IsStr(), id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6', signature=IsStr(), provider_name='openai', ), ThinkingPart(content=IsStr(), id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6'), ThinkingPart(content=IsStr(), id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6'), ThinkingPart(content=IsStr(), id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6'), ThinkingPart(content=IsStr(), id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6'), ToolCallPart( tool_name='update_plan', args=IsStr(), tool_call_id='call_gL7JE6GDeGGsFubqO2XGytyO', id='fc_68c42d3e9e4881968b15fbb8253f58540e8bc41441c948f6', ), ], usage=RequestUsage(input_tokens=124, output_tokens=1926, details={'reasoning_tokens': 1792}), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68c42d28772c819684459966ee2201ed0e8bc41441c948f6', finish_reason='stop', ), ModelRequest( parts=[ ToolReturnPart( tool_name='update_plan', content='plan updated', tool_call_id='call_gL7JE6GDeGGsFubqO2XGytyO', timestamp=IsDatetime(), ) ], instructions="You are a helpful assistant that uses planning. You MUST use the update_plan tool and continually update it as you make progress against the user's prompt", ), ModelResponse( parts=[TextPart(content=IsStr(), id='msg_68c42d408eec8196ae1c5883e07c093e0e8bc41441c948f6')], usage=RequestUsage( input_tokens=2087, cache_read_tokens=2048, output_tokens=124, details={'reasoning_tokens': 0} ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68c42d3fd6a08196bce23d6be960ff8a0e8bc41441c948f6', finish_reason='stop', ), ] ) async def test_openai_responses_thinking_without_summary(allow_model_requests: None): c = response_message( [ ResponseReasoningItem( id='rs_123', summary=[], type='reasoning', encrypted_content='123', ), ResponseOutputMessage( id='msg_123', content=cast(list[Content], [ResponseOutputText(text='4', type='output_text', annotations=[])]), role='assistant', status='completed', type='message', ), ], ) mock_client = MockOpenAIResponses.create_mock(c) model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(openai_client=mock_client)) agent = Agent(model=model) result = await agent.run('What is 2+2?') assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is 2+2?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart(content='', id='rs_123', signature='123', provider_name='openai'), TextPart(content='4', id='msg_123'), ], model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', provider_response_id='123', ), ] ) _, openai_messages = await model._map_messages(result.all_messages(), model_settings=model.settings or {}) # type: ignore[reportPrivateUsage] assert openai_messages == snapshot( [ {'role': 'user', 'content': 'What is 2+2?'}, {'id': 'rs_123', 'summary': [], 'encrypted_content': '123', 'type': 'reasoning'}, { 'role': 'assistant', 'id': 'msg_123', 'content': [{'text': '4', 'type': 'output_text', 'annotations': []}], 'type': 'message', 'status': 'completed', }, ] ) async def test_openai_responses_thinking_with_multiple_summaries(allow_model_requests: None): c = response_message( [ ResponseReasoningItem( id='rs_123', summary=[ Summary(text='1', type='summary_text'), Summary(text='2', type='summary_text'), Summary(text='3', type='summary_text'), Summary(text='4', type='summary_text'), ], type='reasoning', encrypted_content='123', ), ResponseOutputMessage( id='msg_123', content=cast(list[Content], [ResponseOutputText(text='4', type='output_text', annotations=[])]), role='assistant', status='completed', type='message', ), ], ) mock_client = MockOpenAIResponses.create_mock(c) model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(openai_client=mock_client)) agent = Agent(model=model) result = await agent.run('What is 2+2?') assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is 2+2?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart(content='1', id='rs_123', signature='123', provider_name='openai'), ThinkingPart(content='2', id='rs_123'), ThinkingPart(content='3', id='rs_123'), ThinkingPart(content='4', id='rs_123'), TextPart(content='4', id='msg_123'), ], model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', provider_response_id='123', ), ] ) _, openai_messages = await model._map_messages(result.all_messages(), model_settings=model.settings or {}) # type: ignore[reportPrivateUsage] assert openai_messages == snapshot( [ {'role': 'user', 'content': 'What is 2+2?'}, { 'id': 'rs_123', 'summary': [ {'text': '1', 'type': 'summary_text'}, {'text': '2', 'type': 'summary_text'}, {'text': '3', 'type': 'summary_text'}, {'text': '4', 'type': 'summary_text'}, ], 'encrypted_content': '123', 'type': 'reasoning', }, { 'role': 'assistant', 'id': 'msg_123', 'content': [{'text': '4', 'type': 'output_text', 'annotations': []}], 'type': 'message', 'status': 'completed', }, ] ) async def test_openai_responses_thinking_with_modified_history(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) settings = OpenAIResponsesModelSettings(openai_reasoning_effort='low', openai_reasoning_summary='detailed') agent = Agent(m, model_settings=settings) result = await agent.run('What is the meaning of life?') messages = result.all_messages() assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is the meaning of life?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content=IsStr(), id='rs_68c42de022c881948db7ed1cc2529f2e0202c9ad459e0d23', signature=IsStr(), provider_name='openai', ), TextPart(content=IsStr(), id='msg_68c42de31d348194a251b43ad913ef140202c9ad459e0d23'), ], usage=RequestUsage(input_tokens=13, output_tokens=248, details={'reasoning_tokens': 64}), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68c42ddf9bbc8194aa7b97304dd909cb0202c9ad459e0d23', finish_reason='stop', ), ] ) response = messages[-1] assert isinstance(response, ModelResponse) assert isinstance(response.parts, list) response.parts[1] = TextPart(content='The meaning of life is 42') with pytest.raises( ModelHTTPError, match=r"Item '.*' of type 'reasoning' was provided without its required following item\.", ): await agent.run('Anything to add?', message_history=messages) result = await agent.run( 'Anything to add?', message_history=messages, model_settings=OpenAIResponsesModelSettings( openai_reasoning_effort='low', openai_reasoning_summary='detailed', openai_send_reasoning_ids=False, ), ) assert result.new_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Anything to add?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content=IsStr(), id='rs_68c42de4f63c819fb31b6019a4eaf67c051f82c608a83beb', signature=IsStr(), provider_name='openai', ), TextPart(content=IsStr(), id='msg_68c42de8a410819faf7a9cbebd2b4bc4051f82c608a83beb'), ], usage=RequestUsage(input_tokens=142, output_tokens=355, details={'reasoning_tokens': 128}), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68c42de4afcc819f995a1c59fe87c9d5051f82c608a83beb', finish_reason='stop', ), ] ) async def test_openai_responses_thinking_with_code_execution_tool(allow_model_requests: None, openai_api_key: str): provider = OpenAIProvider(api_key=openai_api_key) m = OpenAIResponsesModel( model_name='gpt-5', provider=provider, settings=OpenAIResponsesModelSettings( openai_reasoning_summary='detailed', openai_reasoning_effort='low', openai_include_code_execution_outputs=True, ), ) agent = Agent(model=m, builtin_tools=[CodeExecutionTool()]) result = await agent.run(user_prompt='what is 65465-6544 * 65464-6+1.02255') assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='what is 65465-6544 * 65464-6+1.02255', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content=IsStr(), id='rs_68cdba57390881a3b7ef1d2de5c8499709b7445677780c8f', signature='gAAAAABozbpoKwjspVdWvC2skgCFSKx1Fiw9QGDrOxixFaC8O5gPVmC35FfE2jaedsn0zsHctrsl2LvPt7ELnOB3N20bvDGcDHkYzjSOLpf1jl2IAtQrkPWuLPOb6h8mIPL-Z1wNrngsmuoaKP0rrAcGwDwKzq8hxpLQbjvpRib-bbaVQ0SX7KHDpbOuEam3bIEiNSCNsA1Ot54R091vvwInnCCDMWVj-9u2fn7xtNzRGjHorkAt9mOhOBIVgZNZHnWb4RQ-PaYccgi44-gtwOK_2rhI9Qo0JiCBJ9PDdblms0EzBE7vfAWrCvnb_jKiEmKf2x9BBv3GMydsgnTCJdbBf6UVaMUnth1GvnDuJBdV12ecNT2LhOF2JNs3QjlbdDx661cnNoCDpNhXpdH3bL0Gncl7VApVY3iT2vRw4AJCU9U4xVdHeWb5GYz-sgkTgjbgEGg_RiU42taKsdm6B2gvc5_Pqf4g6WTdq-BNCwOjXQ4DatQBiJkgV5kyg4PqUqr35AD05wiSwz6reIsdnxDEqtWv4gBJWfGj4I96YqkL9YEuIBKORJ7ArZnjE5PSv6TIhqW-X9mmQTGkXl8emxpbdsNfow3QEd_l8rQEo4fHiFOGwU-uuPCikx7v6vDsE-w_fiZTFkM0X4iwFb6NXvOxKSdigfUgDfeCySwfmxtMx67QuoRA4xbfSHI9cctr-guZwMIIsMmKnTT-qGp-0F4UiyRQdgz2pF1bRUjkPml2rsleHQISztdSsiOGC2jozXNHwmf1b5z6KxymO8gvlImvLZ4tgseYpnAP8p_QZzMjIU7Y7Z2NQMDASr9hvv3tVjVCphqz1RH-h4gifjZJexwK9BR9O98u63X03f01NqgimS_dZHZUeC9voUb7_khNizA9-dS-fpYUduqvxZt-KZ7Q9gx7kFIH3wJvF-Gef55lwy4JNb8svu1wSna3EaQWTBeZOPHD3qbMXWVT5Yf5yrz7KvSemiWKqofYIInNaRLTtXLAOqq4VXP3dmgyEmAZIUfbh3IZtQ1uYwaV2hQoF-0YgM7JLPNDBwX8cRZtlyzFstnDsL_QLArf0bA8FMFNPuqPfyKFvXcGTgzquaUzngzNaoGo7k6kPHWLoSsWbvY3WvzYg4CO04sphuuSHh9TZRBy6LXCdxaMHIZDY_qVB1Cf-_dmDW6Eqr9_xodcTMBqs6RHlttLwFMMiul4aE_hUgNFlzOX7oVbisIS2Sm36GTuKE4zrbkvsA==', provider_name='openai', ), BuiltinToolCallPart( tool_name='code_execution', args={ 'container_id': 'cntr_68cdba56addc81918f656db25fd0a6800d6da575ea4fee9b', 'code': """\ # compute the value 65465 - 6544 * 65464 - 6 + 1.02255 """, }, tool_call_id='ci_68cdba5af39881a393a01eebb253854e09b7445677780c8f', provider_name='openai', ), BuiltinToolReturnPart( tool_name='code_execution', content={'status': 'completed', 'logs': ['-428330955.97745']}, tool_call_id='ci_68cdba5af39881a393a01eebb253854e09b7445677780c8f', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content=IsStr(), id='rs_68cdba63843881a3a9c585d83e4df9f309b7445677780c8f', signature='gAAAAABozbpoJefk0Fp1xqQzY6ego00t7KnH2ohbIw-rR9ZgaEAQs3n0Fubka6xbgRxzb1og6Xup1BuT8hQKMS-NHFxYsYXw4b6KeSbCd5oySVO53bsITEVk0A6tgjGssDJc1xSct1ORo-nCNV24MCNZvL9MKFeGQHP-jRypOZ9Vhepje87kFWTpw9lP9j54fZJdRIBGA9G_goI9m1cPztFUufcUxtLsgorsM053oxh8yWiEccAbvBaGXRlPWSoZYktbKrWeBVwiRt2ul-jRV43Z3chB32bEM1l9sIWG1xnvLE3OY6HuAy5s3bB-bnk78dibx5yx_iA36zGOvRkfiF0okXZoYiMNzJz3U7rTSsKlYoMtCKgnYGFdrh0D8RPj4VtxnRr-zAMJSSZQCm7ZipNSMS0PpN1wri14KktSkIGZGLhPBJpzPf9AjzaBBi2ZcUM347BtOfEohPdLBn8R6Cz-WxmoA-jH9qsyO-bPzwtRkv28H5G6836IxU2a402Hl0ZQ0Q-kPb5iqhvNmyvEQr6sEY_FN6ogkxwS-UEdDs0QlvJmgGfOfhMpdxfi5hr-PtElPg7j5_OwA7pXtuEI8mADy2VEqicuZzIpo6d-P72-Wd8sapjo-bC3DLcJVudFF09bJA0UirrxwC-zJZlmOLZKG8OqXKBE4GLfiLn48bYa5FC8a_QznrX8iAV6qPoqyqXANXuBtBClmzTHQU5A3lUgwSgtJo6X_0wZqw0O4lQ1iQQrkt7ZLeT7Ef6QVLyh9ZVaMZqVGrmHbphZK5N1u8b4woZYJKe0J57SrNihO8Slu8jZ71dmXjB4NAPjm0ZN6pVaZNLUajSxolJfmkBuF1BCcMYMVJyvV7Kk9guTCtntLZjN4XVOJWRU8Db5BjL17ciWWHGPlQBMxMdYFZOinwCHLIRrtdVxz4Na2BODjl0-taYJHbKd-_5up5nysUPc4imgNawbN2mNwjhdc1Qv919Q9Cz-he9i3j6lKYnEkgJvKF2RDY6-XAI=', provider_name='openai', ), TextPart( content="""\ Using standard order of operations (multiplication before addition/subtraction): 65465 - 6544 * 65464 - 6 + 1.02255 = -428,330,955.97745 If you intended different grouping with parentheses, let me know.\ """, id='msg_68cdba6652ac81a3a58625883261465809b7445677780c8f', ), ], usage=RequestUsage( input_tokens=1493, cache_read_tokens=1280, output_tokens=125, details={'reasoning_tokens': 64} ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68cdba511c7081a389e67b16621029c609b7445677780c8f', finish_reason='stop', ), ] ) messages = result.all_messages() result = await agent.run(user_prompt='how about 2 to the power of 8?', message_history=messages) assert result.new_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='how about 2 to the power of 8?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content=IsStr(), id='rs_68cdba6c100481a394047de63f3e175009b7445677780c8f', signature='gAAAAABozbpuOXVfjIYw7Gw6uSeadpkyaqMU1Frav7mTaf9LP8p8YuC8CWR9fYa02yZ5oYr1mqmYraD8ViOE33zqO2HBCdiWpOkVdNX-s4SGuPPB7ewyM7bDD4XbaSzo-Q5I6MgZmvVGWDGodqa3MfSKKNcGyD4aEfryQRLi4ObvHE5yuOqRo8FzGXMqe_pFdnvJXXD7njyfUofhWNvQPsLVLQFA_g_e7WKXtJJf_2JY183oi7-jNQ6rD9wGhM81HWSv0sTSBIHMpcE44rvlVQMFuh_rOPVUHUhT7vED7fYtrMoaPl46yDBc148T3MfXTnS-zm163zBOa34Yy_VXjyXw04a8Ig32y72bJY7-PRpZdBaeqD3BLvXfMuY4C911Z7FSxVze36mUxVO62g0uqV4PRw9qFA9mG37KF2j0ZsRzfyAClK1tu5omrYpenVKuRlrOO6JFtgyyE9OtLJxqvRNRKgULe2-cOQlo5S74t9lSMgcSGQFqF4JKG0A4XbzlliIcvC3puEzObHz-jArn_2BVUL_OPqx9ohJ9ZxAkXYgf0IRNYiKF4fOwKufYa5scL1kx2VAmsmEv5Yp5YcWlriB9L9Mpg3IguNBmq9DeJPiEQBtlnuOpSNEaNMTZQl4jTHVLgA5eRoCSbDdqGtQWgQB5wa7eH085HktejdxFeG7g-Fc1neHocRoGARxwhwcTT0U-re2ooJp99c0ujZtym-LiflSQUICi59VMAO8dNBE3CqXhG6S_ZicUmAvguo1iGKaKElMBv1Tv5qWcs41eAQkhRPBXQXoBD6MtBLBK1M-7jhidVrco0uTFhHBUTqx3jTGzE15YUJAwR69WvIOuZOvJdcBNObYWF9k84j0bZjJfRRbJG0C7XbU=', provider_name='openai', ), TextPart(content='256', id='msg_68cdba6e02c881a3802ed88715e0be4709b7445677780c8f'), ], usage=RequestUsage(input_tokens=793, output_tokens=7, details={'reasoning_tokens': 0}), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68cdba6a610481a3b4533f345bea8a7b09b7445677780c8f', finish_reason='stop', ), ] ) async def test_openai_responses_thinking_with_code_execution_tool_stream( allow_model_requests: None, openai_api_key: str ): provider = OpenAIProvider(api_key=openai_api_key) m = OpenAIResponsesModel( model_name='gpt-5', provider=provider, settings=OpenAIResponsesModelSettings(openai_reasoning_summary='detailed', openai_reasoning_effort='low'), ) agent = Agent(model=m, builtin_tools=[CodeExecutionTool()]) event_parts: list[Any] = [] async with agent.iter(user_prompt="what's 123456 to the power of 123?") as agent_run: async for node in agent_run: if Agent.is_model_request_node(node) or Agent.is_call_tools_node(node): async with node.stream(agent_run.ctx) as request_stream: async for event in request_stream: event_parts.append(event) assert agent_run.result is not None assert agent_run.result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content="what's 123456 to the power of 123?", timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content=IsStr(), id='rs_68c3509b2ee0819eba32735182d275ad0f2d670b80edc507', signature=IsStr(), provider_name='openai', ), BuiltinToolCallPart( tool_name='code_execution', args='{"container_id":"cntr_68c3509aa0348191ad0bfefe24878dbb0deaa35a4e39052e","code":"n = pow(123456, 123)\\nlen(str(n))"}', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507', provider_name='openai', ), BuiltinToolReturnPart( tool_name='code_execution', content={'status': 'completed'}, tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507', timestamp=IsDatetime(), provider_name='openai', ), BuiltinToolCallPart( tool_name='code_execution', args='{"container_id":"cntr_68c3509aa0348191ad0bfefe24878dbb0deaa35a4e39052e","code":"str(n)[:100], str(n)[-100:]"}', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507', provider_name='openai', ), BuiltinToolReturnPart( tool_name='code_execution', content={'status': 'completed'}, tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507', timestamp=IsDatetime(), provider_name='openai', ), BuiltinToolCallPart( tool_name='code_execution', args='{"container_id":"cntr_68c3509aa0348191ad0bfefe24878dbb0deaa35a4e39052e","code":"n"}', tool_call_id='ci_68c350a5e1f8819eb082eccb870199ec0f2d670b80edc507', provider_name='openai', ), BuiltinToolReturnPart( tool_name='code_execution', content={'status': 'completed'}, tool_call_id='ci_68c350a5e1f8819eb082eccb870199ec0f2d670b80edc507', timestamp=IsDatetime(), provider_name='openai', ), TextPart( content=IsStr(), id='msg_68c350a75ddc819ea5406470460be7850f2d670b80edc507', ), ], usage=RequestUsage( input_tokens=3727, cache_read_tokens=3200, output_tokens=347, details={'reasoning_tokens': 128} ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68c35098e6fc819e80fb94b25b7d031b0f2d670b80edc507', finish_reason='stop', ), ] ) assert event_parts == snapshot( [ PartStartEvent( index=0, part=ThinkingPart(content='', id='rs_68c3509b2ee0819eba32735182d275ad0f2d670b80edc507') ), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='**Calcul')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='ating')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' a')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' large')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' integer')), PartDeltaEvent( index=0, delta=ThinkingPartDelta( content_delta="""\ ** I\ """ ), ), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' need')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' to')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' compute')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' 123')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='456')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' raised')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' to')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' the')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' power')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' of')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' 123')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='.')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' That')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=IsStr())), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' an')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' enormous')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' integer')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=',')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' and')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' the')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' user')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' probably')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' wants')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' the')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' exact')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' value')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='.')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' I')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' can')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' use')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Python')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta="'s")), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' ability')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' to')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' handle')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' big')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' integers')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=',')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' but')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' the')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' output')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' will')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' likely')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' be')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' extremely')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' long')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' —')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' potentially')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' hundreds')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' of')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' digits')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='.')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' I')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' should')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' consider')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' that')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' and')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' prepare')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' to')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' return')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' the')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' result')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' as')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' plain')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' text')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=',')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' even')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' if')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' it')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' ends')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' up')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' being')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' around')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' 627')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' digits')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='.')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' So')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=',')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' let')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=IsStr())), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' go')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' ahead')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' and')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' compute')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' that')), PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='!')), PartDeltaEvent( index=0, delta=ThinkingPartDelta( signature_delta=IsStr(), provider_name='openai', ), ), PartStartEvent( index=1, part=BuiltinToolCallPart( tool_name='code_execution', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507', provider_name='openai', ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='{"container_id":"cntr_68c3509aa0348191ad0bfefe24878dbb0deaa35a4e39052e","code":"', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507', ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='n', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' =', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' pow', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='(', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='123', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='456', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' ', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='123', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=')\\n', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='len', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='(str', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='(n', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='))', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='"}', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507' ), ), PartStartEvent( index=2, part=BuiltinToolReturnPart( tool_name='code_execution', content={'status': 'completed'}, tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507', timestamp=IsDatetime(), provider_name='openai', ), ), PartStartEvent( index=3, part=BuiltinToolCallPart( tool_name='code_execution', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507', provider_name='openai', ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta='{"container_id":"cntr_68c3509aa0348191ad0bfefe24878dbb0deaa35a4e39052e","code":"', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507', ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta='str', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507' ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta='(n', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507' ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta=')', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507' ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta='[:', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507' ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta='100', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507' ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta='],', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507' ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta=' str', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507' ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta='(n', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507' ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta=')[', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507' ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta='-', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507' ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta='100', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507' ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta=':]', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507' ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta='"}', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507' ), ), PartStartEvent( index=4, part=BuiltinToolReturnPart( tool_name='code_execution', content={'status': 'completed'}, tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507', timestamp=IsDatetime(), provider_name='openai', ), ), PartStartEvent( index=5, part=BuiltinToolCallPart( tool_name='code_execution', tool_call_id='ci_68c350a5e1f8819eb082eccb870199ec0f2d670b80edc507', provider_name='openai', ), ), PartDeltaEvent( index=5, delta=ToolCallPartDelta( args_delta='{"container_id":"cntr_68c3509aa0348191ad0bfefe24878dbb0deaa35a4e39052e","code":"', tool_call_id='ci_68c350a5e1f8819eb082eccb870199ec0f2d670b80edc507', ), ), PartDeltaEvent( index=5, delta=ToolCallPartDelta( args_delta='n', tool_call_id='ci_68c350a5e1f8819eb082eccb870199ec0f2d670b80edc507' ), ), PartDeltaEvent( index=5, delta=ToolCallPartDelta( args_delta='"}', tool_call_id='ci_68c350a5e1f8819eb082eccb870199ec0f2d670b80edc507' ), ), PartStartEvent( index=6, part=BuiltinToolReturnPart( tool_name='code_execution', content={'status': 'completed'}, tool_call_id='ci_68c350a5e1f8819eb082eccb870199ec0f2d670b80edc507', timestamp=IsDatetime(), provider_name='openai', ), ), PartStartEvent( index=7, part=TextPart(content='123', id='msg_68c350a75ddc819ea5406470460be7850f2d670b80edc507') ), FinalResultEvent(tool_name=None, tool_call_id=None), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='456')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='^')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='123')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta=' equals')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta=':\n')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='180')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='302')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='106')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='304')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='044')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='807')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='508')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='140')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='927')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='865')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='938')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='572')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='807')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='342')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='688')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='638')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='559')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='680')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='488')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='440')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='159')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='857')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='958')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='502')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='360')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='813')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='732')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='502')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='197')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='826')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='969')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='863')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='225')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='730')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='871')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='630')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='436')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='419')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='794')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='758')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='932')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='074')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='350')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='380')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='367')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='697')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='649')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='814')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='626')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='542')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='926')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='602')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='664')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='707')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='275')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='874')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='269')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='201')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='777')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='743')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='912')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='313')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='197')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='516')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='323')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='690')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='221')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='274')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='713')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='845')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='895')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='457')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='748')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='735')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='309')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='484')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='337')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='191')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='373')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='255')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='527')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='928')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='271')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='785')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='206')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='382')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='967')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='998')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='984')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='330')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='482')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='105')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='350')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='942')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='229')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='970')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='677')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='054')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='940')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='838')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='210')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='936')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='952')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='303')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='939')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='401')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='656')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='756')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='127')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='607')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='778')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='599')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='667')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='243')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='702')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='814')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='072')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='746')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='219')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='431')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='942')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='293')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='005')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='416')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='411')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='635')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='076')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='021')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='296')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='045')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='493')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='305')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='133')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='645')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='615')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='566')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='590')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='735')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='965')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='652')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='587')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='934')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='290')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='425')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='473')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='827')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='719')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='935')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='012')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='870')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='093')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='575')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='987')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='789')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='431')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='818')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='047')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='013')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='404')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='691')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='795')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='773')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='170')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='405')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='764')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='614')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='646')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='054')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='949')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='298')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='846')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='184')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='678')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='296')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='813')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='625')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='595')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='333')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='311')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='611')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='385')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='251')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='735')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='244')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='505')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='448')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='443')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='050')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='050')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='547')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='161')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='779')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='229')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='749')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='134')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='489')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='643')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='622')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='579')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='100')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='908')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='331')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='839')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='817')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='426')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='366')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='854')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='332')), PartDeltaEvent(index=7, delta=TextPartDelta(content_delta='416')), BuiltinToolCallEvent( # pyright: ignore[reportDeprecated] part=BuiltinToolCallPart( tool_name='code_execution', args='{"container_id":"cntr_68c3509aa0348191ad0bfefe24878dbb0deaa35a4e39052e","code":"n = pow(123456, 123)\\nlen(str(n))"}', tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507', provider_name='openai', ) ), BuiltinToolResultEvent( # pyright: ignore[reportDeprecated] result=BuiltinToolReturnPart( tool_name='code_execution', content={'status': 'completed'}, tool_call_id='ci_68c3509faff0819e96f6d45e6faf78490f2d670b80edc507', timestamp=IsDatetime(), provider_name='openai', ) ), BuiltinToolCallEvent( # pyright: ignore[reportDeprecated] part=BuiltinToolCallPart( tool_name='code_execution', args='{"container_id":"cntr_68c3509aa0348191ad0bfefe24878dbb0deaa35a4e39052e","code":"str(n)[:100], str(n)[-100:]"}', tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507', provider_name='openai', ) ), BuiltinToolResultEvent( # pyright: ignore[reportDeprecated] result=BuiltinToolReturnPart( tool_name='code_execution', content={'status': 'completed'}, tool_call_id='ci_68c350a41d2c819ebb23bdfb9ff322770f2d670b80edc507', timestamp=IsDatetime(), provider_name='openai', ) ), BuiltinToolCallEvent( # pyright: ignore[reportDeprecated] part=BuiltinToolCallPart( tool_name='code_execution', args='{"container_id":"cntr_68c3509aa0348191ad0bfefe24878dbb0deaa35a4e39052e","code":"n"}', tool_call_id='ci_68c350a5e1f8819eb082eccb870199ec0f2d670b80edc507', provider_name='openai', ) ), BuiltinToolResultEvent( # pyright: ignore[reportDeprecated] result=BuiltinToolReturnPart( tool_name='code_execution', content={'status': 'completed'}, tool_call_id='ci_68c350a5e1f8819eb082eccb870199ec0f2d670b80edc507', timestamp=IsDatetime(), provider_name='openai', ) ), ] ) async def test_openai_responses_streaming_usage(allow_model_requests: None, openai_api_key: str): class Result(BaseModel): result: int agent = Agent( model=OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)), model_settings=OpenAIResponsesModelSettings( openai_reasoning_effort='low', openai_service_tier='flex', ), output_type=Result, ) async with agent.iter('Calculate 100 * 200 / 3') as run: async for node in run: if Agent.is_model_request_node(node): async with node.stream(run.ctx) as response_stream: async for _ in response_stream: pass assert response_stream.get().usage == snapshot( RequestUsage(input_tokens=53, output_tokens=469, details={'reasoning_tokens': 448}) ) assert response_stream.usage() == snapshot( RunUsage(input_tokens=53, output_tokens=469, details={'reasoning_tokens': 448}, requests=1) ) assert run.usage() == snapshot(RunUsage(requests=1)) assert run.usage() == snapshot( RunUsage(input_tokens=53, output_tokens=469, details={'reasoning_tokens': 448}, requests=1) ) assert run.usage() == snapshot( RunUsage(input_tokens=53, output_tokens=469, details={'reasoning_tokens': 448}, requests=1) ) async def test_openai_responses_non_reasoning_model_no_item_ids(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('gpt-4.1', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model) @agent.tool_plain def get_meaning_of_life() -> int: return 42 result = await agent.run('What is the meaning of life?') messages = result.all_messages() assert messages == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is the meaning of life?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ToolCallPart( tool_name='get_meaning_of_life', args='{}', tool_call_id='call_3WCunBU7lCG1HHaLmnnRJn8I', id='fc_68cc4fa649ac8195b0c6c239cd2c14470548824120ffcf74', ) ], usage=RequestUsage(input_tokens=36, output_tokens=15, details={'reasoning_tokens': 0}), model_name='gpt-4.1-2025-04-14', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68cc4fa5603481958e2143685133fe530548824120ffcf74', finish_reason='stop', ), ModelRequest( parts=[ ToolReturnPart( tool_name='get_meaning_of_life', content=42, tool_call_id='call_3WCunBU7lCG1HHaLmnnRJn8I', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ TextPart( content="""\ The meaning of life, according to popular culture and famously in Douglas Adams' "The Hitchhiker's Guide to the Galaxy," is 42! If you're looking for a deeper or philosophical answer, let me know your perspective or context, and I can elaborate further.\ """, id='msg_68cc4fa7693081a184ff6f32e5209ab00307c6d4d2ee5985', ) ], usage=RequestUsage(input_tokens=61, output_tokens=56, details={'reasoning_tokens': 0}), model_name='gpt-4.1-2025-04-14', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68cc4fa6a8a881a187b0fe1603057bff0307c6d4d2ee5985', finish_reason='stop', ), ] ) _, openai_messages = await model._map_messages(messages, model_settings=model.settings or {}) # type: ignore[reportPrivateUsage] assert openai_messages == snapshot( [ {'role': 'user', 'content': 'What is the meaning of life?'}, { 'name': 'get_meaning_of_life', 'arguments': '{}', 'call_id': 'call_3WCunBU7lCG1HHaLmnnRJn8I', 'type': 'function_call', }, {'type': 'function_call_output', 'call_id': 'call_3WCunBU7lCG1HHaLmnnRJn8I', 'output': '42'}, { 'role': 'assistant', 'content': """\ The meaning of life, according to popular culture and famously in Douglas Adams' "The Hitchhiker's Guide to the Galaxy," is 42! If you're looking for a deeper or philosophical answer, let me know your perspective or context, and I can elaborate further.\ """, }, ] ) async def test_openai_responses_code_execution_return_image(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel( 'gpt-5', provider=OpenAIProvider(api_key=openai_api_key), settings=OpenAIResponsesModelSettings(openai_include_code_execution_outputs=True), ) agent = Agent(model=model, builtin_tools=[CodeExecutionTool()], output_type=BinaryImage) result = await agent.run('Create a chart of y=x^2 for x=-5 to 5') assert result.output == snapshot( BinaryImage( data=IsBytes(), media_type='image/png', identifier='653a61', ) ) messages = result.all_messages() assert messages == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Create a chart of y=x^2 for x=-5 to 5', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_68cdc38812288190889becf32c2934990187028ba77f15f7', signature=IsStr(), provider_name='openai', ), BuiltinToolCallPart( tool_name='code_execution', args={ 'container_id': 'cntr_68cdc387531c81938b4bee78c36acb820dbd09bdba403548', 'code': """\ import numpy as np\r import matplotlib.pyplot as plt\r \r # Data\r x = np.arange(-5, 6, 1)\r y = x**2\r \r # Plot\r plt.figure(figsize=(6, 4))\r plt.plot(x, y, marker='o')\r plt.title('y = x^2 for x = -5 to 5')\r plt.xlabel('x')\r plt.ylabel('y')\r plt.grid(True, linestyle='--', alpha=0.6)\r plt.xticks(x)\r plt.tight_layout()\r \r # Save and show\r plt.savefig('/mnt/data/y_equals_x_squared.png', dpi=200)\r plt.show()\r \r '/mnt/data/y_equals_x_squared.png'\ """, }, tool_call_id='ci_68cdc39029a481909399d54b0a3637a10187028ba77f15f7', provider_name='openai', ), FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='653a61', ), id='ci_68cdc39029a481909399d54b0a3637a10187028ba77f15f7', ), BuiltinToolReturnPart( tool_name='code_execution', content={'status': 'completed', 'logs': ["'/mnt/data/y_equals_x_squared.png'"]}, tool_call_id='ci_68cdc39029a481909399d54b0a3637a10187028ba77f15f7', timestamp=IsDatetime(), provider_name='openai', ), TextPart( content=IsStr(), id='msg_68cdc398d3bc8190bbcf78c0293a4ca60187028ba77f15f7', ), ], usage=RequestUsage( input_tokens=2973, cache_read_tokens=1920, output_tokens=707, details={'reasoning_tokens': 512} ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68cdc382bc98819083a5b47ec92e077b0187028ba77f15f7', finish_reason='stop', ), ] ) result = await agent.run('Style it more futuristically.', message_history=messages) assert result.output == snapshot( BinaryImage( data=IsBytes(), media_type='image/png', identifier='81863d', ) ) assert result.new_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Style it more futuristically.', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_68cdc39f6aa48190b5aece25d55f80720187028ba77f15f7', signature='gAAAAABozcPV8NxzVAMDdbpqK7_ltYa5_uAVsbnSW9OMWGRwlnwasaLvuaC4XlgGmC2MHbiPrccJ8zYuu0QoQm7jB6KgimG9Ax3vwoFGqMnfVjMAzoy_oJVadn0Odh3sKGifc11yVMmIkvrl0OcPYwJFlxlt2JhPkKotUDHY0P2LziSsMnQB_KaVdyYQxfcVbwrJJnB9wm2QbA3zNZogWepoXGrHXL1mBRR3J7DLdKGfMF_7gQC5fgEtb3G4Xhvk8_XNgCCZel48bqgzWvNUyaVPb4TpbibAuZnKnCNsFll6a9htGu9Ljol004p_aboehEyIp6zAm_1xyTDiJdcmfPfUiNgDLzWSKf-TwGFd-jRoJ3Aiw1_QY-xi1ozFu2oIeXb2oaZJL4h3ENrrMgYod3Wiprr99FfZw9IRN4ApagGJBnWYqW0O75d-e8jUMJS8zFJH0jtCl0jvuuGmM5vBAV4EpRLTcNGOZyoRpfqHwWfZYIi_u_ajs_A6NdqhzYvxYE-FAE1aJ89HxhnQNjRqkQFQnB8sYeoPOLBKIKAWYi3RziNE8klgSPC250QotupFaskTgPVkzbYe9ZtRZ9IHPeWdEHikb2RP-o1LVVO_zFMJdC6l4TwEToqRG8LaZOgSfkxS8eylTw7ROI2p8IBSmMkbkjvEkpmIic0FSx23Ew_Q-Y6DPa9isxGZcMMS0kOPKSPSML2MGoVq5L3-zIVj6ZBcFOMSaV5ytTlH-tKqBP9fejMyujwQFl5iXawuSjVjpnd2VL83o-xKbm6lEgsyXY1vynlS2hT52OYUY3MMvGSCeW5d7xwsVReO0O1EJqKS0lLh8thEMpJvar9dMgg-9ZCgZ1wGkJlpANf2moQlOWXKPXcbBa2kU0OW2WEffr4ecqg1QwPoMFLmR4HDL-KknuWjutF5bo8FW0CAWmxObxiHeDWIJYpS4KIIwp9DoLdJDWlg8FpD6WbBjKQN6xYmewHaTLWbZQw8zMGBcnhAkkyVopjrbM_6rvrH4ew05mPjPRrq9ODdHBqDYEn1kWj9MBDR-nhhLrci_6GImd64HZXYo0OufgcbxNu5mcAOsN3ww13ui8CTQVsPJO20XHc4jfwZ2Yr4iEIYLGdp0Xgv8EjIkJNA1xPeWn9COgCRrRSVLoF6qsgZwt9IRRGGEbH6kvznO_Y7BTTqufsORG6WNKc_8DDlrczoZVy0d6rI1zgqjXSeMuEP9LBG-bJKAvoAGDPXod8ShlqGX3Eb9CmBTZtTOJZYdgAlsZHx9BZ6zHlrJDjSDhc8xvdUAn9G3JvTI3b5JWSNX0eEerZ4c0FVqlpR-mSG201qnFghtoGHTLJhlIf9Ir8Daio_AYxUTRarQbcKnJuyKHPOz1u0PX2zS0xegO-IZhFbzNaB8qwQgeBiHfP-1dP9mkttqIRMt-hMt9NMHXoGIvFxgQ-xUVw7GRWx-ffKY7nPAbZD8kwVP3i4jTVj8phhwQcDy9UmbaPjm4LBgJkfdwNfSpm3g_ePK4aLa_l7iF2WSSfy2wObb7VatDzYDcNRG0ZTMGsiHy8yzZAcec18rG7uE6QCKx32G8NI5YvcN1kbnrZEuoKTBuSb2B_ZAhvED9HxbG8mH4ZEHHioVuH3_-b2TesVUAbORab_-rG9CU6qyy_eAqP54FYiXXSWtBWNo4baVdqCzgSCiNxgpxx64WPw8y2M1bOMoV6KPGwDOjcNwbO9nQwztqTWPW0Ot_Llf0HV0p-RPC1Uy8uBB5flhJ3p5uqxCPV3kDRzXgjh28EaBEkaSw_6SZkJNvwbD_7VihlHGaO89TwlqSIYUT_gc72NZKRrj4f-Y-0NwxjaSVVGuWCoeG-TMjG6uXpSozo2J47_x_a0lr4KCT8NDYlksajyuPUbYhC7jhQ9uJakmAc7ay_VHn_LYlAWRdAA7wYvqw7aYIuSIYg2OfL6NlggCpBnhsUPEXmMRHcfj1Ctc1aeUjBcpLFVmTZ82lB0FdcKRe3bBsKRckbdKalehoK0NJtrWqNQQH7xPrS-r7or_oOWhA4EDIkRUOG9eZhdsvTXBUamxGwutJ97SdDkgppVC4M7DMK2ZGGBzQsE-JMilERvFQ8JqwVWPxExWmE_-H2-bYe-T-CguCin-mTqhLYswHVtXjtruoHBmDs2SdnkD3intwSpqxsltscCfRaoRYWTCTbchCdbctSEIc39ECpc5tL1Gnav0bwSkMYkxyaRVBiYBbmIG9JftkKIYtdZ_Ddjmq8k29QflqrcigahsVLZPye3dxVTuviqbQjRd2SPMv8RxgSebgm5RZZIpP4WposryghYZFvuA1WImRzsImnAJI9J-8dv6IhHpHsWOw9K-Neg8GlnDU1mGHUElMUbqHiLojmXqPGfhBI3iSR0Ugs7ErpeRUrSk3il2o3rysG1Fn7ePuP5qNJUt2NyBUxf3TExMOwG_zqvpIPr2V_ARr3PsfeD0IcY83Bh428S8KPzc7ASOjT9dGQtVVrdjSxHi8o5ANxGx6z3bHC5dJvDCXg8a7FIJHAd5CUqJxrBi-K4p21jf1BNqgO5JAJO1JrvtdTk4GOVe8YEfhxmGWW9oeuRg8crsIWCCCoxr2XJKgPCj2TTPkBDZ1O3Yw3_nuWaBU5sB09uEB5lTKMd0OfSHbPF4c50RWAFgQB-tHjIUss3oEcAUaZHC77r6sIYoAEBlU8Dgly983fFD0HCqtpIpKS_B_K1fTXYpWRM3uUZpPKEgbfw1Kiqp5cweKTeRKNvjlau6VxhPyVi66xPdHUCC_BcX1eeFe-zcxe6fczcJWqGZGtYyVS_S_GlWZcdA6AHvGU6c4KjG0oU_9q-pdHSRtpnrhqFu2L884m64A_HsFU71Dj34AxhmXO1Am-zSL3j9nEPPUe6lJSGyhHU9k8ApDadWagvlODdXYWaWiMCXGXcYtl_iUAm24IJozlLJ1IW9HW6RoTfKrxwQwND3pX9CLNewuPV776pVtRjvUMbLaYg8nzOu1eNT2IW9dUdzc7wqOjiT1gHuVd6RzJyTCWJb9yPwDTkB_NKkjfUPmJ9Id924xtxy6H0eDYRq-SqsSSEklr6KJc88PV35QqvaMUW1dt_tGynHgYy9PXlWXQLKw-Xphku3FS_R4BLUhJbXDsMOQq332yhizP3qQ7vjEmPm8KB4DMIWBNn_D9xFuDuTCMNPAA9AGYWgC39-L4wPbpBHpqWjDwMzijFpm0CEViPD9ghyyV8syT1uLscxJVVDlBx90u_qWLSzMnFrVWmZ60OyWa9EqG44ZU8ELLHlEDRO_yHuTVpSafCLeDe5baOG2mI6tZnDBmm_ysbYdaC2N_zNBK9rhx7g7BNLQPevl0vtZm7GVLYXiVaO5ZinHxeTyJ6dRU5b0HmSw8r7EpdgORfjUuMkUfWPwhXgTU8SbvjTZg1gJowyNDYCvacrgnmnpBG9BgNjsfWlGTwz19AcEP_GjCWRWoE-uE_5fIyq5eFEefCBUKU0Ejs0IB-Re5h8bbdc6bNV3Tnx4UfGDU6FbQrJmPzrw5wp_wCeVYjtNGRbO2MKr_m52km5xMpVMMHtthVbQ9Zsa9F9zB6Dkr-R4F7o0dITMhG3qaREHKc8mXIGoHND-WSGPZLntB43JmRIWwjlJNstv7VlVc-dU89oh6Z1biH9B88SENI1ao2wMQV-BB17E6cmfzm1JsSR-HkzSf3yoUJWwvIu4CaR4jeMZohuoNqfGvQWIJSfyyUNzq5uY5__04QUmNcRVspOTH4EOHAoXLfCV3VI7fodj4FppiIuIXKwS3N03-Qt4sQ__XQWuyDdORvhRJeCvYcK5kkyOQILcABxDItxLmk8AgdT0Hz0BAo_u1U71srS-T8a8O0-fXWsJAHxDg_rJn0LUm6zq2vXNl8zmOKwEayyb0YySbMRxI-LwLyOXGRDyAVvm_7KKJu1HHqMntLyY2G1xowFpwMVLYXlGxDbsSpE-g5kFnHWhj13FiekLxaFgMRNsMA-r5_rWbEjRa6H328FKsUJcYe9qsp2LlzdJmYZDTIMgzxupFwQ-R5F6QjWOudMBsRszb4YqnOPJ8P9YnY2WYd0B7srb5Gh7T6r6mcCl-HAb2z9QDeXOc2Lu7ujuSvGj7_Gk7PkZH-LzoAEaGG9Z-7IVJlV_hOBPif3GlJUSUhTlIwWxn75gOyoOFuMak-rQqkb0SaL5anfXS_NUTVgSh5G5JQIoykLxbVlGiyeq0M_oEvTw2wMZcWT2hhaudcQ6L912pntcD-WF2tfppgp6sN5-cq-D8Y39N5Txvs-wo-H7-vYKPozTNUKCfnzgXfvt5fOi3RBR4MZU3eHT8OZ7d1d3otho_4GVMNIFa6mxjW1BC_J42Hn27-vrNDLZI_BXdF1t2CCq9VeRwxIW1R9vadd04HzAXyhap95BAYacmbULR6BkX97TvY3hv5cMiaQFkzxg-tf-nGC_VCknvwKxu4ocoB14p9w5TPSKcJz4J26XvyQbi6AdaXbOk625ajB_clv3VJvXYz7DgvWZd408tMykYQLMEyv5lnS7qwQokeM4ilIXwM7EugiakhfefTM9ZdxaWVcvQdqGerx98wlhifCSv0FqFRpJdkqgHmV1qzrAjPDEKT5HJOjsvs5hb7gKBqHR-bYlgS94pvDUpPArQXYcGYGum6vFsCAJypefMTF3D7Zhu4hhWQQv-DzSmfcZOxSeVJFrgVeqJnIbZPtd59HCBXNIRXJa42wUYE4szNli8wKWX0rYSIhiX-ig2YYZz3ZoBE1KDOpzheuk9OMYg7tQG2UlmVq27ggaKJ2gEGuVv-GI7uD7vKxPQ97QwCf38gWKU95CjMEBm_EvmLs9eubNpSpz8Yoek8hWWgrCXUSwRsYnF-lGdG0nIkCClvzqqAGOjyPxG4qfrCXJ-4rVc4DQiJUj71_I0EAhOgxb5WYBt4a7C1aUxC__qeOTAecof-UjzNlUPTo91JgOh5xvZkRkgGFNsq1OFqOcRrrKV8U8brizYkIhDjzjwCIzScSYvEfY4S6st-oJBv5fwTqwICSs59hf6WR8GXsPFR4v3UtF0Rkt-Nrek-X6V7BCui1M5HeFRN7lcTYs1Qw2bIwu4Td5PIkZ16oHdCk9u5pEZce-n_MIwj2Yoq_Lq1BBY9f1rpG9IuaycwabFnd2MOj89-xdgC197DAij5WjZjXahooyAl0Mt3p9MrHCit7LYbxqd_dGBOmg9YRfGPhsoZ17oAmHyg_gvpooOsu21T_06ynhvySjOG0yUcphquvtHJWqQdcT6BBX0X-kGE4nA41VdMhepLhDRDXtR4HJ1m_dPFpkHeAAFIefjt5Kb782TDLFE3KuHFWqSU2K2UmlY12P21dpRvyUNz8ss_AA3rl5jFpcnC2IyJNDIZbqdJPd2z0SNlwNyBq7Vl6poenR-j2X3xzIGlCDQ9zRgs50wdWtZ3ZRWLVWMrVkhkddoVKuh1W9rlwsvxmlZbOeRk_Uh0BymAa0-4-n0jI4_-O8jqpL-YzL1Y191brY4ywLUrQXpln41UK76pxc34FojI1Nymw523SNYxAHSlpj01gNmcjPrBTFxQ9SDY7AlrSFwJia_KvWnsZ53qt6fiDHV7p62KzlG_rpz_dQSQoj-z1hZBoUxi4nqzeCIzPcB_3JqeqD6x1O-Vh3uk-6NxN_qCE8cRsizB5vV-Ur-4tqau6LIrdfIB3Db12vpgiCmD_BD4xCxOijDn-97edRZw__xYfhx9_MBEB6gYl1ZBtLJfxDN54N5UION2tiZ2U8THD_h4d8-c26H7NQv44kYppbaseMckhpVOBDh52P5gxWFwp4VGqAIkZ7KU10qAD6M3GTFx7vGth8cT8YS1s2gPDW-WcVQGlAF94gT-FE6vzAjxwRJ4m7B1rJZfYReDvMrAoLroayOVmfB8pOKVQLQEF5dUmlzAIIpeh1NAiTg4n3FXW7OXQhzhU8bmo0e2FuSEOUVimGw9Nk_Wor3kQFp-9kj_iazSC4p5VURnyY_lAirPfyw4nskpZzCjSg_EAU8Au5vvOqrdDEPjrbeT8ks0wi2rsB0AxQxhgf6jUWzp0apeZOIl9dJFH_OnyJfvwrV4YHpee3174WKYhOJIOy2-8FJbMw1MpQtVV49yWmZsIyjRNj2uLbqY7jWBo2UEeOVW5n1tdk5zAVF-RFPKyh9150MnJz_RQtgoNdUD4iLBwlHYHVGLyH4a3GJmOJP6ZC-A-8RiUjvhu5co0yC8M83aVFjLe-yob3sNgJQgdVJnEOfPz4-1DVORoDgIRrRBcZQZqvkZwADFUkyy9jy5oXdEJ5XzthnizbrOZkHk6sQsNXrP4Uadqo9w99uy7TUh62l5AMWBFcaaQhuAuFkUZCavIqoO-2k4oXIDoTeBYzbyo_HH6caMk0D0_zgEg_5i-NhT3EUPdoCBNmjbOKmN2wzf6kqEyc8-nunjfq6HOjC6B6SE6VgOVJgBrhB4cBto4CxO45eqeuCi_WCjRtSS43Bh0QFZi6xK8rRjItyQRIfBpomETElbng3mAmBLPNb_7CzfsBdhBhJQLKu9KZ__uL3YVGtrCaLcOsfwP7BXRNQJH0yN_JWfMZH3y3B8z1O__xGhR63ugExWJZyUn55KAEiODbX35_PcftWXjslq-wzsK4J2fO_HFNU8Pi4egk6ibvCUDFRUelukaAy_YHdb0VTSB6XCymTo96jK0HGjG8FaVwvQaesaUE-e0_JpdMXN3KstKFeTlDUx1o3Ny93-VxLB5rkOSd6cRjEnFRA7Q6HnturEjwPAeJjR2Ll5dsisVrdjqHMbSfSObkpd2dZ0T3LP4-_ug7qRJF60DJTjTPpx7YxeARzuwiu02TlVW0J0PrdXT8EpISHneKc1VWhtRcdD0R0spuAMzJLwELaOemihL1TJSIMBqFikbpulZCZ1k1kA_5D7I5c7pOF1g4uYBW-gJNTenfC9wYmDJAOCcnwk1W4=', provider_name='openai', ), BuiltinToolCallPart( tool_name='code_execution', args={ 'container_id': 'cntr_68cdc387531c81938b4bee78c36acb820dbd09bdba403548', 'code': """\ import numpy as np\r import matplotlib.pyplot as plt\r import matplotlib.patheffects as pe\r \r # Data\r x_smooth = np.linspace(-5, 5, 501)\r y_smooth = x_smooth**2\r x_int = np.arange(-5, 6, 1)\r y_int = x_int**2\r \r # Futuristic styling parameters\r bg_color = '#0b0f14' # deep space blue-black\r grid_color = '#00bcd4' # cyan\r neon_cyan = '#00e5ff'\r neon_magenta = '#ff2bd6'\r accent = '#8a2be2' # electric purple\r \r plt.style.use('dark_background')\r plt.rcParams.update({\r 'font.family': 'DejaVu Sans Mono',\r 'axes.edgecolor': neon_cyan,\r 'xtick.color': '#a7ffff',\r 'ytick.color': '#a7ffff',\r 'axes.labelcolor': '#a7ffff'\r })\r \r fig, ax = plt.subplots(figsize=(8, 5), dpi=200)\r fig.patch.set_facecolor(bg_color)\r ax.set_facecolor(bg_color)\r \r # Neon glow effect: draw the curve multiple times with increasing linewidth and decreasing alpha\r for lw, alpha in [(12, 0.06), (9, 0.09), (6, 0.14), (4, 0.22)]:\r ax.plot(x_smooth, y_smooth, color=neon_cyan, linewidth=lw, alpha=alpha, solid_capstyle='round')\r \r # Main crisp curve\r ax.plot(x_smooth, y_smooth, color=neon_cyan, linewidth=2.5)\r \r # Glowing integer markers\r ax.scatter(x_int, y_int, s=220, color=neon_magenta, alpha=0.10, zorder=3)\r ax.scatter(x_int, y_int, s=60, color=neon_magenta, edgecolor='white', linewidth=0.6, zorder=4)\r \r # Grid and spines\r ax.grid(True, which='major', linestyle=':', linewidth=0.8, color=grid_color, alpha=0.25)\r for spine in ax.spines.values():\r spine.set_linewidth(1.2)\r \r # Labels and title with subtle glow\r title_text = ax.set_title('y = x^2 • x ∈ [-5, 5]', fontsize=16, color=neon_cyan, pad=12)\r title_text.set_path_effects([pe.withStroke(linewidth=3, foreground=accent, alpha=0.35)])\r \r ax.set_xlabel('x', fontsize=12)\r ax.set_ylabel('y', fontsize=12)\r \r # Ticks\r ax.set_xticks(x_int)\r ax.set_yticks(range(0, 26, 5))\r \r # Subtle techy footer\r footer = ax.text(0.98, -0.15, 'generated • neon-grid',\r transform=ax.transAxes, ha='right', va='top',\r color='#7fdfff', fontsize=9, alpha=0.6)\r footer.set_path_effects([pe.withStroke(linewidth=2, foreground=bg_color, alpha=0.9)])\r \r plt.tight_layout()\r \r # Save and show\r out_path = '/mnt/data/y_equals_x_squared_futuristic.png'\r plt.savefig(out_path, facecolor=fig.get_facecolor(), dpi=200, bbox_inches='tight')\r plt.show()\r \r out_path\ """, }, tool_call_id='ci_68cdc3be6f3481908f64d8f0a71dc6bb0187028ba77f15f7', provider_name='openai', ), FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='81863d', ), id='ci_68cdc3be6f3481908f64d8f0a71dc6bb0187028ba77f15f7', ), BuiltinToolReturnPart( tool_name='code_execution', content={ 'status': 'completed', 'logs': [ """\ /tmp/ipykernel_11/962152713.py:40: UserWarning: You passed a edgecolor/edgecolors ('white') for an unfilled marker ('x'). Matplotlib is ignoring the edgecolor in favor of the facecolor. This behavior may change in the future. ax.scatter(x_int, y_int, s=60, color=neon_magenta, edgecolor='white', linewidth=0.6, zorder=4) """, "'/mnt/data/y_equals_x_squared_futuristic.png'", ], }, tool_call_id='ci_68cdc3be6f3481908f64d8f0a71dc6bb0187028ba77f15f7', timestamp=IsDatetime(), provider_name='openai', ), TextPart( content="""\ I gave the chart a neon, futuristic look with a dark theme, glowing curve, and cyber-style markers and grid. Download the image: [y_equals_x_squared_futuristic.png](sandbox:/mnt/data/y_equals_x_squared_futuristic.png) If you want different colors or a holographic gradient background, tell me your preferred palette.\ """, id='msg_68cdc3d0303c8190b2a86413acbedbe60187028ba77f15f7', ), ], usage=RequestUsage( input_tokens=4614, cache_read_tokens=1792, output_tokens=1844, details={'reasoning_tokens': 1024} ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68cdc39da72481909e0512fef9d646240187028ba77f15f7', finish_reason='stop', ), ] ) async def test_openai_responses_code_execution_return_image_stream(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel( 'gpt-5', provider=OpenAIProvider(api_key=openai_api_key), settings=OpenAIResponsesModelSettings(openai_include_code_execution_outputs=True), ) agent = Agent(model=model, builtin_tools=[CodeExecutionTool()], output_type=BinaryImage) event_parts: list[Any] = [] async with agent.iter(user_prompt='Create a chart of y=x^2 for x=-5 to 5') as agent_run: async for node in agent_run: if Agent.is_model_request_node(node) or Agent.is_call_tools_node(node): async with node.stream(agent_run.ctx) as request_stream: async for event in request_stream: event_parts.append(event) assert agent_run.result is not None assert agent_run.result.output == snapshot( BinaryImage( data=IsBytes(), media_type='image/png', identifier='df0d78', ) ) assert agent_run.result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Create a chart of y=x^2 for x=-5 to 5', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_06c1a26fd89d07f20068dd936ae09c8197b90141e9bf8c36b1', signature=IsStr(), provider_name='openai', ), BuiltinToolCallPart( tool_name='code_execution', args="{\"container_id\":\"cntr_68dd936a4cfc81908bdd4f2a2f542b5c0a0e691ad2bfd833\",\"code\":\"import numpy as np\\r\\nimport matplotlib.pyplot as plt\\r\\n\\r\\n# Data\\r\\nx = np.linspace(-5, 5, 1001)\\r\\ny = x**2\\r\\n\\r\\n# Plot\\r\\nfig, ax = plt.subplots(figsize=(6, 4))\\r\\nax.plot(x, y, label='y = x^2', color='#1f77b4')\\r\\nxi = np.arange(-5, 6)\\r\\nyi = xi**2\\r\\nax.scatter(xi, yi, color='#d62728', s=30, zorder=3, label='integer points')\\r\\n\\r\\nax.set_xlabel('x')\\r\\nax.set_ylabel('y')\\r\\nax.set_title('Parabola y = x^2 for x in [-5, 5]')\\r\\nax.grid(True, alpha=0.3)\\r\\nax.set_xlim(-5, 5)\\r\\nax.set_ylim(0, 26)\\r\\nax.legend()\\r\\n\\r\\nplt.tight_layout()\\r\\n\\r\\n# Save image\\r\\nout_path = '/mnt/data/y_eq_x_squared_plot.png'\\r\\nfig.savefig(out_path, dpi=200)\\r\\n\\r\\nout_path\"}", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7', provider_name='openai', ), FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='df0d78', ), id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7', ), BuiltinToolReturnPart( tool_name='code_execution', content={'status': 'completed', 'logs': ["'/mnt/data/y_eq_x_squared_plot.png'"]}, tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7', timestamp=IsDatetime(), provider_name='openai', ), TextPart( content=IsStr(), id='msg_06c1a26fd89d07f20068dd937ecbd48197bd91dc501bd4a4d4', ), ], usage=RequestUsage(input_tokens=2772, output_tokens=1166, details={'reasoning_tokens': 896}), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_06c1a26fd89d07f20068dd9367869c819788cb28e6f19eff9b', finish_reason='stop', ), ] ) assert event_parts == snapshot( [ PartStartEvent( index=0, part=ThinkingPart( content='', id='rs_06c1a26fd89d07f20068dd936ae09c8197b90141e9bf8c36b1', signature=IsStr(), provider_name='openai', ), ), PartStartEvent( index=1, part=BuiltinToolCallPart( tool_name='code_execution', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7', provider_name='openai', ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='{"container_id":"cntr_68dd936a4cfc81908bdd4f2a2f542b5c0a0e691ad2bfd833","code":"', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7', ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='import', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' numpy', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' as', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' np', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='\\r\\n', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='import', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' matplotlib', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.pyplot', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' as', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' plt', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='\\r\\n\\r\\n', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='#', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' Data', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='\\r\\n', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='x', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' =', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' np', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.linspace', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='(-', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='5', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' ', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='5', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' ', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='100', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='1', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=')\\r\\n', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='y', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' =', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' x', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='**', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='2', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='\\r\\n\\r\\n', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='#', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' Plot', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='\\r\\n', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='fig', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' ax', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' =', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' plt', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.subplots', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='(figsize', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='=(', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='6', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' ', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='4', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='))\\r\\n', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='ax', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.plot', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='(x', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' y', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' label', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta="='", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='y', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' =', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' x', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='^', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='2', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta="',", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' color', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta="='#", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='1', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='f', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='77', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='b', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='4', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta="')\\r\\n", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='xi', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' =', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' np', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.arange', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='(-', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='5', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' ', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='6', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=')\\r\\n', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='yi', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' =', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' xi', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='**', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='2', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='\\r\\n', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='ax', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.scatter', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='(x', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='i', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' yi', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' color', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta="='#", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='d', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='627', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='28', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta="',", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' s', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='=', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='30', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' z', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='order', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='=', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='3', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' label', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta="='", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='integer', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' points', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta="')\\r\\n\\r\\n", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='ax', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.set', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='_xlabel', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta="('", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='x', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta="')\\r\\n", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='ax', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.set', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='_ylabel', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta="('", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='y', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta="')\\r\\n", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='ax', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.set', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='_title', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta="('", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='Par', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='ab', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='ola', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' y', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' =', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' x', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='^', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='2', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' for', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' x', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' in', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' [-', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='5', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' ', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='5', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=']', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta="')\\r\\n", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='ax', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.grid', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='(True', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' alpha', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='=', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='0', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='3', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=')\\r\\n', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='ax', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.set', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='_xlim', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='(-', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='5', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' ', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='5', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=')\\r\\n', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='ax', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.set', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='_ylim', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='(', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='0', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' ', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='26', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=')\\r\\n', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='ax', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.legend', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='()\\r\\n\\r\\n', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='plt', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.tight', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='_layout', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='()\\r\\n\\r\\n', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='#', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' Save', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' image', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='\\r\\n', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='out', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='_path', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' =', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=" '/", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='mnt', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='/data', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='/y', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='_eq', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='_x', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='_squared', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='_plot', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.png', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta="'\\r\\n", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='fig', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='.savefig', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='(out', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='_path', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=',', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=' dpi', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='=', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='200', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta=')\\r\\n\\r\\n', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='out', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='_path', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartDeltaEvent( index=1, delta=ToolCallPartDelta( args_delta='"}', tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7' ), ), PartStartEvent( index=2, part=FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='df0d78', ), id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7', ), ), FinalResultEvent(tool_name=None, tool_call_id=None), PartStartEvent( index=3, part=BuiltinToolReturnPart( tool_name='code_execution', content={'status': 'completed', 'logs': ["'/mnt/data/y_eq_x_squared_plot.png'"]}, tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7', timestamp=IsDatetime(), provider_name='openai', ), ), PartStartEvent( index=4, part=TextPart(content='Here', id='msg_06c1a26fd89d07f20068dd937ecbd48197bd91dc501bd4a4d4') ), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=IsStr())), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' the')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' chart')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' of')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' y')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' =')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' x')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='^')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='2')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' for')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' x')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' from')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' -')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='5')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' to')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' ')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='5')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='.')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' \n')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='Download')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' the')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' image')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=':')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' [')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='Download')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' the')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=' chart')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='](')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='sandbox')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=':/')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='mnt')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='/data')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='/y')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='_eq')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='_x')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='_squared')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='_plot')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta='.png')), PartDeltaEvent(index=4, delta=TextPartDelta(content_delta=')')), BuiltinToolCallEvent( # pyright: ignore[reportDeprecated] part=BuiltinToolCallPart( tool_name='code_execution', args="{\"container_id\":\"cntr_68dd936a4cfc81908bdd4f2a2f542b5c0a0e691ad2bfd833\",\"code\":\"import numpy as np\\r\\nimport matplotlib.pyplot as plt\\r\\n\\r\\n# Data\\r\\nx = np.linspace(-5, 5, 1001)\\r\\ny = x**2\\r\\n\\r\\n# Plot\\r\\nfig, ax = plt.subplots(figsize=(6, 4))\\r\\nax.plot(x, y, label='y = x^2', color='#1f77b4')\\r\\nxi = np.arange(-5, 6)\\r\\nyi = xi**2\\r\\nax.scatter(xi, yi, color='#d62728', s=30, zorder=3, label='integer points')\\r\\n\\r\\nax.set_xlabel('x')\\r\\nax.set_ylabel('y')\\r\\nax.set_title('Parabola y = x^2 for x in [-5, 5]')\\r\\nax.grid(True, alpha=0.3)\\r\\nax.set_xlim(-5, 5)\\r\\nax.set_ylim(0, 26)\\r\\nax.legend()\\r\\n\\r\\nplt.tight_layout()\\r\\n\\r\\n# Save image\\r\\nout_path = '/mnt/data/y_eq_x_squared_plot.png'\\r\\nfig.savefig(out_path, dpi=200)\\r\\n\\r\\nout_path\"}", tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7', provider_name='openai', ) ), BuiltinToolResultEvent( # pyright: ignore[reportDeprecated] result=BuiltinToolReturnPart( tool_name='code_execution', content={'status': 'completed', 'logs': ["'/mnt/data/y_eq_x_squared_plot.png'"]}, tool_call_id='ci_06c1a26fd89d07f20068dd937636948197b6c45865da36d8f7', timestamp=IsDatetime(), provider_name='openai', ) ), ] ) async def test_openai_responses_image_generation(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model, output_type=BinaryImage) result = await agent.run('Generate an image of an axolotl.') messages = result.all_messages() assert result.output == snapshot( BinaryImage( data=IsBytes(), media_type='image/png', identifier='68b13f', ) ) assert messages == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Generate an image of an axolotl.', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_68cdc3d72da88191a5af3bc08ac54aad08537600f5445fc6', signature=IsStr(), provider_name='openai', ), BuiltinToolCallPart( tool_name='image_generation', tool_call_id='ig_68cdc3ed36dc8191b543d16151961f8e08537600f5445fc6', provider_name='openai', ), FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='68b13f', ), id='ig_68cdc3ed36dc8191b543d16151961f8e08537600f5445fc6', ), BuiltinToolReturnPart( tool_name='image_generation', content={ 'status': 'completed', 'background': 'opaque', 'quality': 'high', 'size': '1536x1024', 'revised_prompt': IsStr(), }, tool_call_id='ig_68cdc3ed36dc8191b543d16151961f8e08537600f5445fc6', timestamp=IsDatetime(), provider_name='openai', ), TextPart(content='', id='msg_68cdc42eae2c81918eeacdbceb60d7fa08537600f5445fc6'), ], usage=RequestUsage( input_tokens=2746, cache_read_tokens=1664, output_tokens=1106, details={'reasoning_tokens': 960}, ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id=IsStr(), finish_reason='stop', ), ] ) result = await agent.run('Now give it a sombrero.', message_history=messages) assert result.output == snapshot( BinaryImage( data=IsBytes(), media_type='image/png', identifier='2b4fea', ) ) assert result.new_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Now give it a sombrero.', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_68cdc4311c948191a7fb4cb3e04f12f508537600f5445fc6', signature=IsStr(), provider_name='openai', ), BuiltinToolCallPart( tool_name='image_generation', tool_call_id='ig_68cdc46a3bc881919771488b1795a68908537600f5445fc6', provider_name='openai', ), FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='2b4fea', ), id='ig_68cdc46a3bc881919771488b1795a68908537600f5445fc6', ), BuiltinToolReturnPart( tool_name='image_generation', content={ 'status': 'completed', 'background': 'opaque', 'quality': 'high', 'size': '1536x1024', 'revised_prompt': IsStr(), }, tool_call_id='ig_68cdc46a3bc881919771488b1795a68908537600f5445fc6', timestamp=IsDatetime(), provider_name='openai', ), TextPart(content='', id='msg_68cdc4c5951c8191ace8044f1e89571508537600f5445fc6'), ], usage=RequestUsage( input_tokens=2804, cache_read_tokens=1280, output_tokens=792, details={'reasoning_tokens': 576}, ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id=IsStr(), finish_reason='stop', ), ] ) async def test_openai_responses_image_generation_stream(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model, output_type=BinaryImage) async with agent.run_stream('Generate an image of an axolotl') as result: assert await result.get_output() == snapshot( BinaryImage( data=IsBytes(), media_type='image/png', identifier='be46a2', ) ) event_parts: list[Any] = [] async with agent.iter(user_prompt='Generate an image of an axolotl.') as agent_run: async for node in agent_run: if Agent.is_model_request_node(node) or Agent.is_call_tools_node(node): async with node.stream(agent_run.ctx) as request_stream: async for event in request_stream: event_parts.append(event) assert agent_run.result is not None assert agent_run.result.output == snapshot( BinaryImage( data=IsBytes(), media_type='image/png', identifier='69eaa4', ) ) assert agent_run.result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Generate an image of an axolotl.', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_00d13c4dbac420df0068dd91a321d8819faab4a11031f79355', signature=IsStr(), provider_name='openai', ), BuiltinToolCallPart( tool_name='image_generation', tool_call_id='ig_00d13c4dbac420df0068dd91af3070819f86da82a11b9239c2', provider_name='openai', ), FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='69eaa4', ), id='ig_00d13c4dbac420df0068dd91af3070819f86da82a11b9239c2', ), BuiltinToolReturnPart( tool_name='image_generation', content={ 'status': 'completed', 'background': 'opaque', 'quality': 'high', 'size': '1024x1536', 'revised_prompt': IsStr(), }, tool_call_id='ig_00d13c4dbac420df0068dd91af3070819f86da82a11b9239c2', timestamp=IsDatetime(), provider_name='openai', ), ], usage=RequestUsage( input_tokens=1588, output_tokens=1114, details={'reasoning_tokens': 960}, ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id=IsStr(), finish_reason='stop', ), ] ) assert event_parts == snapshot( [ PartStartEvent( index=0, part=ThinkingPart( content='', id='rs_00d13c4dbac420df0068dd91a321d8819faab4a11031f79355', signature=IsStr(), provider_name='openai', ), ), PartStartEvent( index=1, part=BuiltinToolCallPart( tool_name='image_generation', tool_call_id='ig_00d13c4dbac420df0068dd91af3070819f86da82a11b9239c2', provider_name='openai', ), ), PartStartEvent( index=2, part=FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='69eaa4', ), id='ig_00d13c4dbac420df0068dd91af3070819f86da82a11b9239c2', ), ), FinalResultEvent(tool_name=None, tool_call_id=None), PartStartEvent( index=2, part=FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='69eaa4', ), id='ig_00d13c4dbac420df0068dd91af3070819f86da82a11b9239c2', ), ), PartStartEvent( index=3, part=BuiltinToolReturnPart( tool_name='image_generation', content={ 'status': 'completed', 'background': 'opaque', 'quality': 'high', 'size': '1024x1536', 'revised_prompt': IsStr(), }, tool_call_id='ig_00d13c4dbac420df0068dd91af3070819f86da82a11b9239c2', timestamp=IsDatetime(), provider_name='openai', ), ), BuiltinToolCallEvent( # pyright: ignore[reportDeprecated] part=BuiltinToolCallPart( tool_name='image_generation', tool_call_id='ig_00d13c4dbac420df0068dd91af3070819f86da82a11b9239c2', provider_name='openai', ) ), BuiltinToolResultEvent( # pyright: ignore[reportDeprecated] result=BuiltinToolReturnPart( tool_name='image_generation', content={ 'status': 'completed', 'background': 'opaque', 'quality': 'high', 'size': '1024x1536', 'revised_prompt': IsStr(), }, tool_call_id='ig_00d13c4dbac420df0068dd91af3070819f86da82a11b9239c2', timestamp=IsDatetime(), provider_name='openai', ) ), ] ) async def test_openai_responses_image_generation_tool_without_image_output( allow_model_requests: None, openai_api_key: str ): model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model, builtin_tools=[ImageGenerationTool()]) with capture_run_messages() as messages: with pytest.raises( UnexpectedModelBehavior, match=re.escape('Exceeded maximum retries (1) for output validation') ): await agent.run('Generate an image of an axolotl.') assert messages == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Generate an image of an axolotl.', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_68cdec207364819f94cc61029ed4e1d2079003437d26d0c0', signature='gAAAAABozexg98F3au1443vbazt85gDycVpBeC63gC3bUrFg_jpx3BYCksfaKwRkdFirkKpRHBYG1go0Kbzl_1w7ZqwT-BcPYX1Q7a--X9S-5OvU43ikr2kPbJgGhjWv1W37aLPKfIFOvt0VspdWlN3Diq6u67ktR0R0BXOFuSSv7WQmRAIl2JxiDzquSCb12Uc6i61LxNLpzalYk9lyW4Nm5c4czAsbUNv22AeTsB-nwWzO9NJyPfe6cVybz5gdShl8lKIvBsjHMonyiZqqzuSZakXSlbteA8yvZmOYO9XT1ruXNhCoFnq4pNuMHiZuOyCSIvASPUebLO9Q9uMv-t2aKku_4Xg4VsNUuQQpJfZ_gqYJyZFmANBTAcbMGBVotJS0V0ZkO9kyM9W99udKPuS-IzAkPCiHuBsjMaQzhM9xA2-uNm169O4P6TfqD65iCYAMLvwZbXauC6etI17If_731Oo0k4qcR5G7vruSd_Om-vwAGmb0u3_FNcI73bNw4WkhfGdUucfquaGIBkSm2_H63SOfLHOiLsnLIZT1QkEm2k2LP6O57WHAE3H1Rd1nKkw7GQcY-oQlF9_AGi_okM_nCNf7RXzfEocRYXlkSwoJT67TGV_rp1aSzhxKgzOzntDlcOT4FdyVY_0MMtxnBANZL2mBM8nvmqogWOnrJui-7qmFYP6DJj-GkoqPhi_gXlb9gTHtus_lQtLvJSXFhDlQDT40dPbU6T716Bp1TRQSAtj5s4aIhEupcAyoza4Vzko9WF0lrwyTKeU0Yh2nkrieKNqL9XbhknW9bp8dRMRM5-cG4WZHWgD5nLV4EP-8xcZc0ApwBLebiUhkX3MZ7phpS_ZpwnHxO8GDnvuPNT6pXbvvrUL-Vitwe-qWoodziaUetUcopfpGlBYnZb6_cJOVFUoJDxPxgOkLiUW0WSSe-NsU0XllTG75sVx6cciU7LbDJjkPU3yLOrJcwpE81Khsefm-yyk4BOMzPbhJKg9Lrs9pZmuhXa0-GdMP6fHks4UKYeR5pX7zTU36t4BUYFssq-p8QqSuXah64S50W644yvaJR52PzkjDhNtl_lBbLRsVvlimUz2vGuJfFrATSnw-pkuGEDznc5BfdjqNDxncVWpwu0u2HnfAXbzBBtgNFVvWUegjRhBAwqrlWdjhvTcfzp2xUAoaXcQdRmZUh9Cw1Ib3pvejHk8l56i2Gf5X0VrDVxj2av3LugJ0sDgahri96q_EfYVD6TEF5D1lz-GBFTWJ3CZgdICN1HM2ny8yNg60U7EWFNqN3Rn9wx1LnntWcKxmwLRfTWFr3k3-TTHGam9Nw41T8hSkpGmpDYM2LsOcqdGa6ZYlFEBstzvf8JmPtBxIlD-nFIAVLo0Y4lFmt29x8hi56Ybu3_xdwY63SMj0rydOF0bX1K1QXcIJrSY4joCesFCJ05vB9F39HNByztFA3cBvyZkwzpmif9juYOpM2qfZVtG8oCnaBU90u7lkIvfgRd2H8lH0pnVTLjSq885mjhxRad1pnD-0rIoPY7ppz-quELsMOVqNTZWW8mkCy6uKiWna-3m0THLNz0CNFCnIz5ZTmchoj0x1WewlSamGL6n_SnB0H_lIXq9RUZlwrd1ASQtiOnI94pBRHPXfQ3a4PfNyeZv9GOKHr4pR0uHATkCd-rldmWQ5kG6MbNjNMJChaCMuSwrJiBondTeGIZswsMwOfV5eHgoZwfzkTxD3xo91CLGsE77IDjp05mNYc_KMbEqSmnDWpPJzsHWAX5vahfVXsRFx1Jjw-D4d5PIU_Mx4mwjPLjTrWkd5Hl2uKWvjw0Hb55lHT8D3cGlvIjRnTGM6ndLGndeKjXobs0NBcmgDQNLpHMccHAbb2UVIdvx8cF3zhkc6FdKJ17TZGJQbzWSqkkKwNUCYuRrf6CeHoEZh2ErArmcj57QVdXeDREoSzHhu1XRBfgc-ey4WF2RMzJ47Y0LNxFHpLxEk4Tpg4jcMvfRRKv-8tIu5kZeVSBqZTac90ly9qDeb32mv131YXy9G1A4RCLhjCoxM9M5r8a3AnDIvoMCusPxAM5mHpLEdv8A_5mliza9hztzmDKIQq7sQAow_XafhRJfX0dOeOft6aLkLTaq3KHN1HE0xy9Fupg5ut_AUd8tIvst7Av6vHPiK7gR-rxgWNx2FmKKXhvcWqMeeqFwSyq_18Y4w3ibPc-l-oYXD5gEMAaXGa6WgyaeNBSHNup7HDYlm_WLK3UdH-5IuIMxkhLFgDFED7g9lFl5V0I4bmW8Vqg0AqmNC2hkADsr7mNjuYr3NOzGCTsE2Ed992VG_e3k2PqtHVegZ41jxZTbfqYRM_HYg2rOdnzNN_NV3w0hpKmV-F6UIrb8Sfpscdwa2kz9Zz2huG_QGzI6AyjoepNgOYYZ_Phq4JMtrjge8HcOGRR3z8_hV21N61o5Z9yBfwx5kSnAvPXuAgeuh2MIfB_koOrwbEryE4HJTSA9b2IAs3BS9cvAu36VHVYP7Cj-U3EZxaxRIqusjNHb3WIzswa4AXFfjK65aaCCizHwxTSdn53nlSe_f7y9pMnOV3o467Vtt-oR9dqz92pauT1MxXYdBD8o0q7iOgHsqdcHBDvQmWOlpag9W1sF5uEyzA9bxDGlKLA9xtvfwnC2Y3nv9i-haFaoknx8eQGsM_bzWC54o6VlhJiNeeRUuTNEAsoTXv13usbK6MtSXoGvWPNDkj0CJ4sluSWmOidGG6DW0bEj58HYCedg71EKyNcrxcN7JJFklv1ju6IVY4k6pLMPu6kbYdKzXaxFWkOmB27Qz0dgBbK7hHhHagJWjOKrHWNiOphce9SHf9xQP2U0uJRNKqNnqmKRZLBQ-QcwRUxzaFrDByG7nRV0ybRHpJvrRfCjq-FVF0b8JXudNY3D2gI4p7WJeBqk84bt5a00DzmTZap1cEYi8VYs6zwFRa-LTemxgq8jOaeR33x8I8tDBbnqJdOV_o88Mek2E0mXkKfl_3ZzPzajcjyNHYdfhNHfcB0Oeyk6w_TXnVxOJVHuoYUsXuB4gDDMENk2yubSUFjOUzuZhXXZ4CdE4bymK54tzj9qATV0c7k-YsRlfUk5fX0JRQF6iMMWl0VtVgi3HolN7S5K4Tbs9tB0ByOS5H5N0D2BjlDl-kmd9Yrn6-B7Dxz2rxCtj_TQneCyMzfb6edt8X17c-iLsOV-fZOP3mFTCcnI6HyMxaLQDENgPF12gW3mDZyX2gAd7iRFXCHzmTnVkUEBhlCoIbq5Dc5s0niA3Jq9MHvhtgcXaUusGqCxOtQ22_CWixDntwS3hQx1KxEUzYZxThNSv-f5ji56iiWOB9uVzv6XLPdGYkN5CgdKzqPsim6VWfz52q2TTSZFRuaMGZsJuEpprdcWpHcHiBZsk3Qa-giYazywLHxj3Ph_Kf7kByYuzspVpGX3bct_unkM8jQzg8AWkn0LuFIY8ScyzXAVECJbFiOv4HipzyoyYcpDiPmadV-qAG8ghpw90xwcvgrGnHm5pzHQaqZVPKWXrHnkaJFgQ7OyEpmX-U52R5t4PZCeWJA90zAnvmL7s5MFEDLzSlzXPFjzUo3T8XWz6p6tUksLsGdUUqILT7hYdWwCdDnUJYZvjysEVIkNPNx3lAGW_e82KYUZUjQqiQqsbu1meJkdZdvMPmOlVEGx9oFvTW8cZrZZfJ1EKNOPR_1eyGdh5ZOfxGU2sogpOST3U6dxdeUwpEdhl1dTaZA_chepczFdHI7aMoKSISbpNC7nNhKNfQIpBcwPLtAhlgCOQKuBRMJUPK7VcOpl_nhz3FKexgJ0X_hFqN5qygPtKITZ_Et5ME9k5tzelHVAiosKhWOLngFJzKZkYFavSYUOHemVmUo7licjeUTPAb0d6kKbqqrJ44ZP22gL-Rw0YZa7t0VM7LrD4jD_taPhqmZ28CCchPAfP6Umo6txaiXDusvPG7v-zUGh4XWQlV_5SBSQwvPHUfQHlogHH69jxfJYRD3F-lDIfKR9ta8RuCuCdd2VsBUUAWFaRuulGcLiQ1BFWZ2Fx7W6rXgW8QkufqX9sp0zgTK9fCPN0rPLLU27BUwn0EB3EZe4bDBYrm9xAxYCgoOOE28GMpZsznXXIVaAXvUGVTBnXks9ycNghOw35fsAniH64H8u7Yp45JH8BMb7sk4zHcW_An1TzmUxjq3_JdOo9kkzNEu_qs0Y9btf4M6NajoVWlttXT2RD8XPxIrASjFMv8fxYJG0OsVHJoKTnGFlHqy13dIDMtfOkT658EuGe_pHwp8B1zI1jjpPmMW2MG3TAlumFgy9T0iyw0V3dp6qCZCjavMPIJ2HD9V9TJYueufIptuN1_hZF-xESc1ENH6z_NtMBJmW0hwCU9a6UqZ-K3_ZsJ7EK7q06V53KOSzzaJUY7SgUAFgwfbqFpvqi8emyHMxxIFylw_E1iauYGssBb_tzY1fTWwk9n4h4A9bdKesz_JBNRuKmKyOeYOS2LdJGhp9VOsbTvJtJ3MvwXuiH9rgFTXzXbDgIHxSUnUkMo4mJhnWXiqENnfqc_oOgx6zkicwwX05Bjn_k4nj800fT4RkJTY81dXy54TbvqBgPR--nTkq-WJD0e8_9hjOrtD7c7_p08FhVGWl_d499ylunVccNQ51zfeP0uGt8uYK-S9fNN8ED5PJ5iBycLRU0uvyFdsZFS0DJ4N96xSrdkdPAZ5CjfIn4bawnCs8MrHg47sCgONAqrZ1WZTgyL8j8J0kdfVJTZoLRud4oFmM4t8nQsL1sxH322EWVaXsy9aWAMVWGcc2fesk4jVODZ4mfGtnvm-Q8ifjV7wqRa7s5uXv_-JFUawxNvHqMw2AvG1M0RJTIEnRkCKB_8CXNb4K-GRw12XtZs1KRED6j1yPzLwabcWNl2BpR9JCBmogxFFuPPLdevD2JWptQ3YwTQSIMridFriwY8g31iFMFrNub9Z356Vc9zyMvZ0sRBB4oK6iSy8Y39nU3512YdGpDmMTH-T5Cxy3pi1dphlbYHcar1Yl-n5gSS0_dezGILZbxfvGbxOAIL-AGwSE4JJpUFn6N0xRclaNTPDk9VkKpVktgJeWqkWFI1xdBUp0K9BQdNs6XsJsfMCaIE-ed9SbQpJRdc1S7m6lFKFZFvHujK1zplJemcpOrYIpsuTD8wzWJAxzWwtUoo0DXi0YQOrnFdo9PbcTscUGyNArCcGjOYiL5_oMwhJh5kg5L_OPLH3UhiLI_aHs4gT7nX__HHm_3GVOov7-kK_Rs5lGsZtFQ-yoau74FnzVn8N3YWMqWzCVbwGRBhvAm_fdI53h77CZeJm9yWZkWTzrc0Ua2HqA7KB-eZgCNx9Ox9n0Ilh42hdGLFSwOEF1oEHw63x4ZTENyAP7j7mHWnyVbqRVSZOlP6w8JquYAtS9hUJQb8GZs2MFuFcwTO8SX8gMWWVM3tGtpnz7UwqhcFMZHrJ0ehues8kdtrlqR2BWPYAquFhOQebvqhlYxieuLggwAIxudJr3PFYJrAgAxivKZlhKRSoa1HCFSp_4k_kuVp5AvfBMViLJ39pi_xHX8PnokEmi3_GZiz31hGjj1GgNg8HZCkQtQJcOjMA3YPE3kQHy76YIdxzL59EdWsfuHj9IhJ4J_PoHTg5k683yXkvcXsz_sOYj9j6eMNn3Krp-ZFmWbtmqpWuvKS7vmE2Wtq9RmzvkGPC0jeY6J_ndbyCCljLpFGbvSYC50ejEulcMSUw1ypHhHzoDzO1jFo1xBDfta1H_hAsLkmYKOseTZce6hHIZR5xUwWStmu0y3OoOeVT3cZXEErr7qPLxEzB6nTlSgzLRX-ncRCnnUy0f_pXWwBE9dE6w1Nq4Y9BuS2Ip9oZZvj-gRCxTmmJLL8RYd-G9EeiBSlf09kezq4plUsJwvvPqVlj5CVLk6DkEsTvAM5r8DK3FYnLUgf7hQI_EZ8P9VN_rrPTPa25y19MR1-XIsVGLrVPmyXcj_w6XLBxEc1J8qQ37NZCw_DRfS0_ZUUqSDNlIy-y-DsdLIVtXE-BzpUkgqx5ADmbsiFFj87rS7wE5Yi2-btSpkWdTjaBbsWBgN3sOvcZgFt-AQrCK8BMLENwFrkFicExianGcwm55IlO2iUvCNjz84ogzU0IYhzDbHGCZBzYaLNX4JIVeonOoQuKA6QGueCffX1MKQ8fDKVZQc11Pr9rwjPNR3xxAs0G4ykW0c3809YE60dLbP-AZ8Qm6vxvAmTzd3XlMFaC-KbBxskXtMJRJqxUd5jYx-YQMQiOA8wLytP8INXSHi2_lgMI8QivRHoKx4oAl-qTx_qz0Ut4iw192OVWoJqTjhwIE_NB1Um9GawsbM9gb8VgI69RTPmQi9obao9kkQEUU-NrNtDkumrltR9Q9fXFyRbKn5Hs0PHzC2yiRFa_IqGEqJeqz2CSBkdC5GauukZj2XumrXKKCIYV2vJ-42D6MUqD138clb-prSiOe4dA2-wrKPjaaWdpaMeAbLXbLkHuH4K5h6HOpYIVMu_JWdnzzDnvye0o8A8vrxFZsOSDeiHPcoDyN6-6KYQwOlKpjiswFVdoD_e3Aw9ge6YHDOggsKeyERzv46Hc2GwW_GWrwaWgXSv-lePsj94L1b17WG_y4oEKbNMAmE4A4EBH1aJI6_wEeySONFKhbyOIwUBcRKCoKT40dbGie7kW23rrzSTQHpjdd4NbAbNAGEtbAJbVwZbFC2RMwMWQbz8mmnMSdVw0VN6UVaCdUatYzATx-gk-lg_8ikyOhMwA_lXFI9pfnHIIqGmKHDJdrE4pdDBK5wVLB1H_CYqzUneygueeTUc_rHiMj7QdekTGh4KnA2lurqXemNemePYl621G_FqimReuPlTPmn88h-DvnmcVhTJEMCT2O6huU2_6yOlyulJw-mq6KMS_b3PSB3bgYmJEH7EM7ljv7lu0ZIqZm9xbpVTntP2s9jDBPMb95q8AnllIwH6uZEYdyiIDU9NQj9RIlR4RZ8Oi5b6n2IuKojvP6aK47npwKMvC4IOAMmGaE3_S2X0vFnpT1djiFPAjvklOEA8o0k91YV_z-QbWwVTd5fdRgaqXcqb3dLAuvnFq0bOpJMchlL9lrC02JW07Xi9Lw4EIoDsPBRr5s5DWLG8kLfpEv-YNZatryAbjbwMtJX0O9aNxLzG1bzyXVFwBb_HUgkotdbmlT7cXMMX8D4_xIQcDyjwo925uAVU3va121ddHt2JasKJc1vMyuOKXuDg5F3dYByqEQQH8zywgBi_IRtUx8aXNoNXobUf3LGaLc-3HqVTZby9Xv_Axm-s5jSqcEPL4WJX60rY28qx_lmajcmcVLY7irKovGmfEIlVeHYdMxDxZue2nHHHc7NmF7dGORg870x5iGUcqtmjvOx-NIqVShVQlalGOdIF3_u6r8xlvOL8xWJ6WLXKNaAFVtaoDdObEoR3stpG8iaaaGNcrRqIH7J86ntBUmQ8chIgOOvPz81W0Op5jbSc4d2e_qAAuvt6j_qElh9qsGNMVPoY9DlxqqrlJ3ojG_6yqlX_jP6NGSx31vxc-IgggbyeEm2BVt1v3dJv_Z1Kmt8PGa3--atQsH3cemYMbWcwX2mAdMCHLY7xQJs_X9OgDaPd25bGPHFJQVNM4cypyPSWXEDiR-xIqkB7NzTrSEGf82wSgIPRAo7k-CBpbBVvsuLre4zof8K5u7QH2jYFQA0-9YtDa_Uyc_JcErLU7AroB5ZZr7s_s9qx5w_wJxMNW1NLZJdOKUVryP6DJPqTNmly3PT88GaPUDdrcQa7NplSF1FcqFmzOlZc1Se_fSkgEcFKrX9M7_65bTgLbAvj-8bCTIxZp0-PcmoQO4mrkNkW2Vr1rfSuOH5_vqJCT7s9A-H77RjLseMxJ27YF_dEXOHjsEV0DPM_zfno9_Lb6gL0rqffxhKdM_xRhSsLg47PJlCgoZkL2xVTJfahwydAzbr4ZWbZ84WwprOimGLJBdcQgjHEhxx0_cT9tFpUKkUbpAlUYqm1e23JGUXKrS9kBqM68RjcBAiaAgeKMx_5pNU4RzuJqCARPYgqhsy50LxkN6DgIMiDglLxho4wUYHVVkez3XXPHmO8FJcRuuk85Z-7qDeExR-Dp8vHkAvSGuyuUKHdyaQdhigMm18qFzu5-L_m3-C7xEblO7KJBDtK9mDdaviyLU9bQA4i7lLgUUdkCClPjm7yDt3SgjDZKXpBeD_HEb134vjhc6EVJN0IK0bf-lSswaAPJYcGc9ArU_mch_F1w0X1ISwvFHWKLYBM1bUSCr7vLyX-j-sbwroVSJ53bTedlaUpoVhEjKxcksjSgnndvAeeHAwHV-HCkOH_zqhxp5aTO1vNXeNESG7WoSRLE1_6vF7ZzTGmpG3GIbuBexi0BUe95UwrAJpdtzWMrAiRNQ3LlB8JkPIqX_ZXmHsu1bo84_x1u-VWQZFNTOitRXyLdA9GtDqg2q7RUJLj1Axq6CzjcewoW380K7r95Kimr6RDUUkvi85SjekZuV8NNd328heZWNSdov9lzmJlCokX6N5VDpg-NIPvjJyaQtf6YZfYtOk7pp_koGxatbsxZTSVh_DwXz7K8VfC2mEhr_xdDPe9nKAPrU4r_J9zdtAkkzdJssMWhSCMTj8z3l1bbIzMt05ivwEGLZYqZ5Sy2-duQVd1wA0NfKB2HjfgSyYhX5wN4aDW15copsEtPTrxCLidwc75rLdoi5Ch1Jt74v5UzKh8mxDaGqjdWeHkDrHbVy5hDVk00n1TZ5UAzWCq3lge3717y0ECZX992BrkqjffUYe0dZUUJr_3GWKSS0AZHg5uI-1Tka_DGqF7mWwdz7XpafzU4siolRkGa3QYmB8LWqdbAnpvte-uSwxAiQm2LiFF9h4dOO8U_2gNsniQViwLkD0KTHnuk1_N94P6QsypEL2bcPWCvCw1SgMmgKBaXYpP8FIN1trlpqyk_0abqnq9GoeCI2AjAOkHI0LnNsM8lTwWNqh1b8YVco3or8J4dOPeVQ=', provider_name='openai', ), BuiltinToolCallPart( tool_name='image_generation', tool_call_id='ig_68cdec307db4819fbc6af5c42bc6f373079003437d26d0c0', provider_name='openai', ), FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='c51b7b', ), id='ig_68cdec307db4819fbc6af5c42bc6f373079003437d26d0c0', ), BuiltinToolReturnPart( tool_name='image_generation', content={ 'status': 'completed', 'background': 'opaque', 'quality': 'high', 'size': '1024x1024', 'revised_prompt': IsStr(), }, tool_call_id='ig_68cdec307db4819fbc6af5c42bc6f373079003437d26d0c0', timestamp=IsDatetime(), provider_name='openai', ), TextPart(content='', id='msg_68cdec605234819fab332bfc0ba35a5d079003437d26d0c0'), ], usage=RequestUsage( input_tokens=2799, cache_read_tokens=2048, output_tokens=1390, details={'reasoning_tokens': 1216} ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68cdec1f3290819f99d9caba8703b251079003437d26d0c0', finish_reason='stop', ), ModelRequest( parts=[ RetryPromptPart( content='Please return text or call a tool.', tool_call_id=IsStr(), timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_68cdec62725c819f92668a905ed1738d079003437d26d0c0', signature='gAAAAABozey1vHMbs_Q2Ou1f-stI__3zJS-qTasRefyc_eyOxqogM8UGbPpL8D6PLFHcypshJpa9SQli-qZRIyG4ioUDLsKpBwFbfjdIhps667-8st03DRTRP0ms2izupS0ae6QqY9qrsPSchrSF2o2PlJOWKZAFJ609S0hGX8VDtrU8nESfp78NQ5HgpgXksXQTxk3_xRmXES2AThlUD0LYykoVKRX-xOyPQsOK7aDEs1CIk3lG1meiXdtJxP1Jm9JQGLWk6kePWUgwnAs818LMVvjcj8GWzFjxKUQlI3S855vYngivkMqYqh4gOcDRGRWej4NRzRmhOK-2yrATl26qnpRwNA1YXkFtn1ojxEkXD99P8RIXNItH4KW19ALs7ZizQmQlKzd96eyPT16OSLqEIfHAXWEKwoB2vTM2ExvHK4il76X9XmgRDy_CI3HAPI-7M3787MJBEY3z9cBe2sIS_GtSk12_GXRBUREhu8wcc4920FxkufYegHd3FzKxBRjyxGpR-jLyI24ahOZRKvoXi4-n1v4umoD5OSMjYpMtr0ykwIBQyyqldi9KqHBpJCzB0wA3JyAn-4JvQsXwIeeAtq3bNSJFaaf9aLJ5OwMO9I6IIWGxoQ1mzqmCs5cVwwjeJLzEc0T5g2qWJdXxdYmjesvMj3pJtgIq3iR2105LydhUiKE-0VLVAQGg-lnjkCtj-muEqlko2_FCHQ7b_hA0VkOUIKOYUDHRtwgtaeNnUpiWk8L7GnBNHtVQ7_kHEGj00UIVC4CKiJqESXS1om73Xt1K1-bglZLfSKfjrAd6E3W51cKQXM7KOfmpRwP-9DThdeOBgjlmMFveru6NYl2ntiu7GF8JJAvjebF3Q6SR4AtFSp8zrZVjlduW3hzQtKaROHLBVgH1KaMST-Nfnkn4AHCbhYNGSZxg4J8M3hh-BLba-lM7o9d0cHsHSORXeuAg40qioVCZNCtIooo6fAdWSAULw-uGdAbRbrJq5nE-w_Lilyeb2mWnMwMbKBHjQO7Kwe92UHvve46vMkiSSX-wZYwthfbO9BM6_ha5BJOtwNggKuBXxqMVizL8WKdvdTVwzP1guDvuVgVoCYKl340jB_EE2V-L-YzbSdaxHi09Gi6E10MgdaSGhNqUJMZWXrezkT6pyRYYRIWhaaImIuQf6JybMUH5hHH8DDEKvofLnQmgPVccU6womuYosIgLOLPOetK6OEFlMsQPBn95hb6jY5vETMyhiVYAVxaeXgk5WA-NdYQ-F2q4kQQS6Ku858AaO9rXMYpkaJ0nIubIbdgQMaXzq6ha5Z0BaxrJhxCDqmHXA5-INBBqWDw0AgJcAlMM_a5ShZA4zVWu4ydzikq8PlnATLbFzOkL8WBhJGRyveKaSyknPfPCBvXu_1l-hwAyvFv2dWWBloD_IIJ3ID_qtjgT7epwC88qmQd5ICPMMdx4DjEu72hU-rTIz30ks970qi_dKVbgpsLAJbHeCCWXBJzJ3UKrC6sc7Kj3rhtelPNEJqFyuB_EJOVX4o7R0AZvkk3wWs3IZ2nE9TeuYckw-hHg35YsC43QSrbIZUbfonaN57ZbwyrnEwnhH3oYXaMiPqqywH0CsZYrO0QLuAeGJTknlpWHgLEVmz39-e3UZFb6WIGIfSFaZHAFpmQBiPjae-qudcbvvfmAgBHqt-Aq4D_06ySnELOtDWlFusZcmHQwG9b0OCDXt6KRTR_-49uuoPCoXlv2nKb2eFhXp1gp6m6WsH21XNaeLU4RF4PR6oRUh-TCLzyBtwCscukF_3gBvcTdwJ4io0Fu6YVtEJux_Ec1vCaQHlUVGtZR7JDVyE5lu1y-aZx0u4s6HheF0bHLYaFgqgOmaNNWwK_jldqp99ZhU7Qat8GcG8YLLEJ04WDIp6_i_Ri7OUf5xgTEkAxS9gOxeJ1EMKR2oB0pf7YJ18XkNqeA7zxXmufJNIbEmXOC3XQKiDY9-2UzTyqjzdZ4V2naUggs7DjAAntcHhVFLGOZgGeQ5FLJ9jfzFlpE8mAg95ZtVvPzYBNFaPoTynqUlukCH4eje_62w_u2TruBMSU3cOV5IqVTLMHu2uwxHWdA1zrVi32LMv8FEYZ8nPyyk_BdapV-SRGQKn1yjGml__I5ksVlqNWVC3BX4hkIxH9K1bO6HjWP2-cdRtTYtRNcOOGOZZv5RtKfpvzjIK5o6d45KDK-jp39_cY9Veyawzc4XwT7jkyL8U0YNsRTEjafcPONK7yWasrOIzNuUppBFdMyER_R8Q1bTMQp1sE-NoAN-0MqupZe1jltzga6i6KLWuOXtMm1_DeHHH3OPNq-kfVs19gbQD13R9kMNjgu8FbAWdoVreG24tKUVSf2nWKReXwxc3WiiODaYTew2ynZ3BUchm3eKebybh4lKoYCw6lLoclnD7smFkP4-72RfaTylVe_npaWU_kWIhxItYosjWGc_ScJhLFdwAOUaNijGNX0TmeMb3uaESw23E3Y0M2pAC_wVkaHvJEYv_nYebwYc6yON5oMFAnOmqaJ14d-LfhuATtTrqD8fGXTPi73rpN5IpA3fVklkyUuu0GWqvsRujNnEcN2nL43LPRwFvwYSeL_tXJoTpTxdgkwjEg4dJr6hImPIwk6Yu_a159LyNKIeZOSZbHi0gao7OeDiSM2_1zb_srjUXgiVPJ26r3GCz07dhcwqUS8lU6nx5q1ncCt9mjTgUG0qmVPzDjfRmeqOU1gPZhh2XQeiXp2AWB-_9M9vu2EiSeOO2gfYKeaFjVhBLbjOeKs9r0xt5JXpdx5IDB1JOfK_MSlKwjl2kOlNo7p3e7RIVB38MQoih95hSz5E6EyOoH2O6KAXLM3qhgcmXe-XJwQKOkA8rPRclgvN-hLSopl6mDGqg7dNKXZB6SQspQPiB4mx91Wwt62aMqWa7Ve-thQ6-oCq9IQTLT34xpCOpHWz4b8kSfr-WDg9cTDdvYIGEDGj_XlE6CK5PuxzezWGYvYggwVJC_65zkGHFBURkBCRHc7otAyxMTKMCTKZnYWUdUEGpTCBonYFPOlh_ApDPnh1h3feF1x8AEIoVkq_ADRKhKbs28y44LQGp9pe49LdsgKN7YT8_azHknz5frvCUQJu8aiP_TaFCAiZhUc0JSATHPv3q6ZsNoUzF8ZfeSWuI3ZpQyoyMq4wxcyH1sFNqtIHd_iS2U9AkEACp6q6FAohK_O7GaDr_T7VfeO3JuRL9icg82WtPOtgJ1o7oqZxa1lfypGkWAgX_KF5aytblSoxlwn-Zk84Mf_YlbJEBO2mUa0Me5uLhM183akeG4y06FR-ANXrsYxrGmhpIWfl90WAKEG4ExdaexgzQOKXedTLOKnIwDW0ZSAu6O-Eiddn2w5GBO93OGEGQwkXDddA9PB9--mdyHgJM1OvXFYIWtziDLZ5qHAUrUFpYUth9B9mV4TXXLeLqx25TO7DL9czT6cGPeYNSOR3HpNdw93Pbro_kDIk-4zrmhlLd-I6w1tSisK7veJE0Y9Svvf6VLky34iV0RlIw-Z976oPP3rVJpSIujNbuFm84V2EvHFkG1oaHoViDxp4QesbToOdhl8GfnHHuwPaT78C1rwucflil_XkLAi0PBv0uGYLWaaAVlhm_lNZc4CYd7qHcdgma8dL27kHwVUJctIzphtV4yAhL-06SY-kwR9snNogfzDSuuNTVHPofu0_B7qA9vjwf3jeE8WJUbq0HxPSIGMSvJ57uh2YzRPWnMJ2PmARWgHAYoWUsZknHyr7DlKqzV1kxrLmr40xk98D9-Qkkq3enbEazhNWXRTIGMuWQbM1FQB3VL8GX3Xa1TjujWQS8_nC9LTId1XzNWsSCNOg8gHXqvt5hAeJVZ9GMTFJREPCBk5ts9odm3N3bjK5KgA3pNahnOS0u_c2auAc1t9C_5xqxEnIRxE6R1lVHz7hDTebYMcpldFI8IEuToExCjUUpoW6FmpeJrv16hwzTqbX69oToXJ2YA4WYCerDob0BAMHKWDC0nqPJTp9wjq2OnC5YKmMKfJ7lKhVprYG14RKnJfOJdChRpWQH2iK1Hc12sCJBJT2Lvm138cQeRApo2uUTs1dpJ-faoPvb6H_Wg-9ys5JsZtrzUXVpj4ttC84M7dZnbdyEh64iOoUINTSG4yryVDfN7PokiuN3DHuuXlWG8hkWAP4uyZg6sXdeSBGfVOjmG7Tc0zNqxZFkCMo9XEaLk_Zz6X7fQPM-MQVkSrb_0-S7tNwcufe3Y0nEnKpM1WohnyojInkRUzPWLUcBukzYpwuXg3MxxayDLwfjfybNb3hO_aNF_5mLz8s40IotW2Oxa1eKfZO5igty32jA5ipXwPjJjBj5yVgmTESDPmYrPkJCdFUtJJpGRTRX30BbLAybWkhJWBGilR-f5wp7yHp1pAcLl8YIKi-Di35kCCG0qtTimMeyb6E9hQww06pdDKAuVuDmC-RhgG9-x6MlmeJgKeNu2VeANq5lIiAKuDEXz4cs-TBrC_PC4j7dnaIbvchVdxx9Regcqfa2XTeXsKJB8uGwHDBQ_qu6zyKJ2ANyqk8x7Vmmz3YNREGNgiiRQK-zDjU2ZRJN0DJnHxdFMYcmywKz0QOab4orE01eqaG_Zy3vr7fDLOMJOl_puAjLnF7xiVmj1UWC2FwoWngvCrGO-2wsHB7fnvJapv-NpIoW146QuSVwhMROuZ-5SmzQz4MlF-ARtdkEvCAO45BZTM-AnTlOiMqMXspKrHGCiwE_S4FStVdHT4D7m6Ha4q_BRD9nBYp9r0vP4QdsfsK0pegYawDfZ3U9Vuk0dRZp3Z2QBXDLuIs0-0ol7_liDeC64KCdL2zrDSQCXeSQGtDpBdbSDf5xkzQ1N_IStAz6dI_FLbLqRPfE9tf3AfA9k7j3BwN_K6eeVfRueVnf0VOXukHURPwMTVE9C8IdPA8OnwLBD-k1YT2aV3Aow6eC4Dwl7cW2FtQ_BuHcpjMfWuJFiUuw9L8bLCWSlJ3rYdX_MYv-9mY--9d3r49p5FHAoK-bJS5yxHg2Q6Eg6DrSC4dORU5p_fKxrPklgOJKbZoQyb96_dp2qkCVgPjN1naoHfhgqHp49MxalqSx9n-vd86NTSXNw22lnboj4qAsLg54P4RSayO-U6jvj09ZuGtLGrCvKPAgHl_xP4dtpdbOC8OJ3nwHNfxAgZr2P5JEaFHN3RuIQGH5gkwNEA2otd40YptNJvD6r4gasyBPNY15jeYYL18yFQobK60gnXQweT_JXTlnGgbvgoGw6rJ2nifXw_o6Q_uBDQE9MOCJiN0FoivBdcwk-NHU-nNg93U30q4zbGbJ96O0E2X2qRyoOaEhBKAqkHrQM-NGjX7aj1YJFCxIFtQ00OQjT0vhGng6-3cB01l44mGdDFV47PZLzcFrGx7iDaR1Oy2Na5rOLphgT1_zvVF2mCw10HYxOYwSDnm6uqo_kADX_HQAGxQx1xDZ9iaZZGD00hdoZp55kRPGt6uZ9ZEEXPWUpAV8mPUlu0DcK6rr948_btFuMWo9KrVneCiF4qxkk_Q56aFoRa_HQwEEuh3sp9PSCT9wIfBYSR3661Ox7C-25rHNkrdv7XC8ArnQ7xT04y9JYOF_XLxtOLlAzscUryz56Qk7lexv7Qqe80fTTSRNFseDNFCxLjWm6wAo_kpaTOOvFiPUxlYwcmW4hy-hW8zH_JRVPaBCCKR_s68yEEAVve-8q0ePzqcElS4Bt8cFyU2kqodDmzzh2HAFcrA_ScDciNbwKWeJublK97rkWmLCuPZwJcvKNT_FfgYU5OxtF6G2TVVhUcbVAhPQFFegVn_8hYkZ3mJFkZa8FYYNMSGn8nssR8F9RInU9PFLfBiI2_sDJKwfhgLZ9Lb4x2Idx1-XNh9pAFkCv4eRKCoQNrfxZ4VgD7L2UeLTiTBOsH117rSSF3Aq5kaLLV9yqXc7bB8ZVdvsQ64ET6Z3sNM6xk78phFYy-Dnl9sM73dX2qpUefxdItLtql4E_jwm-D2qRdGtdkm3FpQhYhTKgfm--H3hj64AfDQP-7WVykl508pb7Ultl6j9ne28UqtsV6LHaXX3Raq78sZZl7pmkgp3dSZlZXuo0zwyh0eR8aDp201EdOqbG6a8Vs7cHo2pjy_31ZrIGA_rZhFRN5uVohUvtPWCwwV3D6qq9XQRFK6GsiIMgO8oH8v2AB_qopEXWkStyn9HgA-UntHqncuVnnVrprWFYfWVuTDkJhTC1-i9ZgdA1eUvZVxl-I4SfmDG540HUVVRw-Kt15vS7K2vc1FDiQA91Iya8eMjVKOs96Cr--cngQ_zZw062ZqKp7avO0EOTamvz8Zi2a0XzdIH5dH0_9_kXE_T4U43Ud_29QMElOxJfxt-9p9lBNBjfEkUvBayPX2XWlePtoQL89QLg-Xwe7RaGu0hvUiROaArk47B_703dSKDll2V5eUKc5f0H7icWyqp8u5rnjQsafBu6RCWHr7YJ1Pk5TBaw1qQCvNA2Z_FVZWN18No61fV16DHyjoiHBBjTROCS7m7_3snv4SDkoiFvIswpEt7pbYtbXLp5t0EQOQkWQOITojrGYIUi9c23kdiXr3EoPsvSMKlJcDyag25wzVNfA-bfiMCkdHPqaaTFBqYqlwA0SI6bwHKhqFKdGkrJ5YIxgaFLsLwwiNMSBR2wWXSFRXz-HCMewHkVV4LpGxkzeihWXJUO3gXeJuVY1EGxB8U15BUtQQcAAe2Om9KZtOsS2kRtO7vZq62E8jl7bUbTmw0XTZ4eh3xg-IRiK1ynur6XqtZH1kNQFq7k60X-6cFwDS7eDGdzrgl-Kbl6VSzxpwxu5Lz-KIjV5gGBUcOjnIpRuwY_s', provider_name='openai', ), BuiltinToolCallPart( tool_name='image_generation', tool_call_id='ig_68cdec701280819fab216c216ff58efe079003437d26d0c0', provider_name='openai', ), FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='c9d559', ), id='ig_68cdec701280819fab216c216ff58efe079003437d26d0c0', ), BuiltinToolReturnPart( tool_name='image_generation', content={ 'status': 'completed', 'background': 'opaque', 'quality': 'high', 'size': '1024x1024', 'revised_prompt': IsStr(), }, tool_call_id='ig_68cdec701280819fab216c216ff58efe079003437d26d0c0', timestamp=IsDatetime(), provider_name='openai', ), TextPart(content='', id='msg_68cdecb54530819f9e25118291f5d1fe079003437d26d0c0'), ], usage=RequestUsage( input_tokens=2858, cache_read_tokens=1920, output_tokens=1071, details={'reasoning_tokens': 896} ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_68cdec61d0a0819fac14ed057a9946a1079003437d26d0c0', finish_reason='stop', ), ] ) async def test_openai_responses_image_or_text_output(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model, output_type=str | BinaryImage) result = await agent.run('Tell me a two-sentence story about an axolotl.') assert result.output == snapshot(IsStr()) result = await agent.run('Generate an image of an axolotl.') assert result.output == snapshot( BinaryImage( data=IsBytes(), media_type='image/png', identifier='f77253', ) ) async def test_openai_responses_image_and_text_output(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model, builtin_tools=[ImageGenerationTool()]) result = await agent.run('Tell me a two-sentence story about an axolotl with an illustration.') assert result.output == snapshot(IsStr()) assert result.response.files == snapshot( [ BinaryImage( data=IsBytes(), media_type='image/png', identifier='fbb409', ) ] ) async def test_openai_responses_image_generation_with_tool_output(allow_model_requests: None, openai_api_key: str): class Animal(BaseModel): species: str name: str model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model, builtin_tools=[ImageGenerationTool()], output_type=Animal) result = await agent.run('Generate an image of an axolotl.') assert result.output == snapshot(Animal(species='Axolotl', name='Axie')) assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Generate an image of an axolotl.', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_0360827931d9421b0068dd832972fc81a0a1d7b8703a3f8f9c', signature=IsStr(), provider_name='openai', ), BuiltinToolCallPart( tool_name='image_generation', tool_call_id='ig_0360827931d9421b0068dd833f660c81a09fc92cfc19fb9b13', provider_name='openai', ), FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='918a98', ), id='ig_0360827931d9421b0068dd833f660c81a09fc92cfc19fb9b13', ), BuiltinToolReturnPart( tool_name='image_generation', content={ 'status': 'completed', 'background': 'opaque', 'quality': 'high', 'size': '1024x1024', 'revised_prompt': IsStr(), }, tool_call_id='ig_0360827931d9421b0068dd833f660c81a09fc92cfc19fb9b13', timestamp=IsDatetime(), provider_name='openai', ), TextPart(content='', id='msg_0360827931d9421b0068dd836f4de881a0ae6d58054d203eb2'), ], usage=RequestUsage(input_tokens=2253, output_tokens=1755, details={'reasoning_tokens': 1600}), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_0360827931d9421b0068dd8328c08c81a0ba854f245883906f', finish_reason='stop', ), ModelRequest( parts=[ RetryPromptPart( content='Please include your response in a tool call.', tool_call_id=IsStr(), timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_0360827931d9421b0068dd8371573081a09265815c4896c60f', signature=IsStr(), provider_name='openai', ), ToolCallPart( tool_name='final_result', args='{"species":"Axolotl","name":"Axie"}', tool_call_id='call_eE7MHM5WMJnMt5srV69NmBJk', id='fc_0360827931d9421b0068dd83918a8c81a08a765e558fd5e071', ), ], usage=RequestUsage(input_tokens=587, output_tokens=2587, details={'reasoning_tokens': 2560}), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_0360827931d9421b0068dd8370a70081a09d6de822ee43bbc4', finish_reason='stop', ), ModelRequest( parts=[ ToolReturnPart( tool_name='final_result', content='Final result processed.', tool_call_id='call_eE7MHM5WMJnMt5srV69NmBJk', timestamp=IsDatetime(), ) ] ), ] ) async def test_openai_responses_image_generation_with_native_output(allow_model_requests: None, openai_api_key: str): class Animal(BaseModel): species: str name: str model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model, builtin_tools=[ImageGenerationTool()], output_type=NativeOutput(Animal)) result = await agent.run('Generate an image of an axolotl.') assert result.output == snapshot(Animal(species='Ambystoma mexicanum', name='Axolotl')) assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Generate an image of an axolotl.', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_09b7ce6df817433c0068dd840825f481a08746132be64b7dbc', signature=IsStr(), provider_name='openai', ), BuiltinToolCallPart( tool_name='image_generation', tool_call_id='ig_09b7ce6df817433c0068dd8418e65881a09a80011c41848b07', provider_name='openai', ), FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='4ed317', ), id='ig_09b7ce6df817433c0068dd8418e65881a09a80011c41848b07', ), BuiltinToolReturnPart( tool_name='image_generation', content={ 'status': 'completed', 'background': 'opaque', 'quality': 'high', 'size': '1024x1024', 'revised_prompt': IsStr(), }, tool_call_id='ig_09b7ce6df817433c0068dd8418e65881a09a80011c41848b07', timestamp=IsDatetime(), provider_name='openai', ), TextPart( content='{"species":"Ambystoma mexicanum","name":"Axolotl"}', id='msg_09b7ce6df817433c0068dd8455d66481a0a265a59089859b56', ), ], usage=RequestUsage(input_tokens=1789, output_tokens=1312, details={'reasoning_tokens': 1152}), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_09b7ce6df817433c0068dd8407c37881a0ad817ef3cc3a3600', finish_reason='stop', ), ] ) async def test_openai_responses_image_generation_with_prompted_output(allow_model_requests: None, openai_api_key: str): class Animal(BaseModel): species: str name: str model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model, builtin_tools=[ImageGenerationTool()], output_type=PromptedOutput(Animal)) result = await agent.run('Generate an image of an axolotl.') assert result.output == snapshot(Animal(species='axolotl', name='Axel')) assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Generate an image of an axolotl.', timestamp=IsDatetime(), ) ], instructions="""\ Always respond with a JSON object that's compatible with this schema: {"properties": {"species": {"type": "string"}, "name": {"type": "string"}}, "required": ["species", "name"], "title": "Animal", "type": "object"} Don't include any text or Markdown fencing before or after.\ """, ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_0d14a5e3c26c21180068dd8721f7e08190964fcca3611acaa8', signature=IsStr(), provider_name='openai', ), BuiltinToolCallPart( tool_name='image_generation', tool_call_id='ig_0d14a5e3c26c21180068dd87309a608190ab2d8c7af59983ed', provider_name='openai', ), FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='958792', ), id='ig_0d14a5e3c26c21180068dd87309a608190ab2d8c7af59983ed', ), BuiltinToolReturnPart( tool_name='image_generation', content={ 'status': 'completed', 'background': 'opaque', 'quality': 'high', 'size': '1024x1024', 'revised_prompt': IsStr(), }, tool_call_id='ig_0d14a5e3c26c21180068dd87309a608190ab2d8c7af59983ed', timestamp=IsDatetime(), provider_name='openai', ), TextPart( content='{"species":"axolotl","name":"Axel"}', id='msg_0d14a5e3c26c21180068dd8763b4508190bb7487109f73e1f4', ), ], usage=RequestUsage(input_tokens=1812, output_tokens=1313, details={'reasoning_tokens': 1152}), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_0d14a5e3c26c21180068dd871d439081908dc36e63fab0cedf', finish_reason='stop', ), ] ) async def test_openai_responses_image_generation_with_tools(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model, output_type=BinaryImage) @agent.tool_plain async def get_animal() -> str: return 'axolotl' result = await agent.run('Generate an image of the animal returned by the get_animal tool.') assert result.output == snapshot( BinaryImage( data=IsBytes(), media_type='image/png', identifier='160d47', ) ) assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Generate an image of the animal returned by the get_animal tool.', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_0481074da98340df0068dd88e41588819180570a0cf50d0e6e', signature=IsStr(), provider_name='openai', ), ToolCallPart( tool_name='get_animal', args='{}', tool_call_id='call_t76xO1K2zqrJkawkU3tur8vj', id='fc_0481074da98340df0068dd88f000688191afaf54f799b1dfaf', ), ], usage=RequestUsage(input_tokens=389, output_tokens=721, details={'reasoning_tokens': 704}), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_0481074da98340df0068dd88dceb1481918b1d167d99bc51cd', finish_reason='stop', ), ModelRequest( parts=[ ToolReturnPart( tool_name='get_animal', content='axolotl', tool_call_id='call_t76xO1K2zqrJkawkU3tur8vj', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ BuiltinToolCallPart( tool_name='image_generation', tool_call_id='ig_0481074da98340df0068dd88fb39c0819182d36f882ee0904f', provider_name='openai', ), FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='160d47', ), id='ig_0481074da98340df0068dd88fb39c0819182d36f882ee0904f', ), BuiltinToolReturnPart( tool_name='image_generation', content={ 'status': 'completed', 'background': 'opaque', 'quality': 'high', 'size': '1024x1024', 'revised_prompt': IsStr(), }, tool_call_id='ig_0481074da98340df0068dd88fb39c0819182d36f882ee0904f', timestamp=IsDatetime(), provider_name='openai', ), TextPart(content='', id='msg_0481074da98340df0068dd8934b3f48191920fd2feb9de2332'), ], usage=RequestUsage(input_tokens=1294, output_tokens=65, details={'reasoning_tokens': 0}), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_0481074da98340df0068dd88f0ba04819185a168065ef28040', finish_reason='stop', ), ] ) async def test_openai_responses_multiple_images(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model, output_type=BinaryImage) result = await agent.run('Generate two separate images of axolotls.') # The first image is used as output assert result.output == snapshot( BinaryImage( data=IsBytes(), media_type='image/png', identifier='2a8c51', ) ) assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Generate two separate images of axolotls.', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_0b6169df6e16e9690068dd80d6daec8191ba71651890c0e1e1', signature=IsStr(), provider_name='openai', ), BuiltinToolCallPart( tool_name='image_generation', tool_call_id='ig_0b6169df6e16e9690068dd80f7b070819189831dcc01b98a2a', provider_name='openai', ), FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='2a8c51', ), id='ig_0b6169df6e16e9690068dd80f7b070819189831dcc01b98a2a', ), BuiltinToolReturnPart( tool_name='image_generation', content={ 'status': 'completed', 'background': 'opaque', 'quality': 'high', 'size': '1024x1024', 'revised_prompt': IsStr(), }, tool_call_id='ig_0b6169df6e16e9690068dd80f7b070819189831dcc01b98a2a', timestamp=IsDatetime(), provider_name='openai', ), BuiltinToolCallPart( tool_name='image_generation', tool_call_id='ig_0b6169df6e16e9690068dd8125f4448191bac6818b54114209', provider_name='openai', ), FilePart( content=BinaryImage( data=IsBytes(), media_type='image/png', identifier='dd7c41', ), id='ig_0b6169df6e16e9690068dd8125f4448191bac6818b54114209', ), BuiltinToolReturnPart( tool_name='image_generation', content={ 'status': 'completed', 'background': 'opaque', 'quality': 'high', 'size': '1536x1024', 'revised_prompt': IsStr(), }, tool_call_id='ig_0b6169df6e16e9690068dd8125f4448191bac6818b54114209', timestamp=IsDatetime(), provider_name='openai', ), TextPart(content='', id='msg_0b6169df6e16e9690068dd8163a99c8191ae96a95eaa8e6365'), ], usage=RequestUsage( input_tokens=2675, output_tokens=2157, details={'reasoning_tokens': 1984}, ), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_0b6169df6e16e9690068dd80d64aec81919c65f238307673bb', finish_reason='stop', ), ] ) async def test_openai_responses_image_generation_jpeg(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(model=model, builtin_tools=[ImageGenerationTool(output_format='jpeg')], output_type=BinaryImage) result = await agent.run('Generate an image of axolotl.') assert result.output == snapshot( BinaryImage( data=IsBytes(), media_type='image/jpeg', identifier='df8cd2', ) ) assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Generate an image of axolotl.', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_08acbdf1ae54befc0068dd9cee0698819791dc1b2461291dbe', signature=IsStr(), provider_name='openai', ), BuiltinToolCallPart( tool_name='image_generation', tool_call_id='ig_08acbdf1ae54befc0068dd9d0347bc8197ad70005495e64e62', provider_name='openai', ), FilePart( content=BinaryImage( data=IsBytes(), media_type='image/jpeg', identifier='df8cd2', ), id='ig_08acbdf1ae54befc0068dd9d0347bc8197ad70005495e64e62', ), BuiltinToolReturnPart( tool_name='image_generation', content={ 'status': 'completed', 'background': 'opaque', 'quality': 'high', 'size': '1536x1024', 'revised_prompt': IsStr(), }, tool_call_id='ig_08acbdf1ae54befc0068dd9d0347bc8197ad70005495e64e62', timestamp=IsDatetime(), provider_name='openai', ), TextPart(content='', id='msg_08acbdf1ae54befc0068dd9d468248819786f55b61db3a9a60'), ], usage=RequestUsage(input_tokens=1889, output_tokens=1434, details={'reasoning_tokens': 1280}), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_08acbdf1ae54befc0068dd9ced226c8197a2e974b29c565407', finish_reason='stop', ), ] ) async def test_openai_responses_history_with_combined_tool_call_id(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('gpt-5', provider=OpenAIProvider(api_key=openai_api_key)) class CityLocation(BaseModel): city: str country: str agent = Agent(m, output_type=ToolOutput(CityLocation)) messages = [ ModelRequest( parts=[ UserPromptPart( content='What is the largest city in the user country?', ) ] ), ModelResponse( parts=[ ToolCallPart( tool_name='get_user_country', args='{}', tool_call_id='call_ZWkVhdUjupo528U9dqgFeRkH|fc_68477f0bb8e4819cba6d781e174d77f8001fd29e2d5573f7', ) ], model_name='gpt-4o-2024-08-06', provider_name='openai', provider_response_id='resp_68477f0b40a8819cb8d55594bc2c232a001fd29e2d5573f7', finish_reason='stop', ), ModelRequest( parts=[ ToolReturnPart( tool_name='get_user_country', content='Mexico', tool_call_id='call_ZWkVhdUjupo528U9dqgFeRkH|fc_68477f0bb8e4819cba6d781e174d77f8001fd29e2d5573f7', ) ] ), ] result = await agent.run('What is the largest city in the user country?', message_history=messages) assert result.output == snapshot(CityLocation(city='Mexico City', country='Mexico')) assert result.new_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What is the largest city in the user country?', timestamp=IsDatetime(), ) ] ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_001fd29e2d5573f70068ece2e816fc819c82755f049c987ea4', signature='gAAAAABo7OLt_-yMcMz15n_JkwU0selGH2vqiwJDNU86YIjY_jQLXid4usIFjjCppiyOnJjtU_C6e7jUIKnfZRBt1DHVFMGpAVvTBZBVdJhXl0ypGjkAj3Wv_3ecAG9oU3DoUMKrbwEMqL0LaSfNSN1qgCTt-RL2sgeEDgFeiOpX40BWgS8tVMfR4_qBxJcp8KeYvw5niPgwcMF3UPIEjHlaVpglJH2SzZtTOdxeFDfYbnvdWTMvwYFIc0jKOREG_-hZE4AznhHdSLV2-I5nGlxuxqaI4GQCk-Fp8Cvcy15_NYYP62ii50VlR6HPp_gQZEetwgC5pThsiuuG7-n1hGOnsj8gZyjSKsMe2KpzlYzhT7ighmArDVEx8Utvp1FXikqGkEzt4RTqqPInp9kuvqQTSyd8JZ6BEetRl1EuZXT7zXrzLwFN7Vm_gqixmf6mLXZUw6vg6LqGkhSh5fo6C7akPTwwJXjVJ37Dzfejo6RiVKOT-_9sdYCHW2kZ9XfQAmRQfB97UpSZ8QrVfaKy_uRIHLexs8QrQvKuw-uHDQBAL3OEmSTzHzCQ-q7b0FHr514Z29l9etavHNVdpeleWGo6VEtLWGQyblIdIBtf946YnQvr6NYIR8uATn9Z91rr8FsFJTpJh_v5iGA2f8rfPRu27nmw-q8XnPVc_FYCZDk08r_YhdEJZn1INBi8wYSWmpib8VxNpkFO7FFRuK-F8rh3MTpYgIOqPQYbf3LCRvKukTwv1b3mjSKVpHQSm_s6s7djdD-rLuc22-3_MLd0ii4_oOT8w51TQIM61LtonGvxUqf4oKHSUFCVnrWWiT-0ttdpwpJ_iB5frnEeY2mWyU1u7sd38BI3dOzoM82IFaIm98g9fa99bmoA7Z7gI60tzyF8YbJmWF-PCwyKHJ7B1MbCBonO36NmeEM-SplrR54fGykxTmwvtbYGhd5f0cdYzD0zulRDj-AhOd96rrUB_fIgoQGTXey8L_w0whcnVTWdG6is-rx8373Sz8ZRoE5RiLWW1mfHzVXxwslphx4BedRVF0tL-1YO7sg5MXhHCf6hpw8dOht-21NMrb1F1DQadFE_fhySFl-TgOD5BlhAuupLMsqcCIa4lcXP_loyA4ERP6WSdz2Bybz7_1eOiflfVodRrNqvr_DnL0NEXD_JkYTeIn84ziarFV7U7ZnkMvRiA_p1fWdbHTsE_8lu1rsf8fcJ1e76_6ycPkOc4TrOZw8gVRb7gIbMMVrv72BT_sFhW7GkXrzCQpQaeybmRw-bjFhkMMjMDYGXkA_H0q2Zfyh3zCOoa40hl2cqRWp7n1XuafmtKG_F8e9hyWox0q7AhZr5HOOaHz8r3O3-dmNl1KP52bqA8S72rLDslAOQlDupmAQgAmkm5ApYeYcEBredN78jHQ1pviUEI2-3qr4ClXZFHPa54AJ_q4HQ-EcKXEcYQglG21mSUy_tFQF-m4X46Qu8yYWcBVW4E0CG3wbvYx0BCdbc5RhIDkJo1elxLK8XS64lpFkCWy62xLVeMuVuCj8q84-Kk7tZ7gtMtLV9PHQCdbl3s2pAzMfuNIBJog6-HPmwha2n9T0Md5qF7OqCtnYWOWUfIMmQVcdW-ECGsQy9uIUmpsOjdtH31hrX3MUEhIOUB5xErLwfp-_s22ciAY_ap3JlYAiTKGlMCxKxTzK7wWEG_nYhDXC1Afj2z-tgvYhtn9MyDf2v0aIpDM9BoTOLEO-ButzylJ06pJlrJhpdvklvwJxUiuhlwy0bHNilb4Zv4QwnUv3DCrIeKe1ne90vEXe6YlDwSMeWJcz1DZIQBvVcNlN8q2y8Rae3lMWzsvD0YXrcXp02ckYoLSOQZgNYviGYLsgRgPGiIkncjSDt7WWV6td3l-zTrP6MT_hKigmg5F5_F6tS1bKb0jlQBZd0NP-_L_TPqMGRjCYG8johd6VyMiagslDjxG39Dh2wyTI19ZW7h_AOuOpnfkt2armqiq6iGfevA3malqkNakb6mFAS04J9O0butWVAw4yiPCEcLuDNAzzi_qrqLee4gkjh0NplvfGCaE6qqYms61GJbJC4wge6vjyTakurbqWEV3YoR3y_dn-0pjQ7TOx9kkruDwg0nZIV5O6yYxaulmbuvo3fs5CZb9ptZPD0MzGZj7CZU2MDCa4a4gr0McOx2MricxSzIu6emuRUzZuC6C1JxPRC00M0TrZNMIe_WVa9fXDLV1ULEAIMwMXzNT9zV6yiYQCwhkp30Wqde3W0LlIRpSbDuJXcvT8OCbXkdPNIScccdT9LvUQQ--hU2P45kisOev3TYn7yv-pdxM3u1KFNwuFxedSArMBPg7GDz1BOxDQRzv0mfwbf_CcoFbuyj7Tf4zWO46HVdHeRNbvIE--bnaSYD-UFaKknp8ZsBQQhBU_2TEca3fKwmg81-g7Vdb28QUZEuPzgE4ekxZejkKpiKqlLC5nJYgvXrqk2H35D51mYdzPs0ST05Mc41x9MFm_YOLxSFyA0yGAKVINmD5wT6kvRflPkgoksd2ryIvo4KMw3oZQKodv5By0mSJ8iX2vhTGylxiM8wj-ICyNuOsaRFrcMSpX7tZbXcDyysApdmx217BSADoQiNZBLngF7ptxc2QGyo3CwuDjaljwmSgL9KeGthd1RJFd826M287IPpCjLM4WRquCL_E0pQryNqOMn-ZEOCAlBjE37290EhkjKbhiGBEnHUvSbhoH4nL47AmunP_Q5aqh5173VfyoyaybuS3fXjQ5WO0kyFjMdD-a7C6PVdwToCTP-TljoF2YnQKCiqUGs9gNHS9mYhQSXzY4uuGlTHLfKB4JKS5_MQHvwI9zCbTvVG854fPuo_2mzSh-y8TSzBWPokhYWI_q095Sh6tOqDIJNMGyjI2GDFRSyKpKhIFCLyU2JEo9B6l91jPlir0XI8ZOQfBd9J0I4JIqnyoj40_1bF1zUDGc014bdGfxazxwlGph_ysKAP39wV7X9DBFS3ZmeSIn-r3s-sci0HmwnJUb2r03m40rFuNTV1cJMAFP7ZY7PQQQ0TtlO_al0uedaOWylLauap_eoRqc6xGJ2rSz1e7cOevksUlAqzK5xknYKHlsW970xuDGHKOZnKPg8O9nb2PKrcjwEQF5RFPc3l8TtOUXPhhvTERZFGoEuGuSuSp1cJhzba06yPnL-wE3CstYUm3jvkaUme6kKqM4tWBCQDg-_2PYf24xXYlmkIklylskqId826Y3pVVUd7e0vQO0POPeVYU1qwtTp7Ln-MhYEWexxptdNkVQ-kWx63w6HXF6_kefSxaf0UcvL8tOV73u7w_udle9MC_TXgwJZpoW2tSi5HETjQ_i28FAP2iJmclWOm3gP08cMiXvgpTpjzh6meBdvKepnifl_ivPzRnyjz3mYCZH-UJ4LmOHIonv-8arnckhCwHoFIpaIX7eSZyY0JcbBETKImtUwrlTSlbD8l02KDtqw2FJURtEWI5dC1sTS8c2HcyjXyQDA9A25a0M1yIgZyaadODGQ1zoa9xXB', provider_name='openai', ), ToolCallPart( tool_name='final_result', args='{"city":"Mexico City","country":"Mexico"}', tool_call_id='call_LIXPi261Xx3dGYzlDsOoyHGk', id='fc_001fd29e2d5573f70068ece2ecc140819c97ca83bd4647a717', ), ], usage=RequestUsage(input_tokens=103, output_tokens=409, details={'reasoning_tokens': 384}), model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_001fd29e2d5573f70068ece2e6dfbc819c96557f0de72802be', finish_reason='stop', ), ModelRequest( parts=[ ToolReturnPart( tool_name='final_result', content='Final result processed.', tool_call_id='call_LIXPi261Xx3dGYzlDsOoyHGk', timestamp=IsDatetime(), ) ] ), ] ) async def test_openai_responses_model_mcp_server_tool(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel( 'o4-mini', provider=OpenAIProvider(api_key=openai_api_key), ) agent = Agent( m, instructions='You are a helpful assistant.', builtin_tools=[ MCPServerTool( id='deepwiki', url='https://mcp.deepwiki.com/mcp', description='DeepWiki MCP server', allowed_tools=['ask_question'], headers={'custom-header-key': 'custom-header-value'}, ), ], ) result = await agent.run('Can you tell me more about the pydantic/pydantic-ai repo? Keep your answer short') assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Can you tell me more about the pydantic/pydantic-ai repo? Keep your answer short', timestamp=IsDatetime(), ) ], instructions='You are a helpful assistant.', ), ModelResponse( parts=[ BuiltinToolCallPart( tool_name='mcp_server:deepwiki', args={'action': 'list_tools'}, tool_call_id='mcpl_0083938b3a28070e0068fabd81d51081a09d4b183ced693273', provider_name='openai', ), BuiltinToolReturnPart( tool_name='mcp_server:deepwiki', content={ 'tools': [ { 'input_schema': { 'type': 'object', 'properties': { 'repoName': { 'type': 'string', 'description': 'GitHub repository: owner/repo (e.g. "facebook/react")', }, 'question': { 'type': 'string', 'description': 'The question to ask about the repository', }, }, 'required': ['repoName', 'question'], 'additionalProperties': False, '$schema': 'http://json-schema.org/draft-07/schema#', }, 'name': 'ask_question', 'annotations': {'read_only': False}, 'description': 'Ask any question about a GitHub repository', } ], 'error': None, }, tool_call_id='mcpl_0083938b3a28070e0068fabd81d51081a09d4b183ced693273', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_0083938b3a28070e0068fabd84727c81a0a52c171d2568a947', signature='gAAAAABo-r2bs6ChS2NtAXH6S8ZWRHzygQvAZrQGsb5ziJKg6dINF9TQnq4llBquiZh-3Ngx2Ha4S-2_TLSbgcsglradULI8c8N2CnilghcqlLE90MXgHWzGfMDbmnRVpTW9iJsOnBn4ferQtNLIsXzfGWq4Ov0Bbvlw_fCm9pQsqOavcJ5Kop2lJ9Xqb__boYMcBCPq3FcNlfC3aia2wZkacS4qKZGqytqQP13EX3q6LwFVnAMIFuwn5XLrh4lFf-S5u8UIw3C6wvVIXEUatY6-awgHHJKXxWUxqRQPJegatMb8KE-QtuKQUfdvEE0ykdHtWqT7nnC3qTY67UaSCCvJ9SdXj-t806GVei9McSUe8riU3viHnfY0R0u9GIXsVnfVthIDRnX7KzpF5ot_CpCrgbCmD9Rj2AAos5pCdSzpc08G5auUuuMZfoiWANADTHHhO2OvflSEpmO8pb-QAYfMoK9exYVQ8Oig-Nj35unupcYy7A2bDCViXzqy32aw9QHmH7rErI4v72beWQxRVdX15Z7VS2c6L1dD7cU18K35CWqlSz9hEX5AcGqEEtIDVu1TdF3m1m2u4ooc4TjYpRecjYoG8Ib-vVKoX5C65a7G1cTbCo8dO0DYKGgM8jM7ZDubxbCcZ22Sxk58f8cer7WxHyp7WRo5-6zvMwMCk8uEY44RJmg-m0Oxl_6qxdr4Md80xZah_6tCCB62agQmYwCrR75_r93xOckQAK0R_37khvQD5gWVlE5Rg-01eUTboiPGqYmIsqWvOkziMGnxgKVw_yUf8swHU1ciWr7O1EdVPHLG7YXlVQTHTE_CX3uOsE2FoZnpS_MgpxGfjb76majV50h7mJ6ySVPF_3NF3RQXx64W08SW4eVFD8JJf0yChqXDmlwu2CDZN1n99xdaE9QbMODNEOmfTQOPhQ9g-4LhstNTKCCxWDh0qiv_dq2qAd0I9Gupoit33xGpb66mndc0nuuNFe8-16iC_KzQtHBNzgasgYK-r83KFVmiYK3Jxvz_2dfdwe0M1q7NLBvbnWc6k9LIf8iDUF6Q1J-cfC7SsncCbROtzIPlKpQwxhP-M09Xy3RVxlH9dcvuk3_qqEAartUQC8ZbuLRbhiq66eE1RvQzdNd2tsoBQ85cdNs57Penio7w9zILUf1JP5O8-zCe5GPC3W3EXTIEvHR-kiuxJvhcsySijpldGmuygRx05ARNOIT7VDCZvF23RfmnRduY1X1FAqb_i_aMStK7iyHr_2ohwOWLuklpyuoG0Y1ulvq1A9-hyCZ0mpvTEF6om2tAZ9_7h8W9ksiOkey0yA-6ze17MCjfnK2XcbqmSMgOngW1PrD81oKoheMnIeJdcWgF2mk8VDqmAwaDTxMxdnXkzK74rA43a4rWk3d2bUts8dAUkuYXTwJwKQw4LfXtu-mwwgJ6BkT_GiBcBJ6ulBuPsNZfpwPuxox6PS6KpzVTQ94cKNqSIIyFCD4xZsEvPALud09-gmAEDHxdnPjqLSi2U8xd0j-6XYKN0JtZ45kwEIRsOrFu-SYLz1OcYFKI5A5P-vYlzGx1WhEnoeUlyooJBhNj6ZBfj9f63SByxm7sgh260vf1t-4OGzVTIUKFluxkI4ubigLZ-g4q4dSwiEWXn50JFPrtuPs5VxsIIz_lXbh1SrKeQ647KdDSAQZFgEfzOOt3el5K97V1x7V7gEWCCgmqDIz3yZPpwD6qmUQKqlj_p8-OQrniamGULkXrmrgbNQVfV-Qw7Hg6ELw4aHF_IZME9Qnyn7peFhH6ai_YapuNF7FK-MBtPYoMaqBf05U2-uJAVUas3VuT_-pTyHvhtFmB7vc0-qgf_CtVNIXSPq2_vXdQdEwwCVPPwW6xWm-invrzhyQR_mf3OQqZT6_zOHIMPBJUaXcQKT0KTdoBZUDamAR-ECZl8r6wdLCn0HjAEwj3ifUCNMzQ7CZHUQG46rj61YyasNWO__4Ef4kTcApKgljosuABqP4HAdmkP5eEnX-6nutrL50iv-Mms_R-T7SKtmEEf9wihTu4Meb441cU9DI4WwSyiBSnsYdGy9FJKmHwP7HD0FmpmWkOrtROkQVMlMVKQFlKK8OBtxafHYsZkWDawbA1eetzMBzQ3PP8PSvva6SJWjbgURHVm5RjXV8Hk6toIBEDx9r9vAIczSp49eDCkQbzPkGAVilO3KLQpNx2itBbZzgE36uV0neZZsVs7aqafI4qCTQOLzYA8YFDKz92yhgdIzl5VPFLFNHqRS4duPRQImQ7vb6yKSxjDThiyQQUTPBX_EXUAAR7JHwJI1i8la3V', provider_name='openai', ), BuiltinToolCallPart( tool_name='mcp_server:deepwiki', args={ 'action': 'call_tool', 'tool_name': 'ask_question', 'tool_args': { 'repoName': 'pydantic/pydantic-ai', 'question': 'Provide a brief summary of the repository, including purpose, main features, and status.', }, }, tool_call_id='mcp_0083938b3a28070e0068fabd88db5c81a08e56f163bbc6088b', provider_name='openai', ), BuiltinToolReturnPart( tool_name='mcp_server:deepwiki', content={ 'output': """\ Pydantic AI is a Python agent framework designed to build production-grade applications using Generative AI, emphasizing an ergonomic developer experience and type-safety . It provides type-safe agents, a model-agnostic design supporting over 15 LLM providers, structured outputs with Pydantic validation, comprehensive observability, and production-ready tooling . The project is structured as a UV workspace monorepo, including core framework components, an evaluation system, a graph execution engine, examples, and a CLI tool . ## Purpose <cite/> The primary purpose of Pydantic AI is to simplify the development of reliable AI applications by offering a robust framework that integrates type-safety and an intuitive developer experience . It aims to provide a unified approach to interacting with various LLM providers and managing complex agent workflows . ## Main Features <cite/> ### Type-Safe Agents <cite/> Pydantic AI agents are generic `Agent[Deps, Output]` for compile-time validation, utilizing `RunContext[Deps]` for dependency injection and Pydantic `output_type` for output validation . This ensures that the inputs and outputs of agents are strictly typed and validated . ### Model-Agnostic Design <cite/> The framework supports over 15 LLM providers through a unified `Model` interface, allowing developers to switch between different models without significant code changes . Implementations for providers like OpenAI, Anthropic, and Google are available . ### Structured Outputs <cite/> Pydantic AI leverages Pydantic for automatic validation and self-correction of structured outputs from LLMs . This is crucial for ensuring data integrity and reliability in AI applications . ### Comprehensive Observability <cite/> The framework includes comprehensive observability features via OpenTelemetry and native Logfire integration . This allows for tracing agent runs, model requests, tool executions, and monitoring token usage and costs . ### Production-Ready Tooling <cite/> Pydantic AI offers an evaluation framework, durable execution capabilities, and protocol integrations . * **Tool System**: Tools can be registered using the `@agent.tool` decorator, with automatic JSON schema generation from function signatures and docstrings . * **Graph Execution**: The `pydantic_graph.Graph` module provides a graph-based state machine for orchestrating agent execution, using nodes like `UserPromptNode`, `ModelRequestNode`, and `CallToolsNode` . * **Evaluation Framework**: The `pydantic-evals` package provides tools for creating datasets, running evaluators (e.g., `ExactMatch`, `LLMEvaluator`), and generating reports . * **Integrations**: It integrates with various protocols and environments, including Model Context Protocol (MCP) for external tool servers, AG-UI for interactive frontends, and Temporal/DBOS for durable execution . ## Status <cite/> The project is actively maintained and considered "Production/Stable" . It supports Python versions 3.10 through 3.13 . The documentation is built using MkDocs and includes API references and examples . ## Notes <cite/> The repository is organized as a monorepo using `uv` for package management . Key packages include `pydantic-ai-slim` (core framework), `pydantic-evals` (evaluation system), `pydantic-graph` (graph execution engine), `examples` (example applications), and `clai` (CLI tool) . Wiki pages you might want to explore: - [Overview (pydantic/pydantic-ai)](/wiki/pydantic/pydantic-ai#1) View this search on DeepWiki: https://deepwiki.com/search/provide-a-brief-summary-of-the_a5712f6e-e928-4886-bcea-b9b75761aac5 """, 'error': None, }, tool_call_id='mcp_0083938b3a28070e0068fabd88db5c81a08e56f163bbc6088b', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_0083938b3a28070e0068fabd97008081a0ad1b2362bcb153c9', signature='gAAAAABo-r2bD-v0Y3pAlyAEK1Sb8qJJcJRKSRtYwymHwLNXY-SKCqd_Q5RbN0DLCclspuPCAasGLm1WM1Q2Y_3szaEEr_OJalXTVEfRvhCJE1iTgoz2Uyf7KttZ4W92hlYjE8cjgdo5tKtSVkNyzTs4JUHKRHoDMutL2KivjZKuK_4n-lo9paJC_jmz6RWO8wUoXo3_fGxjliOGnWyRXwEPmgAcEWNOSVgCgAEO3vXerXRPLie02HegWcLMtK6WORDHd02Kr86QSK3W30bnvU7glAFX6VhSSnR8G0ceAM-ImoomQ8obEDyedX1-pYDKPOa4pZ5iTjD24ABYOwz-0L7SNziQJLycwwsr11Fj0_Au9yJph8YkNb2nAyFeiNVCRjKul51B7dZgz-UZ9juWO2ffeI0GNtQTYzf46_Y1t0qykGW6w59xjmBHTKf5SiSe0pqWxZ6LOLoPx01rX2gLaKgNZZiERSbO0iwbA4tpxb9ur-qeFVv5tS7xy8KFYOa8SPrypvFWDoY6CjSwTS3ir0vyfpbJy-n6bcYP_pTwDZxy_1aVkciim8Tmm_9wYgI0uY5kcA9VYJuyc4cg7S7ykTUxMZz7xiLMf8FoXl1gHbVJrYriyZzh2poYTWlcCuSCiUaXhQKxcxMRrt_P7WANx0n68ENQ40HkoJ6rThvWUuwtmEYqZ0ldh3XSFtyNrqha4PQ5eg_DudlU_5CxyykuzWmi_o5MEW4_XW4b9vdXg1laqx4189_jEuV_JPGNeL3Ke4EbMbKHzsiaGePRZGgNutnlERagmU4VFTeoE5bN3oHlR_Au4PeQxdb7BuBmZRDDCnnIRd2NfSWb7bgfUozkA4S6rm_089OlRBeRVoLtA8zZZinNGtOZl7MtkLnoJVIWpF1rr7D_47eWSyyegUIIS2e5UKLJfCLkNgSlWPU9VquHEzSfqeHfzoN5ccoVwrvrHmeveTjI-wIJygdfuyti5cMgOOkAtLzjWmbs4CjmlWcbZKeidtDj5YpCSmYAGFuZze-cSbNjMv4th639dCu_jmRMze-l2Y5npbRwMqEJr7VLXghmLc1vhOsaQM3gxoF0CJJlmvtR4jxPqhE3694YRva6LS1WjR4oueM6zfpVeB2kC0hQgqaL6MiwtTRYFfuCzEHi18TwA5bqqkfgrDXedmjAzlEGSZFe2EBRlF_ZtagrVVTCagHQArnH3DkVQMEDCHCqDxA_PINR_997IxeNgGPsvazVdOOBef7sO4rvAWrC94nIlt7d4aViqbTNMW-W8rqjGFOqj1swrM0yoX5y6LY5oXPc3Mu35xeitn_paqtGPkvuH6WeGzAiNZFDoQkUdLkZ4SIH2lr4ZXmMI3nuTzCrwyshwcEu-hhVtGAEQEqVrIn8J75IzYTs1UGLBvhmcpHxCfG04MFNoVf-EPI4SgjNEgV61861TYshxCRrydVhaJmbLqYh8yzLYBHK6oIymv-BrIJ0LX222LwoGbSc0gMTMaudtthlFXrHdnswKf81ubhF7viiD3Y=', provider_name='openai', ), TextPart( content=IsStr(), id='msg_0083938b3a28070e0068fabd989bb481a08c61416ab343ef49', ), ], usage=RequestUsage(input_tokens=1207, output_tokens=535, details={'reasoning_tokens': 320}), model_name='o4-mini-2025-04-16', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_0083938b3a28070e0068fabd81970881a0a1195f2cab45bd04', finish_reason='stop', ), ] ) messages = result.all_messages() result = await agent.run('What packages does the repo contain?', message_history=messages) assert result.new_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='What packages does the repo contain?', timestamp=IsDatetime(), ) ], instructions='You are a helpful assistant.', ), ModelResponse( parts=[ ThinkingPart( content='', id='rs_0083938b3a28070e0068fabd9de42881a08fbb49a65d0f9b06', signature='gAAAAABo-r2izZacxe_jVh_p3URhewxBJuyLNqkJOd0owsDPt9uCE7MXn06WHhO_mp6gLDAqcF1uhMhXCqwztJ1Nbpc0cEDAxUpUCUn2bKSgG6r8Snc_FPtKGgQWDsByvW_Nigx55CyPuNeDO_MiDgYee_WeUw7ASLPfiGOx_9YNc_BFYo1ngsb8CKZcJn3AoponMheLoxkVAPgOjMgteRVaQTr13MljTDUlBIZLIOhVbtIu_dI23saXPigbgwR4RhGn5mCHG_a9ILNkXDJUmGy5TKklIEi2HuJM3ZJ3gfoGYS3OONvzmU4AgMP2UrU17YKZAYKxUBKSpyAqigd4RJSYWzxBCoYzCTmiITwdZ6Cpsw1X9Wox_TQSGt5G2Xu0UY2TQZGRNNH8knJpWs-UQxBBV4L3alMwJuIeV-uzqeKr5fKO5rL_c9as-qQIW_EGQItjvR5z80Hi-S9VXthWCmtqZFIJkgLB5JfTYuFL86valsFVLzSavUIWJAG5qOcxag2mbZMwMRRNfvR__BBtoqBoeGIqveQAbIeZbG0ymw30PH1a2v1mmSrpkK6PB3AHYRDdpkezXLkbyGYgidyV2DAAtPaFplsubWCh_74UxmOuk4BH-9cWkE15mRUBrvtnbTb793RsPzOe7nPmkMpdgqa3nqc6RcQZ_M30lFLUViAbfpEpMVrCzz2cv1RklT1JUzpuVXBTKqQ4FxVCfnvzSgQ2INQ8K50E1X5w_7TAWhrHbNg6LetCa-4KWe9ps0GH6r1x9FWvGyVxSwa7SIdPq3sGpxjOydluPECbBOnHWFUB-3rI2DcUl4rGWYbv2FEFNeCH9Zr67uUvMc4Doi8nVMoeb1lJxFCrfziGhbEXY0FepH3zIzlj-_dXqLAL1qqhfCznT_xkDMVYg-D5gMu-_p3r2SirjJbeaz5UFmP-Dihd9v7jWgD6hx_Mq1uIdzIPE8ImGiDPR7PK64svkvwYg1Czdrc_7GmrKRuzsBL0720UXe19NQqCZfYvUJAjgbEqr3tuS_RkhuEQeeVORn88xkhkrGCEgBS0LHFpe4tcnUEXKnaYYRnoYtk5xo4EyOGVKR2yhF9ht2zrMTo83YuRAPcNT38Jk4gMtVhBaJw_GOfee-IWN_F258rpmU4p8sRV-1iSuQI3Arm4JBU66QuyjoY-KJmTcE9ft3Bfm9If3yG5W0RFRJrsVb--GjHmiiXDGWiR5Q8L1of_RnSD5QDEbXXxhn4dsDejtCXUaQXE9Ty-NvkvA7G6Ru8cMvIKqP2fXS9SmiW6ePJ2Znrlyafxx6L58pT26RF42h90BVrSldf6SjxQApK3AKZW6q8AkuJnYWTtkR9-qfIDl7W94BsgOFoEd-SDQGxWzGJV9YqAu6_SQKiNDQoZZHrJkRSOPEW_b3-BAdrpwL700I92Rye4-BdhlgeK1RwhT3w1Z-z1tvGZXJtPwdpPa3iIw2TIlesMbC1ZJ22iT3CB_r0lnlZhMtIH6o50l50UGfSDuv8HZ_RNgGnYEPqP3FW-o_VD_Yu_KBqGSA0Eb5xAJjl0vpin2vFGO1P4RdgI17eZXRsCp1KvkpWjbEQTWAvJz39yr7wFQ4BrPfgxUqMP0-ZI_h1DkdPBzWs1uKqHw-4qC77sZXgxgHGEIU1tfKosTy_fK4c-WAbdqIHNTh9VdlM1EdrUJQ4rs2rsUG8o9WXwnGTFchI9Ao64LiCFTFTiFL_dvKI4ZraNNXXprfPhxsdLBaNfgj2CIfUwBMJ9xMGmHKQKLtwZdHpQNVqi8DNm1qjvs3CxbSXGKtkl5K8UhJtI1g4OnEnbq3jDO8DGIyDl0NH-0bcCDqS2yAkh8I3IobzxTg16mqU3roXLQ4pGXnWbx26A_9zb4Y1jV7rzCq24VIfNJzMUtW4fVMYzlrp3X1l32I5hF3YP-tU2paD98xobgc2Cn2RWXd3OirrdjKAE088KhXYLZZY59y4LYRLC6MDMHSX0cbEXbBvl6mKmbaFig2_7ICiSa7rR_Ij6PpQRxIW7NfS7ZMu5w7TnhLJyg5nuwMI8A5pVxfy3gYg2L60wepuX7UUV0USaHNKi8qxbp4RJj4nO-GdE8TbLJtvPw-OzrH9Qiv7iDHVMHOe1CDPLD5IeGqmVB0tuLqlyASuIe3oPxTU7QdctyxHa1z-sO8nN6kpPnzmVmS6XK8bY-h5do28dkZvefomSquXwKeiVg9VAMWVziKLPWWg5iWp2x-spLkWcQsQle2T7xizyETaF1t6YbecXtSoVFmu90_o6ns07etU3RVK1YpQLgqUIJwwF3ZwP65MaWPwqDuWCuoQErlApdhRptxId67KE3UC4j8cAaGSoG0kXnws-jzpPyAg1GU8c-Gu_K0F-h-KFbHPMiWCrrQqzVfvoA2wLaQz3NPAqpq-kbFmrXRGkzLIeIvRVxck-sKkxQIcg3amSV5Dykl-lRCXGxlWNiFG_1SFrTSfp5VKyg7l1KjJzXUXHtqAErsPtMyhxaMmlh4An5a8NIaM9W6tafJrBXpUh85DfwZ8W92OAi1WOgoJIwWXSSeSuo6ECDstjVWW3OQQh9183jliwS7Bis3eu9jgAF3q8sYILBdwjrJRa6aAna2GirNwqZMEIg60kIlvmf1U6S2PgYaPm9UDzvMxjpzwjhXhzxHJitfU1tfl0vo-ATaTV8CxmKerNzy2AjlIZnjknG3xLyonCHbGbAe33QQTclb98y_vr5nA4WKlrls413o0a0f8GL8GjINCOd1RHVMjV', provider_name='openai', ), TextPart( content="""\ The monorepo is organized into these main packages: \n\ • pydantic-ai-slim\u2003– core agent framework (type-safe agents, model interface, tooling) \n\ • pydantic-evals\u2003\u2003– evaluation system (datasets, metrics, evaluators, reports) \n\ • pydantic-graph\u2003\u2003– graph-based execution engine (state-machine orchestration) \n\ • clai\u2003\u2003\u2003\u2003\u2003\u2003\u2003– CLI for scaffolding and running agents \n\ • examples\u2003\u2003\u2003\u2003– sample apps & demos showing real-world usage\ """, id='msg_0083938b3a28070e0068fabda04de881a089010e6710637ab3', ), ], usage=RequestUsage(input_tokens=1109, output_tokens=444, details={'reasoning_tokens': 320}), model_name='o4-mini-2025-04-16', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_0083938b3a28070e0068fabd9d414881a089cf24784f80e021', finish_reason='stop', ), ] ) async def test_openai_responses_model_mcp_server_tool_stream(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel('o4-mini', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent( m, instructions='You are a helpful assistant.', builtin_tools=[ MCPServerTool( id='deepwiki', url='https://mcp.deepwiki.com/mcp', allowed_tools=['ask_question', 'read_wiki_structure'], ), ], ) event_parts: list[Any] = [] async with agent.iter( user_prompt='Can you tell me more about the pydantic/pydantic-ai repo? Keep your answer short' ) as agent_run: async for node in agent_run: if Agent.is_model_request_node(node) or Agent.is_call_tools_node(node): async with node.stream(agent_run.ctx) as request_stream: async for event in request_stream: if ( isinstance(event, PartStartEvent) and isinstance(event.part, BuiltinToolCallPart | BuiltinToolReturnPart) ) or (isinstance(event, PartDeltaEvent) and isinstance(event.delta, ToolCallPartDelta)): event_parts.append(event) assert agent_run.result is not None messages = agent_run.result.all_messages() assert messages == snapshot( [ ModelRequest( parts=[ UserPromptPart( content='Can you tell me more about the pydantic/pydantic-ai repo? Keep your answer short', timestamp=IsDatetime(), ) ], instructions='You are a helpful assistant.', ), ModelResponse( parts=[ BuiltinToolCallPart( tool_name='mcp_server:deepwiki', args={'action': 'list_tools'}, tool_call_id='mcpl_00b9cc7a23d047270068faa0e29804819fb060cec0408ffbcd', provider_name='openai', ), BuiltinToolReturnPart( tool_name='mcp_server:deepwiki', content={ 'tools': [ { 'input_schema': { 'type': 'object', 'properties': { 'repoName': { 'type': 'string', 'description': 'GitHub repository: owner/repo (e.g. "facebook/react")', } }, 'required': ['repoName'], 'additionalProperties': False, '$schema': 'http://json-schema.org/draft-07/schema#', }, 'name': 'read_wiki_structure', 'annotations': {'read_only': False}, 'description': 'Get a list of documentation topics for a GitHub repository', }, { 'input_schema': { 'type': 'object', 'properties': { 'repoName': { 'type': 'string', 'description': 'GitHub repository: owner/repo (e.g. "facebook/react")', }, 'question': { 'type': 'string', 'description': 'The question to ask about the repository', }, }, 'required': ['repoName', 'question'], 'additionalProperties': False, '$schema': 'http://json-schema.org/draft-07/schema#', }, 'name': 'ask_question', 'annotations': {'read_only': False}, 'description': 'Ask any question about a GitHub repository', }, ], 'error': None, }, tool_call_id='mcpl_00b9cc7a23d047270068faa0e29804819fb060cec0408ffbcd', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_00b9cc7a23d047270068faa0e4cd5c819f8855c183ff0fe957', signature='gAAAAABo-qDma-ZMjX6meVDoCLYMqgkbQoEVzx_VFnmBFRLqsq37MiF7LP1HrMpqXqtrZ0R2Knb6lUiGSKhsOjOUAn9IFNUCuJx23cPLObF2CKt86wGLb7vccbCrp8bx-I6-kUtZASjlJx7_eJnvwyr24FLZlaDyGDuqRecGA8H4tXnQSAQTT9fJqy8h8dXvxvYzNj5rgOUWgRGn1NBph164KpiEzVWHADzZ_K0l4fX-DFHgtNFssPDYqOKLs_nU0XO8xaIZOgJ8QTf0XmHYF02GA_KciV6sIlSzVricQkwmu1XfJbjpME8XmRMIzlnLRqC8SAJs2kiaYnA8ObfI-s0RbRd3ztIUrzmAsdeo13ualD3tqC1w1_H6S5F47BB47IufTTbpwe_P6f5dLGpOzcrDPbtfHXv-aAW5YEsGyusXqxk51Wp7EONtADmPmVLJffFbRgnwfvPslbxxpNGfxNkN2pIs3U1FW7g1VvmxUfrF84LJpPKvs3xOaWXGorrPBY5nUyeRckhDFt6hGdS59VICmVy8lT4dL_LNswq7dVRS74HrrkfraXDDm2EhL2rtkwhiMqZtuYFsyIK2ys0lZuhNAkhtfgIoV8IwY6O4Y7iXbODxXUr48oZyvLdgV2J2TCcyqIbWClh3-q8MXMmP5wUJdrqajJ8lMVyhQt0UtMJKyk6EWY1DayGpSEW6t8vkqmuYdhyXQOstluONd31LqnEq58Sh8aHCzrypjcLfjDRo5Om1RlxIa-y8S-6rEIXahcJCX_juSg8uYHzDNJffYdBbcLSVQ5mAVl6OM9hE8gHs7SYqw-k-MCeoYsZwt3MqSV7piAu91SMZqB0gXrRDD67bdhmcLBYKmZYKNmLce60WkLH0eZMPSls-n2yyvmwflJA---IZQZOvYXpNUuS7FgMrh3c7n9oDVp15bUgJ8jDx6Mok4pq9E-MHxboblGUpMlFCJDH3NK_7_iHetcqC6Mp2Vc5KJ0OMpDFhCfT3Bvohsee5dUYZezxAkM67qg0BUFyQykulYLHoayemGxzi1YhiX1Of_PEfijmwV2qkUJodq5-LeBVIv8Nj0WgRO-1Y_QW3AWNfQ80Iy6AVa8j9YfsvQU1vwwE9qiAhzSIEeN1Pm2ub8PaRhVIFRgyMOLPVW7cDoNN8ibcOpX-k9p_SfKA9WSzSXuorAs80CTC9OwJibfcPzFVugnnBjBENExTQRfn4l7nWq-tUQNrT4UNGx-xdNeiSeEFCNZlH50Vr5dMaz5sjQQEw_lcTrvxKAV5Zs1mtDf6Kf29LkqhuUEdlMLEJwnAdz2IHLIy41zWLQctSnzBl9HB3mkw8eHZ1LdaRBQRFH4o7Rumhb3D1HdIqDLWeE3jkA6ZBAh2KadGx1u3AIIh4g3dHUS6UREkmzyRIuImbdTsoin1DrQbuYbaqZwIqU4TTIEmA8VeohMfff0rIL5yyFy7cfgGYurgAyMhARPGAAMAoTrR8ldWwymzPkGOJ_SQlzfNGV8weHOEYUl2BgQe57EDX4n1Uk294GIbvGR7eLRL_TLBUyHQErCaOCi8TkBNlLXIobw4ScN_jqqtURmC0mjRDVZeBi6hfrVShWChpQR8A2HxxHrcuHi2hi_2akgUea3zz6_zbUYVoIRdOa9DvZuN015E8ZSL-v_1_vOzUGvt0MuWPazjiRDWgpgcISYzT8N-Xzu_EbwO1OsaOFIeUqrD8mZ6MKOuBQts68og0DWo8KQaHmCaWi4O-c8-5fbB2q3H6oiIoZtSJIoowAmFGOwyWxn_OPS9svDgEaeFYEYhXZ5wZDphxoHkjJ703opxrWoEfQw==', provider_name='openai', ), BuiltinToolCallPart( tool_name='mcp_server:deepwiki', args='{"action":"call_tool","tool_name":"ask_question","tool_args":{"repoName":"pydantic/pydantic-ai","question":"What is the pydantic/pydantic-ai repository about?"}}', tool_call_id='mcp_00b9cc7a23d047270068faa0e67fb0819fa9e21302c398e9ac', provider_name='openai', ), BuiltinToolReturnPart( tool_name='mcp_server:deepwiki', content={ 'error': None, 'output': """\ The `pydantic/pydantic-ai` repository is a Python agent framework designed to simplify the development of production-grade applications using Generative AI . It aims to bring the ergonomic developer experience and type-safety philosophy of Pydantic and FastAPI to AI agent development . ## Core Purpose and Features The framework focuses on providing a robust and type-safe environment for building AI agents . Key features include: * **Type-safe Agents**: Agents are generic `Agent[Deps, Output]` for compile-time validation, leveraging Pydantic for output validation and dependency injection . * **Model-agnostic Design**: It supports over 15 LLM providers through a unified `Model` interface, allowing for easy switching between different models and providers . * **Structured Outputs**: Automatic Pydantic validation and reflection/self-correction ensure structured and reliable outputs from LLMs . * **Comprehensive Observability**: Integration with OpenTelemetry and native Logfire provides real-time debugging, performance monitoring, and cost tracking . * **Production-ready Tooling**: This includes an evaluation framework (`pydantic-evals`), durable execution capabilities, and various protocol integrations like MCP, A2A, and AG-UI . * **Graph Support**: It provides a way to define graphs using type hints for complex applications . ## Framework Architecture The framework is structured as a UV workspace monorepo, containing several packages . ### Core Packages * `pydantic-ai-slim`: Contains the core framework components such as `Agent`, `Model`, and tools . * `pydantic-ai`: A meta-package that includes all optional extras . ### Supporting Packages * `pydantic-graph`: Provides the graph execution engine with `Graph` and `BaseNode` . * `pydantic-evals`: An evaluation framework for datasets and evaluators . * `examples`: Contains example applications . * `clai`: Provides a CLI interface . ## Agent Execution Flow The `Agent` class serves as the primary orchestrator . Agent execution is graph-based, utilizing a state machine from `pydantic_graph.Graph` . The execution involves three core node types: * `UserPromptNode`: Processes user input and creates initial `ModelRequest` . * `ModelRequestNode`: Calls `model.request()` or `model.request_stream()` and handles retries . * `CallToolsNode`: Executes tool functions via `RunContext[Deps]` . The `Agent` provides methods like `run()`, `run_sync()`, and `run_stream()` for different execution scenarios . ## Model Provider Support The framework offers a unified `Model` abstract base class for various LLM providers . This includes native support for providers like OpenAI, Anthropic, Google, Groq, Mistral, Cohere, and Bedrock . Additionally, many OpenAI-compatible providers can be used with `OpenAIChatModel` . ## Tool System Tools are registered using the `@agent.tool` decorator . The system automatically generates JSON schemas from function signatures and docstrings, validates tool call arguments, and provides context injection via `RunContext[Deps]` . ## Observability Integration Pydantic AI integrates with OpenTelemetry, allowing for instrumentation of agent runs, model requests, and tool executions . It has native integration with Pydantic Logfire for enhanced monitoring and visualization . ## Evaluation Framework The `pydantic-evals` package provides a framework for systematically testing and evaluating AI systems . It supports defining datasets with `Case` objects and using various evaluators, including built-in and custom ones . ## Integration Ecosystem Pydantic AI supports various integrations for development and production: * **Model Context Protocol (MCP)**: For external tool server access . * **AG-UI Protocol**: For interactive application frontends . * **Agent2Agent (A2A)**: For multi-agent communication and workflows . * **Temporal**: For durable workflow execution . * **DBOS**: For database-backed execution and state persistence . ## Notes The `CLAUDE.md` file provides guidance for Claude Code when working with the repository, including development commands and an overview of core components and design patterns . The `mkdocs.yml` file defines the structure and content of the project's documentation, including navigation, plugins, and watch directories for various packages . The `docs/install.md` file details how to install the `pydantic-ai` package and its optional components, including a "slim" installation option for specific model dependencies . Wiki pages you might want to explore: - [Overview (pydantic/pydantic-ai)](/wiki/pydantic/pydantic-ai#1) View this search on DeepWiki: https://deepwiki.com/search/what-is-the-pydanticpydanticai_e234e9cf-d4aa-4c67-a257-56034816dd56 """, }, tool_call_id='mcp_00b9cc7a23d047270068faa0e67fb0819fa9e21302c398e9ac', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_00b9cc7a23d047270068faa0f4ff54819f9fb9ff25bebe7f5f', signature='gAAAAABo-qD2WTMmhASwWVtFPlo7ILZP_OxHfRvHhda5gZeKL20cUyt0Np6wAHsJ6pyAsXCkLlKBVz3Vwm52JrJuUbqmw-zlXL19rbpvTPRMkiv_GdSfvmxKKNJvSm417OznBDVjsIAqmes2bMq03nRf6Pq2C0oUJnIbpbMwtWzs3jMQqUb0IwyopqXGhn3MWKctLPKZS89nyL4E9kJAx_TyWTQvME8bf8UrV8y2yrNz9odjSQQyZq5YXrlHzpOJjDTfLofVFjsEzM8J29SdLcWnqlv4djJ8xeMpP2ByXuHRnTEyNNuxpYJB7uQbYT0T_eLhwcLv2ZzDZ_hf2Msv7ZdyuPc7Yxc5YWlChB0iaHqQ_8UuMjIVurfgSIjSq2lTvJwdaA365-ZoBMpo4mG04jQDP3XM-0xEM6JTFWc4jZ1OjIXVpkjaXxdOOkYq3t3j8cqBQH69shFCEQr5tnM8jOEl3WHnkvaBg4xEMcd61hiLOKnWbQiYisbFucA8z5ZNbdohUZd-4ww0R8kSjIE5veiyT66gpIte0ItUnTyhIWy8SZYF9bnZGeS-2InDhv5UgjF2iXzgl6dmUrS-_ITgJkwu4Rdf9SBDJhji3_GUO9Za0sBKW8WohP142qY0Tbq4I6-7W1wJ3_gHJqiXVwDLcY90ODSyyC5_I3MgaALRC1wt55sHSeSsDjmNGmiH-m0snaqsI0JnAZwycnWCK17NamjQ9SxVM5tTqJgemkGFQNH1XhZPWvVj56mlj74KKbCJALQpdXD27C8LfdrlBd0v_zEmF1dh7e12I95fYeAlO51xOglBaMCgcMWSDHMGHsJBbJ04eVQSwYTl72rmkASTMaybD-aAm1m8qZnKU-f3xQradhs9l1x9eOfQDIsfWMr1aVMiZi59--VsrgYCbqBj7AGf8n6VNbQWkhO2etozwYZcdGIyiu4TaULX1Xp89Gb28M-tVkIrkQoHO_Z7wzKU1HRBViES1wRKUJ-Sa6wc8UP5orDxeOTFPUr7JL-qaj49cpKzvdlfuoIdbYwpsNvAg69sNbFI3w4jLxOT4yxS6thra1Bit6SY5wAEfrrjtzofLeg49aFqFVGIHeJ8kE3spc1rctpETkdHNyP9fEjZaM3mxR4yz0tPmEgUsd-sdw5BbOKDAVzwconmbeGBmf9KLXMEpRRH7-qSIWUscCi5qIdHXGYoQkStsNGrnhucn_hwqZCSti3Kbzfosud3zQPjW6NyuJCdeTxbDbsnrV7Lkge5j92pyxCHw9j0iuzofRW55_KToBtIvRoPr_37G_6d6TxK42mKqdbgk9GHrcXf27mXszCEzX-VfRVTxyc6JLfEy1iikdo-J2AzXPd4m3zE-zazBU3Z5ey596g8gxwXMkHakLrvwp4_-fQfcvs7sIH34xkEhz7BRdNok3Aqbu_zCt2np69jjHqfPQWZzAy1C-bmMuhAaItPYkkw-LgSu-YP6L89zNofK9Q_S3JwVsLN-fq-9OwhSjy_rQu22Gn4KD6saAu61QMXBPa6z0QJSFUZHJQ_megq1tENfB6wRVtQ0DdAvUwhUsMwx6yE9CT20bma4CloGW__aZuD9gikdQrQ1DCHOvTrfEpvHkl6-wuCImeNjsCvbRFAkx6Xgpc6fdbq4j6WyEVW_4VePNknFWYZ1cw795ka5uJMLc3hVughVlGwDbw60Q3utsjHPbu03pxPle5pdcVEYSQWa0WbFDCrF4ysK0lpmlF7', provider_name='openai', ), TextPart( content=IsStr(), id='msg_00b9cc7a23d047270068faa0f63798819f83c5348ca838d252', ), ], usage=RequestUsage(input_tokens=1401, output_tokens=480, details={'reasoning_tokens': 256}), model_name='o4-mini-2025-04-16', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_00b9cc7a23d047270068faa0e25934819f9c3bfdec80065bc4', finish_reason='stop', ), ] ) assert event_parts == snapshot( [ PartStartEvent( index=0, part=BuiltinToolCallPart( tool_name='mcp_server:deepwiki', args={'action': 'list_tools'}, tool_call_id='mcpl_00b9cc7a23d047270068faa0e29804819fb060cec0408ffbcd', provider_name='openai', ), ), PartStartEvent( index=1, part=BuiltinToolReturnPart( tool_name='mcp_server:deepwiki', content={ 'tools': [ { 'input_schema': { 'type': 'object', 'properties': { 'repoName': { 'type': 'string', 'description': 'GitHub repository: owner/repo (e.g. "facebook/react")', } }, 'required': ['repoName'], 'additionalProperties': False, '$schema': 'http://json-schema.org/draft-07/schema#', }, 'name': 'read_wiki_structure', 'annotations': {'read_only': False}, 'description': 'Get a list of documentation topics for a GitHub repository', }, { 'input_schema': { 'type': 'object', 'properties': { 'repoName': { 'type': 'string', 'description': 'GitHub repository: owner/repo (e.g. "facebook/react")', }, 'question': { 'type': 'string', 'description': 'The question to ask about the repository', }, }, 'required': ['repoName', 'question'], 'additionalProperties': False, '$schema': 'http://json-schema.org/draft-07/schema#', }, 'name': 'ask_question', 'annotations': {'read_only': False}, 'description': 'Ask any question about a GitHub repository', }, ], 'error': None, }, tool_call_id='mcpl_00b9cc7a23d047270068faa0e29804819fb060cec0408ffbcd', timestamp=IsDatetime(), provider_name='openai', ), ), PartStartEvent( index=3, part=BuiltinToolCallPart( tool_name='mcp_server:deepwiki', tool_call_id='mcp_00b9cc7a23d047270068faa0e67fb0819fa9e21302c398e9ac', provider_name='openai', ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta='{"action":"call_tool","tool_name":"ask_question","tool_args":', tool_call_id='mcp_00b9cc7a23d047270068faa0e67fb0819fa9e21302c398e9ac', ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta='{"repoName":"pydantic/pydantic-ai","question":"What is the pydantic/pydantic-ai repository about?"}', tool_call_id='mcp_00b9cc7a23d047270068faa0e67fb0819fa9e21302c398e9ac', ), ), PartDeltaEvent( index=3, delta=ToolCallPartDelta( args_delta='}', tool_call_id='mcp_00b9cc7a23d047270068faa0e67fb0819fa9e21302c398e9ac' ), ), PartStartEvent( index=4, part=BuiltinToolReturnPart( tool_name='mcp_server:deepwiki', content={ 'error': None, 'output': """\ The `pydantic/pydantic-ai` repository is a Python agent framework designed to simplify the development of production-grade applications using Generative AI . It aims to bring the ergonomic developer experience and type-safety philosophy of Pydantic and FastAPI to AI agent development . ## Core Purpose and Features The framework focuses on providing a robust and type-safe environment for building AI agents . Key features include: * **Type-safe Agents**: Agents are generic `Agent[Deps, Output]` for compile-time validation, leveraging Pydantic for output validation and dependency injection . * **Model-agnostic Design**: It supports over 15 LLM providers through a unified `Model` interface, allowing for easy switching between different models and providers . * **Structured Outputs**: Automatic Pydantic validation and reflection/self-correction ensure structured and reliable outputs from LLMs . * **Comprehensive Observability**: Integration with OpenTelemetry and native Logfire provides real-time debugging, performance monitoring, and cost tracking . * **Production-ready Tooling**: This includes an evaluation framework (`pydantic-evals`), durable execution capabilities, and various protocol integrations like MCP, A2A, and AG-UI . * **Graph Support**: It provides a way to define graphs using type hints for complex applications . ## Framework Architecture The framework is structured as a UV workspace monorepo, containing several packages . ### Core Packages * `pydantic-ai-slim`: Contains the core framework components such as `Agent`, `Model`, and tools . * `pydantic-ai`: A meta-package that includes all optional extras . ### Supporting Packages * `pydantic-graph`: Provides the graph execution engine with `Graph` and `BaseNode` . * `pydantic-evals`: An evaluation framework for datasets and evaluators . * `examples`: Contains example applications . * `clai`: Provides a CLI interface . ## Agent Execution Flow The `Agent` class serves as the primary orchestrator . Agent execution is graph-based, utilizing a state machine from `pydantic_graph.Graph` . The execution involves three core node types: * `UserPromptNode`: Processes user input and creates initial `ModelRequest` . * `ModelRequestNode`: Calls `model.request()` or `model.request_stream()` and handles retries . * `CallToolsNode`: Executes tool functions via `RunContext[Deps]` . The `Agent` provides methods like `run()`, `run_sync()`, and `run_stream()` for different execution scenarios . ## Model Provider Support The framework offers a unified `Model` abstract base class for various LLM providers . This includes native support for providers like OpenAI, Anthropic, Google, Groq, Mistral, Cohere, and Bedrock . Additionally, many OpenAI-compatible providers can be used with `OpenAIChatModel` . ## Tool System Tools are registered using the `@agent.tool` decorator . The system automatically generates JSON schemas from function signatures and docstrings, validates tool call arguments, and provides context injection via `RunContext[Deps]` . ## Observability Integration Pydantic AI integrates with OpenTelemetry, allowing for instrumentation of agent runs, model requests, and tool executions . It has native integration with Pydantic Logfire for enhanced monitoring and visualization . ## Evaluation Framework The `pydantic-evals` package provides a framework for systematically testing and evaluating AI systems . It supports defining datasets with `Case` objects and using various evaluators, including built-in and custom ones . ## Integration Ecosystem Pydantic AI supports various integrations for development and production: * **Model Context Protocol (MCP)**: For external tool server access . * **AG-UI Protocol**: For interactive application frontends . * **Agent2Agent (A2A)**: For multi-agent communication and workflows . * **Temporal**: For durable workflow execution . * **DBOS**: For database-backed execution and state persistence . ## Notes The `CLAUDE.md` file provides guidance for Claude Code when working with the repository, including development commands and an overview of core components and design patterns . The `mkdocs.yml` file defines the structure and content of the project's documentation, including navigation, plugins, and watch directories for various packages . The `docs/install.md` file details how to install the `pydantic-ai` package and its optional components, including a "slim" installation option for specific model dependencies . Wiki pages you might want to explore: - [Overview (pydantic/pydantic-ai)](/wiki/pydantic/pydantic-ai#1) View this search on DeepWiki: https://deepwiki.com/search/what-is-the-pydanticpydanticai_e234e9cf-d4aa-4c67-a257-56034816dd56 """, }, tool_call_id='mcp_00b9cc7a23d047270068faa0e67fb0819fa9e21302c398e9ac', timestamp=IsDatetime(), provider_name='openai', ), ), ] ) async def test_openai_responses_model_mcp_server_tool_with_connector(allow_model_requests: None, openai_api_key: str): m = OpenAIResponsesModel( 'o4-mini', provider=OpenAIProvider(api_key=openai_api_key), ) agent = Agent( m, instructions='You are a helpful assistant.', builtin_tools=[ MCPServerTool( id='google_calendar', url='x-openai-connector:connector_googlecalendar', authorization_token='fake', description='Google Calendar', allowed_tools=['search_events'], ), ], ) result = await agent.run('What do I have on my Google Calendar for today?') assert result.all_messages() == snapshot( [ ModelRequest( parts=[ UserPromptPart(content='What do I have on my Google Calendar for today?', timestamp=IsDatetime()) ], instructions='You are a helpful assistant.', ), ModelResponse( parts=[ BuiltinToolCallPart( tool_name='mcp_server:google_calendar', args={'action': 'list_tools'}, tool_call_id='mcpl_0558010cf1416a490068faa0f9679481a082dc4ac08889f104', provider_name='openai', ), BuiltinToolReturnPart( tool_name='mcp_server:google_calendar', content={ 'tools': [ { 'input_schema': { 'properties': { 'calendar_id': { 'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "The ID of the calendar to search. Default one is 'primary'", 'title': 'Calendar Id', }, 'max_results': {'default': 50, 'title': 'Max Results', 'type': 'integer'}, 'next_page_token': { 'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'title': 'Next Page Token', }, 'query': { 'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'title': 'Query', }, 'time_max': { 'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Time in the ISO-8601 format. You can also use 'now' or leave null.", 'title': 'Time Max', }, 'time_min': { 'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Time in the ISO-8601 format. You can also use 'now' or leave null.", 'title': 'Time Min', }, 'timezone_str': { 'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Timezone of the event. Default is 'America/Los_Angeles'", 'title': 'Timezone Str', }, }, 'title': 'search_events_input', 'type': 'object', }, 'name': 'search_events', 'annotations': {'read_only': True}, 'description': 'Look up Google Calendar events using various filters.', } ], 'error': None, }, tool_call_id='mcpl_0558010cf1416a490068faa0f9679481a082dc4ac08889f104', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_0558010cf1416a490068faa0fb684081a0a0b70f55d8194bb5', signature='gAAAAABo-qEE669V-_c3vkQAeRtSj9pi72OLJweRJe4IRZkLcFfnuwdxSeJM5DVDLzb3LbfzU0ee6a4KAae0XsETU3hELT1hn3LZPwfFku5zl7CVgsc1DmYBf41Qki1EPHFyIlMj937K8TbppAAqMknfLHHwV1FLb8TapccSEhJbzGutqD3c2519P9f6XHKcuDa8d-sjyUejF0QuSjINFcjifJ8DiU40cL_-K6OJotlx6e0FqOivz6Nlj13QZxQ0I3FiiSi03mYKy240jYMpOpjXr7yPmEXLdCJdP5ycmTiJLxf4Bugww6u4F2uxy22978ACyFGSLHBiQyjczj_can7qKXAkMwYJKcGNjaNi8jG5iTIwsGswRjD1hvY-AGUotMFbPCszX3HW1M_ar-livaheiZauCfKV-Uc1ZeI3gijWEwtWQ0jye29FyQPCCpOBvT6RbUvFEpfqpwcMQuUhOyEfgzli2dpuOAgkSjCPE6ctoxjbYa62YzE-yrXAGc5_ptQy_2vw7t0k3jUzSo2Tv0aKnqvvKcj9SIilkZV4Nf-TL_d2E7d48bBJDlqbAv7fkhhd2YlkLqwdR1MqZtygcR1Jh8p2Y1pFAa4mSj7hh4M-zfSu--6dij2iKIbnKQ4DbXyGpMZXBAqTHMe9PPOwGxWKShlN5a5T89B04d_GwJYBDJx2ctecqZxDMjkTn3wVGl_5wuDnrEgd0I91vmAoYuWldR_h8M_FjDFiHefdbZjw1TxVKjkp6wk6zQiXCvvCZYJa9XkhytcllWvUI4C0gbxHrEzZRy9Vii3buqnbiIM9Qj0VPx-Q-FKM_usZBBmlvmk9PMQ8rH9vVT8dRFNQEj-aqudB5yUcTx8XaUFwYAts04OObGBqXoazYtxh6WvHwrf09pb_g0dwzE_rlcQdYxcFLOpYD-AentRAjOuIr4bLRM9BMERBxPvvPCxZ2Mva8YqV2TIOtxzMY08freim6du1IuYprO6CoejPaBdULhct-nsPubOdjLBikZt_bwumvmqGXnxI_uu51b9HtzPeDpWIjF6pi88bcsOk0qglA9GAu3wwX-iIdaV19VdVCO4KJjxiVrbTY1IVgWSdz98Alb_HzpXsoS6i2PRAjjsYOe4RBX3etxjsY07XXLlmXAM_vuYXc8Y6STxvBk4ST4OkaCvUk9DoZbVL5KmVcT6TaFpbVCOB_eHkHIvMjXc35kzxCdqEMG3FpRzL_UkY8pPridvq2z1Xw0al2KEBvdKPlInB8-zX5ANGeRkMGZ6ZfyX1zCIdYLe3wrC8xqr5nUZ-ueWmtqYLavSg8mQKphp4QyVaiwtbxEt5GEiVG7_LR754mGQYPdr9Shh3ECAp8wmSfDVO8MHaLmzgo3RXeqlqFldRjQzDHtCaGhjD9bHKF3yWF2LtH4gUN-Sf--86lcq7iwHDSDm656P_FBfYmE7rA0svH-m3hQoBhza4CKJ7s7f7ZymEhcHAfH7SPImZ3Y-kT_Sy1mbCCf3Yg8uitrpX7ukO6_bIANS_R4oiOPcuLixbWY0ZSyq8ERB5fa5EsIUm7PpGxbO96nmk5rPkewyB4gCtslwJI0Ye7zHtqrDBz1j1nsjIKsRCfFWlUdRF8J1JPiiBSvP8SraQ_94cnKBCsl34BGsVm-R1_ULbuyahBzSHq2Kwr0XQuNLdGChyLKS_FZVT58kbRFsvjZnbalAZ-k9alMeZ-pdWX5f9nSn3w7fz675zOxnBaqiZmoWHXFNOBVGH7gkz05ynJ2B8j_RpdRNJKXUN8pAvf595HGl2IPdaDhqoeS2_3jixO5mmxZuPEdzopoBFRarWud99mxH-mYxWJzKiA1pLNqj7SO93p2-jB-jtsCfZfk6bVEWpRRkIEz0XvxffFTVuGUCqpGS7FiFZc4pQU24pCrdpg2w3xeDSrmfHDAx2vUvv0iRBnQxTTWx2-de2TQQTpR5tjFNyOhYGVn1OXqkbkNtIUHdnNGA1QBCU0Qs0471Ss1CrxXIeeNVSTd00jiu4_ELk6nJYgSpmS8G_crrDza8mRLV5Yk0ItRrZj6pwKUOEaYeyM-RHyhrjf09yaf7Qc3sAozQF0aXFCQjSYiVb98DuGH28HLUxW9ulmSKKR4pYKlCOLNGm0h_gWCpSa0H1HXCgEoPn68HyaJogv_xH3k4ERYyJnxu8zVbVPMGoa9q9nNRQQ9Ks2AvxYRQeGFSCTACBmuookvHsO1zjYfHNuSCD7pCLRFE76KlmSiAX6l9LNOq_xe9Oos-1AvcZHkmVsuh-mjTVkBOjG6zmnHiNJirBpORs_UWL5lmlQBeaXgdHxcb4tHIn8XYXFkQiC4b4pw==', provider_name='openai', ), BuiltinToolCallPart( tool_name='mcp_server:google_calendar', args={ 'action': 'call_tool', 'tool_name': 'search_events', 'tool_args': { 'time_min': '2025-10-23T00:00:00', 'time_max': '2025-10-23T23:59:59', 'timezone_str': 'America/Los_Angeles', 'max_results': 50, 'query': None, 'calendar_id': 'primary', 'next_page_token': None, }, }, tool_call_id='mcp_0558010cf1416a490068faa0fdf64481a085a3e5b8f7d6559a', provider_name='openai', ), BuiltinToolReturnPart( tool_name='mcp_server:google_calendar', content={ 'output': None, 'error': { 'code': 500, 'message': 'An unknown error occurred while executing the tool.', 'type': 'http_error', }, }, tool_call_id='mcp_0558010cf1416a490068faa0fdf64481a085a3e5b8f7d6559a', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_0558010cf1416a490068faa0ff5c9081a0b156a84d46e5d787', signature='gAAAAABo-qEE72KCH4RlulMdH6cOTaOQwFy4of4dPd8YlZ-zF9MIsPbumWO2qYlZdGjIIXDJTrlRh_5FJv2LtTmMbdbbECA20AzFMwE4pfNd2aNLC5RhcHKa4M9acC1wYKAddqEOPP7ETVNBj-GMx-tMT_CY8XnBLWvSwPpcfde9E--kSrfsgvRn1umqDsao4sLlAtV-9Gc6hmW1P9CSJDQbHWkdTKMV-cjQ-wZHFCly5kSdIW4OKluFuFRPkrXs7kVmlGnMr8-Q5Zuu1ZOFR9mPvpu2JdxAFohjioM-ftjeBuBWVJvOrIF4nV-yIVHVT-_psAZaPUUB5cyPAtqpoxxIV3iPKPU8DHctP03g_0R6pSWWHhggvO5PBw3zyPwtBwOrHBipc4nQEWEMxZxLH5SYJauTKwHNOx9NyCq8JUjZXM_v4xsGxNa4cAp7GuXqR2YyW2sx7syRUiDwtebh0xk_YOQtkv8tAjzCofmaz3n8FJ2nGSXkilaV5Q8LUNO-9-D2tsAaScDVMuLMMAHFNp_GPplWrmGES4mTCNtTXWyF1GLcQBw8dYYctV66Ocy2_zxyDoB7SsR5htlV77nJ6u1Hbp3tk26LutDrhAhe55xcki8iblHbXNY9MRzR1SS5Zk3-dv0ex4QOzC663NvS9aK3olQbKYko5TvM7Pq4MFYfaxwFTVFVEdaskoDJieVyikz0ZzBjTsItIwL-Q2BVN2F_P_wgCV5hyDclNMPEGTMxajxfIFv-oEunmHY1_RJavl47iXWS8H3JWAvp-9YYQdTS4Aa6m5zPndvHOvEV355UawLHRPctHFUS7rE7rYmcU6KQaqC96JRM0KRfXNIgYtNfw6cxgnyqGxzTF7qeeVzObOqoQmz59Rh0U9ti37vqHb8Ca43-q2Gx2KaVZFj7MBQK8UodfaDRIEuyMB3XNfckxCefwHs7FeAj5NuNDBrm0uDcwJjs2JfY2i54gAES8kAPLGJgRpq_qdjVXqpO6W0H9E1vBdRem7zLPYbA8OOo-KCkRW4AFCVbgCpgIvo4GDNvFOMksl-d8zgQU2qroUWJRu58j1bdaar7Zlfxk0UR33nROmJpXGb_R-RCNAN1ZxJTdEU_dVfyLCeuIXPsnO-FlfO8J6Un3WWPNLuN_bDS5RocniI_ms71qLsisJQiPTs-JDFl-eMM2Hk3QqSCC6OT0CLG9XMmI_zva9yp2joQ8HdGMddE3FDCbLejRrx8fV-9Nd0tZ7SYjFG78_fre8IfL0L67CK1JIPYzhgRZgCb-FFwUy-stR_BstIn0sRr_tDCoHdxuoVCh0dZfTY1p27xbKQ50svHxp1caNp3uze0wLXP9STNouFjFpdIHMsDRaGfO9R9mMmUsFcmBMK3aikuHTpebyL1CeZsIzH2cbZLPRx3pN2IqJ-5h6-cORHuMqf3ysEEFCjXnqmzvWPuBjYDsxnxA1awaGkYKsKhqchgakrfplOjdG5tSkklggBJA93iRaUWIR-4oV6HkkrnpdK1w7BL_VT8upqZmkpHZtZCDSgINk5S5hoYPLBTtS3dcCmQIbLvPXPuGzdAZxl0bhD4Rm3GPDFszaDoFK0Jszcjlaf4SJqyZABKEf71dDbi1as-2Qwr4fxBiQIOsF8ChbYo6Z2iFtUpBnbruFUIwB5QyKfWnwEZbOgf4UbIvIqNMkTzMc8tJgz6Ddqfih8VeNH3v8_84J6vHU0SVm_gvkgQ6P6N_6r5LwNdlAEff0hFwn-aTHWZ3s8MICckUZj97lKoZxAl91WlsKa0yrLw24dxvJ6bhZf0FsOitUJGd7vFPx0TxSobUkzE2RrbQ3hziPxw2Gins4aI6YG3M1gfumd3MgdH-fYBvZulJ9vmw0ZC1Dqh6BkCWHOFKsnpQvHmYuyTzUmnYuJf8N5j_b9XNw0krmxouOCPQClFmIOBLw8XPbe3xf0F5JP7BC0PpjlPT33A5Z6Za5zlA5O-DE_Wp0WG885-GaKtZI-zBZW3R0lc9A4s0HbxqA3lqH8leXOCe6WO46Z_iTQlALpTR-7oaHqzTegq0KSmEjCFO-jLSrVZnBOQ4ddTvLj4ASsQbj-o6TFUFVZAKSLI3FtWovHw02Gc_D0luFz9TbfaXM-EapEQYajkG0_b_nSCoPq0T9HSyvU4oCxXyQvhwIgzbijR-BheN6a_l6hiqZCw9L1c8MdPRtjpbHtEwWkpQ62s8XdydeJnV5vJYp9ezBbS_vWQ7Nz1siai6epJTdzDkRm-dudVhKzdohwg-FOQ-5gSrvoPS_MF4lZvah3iXY1g4uePO4eNDWGJ74YPybiy', provider_name='openai', ), BuiltinToolCallPart( tool_name='mcp_server:google_calendar', args={ 'action': 'call_tool', 'tool_name': 'search_events', 'tool_args': { 'time_min': '2025-10-23T00:00:00Z', 'time_max': '2025-10-23T23:59:59Z', 'timezone_str': None, 'max_results': 50, 'query': None, 'calendar_id': 'primary', 'next_page_token': None, }, }, tool_call_id='mcp_0558010cf1416a490068faa102400481a09fa35e84bc26c170', provider_name='openai', ), BuiltinToolReturnPart( tool_name='mcp_server:google_calendar', content={ 'output': None, 'error': { 'code': 500, 'message': 'An unknown error occurred while executing the tool.', 'type': 'http_error', }, }, tool_call_id='mcp_0558010cf1416a490068faa102400481a09fa35e84bc26c170', timestamp=IsDatetime(), provider_name='openai', ), ThinkingPart( content='', id='rs_0558010cf1416a490068faa102d89481a0b74cca04bcb8f127', signature='gAAAAABo-qEECuiSxfvrR92v1hkqyCTCWyfmpHSaW-vVouk5mOTIFDvaBZdVTFH8-dJfpwEG3MCejRKh9V-I8mrYAjhudVr1ayHo8UYOOU1cfVc6w3wsrkL8hXljjE-amiJhBSjvRc2nwwGtgYpDxOfWTqJkaUvFnMD6MrS4CwMrCBbDOLYZgM1cQbidtrrtpP7D5u42tR6coC_PCOqwPzDN4f0RggrxVxh0038p81VUmlkUeA2jWzRyFpeDGRjXFk84Og73rXAp7EWQv7TmzgVXBjCVwwzJNU8HCZ_gkwh5dvL94QxBx32lEmfOOKcqA3hN3FLwDqXlZ8f7jEqYInnpILQgX5XMdM9OrCyXmDCr_eIy00cjvxnTcXhCnZBOaKCKmTP74yUpGNdLbQcr4BalTiviNYEeCAhJyRo4KnhUZbBoT7MB5NULf-kqhRo1gEGKjWiLdV47PhR7Z8i4BK7zBceganMKpLtzIMW5a6JAujC4Z9FYxcpJZI_CD9NHsPr4SjKgIwv89d6BYo89-xfflF6ZUZBkuDUnL2-Nc9CKgGuKlcDunvYLr38pzA278OFYzh9T42u4SbS8KkSXKjGU3H8LfpMnBEZigriixLt5vj7qnWmZvCFarzxT4U4qqR1ITp5rkO6G9kYvBEfS7wu768mteDBgAajUaeOMQEfjJRErC4wfzbB89YCsXPJz0JE90QZ5LeiP5ZlVezTTaddG9JmiGsBCPckqUb1LWdpvekCfPkePF_uDMVWyJpQ4ZBzQsZx8sHf5spygsiQjlzTiriqwhoTcPuXoONoCr9HeFX1Qy8SGOm87siRPAD7FHJdDxbJwq8tOlMpx8MH1dqEY07lwoxZB0GQ9XbB7QJXfQR_27nkpqBYFkrbqChNJLO2x8gNFClbB0mgYQE1CRy64y6yOrG3CtS53RK5VGrF1GnqwuWdZ452VgShT5nAmPFRlRk1S9px4eMUTAozT0QAYrlHQC7b6I6K3m_Qe3kXGpnn_87i2eGG8mHmXG2FvFChkgf2OU7-LRy_Wl_u-ataICeoBwfngBFMppvUW6tJP009HK7mUE8P1KJntN3ExKLIBhmKhV6ziBpIi1bSTmd8leYqfSaf648c7-sVuDRx7DzxTp19l3fwVFa67GdiagZFs7xaU1HxMnMc3uy5VKWAH_qcv-Mga3VCTtTPpMTjvB95nsLeOFjS2FtpPvaP0N6o5kkkzW7cteWpOHhSX0z7AQA7CqgOCQLfLUc7ltVxnOH4WdHoeZFah_q_Ue6caf0kNo4YsTfbRDdzsW70o8P5Agr-Pgttg19vTDA_eBFur9GDKIRT0vYMWPpykwJBDTgJKOFW6uyNkqNWk_RAAvleE9pAyOoSmgomyrMcnnpdeYHNxeNxvTWFC3mcKSjJIB316wypPvaGTJyaK_pxJScD7CtLrIPkgwPpOsJnDySF6wGe-fGsUMt3zxJrc-S6fp24mYVfTRZbjUsP0fJgLmCohJiAtEg_xvlQ8sPyuLoLdOdossTQ7ufl0CwVn4f_ol4q__gpTvYVaoGsWl3QmHul5zj7OUAn7of6iBfCSlXbrauJvMyNYt4x_dLM8SXTRNPe-ZMDmER9DOw0KJXcUrpl6uw4TphKmUOK6KrxqshujXdN9VDgOwD7eKqIHpvC_6a2R6sS6ZHcebmh2o3bic-Hctomrbv03OQ==', provider_name='openai', ), TextPart( content=IsStr(), id='msg_0558010cf1416a490068faa103e6c481a0930eda4f04bb3f2a', ), ], usage=RequestUsage(input_tokens=1065, output_tokens=760, details={'reasoning_tokens': 576}), model_name='o4-mini-2025-04-16', timestamp=IsDatetime(), provider_name='openai', provider_details={'finish_reason': 'completed'}, provider_response_id='resp_0558010cf1416a490068faa0f945bc81a0b6a6dfb7391030d5', finish_reason='stop', ), ] ) async def test_openai_responses_requires_function_call_status_none(allow_model_requests: None, openai_api_key: str): model = OpenAIResponsesModel( 'gpt-5', provider=OpenAIProvider(api_key=openai_api_key), profile=replace(openai_model_profile('gpt-5'), openai_responses_requires_function_call_status_none=True), ) agent = Agent(model) @agent.tool_plain def get_meaning_of_life() -> int: return 42 result = await agent.run('What is the meaning of life?') messages = result.all_messages() _, openai_messages = await model._map_messages(messages, model_settings=model.settings or {}) # type: ignore[reportPrivateUsage] assert openai_messages == snapshot( [ {'role': 'user', 'content': 'What is the meaning of life?'}, { 'id': 'rs_01d311e2633707df0068fbac0050ec81a2ad76fd9256abcaf7', 'summary': [], 'encrypted_content': 'gAAAAABo-6wE6H4S9A886ZkwXcvvHqZ6Vx5BtpYvvNAJV5Ijq7pz-mTBJxfdjilNSzBj0ruy7NOsMRMhWzNahRf-n3KDQ2x1p-PjVCHM5IAGqHqae8A-aAUn_FDRiTbAT5N5FXTrZ80DAtdDv17z2HlODmTTYRvBU2-rX7opysjc4rf7-rvy6j4cUcNbM0ntT5DH8UHxC9LCM_s7Cb2unEV0jaDt7NzFxgfWN2u24Avs2EnjPoxOjd6BR-PWHJk_7kGGkVBub8NU7ZOyHsci3T8DAq_eX38DgkHJBJCPT4EqvlNP-VjPdecYEFUCw5G_Pye6h55-77g8LjkrFO43f8p6wscQ0iM601i1Ugmqbzxyv1ogPIN-YuSk2tkCw-D7xBD7I4fum2AmvyN-fR58lWcn-Z0WTqACA4baTJiCtW5b7uVeAp8vm8-gWzFR5BdDHVdQqu1TAKVWl_1P8NauDtd5M24MjVZd6WC0WrbTDPY9i2gieMMjFek2M8aoQFO0CG7r3JHn2zxfFB3THWCpl4VqZAQp6Ok7rymeY0Oayj--OLpNMBXIYUWc51eyYeurwQ943BSkf-m6PPVKO8T5U__Bx-biCNCePSlFKp7V0Du6h7UgYoqqonH2S3Jrg87c6dk7VJ7ca2i8sZqhy0rG6Kb7ENDVvwkMOdpnaFgdWd3VINp6P8j69kBQg-qwWP-YHPC9LnsjT2j1ktMowVO97eOpV4j2BhiThxunmu_SOIAEbghmjJEkLuRxLxBUPFRIajke2CvvFeIuReJr53isPKOxOjVzsc6oG5ZeykDlfz_mfEap7AByPNY0987zwG58tGueNxXjdpd7NQFcn_6DKj60SvUg0sk49V_QrDY3cAhSRvZoEeqA8XR97pEe7CByYMl80b9fzgyahc4NCdUwK8es2ll-lsJwEx1ZGdC8cB45QOrTnw8tJAUsSM44rLKwAQY-KsuN4UygO99d1CQZEm2YWtnPAvA9I-EhY87UIDx0CpPsEyxxFu2GZCTy7ceSnpcmQbAFWXzfBSpM7k42xVV8G8IK_bHpoF1enF5Vbc37_L_aWd4AgzuAwF_RVyd8exVh3NVJtO3BqPv72kTukr2Fok3KEaSeU0whP_dxr-thP2exS0F2Jdn13ZtB_pqxwKVWEsvzdbN92Q9qs10BAgYs2SA4cq66semwRl-1n-dr7XJyZzPOEiA9TQYgUCw0ueIc0ciMOZ0Waaj094bKIylw_TD5Bu1diXpzbTma_AVO-NZn7INhAZN3guSme-zIUEMrh66w0VJP-DbDA-ecSD41eMRSadyV4g86wLL4NOBE5NwSiSkwd2xJ9NqG7YohFM8BlPdEV4zhmqHcIKpVwAitFItqnAaUSU42Aebdritt9oNVnpKCeeA4QQv_8W7rOXJlLfGXRJUBCrh3Rv7KCVC3yncAOIU8FWu3jyaAqhLrWHLW958wjF8ka7lw80YZbToPjIuiii0UXu2w3Tv5EGVdkhf05A3Yj6M_LXStns8iBMzcU4-mJ1649FnnImLnW5AeohoWPBB6WYhW9gfwjuxejTI3Q5R0mo9jUSP3_tFiawlC2zFgvkNFufC6Kry8-Burjf8l6rpAX7_sjtCu1AlAbI6PEFtxcKhNWHfQp4mUATR6P4k68jk_Kl-FpRBtNOf8YOlLGrKE-WbwCoIV7VAgK2CTZJOxaslxVZRCLObNrA3XuEtc3jo8pMzqx8GJWshIgmF4XiQcmgh65U_kjB07adlgnbCZvGUXdIIQiA2vqIWC6Qu8SSO20nOOR65hGXyIgf4aOolU0Ljbi4slXnJKjbcPaX5O3cXvKHbkVFwXmHK2Ymaqb6fZcap78_On8jLK_GRlw3jV18SLeOcJiG2LqtHzcUawY4K7bPDNY2QX89yL5d4qxRF577QgzalmdQDsKyC_N-wk', 'type': 'reasoning', }, { 'name': 'get_meaning_of_life', 'arguments': '{}', 'call_id': 'call_cp3x6W9eeyMIryJUNhgMaP5w', 'type': 'function_call', 'status': None, 'id': 'fc_01d311e2633707df0068fbac038f1c81a29847e80d6a1a3f60', }, {'type': 'function_call_output', 'call_id': 'call_cp3x6W9eeyMIryJUNhgMaP5w', 'output': '42'}, { 'role': 'assistant', 'id': 'msg_01d311e2633707df0068fbac094ff481a297b1f4fdafb6ebd9', 'content': [{'text': '42', 'type': 'output_text', 'annotations': []}], 'type': 'message', 'status': 'completed', }, ] )

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pydantic/pydantic-ai'

If you have feedback or need assistance with the MCP directory API, please join our Discord server