@poolzin/pool-bot 2026.3.25 → 2026.3.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. package/dist/agents/model-fallback.js +5 -4
  2. package/dist/agents/tools/common.js +16 -201
  3. package/dist/auto-reply/auto-reply/reply/agent-runner-execution.js +502 -0
  4. package/dist/auto-reply/auto-reply/reply/agent-runner-helpers.js +65 -0
  5. package/dist/auto-reply/auto-reply/reply/agent-runner-memory.js +160 -0
  6. package/dist/auto-reply/auto-reply/reply/agent-runner-payloads.js +85 -0
  7. package/dist/auto-reply/auto-reply/reply/agent-runner-utils.js +101 -0
  8. package/dist/auto-reply/auto-reply/reply/bash-command.js +338 -0
  9. package/dist/auto-reply/auto-reply/reply/block-streaming.js +91 -0
  10. package/dist/auto-reply/auto-reply/reply/commands-approve.js +88 -0
  11. package/dist/auto-reply/auto-reply/reply/commands-bash.js +26 -0
  12. package/dist/auto-reply/auto-reply/reply/commands-compact.js +107 -0
  13. package/dist/auto-reply/auto-reply/reply/commands-config.js +241 -0
  14. package/dist/auto-reply/auto-reply/reply/commands-context-report.js +295 -0
  15. package/dist/auto-reply/auto-reply/reply/commands-context.js +30 -0
  16. package/dist/auto-reply/auto-reply/reply/commands-core.js +151 -0
  17. package/dist/auto-reply/auto-reply/reply/commands-export-session.js +163 -0
  18. package/dist/auto-reply/auto-reply/reply/commands-info.js +184 -0
  19. package/dist/auto-reply/auto-reply/reply/commands-models.js +299 -0
  20. package/dist/auto-reply/auto-reply/reply/commands-plugin.js +35 -0
  21. package/dist/auto-reply/auto-reply/reply/commands-ptt.js +171 -0
  22. package/dist/auto-reply/auto-reply/reply/commands-setunset-standard.js +13 -0
  23. package/dist/auto-reply/auto-reply/reply/commands-setunset.js +73 -0
  24. package/dist/auto-reply/auto-reply/reply/commands-slash-parse.js +31 -0
  25. package/dist/auto-reply/auto-reply/reply/commands-status.js +178 -0
  26. package/dist/auto-reply/auto-reply/reply/commands-subagents.js +73 -0
  27. package/dist/auto-reply/auto-reply/reply/commands-system-prompt.js +117 -0
  28. package/dist/auto-reply/auto-reply/reply/commands-tts.js +231 -0
  29. package/dist/auto-reply/auto-reply/reply/directive-handling.impl.js +380 -0
  30. package/dist/auto-reply/auto-reply/reply/followup-runner.js +227 -0
  31. package/dist/auto-reply/auto-reply/reply/get-reply-directives-apply.js +201 -0
  32. package/dist/auto-reply/auto-reply/reply/get-reply-directives-utils.js +54 -0
  33. package/dist/auto-reply/auto-reply/reply/get-reply-directives.js +332 -0
  34. package/dist/auto-reply/auto-reply/reply/get-reply-inline-actions.js +258 -0
  35. package/dist/auto-reply/auto-reply/reply/get-reply-run.js +297 -0
  36. package/dist/auto-reply/auto-reply/reply/groups.js +102 -0
  37. package/dist/auto-reply/auto-reply/reply/mentions.js +129 -0
  38. package/dist/auto-reply/auto-reply/reply/reply-delivery.js +92 -0
  39. package/dist/auto-reply/auto-reply/reply/reply-directives.js +30 -0
  40. package/dist/auto-reply/auto-reply/reply/reply-dispatcher.js +152 -0
  41. package/dist/auto-reply/auto-reply/reply/reply-elevated.js +166 -0
  42. package/dist/auto-reply/auto-reply/reply/reply-inline.js +28 -0
  43. package/dist/auto-reply/auto-reply/reply/reply-payloads.js +114 -0
  44. package/dist/auto-reply/auto-reply/reply/reply-reference.js +36 -0
  45. package/dist/auto-reply/auto-reply/reply/reply-tags.js +13 -0
  46. package/dist/auto-reply/auto-reply/reply/reply-threading.js +41 -0
  47. package/dist/auto-reply/auto-reply/reply/session-updates.js +233 -0
  48. package/dist/auto-reply/auto-reply/reply/stage-sandbox-media.js +146 -0
  49. package/dist/build-info.json +3 -3
  50. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  51. package/dist/canvas-host/a2ui/a2ui.bundle.js +2 -17772
  52. package/dist/canvas-host/a2ui/index.html +1 -307
  53. package/dist/channels/channels/directory-config.js +185 -0
  54. package/dist/channels/channels/discord/handle-action.guild-admin.js +332 -0
  55. package/dist/channels/channels/discord/handle-action.js +165 -0
  56. package/dist/channels/channels/discord.js +413 -0
  57. package/dist/channels/channels/dock.js +436 -0
  58. package/dist/channels/channels/index.js +51 -0
  59. package/dist/channels/channels/plugins/outbound/discord.js +101 -0
  60. package/dist/channels/channels/whatsapp.js +17 -0
  61. package/dist/channels/plugins/types.js +1 -1
  62. package/dist/channels/run-state-machine.js +7 -0
  63. package/dist/commands/models/auth.js +47 -1
  64. package/dist/commands-subagents/action-agents.js +44 -0
  65. package/dist/commands-subagents/action-focus.js +64 -0
  66. package/dist/commands-subagents/action-help.js +4 -0
  67. package/dist/commands-subagents/action-info.js +45 -0
  68. package/dist/commands-subagents/action-kill.js +60 -0
  69. package/dist/commands-subagents/action-list.js +44 -0
  70. package/dist/commands-subagents/action-log.js +29 -0
  71. package/dist/commands-subagents/action-send.js +119 -0
  72. package/dist/commands-subagents/action-spawn.js +52 -0
  73. package/dist/commands-subagents/action-unfocus.js +30 -0
  74. package/dist/commands-subagents/shared.js +303 -0
  75. package/dist/config/config.js +1 -8
  76. package/dist/config/types.secrets.js +61 -0
  77. package/dist/control-ui/assets/{index-D7shnQwQ.js → index-umCsvrWy.js} +884 -741
  78. package/dist/control-ui/assets/index-umCsvrWy.js.map +1 -0
  79. package/dist/control-ui/assets/pt-BR-DedEVAvY.js +2 -0
  80. package/dist/control-ui/assets/pt-BR-DedEVAvY.js.map +1 -0
  81. package/dist/control-ui/assets/zh-CN-CDzeklK-.js +2 -0
  82. package/dist/control-ui/assets/zh-CN-CDzeklK-.js.map +1 -0
  83. package/dist/control-ui/assets/zh-TW-BJCRYNWH.js +2 -0
  84. package/dist/control-ui/assets/zh-TW-BJCRYNWH.js.map +1 -0
  85. package/dist/control-ui/index.html +1 -1
  86. package/dist/gateway/method-scopes.js +9 -1
  87. package/dist/gateway/node-pending-work.js +142 -0
  88. package/dist/gateway/protocol/index.js +5 -1
  89. package/dist/gateway/protocol/schema/nodes.js +18 -0
  90. package/dist/gateway/server-methods/nodes-pending.js +96 -0
  91. package/dist/gateway/server-methods-list.js +4 -0
  92. package/dist/gateway/server-methods.js +2 -0
  93. package/dist/imessage/channel.js +253 -0
  94. package/dist/imessage/monitor/echo-cache.js +70 -0
  95. package/dist/imessage/monitor/loop-rate-limiter.js +51 -0
  96. package/dist/imessage/monitor/reflection-guard.js +50 -0
  97. package/dist/imessage/monitor/sanitize-outbound.js +25 -0
  98. package/dist/imessage/monitor/self-chat-cache.js +75 -0
  99. package/dist/imessage/runtime.js +3 -0
  100. package/dist/infra/exec-approval-reply.js +7 -0
  101. package/dist/infra/tmp-openclaw-dir.js +84 -0
  102. package/dist/pairing/pairing-challenge.js +15 -0
  103. package/dist/plugin-sdk/account-id.d.ts +1 -0
  104. package/dist/plugin-sdk/agent-media-payload.d.ts +12 -0
  105. package/dist/plugin-sdk/allow-from.d.ts +27 -0
  106. package/dist/plugin-sdk/command-auth.d.ts +25 -0
  107. package/dist/plugin-sdk/command-auth.js +3 -1
  108. package/dist/plugin-sdk/config-paths.d.ts +6 -0
  109. package/dist/plugin-sdk/file-lock.d.ts +16 -0
  110. package/dist/plugin-sdk/index.d.ts +428 -0
  111. package/dist/plugin-sdk/index.js +237 -103
  112. package/dist/plugin-sdk/json-store.d.ts +5 -0
  113. package/dist/plugin-sdk/keyed-async-queue.d.ts +12 -0
  114. package/dist/plugin-sdk/onboarding.d.ts +11 -0
  115. package/dist/plugin-sdk/provider-auth-result.d.ts +14 -0
  116. package/dist/plugin-sdk/slack-message-actions.d.ts +11 -0
  117. package/dist/plugin-sdk/status-helpers.d.ts +25 -0
  118. package/dist/plugin-sdk/temp-path.d.ts +12 -0
  119. package/dist/plugin-sdk/text-chunking.d.ts +1 -0
  120. package/dist/plugin-sdk/tool-send.d.ts +4 -0
  121. package/dist/plugin-sdk/webhook-path.d.ts +6 -0
  122. package/dist/plugin-sdk/webhook-targets.d.ts +23 -0
  123. package/dist/plugin-sdk/windows-spawn.d.ts +39 -0
  124. package/dist/plugin-sdk-internal/accounts.js +6 -0
  125. package/dist/plugin-sdk-internal/discord.js +23 -0
  126. package/dist/plugin-sdk-internal/imessage.js +13 -0
  127. package/dist/plugin-sdk-internal/setup.js +9 -0
  128. package/dist/plugin-sdk-internal/signal.js +13 -0
  129. package/dist/plugin-sdk-internal/slack.js +22 -0
  130. package/dist/plugin-sdk-internal/telegram.js +32 -0
  131. package/dist/plugin-sdk-internal/whatsapp.js +29 -0
  132. package/dist/routing/session-key.js +4 -185
  133. package/dist/shared/pid-alive.js +2 -61
  134. package/dist/shared/process-scoped-map.js +5 -7
  135. package/dist/signal/channel.js +264 -0
  136. package/dist/signal/monitor/access-policy.js +60 -0
  137. package/dist/signal/runtime.js +3 -0
  138. package/dist/slack/account-inspect.js +135 -0
  139. package/dist/slack/blocks-input.js +7 -38
  140. package/dist/slack/channel.js +394 -0
  141. package/dist/slack/interactive-replies.js +28 -0
  142. package/dist/slack/monitor/channel-type.js +31 -0
  143. package/dist/slack/monitor/dm-auth.js +49 -0
  144. package/dist/slack/monitor/events/interactions.modal.js +137 -0
  145. package/dist/slack/monitor/events/message-subtype-handlers.js +68 -0
  146. package/dist/slack/monitor/events/system-event-context.js +29 -0
  147. package/dist/slack/monitor/events/system-event-test-harness.js +41 -0
  148. package/dist/slack/monitor/external-arg-menu-store.js +46 -0
  149. package/dist/slack/monitor/message-handler/prepare-content.js +69 -0
  150. package/dist/slack/monitor/message-handler/prepare-thread-context.js +91 -0
  151. package/dist/slack/monitor/message-handler/prepare.test-helpers.js +55 -0
  152. package/dist/slack/monitor/reconnect-policy.js +78 -0
  153. package/dist/slack/monitor/slash-commands.runtime.js +1 -0
  154. package/dist/slack/monitor/slash-dispatch.runtime.js +9 -0
  155. package/dist/slack/monitor/slash-skill-commands.runtime.js +1 -0
  156. package/dist/slack/resolve-allowlist-common.js +36 -0
  157. package/dist/slack/runtime.js +3 -0
  158. package/dist/slack/sent-thread-cache.js +61 -0
  159. package/dist/slack/truncate.js +10 -0
  160. package/dist/telegram/account-inspect.js +175 -0
  161. package/dist/telegram/allow-from.js +10 -0
  162. package/dist/telegram/api-fetch.js +18 -0
  163. package/dist/telegram/approval-buttons.js +30 -0
  164. package/dist/telegram/audit-membership-runtime.js +61 -0
  165. package/dist/telegram/bot/delivery.replies.js +508 -0
  166. package/dist/telegram/bot/delivery.resolve-media.js +227 -0
  167. package/dist/telegram/bot/delivery.send.js +132 -0
  168. package/dist/telegram/bot/reply-threading.js +46 -0
  169. package/dist/telegram/bot-message-context.body.js +186 -0
  170. package/dist/telegram/bot-message-context.session.js +207 -0
  171. package/dist/telegram/bot-message-context.types.js +1 -0
  172. package/dist/telegram/bot-native-commands.test-helpers.js +117 -0
  173. package/dist/telegram/bot.media.e2e-harness.js +81 -0
  174. package/dist/telegram/bot.media.test-utils.js +81 -0
  175. package/dist/telegram/channel-actions.js +225 -0
  176. package/dist/telegram/channel.js +515 -0
  177. package/dist/telegram/conversation-route.js +107 -0
  178. package/dist/telegram/delivery.js +2 -0
  179. package/dist/telegram/delivery.replies.js +508 -0
  180. package/dist/telegram/dm-access.js +86 -0
  181. package/dist/telegram/draft-stream.test-helpers.js +62 -0
  182. package/dist/telegram/exec-approvals-handler.js +281 -0
  183. package/dist/telegram/exec-approvals.js +62 -0
  184. package/dist/telegram/forum-service-message.js +22 -0
  185. package/dist/telegram/group-config-helpers.js +10 -0
  186. package/dist/telegram/lane-delivery-state.js +19 -0
  187. package/dist/telegram/lane-delivery-text-deliverer.js +357 -0
  188. package/dist/telegram/lane-delivery.js +2 -0
  189. package/dist/telegram/normalize.js +37 -0
  190. package/dist/telegram/onboarding.js +192 -0
  191. package/dist/telegram/outbound-adapter.js +100 -0
  192. package/dist/telegram/polling-session.js +275 -0
  193. package/dist/telegram/runtime.js +3 -0
  194. package/dist/telegram/sendchataction-401-backoff.js +71 -0
  195. package/dist/telegram/sequential-key.js +46 -0
  196. package/dist/telegram/status-issues.js +105 -0
  197. package/dist/telegram/target-writeback.js +165 -0
  198. package/dist/telegram/thread-bindings.js +560 -0
  199. package/dist/utils.js +32 -257
  200. package/dist/wizard/prompts.js +5 -5
  201. package/extensions/feishu/src/policy.ts +1 -1
  202. package/extensions/firecrawl/index.test.ts +82 -0
  203. package/extensions/firecrawl/index.ts +20 -0
  204. package/extensions/firecrawl/openclaw.plugin.json +8 -0
  205. package/extensions/firecrawl/package.json +12 -0
  206. package/extensions/firecrawl/src/config.ts +159 -0
  207. package/extensions/firecrawl/src/firecrawl-client.ts +446 -0
  208. package/extensions/firecrawl/src/firecrawl-scrape-tool.ts +89 -0
  209. package/extensions/firecrawl/src/firecrawl-search-provider.ts +63 -0
  210. package/extensions/firecrawl/src/firecrawl-search-tool.ts +76 -0
  211. package/package.json +1 -1
  212. package/dist/.buildstamp +0 -1
  213. package/dist/acp/bindings-store.js +0 -209
  214. package/dist/acp/control-plane/runtime-cache.js +0 -54
  215. package/dist/acp/control-plane/runtime-options.js +0 -215
  216. package/dist/acp/control-plane/session-actor-queue.js +0 -36
  217. package/dist/acp/index.js +0 -2
  218. package/dist/acp/runtime/errors.js +0 -47
  219. package/dist/acp/runtime/registry.js +0 -86
  220. package/dist/acp/secret-file.js +0 -22
  221. package/dist/agents/auth-profiles.resolve-auth-profile-order.fixtures.js +0 -23
  222. package/dist/agents/bash-process-registry.test-helpers.js +0 -29
  223. package/dist/agents/bash-tools.exec-approval-request.js +0 -20
  224. package/dist/agents/bash-tools.exec-host-gateway.js +0 -240
  225. package/dist/agents/bash-tools.exec-host-node.js +0 -235
  226. package/dist/agents/checkpoint-manager.js +0 -290
  227. package/dist/agents/claude-cli-runner.js +0 -3
  228. package/dist/agents/error-classifier.js +0 -251
  229. package/dist/agents/live-model-filter.js +0 -84
  230. package/dist/agents/nvidia-models.js +0 -228
  231. package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +0 -34
  232. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +0 -156
  233. package/dist/agents/pi-embedded-subscribe.handlers.tools.media.test-helpers.js +0 -30
  234. package/dist/agents/provider/config-loader.js +0 -76
  235. package/dist/agents/provider/index.js +0 -15
  236. package/dist/agents/provider/models-dev.js +0 -129
  237. package/dist/agents/provider/session-binding.js +0 -376
  238. package/dist/agents/queued-file-writer.js +0 -22
  239. package/dist/agents/skills/bundled-context.js +0 -23
  240. package/dist/agents/skills/security.js +0 -211
  241. package/dist/agents/skills/tools-dir.js +0 -9
  242. package/dist/agents/skills-install-download.js +0 -290
  243. package/dist/agents/skills-install-output.js +0 -30
  244. package/dist/agents/skills-install.download-test-utils.js +0 -36
  245. package/dist/agents/skills.test-helpers.js +0 -13
  246. package/dist/agents/subagent-announce-reliability.js +0 -160
  247. package/dist/agents/subagent-registry.mocks.shared.js +0 -12
  248. package/dist/agents/test-helpers/assistant-message-fixtures.js +0 -29
  249. package/dist/agents/test-helpers/fast-coding-tools.js +0 -1
  250. package/dist/agents/test-helpers/fast-core-tools.js +0 -8
  251. package/dist/agents/test-helpers/fast-tool-stubs.js +0 -18
  252. package/dist/agents/test-helpers/host-sandbox-fs-bridge.js +0 -74
  253. package/dist/agents/test-helpers/pi-tools-sandbox-context.js +0 -27
  254. package/dist/agents/tool-display-common.js +0 -915
  255. package/dist/agents/tool-policy-shared.js +0 -108
  256. package/dist/agents/tool-policy.conformance.js +0 -14
  257. package/dist/agents/tool-result-truncation.js +0 -299
  258. package/dist/agents/tools/cron-tool.test-helpers.js +0 -12
  259. package/dist/agents/tools/discord-actions-moderation-shared.js +0 -27
  260. package/dist/agents/tools/discord-actions-presence.js +0 -78
  261. package/dist/control-ui/assets/index-D7shnQwQ.js.map +0 -1
  262. package/dist/discord/discord-improvements.js +0 -167
  263. package/dist/discord/index.js +0 -2
  264. package/dist/hooks/bundled/boot-md/HOOK.md +0 -19
  265. package/dist/hooks/bundled/command-logger/HOOK.md +0 -122
  266. package/dist/hooks/bundled/session-memory/HOOK.md +0 -86
  267. package/dist/hooks/bundled/soul-evil/HOOK.md +0 -71
  268. package/dist/whatsapp/normalize.js +0 -66
  269. package/dist/whatsapp/resolve-outbound-target.js +0 -42
  270. /package/dist/{acp/runtime/types.js → auto-reply/auto-reply/reply/commands-types.js} +0 -0
  271. /package/dist/{agents/pi-embedded-payloads.js → slack/account-surface-fields.js} +0 -0
