From b85d97f22ccc477fd4e826803d84858453b59ef0 Mon Sep 17 00:00:00 2001 From: Ayaan Zaidi Date: Wed, 18 Mar 2026 10:08:30 +0530 Subject: [PATCH] refactor(telegram): inject shared bot deps --- extensions/telegram/src/bot-deps.ts | 28 +++++++++++++++++++ .../telegram/src/bot-message-dispatch.ts | 22 +++------------ extensions/telegram/src/bot-message.ts | 4 +++ .../telegram/src/bot-native-commands.ts | 27 ++++-------------- extensions/telegram/src/bot.ts | 11 +++++--- 5 files changed, 49 insertions(+), 43 deletions(-) create mode 100644 extensions/telegram/src/bot-deps.ts diff --git a/extensions/telegram/src/bot-deps.ts b/extensions/telegram/src/bot-deps.ts new file mode 100644 index 00000000000..49193bebdc1 --- /dev/null +++ b/extensions/telegram/src/bot-deps.ts @@ -0,0 +1,28 @@ +import { loadConfig, resolveStorePath } from "openclaw/plugin-sdk/config-runtime"; +import { readChannelAllowFromStore } from "openclaw/plugin-sdk/conversation-runtime"; +import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime"; +import { + dispatchReplyWithBufferedBlockDispatcher, + listSkillCommandsForAgents, +} from "openclaw/plugin-sdk/reply-runtime"; +import { wasSentByBot } from "./sent-message-cache.js"; + +export type TelegramBotDeps = { + loadConfig: typeof loadConfig; + resolveStorePath: typeof resolveStorePath; + readChannelAllowFromStore: typeof readChannelAllowFromStore; + enqueueSystemEvent: typeof enqueueSystemEvent; + dispatchReplyWithBufferedBlockDispatcher: typeof dispatchReplyWithBufferedBlockDispatcher; + listSkillCommandsForAgents: typeof listSkillCommandsForAgents; + wasSentByBot: typeof wasSentByBot; +}; + +export const defaultTelegramBotDeps: TelegramBotDeps = { + loadConfig, + resolveStorePath, + readChannelAllowFromStore, + enqueueSystemEvent, + dispatchReplyWithBufferedBlockDispatcher, + listSkillCommandsForAgents, + wasSentByBot, +}; diff --git a/extensions/telegram/src/bot-message-dispatch.ts b/extensions/telegram/src/bot-message-dispatch.ts index 3e9a3084fdb..75df3bd5f2c 100644 --- a/extensions/telegram/src/bot-message-dispatch.ts +++ b/extensions/telegram/src/bot-message-dispatch.ts @@ -24,10 +24,10 @@ import type { import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime"; import { resolveChunkMode } from "openclaw/plugin-sdk/reply-runtime"; import { clearHistoryEntriesIfEnabled } from "openclaw/plugin-sdk/reply-runtime"; -import { dispatchReplyWithBufferedBlockDispatcher } from "openclaw/plugin-sdk/reply-runtime"; import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env"; import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { defaultTelegramBotDeps, type TelegramBotDeps } from "./bot-deps.js"; import type { TelegramMessageContext } from "./bot-message-context.js"; import type { TelegramBotOptions } from "./bot.js"; import { deliverReplies } from "./bot/delivery.js"; @@ -52,18 +52,6 @@ import { editMessageTelegram } from "./send.js"; import { cacheSticker, describeStickerImage } from "./sticker-cache.js"; const EMPTY_RESPONSE_FALLBACK = "No response generated. Please try again."; -const DEFAULT_BOT_MESSAGE_DISPATCH_RUNTIME = { - dispatchReplyWithBufferedBlockDispatcher, -}; -let botMessageDispatchRuntimeForTest: - | Partial - | undefined; - -export function setBotMessageDispatchRuntimeForTest( - runtime?: Partial, -): void { - botMessageDispatchRuntimeForTest = runtime; -} /** Minimum chars before sending first streaming message (improves push notification UX) */ const DRAFT_MIN_INITIAL_CHARS = 30; @@ -122,6 +110,7 @@ type DispatchTelegramMessageParams = { streamMode: TelegramStreamMode; textLimit: number; telegramCfg: TelegramAccountConfig; + telegramDeps?: TelegramBotDeps; opts: Pick; }; @@ -159,12 +148,9 @@ export const dispatchTelegramMessage = async ({ streamMode, textLimit, telegramCfg, + telegramDeps = defaultTelegramBotDeps, opts, }: DispatchTelegramMessageParams) => { - const botMessageDispatchRuntime = { - ...DEFAULT_BOT_MESSAGE_DISPATCH_RUNTIME, - ...botMessageDispatchRuntimeForTest, - }; const { ctxPayload, msg, @@ -551,7 +537,7 @@ export const dispatchTelegramMessage = async ({ let dispatchError: unknown; try { - ({ queuedFinal } = await botMessageDispatchRuntime.dispatchReplyWithBufferedBlockDispatcher({ + ({ queuedFinal } = await telegramDeps.dispatchReplyWithBufferedBlockDispatcher({ ctx: ctxPayload, cfg, dispatcherOptions: { diff --git a/extensions/telegram/src/bot-message.ts b/extensions/telegram/src/bot-message.ts index cb625c7b965..0957b0d062b 100644 --- a/extensions/telegram/src/bot-message.ts +++ b/extensions/telegram/src/bot-message.ts @@ -2,6 +2,7 @@ import type { ReplyToMode } from "openclaw/plugin-sdk/config-runtime"; import type { TelegramAccountConfig } from "openclaw/plugin-sdk/config-runtime"; import { danger } from "openclaw/plugin-sdk/runtime-env"; import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import type { TelegramBotDeps } from "./bot-deps.js"; import { buildTelegramMessageContext, type BuildTelegramMessageContextParams, @@ -21,6 +22,7 @@ type TelegramMessageProcessorDeps = Omit< replyToMode: ReplyToMode; streamMode: TelegramStreamMode; textLimit: number; + telegramDeps: TelegramBotDeps; opts: Pick; }; @@ -45,6 +47,7 @@ export const createTelegramMessageProcessor = (deps: TelegramMessageProcessorDep replyToMode, streamMode, textLimit, + telegramDeps, opts, } = deps; @@ -89,6 +92,7 @@ export const createTelegramMessageProcessor = (deps: TelegramMessageProcessorDep streamMode, textLimit, telegramCfg, + telegramDeps, opts, }); } catch (err) { diff --git a/extensions/telegram/src/bot-native-commands.ts b/extensions/telegram/src/bot-native-commands.ts index edbe98f146f..1bb90952815 100644 --- a/extensions/telegram/src/bot-native-commands.ts +++ b/extensions/telegram/src/bot-native-commands.ts @@ -37,8 +37,6 @@ import { resolveCommandArgMenu, } from "openclaw/plugin-sdk/reply-runtime"; import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-runtime"; -import { dispatchReplyWithBufferedBlockDispatcher } from "openclaw/plugin-sdk/reply-runtime"; -import { listSkillCommandsForAgents } from "openclaw/plugin-sdk/reply-runtime"; import { resolveAgentRoute } from "openclaw/plugin-sdk/routing"; import { resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing"; import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env"; @@ -46,6 +44,7 @@ import { getChildLogger } from "openclaw/plugin-sdk/runtime-env"; import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { withTelegramApiErrorLogging } from "./api-logging.js"; import { isSenderAllowed, normalizeDmAllowFromWithStore } from "./bot-access.js"; +import { defaultTelegramBotDeps, type TelegramBotDeps } from "./bot-deps.js"; import type { TelegramMediaRef } from "./bot-message-context.js"; import { buildCappedTelegramMenuCommands, @@ -77,19 +76,6 @@ import { resolveTelegramGroupPromptSettings } from "./group-config-helpers.js"; import { buildInlineKeyboard } from "./send.js"; const EMPTY_RESPONSE_FALLBACK = "No response generated. Please try again."; -const DEFAULT_BOT_NATIVE_COMMANDS_RUNTIME = { - dispatchReplyWithBufferedBlockDispatcher, - listSkillCommandsForAgents, -}; -let botNativeCommandsRuntimeForTest: - | Partial - | undefined; - -export function setBotNativeCommandsRuntimeForTest( - runtime?: Partial, -): void { - botNativeCommandsRuntimeForTest = runtime; -} type TelegramNativeCommandContext = Context & { match?: string }; @@ -114,6 +100,7 @@ export type RegisterTelegramHandlerParams = { telegramTransport?: TelegramTransport; runtime: RuntimeEnv; telegramCfg: TelegramAccountConfig; + telegramDeps?: TelegramBotDeps; allowFrom?: Array; groupAllowFrom?: Array; resolveGroupPolicy: (chatId: string | number) => ChannelGroupPolicy; @@ -155,6 +142,7 @@ export type RegisterTelegramNativeCommandsParams = { messageThreadId?: number, ) => { groupConfig?: TelegramGroupConfig; topicConfig?: TelegramTopicConfig }; shouldSkipUpdate: (ctx: TelegramUpdateKeyContext) => boolean; + telegramDeps?: TelegramBotDeps; opts: { token: string }; }; @@ -377,12 +365,9 @@ export const registerTelegramNativeCommands = ({ resolveGroupPolicy, resolveTelegramGroupConfig, shouldSkipUpdate, + telegramDeps = defaultTelegramBotDeps, opts, }: RegisterTelegramNativeCommandsParams) => { - const botNativeCommandsRuntime = { - ...DEFAULT_BOT_NATIVE_COMMANDS_RUNTIME, - ...botNativeCommandsRuntimeForTest, - }; const silentErrorReplies = telegramCfg.silentErrorReplies === true; const boundRoute = nativeEnabled && nativeSkillsEnabled @@ -395,7 +380,7 @@ export const registerTelegramNativeCommands = ({ } const skillCommands = nativeEnabled && nativeSkillsEnabled && boundRoute - ? botNativeCommandsRuntime.listSkillCommandsForAgents({ + ? telegramDeps.listSkillCommandsForAgents({ cfg, agentIds: [boundRoute.agentId], }) @@ -776,7 +761,7 @@ export const registerTelegramNativeCommands = ({ accountId: route.accountId, }); - await botNativeCommandsRuntime.dispatchReplyWithBufferedBlockDispatcher({ + await telegramDeps.dispatchReplyWithBufferedBlockDispatcher({ ctx: ctxPayload, cfg, dispatcherOptions: { diff --git a/extensions/telegram/src/bot.ts b/extensions/telegram/src/bot.ts index 617a1231798..c9f3040a49b 100644 --- a/extensions/telegram/src/bot.ts +++ b/extensions/telegram/src/bot.ts @@ -10,7 +10,6 @@ import { resolveNativeSkillsEnabled, } from "openclaw/plugin-sdk/config-runtime"; import type { OpenClawConfig, ReplyToMode } from "openclaw/plugin-sdk/config-runtime"; -import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; import { resolveChannelGroupPolicy, resolveChannelGroupRequireMention, @@ -24,6 +23,7 @@ import { getChildLogger } from "openclaw/plugin-sdk/runtime-env"; import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; import { createNonExitingRuntime, type RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { resolveTelegramAccount } from "./accounts.js"; +import { defaultTelegramBotDeps, type TelegramBotDeps } from "./bot-deps.js"; import { registerTelegramHandlers } from "./bot-handlers.js"; import { createTelegramMessageProcessor } from "./bot-message.js"; import { registerTelegramNativeCommands } from "./bot-native-commands.js"; @@ -64,6 +64,7 @@ export type TelegramBotOptions = { }; /** Pre-resolved Telegram transport to reuse across bot instances. If not provided, creates a new one. */ telegramTransport?: TelegramTransport; + telegramDeps?: TelegramBotDeps; }; export { getTelegramSequentialKey }; @@ -72,14 +73,12 @@ type TelegramBotRuntime = { Bot: typeof Bot; sequentialize: typeof sequentialize; apiThrottler: typeof apiThrottler; - loadConfig: typeof loadConfig; }; const DEFAULT_TELEGRAM_BOT_RUNTIME: TelegramBotRuntime = { Bot, sequentialize, apiThrottler, - loadConfig, }; let telegramBotRuntimeForTest: TelegramBotRuntime | undefined; @@ -124,7 +123,8 @@ function extractTelegramApiMethod(input: TelegramFetchInput): string | null { export function createTelegramBot(opts: TelegramBotOptions) { const botRuntime = telegramBotRuntimeForTest ?? DEFAULT_TELEGRAM_BOT_RUNTIME; const runtime: RuntimeEnv = opts.runtime ?? createNonExitingRuntime(); - const cfg = opts.config ?? botRuntime.loadConfig(); + const telegramDeps = opts.telegramDeps ?? defaultTelegramBotDeps; + const cfg = opts.config ?? telegramDeps.loadConfig(); const account = resolveTelegramAccount({ cfg, accountId: opts.accountId, @@ -490,6 +490,7 @@ export function createTelegramBot(opts: TelegramBotOptions) { streamMode, textLimit, opts, + telegramDeps, }); registerTelegramNativeCommands({ @@ -510,6 +511,7 @@ export function createTelegramBot(opts: TelegramBotOptions) { resolveTelegramGroupConfig, shouldSkipUpdate, opts, + telegramDeps, }); registerTelegramHandlers({ @@ -528,6 +530,7 @@ export function createTelegramBot(opts: TelegramBotOptions) { shouldSkipUpdate, processMessage, logger, + telegramDeps, }); const originalStop = bot.stop.bind(bot);