diff --git a/CHANGELOG.md b/CHANGELOG.md index 2efb2b4a62e..1eb9ea653ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Telegram/startup: use the existing `getMe` request guard for the gateway bot probe instead of a fixed 2.5-second budget, and honor higher `timeoutSeconds` configs for slow Telegram API paths. Fixes #75783. Thanks @tankotan. - Infer/media: report missing image-understanding and audio-transcription provider configuration for `image describe`, `image describe-many`, and `audio transcribe` instead of blaming the input path when no provider is available. Fixes #73569 and supersedes #73593, #74288, and #74495. Thanks @bittoby, @tmimmanuel, @Linux2010, and @vyctorbrzezowski. - Docs/health: clarify that session listing surfaces stored conversation rows rather than Discord/channel socket liveness, and point connectivity checks at channel status and health probes. Fixes #70420. Thanks @ashersoutherncities-art and @martingarramon. - WhatsApp/Cron: keep DM pairing-store approvals out of implicit cron and heartbeat recipient fallback, so scheduled automation only uses explicit targets, active configured recipients, or configured `allowFrom` entries. Fixes #62339. Thanks @kelvinisly-collab. diff --git a/extensions/telegram/src/channel.gateway.test.ts b/extensions/telegram/src/channel.gateway.test.ts index a70e328882e..b5d3605d286 100644 --- a/extensions/telegram/src/channel.gateway.test.ts +++ b/extensions/telegram/src/channel.gateway.test.ts @@ -27,12 +27,16 @@ function installTelegramRuntime() { } as unknown as TelegramRuntime); } -function createTelegramConfig(accountId = "default"): OpenClawConfig { +function createTelegramConfig( + accountId = "default", + telegramOverrides: Record = {}, +): OpenClawConfig { if (accountId === "default") { return { channels: { telegram: { botToken: "123456:bad-token", + ...telegramOverrides, }, }, } as OpenClawConfig; @@ -44,6 +48,7 @@ function createTelegramConfig(accountId = "default"): OpenClawConfig { accounts: { [accountId]: { botToken: "123456:bad-token", + ...telegramOverrides, }, }, }, @@ -51,8 +56,11 @@ function createTelegramConfig(accountId = "default"): OpenClawConfig { } as OpenClawConfig; } -function startTelegramAccount(accountId = "default") { - const cfg = createTelegramConfig(accountId); +function startTelegramAccount( + accountId = "default", + telegramOverrides: Record = {}, +) { + const cfg = createTelegramConfig(accountId, telegramOverrides); const account = telegramPlugin.config.resolveAccount(cfg, accountId); const startAccount = telegramPlugin.gateway?.startAccount; expect(startAccount).toBeDefined(); @@ -115,4 +123,50 @@ describe("telegramPlugin gateway startup", () => { }), ); }); + + it("uses the getMe request guard for startup probe timeout", async () => { + installTelegramRuntime(); + probeTelegram.mockResolvedValue({ + ok: true, + status: null, + error: null, + elapsedMs: 12, + }); + monitorTelegramProvider.mockResolvedValue(undefined); + + const { task } = startTelegramAccount(); + + await expect(task).resolves.toBeUndefined(); + expect(probeTelegram).toHaveBeenCalledWith( + "123456:bad-token", + 15_000, + expect.objectContaining({ + accountId: "default", + includeWebhookInfo: false, + }), + ); + }); + + it("honors higher per-account timeoutSeconds for startup probe", async () => { + installTelegramRuntime(); + probeTelegram.mockResolvedValue({ + ok: true, + status: null, + error: null, + elapsedMs: 12, + }); + monitorTelegramProvider.mockResolvedValue(undefined); + + const { task } = startTelegramAccount("ops", { timeoutSeconds: 60 }); + + await expect(task).resolves.toBeUndefined(); + expect(probeTelegram).toHaveBeenCalledWith( + "123456:bad-token", + 60_000, + expect.objectContaining({ + accountId: "ops", + includeWebhookInfo: false, + }), + ); + }); }); diff --git a/extensions/telegram/src/channel.ts b/extensions/telegram/src/channel.ts index bf604b40287..7f2ab95bb02 100644 --- a/extensions/telegram/src/channel.ts +++ b/extensions/telegram/src/channel.ts @@ -61,6 +61,7 @@ import { parseTelegramReplyToMessageId, parseTelegramThreadId } from "./outbound import type { TelegramProbe } from "./probe.js"; import * as probeModule from "./probe.js"; import { resolveTelegramReactionLevel } from "./reaction-level.js"; +import { resolveTelegramStartupProbeTimeoutMs } from "./request-timeouts.js"; import { getTelegramRuntime } from "./runtime.js"; import { telegramSecurityAdapter } from "./security.js"; import { resolveTelegramSessionConversation } from "./session-conversation.js"; @@ -893,13 +894,17 @@ export const telegramPlugin = createChatChannelPlugin({ let telegramBotLabel = ""; let unauthorizedTokenReason: string | null = null; try { - const probe = await resolveTelegramProbe()(token, 2500, { - accountId: account.accountId, - proxyUrl: account.config.proxy, - network: account.config.network, - apiRoot: account.config.apiRoot, - includeWebhookInfo: false, - }); + const probe = await resolveTelegramProbe()( + token, + resolveTelegramStartupProbeTimeoutMs(account.config.timeoutSeconds), + { + accountId: account.accountId, + proxyUrl: account.config.proxy, + network: account.config.network, + apiRoot: account.config.apiRoot, + includeWebhookInfo: false, + }, + ); const username = probe.ok ? probe.bot?.username?.trim() : null; if (username) { telegramBotLabel = ` (@${username})`; diff --git a/extensions/telegram/src/request-timeouts.test.ts b/extensions/telegram/src/request-timeouts.test.ts index 500c0eab4a7..c43e34c3b73 100644 --- a/extensions/telegram/src/request-timeouts.test.ts +++ b/extensions/telegram/src/request-timeouts.test.ts @@ -1,5 +1,8 @@ import { describe, expect, it } from "vitest"; -import { resolveTelegramRequestTimeoutMs } from "./request-timeouts.js"; +import { + resolveTelegramRequestTimeoutMs, + resolveTelegramStartupProbeTimeoutMs, +} from "./request-timeouts.js"; describe("resolveTelegramRequestTimeoutMs", () => { it("bounds Telegram startup control-plane methods", () => { @@ -26,3 +29,17 @@ describe("resolveTelegramRequestTimeoutMs", () => { expect(resolveTelegramRequestTimeoutMs(null)).toBeUndefined(); }); }); + +describe("resolveTelegramStartupProbeTimeoutMs", () => { + it("uses the getMe request guard by default", () => { + expect(resolveTelegramStartupProbeTimeoutMs(undefined)).toBe(15_000); + }); + + it("does not let low client timeoutSeconds shorten startup getMe", () => { + expect(resolveTelegramStartupProbeTimeoutMs(2)).toBe(15_000); + }); + + it("honors higher configured timeoutSeconds", () => { + expect(resolveTelegramStartupProbeTimeoutMs(60)).toBe(60_000); + }); +}); diff --git a/extensions/telegram/src/request-timeouts.ts b/extensions/telegram/src/request-timeouts.ts index ee317a9a324..207238dbf8d 100644 --- a/extensions/telegram/src/request-timeouts.ts +++ b/extensions/telegram/src/request-timeouts.ts @@ -33,3 +33,12 @@ export function resolveTelegramRequestTimeoutMs(method: string | null): number | } return TELEGRAM_REQUEST_TIMEOUTS_MS[method as keyof typeof TELEGRAM_REQUEST_TIMEOUTS_MS]; } + +export function resolveTelegramStartupProbeTimeoutMs(timeoutSeconds: unknown): number { + const getMeTimeoutMs = resolveTelegramRequestTimeoutMs("getme") ?? 15_000; + if (typeof timeoutSeconds !== "number" || !Number.isFinite(timeoutSeconds)) { + return getMeTimeoutMs; + } + const configuredTimeoutMs = Math.max(1, Math.floor(timeoutSeconds)) * 1000; + return Math.max(getMeTimeoutMs, configuredTimeoutMs); +}