fix(agent): preserve external cancellation in message loop

Made-with: Cursor
This commit is contained in:
Xubin Ren
2026-03-20 11:24:05 +00:00
committed by Xubin Ren
parent d83ba36800
commit aacbb95313
2 changed files with 15 additions and 3 deletions

View File

@@ -265,9 +265,9 @@ class AgentLoop:
except asyncio.TimeoutError:
continue
except asyncio.CancelledError:
# anyio/MCP cancel scopes surface as CancelledError (a BaseException subclass).
# Re-raise only if the loop itself is being shut down; otherwise keep running.
if not self._running:
# Preserve real task cancellation so shutdown can complete cleanly.
# Only ignore non-task CancelledError signals that may leak from integrations.
if not self._running or asyncio.current_task().cancelling():
raise
continue
except Exception as e:

View File

@@ -65,6 +65,18 @@ class TestRestartCommand:
mock_handle.assert_called_once()
@pytest.mark.asyncio
async def test_run_propagates_external_cancellation(self):
"""External task cancellation should not be swallowed by the inbound wait loop."""
loop, _bus = _make_loop()
run_task = asyncio.create_task(loop.run())
await asyncio.sleep(0.1)
run_task.cancel()
with pytest.raises(asyncio.CancelledError):
await asyncio.wait_for(run_task, timeout=1.0)
@pytest.mark.asyncio
async def test_help_includes_restart(self):
loop, bus = _make_loop()