Skip to content

Commit fa9b8c8

Browse files
committed
test(telegram): cover raw rich progress output
1 parent f5a9456 commit fa9b8c8

2 files changed

Lines changed: 139 additions & 4 deletions

File tree

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

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2523,7 +2523,7 @@ describe("dispatchTelegramMessage draft streaming", () => {
25232523
});
25242524

25252525
expect(answerDraftStream.updatePreview).not.toHaveBeenCalledWith(
2526-
expect.stringContaining("stdout line one"),
2526+
expect.objectContaining({ text: expect.stringContaining("stdout line one") }),
25272527
);
25282528
expect(answerDraftStream.updatePreview).toHaveBeenLastCalledWith(
25292529
expect.objectContaining({
@@ -2758,6 +2758,92 @@ describe("dispatchTelegramMessage draft streaming", () => {
27582758
expect(draftStream.flush).toHaveBeenCalled();
27592759
});
27602760

2761+
it("renders command status without command output in Telegram progress draft previews", async () => {
2762+
const draftStream = createSequencedDraftStream(2001);
2763+
createTelegramDraftStream.mockReturnValue(draftStream);
2764+
dispatchReplyWithBufferedBlockDispatcher.mockImplementation(async ({ replyOptions }) => {
2765+
await replyOptions?.onReplyStart?.();
2766+
await replyOptions?.onAssistantMessageStart?.();
2767+
await replyOptions?.onToolStart?.({
2768+
name: "exec",
2769+
phase: "start",
2770+
toolCallId: "exec-1",
2771+
args: { command: "false" },
2772+
});
2773+
await replyOptions?.onCommandOutput?.({
2774+
phase: "end",
2775+
title: "command false",
2776+
name: "exec",
2777+
toolCallId: "exec-1",
2778+
output: "No such file or directory",
2779+
exitCode: 2,
2780+
});
2781+
return { queuedFinal: false };
2782+
});
2783+
2784+
await dispatchWithContext({
2785+
context: createContext(),
2786+
streamMode: "progress",
2787+
telegramCfg: {
2788+
streaming: {
2789+
mode: "progress",
2790+
progress: { label: "Shelling", commandText: "raw" },
2791+
},
2792+
},
2793+
});
2794+
2795+
expect(draftStream.updatePreview).toHaveBeenLastCalledWith({
2796+
text: "Shelling\n\n`🛠️ exit 2; command false`",
2797+
richMessage: {
2798+
html: "<b>Shelling</b><br><b>🛠️ Exec</b> <code>command false</code> <i>exit 2</i>",
2799+
skip_entity_detection: true,
2800+
},
2801+
});
2802+
});
2803+
2804+
it("hides command titles in Telegram status-only progress draft previews", async () => {
2805+
const draftStream = createSequencedDraftStream(2001);
2806+
createTelegramDraftStream.mockReturnValue(draftStream);
2807+
dispatchReplyWithBufferedBlockDispatcher.mockImplementation(async ({ replyOptions }) => {
2808+
await replyOptions?.onReplyStart?.();
2809+
await replyOptions?.onAssistantMessageStart?.();
2810+
await replyOptions?.onToolStart?.({
2811+
name: "exec",
2812+
phase: "start",
2813+
toolCallId: "exec-1",
2814+
args: { command: "curl -H 'Authorization: token' https://example.test" },
2815+
});
2816+
await replyOptions?.onCommandOutput?.({
2817+
phase: "end",
2818+
title: "curl -H 'Authorization: token' https://example.test",
2819+
name: "exec",
2820+
toolCallId: "exec-1",
2821+
output: "secret response",
2822+
exitCode: 2,
2823+
});
2824+
return { queuedFinal: false };
2825+
});
2826+
2827+
await dispatchWithContext({
2828+
context: createContext(),
2829+
streamMode: "progress",
2830+
telegramCfg: {
2831+
streaming: {
2832+
mode: "progress",
2833+
progress: { label: "Shelling", commandText: "status" },
2834+
},
2835+
},
2836+
});
2837+
2838+
expect(draftStream.updatePreview).toHaveBeenLastCalledWith({
2839+
text: "Shelling\n\n`🛠️ exit 2`",
2840+
richMessage: {
2841+
html: "<b>Shelling</b><br><b>🛠️ Exec</b> <code>exit 2</code>",
2842+
skip_entity_detection: true,
2843+
},
2844+
});
2845+
});
2846+
27612847
it("composes streamed reasoning with tool progress in Telegram progress drafts", async () => {
27622848
const draftStream = createSequencedDraftStream(2001);
27632849
createTelegramDraftStream.mockReturnValue(draftStream);
@@ -2842,9 +2928,11 @@ describe("dispatchTelegramMessage draft streaming", () => {
28422928
},
28432929
});
28442930

2845-
expect(draftStream.updatePreview).not.toHaveBeenCalledWith(
2846-
expect.objectContaining({ text: expect.stringContaining("Checking recent") }),
2847-
);
2931+
expect(
2932+
draftStream.updatePreview.mock.calls.every(
2933+
([preview]) => !preview.text.includes("Checking recent"),
2934+
),
2935+
).toBe(true);
28482936
});
28492937

28502938
it("keeps the progress draft label when tool progress lines are hidden", async () => {

src/channels/streaming.test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { describe, expect, it } from "vitest";
2+
import { buildChannelProgressDraftLine } from "./streaming.js";
3+
4+
describe("buildChannelProgressDraftLine", () => {
5+
it("keeps command status and title in raw command progress lines", () => {
6+
const line = buildChannelProgressDraftLine(
7+
{
8+
event: "command-output",
9+
toolCallId: "exec-1",
10+
phase: "end",
11+
title: "command false",
12+
name: "exec",
13+
exitCode: 2,
14+
},
15+
{ commandText: "raw" },
16+
);
17+
18+
expect(line).toMatchObject({
19+
kind: "command-output",
20+
id: "exec-1",
21+
text: "🛠️ exit 2; command false",
22+
detail: "command false",
23+
status: "exit 2",
24+
});
25+
});
26+
27+
it("keeps only command status in status-only progress lines", () => {
28+
const line = buildChannelProgressDraftLine(
29+
{
30+
event: "command-output",
31+
phase: "end",
32+
title: "command false",
33+
name: "exec",
34+
exitCode: 2,
35+
},
36+
{ commandText: "status" },
37+
);
38+
39+
expect(line).toMatchObject({
40+
kind: "command-output",
41+
text: "🛠️ exit 2",
42+
detail: "exit 2",
43+
status: "exit 2",
44+
});
45+
expect(line?.text).not.toContain("command false");
46+
});
47+
});

0 commit comments

Comments
 (0)