Skip to content

fix(web): settle subagent entries stuck at "running" after interruption or disconnect#1969

Open
youngting520 wants to merge 1 commit into
MoonshotAI:mainfrom
youngting520:fix/1963-stale-running-subagents
Open

fix(web): settle subagent entries stuck at "running" after interruption or disconnect#1969
youngting520 wants to merge 1 commit into
MoonshotAI:mainfrom
youngting520:fix/1963-stale-running-subagents

Conversation

@youngting520

Copy link
Copy Markdown

Related Issue

Resolve #1963

Problem

In kimi web sessions, subagent entries can stay "running" forever with an ever-growing timer even though the subagent already finished: an interrupted subagent (e.g. a 429 rate limit aborting the run) never emits a terminal subagent.* event, and the web client has no way to recover from a missed terminal event — foreground subagents are served neither by REST /tasks nor by the snapshot roster once the next main turn starts, so a stale row survives every refresh. The same stale state also appears after an ordinary client disconnect with no error at all, while background tasks recover correctly via REST /tasks.

What changed

Close the gap at three layers so a spawned subagent always reaches a terminal UI state:

  • Engine: mirrorAgentRun now guarantees exactly one terminal event after subagent.started — aborts publish subagent.failed like any other failure instead of being silently swallowed (matching the v1 engine's behavior). The swarm scheduler keeps its existing suppression, and session init opts out explicitly via a new suppressAbortFailureEvent option to stay quiet on user cancellation.
  • Web client (live): when the main prompt ends (prompt.completed / prompt.aborted), foreground subagent rows still running are settled as failed — a foreground subagent cannot outlive its prompt, so such a row is stale by definition. Background and detached (Ctrl+B) subagents are left to REST /tasks.
  • Web client (resync): the snapshot merge applies the same settle when the snapshot shows an idle main turn, so even a client that missed every event heals on the next refresh instead of keeping the row forever.

Tests: new engine-side cases for abort/suppressed-abort mirroring, reducer cases for the prompt-end settle, and snapshot-merge cases for the idle-session settle (kimi-web suite 652 tests, agent-core-v2 and kap-server suites green).

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 46d65dc369

ℹ️ 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".

Comment thread apps/kimi-web/src/api/daemon/eventReducer.ts Outdated
Comment thread packages/agent-core-v2/src/session/subagent/mirrorAgentRun.ts Outdated
…on or disconnect

An interrupted subagent (e.g. a 429 rate limit aborting the run) never
emitted a terminal subagent.* event: mirrorAgentRun swallowed the failure
for any AbortError, so the web UI kept the entry "running" forever. The
client also had no way to recover a missed terminal event — foreground
subagents are served neither by REST /tasks nor by the snapshot roster
once the next main turn starts.

Close the gap at three layers:

- Engine: mirrorAgentRun guarantees exactly one terminal event after
  subagent.started; aborts publish subagent.failed (matching v1). The
  swarm scheduler keeps its suppression, and session init opts out via
  the new suppressAbortFailureEvent option.
- Web client: when the main turn ends (turnActiveChanged active:false —
  the single source of truth for the main-turn boundary), foreground
  subagent rows still running are settled as failed; background/detached
  subagents stay owned by REST /tasks. Prompt-level events are not used
  as the settle signal: aborting a queued prompt emits promptAborted
  while the active turn and its subagents legitimately keep running.
- Web client: when the snapshot shows an idle main turn, the merge drops
  stale live foreground rows the roster no longer knows instead of
  guessing a terminal state — absence from the roster cannot distinguish
  completed from failed, so the persisted Agent tool result drives the
  final display.

Resolve MoonshotAI#1963
@youngting520
youngting520 force-pushed the fix/1963-stale-running-subagents branch from 46d65dc to 47d0370 Compare July 20, 2026 15:07
@changeset-bot

changeset-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 47d0370

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Patch

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Web UI keeps showing finished subagents as running after 429 interruption + resume

1 participant