Files
openclaw/test/scripts/channel-message-flows.test.ts
Patrick Erichsen d60ab48511 Add Telegram progress preview flows (#83847)
* feat(telegram): add progress preview flow tooling

* docs: add channel flow preview skill

* test(telegram): exercise native draft flow fixture

* fix(telegram): remove progress label ellipsis animation

* fix(telegram): address progress preview review
2026-05-18 21:23:55 -07:00

184 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it, vi } from "vitest";
import {
parseChannelMessageFlowArgs,
resolveTelegramFlowThreadSpec,
runTelegramThinkingFinalFlow,
runTelegramWorkingFinalFlow,
} from "../../scripts/dev/channel-message-flows.ts";
import type { OpenClawConfig } from "../../src/config/types.openclaw.js";
describe("channel message flows dev runner", () => {
it("parses the Telegram thinking-final flow from channel/target flags", () => {
const parsed = parseChannelMessageFlowArgs([
"--channel",
"telegram",
"--target",
"123",
"--flow",
"thinking-final",
"--account",
"sut",
"--thread-id",
"42",
"--delay-ms",
"0",
]);
expect(parsed).toEqual({
accountId: "sut",
channel: "telegram",
delayMs: 0,
flow: "thinking-final",
target: "123",
threadId: 42,
});
});
it("parses the Telegram working-final flow from channel/chat flags", () => {
const parsed = parseChannelMessageFlowArgs([
"--channel",
"telegram",
"--chat",
"123",
"--flow",
"working-final",
"--duration-ms",
"12000",
"--delay-ms",
"0",
]);
expect(parsed).toEqual({
channel: "telegram",
delayMs: 0,
durationMs: 12000,
flow: "working-final",
target: "123",
});
});
it("streams thinking updates, clears the preview, then sends the final answer", async () => {
const events: string[] = [];
const stream = {
update: vi.fn((text: string) => {
events.push(`update:${text}`);
}),
flush: vi.fn(async () => {
events.push("flush");
}),
clear: vi.fn(async () => {
events.push("clear");
}),
stop: vi.fn(async () => {}),
messageId: vi.fn(() => 17),
forceNewMessage: vi.fn(),
};
const sendFinal = vi.fn(async () => {
events.push("final");
return { messageId: "99", chatId: "123" };
});
const result = await runTelegramThinkingFinalFlow(
{
cfg: {} as OpenClawConfig,
delayMs: 0,
target: "123",
thinkingUpdates: ["Checking the request.", "Reading the Telegram code.", "Ready."],
},
{
createDraftStream: vi.fn(() => stream),
sendFinal,
sleep: vi.fn(async () => {}),
},
);
expect(stream.update).toHaveBeenCalledTimes(3);
expect(stream.update.mock.calls[0]?.[0]).toContain("Thinking");
expect(stream.update.mock.calls[0]?.[0]).toContain("_Checking the request._");
expect(events.at(-2)).toBe("clear");
expect(events.at(-1)).toBe("final");
expect(sendFinal).toHaveBeenCalledWith({
accountId: undefined,
cfg: {},
target: "123",
text: "Final answer: the Telegram thinking preview cleared and this durable reply landed.",
threadId: undefined,
});
expect(result).toEqual({ finalMessageId: "99", previewUpdates: 3 });
});
it("streams working updates through native message drafts before the final answer", async () => {
const draft = {
update: vi.fn(async () => true),
stop: vi.fn(async () => {}),
};
const sendFinal = vi.fn(async () => ({ messageId: "100", chatId: "123" }));
const result = await runTelegramWorkingFinalFlow(
{
cfg: {} as OpenClawConfig,
delayMs: 0,
durationMs: 12_000,
target: "123",
},
{
createNativeToolProgressDraft: vi.fn(() => draft),
sendFinal,
sleep: vi.fn(async () => {}),
},
);
expect(draft.update).toHaveBeenNthCalledWith(1, "Working");
expect(draft.update.mock.calls[2]?.[0]).toContain("🛠️ pgrep -fl Discord || true (agent)");
expect(draft.update.mock.calls[2]?.[0]).toContain(
"🛠️ list files in /Applications/Discord.app -> run true (agent)",
);
expect(draft.update.mock.calls[4]?.[0]).toContain(
"• Discord is installed as a normal '/Applications/Discord.app'",
);
expect(draft.update).toHaveBeenCalledWith(
expect.stringContaining("Working\n\n🛠 pgrep -fl Discord || true (agent)"),
);
expect(draft.stop).toHaveBeenCalledBefore(sendFinal);
expect(sendFinal).toHaveBeenCalledWith({
accountId: undefined,
cfg: {},
target: "123",
text: "Final answer: the Telegram working preview cleared and this durable reply landed.",
threadId: undefined,
});
expect(draft.update).not.toHaveBeenCalledWith(expect.stringContaining("Working for"));
expect(result).toEqual({ finalMessageId: "100", previewUpdates: 6 });
});
it("uses two second progress update cadence by default", async () => {
const draft = {
update: vi.fn(async () => true),
stop: vi.fn(async () => {}),
};
const sleep = vi.fn(async () => {});
const result = await runTelegramWorkingFinalFlow(
{
cfg: {} as OpenClawConfig,
durationMs: 20_000,
target: "123",
},
{
createNativeToolProgressDraft: vi.fn(() => draft),
sendFinal: vi.fn(async () => ({ messageId: "101", chatId: "123" })),
sleep,
},
);
expect(sleep).toHaveBeenCalledTimes(9);
expect(sleep).toHaveBeenCalledWith(2_000);
expect(result.previewUpdates).toBe(7);
});
it("maps flow thread ids to Telegram forum topic specs", () => {
expect(resolveTelegramFlowThreadSpec(42)).toEqual({ id: 42, scope: "forum" });
expect(resolveTelegramFlowThreadSpec()).toBeUndefined();
});
});