From e7f3fde12bacf6bbfd6519c7384a657d7c803a8a Mon Sep 17 00:00:00 2001 From: can1357 Date: Wed, 22 Jul 2026 20:51:04 +0200 Subject: [PATCH] fix(tui): prune settled-component cache to rendered messages on rebuild Session entries keep AgentMessage objects strongly reachable for the whole session, so WeakMap entries for compacted-away history pinned their components' rendered layout caches forever. Rebuild now retains only components for messages the new transcript context actually renders. --- packages/coding-agent/src/modes/interactive-mode.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/coding-agent/src/modes/interactive-mode.ts b/packages/coding-agent/src/modes/interactive-mode.ts index 259a027dd..8f4583bf2 100644 --- a/packages/coding-agent/src/modes/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive-mode.ts @@ -1691,6 +1691,17 @@ export class InteractiveMode implements InteractiveModeContext { const context = this.viewSession.buildTranscriptSessionContext({ collapseCompactedHistory: settings.get("display.collapseCompacted"), }); + // Prune the settled-component cache to the messages this rebuild will + // actually render. Message objects stay strongly reachable through + // session entries for the whole session, so entries for compacted-away + // history would otherwise pin their components' rendered layout caches + // forever — exactly the memory a collapsed compaction used to release. + const retained = new WeakMap(); + for (const message of context.messages) { + const component = this.transcriptMessageComponents.get(message); + if (component) retained.set(message, component); + } + this.transcriptMessageComponents = retained; this.renderSessionContext(context, { reuseSettledComponents: options.reuseSettledComponents }); for (const child of liveComponents) { this.chatContainer.addChild(child);