Repository navigation
fix(kimi-code): keep the previous turn's answer visible when a task-notification turn ends - #3799
Conversation
🦋 Changeset detectedLatest commit: 9867a50 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 |
commit: |
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c116ccc52e
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e6bd3d73c0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
Confirming this exact bug on release 2.1.1 — 100% reproducible. Posting since the PR notes no separate issue was filed. Environment: kimi-code 2.1.1, macOS, Warp terminal ( Repro (every time):
Notes
|
…otification turn ends
e6bd3d7 to
c9dbfe5
Compare
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c9dbfe57a9
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
The previous commit also made background.task.terminated mount a terminal card for every task kind, which smuggled a behavior change into the bug fix: agent-kind tasks terminating without a subagent lifecycle event used to be silent in the transcript and would now gain a status card. It also raced the subagent lifecycle path — an agent finishing before background.task.started synced could end up with two terminal cards. Restore the terminated branch to its main behavior: only process and question tasks mount a card there (now also registered for anchoring); agent terminal cards remain owned by the subagent lifecycle path. The notification-turn anchor keeps its mount-if-missing fallback, which is the single new product behavior and covers abnormally terminated agents with no card to anchor — making the reconciliation machinery unnecessary.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bedfdcd265
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…s spawn-time task id A spawn-time background agent whose subagent.completed lands before the background.task.started sync could not be matched to a task id by findAgentTaskId, so its terminal card never registered in backgroundTaskTerminalEntries. When the task-notification turn started, anchorTaskNotificationTurn found no mounted card and appended a second terminal card — a duplicate. The subagent.spawned event already carries the task id (the Agent tool fills it from the task registration), so keep it on BackgroundAgentMetadata and prefer it over the task-table lookup in the completed/failed/cancelled paths; the lookup stays as fallback for spawn paths that carry no task id.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f68694f2ba
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…the notification turn Tower's spawnTool emits subagent.spawned without a task id (the task is registered only after launch() returns), so a tower worker that finishes before the registration mounts its terminal card with no task id to key on: the spawn event has no taskId and findAgentTaskId searches an empty task table. The card never registers in backgroundTaskTerminalEntries, and when the task-notification turn starts, anchorTaskNotificationTurn finds no mounted card and appends a second terminal card — a duplicate. Keep the agentId on the card's BackgroundAgentStatusData and, before falling back to mounting, resolve the agentId from the now-synced task table and scan the transcript for that agent's terminal card. When one is found, register it under the task id and move it to the turn start like any mapped card; only mount a new card when the agent left none. Process-kind anchoring is unchanged.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 78878bf260
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
A resumed background agent keeps its previous agentId, so the orphaned terminal-card scan at the notification turn could match the previous run's card. When the resumed task then terminated without mounting a card of its own (e.g. timed out), the anchor moved the earlier run's card to the new turn and returned, so the resumed task's real terminal status was never shown. Skip candidates already registered in backgroundTaskTerminalEntries under a different task id and mount the task's own terminal card instead.
|
@codex review |
|
Codex Review: Didn't find any major issues. Delightful! Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
Related Issue
Follow-up to #3154 (same root-cause family; no separate issue filed).
Problem
The TUI folds completed-turn assistant messages beyond a keep cap into a step summary, grouped by "fold segments" delimited by turn-boundary components. A turn started by a background task completion notification (detached subagent / background bash / process task injecting an
origin: { kind: 'task' }user message while the agent is idle) mounts no fold-segment boundary of its own: the injected message is never rendered, and the task's terminal status card is mounted asynchronously at termination time, decoupled from the turn it belongs to. When such a notification turn ends, its output shares the previous user turn's fold segment, so the fold cap folds the previous turn's final answer into the step summary — the answer disappears from the transcript and cannot be expanded.This is the same root cause as #3154 (cron-fired turns), which fixed the cron variant by treating the cron card as a fold-segment boundary.
What changed
Minimal, precedent-following fix (a turnId-ownership-based boundary rework is intentionally left for a future, unified discussion). Three logical pieces:
tui/kimi-tui.ts—isFoldSegmentBoundaryComponentnow also accepts aBackgroundAgentStatusComponentwhose phase is terminal (anything butstarted;started-phase cards are excluded so merely starting a background task does not fragment the active turn's fold segment).tui/components/messages/background-agent-status.tsexposes the card'sphasefor the check.tui/controllers/session-event-handler.ts— onturn.startedwith ataskorigin,anchorTaskNotificationTurnmoves the task's already-mounted terminal card to the turn start (moveTranscriptEntryToEnd, so each notification turn begins with its own boundary), falling back to mounting a card when none exists (e.g. an agent that terminated without a lifecycle card). Cards are tracked in abackgroundTaskTerminalEntriesmap populated at every mount path — the terminated branch (process/question, behavior unchanged from main) and the subagent lifecycle handler (agent completed/failed/killed).BackgroundAgentMetadatanow carries the optionaltaskIdfromsubagent.spawned(filled by the Agent tool at registration), so an agent that completes beforebackground.task.startedsyncs the task map still registers its card immediately instead of relying on the not-yet-synced lookup.BackgroundAgentStatusDatacarries theagentId, and the anchor resolves the turn'staskIdto itsagentIdvia the (by then synced) task map and reuses an existing orphaned terminal card — covering Tower spawns, which omittaskIdat spawn time. Cards already registered to a differenttaskIdare skipped, so a resumed background agent (which intentionally shares its predecessor'sagentId) never inherits the previous run's card.Deliberately not changed: the
background.task.terminatedbranch keeps main's behavior (agent-kind tasks still mount nothing there) — making all kinds mount a card turned out to be an out-of-scope UX change and a source of duplicate-card races. Replay needed no changes: it already mounts the notification card at the notification's position, matching the anchored live behavior.Trade-off, same as #3154 accepted for mid-turn cron fires: a task that terminates while a turn is still running inserts a segment boundary mid-turn, so that turn's earlier steps may stay expanded instead of being folded. Correctness (never folding away an answer) takes precedence over compactness.
Out of scope, tracked as follow-up:
trimTranscriptWindoweviction still only recognizes user-turn boundaries, so a long autonomous run of task-notification turns is not window-trimmed (pre-existing on main; fixing it touches undo/replay/fold interactions and belongs in its own change).Tests
New regression tests (each fails before its respective fix, passes after):
test/tui/kimi-tui-message-flow.test.ts— the previous turn's final answer stays mounted when a task-notification turn completes (background bash and tower/worker paths), and when another task terminates mid notification turn (anchor scenario).test/tui/message-replay.test.ts— same guarantee on the replay path.test/tui/controllers/session-event-handler-background-task.test.ts— completion-before-task-sync registers exactly one card; Tower-style spawn withouttaskIdreuses the orphaned card; a resumed agent sharing anagentIdnever steals the previous run's card; an agent that terminates with no lifecycle card gets one mounted at anchor time.Full
test/tuisuite green (one pre-existing, environment-dependent failure intest/tui/commands/registry.test.ts— it reads$HOMEand fails identically on a clean checkout).tsc --noEmitclean;oxlint --type-aware0 errors.Checklist
gen-changesetsskill (patch changeset included).gen-docsskill, or this PR needs no doc update.