From b721ec1445f3078006a405fe0040360714475f4f Mon Sep 17 00:00:00 2001 From: Nils Reeh Date: Wed, 15 Apr 2026 02:36:07 +0200 Subject: [PATCH] fix(pi-coding-agent): finalize streaming component on agent_end instead of removing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When message_end does not fire before agent_end (e.g. abort path), the agent_end case was calling chatContainer.removeChild(streamingComponent), which silently erased the last assistant message from the TUI chat history. Fix: follow the message_end finalization pattern — call setShowMetadata(true) and updateContent() before clearing the reference. Never call removeChild on a component that was added to the persistent chat history. Closes #4197 --- .../interactive/controllers/chat-controller.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts b/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts index 59d780223..cc6078394 100644 --- a/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +++ b/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts @@ -546,11 +546,18 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & { host.loadingAnimation = undefined; host.statusContainer.clear(); } - if (host.streamingComponent) { - host.chatContainer.removeChild(host.streamingComponent); - host.streamingComponent = undefined; - host.streamingMessage = undefined; + // If message_end did not already finalize the streaming component + // (e.g. abort path or event ordering edge case), finalize it now + // instead of removing it. Calling removeChild would erase the last + // assistant message from the chat history (issue #4197). + if (host.streamingComponent && host.streamingMessage) { + host.streamingComponent.setShowMetadata(true); + host.streamingComponent.updateContent(host.streamingMessage); } + host.streamingComponent = undefined; + host.streamingMessage = undefined; + renderedSegments = []; + lastContentLength = 0; host.pendingTools.clear(); // Pinned output is only useful while work is actively streaming. // Keep chat history as the single source after completion.