From 8aaeaadcdc9fca04cdf27a27ffece9bd84b9a3d1 Mon Sep 17 00:00:00 2001 From: can1357 Date: Sat, 3 Jan 2026 05:30:37 +0100 Subject: [PATCH] fix(coding-agent): fixed Task tool output duplication from streaming events message_update events contain full accumulated text, not deltas. Previously appending them caused repeated content in artifacts and progress display. Now message_update only updates progress display (replacing, not accumulating) and message_end handles final output. --- packages/coding-agent/CHANGELOG.md | 5 ++++ .../src/core/tools/task/executor.ts | 29 ++++++++++++------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index d5cd7b520..a5ac86359 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -17,6 +17,11 @@ - Updated bundled `reviewer` agent to use structured review tools with priority-based findings (P0-P3) and formal verdict submission +### Fixed + +- Fixed Task tool output artifacts (`out.md`) containing duplicated text from streaming updates +- Fixed Task tool progress display showing repeated nearly-identical lines during streaming + ## [1.341.0] - 2026-01-03 ### Added diff --git a/packages/coding-agent/src/core/tools/task/executor.ts b/packages/coding-agent/src/core/tools/task/executor.ts index a3aebab41..e3255865c 100644 --- a/packages/coding-agent/src/core/tools/task/executor.ts +++ b/packages/coding-agent/src/core/tools/task/executor.ts @@ -259,22 +259,29 @@ export async function runSubprocess(options: ExecutorOptions): Promise l.trim()); + allText.push(...lines); + } + } + // Show last 8 lines from current state (not accumulated) + progress.recentOutput = allText.slice(-8).reverse(); + } + break; + } + case "message_end": { - // Extract text content for recent output (prefer message.content, fallback to event.content) + // Extract final text content from completed message const messageContent = event.message?.content || event.content; if (messageContent && Array.isArray(messageContent)) { for (const block of messageContent) { if (block.type === "text" && block.text) { - const lines = block.text.split("\n").filter((l: string) => l.trim()); - for (const l of lines) { - if (!progress.recentOutput.includes(l)) { - progress.recentOutput.unshift(l); - if (progress.recentOutput.length > 8) { - progress.recentOutput.pop(); - } - } - } output += block.text; } }