Skip to content

Conversation

@mjschock
Copy link

@mjschock mjschock commented Nov 27, 2025

Fix: Duplicate function_call items in session history after resuming from interruption

Fixes #701

Problem

When using OpenAIConversationsSession with human-in-the-loop (HITL) tool approval, function_call items were being duplicated in conversation history. This occurred because _currentTurnPersistedItemCount was incorrectly reset to 0 after resolveInterruptedTurn, undoing the rewind logic that had already adjusted the counter.

Flow:

  1. Initial run: Counter = 2, function_call item saved to session
  2. Resume after approval: resolveInterruptedTurn rewinds counter (2 → 1) ✓
  3. Counter reset to 0 ❌ (bug)
  4. saveToSession with counter=0 saves all items again → duplicate created

Root Cause

After resolveInterruptedTurn returned next_step_run_again, the code was resetting _currentTurnPersistedItemCount to 0 in multiple places (non-streaming and streaming paths). This caused saveToSession to save all items again, including the already-persisted function_call item, because the counter was reset instead of preserving the rewound value.

Additionally, when continuing from an interruption, the loop would treat it as a new turn and re-execute input guardrails, causing them to run twice.

Solution

1. Removed counter resets after resolveInterruptedTurn: Removed all instances where _currentTurnPersistedItemCount was reset to 0 immediately after resolveInterruptedTurn returns next_step_run_again (lines 735, 870, 1025, 1210 in run.ts).

2. Preserve rewound counter value: When continuing from interruption with next_step_run_again, only reset the counter if it's already 0 (indicating a new turn). If the counter is non-zero (was rewound), preserve the rewound value to prevent duplicates.

3. Added handoff filtering: Added logic in resolveInterruptedTurn to filter out already-executed handoffs by callId to prevent re-execution when resuming from interruption.

  1. Removed counter resets after resolveInterruptedTurn: Removed all instances where _currentTurnPersistedItemCount was reset to 0 immediately after resolveInterruptedTurn returns next_step_run_again.

  2. Use _lastTurnResponse to detect continuation: When continuing from an interruption with next_step_run_again, set _currentStep to undefined and continue the loop. In the next_step_run_again block, only increment the turn and reset the counter if !state._lastTurnResponse (indicating a new turn, not a continuation).

  3. Prevent guardrails from running twice: Added check !state._lastTurnResponse to the input guardrail execution condition to prevent them from running again when continuing from an interruption.

Changes

  • packages/agents-core/src/run.ts:
    * Removed counter resets after resolveInterruptedTurn in non-streaming path (lines 735, 870)
    * Removed counter resets after resolveInterruptedTurn in streaming path (lines 1025, 1210)
    * Modified counter reset logic to only reset when counter is already 0 (preserving rewound values)

    • Non-streaming path (lines 735-763):
      • Removed counter reset after resolveInterruptedTurn returns next_step_run_again
      • When continuing from interruption, set _currentStep to undefined and continue loop
      • Only increment turn and reset counter when !state._lastTurnResponse (new turn)
      • Added !state._lastTurnResponse check to input guardrail execution (line 785)
    • Streaming path (lines 1036-1063):
      • Applied same fixes as non-streaming path
  • packages/agents-core/src/runImplementation.ts:
    * Added handoff filtering in resolveInterruptedTurn to prevent re-execution of already-executed handoffs

  • packages/agents-core/test/run.test.ts:

    • Added integration test: "prevents duplicate function_call items when resuming from interruption after tool approval" to verify the fix and prevent regressions

Testing

* All existing tests continue to pass

Impact

  • ✅ Fixes duplicate function_call items in session history
  • ✅ Prevents input guardrails from executing twice when continuing from interruption
  • ✅ No breaking changes
  • ✅ Backward compatible
  • ✅ Affects all users using OpenAIConversationsSession with HITL tool approval

@changeset-bot
Copy link

changeset-bot bot commented Nov 27, 2025

⚠️ No Changeset found

Latest commit: 9a619ad

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@seratch seratch added this to the 0.3.x milestone Dec 2, 2025
@seratch seratch changed the title fix: prevent duplicate function_call items in session history after r… fix: #701 prevent duplicate function_call items in session history after resuming from interrruption Dec 2, 2025
@seratch seratch changed the title fix: #701 prevent duplicate function_call items in session history after resuming from interrruption fix: #701 prevent duplicate function_call items in session history after resuming from interruption Dec 2, 2025
@seratch
Copy link
Member

seratch commented Dec 3, 2025

Thanks for sending this PR! To prevent future regressions, may I ask you to add unit tests?

@mjschock
Copy link
Author

mjschock commented Dec 4, 2025

Thanks for sending this PR! To prevent future regressions, may I ask you to add unit tests?

Yep, np. I added a test, verified it fails against main, then created a fresh, hopefully simpler fix, that gets the test passing.

@mjschock
Copy link
Author

mjschock commented Dec 4, 2025

Thanks for sending this PR! To prevent future regressions, may I ask you to add unit tests?

Yep, np. I added a test, verified it fails against main, then created a fresh, hopefully simpler fix, that gets the test passing.

P.S. If you'd prefer the previous fix, just lemme know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Duplicate function_call items in session history after resuming from interruption

2 participants