Repository navigation
fix(execution): grouped sub-agent edited args validated, abort ends wedged tool waits, re-pause keeps approvalIds (Eve2-F4/F5/F6) - #618
Merged
Conversation
…edged tool waits, re-pause keeps approvalIds (Eve2-F4/F5/F6) - Eve2-F4: approve-with-edits on a sub-agent's grouped approval stored decision.args raw, so schema-invalid args ran the tool; the sub-agent's resume now validates every decided group's edited args before the step runs (LOUSHO_TOOL_ARGS_INVALID leaves the approval pending). - Eve2-F5: a tool that ignores its abortSignal held send() / stream() / approvals.resolve() open forever. The tool batch's settle wait and the resume's approved-tool wait are raced against the run's signal like the model call already was (Eve CORE-F15): the run ends 'aborted' with a 'cancelled' result for calls still running, a settlement already landing as the signal fires is still kept, and the tool keeps running. - Eve2-F6: markAwaitingApproval() wrote only approvalId on a re-pause, so durable discovery saw 1 of N pending approvals; it now carries the group's approvalIds like markGroupPending() does.
…ve2-F5) The settle-on-abort race yielded a single event-loop turn, which dropped the result of any tool still running when the signal fired - a 20ms tool aborted mid-flight lost its B4 'waited' transcript entry. The abort side now drains for TOOL_ABORT_GRACE_MS (500ms), so a tool released while the run unwinds keeps its real result (B4 contract restored) while a truly wedged tool still abandons inside ~500ms, well under any caller-visible latency (F5 contract kept). Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 of 2 tasks
LinuxDevil
pushed a commit
that referenced
this pull request
Oct 12, 2026
…sumed tool calls The resumed-tool race added in #618 duplicated generateStep's abortable(); both now share it, with an optional grace period for the tool path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BG6n8mwoFq1jmay9zCPS6n
LinuxDevil
pushed a commit
that referenced
this pull request
Oct 12, 2026
…sumed tool calls The resumed-tool race added in #618 duplicated generateStep's abortable(); both now share it, with an optional grace period for the tool path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BG6n8mwoFq1jmay9zCPS6n
LinuxDevil
added a commit
that referenced
this pull request
Oct 12, 2026
…opy errors, usable templates, eval/dev accuracy, slimmer image (#613) * fix(cli): kits load under plain node, dev reloads local helpers, import hints Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BG6n8mwoFq1jmay9zCPS6n * fix(providers): pass OPENAI_BASE_URL / ANTHROPIC_BASE_URL on ai 4 provider packages Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BG6n8mwoFq1jmay9zCPS6n * fix(execution): PropagatingToolError, McpToolError, WorkspaceError instanceof across SDK copies Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BG6n8mwoFq1jmay9zCPS6n * feat(cli): build agent modules, usable minimal/tools scaffolds, leaner docker image Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BG6n8mwoFq1jmay9zCPS6n * fix(cli): eval timeouts and empty runs, command help, small message and exit-code fixes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BG6n8mwoFq1jmay9zCPS6n * chore(package): stop shipping the CJS CLI build; changelog and upgrading notes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BG6n8mwoFq1jmay9zCPS6n * refactor(cli): split failLateCases so it stays under the cognitive-complexity limit Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BG6n8mwoFq1jmay9zCPS6n * refactor(execution): one abortable() helper for provider calls and resumed tool calls The resumed-tool race added in #618 duplicated generateStep's abortable(); both now share it, with an optional grace period for the tool path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BG6n8mwoFq1jmay9zCPS6n * test(mcp): let the run start before the client timeout fires A 200 ms timeout could fire before a cold runner started the run, so the cancel matched nothing and the run was never aborted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BG6n8mwoFq1jmay9zCPS6n * ci: retrigger checks * test(mcp): give serveMcp's run-start and cancel waits room on busy runners vi.waitFor's 1 s default failed on a CI runner whose suite took 300 s, before the server had started the run. The late-cancel test's runs now last long enough for the cancel to land first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BG6n8mwoFq1jmay9zCPS6n --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes three findings from the second adversarial audit (
audit/eve2), all in the approval/abort resume path. All repros verified against this branch.Eve2-F4 — grouped sub-agent edited args skip schema validation (High)
groupDecision()storeddecision.argsraw forsnapshot.subagentrecords (the lead's registry holds none of the sub-agent's tools), so an invalid edit like{ a: 'not-a-number' }reachedexecute()unchecked.decideGroupMember()now runsvalidateGroupArgs()once every call of the step is decided — inside the sub-agent's own resume, against the registry that owns the tools — and replaces each decision's args with the parsed output, likewithEditedArgs()does for a single call. An invalid edit throwsLOUSHO_TOOL_ARGS_INVALIDand the claimed record goes back, so the approval stays pending.npx tsx audit/eve2/repro/subagentGroupEditedArgs.ts→ "OK: edited args were validated/rejected"src/parallelApprovals.test.ts(invalid args rejected, valid args run)Eve2-F5 — abort during tool execution never settles the run (High)
Two tool waits were not raced against the run's signal the way the model call already is (Eve CORE-F15):
Promise.all(this.running)inToolBatchandexecuteApprovedTool()inresume.ts. A signal-ignoring/wedged tool leftsend(),stream()andapprovals.resolve()pending forever.ToolBatch.settled()races the running calls against the run signal; when the abort side wins after a one-turn drain (so a settlement already landing still records — a tool released just as the run aborted keeps its result), still-running calls are reported unrecorded and get the same 'cancelled' result as calls never reached. Late settlements record nothing on top.executeApprovedTool()waits onabortableToolCall(), the same drain-aware race, so a tool that aborts the signal inside its ownexecute()still returns its real result.ExecuteOptions.signal); the run endsfinishReason: 'aborted'withabortReason, through the existingabortRun()path.abortDuringToolExecution.ts→ resolvedfinish=abortedin ~173ms;abortDuringResumedTool.ts→ resolvedfinish=abortedin ~167ms.src/execution/abortEdges.test.ts(wedged tool in a batch; wedged approved tool on resume)Eve2-F6 — re-paused run's checkpoint drops approvalIds (Medium-High)
markAwaitingApproval()wrote onlyapprovalId, so a run re-pausing on several of a step's calls (e.g. a resumed sub-agent pausing again) showed durable readers 1 of N pending approvals. It now carriesapprovalIdslikemarkGroupPending()does.rePausedSubagentCheckpointIds.ts→ "OK: checkpoint names every pending approval"src/execution/approvalResumeDurability.test.tsVerification
npx vitest run src/execution: 73 files / 1064 tests pass (incl.parallelApprovals14,abortEdges9,approvalResumeDurability4)npx vitest runon resume/approval consumers outsidesrc/execution(cloudflare checkpoint, kvCheckpointStore, publicSurface, SqliteStore): 178 tests passnpx tsc --noEmit -p tsconfig.json: cleannpm run lint: clean