Skip to content

Commit 26e9571

Browse files
committed
fix: add test to ensure current turn is preserved when converting RunResult to RunState
1 parent 4b8b8f9 commit 26e9571

File tree

1 file changed

+53
-0
lines changed

1 file changed

+53
-0
lines changed

tests/test_hitl_error_scenarios.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
357410
async def test_deserialize_only_function_approvals_breaks_hitl_for_other_tools():
358411
"""Test that deserialization correctly reconstructs shell tool approvals.

0 commit comments

Comments
 (0)