@@ -1644,6 +1644,58 @@ def _make_agent_tree():
16441644 return root , child1 , child2
16451645
16461646
1647+ @pytest .mark .asyncio
1648+ async def test_empty_stop_after_tool_call_surfaces_error_event ():
1649+ """Regression test for empty Gemini turn after a successful tool call (#5631).
1650+
1651+ Turn 1 returns a function_call which executes successfully, then turn 2
1652+ returns Content(role='model', parts=[]) with finish_reason=STOP and no error.
1653+ In non-streaming mode the flow must surface that empty turn as an error event
1654+ instead of a silent empty final response.
1655+ """
1656+ function_call_part = types .Part .from_function_call (
1657+ name = 'increase_by_one' , args = {'x' : 1 }
1658+ )
1659+
1660+ turn_1 = LlmResponse (
1661+ content = types .Content (role = 'model' , parts = [function_call_part ]),
1662+ finish_reason = types .FinishReason .STOP ,
1663+ )
1664+ # An empty Gemini turn: STOP with no content parts and no error from the model.
1665+ turn_2 = LlmResponse (
1666+ content = types .Content (role = 'model' , parts = []),
1667+ finish_reason = types .FinishReason .STOP ,
1668+ )
1669+
1670+ function_called = 0
1671+
1672+ def increase_by_one (x : int ) -> int :
1673+ nonlocal function_called
1674+ function_called += 1
1675+ return x + 1
1676+
1677+ mock_model = testing_utils .MockModel .create (responses = [turn_1 , turn_2 ])
1678+ agent = Agent (name = 'root_agent' , model = mock_model , tools = [increase_by_one ])
1679+ runner = testing_utils .InMemoryRunner (agent )
1680+ events = runner .run ('test' )
1681+
1682+ assert function_called == 1 , 'Tool should still execute on turn 1'
1683+
1684+ function_call_events = [e for e in events if e .get_function_calls ()]
1685+ function_response_events = [e for e in events if e .get_function_responses ()]
1686+ assert len (function_call_events ) == 1
1687+ assert len (function_response_events ) == 1
1688+
1689+ # The empty turn 2 must surface as an error event, not an empty final.
1690+ error_events = [e for e in events if e .error_code ]
1691+ assert len (error_events ) == 1
1692+ err = error_events [0 ]
1693+ assert err .error_code == 'MODEL_RETURNED_NO_CONTENT'
1694+ assert err .error_message
1695+ # And it must be the run's final event (no silent empty event after it).
1696+ assert events [- 1 ] is err
1697+
1698+
16471699@pytest .mark .asyncio
16481700async def test_transfer_to_sibling_disallowed_raises_value_error ():
16491701 """Transfer to sibling raises ValueError when disallow_transfer_to_peers is True."""
0 commit comments