From 9d005e6fbbe222a458e84c603095dccbb7a8edcb Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 30 Mar 2026 02:58:45 +0100 Subject: [PATCH] fix: stabilize telegram contract runtime coverage --- extensions/telegram/src/channel.ts | 84 ++++++++++++++++++++++-------- extensions/telegram/src/runtime.ts | 18 ++++++- 2 files changed, 80 insertions(+), 22 deletions(-) diff --git a/extensions/telegram/src/channel.ts b/extensions/telegram/src/channel.ts index b963a048d1f..90d4a596360 100644 --- a/extensions/telegram/src/channel.ts +++ b/extensions/telegram/src/channel.ts @@ -93,19 +93,52 @@ type TelegramSendFn = typeof sendMessageTelegram; type TelegramSendOptions = NonNullable[2]>; function resolveTelegramProbe() { - return probeModule.probeTelegram; + return ( + getOptionalTelegramRuntime()?.channel?.telegram?.probeTelegram ?? probeModule.probeTelegram + ); } function resolveTelegramAuditCollector() { - return auditModule.collectTelegramUnmentionedGroupIds; + return ( + getOptionalTelegramRuntime()?.channel?.telegram?.collectTelegramUnmentionedGroupIds ?? + auditModule.collectTelegramUnmentionedGroupIds + ); } function resolveTelegramAuditMembership() { - return auditModule.auditTelegramGroupMembership; + return ( + getOptionalTelegramRuntime()?.channel?.telegram?.auditTelegramGroupMembership ?? + auditModule.auditTelegramGroupMembership + ); } function resolveTelegramMonitor() { - return monitorModule.monitorTelegramProvider; + return ( + getOptionalTelegramRuntime()?.channel?.telegram?.monitorTelegramProvider ?? + monitorModule.monitorTelegramProvider + ); +} + +function getOptionalTelegramRuntime() { + try { + return getTelegramRuntime(); + } catch { + return null; + } +} + +function resolveTelegramSend(deps?: OutboundSendDeps): TelegramSendFn { + return ( + resolveOutboundSendDep(deps, "telegram") ?? + getOptionalTelegramRuntime()?.channel?.telegram?.sendMessageTelegram ?? + sendMessageTelegram + ); +} + +function resolveTelegramTokenHelper() { + return ( + getOptionalTelegramRuntime()?.channel?.telegram?.resolveTelegramToken ?? resolveTelegramToken + ); } function buildTelegramSendOptions(params: { @@ -148,8 +181,7 @@ async function sendTelegramOutbound(params: { silent?: boolean | null; gatewayClientScopes?: readonly string[] | null; }) { - const send = - resolveOutboundSendDep(params.deps, "telegram") ?? sendMessageTelegram; + const send = resolveTelegramSend(params.deps); return await send( params.to, params.text, @@ -166,6 +198,28 @@ async function sendTelegramOutbound(params: { ); } +const telegramMessageActions: ChannelMessageActionAdapter = { + describeMessageTool: (ctx) => + getOptionalTelegramRuntime()?.channel?.telegram?.messageActions?.describeMessageTool?.(ctx) ?? + telegramMessageActionsImpl.describeMessageTool?.(ctx) ?? + null, + extractToolSend: (ctx) => + getOptionalTelegramRuntime()?.channel?.telegram?.messageActions?.extractToolSend?.(ctx) ?? + telegramMessageActionsImpl.extractToolSend?.(ctx) ?? + null, + handleAction: async (ctx) => { + const runtimeHandleAction = + getOptionalTelegramRuntime()?.channel?.telegram?.messageActions?.handleAction; + if (runtimeHandleAction) { + return await runtimeHandleAction(ctx); + } + if (!telegramMessageActionsImpl.handleAction) { + throw new Error("Telegram message actions not available"); + } + return await telegramMessageActionsImpl.handleAction(ctx); + }, +}; + function normalizeTelegramAcpConversationId(conversationId: string) { const parsed = parseTelegramTopicConversation({ conversationId }); if (!parsed || !parsed.chatId.startsWith("-")) { @@ -387,17 +441,6 @@ const telegramNativeApprovalAdapter = createApproverRestrictedNativeApprovalAdap target.accountId?.trim() || request.request.turnSourceAccountId?.trim() || undefined, }); -const telegramMessageActions: ChannelMessageActionAdapter = { - describeMessageTool: (ctx) => telegramMessageActionsImpl.describeMessageTool?.(ctx) ?? null, - extractToolSend: (ctx) => telegramMessageActionsImpl.extractToolSend?.(ctx) ?? null, - handleAction: async (ctx) => { - if (!telegramMessageActionsImpl.handleAction) { - throw new Error("Telegram message actions not available"); - } - return await telegramMessageActionsImpl.handleAction(ctx); - }, -}; - const resolveTelegramAllowlistGroupOverrides = createNestedAllowlistOverrideResolver({ resolveRecord: (account: ResolvedTelegramAccount) => account.config.groups, outerLabel: (groupId) => groupId, @@ -770,11 +813,11 @@ export const telegramPlugin = createChatChannelPlugin({ message: PAIRING_APPROVED_MESSAGE, normalizeAllowEntry: createPairingPrefixStripper(/^(telegram|tg):/i), notify: async ({ cfg, id, message, accountId }) => { - const { token } = resolveTelegramToken(cfg, { accountId }); + const { token } = resolveTelegramTokenHelper()(cfg, { accountId }); if (!token) { throw new Error("telegram token not configured"); } - await sendMessageTelegram(id, message, { token, accountId }); + await resolveTelegramSend()(id, message, { token, accountId }); }, }, }, @@ -838,8 +881,7 @@ export const telegramPlugin = createChatChannelPlugin({ forceDocument, gatewayClientScopes, }) => { - const send = - resolveOutboundSendDep(deps, "telegram") ?? sendMessageTelegram; + const send = resolveTelegramSend(deps); const result = await sendTelegramPayloadMessages({ send, to, diff --git a/extensions/telegram/src/runtime.ts b/extensions/telegram/src/runtime.ts index 4d28400d3ec..c5c93c1a926 100644 --- a/extensions/telegram/src/runtime.ts +++ b/extensions/telegram/src/runtime.ts @@ -1,9 +1,25 @@ import type { PluginRuntime } from "openclaw/plugin-sdk/core"; import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store"; +type TelegramChannelRuntime = { + probeTelegram?: typeof import("./probe.js").probeTelegram; + collectTelegramUnmentionedGroupIds?: typeof import("./audit.js").collectTelegramUnmentionedGroupIds; + auditTelegramGroupMembership?: typeof import("./audit.js").auditTelegramGroupMembership; + monitorTelegramProvider?: typeof import("./monitor.js").monitorTelegramProvider; + sendMessageTelegram?: typeof import("./send.js").sendMessageTelegram; + resolveTelegramToken?: typeof import("./token.js").resolveTelegramToken; + messageActions?: typeof import("./channel-actions.js").telegramMessageActions; +}; + +export type TelegramRuntime = PluginRuntime & { + channel: PluginRuntime["channel"] & { + telegram?: TelegramChannelRuntime; + }; +}; + const { setRuntime: setTelegramRuntime, clearRuntime: clearTelegramRuntime, getRuntime: getTelegramRuntime, -} = createPluginRuntimeStore("Telegram runtime not initialized"); +} = createPluginRuntimeStore("Telegram runtime not initialized"); export { clearTelegramRuntime, getTelegramRuntime, setTelegramRuntime };