fix: #701 prevent duplicate function_call items in session history after resuming from interruption #702
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fix: Duplicate function_call items in session history after resuming from interruption
Fixes #701
Problem
When using
OpenAIConversationsSessionwith human-in-the-loop (HITL) tool approval,function_callitems were being duplicated in conversation history. This occurred because_currentTurnPersistedItemCountwas incorrectly reset to 0 afterresolveInterruptedTurn, undoing the rewind logic that had already adjusted the counter.Flow:
function_callitem saved to sessionresolveInterruptedTurnrewinds counter (2 → 1) ✓saveToSessionwith counter=0 saves all items again → duplicate createdRoot Cause
After
resolveInterruptedTurnreturnednext_step_run_again, the code was resetting_currentTurnPersistedItemCountto 0 in multiple places (non-streaming and streaming paths). This causedsaveToSessionto save all items again, including the already-persistedfunction_callitem, 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 afterresolveInterruptedTurn: Removed all instances where_currentTurnPersistedItemCountwas reset to 0 immediately afterresolveInterruptedTurnreturnsnext_step_run_again(lines 735, 870, 1025, 1210 inrun.ts).2. Preserve rewound counter value: When continuing from interruption withnext_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 inresolveInterruptedTurnto filter out already-executed handoffs bycallIdto prevent re-execution when resuming from interruption.Removed counter resets after
resolveInterruptedTurn: Removed all instances where_currentTurnPersistedItemCountwas reset to 0 immediately afterresolveInterruptedTurnreturnsnext_step_run_again.Use
_lastTurnResponseto detect continuation: When continuing from an interruption withnext_step_run_again, set_currentSteptoundefinedand continue the loop. In thenext_step_run_againblock, only increment the turn and reset the counter if!state._lastTurnResponse(indicating a new turn, not a continuation).Prevent guardrails from running twice: Added check
!state._lastTurnResponseto 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 afterresolveInterruptedTurnin non-streaming path (lines 735, 870)* Removed counter resets afterresolveInterruptedTurnin streaming path (lines 1025, 1210)* Modified counter reset logic to only reset when counter is already 0 (preserving rewound values)resolveInterruptedTurnreturnsnext_step_run_again_currentSteptoundefinedand continue loop!state._lastTurnResponse(new turn)!state._lastTurnResponsecheck to input guardrail execution (line 785)packages/agents-core/src/runImplementation.ts:* Added handoff filtering inresolveInterruptedTurnto prevent re-execution of already-executed handoffspackages/agents-core/test/run.test.ts:"prevents duplicate function_call items when resuming from interruption after tool approval"to verify the fix and prevent regressionsTesting
* All existing tests continue to passfunction_callitem exists in session after resuming from interruptionImpact
function_callitems in session historyOpenAIConversationsSessionwith HITL tool approval