From 33e93e2a07d9d0ff8c01dd88134e96532ae0b780 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 7 Apr 2026 14:14:54 +0100 Subject: [PATCH] Telegram: lazy load send runtime from entrypoints --- extensions/telegram/index.test.ts | 12 ++++++--- extensions/telegram/setup-entry.ts | 2 +- extensions/telegram/src/channel.ts | 30 ++++++++++++++------- extensions/telegram/src/outbound-adapter.ts | 25 ++++++++++------- extensions/telegram/src/thread-bindings.ts | 9 ++++++- 5 files changed, 53 insertions(+), 25 deletions(-) diff --git a/extensions/telegram/index.test.ts b/extensions/telegram/index.test.ts index cbacb99c565..463ba555936 100644 --- a/extensions/telegram/index.test.ts +++ b/extensions/telegram/index.test.ts @@ -1,11 +1,15 @@ -import { describe, expect, it } from "vitest"; +import { beforeEach, describe, expect, it, vi } from "vitest"; import entry from "./index.js"; import setupEntry from "./setup-entry.js"; describe("telegram bundled entries", () => { - it("loads the channel plugin without importing the broad api barrel", () => { - const plugin = entry.loadChannelPlugin(); - expect(plugin.id).toBe("telegram"); + beforeEach(() => { + vi.useRealTimers(); + }); + + it("declares the channel entry without importing the broad api barrel", () => { + expect(entry.id).toBe("telegram"); + expect(entry.name).toBe("Telegram"); }); it("loads the setup plugin without importing the broad api barrel", () => { diff --git a/extensions/telegram/setup-entry.ts b/extensions/telegram/setup-entry.ts index 45d5e8aaaeb..87bf37a9715 100644 --- a/extensions/telegram/setup-entry.ts +++ b/extensions/telegram/setup-entry.ts @@ -3,7 +3,7 @@ import { defineBundledChannelSetupEntry } from "openclaw/plugin-sdk/channel-entr export default defineBundledChannelSetupEntry({ importMetaUrl: import.meta.url, plugin: { - specifier: "./channel-plugin-api.js", + specifier: "./src/channel.setup.js", exportName: "telegramSetupPlugin", }, secrets: { diff --git a/extensions/telegram/src/channel.ts b/extensions/telegram/src/channel.ts index 9b568fa370e..6b7edf5dad5 100644 --- a/extensions/telegram/src/channel.ts +++ b/extensions/telegram/src/channel.ts @@ -60,7 +60,6 @@ import * as probeModule from "./probe.js"; import { resolveTelegramReactionLevel } from "./reaction-level.js"; import { getTelegramRuntime } from "./runtime.js"; import { collectTelegramSecurityAuditFindings } from "./security-audit.js"; -import { sendMessageTelegram, sendPollTelegram, sendTypingTelegram } from "./send.js"; import { resolveTelegramSessionConversation } from "./session-conversation.js"; import { telegramSetupAdapter } from "./setup-core.js"; import { telegramSetupWizard } from "./setup-surface.js"; @@ -82,7 +81,14 @@ import { buildTelegramThreadingToolContext } from "./threading-tool-context.js"; import { resolveTelegramToken } from "./token.js"; import { parseTelegramTopicConversation } from "./topic-conversation.js"; -type TelegramSendFn = typeof sendMessageTelegram; +type TelegramSendFn = typeof import("./send.js").sendMessageTelegram; + +let telegramSendModulePromise: Promise | undefined; + +async function loadTelegramSendModule() { + telegramSendModulePromise ??= import("./send.js"); + return await telegramSendModulePromise; +} type TelegramSendOptions = NonNullable[2]>; @@ -121,11 +127,11 @@ function getOptionalTelegramRuntime() { } } -function resolveTelegramSend(deps?: OutboundSendDeps): TelegramSendFn { +async function resolveTelegramSend(deps?: OutboundSendDeps): Promise { return ( resolveOutboundSendDep(deps, "telegram") ?? getOptionalTelegramRuntime()?.channel?.telegram?.sendMessageTelegram ?? - sendMessageTelegram + (await loadTelegramSendModule()).sendMessageTelegram ); } @@ -175,7 +181,7 @@ async function sendTelegramOutbound(params: { silent?: boolean | null; gatewayClientScopes?: readonly string[] | null; }) { - const send = resolveTelegramSend(params.deps); + const send = await resolveTelegramSend(params.deps); return await send( params.to, params.text, @@ -961,7 +967,8 @@ export const telegramPlugin = createChatChannelPlugin({ if (!token) { throw new Error("telegram token not configured"); } - await resolveTelegramSend()(id, message, { token, accountId }); + const send = await resolveTelegramSend(); + await send(id, message, { token, accountId }); }, }, }, @@ -1004,6 +1011,7 @@ export const telegramPlugin = createChatChannelPlugin({ : typeof target.threadId === "string" ? Number.parseInt(target.threadId, 10) : undefined; + const { sendTypingTelegram } = await loadTelegramSendModule(); await sendTypingTelegram(target.to, { cfg, accountId: target.accountId ?? undefined, @@ -1030,7 +1038,7 @@ export const telegramPlugin = createChatChannelPlugin({ forceDocument, gatewayClientScopes, }) => { - const send = resolveTelegramSend(deps); + const send = await resolveTelegramSend(deps); const result = await sendTelegramPayloadMessages({ send, to, @@ -1108,15 +1116,17 @@ export const telegramPlugin = createChatChannelPlugin({ silent, isAnonymous, gatewayClientScopes, - }) => - await sendPollTelegram(to, poll, { + }) => { + const { sendPollTelegram } = await loadTelegramSendModule(); + return await sendPollTelegram(to, poll, { cfg, accountId: accountId ?? undefined, messageThreadId: parseTelegramThreadId(threadId), silent: silent ?? undefined, isAnonymous: isAnonymous ?? undefined, gatewayClientScopes, - }), + }); + }, }, }, }); diff --git a/extensions/telegram/src/outbound-adapter.ts b/extensions/telegram/src/outbound-adapter.ts index dcb942b7e7f..8be02021c85 100644 --- a/extensions/telegram/src/outbound-adapter.ts +++ b/extensions/telegram/src/outbound-adapter.ts @@ -18,21 +18,27 @@ import type { TelegramInlineButtons } from "./button-types.js"; import { resolveTelegramInlineButtons } from "./button-types.js"; import { markdownToTelegramHtmlChunks } from "./format.js"; import { parseTelegramReplyToMessageId, parseTelegramThreadId } from "./outbound-params.js"; -import { sendMessageTelegram } from "./send.js"; export const TELEGRAM_TEXT_CHUNK_LIMIT = 4000; -type TelegramSendFn = typeof sendMessageTelegram; +type TelegramSendFn = typeof import("./send.js").sendMessageTelegram; type TelegramSendOpts = Parameters[2]; -function resolveTelegramSendContext(params: { +let telegramSendModulePromise: Promise | undefined; + +async function loadTelegramSendModule() { + telegramSendModulePromise ??= import("./send.js"); + return await telegramSendModulePromise; +} + +async function resolveTelegramSendContext(params: { cfg: NonNullable["cfg"]; deps?: OutboundSendDeps; accountId?: string | null; replyToId?: string | null; threadId?: string | number | null; gatewayClientScopes?: readonly string[]; -}): { +}): Promise<{ send: TelegramSendFn; baseOpts: { cfg: NonNullable["cfg"]; @@ -43,9 +49,10 @@ function resolveTelegramSendContext(params: { accountId?: string; gatewayClientScopes?: readonly string[]; }; -} { +}> { const send = - resolveOutboundSendDep(params.deps, "telegram") ?? sendMessageTelegram; + resolveOutboundSendDep(params.deps, "telegram") ?? + (await loadTelegramSendModule()).sendMessageTelegram; return { send, baseOpts: { @@ -126,7 +133,7 @@ export const telegramOutbound: ChannelOutboundAdapter = { threadId, gatewayClientScopes, }) => { - const { send, baseOpts } = resolveTelegramSendContext({ + const { send, baseOpts } = await resolveTelegramSendContext({ cfg, deps, accountId, @@ -152,7 +159,7 @@ export const telegramOutbound: ChannelOutboundAdapter = { forceDocument, gatewayClientScopes, }) => { - const { send, baseOpts } = resolveTelegramSendContext({ + const { send, baseOpts } = await resolveTelegramSendContext({ cfg, deps, accountId, @@ -182,7 +189,7 @@ export const telegramOutbound: ChannelOutboundAdapter = { forceDocument, gatewayClientScopes, }) => { - const { send, baseOpts } = resolveTelegramSendContext({ + const { send, baseOpts } = await resolveTelegramSendContext({ cfg, deps, accountId, diff --git a/extensions/telegram/src/thread-bindings.ts b/extensions/telegram/src/thread-bindings.ts index 2f2f8b7cd78..71d96cc6fa1 100644 --- a/extensions/telegram/src/thread-bindings.ts +++ b/extensions/telegram/src/thread-bindings.ts @@ -18,7 +18,6 @@ import { normalizeAccountId } from "openclaw/plugin-sdk/routing"; import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; import { resolveStateDir } from "openclaw/plugin-sdk/state-paths"; import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; -import { createForumTopicTelegram } from "./send.js"; import { resolveTelegramToken } from "./token.js"; const DEFAULT_THREAD_BINDING_IDLE_TIMEOUT_MS = 24 * 60 * 60 * 1000; @@ -26,6 +25,13 @@ const DEFAULT_THREAD_BINDING_MAX_AGE_MS = 0; const THREAD_BINDINGS_SWEEP_INTERVAL_MS = 60_000; const STORE_VERSION = 1; +let telegramSendModulePromise: Promise | undefined; + +async function loadTelegramSendModule() { + telegramSendModulePromise ??= import("./send.js"); + return await telegramSendModulePromise; +} + type TelegramBindingTargetKind = "subagent" | "acp"; export type TelegramThreadBindingRecord = { @@ -593,6 +599,7 @@ export function createTelegramThreadBindingManager( if (!tokenResolution.token) { return null; } + const { createForumTopicTelegram } = await loadTelegramSendModule(); const result = await createForumTopicTelegram(chatId, threadName, { cfg, token: tokenResolution.token,