Skip to content

fix: prevent agent loop deadlock when LLM response is silently dropped (#72940) - #72954

Closed
webtecnica wants to merge 2 commits into
NousResearch:mainfrom
webtecnica:fix/agent-loop-deadlock-response-dropped-72940
Closed

fix: prevent agent loop deadlock when LLM response is silently dropped (#72940)#72954
webtecnica wants to merge 2 commits into
NousResearch:mainfrom
webtecnica:fix/agent-loop-deadlock-response-dropped-72940

Conversation

@webtecnica

Copy link
Copy Markdown
Contributor

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() returns True (cron turns, delegated children, subagent platform), the conversation loop calls direct_api_call() to issue synchronous LLM requests. After the API request completes successfully, this function checked agent._interrupt_requested and raised InterruptedError — 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_call should behave the same way.

The conversation loop's own redirect/finally handling (in conversation_loop.py) already catches pending redirects via the _redirect_crossed_response mechanism before response processing begins, so the duplicate check in direct_api_call was both redundant and harmful.

The Fix

Removed the _interrupt_requested check from the success path of direct_api_call(). A valid response is now always returned to the conversation loop, which handles interrupts and redirects through its own established mechanisms.

Testing

  • The except-path interrupt check is preserved — if the API call fails and the interrupt flag is set, it still raises InterruptedError as before
  • The worker-based path is unchanged
  • The conversation loop's redirect handling (_redirect_crossed_response in the finally block of _perform_api_call) continues to work independently

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
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/desktop Electron desktop app (apps/desktop/*) area/sessions Session lifecycle, resume, persistence, history needs-repro Bug needs reproduction steps duplicate This issue or pull request already exists sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Jul 27, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

This PR contains the complete pinned-session sync patch already proposed by #72953, plus an independent direct-call interruption hunk for #72940. Please split and rebase the agent-loop change; the bundled pin-sync portion duplicates #72953.

@webtecnica

Copy link
Copy Markdown
Contributor Author

Closing as requested by triage — this PR bundles #72953 (pinned sessions sync) which is its own PR. The independent agent-loop deadlock fix (#72940) should be submitted as a focused PR. See alt-glitch comment.

@webtecnica webtecnica closed this Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/sessions Session lifecycle, resume, persistence, history comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/desktop Electron desktop app (apps/desktop/*) duplicate This issue or pull request already exists needs-repro Bug needs reproduction steps P2 Medium — degraded but workaround exists sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Agent loop deadlock: LLM response received but not processed (no tool calls, no output)

2 participants