fix(tui): stop pinned latest-output mirror from duplicating streaming text

The pinned `Working · Latest Output` border above the editor mirrors
the assistant's latest text block while tools run, so prose stays
visible after a tool's output scrolls it off-screen. The mirror walked
content blocks from the end and picked the last text block — but when
the assistant streams a *new* text block after a tool call (sequence
`[text1, tool1, text2_streaming]`), it picked `text2`, which was also
being streamed live into the chat container. Result: identical tokens
rendered in two places at once.

Restrict the search to text blocks whose index is strictly less than
the index of the most recent tool call. Text after the last tool call
stays in the chat container only; earlier prose (e.g. `text1`) remains
mirrored the entire time the new text streams, so context isn't lost
and the loading-animation handoff is undisturbed.

Fixes #4120

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeremy 2026-04-13 08:16:16 -05:00
parent 4d41b21fbd
commit dc84694c65

View file

@ -286,9 +286,20 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
if (hasTools) hasToolsInTurn = true;
if (hasToolsInTurn) {
// Collect the latest text block(s) from the assistant message
let latestText = "";
// Mirror the latest text block that precedes the most recent tool
// call. Text blocks that come *after* the last tool call are still
// streaming live into the chat container, so mirroring them would
// duplicate the same tokens in two places at once.
let lastToolIdx = -1;
for (let i = contentBlocks.length - 1; i >= 0; i--) {
const c = contentBlocks[i] as any;
if (c.type === "toolCall" || c.type === "serverToolUse") {
lastToolIdx = i;
break;
}
}
let latestText = "";
for (let i = lastToolIdx - 1; i >= 0; i--) {
const c = contentBlocks[i] as any;
if (c.type === "text" && c.text?.trim()) {
latestText = c.text.trim();