@@ -353,6 +353,59 @@ async def needs_approval(_ctx, _params, _call_id) -> bool:
353353 assert result2 is not None , "Run should complete successfully with max_turns=20 from state"
354354
355355
356+ @pytest .mark .asyncio
357+ async def test_current_turn_not_preserved_in_to_state ():
358+ """Test that current turn counter is preserved when converting RunResult to RunState.
359+
360+ When a run is interrupted after one or more turns and converted to state via result.to_state(),
361+ the current turn counter should be preserved. This ensures:
362+ 1. Turn numbers are reported correctly in resumed execution
363+ 2. max_turns enforcement works correctly across resumption
364+
365+ BUG: to_state() initializes RunState with _current_turn=0 instead of preserving
366+ the actual current turn from the result.
367+ """
368+ model = FakeModel ()
369+
370+ async def test_tool () -> str :
371+ return "tool_result"
372+
373+ async def needs_approval (_ctx , _params , _call_id ) -> bool :
374+ return True
375+
376+ tool = function_tool (test_tool , needs_approval = needs_approval )
377+ agent = Agent (name = "TestAgent" , model = model , tools = [tool ])
378+
379+ # Model emits a tool call requiring approval
380+ model .set_next_output (
381+ [
382+ cast (
383+ ResponseFunctionToolCall ,
384+ {
385+ "type" : "function_call" ,
386+ "name" : "test_tool" ,
387+ "call_id" : "call-1" ,
388+ "arguments" : "{}" ,
389+ },
390+ )
391+ ]
392+ )
393+
394+ # First turn with interruption
395+ result1 = await Runner .run (agent , "call test_tool" )
396+ assert result1 .interruptions , "should have interruption on turn 1"
397+
398+ # Convert to state - this should preserve current_turn=1
399+ state1 = result1 .to_state ()
400+
401+ # BUG: state1._current_turn should be 1, but to_state() resets it to 0
402+ # This will fail when the bug exists
403+ assert state1 ._current_turn == 1 , (
404+ f"Expected current_turn=1 after 1 turn, got { state1 ._current_turn } . "
405+ "to_state() should preserve the current turn counter."
406+ )
407+
408+
356409@pytest .mark .asyncio
357410async def test_deserialize_only_function_approvals_breaks_hitl_for_other_tools ():
358411 """Test that deserialization correctly reconstructs shell tool approvals.
0 commit comments