test_openai_responses.py•364 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, 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(),
)
]
),
]
)