Skip to content

Commit 3217f45

Browse files
obviyusvincentkoc
authored andcommitted
fix(channels): preserve command progress detail
(cherry picked from commit 392039a)
1 parent dbd5689 commit 3217f45

7 files changed

Lines changed: 40 additions & 35 deletions

File tree

extensions/discord/src/monitor/message-handler.process.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3057,8 +3057,8 @@ describe("processDiscordMessage draft streaming", () => {
30573057
await runProcessDiscordMessage(ctx);
30583058

30593059
const lastUpdate = draftStream.update.mock.calls.at(-1)?.[0];
3060-
expect(lastUpdate).toContain("completed");
3061-
expect(lastUpdate).not.toContain("install dependencies");
3060+
expect(lastUpdate).toContain("install dependencies");
3061+
expect(lastUpdate).not.toContain("completed");
30623062
});
30633063

30643064
it("drops later tool warning finals after progress preview final replies", async () => {

extensions/matrix/src/matrix/monitor/handler.test.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3229,13 +3229,13 @@ describe("matrix monitor handler draft streaming", () => {
32293229
expect(editMessageMatrixMock).toHaveBeenCalledWith(
32303230
"!room:example.org",
32313231
"$draft1",
3232-
expect.stringContaining("completed"),
3232+
expect.stringContaining("Exec"),
32333233
expect.any(Object),
32343234
);
32353235
const recoveredEdit = mockCalls(editMessageMatrixMock, "editMessageMatrix").find(
3236-
([, eventId, body]) =>
3237-
eventId === "$draft1" && typeof body === "string" && body.includes("completed"),
3236+
([, eventId, body]) => eventId === "$draft1" && typeof body === "string",
32383237
);
3238+
expect(recoveredEdit?.[2]).not.toContain("completed");
32393239
expect(recoveredEdit?.[2]).not.toContain("failed");
32403240
expect(recoveredEdit?.[2]).not.toContain("run openclaw cron -> run jq");
32413241
});
@@ -3293,7 +3293,8 @@ describe("matrix monitor handler draft streaming", () => {
32933293
([, eventId, body]) =>
32943294
eventId === "$draft1" && typeof body === "string" && body.includes("completed"),
32953295
);
3296-
expect(completedEdit?.[2]).not.toContain("install dependencies");
3296+
expect(completedEdit).toBeUndefined();
3297+
expect(singleTextMessageBody()).toContain("install dependencies");
32973298
});
32983299

32993300
it("replaces Matrix patch progress when the patch summary completes", async () => {

extensions/msteams/src/reply-dispatcher.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,8 @@ describe("createMSTeamsReplyDispatcher", () => {
454454
});
455455

456456
const lastUpdate = getStreamMock().update.mock.calls.at(-1)?.[0];
457-
expect(lastUpdate).toContain("completed");
458-
expect(lastUpdate).not.toContain("install dependencies");
457+
expect(lastUpdate).toContain("install dependencies");
458+
expect(lastUpdate).not.toContain("completed");
459459
});
460460

461461
it("replaces reasoning progress snapshots in progress mode", async () => {

extensions/telegram/src/bot-message-dispatch.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2625,10 +2625,10 @@ describe("dispatchTelegramMessage draft streaming", () => {
26252625
});
26262626

26272627
const lastUpdate = answerDraftStream.updatePreview.mock.calls.at(-1)?.[0];
2628-
expect(lastUpdate?.text).toContain("completed");
2629-
expect(lastUpdate?.text).not.toContain("install dependencies");
2628+
expect(lastUpdate?.text).toContain("install dependencies");
2629+
expect(lastUpdate?.text).not.toContain("completed");
26302630
expect(lastUpdate?.richMessage).toEqual({
2631-
html: "<b>Shelling</b><br><b>🛠️ Exec</b> <code>completed</code>",
2631+
html: "<b>Shelling</b><br><b>🛠️ Exec</b> <code>install dependencies</code>",
26322632
skip_entity_detection: true,
26332633
});
26342634
});

src/channels/streaming.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ describe("buildChannelProgressDraftLine", () => {
2424
});
2525
});
2626

