mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 00:53:28 +00:00
fix(telegram): add initial message debounce for better push notifications (#18147)
Merged via /review-pr -> /prepare-pr -> /merge-pr.
Prepared head SHA: 5e2285b6a0
Co-authored-by: Marvae <11957602+Marvae@users.noreply.github.com>
Co-authored-by: obviyus <22031114+obviyus@users.noreply.github.com>
Reviewed-by: @obviyus
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createTelegramDraftStream } from "./draft-stream.js";
|
||||
|
||||
function createMockDraftApi(sendMessageImpl?: () => Promise<{ message_id: number }>) {
|
||||
@@ -134,3 +134,142 @@ describe("createTelegramDraftStream", () => {
|
||||
expect(api.sendMessage).toHaveBeenLastCalledWith(123, "After thinking", undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe("draft stream initial message debounce", () => {
|
||||
const createMockApi = () => ({
|
||||
sendMessage: vi.fn().mockResolvedValue({ message_id: 42 }),
|
||||
editMessageText: vi.fn().mockResolvedValue(true),
|
||||
deleteMessage: vi.fn().mockResolvedValue(true),
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
describe("isFinal has highest priority", () => {
|
||||
it("sends immediately on stop() even with 1 character", async () => {
|
||||
const api = createMockApi();
|
||||
const stream = createTelegramDraftStream({
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
api: api as any,
|
||||
chatId: 123,
|
||||
minInitialChars: 30,
|
||||
});
|
||||
|
||||
stream.update("Y");
|
||||
await stream.stop();
|
||||
await stream.flush();
|
||||
|
||||
expect(api.sendMessage).toHaveBeenCalledWith(123, "Y", undefined);
|
||||
});
|
||||
|
||||
it("sends immediately on stop() with short sentence", async () => {
|
||||
const api = createMockApi();
|
||||
const stream = createTelegramDraftStream({
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
api: api as any,
|
||||
chatId: 123,
|
||||
minInitialChars: 30,
|
||||
});
|
||||
|
||||
stream.update("Ok.");
|
||||
await stream.stop();
|
||||
await stream.flush();
|
||||
|
||||
expect(api.sendMessage).toHaveBeenCalledWith(123, "Ok.", undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe("minInitialChars threshold", () => {
|
||||
it("does not send first message below threshold", async () => {
|
||||
const api = createMockApi();
|
||||
const stream = createTelegramDraftStream({
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
api: api as any,
|
||||
chatId: 123,
|
||||
minInitialChars: 30,
|
||||
});
|
||||
|
||||
stream.update("Processing"); // 10 chars, below 30
|
||||
await stream.flush();
|
||||
|
||||
expect(api.sendMessage).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("sends first message when reaching threshold", async () => {
|
||||
const api = createMockApi();
|
||||
const stream = createTelegramDraftStream({
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
api: api as any,
|
||||
chatId: 123,
|
||||
minInitialChars: 30,
|
||||
});
|
||||
|
||||
// Exactly 30 chars
|
||||
stream.update("I am processing your request..");
|
||||
await stream.flush();
|
||||
|
||||
expect(api.sendMessage).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("works with longer text above threshold", async () => {
|
||||
const api = createMockApi();
|
||||
const stream = createTelegramDraftStream({
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
api: api as any,
|
||||
chatId: 123,
|
||||
minInitialChars: 30,
|
||||
});
|
||||
|
||||
stream.update("I am processing your request, please wait a moment"); // 50 chars
|
||||
await stream.flush();
|
||||
|
||||
expect(api.sendMessage).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("subsequent updates after first message", () => {
|
||||
it("edits normally after first message is sent", async () => {
|
||||
const api = createMockApi();
|
||||
const stream = createTelegramDraftStream({
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
api: api as any,
|
||||
chatId: 123,
|
||||
minInitialChars: 30,
|
||||
});
|
||||
|
||||
// First message at threshold (30 chars)
|
||||
stream.update("I am processing your request..");
|
||||
await stream.flush();
|
||||
expect(api.sendMessage).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Subsequent updates should edit, not wait for threshold
|
||||
stream.update("I am processing your request.. and summarizing");
|
||||
await stream.flush();
|
||||
|
||||
expect(api.editMessageText).toHaveBeenCalled();
|
||||
expect(api.sendMessage).toHaveBeenCalledTimes(1); // still only 1 send
|
||||
});
|
||||
});
|
||||
|
||||
describe("default behavior without debounce params", () => {
|
||||
it("sends immediately without minInitialChars set (backward compatible)", async () => {
|
||||
const api = createMockApi();
|
||||
const stream = createTelegramDraftStream({
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
api: api as any,
|
||||
chatId: 123,
|
||||
// no minInitialChars (backward-compatible behavior)
|
||||
});
|
||||
|
||||
stream.update("Hi");
|
||||
await stream.flush();
|
||||
|
||||
expect(api.sendMessage).toHaveBeenCalledWith(123, "Hi", undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user