fix(agent-core): stop loop after aborted tool run#94412
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 22, 2026, 5:00 AM ET / 09:00 UTC. Summary PR surface: Source +43, Tests +148. Total +191 across 2 files. Reproducibility: yes. Current source shows the missing post-tool abort check before Review metrics: 1 noteworthy metric.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the focused shared agent-core abort boundary after current-head CI is clean or the remaining unrelated shard failure is explicitly scoped by maintainers. Do we have a high-confidence way to reproduce the issue? Yes. Current source shows the missing post-tool abort check before Is this the best way to solve the issue? Yes. The shared agent-core loop boundary is the right layer because both the plain AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against e20edd753bd7. Label changesLabel justifications:
Evidence reviewedPR surface: Source +43, Tests +148. Total +191 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
0308d98 to
468234a
Compare
fa08a2d to
530e68f
Compare
530e68f to
e11d971
Compare
|
Merged via squash.
Thanks @szsip239! |
Merged via squash. Prepared head SHA: e11d971 Co-authored-by: szsip239 <[email protected]> Co-authored-by: vincentkoc <[email protected]> Reviewed-by: @vincentkoc
Summary
Real behavior proof
Behavior addressed: When a tool aborts the active run during tool execution, current
origin/mainstill starts another model turn with the already-aborted signal. That extra turn can keep the caller/session path open after the user-visible abort, which matches the observed session-lock symptom after switching away from an in-flight OpenClaw run. This PR ends the agent loop immediately after the aborted tool result andturn_endhave been emitted.Real environment tested: Local OpenClaw source checkout on macOS, Node v26.3.0, pnpm 11.2.2. I ran the same inline reproduction against current
origin/mainat0cae5b3672and this PR branchcodex/fix-abort-tool-lock-releaseat1096846d2f. The reproduction imports the real OpenClawpackages/agent-core/src/agent-loop.tsthroughtsxand exercisesrunAgentLoopwith a model stream, an actual OpenClaw tool object, and anAbortControllersignal; no mocked unit-test runner is involved in this proof.Exact steps or command run after this patch: On the PR branch, I ran an inline
node --import tsx --input-type=modulereproduction that creates a first assistanttoolCall, executes anabort_toolwhoseexecutecallscontroller.abort(new Error("user aborted")), then fails ifstreamFnis called more than once. I also rannode scripts/run-vitest.mjs packages/agent-core/src/agent-loop.test.ts -t "does not request another model turn after a tool aborts the run".Evidence after fix: The same reproduction fails on
origin/mainand passes on this PR branch. Onorigin/main(0cae5b3672) it printed:{ "commit": "0cae5b3672", "streamCalls": 2, "aborted": true, "roles": ["user", "assistant", "toolResult", "assistant"], "finalEvent": "agent_end" }and then threw
Error: BUG: model turn continued after abort. On this PR branch (1096846d2f) it printed:{ "commit": "1096846d2f", "streamCalls": 1, "aborted": true, "roles": ["user", "assistant", "toolResult"], "finalEvent": "agent_end" }The targeted regression test output was:
Observed result after fix: After the tool aborts the run, OpenClaw emits the tool result and
agent_endwithout issuing a second model request. The returned messages stop atuser,assistant, andtoolResult; there is no extra assistant message from an aborted follow-up turn.What was not tested: I did not rerun a full packaged gateway/CLI release build with a live external model provider for this PR-body refresh. The proof above isolates the real OpenClaw agent-loop path locally; full-suite and broader gateway checks remain supplemental CI/maintainer validation.
Verification
node scripts/run-vitest.mjs packages/agent-core/src/agent-loop.test.ts -t "does not request another model turn after a tool aborts the run"node scripts/run-vitest.mjs packages/agent-core/src/agent-loop.test.tsnode scripts/run-vitest.mjs src/agents/embedded-agent-runner/run/attempt.subscription-cleanup.test.ts src/agents/embedded-agent-runner/run/attempt.session-lock.test.tspnpm tsgo:test:packagespnpm tsgo:core