@@ -0,0 +1,515 @@
1
+ import { createScopedChannelConfigBase } from "openclaw/plugin-sdk/compat";
2
+ import { collectAllowlistProviderGroupPolicyWarnings, collectOpenGroupPolicyRouteAllowlistWarnings, createScopedAccountConfigAccessors, createScopedDmSecurityResolver, formatAllowFromLowercase, } from "openclaw/plugin-sdk/compat";
3
+ import { applyAccountNameToChannelSection, buildChannelConfigSchema, buildTokenChannelStatusSummary, clearAccountEntryFields, collectTelegramStatusIssues, DEFAULT_ACCOUNT_ID, getChatChannelMeta, inspectTelegramAccount, listTelegramAccountIds, listTelegramDirectoryGroupsFromConfig, listTelegramDirectoryPeersFromConfig, looksLikeTelegramTargetId, migrateBaseNameToDefaultAccount, normalizeAccountId, normalizeTelegramMessagingTarget, PAIRING_APPROVED_MESSAGE, parseTelegramReplyToMessageId, parseTelegramThreadId, projectCredentialSnapshotFields, resolveConfiguredFromCredentialStatuses, resolveDefaultTelegramAccountId, resolveTelegramAccount, resolveTelegramGroupRequireMention, resolveTelegramGroupToolPolicy, sendTelegramPayloadMessages, telegramOnboardingAdapter, TelegramConfigSchema, } from "openclaw/plugin-sdk/telegram";
4
+ import { resolveOutboundSendDep, } from "../../../src/infra/outbound/send-deps.js";
5
+ import { getTelegramRuntime } from "./runtime.js";
6
+ const meta = getChatChannelMeta("telegram");
7
+ function findTelegramTokenOwnerAccountId(params) {
8
+ const normalizedAccountId = normalizeAccountId(params.accountId);
9
+ const tokenOwners = new Map();
10
+ for (const id of listTelegramAccountIds(params.cfg)) {
11
+ const account = inspectTelegramAccount({ cfg: params.cfg, accountId: id });
12
+ const token = (account.token ?? "").trim();
13
+ if (!token) {
14
+ continue;
15
+ }
16
+ const ownerAccountId = tokenOwners.get(token);
17
+ if (!ownerAccountId) {
18
+ tokenOwners.set(token, account.accountId);
19
+ continue;
20
+ }
21
+ if (account.accountId === normalizedAccountId) {
22
+ return ownerAccountId;
23
+ }
24
+ }
25
+ return null;
26
+ }
27
+ function formatDuplicateTelegramTokenReason(params) {
28
+ return (`Duplicate Telegram bot token: account "${params.accountId}" shares a token with ` +
29
+ `account "${params.ownerAccountId}". Keep one owner account per bot token.`);
30
+ }
31
+ function buildTelegramSendOptions(params) {
32
+ return {
33
+ verbose: false,
34
+ cfg: params.cfg,
35
+ ...(params.mediaUrl ? { mediaUrl: params.mediaUrl } : {}),
36
+ ...(params.mediaLocalRoots?.length ? { mediaLocalRoots: params.mediaLocalRoots } : {}),
37
+ messageThreadId: parseTelegramThreadId(params.threadId),
38
+ replyToMessageId: parseTelegramReplyToMessageId(params.replyToId),
39
+ accountId: params.accountId ?? undefined,
40
+ silent: params.silent ?? undefined,
41
+ };
42
+ }
43
+ async function sendTelegramOutbound(params) {
44
+ const send = resolveOutboundSendDep(params.deps, "telegram") ??
45
+ getTelegramRuntime().channel.telegram.sendMessageTelegram;
46
+ return await send(params.to, params.text, buildTelegramSendOptions({
47
+ cfg: params.cfg,
48
+ mediaUrl: params.mediaUrl,
49
+ mediaLocalRoots: params.mediaLocalRoots,
50
+ accountId: params.accountId,
51
+ replyToId: params.replyToId,
52
+ threadId: params.threadId,
53
+ silent: params.silent,
54
+ }));
55
+ }
56
+ const telegramMessageActions = {
57
+ listActions: (ctx) => getTelegramRuntime().channel.telegram.messageActions?.listActions?.(ctx) ?? [],
58
+ extractToolSend: (ctx) => getTelegramRuntime().channel.telegram.messageActions?.extractToolSend?.(ctx) ?? null,
59
+ handleAction: async (ctx) => {
60
+ const ma = getTelegramRuntime().channel.telegram.messageActions;
61
+ if (!ma?.handleAction) {
62
+ throw new Error("Telegram message actions not available");
63
+ }
64
+ return ma.handleAction(ctx);
65
+ },
66
+ };
67
+ const telegramConfigAccessors = createScopedAccountConfigAccessors({
68
+ resolveAccount: ({ cfg, accountId }) => resolveTelegramAccount({ cfg, accountId }),
69
+ resolveAllowFrom: (account) => account.config.allowFrom,
70
+ formatAllowFrom: (allowFrom) => formatAllowFromLowercase({ allowFrom, stripPrefixRe: /^(telegram|tg):/i }),
71
+ resolveDefaultTo: (account) => account.config.defaultTo,
72
+ });
73
+ const telegramConfigBase = createScopedChannelConfigBase({
74
+ sectionKey: "telegram",
75
+ listAccountIds: listTelegramAccountIds,
76
+ resolveAccount: (cfg, accountId) => resolveTelegramAccount({ cfg, accountId }),
77
+ inspectAccount: (cfg, accountId) => inspectTelegramAccount({ cfg, accountId }),
78
+ defaultAccountId: resolveDefaultTelegramAccountId,
79
+ clearBaseFields: ["botToken", "tokenFile", "name"],
80
+ });
81
+ const resolveTelegramDmPolicy = createScopedDmSecurityResolver({
82
+ channelKey: "telegram",
83
+ resolvePolicy: (account) => account.config.dmPolicy,
84
+ resolveAllowFrom: (account) => account.config.allowFrom,
85
+ policyPathSuffix: "dmPolicy",
86
+ normalizeEntry: (raw) => raw.replace(/^(telegram|tg):/i, ""),
87
+ });
88
+ export const telegramPlugin = {
89
+ id: "telegram",
90
+ meta: {
91
+ ...meta,
92
+ quickstartAllowFrom: true,
93
+ },
94
+ onboarding: telegramOnboardingAdapter,
95
+ pairing: {
96
+ idLabel: "telegramUserId",
97
+ normalizeAllowEntry: (entry) => entry.replace(/^(telegram|tg):/i, ""),
98
+ notifyApproval: async ({ cfg, id }) => {
99
+ const { token } = getTelegramRuntime().channel.telegram.resolveTelegramToken(cfg);
100
+ if (!token) {
101
+ throw new Error("telegram token not configured");
102
+ }
103
+ await getTelegramRuntime().channel.telegram.sendMessageTelegram(id, PAIRING_APPROVED_MESSAGE, {
104
+ token,
105
+ });
106
+ },
107
+ },
108
+ capabilities: {
109
+ chatTypes: ["direct", "group", "channel", "thread"],
110
+ reactions: true,
111
+ threads: true,
112
+ media: true,
113
+ polls: true,
114
+ nativeCommands: true,
115
+ blockStreaming: true,
116
+ },
117
+ reload: { configPrefixes: ["channels.telegram"] },
118
+ configSchema: buildChannelConfigSchema(TelegramConfigSchema),
119
+ config: {
120
+ ...telegramConfigBase,
121
+ isConfigured: (account, cfg) => {
122
+ if (!account.token?.trim()) {
123
+ return false;
124
+ }
125
+ return !findTelegramTokenOwnerAccountId({ cfg, accountId: account.accountId });
126
+ },
127
+ unconfiguredReason: (account, cfg) => {
128
+ if (!account.token?.trim()) {
129
+ return "not configured";
130
+ }
131
+ const ownerAccountId = findTelegramTokenOwnerAccountId({ cfg, accountId: account.accountId });
132
+ if (!ownerAccountId) {
133
+ return "not configured";
134
+ }
135
+ return formatDuplicateTelegramTokenReason({
136
+ accountId: account.accountId,
137
+ ownerAccountId,
138
+ });
139
+ },
140
+ describeAccount: (account, cfg) => ({
141
+ accountId: account.accountId,
142
+ name: account.name,
143
+ enabled: account.enabled,
144
+ configured: Boolean(account.token?.trim()) &&
145
+ !findTelegramTokenOwnerAccountId({ cfg, accountId: account.accountId }),
146
+ tokenSource: account.tokenSource,
147
+ }),
148
+ ...telegramConfigAccessors,
149
+ },
150
+ security: {
151
+ resolveDmPolicy: resolveTelegramDmPolicy,
152
+ collectWarnings: ({ account, cfg }) => {
153
+ const groupAllowlistConfigured = account.config.groups && Object.keys(account.config.groups).length > 0;
154
+ return collectAllowlistProviderGroupPolicyWarnings({
155
+ cfg,
156
+ providerConfigPresent: cfg.channels?.telegram !== undefined,
157
+ configuredGroupPolicy: account.config.groupPolicy,
158
+ collect: (groupPolicy) => collectOpenGroupPolicyRouteAllowlistWarnings({
159
+ groupPolicy,
160
+ routeAllowlistConfigured: Boolean(groupAllowlistConfigured),
161
+ restrictSenders: {
162
+ surface: "Telegram groups",
163
+ openScope: "any member in allowed groups",
164
+ groupPolicyPath: "channels.telegram.groupPolicy",
165
+ groupAllowFromPath: "channels.telegram.groupAllowFrom",
166
+ },
167
+ noRouteAllowlist: {
168
+ surface: "Telegram groups",
169
+ routeAllowlistPath: "channels.telegram.groups",
170
+ routeScope: "group",
171
+ groupPolicyPath: "channels.telegram.groupPolicy",
172
+ groupAllowFromPath: "channels.telegram.groupAllowFrom",
173
+ },
174
+ }),
175
+ });
176
+ },
177
+ },
178
+ groups: {
179
+ resolveRequireMention: resolveTelegramGroupRequireMention,
180
+ resolveToolPolicy: resolveTelegramGroupToolPolicy,
181
+ },
182
+ threading: {
183
+ resolveReplyToMode: ({ cfg }) => cfg.channels?.telegram?.replyToMode ?? "off",
184
+ },
185
+ messaging: {
186
+ normalizeTarget: normalizeTelegramMessagingTarget,
187
+ targetResolver: {
188
+ looksLikeId: looksLikeTelegramTargetId,
189
+ hint: "<chatId>",
190
+ },
191
+ },
192
+ directory: {
193
+ self: async () => null,
194
+ listPeers: async (params) => listTelegramDirectoryPeersFromConfig(params),
195
+ listGroups: async (params) => listTelegramDirectoryGroupsFromConfig(params),
196
+ },
197
+ actions: telegramMessageActions,
198
+ setup: {
199
+ resolveAccountId: ({ accountId }) => normalizeAccountId(accountId),
200
+ applyAccountName: ({ cfg, accountId, name }) => applyAccountNameToChannelSection({
201
+ cfg,
202
+ channelKey: "telegram",
203
+ accountId,
204
+ name,
205
+ }),
206
+ validateInput: ({ accountId, input }) => {
207
+ if (input.useEnv && accountId !== DEFAULT_ACCOUNT_ID) {
208
+ return "TELEGRAM_BOT_TOKEN can only be used for the default account.";
209
+ }
210
+ if (!input.useEnv && !input.token && !input.tokenFile) {
211
+ return "Telegram requires token or --token-file (or --use-env).";
212
+ }
213
+ return null;
214
+ },
215
+ applyAccountConfig: ({ cfg, accountId, input }) => {
216
+ const namedConfig = applyAccountNameToChannelSection({
217
+ cfg,
218
+ channelKey: "telegram",
219
+ accountId,
220
+ name: input.name,
221
+ });
222
+ const next = accountId !== DEFAULT_ACCOUNT_ID
223
+ ? migrateBaseNameToDefaultAccount({
224
+ cfg: namedConfig,
225
+ channelKey: "telegram",
226
+ })
227
+ : namedConfig;
228
+ if (accountId === DEFAULT_ACCOUNT_ID) {
229
+ return {
230
+ ...next,
231
+ channels: {
232
+ ...next.channels,
233
+ telegram: {
234
+ ...next.channels?.telegram,
235
+ enabled: true,
236
+ ...(input.useEnv
237
+ ? {}
238
+ : input.tokenFile
239
+ ? { tokenFile: input.tokenFile }
240
+ : input.token
241
+ ? { botToken: input.token }
242
+ : {}),
243
+ },
244
+ },
245
+ };
246
+ }
247
+ return {
248
+ ...next,
249
+ channels: {
250
+ ...next.channels,
251
+ telegram: {
252
+ ...next.channels?.telegram,
253
+ enabled: true,
254
+ accounts: {
255
+ ...next.channels?.telegram?.accounts,
256
+ [accountId]: {
257
+ ...next.channels?.telegram?.accounts?.[accountId],
258
+ enabled: true,
259
+ ...(input.tokenFile
260
+ ? { tokenFile: input.tokenFile }
261
+ : input.token
262
+ ? { botToken: input.token }
263
+ : {}),
264
+ },
265
+ },
266
+ },
267
+ },
268
+ };
269
+ },
270
+ },
271
+ outbound: {
272
+ deliveryMode: "direct",
273
+ chunker: (text, limit) => getTelegramRuntime().channel.text.chunkMarkdownText(text, limit),
274
+ chunkerMode: "markdown",
275
+ textChunkLimit: 4000,
276
+ pollMaxOptions: 10,
277
+ sendPayload: async ({ cfg, to, payload, mediaLocalRoots, accountId, deps, replyToId, threadId, silent, }) => {
278
+ const send = resolveOutboundSendDep(deps, "telegram") ??
279
+ getTelegramRuntime().channel.telegram.sendMessageTelegram;
280
+ const result = await sendTelegramPayloadMessages({
281
+ send,
282
+ to,
283
+ payload,
284
+ baseOpts: buildTelegramSendOptions({
285
+ cfg,
286
+ mediaLocalRoots,
287
+ accountId,
288
+ replyToId,
289
+ threadId,
290
+ silent,
291
+ }),
292
+ });
293
+ return { channel: "telegram", ...result };
294
+ },
295
+ sendText: async ({ cfg, to, text, accountId, deps, replyToId, threadId, silent }) => {
296
+ const result = await sendTelegramOutbound({
297
+ cfg,
298
+ to,
299
+ text,
300
+ accountId,
301
+ deps,
302
+ replyToId,
303
+ threadId,
304
+ silent,
305
+ });
306
+ return { channel: "telegram", ...result };
307
+ },
308
+ sendMedia: async ({ cfg, to, text, mediaUrl, mediaLocalRoots, accountId, deps, replyToId, threadId, silent, }) => {
309
+ const result = await sendTelegramOutbound({
310
+ cfg,
311
+ to,
312
+ text,
313
+ mediaUrl,
314
+ mediaLocalRoots,
315
+ accountId,
316
+ deps,
317
+ replyToId,
318
+ threadId,
319
+ silent,
320
+ });
321
+ return { channel: "telegram", ...result };
322
+ },
323
+ sendPoll: async ({ cfg, to, poll, accountId, threadId, silent, isAnonymous }) => await getTelegramRuntime().channel.telegram.sendPollTelegram(to, poll, {
324
+ cfg,
325
+ accountId: accountId ?? undefined,
326
+ messageThreadId: parseTelegramThreadId(threadId),
327
+ silent: silent ?? undefined,
328
+ isAnonymous: isAnonymous ?? undefined,
329
+ }),
330
+ },
331
+ status: {
332
+ defaultRuntime: {
333
+ accountId: DEFAULT_ACCOUNT_ID,
334
+ running: false,
335
+ lastStartAt: null,
336
+ lastStopAt: null,
337
+ lastError: null,
338
+ },
339
+ collectStatusIssues: collectTelegramStatusIssues,
340
+ buildChannelSummary: ({ snapshot }) => buildTokenChannelStatusSummary(snapshot),
341
+ probeAccount: async ({ account, timeoutMs }) => getTelegramRuntime().channel.telegram.probeTelegram(account.token, timeoutMs, {
342
+ accountId: account.accountId,
343
+ proxyUrl: account.config.proxy,
344
+ network: account.config.network,
345
+ }),
346
+ auditAccount: async ({ account, timeoutMs, probe, cfg }) => {
347
+ const groups = cfg.channels?.telegram?.accounts?.[account.accountId]?.groups ??
348
+ cfg.channels?.telegram?.groups;
349
+ const { groupIds, unresolvedGroups, hasWildcardUnmentionedGroups } = getTelegramRuntime().channel.telegram.collectUnmentionedGroupIds(groups);
350
+ if (!groupIds.length && unresolvedGroups === 0 && !hasWildcardUnmentionedGroups) {
351
+ return undefined;
352
+ }
353
+ const botId = probe?.ok && probe.bot?.id != null ? probe.bot.id : null;
354
+ if (!botId) {
355
+ return {
356
+ ok: unresolvedGroups === 0 && !hasWildcardUnmentionedGroups,
357
+ checkedGroups: 0,
358
+ unresolvedGroups,
359
+ hasWildcardUnmentionedGroups,
360
+ groups: [],
361
+ elapsedMs: 0,
362
+ };
363
+ }
364
+ const audit = await getTelegramRuntime().channel.telegram.auditGroupMembership({
365
+ token: account.token,
366
+ botId,
367
+ groupIds,
368
+ proxyUrl: account.config.proxy,
369
+ network: account.config.network,
370
+ timeoutMs,
371
+ });
372
+ return { ...audit, unresolvedGroups, hasWildcardUnmentionedGroups };
373
+ },
374
+ buildAccountSnapshot: ({ account, cfg, runtime, probe, audit }) => {
375
+ const configuredFromStatus = resolveConfiguredFromCredentialStatuses(account);
376
+ const ownerAccountId = findTelegramTokenOwnerAccountId({
377
+ cfg,
378
+ accountId: account.accountId,
379
+ });
380
+ const duplicateTokenReason = ownerAccountId
381
+ ? formatDuplicateTelegramTokenReason({
382
+ accountId: account.accountId,
383
+ ownerAccountId,
384
+ })
385
+ : null;
386
+ const configured = (configuredFromStatus ?? Boolean(account.token?.trim())) && !ownerAccountId;
387
+ const groups = cfg.channels?.telegram?.accounts?.[account.accountId]?.groups ??
388
+ cfg.channels?.telegram?.groups;
389
+ const allowUnmentionedGroups = groups?.["*"]?.requireMention === false ||
390
+ Object.entries(groups ?? {}).some(([key, value]) => key !== "*" && value?.requireMention === false);
391
+ return {
392
+ accountId: account.accountId,
393
+ name: account.name,
394
+ enabled: account.enabled,
395
+ configured,
396
+ ...projectCredentialSnapshotFields(account),
397
+ running: runtime?.running ?? false,
398
+ lastStartAt: runtime?.lastStartAt ?? null,
399
+ lastStopAt: runtime?.lastStopAt ?? null,
400
+ lastError: runtime?.lastError ?? duplicateTokenReason,
401
+ mode: runtime?.mode ?? (account.config.webhookUrl ? "webhook" : "polling"),
402
+ probe,
403
+ audit,
404
+ allowUnmentionedGroups,
405
+ lastInboundAt: runtime?.lastInboundAt ?? null,
406
+ lastOutboundAt: runtime?.lastOutboundAt ?? null,
407
+ };
408
+ },
409
+ },
410
+ gateway: {
411
+ startAccount: async (ctx) => {
412
+ const account = ctx.account;
413
+ const ownerAccountId = findTelegramTokenOwnerAccountId({
414
+ cfg: ctx.cfg,
415
+ accountId: account.accountId,
416
+ });
417
+ if (ownerAccountId) {
418
+ const reason = formatDuplicateTelegramTokenReason({
419
+ accountId: account.accountId,
420
+ ownerAccountId,
421
+ });
422
+ ctx.log?.error?.(`[${account.accountId}] ${reason}`);
423
+ throw new Error(reason);
424
+ }
425
+ const token = (account.token ?? "").trim();
426
+ let telegramBotLabel = "";
427
+ try {
428
+ const probe = await getTelegramRuntime().channel.telegram.probeTelegram(token, 2500, {
429
+ accountId: account.accountId,
430
+ proxyUrl: account.config.proxy,
431
+ network: account.config.network,
432
+ });
433
+ const username = probe.ok ? probe.bot?.username?.trim() : null;
434
+ if (username) {
435
+ telegramBotLabel = ` (@${username})`;
436
+ }
437
+ }
438
+ catch (err) {
439
+ if (getTelegramRuntime().logging.shouldLogVerbose()) {
440
+ ctx.log?.debug?.(`[${account.accountId}] bot probe failed: ${String(err)}`);
441
+ }
442
+ }
443
+ ctx.log?.info(`[${account.accountId}] starting provider${telegramBotLabel}`);
444
+ return getTelegramRuntime().channel.telegram.monitorTelegramProvider({
445
+ token,
446
+ accountId: account.accountId,
447
+ config: ctx.cfg,
448
+ runtime: ctx.runtime,
449
+ abortSignal: ctx.abortSignal,
450
+ useWebhook: Boolean(account.config.webhookUrl),
451
+ webhookUrl: account.config.webhookUrl,
452
+ webhookSecret: account.config.webhookSecret,
453
+ webhookPath: account.config.webhookPath,
454
+ webhookHost: account.config.webhookHost,
455
+ webhookPort: account.config.webhookPort,
456
+ webhookCertPath: account.config.webhookCertPath,
457
+ });
458
+ },
459
+ logoutAccount: async ({ accountId, cfg }) => {
460
+ const envToken = process.env.TELEGRAM_BOT_TOKEN?.trim() ?? "";
461
+ const nextCfg = { ...cfg };
462
+ const nextTelegram = cfg.channels?.telegram ? { ...cfg.channels.telegram } : undefined;
463
+ let cleared = false;
464
+ let changed = false;
465
+ if (nextTelegram) {
466
+ if (accountId === DEFAULT_ACCOUNT_ID && nextTelegram.botToken) {
467
+ delete nextTelegram.botToken;
468
+ cleared = true;
469
+ changed = true;
470
+ }
471
+ const accountCleanup = clearAccountEntryFields({
472
+ accounts: nextTelegram.accounts,
473
+ accountId,
474
+ fields: ["botToken"],
475
+ });
476
+ if (accountCleanup.changed) {
477
+ changed = true;
478
+ if (accountCleanup.cleared) {
479
+ cleared = true;
480
+ }
481
+ if (accountCleanup.nextAccounts) {
482
+ nextTelegram.accounts = accountCleanup.nextAccounts;
483
+ }
484
+ else {
485
+ delete nextTelegram.accounts;
486
+ }
487
+ }
488
+ }
489
+ if (changed) {
490
+ if (nextTelegram && Object.keys(nextTelegram).length > 0) {
491
+ nextCfg.channels = { ...nextCfg.channels, telegram: nextTelegram };
492
+ }
493
+ else {
494
+ const nextChannels = { ...nextCfg.channels };
495
+ delete nextChannels.telegram;
496
+ if (Object.keys(nextChannels).length > 0) {
497
+ nextCfg.channels = nextChannels;
498
+ }
499
+ else {
500
+ delete nextCfg.channels;
501
+ }
502
+ }
503
+ }
504
+ const resolved = resolveTelegramAccount({
505
+ cfg: changed ? nextCfg : cfg,
506
+ accountId,
507
+ });
508
+ const loggedOut = resolved.tokenSource === "none";
509
+ if (changed) {
510
+ await getTelegramRuntime().config.writeConfigFile(nextCfg);
511
+ }
512
+ return { cleared, envToken: Boolean(envToken), loggedOut };
513
+ },
514
+ },
515
+ };
@@ -0,0 +1,107 @@
1
+ import { resolveConfiguredAcpRoute } from "../../../src/acp/persistent-bindings.route.js";
2
+ import { logVerbose } from "../../../src/globals.js";
3
+ import { getSessionBindingService } from "../../../src/infra/outbound/session-binding-service.js";
4
+ import { buildAgentSessionKey, deriveLastRoutePolicy, pickFirstExistingAgentId, resolveAgentRoute, } from "../../../src/routing/resolve-route.js";
5
+ import { buildAgentMainSessionKey, resolveAgentIdFromSessionKey, } from "../../../src/routing/session-key.js";
6
+ import { buildTelegramGroupPeerId, buildTelegramParentPeer, resolveTelegramDirectPeerId, } from "./bot/helpers.js";
7
+ export function resolveTelegramConversationRoute(params) {
8
+ const peerId = params.isGroup
9
+ ? buildTelegramGroupPeerId(params.chatId, params.resolvedThreadId)
10
+ : resolveTelegramDirectPeerId({
11
+ chatId: params.chatId,
12
+ senderId: params.senderId,
13
+ });
14
+ const parentPeer = buildTelegramParentPeer({
15
+ isGroup: params.isGroup,
16
+ resolvedThreadId: params.resolvedThreadId,
17
+ chatId: params.chatId,
18
+ });
19
+ let route = resolveAgentRoute({
20
+ cfg: params.cfg,
21
+ channel: "telegram",
22
+ accountId: params.accountId,
23
+ peer: {
24
+ kind: params.isGroup ? "group" : "direct",
25
+ id: peerId,
26
+ },
27
+ parentPeer,
28
+ });
29
+ const rawTopicAgentId = params.topicAgentId?.trim();
30
+ if (rawTopicAgentId) {
31
+ const topicAgentId = pickFirstExistingAgentId(params.cfg, rawTopicAgentId);
32
+ route = {
33
+ ...route,
34
+ agentId: topicAgentId,
35
+ sessionKey: buildAgentSessionKey({
36
+ agentId: topicAgentId,
37
+ channel: "telegram",
38
+ accountId: params.accountId,
39
+ peer: { kind: params.isGroup ? "group" : "direct", id: peerId },
40
+ dmScope: params.cfg.session?.dmScope,
41
+ identityLinks: params.cfg.session?.identityLinks,
42
+ }).toLowerCase(),
43
+ mainSessionKey: buildAgentMainSessionKey({
44
+ agentId: topicAgentId,
45
+ }).toLowerCase(),
46
+ lastRoutePolicy: deriveLastRoutePolicy({
47
+ sessionKey: buildAgentSessionKey({
48
+ agentId: topicAgentId,
49
+ channel: "telegram",
50
+ accountId: params.accountId,
51
+ peer: { kind: params.isGroup ? "group" : "direct", id: peerId },
52
+ dmScope: params.cfg.session?.dmScope,
53
+ identityLinks: params.cfg.session?.identityLinks,
54
+ }).toLowerCase(),
55
+ mainSessionKey: buildAgentMainSessionKey({
56
+ agentId: topicAgentId,
57
+ }).toLowerCase(),
58
+ }),
59
+ };
60
+ logVerbose(`telegram: topic route override: topic=${params.resolvedThreadId ?? params.replyThreadId} agent=${topicAgentId} sessionKey=${route.sessionKey}`);
61
+ }
62
+ const configuredRoute = resolveConfiguredAcpRoute({
63
+ cfg: params.cfg,
64
+ route,
65
+ channel: "telegram",
66
+ accountId: params.accountId,
67
+ conversationId: peerId,
68
+ parentConversationId: params.isGroup ? String(params.chatId) : undefined,
69
+ });
70
+ let configuredBinding = configuredRoute.configuredBinding;
71
+ let configuredBindingSessionKey = configuredRoute.boundSessionKey ?? "";
72
+ route = configuredRoute.route;
73
+ const threadBindingConversationId = params.replyThreadId != null
74
+ ? `${params.chatId}:topic:${params.replyThreadId}`
75
+ : !params.isGroup
76
+ ? String(params.chatId)
77
+ : undefined;
78
+ if (threadBindingConversationId) {
79
+ const threadBinding = getSessionBindingService().resolveByConversation({
80
+ channel: "telegram",
81
+ accountId: params.accountId,
82
+ conversationId: threadBindingConversationId,
83
+ });
84
+ const boundSessionKey = threadBinding?.targetSessionKey?.trim();
85
+ if (threadBinding && boundSessionKey) {
86
+ route = {
87
+ ...route,
88
+ sessionKey: boundSessionKey,
89
+ agentId: resolveAgentIdFromSessionKey(boundSessionKey),
90
+ lastRoutePolicy: deriveLastRoutePolicy({
91
+ sessionKey: boundSessionKey,
92
+ mainSessionKey: route.mainSessionKey,
93
+ }),
94
+ matchedBy: "binding.channel",
95
+ };
96
+ configuredBinding = null;
97
+ configuredBindingSessionKey = "";
98
+ getSessionBindingService().touch(threadBinding.bindingId);
99
+ logVerbose(`telegram: routed via bound conversation ${threadBindingConversationId} -> ${boundSessionKey}`);
100
+ }
101
+ }
102
+ return {
103
+ route,
104
+ configuredBinding,
105
+ configuredBindingSessionKey,
106
+ };
107
+ }
@@ -0,0 +1,2 @@
1
+ export { deliverReplies } from "./delivery.replies.js";
2
+ export { resolveMedia } from "./delivery.resolve-media.js";