From b345b3aa57497f655f8d95d325d31dbee7cf5cb2 Mon Sep 17 00:00:00 2001 From: roboomp Date: Sun, 21 Jun 2026 15:37:04 +0000 Subject: [PATCH] fix(tui): refreshed optimistic replay handles Updated optimistic replay to track the replacement component handles created during transcript rebuilds, so expanded slash prompts still replace the raw replayed message. Extended the regression test to cover the rebuild window called out in review. Fixes #3199 --- .../src/modes/interactive-mode.ts | 20 ++++++++++--------- .../test/issue-2372-repro.test.ts | 3 ++- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/coding-agent/src/modes/interactive-mode.ts b/packages/coding-agent/src/modes/interactive-mode.ts index d1396ad53..fdc1c58ae 100644 --- a/packages/coding-agent/src/modes/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive-mode.ts @@ -1461,15 +1461,17 @@ export class InteractiveMode implements InteractiveModeContext { if (!this.optimisticUserMessageSignature) return; const submission = this.#pendingSubmittedInput; if (!submission || submission.cancelled || submission.customType) return; - this.addMessageToChat( - { - role: "user", - content: [{ type: "text", text: submission.text }, ...(submission.images ?? [])], - attribution: "user", - timestamp: Date.now(), - }, - { imageLinks: submission.imageLinks }, - ); + this.#optimisticUserMessageComponents = this.#captureAddedChatComponents(() => { + this.addMessageToChat( + { + role: "user", + content: [{ type: "text", text: submission.text }, ...(submission.images ?? [])], + attribution: "user", + timestamp: Date.now(), + }, + { imageLinks: submission.imageLinks }, + ); + }); } #formatTodoLine(todo: TodoItem, prefix: string, matched: boolean): string { diff --git a/packages/coding-agent/test/issue-2372-repro.test.ts b/packages/coding-agent/test/issue-2372-repro.test.ts index 01032ccbe..681992914 100644 --- a/packages/coding-agent/test/issue-2372-repro.test.ts +++ b/packages/coding-agent/test/issue-2372-repro.test.ts @@ -116,6 +116,7 @@ describe("issue #2372 pre-streaming chat rebuild preserves optimistic submission const addMessageSpy = vi.spyOn(mode, "addMessageToChat"); mode.startPendingSubmission({ text: "/jira-task" }); + mode.rebuildChatFromMessages(); await controller.handleEvent({ type: "message_start", message: { @@ -135,7 +136,7 @@ describe("issue #2372 pre-streaming chat rebuild preserves optimistic submission .map(content => content.text) .join("\n"); }); - expect(renderedTexts).toEqual(["/jira-task", "Expanded Jira task prompt"]); + expect(renderedTexts).toEqual(["/jira-task", "/jira-task", "Expanded Jira task prompt"]); expect(mode.chatContainer.children).toHaveLength(1); expect(mode.optimisticUserMessageSignature).toBeUndefined(); expect(mode.locallySubmittedUserSignatures.has("/jira-task\u00000")).toBe(false);