From 257d540297e6d6a94822c2da2fba43819d5bb683 Mon Sep 17 00:00:00 2001 From: keshavbotagent Date: Wed, 17 Jun 2026 00:11:59 +0530 Subject: [PATCH] Keep command text in progress drafts (#93711) * Keep command text in progress drafts * test(channels): align successful progress drafts --------- Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> --- .../monitor/message-handler.process.test.ts | 4 +- extensions/slack/src/progress-blocks.test.ts | 4 +- extensions/slack/src/progress-blocks.ts | 7 +++- .../telegram/src/bot-message-dispatch.test.ts | 4 +- .../telegram/src/bot-message-dispatch.ts | 2 +- src/channels/streaming.test.ts | 38 +++++++++++++++++++ src/channels/streaming.ts | 16 +++++--- src/plugin-sdk/channel-streaming.test.ts | 14 +++++-- 8 files changed, 72 insertions(+), 17 deletions(-) diff --git a/extensions/discord/src/monitor/message-handler.process.test.ts b/extensions/discord/src/monitor/message-handler.process.test.ts index 09473c9bc56a..9bd5fbbd5ec5 100644 --- a/extensions/discord/src/monitor/message-handler.process.test.ts +++ b/extensions/discord/src/monitor/message-handler.process.test.ts @@ -3057,8 +3057,8 @@ describe("processDiscordMessage draft streaming", () => { await runProcessDiscordMessage(ctx); const lastUpdate = draftStream.update.mock.calls.at(-1)?.[0]; - expect(lastUpdate).toContain("completed"); - expect(lastUpdate).not.toContain("install dependencies"); + expect(lastUpdate).toContain("install dependencies"); + expect(lastUpdate).not.toContain("completed"); }); it("drops later tool warning finals after progress preview final replies", async () => { diff --git a/extensions/slack/src/progress-blocks.test.ts b/extensions/slack/src/progress-blocks.test.ts index bcf83246be21..45aec9dd3b0f 100644 --- a/extensions/slack/src/progress-blocks.test.ts +++ b/extensions/slack/src/progress-blocks.test.ts @@ -134,7 +134,7 @@ describe("buildSlackProgressDraftBlocks", () => { ], }); - expectLegacyLineBlock(blocks?.[1], "• *Exec*", "command finished · completed"); + expectLegacyLineBlock(blocks?.[1], "• *Exec*", "command finished"); expectLegacyLineBlock(blocks?.[2], "• *Exec*", "command failed · exit 1"); }); @@ -243,7 +243,7 @@ describe("native Slack progress stream chunks", () => { }), ).toEqual([ planUpdate("Shelling..."), - taskUpdate("exec_1", "Exec — command finished · completed", "complete"), + taskUpdate("exec_1", "Exec — command finished", "complete"), taskUpdate("exec_2", "Exec — command failed · exit 1", "error"), ]); }); diff --git a/extensions/slack/src/progress-blocks.ts b/extensions/slack/src/progress-blocks.ts index 6ad35e44f1d8..6b911b6d7ca7 100644 --- a/extensions/slack/src/progress-blocks.ts +++ b/extensions/slack/src/progress-blocks.ts @@ -59,7 +59,12 @@ function compactChunkText(value: string): string { } function lineDetailParts(line: ChannelProgressDraftLine): string[] { - return [line.detail, line.status && !line.detail?.includes(line.status) ? line.status : undefined] + return [ + line.detail, + line.status && line.status !== "completed" && !line.detail?.includes(line.status) + ? line.status + : undefined, + ] .map((part) => part?.trim()) .filter((part): part is string => Boolean(part)); } diff --git a/extensions/telegram/src/bot-message-dispatch.test.ts b/extensions/telegram/src/bot-message-dispatch.test.ts index c07274610752..57672686829b 100644 --- a/extensions/telegram/src/bot-message-dispatch.test.ts +++ b/extensions/telegram/src/bot-message-dispatch.test.ts @@ -2625,10 +2625,10 @@ describe("dispatchTelegramMessage draft streaming", () => { }); const lastUpdate = answerDraftStream.updatePreview.mock.calls.at(-1)?.[0]; - expect(lastUpdate?.text).toContain("completed"); expect(lastUpdate?.text).toContain("install dependencies"); + expect(lastUpdate?.text).not.toContain("completed"); expect(lastUpdate?.richMessage).toEqual({ - html: "Shelling
🛠️ Exec install dependencies completed", + html: "Shelling
🛠️ Exec install dependencies", skip_entity_detection: true, }); }); diff --git a/extensions/telegram/src/bot-message-dispatch.ts b/extensions/telegram/src/bot-message-dispatch.ts index f8d5a5497805..637481870168 100644 --- a/extensions/telegram/src/bot-message-dispatch.ts +++ b/extensions/telegram/src/bot-message-dispatch.ts @@ -458,7 +458,7 @@ function renderTelegramProgressLine(line: ChannelProgressDraftCompositorLine): s parts.push(renderTelegramProgressStringLine(text)); } } - if (line.status && line.status !== line.detail) { + if (line.status && line.status !== "completed" && line.status !== line.detail) { parts.push(`${escapeTelegramProgressHtml(line.status)}`); } return parts.join(" "); diff --git a/src/channels/streaming.test.ts b/src/channels/streaming.test.ts index 802a231b590b..10e67e373d06 100644 --- a/src/channels/streaming.test.ts +++ b/src/channels/streaming.test.ts @@ -2,6 +2,44 @@ import { describe, expect, it } from "vitest"; import { buildChannelProgressDraftLine } from "./streaming.js"; describe("buildChannelProgressDraftLine", () => { + it("omits generic completed status from successful command output with title", () => { + const line = buildChannelProgressDraftLine( + { + event: "command-output", + toolCallId: "exec-1", + phase: "end", + title: "pwd", + name: "exec", + exitCode: 0, + }, + { commandText: "raw" }, + ); + + expect(line).toMatchObject({ + kind: "command-output", + id: "exec-1", + text: "🛠️ pwd", + detail: "pwd", + status: "completed", + }); + }); + + it("uses the tool label when successful command output has no title", () => { + const line = buildChannelProgressDraftLine({ + event: "command-output", + phase: "end", + name: "exec", + exitCode: 0, + }); + + expect(line).toMatchObject({ + kind: "command-output", + text: "🛠️ Exec", + status: "completed", + }); + expect(line?.detail).toBeUndefined(); + }); + it("keeps command status and title in raw command progress lines", () => { const line = buildChannelProgressDraftLine( { diff --git a/src/channels/streaming.ts b/src/channels/streaming.ts index 80759a961eb3..f9f325b2379f 100644 --- a/src/channels/streaming.ts +++ b/src/channels/streaming.ts @@ -443,6 +443,9 @@ function buildCommandOutputProgressLine( if (!line || !status) { return line; } + if (status === "completed") { + return line; + } if (!line.detail || line.detail === status) { const statusLine = { ...line, @@ -1055,11 +1058,14 @@ function getProgressDraftLineText(line: string | ChannelProgressDraftLine): stri const label = line.label.trim(); const detail = line.detail?.trim(); const status = line.status?.trim(); + const displayStatus = status === "completed" ? undefined : status; if (detail) { const compactCommandLine = line.toolName === "exec" || line.toolName === "bash" || line.toolName === "shell"; - if (line.kind === "command-output" && status && detail !== status) { - const outputDetail = detail.startsWith(`${status};`) ? detail : `${status}; ${detail}`; + if (line.kind === "command-output" && displayStatus && detail !== displayStatus) { + const outputDetail = detail.startsWith(`${displayStatus};`) + ? detail + : `${displayStatus}; ${detail}`; if (compactCommandLine) { return `${prefix}${outputDetail}`; } @@ -1070,11 +1076,11 @@ function getProgressDraftLineText(line: string | ChannelProgressDraftLine): stri } return `${prefix}${detail}`; } - if (status) { + if (displayStatus) { if (label) { - return `${prefix}${label}: ${status}`; + return `${prefix}${label}: ${displayStatus}`; } - return `${prefix}${status}`; + return `${prefix}${displayStatus}`; } const text = line.text.trim(); if (!icon && text && text !== label) { diff --git a/src/plugin-sdk/channel-streaming.test.ts b/src/plugin-sdk/channel-streaming.test.ts index 378b2507b85c..7fff4a7b4ac9 100644 --- a/src/plugin-sdk/channel-streaming.test.ts +++ b/src/plugin-sdk/channel-streaming.test.ts @@ -601,10 +601,16 @@ describe("channel-streaming", () => { expect(updated[0]).toMatchObject({ id: "tool:call-1-output", kind: "command-output", - status: "completed", detail: "install dependencies", - text: "🛠️ completed; install dependencies", + status: "completed", + text: "🛠️ install dependencies", }); + expect( + formatChannelProgressDraftText({ + lines: updated, + entry: { streaming: { progress: { label: false } } }, + }), + ).toBe("🛠️ install dependencies"); const recoveredItemLine = buildChannelProgressDraftLine({ event: "item", @@ -634,9 +640,9 @@ describe("channel-streaming", () => { { id: "command-2", kind: "command-output", - status: "completed", detail: "install dependencies failed", - text: "🛠️ completed; install dependencies failed", + status: "completed", + text: "🛠️ install dependencies failed", }, ]); });