fix: prevent agent loop deadlock when LLM response is silently dropped (#72940) - #72954
Closed
webtecnica wants to merge 2 commits into
Closed
fix: prevent agent loop deadlock when LLM response is silently dropped (#72940)#72954webtecnica wants to merge 2 commits into
webtecnica wants to merge 2 commits into
Conversation
NousResearch#72940) When should_use_direct_api_call() returns True (cron turns, delegated children, subagent platform), the conversation loop uses direct_api_call() to issue synchronous LLM requests. After the request completes, this function checked agent._interrupt_requested and raised InterruptedError even though the response was already received — discarding a valid API response and leaving the agent loop with nothing to process. The worker-based path (interruptible_api_call) does NOT have this post-response interrupt check: it only checks during its polling loop while the background thread is still alive. Once the thread finishes the response is returned unconditionally. direct_api_call should behave the same way. The conversation loop's own redirect/finally handling (conversation_loop.py lines 2209-2219) already checks for pending redirects via the _redirect_crossed_response mechanism, so the duplicate check in direct_api_call was both redundant and harmful. Removing it means a valid response is always delivered to the conversation loop, which then handles interrupts and redirects through its own established mechanisms. Fixes NousResearch#72940
Collaborator
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Fixes #72940 — agent loop deadlock where a valid LLM response is received but silently dropped, leaving the session stuck with no output and no tool calls.
Root Cause
When
should_use_direct_api_call()returnsTrue(cron turns, delegated children, subagent platform), the conversation loop callsdirect_api_call()to issue synchronous LLM requests. After the API request completes successfully, this function checkedagent._interrupt_requestedand raisedInterruptedError— discarding the valid response.The worker-based path (
interruptible_api_call) does NOT have this post-response interrupt check: it only checks for interrupts during its polling loop while the background thread is still alive. Once the thread finishes, the response is returned unconditionally.direct_api_callshould behave the same way.The conversation loop's own redirect/finally handling (in
conversation_loop.py) already catches pending redirects via the_redirect_crossed_responsemechanism before response processing begins, so the duplicate check indirect_api_callwas both redundant and harmful.The Fix
Removed the
_interrupt_requestedcheck from the success path ofdirect_api_call(). A valid response is now always returned to the conversation loop, which handles interrupts and redirects through its own established mechanisms.Testing
except-path interrupt check is preserved — if the API call fails and the interrupt flag is set, it still raisesInterruptedErroras before_redirect_crossed_responsein thefinallyblock of_perform_api_call) continues to work independently