@@ -99,6 +99,24 @@ async def generator():
9999 return generator ()
100100
101101
102+ class MultiYieldToolExecutor :
103+ """Simulate a local tool that yields multiple results for one call."""
104+
105+ @classmethod
106+ def execute (cls , tool , run_context , ** tool_args ):
107+ async def generator ():
108+ from mcp .types import CallToolResult , TextContent
109+
110+ yield CallToolResult (
111+ content = [TextContent (type = "text" , text = "first streamed result" )]
112+ )
113+ yield CallToolResult (
114+ content = [TextContent (type = "text" , text = "second streamed result" )]
115+ )
116+
117+ return generator ()
118+
119+
102120class LargeTextToolExecutor :
103121 """模拟返回超长文本的工具执行器"""
104122
@@ -621,6 +639,34 @@ async def snapshot_context_manager(messages, trusted_token_usage=0):
621639 assert "工具执行结果" in tool_messages [0 ].content
622640
623641
642+ @pytest .mark .asyncio
643+ async def test_tool_loop_merges_multiple_results_from_one_tool_call (
644+ runner , provider_request , mock_hooks
645+ ):
646+ """Multiple executor yields must remain one complete provider tool result."""
647+ provider = CapturingToolLoopProvider ("test_tool" )
648+
649+ await runner .reset (
650+ provider = provider ,
651+ request = provider_request ,
652+ run_context = ContextWrapper (context = None ),
653+ tool_executor = MultiYieldToolExecutor ,
654+ agent_hooks = mock_hooks ,
655+ streaming = False ,
656+ )
657+
658+ async for _ in runner .step_until_done (3 ):
659+ pass
660+
661+ assert provider .call_count == 2
662+ second_contexts = provider .received_contexts [1 ]
663+ tool_messages = [msg for msg in second_contexts if msg .role == "tool" ]
664+ assert len (tool_messages ) == 1
665+ assert tool_messages [0 ].tool_call_id == "call_context_refresh"
666+ assert "first streamed result" in tool_messages [0 ].content
667+ assert "second streamed result" in tool_messages [0 ].content
668+
669+
624670@pytest .mark .asyncio
625671async def test_normal_completion_without_max_step (
626672 runner , mock_provider , provider_request , mock_tool_executor , mock_hooks
0 commit comments