fix(sdk): re-check cancellation after acquiring resource lock in ParallelToolExecutor - #4875
Conversation
ParallelToolExecutor._run_safe checked the cancel token only before resource resolution. A call cancelled while blocked on a resource lock still invoked tool_runner once the lock became available. Re-check the token after acquiring the lock and return the synthetic cancellation error instead. Fixes OpenHands#4777 Co-authored-by: openhands <openhands@all-hands.dev>
|
📁 PR Artifacts Notice This PR contains a |
|
Heads up on the two failing sdk-tests checks: both are pre-existing on
Both fail identically on main's own CI. The four tests added by this PR all pass in the same run (visible in the 6092 passed). |
|
🚦 CI is currently failing on this PR's latest commit. Please fix the failing checks before OpenHands reviews it - this is re-checked automatically once you push a new commit. (A maintainer can also request This is an automated check - no AI was used to generate this comment. |
|
Tracked the two failing sdk-tests in #4877 (red on main from model-metadata data drift, not a code change). This PR's own four tests pass; happy to help land the metadata-test fix if useful. |
HUMAN:
Hit this on my self-hosted agent-canvas deployment: a cancelled tool call kept running after interrupt. Validated the fix end-to-end on my live box before submitting, and reviewed the diff myself.
AGENT:
Why
ParallelToolExecutor._run_safecheckscancel_token.is_cancelledonce, before resolving resource locks. A tool call that blocks waiting for aResourceLockManagerlock and is cancelled during that wait still invokestool_runneronce the lock becomes available. This violates the documented contract that pending tool calls are skipped after cancellation, and lets a queued file/terminal/browser operation start after the user interrupted the run.Summary
cancel_token.is_cancelledimmediately after acquiring the resource lock, returning the existing synthetic cancellation error instead of running the tool.tests/sdk/agent/test_parallel_executor_cancel_wait.py: parametrised regression test covering sync declared-resource, sync tool-mutex, and async paths, plus an uncancelled-path sanity test.Issue Number
Fixes #4777
How to Test
Run the new regression tests:
End-to-end verification performed on a self-hosted agent-canvas deployment (SDK v1.44.1,
ghcr.io/openhands/agent-canvas:main):tool_runnerafter the lock became available (reproduces on v1.44.1 and currentmain).AgentErrorEvent("Tool call cancelled by interrupt.") andtool_runneris never invoked; the uncancelled path still returns normal tool output.sleep 120terminal tool call,POST /api/conversations/{id}/interruptmoved the conversation fromrunningtopausedimmediately. Server log:Skipping tool 'terminal' -- cancelled while waiting for lock.Video/Screenshots
N/A - no UI change; behaviour is terminal-observable only.
Type
Notes
file, 60stool, 300sterminal/browser/mcp). A cancel-awareFIFOLock.acquirewould be the proper follow-up.