27-
it("uses completed status when successful command output has no title", () => {
27+
it("uses the tool label when successful command output has no title", () => {
2828
const line = buildChannelProgressDraftLine({
2929
event: "command-output",
3030
phase: "end",
@@ -34,10 +34,10 @@ describe("buildChannelProgressDraftLine", () => {
3434

3535
expect(line).toMatchObject({
3636
kind: "command-output",
37-
text: "🛠️ completed",
38-
detail: "completed",
37+
text: "🛠️ Exec",
3938
status: "completed",
4039
});
40+
expect(line?.detail).toBeUndefined();
4141
});
4242

4343
it("keeps command status and title in raw command progress lines", () => {

src/channels/streaming.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,15 @@ function resolveCommandProgressCorrelationKey(input: { toolCallId?: string }): s
411411
return toolCallId ? `command:${toolCallId}` : undefined;
412412
}
413413

414+
function isTerminalProgressStatus(status: string | undefined): boolean {
415+
const normalized = normalizeOptionalLowercaseString(status);
416+
return (
417+
normalized === "completed" ||
418+
normalized === "failed" ||
419+
normalized?.startsWith("exit ") === true
420+
);
421+
}
422+
414423
function isEmptyReasoningProgressItem(
415424
input: Extract<ChannelProgressDraftLineInput, { event: "item" }>,
416425
meta: string | undefined,
@@ -444,15 +453,6 @@ function buildCommandOutputProgressLine(
444453
return line;
445454
}
446455
if (status === "completed") {
447-
if (!line.detail) {
448-
const statusLine = {
449-
...line,
450-
detail: status,
451-
text: formatToolAggregate(name, [status], { markdown: options?.markdown }),
452-
};
453-
setProgressDraftLineCorrelationKey(statusLine, correlationKey);
454-
return statusLine;
455-
}
456456
return line;
457457
}
458458
if (!line.detail || line.detail === status) {
@@ -1153,13 +1153,16 @@ function mergeProgressDraftLineUpdate<TLine extends string | ChannelProgressDraf
11531153
if (
11541154
line.kind !== "command-output" ||
11551155
!line.status ||
1156-
line.status === "completed" ||
11571156
(line.detail && line.detail !== line.status)
11581157
) {
11591158
return line;
11601159
}
11611160
const previousDetail = previous.detail?.trim();
1162-
if (!previousDetail || previousDetail === previous.status) {
1161+
if (
1162+
!previousDetail ||
1163+
previousDetail === previous.status ||
1164+
isTerminalProgressStatus(previous.status)
1165+
) {
11631166
return line;
11641167
}
11651168
const replacement = {

src/plugin-sdk/channel-streaming.test.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -601,16 +601,16 @@ describe("channel-streaming", () => {
601601
expect(updated[0]).toMatchObject({
602602
id: "tool:call-1-output",
603603
kind: "command-output",
604-
detail: "completed",
604+
detail: "install dependencies",
605605
status: "completed",
606-
text: "🛠️ completed",
606+
text: "🛠️ install dependencies",
607607
});
608608
expect(
609609
formatChannelProgressDraftText({
610610
lines: updated,
611611
entry: { streaming: { progress: { label: false } } },
612612
}),
613-
).toBe("🛠️ completed");
613+
).toBe("🛠️ install dependencies");
614614

615615
const recoveredItemLine = buildChannelProgressDraftLine({
616616
event: "item",
@@ -632,19 +632,20 @@ describe("channel-streaming", () => {
632632
if (!recoveredItemLine || !recoveredCommandLine) {
633633
throw new Error("expected recovered command progress lines");
634634
}
635-
expect(
636-
mergeChannelProgressDraftLine([recoveredItemLine], recoveredCommandLine, {
637-
maxLines: 4,
638-
}),
639-
).toMatchObject([
635+
const recoveredUpdated = mergeChannelProgressDraftLine(
636+
[recoveredItemLine],
637+
recoveredCommandLine,
638+
{ maxLines: 4 },
639+
);
640+
expect(recoveredUpdated).toMatchObject([
640641
{
641642
id: "command-2",
642643
kind: "command-output",
643-
detail: "completed",
644644
status: "completed",
645-
text: "🛠️ completed",
645+
text: "🛠️ Bash",
646646
},
647647
]);
648+
expect(recoveredUpdated[0]).not.toHaveProperty("detail");
648649
});
649650

650651
it("starts progress drafts after five seconds or a second work event", async () => {

0 commit comments

Comments
 (0)