fix(tui): reclaim transcript entries when turns fold - #2603
Conversation
foldCurrentTurnContent and mergeAllTurnSteps dispose the merged components and splice the child list, but the matching entries stayed in state.transcriptEntries forever, so the entry list grew underneath the folded component tree. The Component-to-entry WeakMap already existed for exactly this mapping; use it to drop folded entries along with their components. Refs MoonshotAI#2556
|
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1dee7cfbc9
ℹ️ 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".
| const entry = getTranscriptComponentEntry(component); | ||
| if (entry !== undefined) dropped.add(entry); |
There was a problem hiding this comment.
Reclaim entries created by the streaming controller
When assistant blocks are created through the normal live or replay path, StreamingUIController.onStreamingTextStart() pushes the entry and component separately without calling markTranscriptComponent (streaming-ui.ts:593-608), so this lookup returns undefined for the assistant components being folded. Once a turn exceeds the assistant cap, the components disappear but their potentially large text entries remain in transcriptEntries; the new test misses this because it uses appendTranscriptEntry(), which does establish the mapping. Associate the entry when the streaming controller creates the component, or reclaim it through another reliable association.
AGENTS.md reference: apps/kimi-code/AGENTS.md:L38-L39
Useful? React with 👍 / 👎.
Refs #2556.
One of the two reclaim paths in that issue: both fold paths (
foldCurrentTurnContenton turn completion,mergeAllTurnStepsfor replayed sessions) dispose the merged components and splice the transcript child list, but the matching entries stay instate.transcriptEntriesforever. Components shrink to a summary while the entry list keeps every thinking/tool/assistant record underneath, so memory keeps growing in exactly the sessions folding was meant to bound.The
Component ↔ TranscriptEntryWeakMap already exists for this mapping. Both fold paths now route their merged children through a small helper that drops the matching entries along with the components.Scope note: this is the unambiguous half of #2556. The other half (pure
!sessions pinning every entry in the untrimmable tail turn) is a trim-policy question, deliberately left out here.Verification
New
transcript-fold-reclaim.test.tsbuilds a realKimiTUIagainst a mock harness, appends a turn with four assistant entries, folds on completion, and asserts the two folded entries are gone fromtranscriptEntries(the tail and the summary stay), plus the no-op case under the caps. The fold test fails without the change (entries survive the fold) and passes with it. Fullapps/kimi-codeTUI suite: 127 files, 1718 tests pass. oxlint/tsc clean.