fix(agent-core-v2): keep user-cancellation identity when aborting swarm tool runs - #3729
fix(agent-core-v2): keep user-cancellation identity when aborting swarm tool runs#3729kimi-agent-bot wants to merge 2 commits into
Conversation
…rm tool runs Interrupting an AgentSwarm with Esc aborted turn tools without an abort reason, so the interruption lost its UserCancellationError identity and the swarm batch rejected instead of resolving per-subagent "aborted" results. The rejection then surfaced on a floating promise derived by promise.finally(cleanup) in SessionSwarmService, raising an unhandledRejection that killed the whole process with exit 1. - abort turn tools with the user-cancellation reason on the input.abort and abort-escalation paths in the agent machine - swallow the derived cleanup promise rejection in SessionSwarmService so a failing batch can no longer crash the process on its own - recognise user cancellations structurally across class copies so the human kernel (which cannot import _base) can flag its own reason
🦋 Changeset detectedLatest commit: 807f855 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: eeab7d6777
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
The release changelog entry only needs the user-visible outcome; implementation details live in the PR body.
|
@codex review |
|
Codex Review: Didn't find any major issues. What shall we delve into next? Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
Problem
Interrupting an AgentSwarm (>=2 items running) with Esc in the TUI killed the whole process with exit 1 within ~1s, taking the main agent and all subagents down mid-turn with nothing in the log. Seen twice in production on 0.42.0.
Two faults chain together:
human/agent/machine.tsaborted turn tools viaentry.scope.abort()with no reason. The interruption therefore lost itsUserCancellationErroridentity and surfaced as a genericDOMException("This operation was aborted"). Infeatures/swarm/session/agentRunBatch.ts, thebatchAbortListener'sisUserCancellationcheck then failed, so the batch went down thefail()path and rejected instead of resolving per-subagent"aborted"results.features/swarm/session/sessionSwarmService.tsattached cleanup viapromise.finally(cleanup)and dropped the derived promise. When the batch rejects, that floating promise rejects unobserved ->unhandledRejection->run-shell.tsemergencyExit(1).Fault 2 stands on its own: any genuine
AgentRunBatchfailure (not just user interruption) crashed the process the same way.Fix
machine.ts: on theinput.abortand abort-escalation paths, turn-tool scopes are now aborted with the user-cancellation reason (abortTurnToolsUserCancelled/stopTurnToolsUserCancelled/abortSpawnedTools), so an interrupted swarm batch resolves per-subagent"aborted"results as designed. The plain turn-exit path (abortTurnTools/stopTurnTools) still aborts without a reason, keeping the "turn over" semantics distinct from user cancellation. The firstabort()latches the reason, so the later exit-path aborts cannot clobber it.sessionSwarmService.ts: the cleanup chain now ends in.catch(() => {}), so a rejecting batch can no longer crash the process through the floating derived promise. The returned promise still rejects to the caller unchanged._base(import-boundary rule: human is the pure kernel), so it gets its ownUserCancellationError(userCancelled = true, nameAbortError) inhuman/utils/abort.ts, and_base'sisUserCancellationnow also recognises cancellations structurally (userCancelled === true) across class copies.Tests
machine.test.ts: aborting a turn now passes aUserCancellationErrorreason to running turn tools.sessionSwarm.test.ts: a failing swarm batch no longer raises anunhandledRejectionwhilerun()still rejects to the caller.abort.test.ts:isUserCancellationrecognises a foreign class copy flagged withuserCancelled.All three fail before the fix and pass after. Full agent-core-v2 suite (6466 tests), typecheck, lint:imports, oxlint, build, and the no-comments check are green.