fix(web): reconcile subagents stuck at "running"#1969
Conversation
There was a problem hiding this comment.
💡 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".
46d65dc to
47d0370
Compare
🦋 Changeset detectedLatest commit: 91c3b5b 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 |
35916c4 to
328ce08
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 328ce08b6e
ℹ️ 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".
328ce08 to
37ce1f0
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 37ce1f07f6
ℹ️ 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".
acdaa62 to
8b41de7
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8b41de794d
ℹ️ 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".
| ((appEvent.mainTurnActive === false && wasMainTurnActive) || | ||
| (appEvent.mainTurnActive === undefined && !appEvent.busy)) && | ||
| (appEvent.mainTurnActive === undefined && !appEvent.busy && wasMainTurnActive)) && |
There was a problem hiding this comment.
Keep clearing legacy quiet events without an active-turn marker
When an older server omits mainTurnActive and the client misses turn.started, wasMainTurnActive is false even though a locally submitted prompt may still have inFlightBySession set. Requiring that marker now skips clearWorkingFlags on the authoritative busy: false fallback, leaving the waiting indicator active and causing subsequent prompts to remain queued despite the session being idle. Keep the unconditional legacy quiet cleanup, and gate only the new subagent-reconciliation request on wasMainTurnActive if duplicate snapshots are the concern.
Useful? React with 👍 / 👎.
8b41de7 to
3253cdf
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3253cdfe8b
ℹ️ 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".
Finished foreground subagents could stay 'running' in Kimi Web when the terminal lifecycle event was missed or a late/replayed progress frame re-opened the row. - Preserve the distinction between an omitted subagent roster (older server) and an authoritative empty roster, and reconcile authoritative snapshots by removing stale live foreground rows while keeping REST-managed background tasks and terminal history. - Request a coalesced snapshot at the turn boundary (turn.ended, plus the quiet sessionWorkChanged fallback for a lost turn.ended) whenever a live foreground subagent still needs reconciliation. - Never let a late/replayed subagent progress frame downgrade a terminal row back to running; explicit lifecycle events (subagent.started on resume) still re-open it. - Seed the projector's subagent meta from the same snapshot roster that seeds the reducer's task rows, so the terminal knowledge survives a resync reset.
3253cdf to
91c3b5b
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 91c3b5b8e0
ℹ️ 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".
| ) { | ||
| subagentReconcileStaleRetries.set(sessionId, reconcileRetryCount + 1); | ||
| snapshotSyncRunner.request(sessionId); | ||
| } else { | ||
| subagentReconcileStaleRetries.delete(sessionId); |
There was a problem hiding this comment.
Keep reconciliation pending after exhausting immediate retries
When background-agent, BTW, or other durable events advance the session cursor during all three snapshot requests, every response enters this stale-snapshot branch; the final attempt deletes the retry state without applying the authoritative roster or scheduling a later retry. Since the main turn has already ended, there may be no subsequent boundary to trigger reconciliation, so the foreground subagent remains permanently running—the new test at event-batcher.test.ts even demonstrates this terminal state. Use a delayed/backoff retry or reconcile the roster independently of the stale full-session payload rather than abandoning the candidate.
Useful? React with 👍 / 👎.
Related Issue
Resolves #1963
Problem
Kimi Web can keep a foreground subagent row in
runningafter the subagent has already finished. Reports show that this can happen both around interruption/reconnection and during an otherwise healthy session.The Web task projection is driven by an incremental event stream, while the session snapshot provides the authoritative foreground-subagent roster. Several convergence gaps could leave the projected state stale:
subagentsfield from an older server and an explicit empty roster into the same value, then treated an empty roster as a no-op. An authoritative snapshot therefore could not remove stale foreground rows.assistant.delta,tool.call.started, ortool.progress) could recreate a removed row asrunning, with no guaranteed later event to correct it.The exact event sequence behind every reported occurrence has not been captured, but these paths share the same underlying problem: the Web projection lacked a reliable way to converge back to authoritative state without affecting tasks outside the foreground roster.
The TUI does not use this Web-side task projection path.
What changed
subagent.spawned,subagent.started, and backgroundtask.startedevents clear pending cleanup and intentionally reopen a previously removed row.running.turn.endedquiet fallback whenever a live foreground subagent still needs reconciliation. A reconcile makes the initial request plus at most two serial retries when snapshots lag the local cursor, and stops early when the candidate settles. Both protocol branches require a previously active main turn, preventing duplicate requests.This keeps the fix in Kimi Web and avoids changing the agent engine, WebSocket protocol, or server behavior.
Reviewer guide
apps/kimi-web/src/api/daemon/client.tsandapps/kimi-web/src/api/types.tsapps/kimi-web/src/api/daemon/agentEventProjector.tsapps/kimi-web/src/composables/useKimiWebClient.tsapps/kimi-web/src/lib/taskMerge.tsValidation
pnpm --filter @moonshot-ai/kimi-web test(684 tests)pnpm --filter @moonshot-ai/kimi-web typecheckpnpm --filter @moonshot-ai/kimi-web buildpnpm --filter @moonshot-ai/kimi-web check:stylepnpm lint(0 errors; existing warnings only)git diff --check upstream/main...HEADpnpm changeset status --since=upstream/mainChecklist
gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.