mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 15:20:44 +00:00
fix(telegram): expose media group flush config
This commit is contained in:
@@ -148,7 +148,10 @@ export const registerTelegramHandlers = ({
|
||||
typeof opts.testTimings?.mediaGroupFlushMs === "number" &&
|
||||
Number.isFinite(opts.testTimings.mediaGroupFlushMs)
|
||||
? Math.max(10, Math.floor(opts.testTimings.mediaGroupFlushMs))
|
||||
: MEDIA_GROUP_TIMEOUT_MS;
|
||||
: typeof telegramCfg.mediaGroupFlushMs === "number" &&
|
||||
Number.isFinite(telegramCfg.mediaGroupFlushMs)
|
||||
? Math.max(10, Math.floor(telegramCfg.mediaGroupFlushMs))
|
||||
: MEDIA_GROUP_TIMEOUT_MS;
|
||||
|
||||
const mediaGroupBuffer = new Map<string, MediaGroupEntry>();
|
||||
let mediaGroupProcessing: Promise<void> = Promise.resolve();
|
||||
|
||||
@@ -45,9 +45,18 @@ function getChannelPostHandler() {
|
||||
return getOnHandler("channel_post") as (ctx: Record<string, unknown>) => Promise<void>;
|
||||
}
|
||||
|
||||
function getChannelPostHandlerWithRuntimeTimings() {
|
||||
createTelegramBot({ token: "tok" });
|
||||
return getOnHandler("channel_post") as (ctx: Record<string, unknown>) => Promise<void>;
|
||||
}
|
||||
|
||||
function resolveFlushTimer(setTimeoutSpy: ReturnType<typeof vi.spyOn>) {
|
||||
return resolveFlushTimerForDelay(setTimeoutSpy, TELEGRAM_TEST_TIMINGS.mediaGroupFlushMs);
|
||||
}
|
||||
|
||||
function resolveFlushTimerForDelay(setTimeoutSpy: ReturnType<typeof vi.spyOn>, delayMs: number) {
|
||||
const flushTimerCallIndex = setTimeoutSpy.mock.calls.findLastIndex(
|
||||
(call: Parameters<typeof setTimeout>) => call[1] === TELEGRAM_TEST_TIMINGS.mediaGroupFlushMs,
|
||||
(call: Parameters<typeof setTimeout>) => call[1] === delayMs,
|
||||
);
|
||||
const flushTimer =
|
||||
flushTimerCallIndex >= 0
|
||||
@@ -104,6 +113,15 @@ async function flushChannelPostMediaGroup(setTimeoutSpy: ReturnType<typeof vi.sp
|
||||
await flushTimer?.();
|
||||
}
|
||||
|
||||
async function flushChannelPostMediaGroupForDelay(
|
||||
setTimeoutSpy: ReturnType<typeof vi.spyOn>,
|
||||
delayMs: number,
|
||||
) {
|
||||
const flushTimer = resolveFlushTimerForDelay(setTimeoutSpy, delayMs);
|
||||
expect(flushTimer).toBeTypeOf("function");
|
||||
await flushTimer?.();
|
||||
}
|
||||
|
||||
async function queueChannelPostAlbum(
|
||||
handler: ReturnType<typeof getChannelPostHandler>,
|
||||
params: {
|
||||
@@ -181,6 +199,44 @@ describe("createTelegramBot channel_post media", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("honors configured mediaGroupFlushMs for channel_post albums", async () => {
|
||||
loadConfig.mockReturnValue({
|
||||
channels: {
|
||||
telegram: {
|
||||
groupPolicy: "open",
|
||||
mediaGroupFlushMs: 75,
|
||||
groups: {
|
||||
"-100777111222": {
|
||||
enabled: true,
|
||||
requireMention: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const fetchSpy = createImageFetchSpy();
|
||||
const setTimeoutSpy = vi.spyOn(globalThis, "setTimeout");
|
||||
try {
|
||||
const handler = getChannelPostHandlerWithRuntimeTimings();
|
||||
await queueChannelPostAlbum(handler, {
|
||||
caption: "configured album",
|
||||
mediaGroupId: "channel-album-configured",
|
||||
firstMessageId: 211,
|
||||
secondMessageId: 212,
|
||||
});
|
||||
expect(replySpy).not.toHaveBeenCalled();
|
||||
await flushChannelPostMediaGroupForDelay(setTimeoutSpy, 75);
|
||||
|
||||
expect(replySpy).toHaveBeenCalledTimes(1);
|
||||
const payload = replySpy.mock.calls[0]?.[0] as { Body?: string };
|
||||
expect(payload.Body).toContain("configured album");
|
||||
} finally {
|
||||
setTimeoutSpy.mockRestore();
|
||||
fetchSpy.mockRestore();
|
||||
}
|
||||
});
|
||||
|
||||
it("coalesces channel_post near-limit text fragments into one message", async () => {
|
||||
setOpenChannelPostConfig();
|
||||
|
||||
|
||||
@@ -66,6 +66,24 @@ describe("telegram custom commands schema", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("accepts mediaGroupFlushMs overrides per account", () => {
|
||||
const res = TelegramConfigSchema.safeParse({
|
||||
mediaGroupFlushMs: 750,
|
||||
accounts: { ops: { mediaGroupFlushMs: 1500 } },
|
||||
});
|
||||
|
||||
expect(res.success).toBe(true);
|
||||
if (res.success) {
|
||||
expect(res.data.mediaGroupFlushMs).toBe(750);
|
||||
expect(res.data.accounts?.ops?.mediaGroupFlushMs).toBe(1500);
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects mediaGroupFlushMs outside the supported flush bounds", () => {
|
||||
expectTelegramConfigIssue({ mediaGroupFlushMs: 9 }, "mediaGroupFlushMs");
|
||||
expectTelegramConfigIssue({ mediaGroupFlushMs: 60_001 }, "mediaGroupFlushMs");
|
||||
});
|
||||
|
||||
it("accepts DM thread reply policy overrides", () => {
|
||||
const res = TelegramConfigSchema.safeParse({
|
||||
dm: { threadReplies: "off" },
|
||||
|
||||
@@ -101,6 +101,10 @@ export const telegramChannelConfigUiHints = {
|
||||
label: "Telegram API Timeout (seconds)",
|
||||
help: "Max seconds before Telegram API requests are aborted (default: 500 per grammY).",
|
||||
},
|
||||
mediaGroupFlushMs: {
|
||||
label: "Telegram Media Group Flush (ms)",
|
||||
help: "Milliseconds to buffer Telegram albums/media groups before dispatching them as one inbound message. Default: 500.",
|
||||
},
|
||||
pollingStallThresholdMs: {
|
||||
label: "Telegram Polling Stall Threshold (ms)",
|
||||
help: "Milliseconds without completed Telegram getUpdates liveness before the polling watchdog restarts the polling runner. Default: 120000.",
|
||||
|
||||
Reference in New Issue
Block a user