@@ -1694,12 +1694,15 @@ def __init__(self) -> None:
16941694 response_id = "resp_nested" ,
16951695 )
16961696 ]
1697- self .is_complete = True
1697+ self .run_loop_task = asyncio . create_task ( asyncio . sleep ( 0 ))
16981698
16991699 async def stream_events (self ):
17001700 yield stream_event
17011701 raise asyncio .CancelledError ("stream-cancelled" )
17021702
1703+ streaming_result = DummyStreamingResult ()
1704+ await streaming_result .run_loop_task
1705+
17031706 def fake_run_streamed (
17041707 cls ,
17051708 starting_agent ,
@@ -1714,7 +1717,7 @@ def fake_run_streamed(
17141717 conversation_id ,
17151718 session ,
17161719 ):
1717- return DummyStreamingResult ()
1720+ return streaming_result
17181721
17191722 async def unexpected_run (* args : Any , ** kwargs : Any ) -> None :
17201723 raise AssertionError ("Runner.run should not be called when on_stream is provided." )
@@ -1838,6 +1841,86 @@ async def on_stream(payload: AgentToolStreamEvent) -> None:
18381841 await streaming_result .run_loop_task
18391842
18401843
1844+ @pytest .mark .asyncio
1845+ async def test_agent_as_tool_streaming_reraises_caller_cancellation_with_cancelled_run_loop (
1846+ monkeypatch : pytest .MonkeyPatch ,
1847+ ) -> None :
1848+ agent = Agent (name = "streamer" )
1849+ stream_event = RawResponsesStreamEvent (data = cast (Any , {"type" : "response_started" }))
1850+
1851+ class DummyStreamingResult :
1852+ def __init__ (self ) -> None :
1853+ self .final_output = ""
1854+ self .current_agent = agent
1855+ self .new_items : list [Any ] = []
1856+ self .raw_responses = [
1857+ ModelResponse (
1858+ output = [get_text_message ("Recovered nested summary" )],
1859+ usage = Usage (),
1860+ response_id = "resp_nested" ,
1861+ )
1862+ ]
1863+ self .run_loop_task = asyncio .create_task (asyncio .sleep (60 ))
1864+
1865+ async def stream_events (self ):
1866+ yield stream_event
1867+ raise asyncio .CancelledError ("stream-cancelled" )
1868+
1869+ streaming_result = DummyStreamingResult ()
1870+ streaming_result .run_loop_task .cancel ()
1871+ with contextlib .suppress (asyncio .CancelledError ):
1872+ await streaming_result .run_loop_task
1873+
1874+ def fake_run_streamed (
1875+ cls ,
1876+ starting_agent ,
1877+ input ,
1878+ * ,
1879+ context ,
1880+ max_turns ,
1881+ hooks ,
1882+ run_config ,
1883+ previous_response_id ,
1884+ auto_previous_response_id = False ,
1885+ conversation_id ,
1886+ session ,
1887+ ):
1888+ return streaming_result
1889+
1890+ async def unexpected_run (* args : Any , ** kwargs : Any ) -> None :
1891+ raise AssertionError ("Runner.run should not be called when on_stream is provided." )
1892+
1893+ monkeypatch .setattr (Runner , "run_streamed" , classmethod (fake_run_streamed ))
1894+ monkeypatch .setattr (Runner , "run" , classmethod (unexpected_run ))
1895+
1896+ async def on_stream (payload : AgentToolStreamEvent ) -> None :
1897+ del payload
1898+
1899+ tool_call = ResponseFunctionToolCall (
1900+ id = "call_cancelled_done" ,
1901+ arguments = '{"input": "recover"}' ,
1902+ call_id = "call-cancelled-done" ,
1903+ name = "stream_tool" ,
1904+ type = "function_call" ,
1905+ )
1906+
1907+ tool = agent .as_tool (
1908+ tool_name = "stream_tool" ,
1909+ tool_description = "Streams events" ,
1910+ on_stream = on_stream ,
1911+ )
1912+
1913+ tool_context = ToolContext (
1914+ context = None ,
1915+ tool_name = "stream_tool" ,
1916+ tool_call_id = tool_call .call_id ,
1917+ tool_arguments = tool_call .arguments ,
1918+ tool_call = tool_call ,
1919+ )
1920+ with pytest .raises (asyncio .CancelledError , match = "stream-cancelled" ):
1921+ await tool .on_invoke_tool (tool_context , '{"input": "recover"}' )
1922+
1923+
18411924@pytest .mark .asyncio
18421925async def test_agent_as_tool_streaming_extractor_can_access_agent_tool_invocation (
18431926 monkeypatch : pytest .MonkeyPatch ,
0 commit comments