Skip to content

fix: prevent AssistantAgent deadlock on tool call cancellation - #8143

Closed
MOHAMMED WASIM KHAN (wasim-builds) wants to merge 3 commits into
microsoft:mainfrom
wasim-builds:fix/7956-assistant-agent-cancellation-deadlock
Closed

MOHAMMED WASIM KHAN (wasim-builds) wants to merge 3 commits into
microsoft:mainfrom
wasim-builds:fix/7956-assistant-agent-cancellation-deadlock

Conversation

@wasim-builds

@wasim-builds MOHAMMED WASIM KHAN (wasim-builds) commented Sep 2, 2026 •

Copy link
Copy Markdown

Summary

Fixes #7956 and adds regression test for #8092

Previously, cancelling an in-flight tool call would cause asyncio.gather to raise without executing put_nowait(None), leaving the consumer loop blocking forever on stream.get(). This violated the documented cancellation contract.

Changes

  • Added return_exceptions=True to asyncio.gather in _execute_tool_calls
  • Handle exceptions in tool call results by converting them to error FunctionExecutionResult
  • This ensures put_nowait(None) always executes, allowing the consumer loop to terminate properly even when a tool call raises (including CancelledError)
  • Added regression test that verifies stream terminates after tool cancellation

Test plan

  • New regression test passes
  • Existing tests still pass

Previously, cancelling an in-flight tool call would cause asyncio.gather
to raise without executing put_nowait(None), leaving the consumer loop
blocking forever on stream.get().

Now return_exceptions=True ensures put_nowait(None) always executes,
allowing the consumer loop to terminate properly.

Fixes microsoft#7956
Copilot AI lite review requested due to automatic review settings September 2, 2026 04:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The current return_exceptions=True change can return exception objects that break downstream tuple-unpacking and the end-of-stream sentinel still isn’t guaranteed via finally.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR targets a deadlock in AssistantAgent.on_messages_stream when an in-flight tool call is cancelled: the streaming consumer loop can block forever if the producer never enqueues the end-of-stream sentinel.

Changes:

  • Modifies _execute_tool_calls to avoid hanging the streaming consumer when a tool call raises during asyncio.gather.
  • Updates inline comments around the end-of-stream sentinel behavior.
File summaries
File Description
python/packages/autogen-agentchat/src/autogen_agentchat/agents/_assistant_agent.py Adjusts tool-call execution/stream termination logic to prevent deadlocks on cancellation/exception paths.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 1209 to 1213
)
for call in function_calls
]
],
return_exceptions=True,
)
Wasim added 2 commits September 2, 2026 10:20
When return_exceptions=True and a tool call raises (e.g. CancelledError),
the result is an exception object rather than a tuple. This update
converts exceptions to error FunctionExecutionResult objects so downstream
processing doesn't fail with a TypeError.
Verifies that AssistantAgent.on_messages_stream terminates cleanly
when a tool call is cancelled mid-flight, preventing the deadlock
described in issue microsoft#8092.
@wasim-builds

Copy link
Copy Markdown
Author

Superseded by #8182

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cancelling an in-flight tool call deadlocks AssistantAgent.on_messages_stream

2 participants