From c30ffe25d635017581a871b8bead05182b0146fc Mon Sep 17 00:00:00 2001 From: Fernando Celmer Date: Sat, 15 Aug 2026 22:42:17 -0300 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=AA=B2=20BUG-#28:=20Track=20rendered?= =?UTF-8?q?=20assistant=20text=20alongside=20turnEndSeen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- media/dom.js | 1 + 1 file changed, 1 insertion(+) diff --git a/media/dom.js b/media/dom.js index b07ba02..a539481 100644 --- a/media/dom.js +++ b/media/dom.js @@ -54,6 +54,7 @@ const sessionGalleryNew = document.getElementById("session-gallery-new"); let assistantTurn = null; let pendingAssistantText = ""; let turnEndSeen = false; +let renderedAssistantText = ""; let isBusy = false; const pendingToolCards = new Map(); let currentModel = ""; From c92d032896b460ecbe33952320cc2db92c645f7d Mon Sep 17 00:00:00 2001 From: Fernando Celmer Date: Sat, 15 Aug 2026 22:42:17 -0300 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=AA=B2=20BUG-#28:=20Accumulate=20clos?= =?UTF-8?q?ed=20turn=20text=20into=20renderedAssistantText?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- media/chat-turns.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/media/chat-turns.js b/media/chat-turns.js index 3ef6cad..7d36397 100644 --- a/media/chat-turns.js +++ b/media/chat-turns.js @@ -244,6 +244,9 @@ function finishAssistantTurn(fallbackText) { } else if (!assistantTurn.rawText.trim()) { assistantTurn.turnEl.remove(); } + if (assistantTurn && assistantTurn.rawText) { + renderedAssistantText += assistantTurn.rawText; + } assistantTurn = null; } From 2ef8569bbec33009132e26de228d8f14ead59dd0 Mon Sep 17 00:00:00 2001 From: Fernando Celmer Date: Sat, 15 Aug 2026 22:42:17 -0300 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=AA=B2=20BUG-#28:=20Flush=20unrendere?= =?UTF-8?q?d=20remainder=20of=20done=20text=20instead=20of=20dropping=20it?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- media/app.js | 12 ++++++++++-- media/composer.js | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/media/app.js b/media/app.js index 0727c9d..cbcb5d4 100644 --- a/media/app.js +++ b/media/app.js @@ -76,11 +76,19 @@ window.addEventListener("message", (event) => { case "retry": addSystemNote("Retrying (" + message.attempt + "/3) — " + message.error, true); break; - case "done": - finishAssistantTurn(turnEndSeen ? undefined : message.text); + case "done": { + let fallback = message.text; + if (turnEndSeen) { + fallback = message.text.startsWith(renderedAssistantText) + ? message.text.slice(renderedAssistantText.length).trimStart() + : ""; + } + finishAssistantTurn(fallback || undefined); turnEndSeen = false; + renderedAssistantText = ""; setBusy(false); break; + } case "error": finishAssistantTurn(); addErrorNote(message.message); diff --git a/media/composer.js b/media/composer.js index 8189a69..1115ec2 100644 --- a/media/composer.js +++ b/media/composer.js @@ -66,6 +66,7 @@ function send() { renderAttachmentsPreview(); assistantTurn = null; turnEndSeen = false; + renderedAssistantText = ""; setBusy(true); showThinkingIndicator(); vscode.postMessage({ type: "sendPrompt", prompt, images }); From 624d0de979e78c40761b2a4069f04e56ee553cfe Mon Sep 17 00:00:00 2001 From: Fernando Celmer Date: Sun, 16 Aug 2026 00:09:41 -0300 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=AA=B2=20BUG-#28:=20Preserve=20leadin?= =?UTF-8?q?g=20whitespace=20and=20warn=20on=20text=20mismatch=20in=20done?= =?UTF-8?q?=20fallback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- media/app.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/media/app.js b/media/app.js index cbcb5d4..8a1b592 100644 --- a/media/app.js +++ b/media/app.js @@ -79,9 +79,16 @@ window.addEventListener("message", (event) => { case "done": { let fallback = message.text; if (turnEndSeen) { - fallback = message.text.startsWith(renderedAssistantText) - ? message.text.slice(renderedAssistantText.length).trimStart() - : ""; + if (message.text.startsWith(renderedAssistantText)) { + const remainder = message.text.slice(renderedAssistantText.length); + fallback = remainder.trim() ? remainder : ""; + } else { + console.warn( + "[vscodeloop] done: text/renderedAssistantText mismatch — using full text as fallback", + { textLen: message.text.length, renderedLen: renderedAssistantText.length } + ); + fallback = message.text; + } } finishAssistantTurn(fallback || undefined); turnEndSeen = false; From 9fee5b04e9f1e4656c1b793280fd614d040aef95 Mon Sep 17 00:00:00 2001 From: Fernando Celmer Date: Sun, 16 Aug 2026 00:09:41 -0300 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=93=9D=20LINT-#28:=20Declare=20turnEn?= =?UTF-8?q?dSeen/renderedAssistantText=20globals=20for=20ESLint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- eslint.config.mjs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eslint.config.mjs b/eslint.config.mjs index 0f7fb55..8bb04cf 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -114,6 +114,7 @@ export default tseslint.config( renderTable: "writable", renderTextBlock: "writable", renderThinkingText: "writable", + renderedAssistantText: "writable", renderToolCall: "writable", resolveAsideTurn: "writable", resolveToolResult: "writable", @@ -141,6 +142,7 @@ export default tseslint.config( thinkingStartedAt: "writable", thinkingTimer: "writable", toolIcon: "writable", + turnEndSeen: "writable", updateCommandMenu: "writable", vscode: "writable", },