fix(agent-core-v2): emit subagent.failed when background task registration fails - #2749
fix(agent-core-v2): emit subagent.failed when background task registration fails#2749tarikermis wants to merge 2 commits into
Conversation
…ation fails The Agent tool announces a background subagent through subagent.spawned before registering it as a background task. When registration hit the running-task limit, the tool aborted the run and returned the limit error, but the abort surfaced in mirrorAgentRun as an abort error — which deliberately never publishes subagent.failed — so clients that tracked the run from spawned/started (task panels, the TUI background agent badge) kept the rejected launch as a ghost running entry that could never be stopped (the engine never created the task). Publish subagent.failed from the registration-failure path so the spawned run always reaches a terminal signal, via a shared emitAgentRunFailed helper now also used by mirrorAgentRun.
🦋 Changeset detectedLatest commit: 6b222ab 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 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6b222abf88
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // The spawn was already announced, so clients tracking the run (task | ||
| // panels, the TUI background-agent badge) need a terminal signal — | ||
| // without one the rejected launch lingers as a ghost "running" entry. |
There was a problem hiding this comment.
Move the inline explanation to the file header
Remove this new statement-level explanatory comment or incorporate the scenario into the test name and the file’s top-of-file header; this package explicitly prohibits comments beside statements and permits them only in the top-of-file /** */ block.
AGENTS.md reference: packages/agent-core-v2/AGENTS.md:L36-L40
Useful? React with 👍 / 👎.
The package convention keeps comments solely in the top-of-file header block; the assertion sequence is self-explanatory without it.
Related Issue
Resolve #2673
Problem
On the default agent-core-v2 engine, a background subagent rejected by the running-task limit leaves a permanent ghost "running" entry in task panels: the entry's runtime keeps growing, Stop fails with
task agent-N does not exist in session ..., and the entry never self-heals (the agent-facing TaskList correctly shows 0 active tasks).Root cause: the Agent tool announces the launch through
subagent.spawned(withrunInBackground: true) andsubagent.startedbefore registering the background task. When registration hits the limit, the tool aborts the run and returns theToo many background tasks are already running.tool error, but the abort surfaces inmirrorAgentRunas an abort error — which deliberately never publishessubagent.failed. Clients that tracked the run from spawned/started therefore wait forever for a terminal event that never comes, while the engine-side task service never created the task (hence "does not exist" on stop). The legacy v1 engine self-heals here because its spawn pipeline emitssubagent.failedeven for aborts; v2 does not.What changed
agentTool.ts: in the background-registration failure catch, publishsubagent.failedfor the spawned agent (same message the tool returns), so an announced run always reaches a terminal signal. The emitted error text and the tool output now share oneregistrationFailureMessagehelper, so they cannot drift.mirrorAgentRun.ts: extracted the existing inlinesubagent.failedpublish into an exportedemitAgentRunFailedhelper (same captured event bus, identical behavior) that the tool reuses.test/tool/tool.test.tsto assertsubagent.spawnedprecedes exactly onesubagent.failedfor the rejected agent, with the limit message.@moonshot-ai/kimi-code, patch — internal engine fix with user-visible panel behavior).Deliberately narrow: user-cancellation aborts must keep not emitting
subagent.failed(clients render those as cancellations), so the fix lives at the registration-failure site rather than inmirrorAgentRun's generic abort suppression. A theoretical race (the child failing with a real error in the same instant as the abort) could yield a secondsubagent.failed; both are terminal "failed" signals and the TUI/web handlers are idempotent, so this is benign.Verification
subagent.spawned+subagent.startedfor the rejected agent — matching the issue's ghost-entry symptom.npx vitest run --project agent-core-v2: 310 files, 4890 passed / 1 skipped.tsc -p tsconfig.json --noEmit(agent-core-v2): clean.oxlinton changed files: 0 errors (1 pre-existing duplicate-import warning inmirrorAgentRun.tsthat already exists on main).mirrorAgentRun).Testing limitation, honestly noted: the reporter's panel was the web UI, whose source lives outside this repo, so the end-to-end panel behavior is verified at the engine event-contract level (
subagent.spawnednow always pairs with a terminal event) plus the TUI's equivalent background-agent badge path, not by clicking through the web panel.Checklist
gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.