@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,207 @@
1
+ import { normalizeCommandBody } from "../../../src/auto-reply/commands-registry.js";
2
+ import { formatInboundEnvelope, resolveEnvelopeFormatOptions, } from "../../../src/auto-reply/envelope.js";
3
+ import { buildPendingHistoryContextFromMap, } from "../../../src/auto-reply/reply/history.js";
4
+ import { finalizeInboundContext } from "../../../src/auto-reply/reply/inbound-context.js";
5
+ import { toLocationContext } from "../../../src/channels/location.js";
6
+ import { recordInboundSession } from "../../../src/channels/session.js";
7
+ import { readSessionUpdatedAt, resolveStorePath } from "../../../src/config/sessions.js";
8
+ import { logVerbose, shouldLogVerbose } from "../../../src/globals.js";
9
+ import { resolveInboundLastRouteSessionKey } from "../../../src/routing/resolve-route.js";
10
+ import { resolvePinnedMainDmOwnerFromAllowlist } from "../../../src/security/dm-policy-shared.js";
11
+ import { normalizeAllowFrom } from "./bot-access.js";
12
+ import { buildGroupLabel, buildSenderLabel, buildSenderName, buildTelegramGroupFrom, describeReplyTarget, normalizeForwardedContext, } from "./bot/helpers.js";
13
+ import { resolveTelegramGroupPromptSettings } from "./group-config-helpers.js";
14
+ export async function buildTelegramInboundContextPayload(params) {
15
+ const { cfg, primaryCtx, msg, allMedia, replyMedia, isGroup, isForum, chatId, senderId, senderUsername, resolvedThreadId, dmThreadId, threadSpec, route, rawBody, bodyText, historyKey, historyLimit, groupHistories, groupConfig, topicConfig, stickerCacheHit, effectiveWasMentioned, commandAuthorized, locationData, options, dmAllowFrom, } = params;
16
+ const replyTarget = describeReplyTarget(msg);
17
+ const forwardOrigin = normalizeForwardedContext(msg);
18
+ const replyForwardAnnotation = replyTarget?.forwardedFrom
19
+ ? `[Forwarded from ${replyTarget.forwardedFrom.from}${replyTarget.forwardedFrom.date
20
+ ? ` at ${new Date(replyTarget.forwardedFrom.date * 1000).toISOString()}`
21
+ : ""}]\n`
22
+ : "";
23
+ const replySuffix = replyTarget
24
+ ? replyTarget.kind === "quote"
25
+ ? `\n\n[Quoting ${replyTarget.sender}${replyTarget.id ? ` id:${replyTarget.id}` : ""}]\n${replyForwardAnnotation}"${replyTarget.body}"\n[/Quoting]`
26
+ : `\n\n[Replying to ${replyTarget.sender}${replyTarget.id ? ` id:${replyTarget.id}` : ""}]\n${replyForwardAnnotation}${replyTarget.body}\n[/Replying]`
27
+ : "";
28
+ const forwardPrefix = forwardOrigin
29
+ ? `[Forwarded from ${forwardOrigin.from}${forwardOrigin.date ? ` at ${new Date(forwardOrigin.date * 1000).toISOString()}` : ""}]\n`
30
+ : "";
31
+ const groupLabel = isGroup ? buildGroupLabel(msg, chatId, resolvedThreadId) : undefined;
32
+ const senderName = buildSenderName(msg);
33
+ const conversationLabel = isGroup
34
+ ? (groupLabel ?? `group:${chatId}`)
35
+ : buildSenderLabel(msg, senderId || chatId);
36
+ const storePath = resolveStorePath(cfg.session?.store, {
37
+ agentId: route.agentId,
38
+ });
39
+ const envelopeOptions = resolveEnvelopeFormatOptions(cfg);
40
+ const previousTimestamp = readSessionUpdatedAt({
41
+ storePath,
42
+ sessionKey: route.sessionKey,
43
+ });
44
+ const body = formatInboundEnvelope({
45
+ channel: "Telegram",
46
+ from: conversationLabel,
47
+ timestamp: msg.date ? msg.date * 1000 : undefined,
48
+ body: `${forwardPrefix}${bodyText}${replySuffix}`,
49
+ chatType: isGroup ? "group" : "direct",
50
+ sender: {
51
+ name: senderName,
52
+ username: senderUsername || undefined,
53
+ id: senderId || undefined,
54
+ },
55
+ previousTimestamp,
56
+ envelope: envelopeOptions,
57
+ });
58
+ let combinedBody = body;
59
+ if (isGroup && historyKey && historyLimit > 0) {
60
+ combinedBody = buildPendingHistoryContextFromMap({
61
+ historyMap: groupHistories,
62
+ historyKey,
63
+ limit: historyLimit,
64
+ currentMessage: combinedBody,
65
+ formatEntry: (entry) => formatInboundEnvelope({
66
+ channel: "Telegram",
67
+ from: groupLabel ?? `group:${chatId}`,
68
+ timestamp: entry.timestamp,
69
+ body: `${entry.body} [id:${entry.messageId ?? "unknown"} chat:${chatId}]`,
70
+ chatType: "group",
71
+ senderLabel: entry.sender,
72
+ envelope: envelopeOptions,
73
+ }),
74
+ });
75
+ }
76
+ const { skillFilter, groupSystemPrompt } = resolveTelegramGroupPromptSettings({
77
+ groupConfig,
78
+ topicConfig,
79
+ });
80
+ const commandBody = normalizeCommandBody(rawBody, {
81
+ botUsername: primaryCtx.me?.username?.toLowerCase(),
82
+ });
83
+ const inboundHistory = isGroup && historyKey && historyLimit > 0
84
+ ? (groupHistories.get(historyKey) ?? []).map((entry) => ({
85
+ sender: entry.sender,
86
+ body: entry.body,
87
+ timestamp: entry.timestamp,
88
+ }))
89
+ : undefined;
90
+ const currentMediaForContext = stickerCacheHit ? [] : allMedia;
91
+ const contextMedia = [...currentMediaForContext, ...replyMedia];
92
+ const ctxPayload = finalizeInboundContext({
93
+ Body: combinedBody,
94
+ BodyForAgent: bodyText,
95
+ InboundHistory: inboundHistory,
96
+ RawBody: rawBody,
97
+ CommandBody: commandBody,
98
+ From: isGroup ? buildTelegramGroupFrom(chatId, resolvedThreadId) : `telegram:${chatId}`,
99
+ To: `telegram:${chatId}`,
100
+ SessionKey: route.sessionKey,
101
+ AccountId: route.accountId,
102
+ ChatType: isGroup ? "group" : "direct",
103
+ ConversationLabel: conversationLabel,
104
+ GroupSubject: isGroup ? (msg.chat.title ?? undefined) : undefined,
105
+ GroupSystemPrompt: isGroup || (!isGroup && groupConfig) ? groupSystemPrompt : undefined,
106
+ SenderName: senderName,
107
+ SenderId: senderId || undefined,
108
+ SenderUsername: senderUsername || undefined,
109
+ Provider: "telegram",
110
+ Surface: "telegram",
111
+ BotUsername: primaryCtx.me?.username ?? undefined,
112
+ MessageSid: options?.messageIdOverride ?? String(msg.message_id),
113
+ ReplyToId: replyTarget?.id,
114
+ ReplyToBody: replyTarget?.body,
115
+ ReplyToSender: replyTarget?.sender,
116
+ ReplyToIsQuote: replyTarget?.kind === "quote" ? true : undefined,
117
+ ReplyToForwardedFrom: replyTarget?.forwardedFrom?.from,
118
+ ReplyToForwardedFromType: replyTarget?.forwardedFrom?.fromType,
119
+ ReplyToForwardedFromId: replyTarget?.forwardedFrom?.fromId,
120
+ ReplyToForwardedFromUsername: replyTarget?.forwardedFrom?.fromUsername,
121
+ ReplyToForwardedFromTitle: replyTarget?.forwardedFrom?.fromTitle,
122
+ ReplyToForwardedDate: replyTarget?.forwardedFrom?.date
123
+ ? replyTarget.forwardedFrom.date * 1000
124
+ : undefined,
125
+ ForwardedFrom: forwardOrigin?.from,
126
+ ForwardedFromType: forwardOrigin?.fromType,
127
+ ForwardedFromId: forwardOrigin?.fromId,
128
+ ForwardedFromUsername: forwardOrigin?.fromUsername,
129
+ ForwardedFromTitle: forwardOrigin?.fromTitle,
130
+ ForwardedFromSignature: forwardOrigin?.fromSignature,
131
+ ForwardedFromChatType: forwardOrigin?.fromChatType,
132
+ ForwardedFromMessageId: forwardOrigin?.fromMessageId,
133
+ ForwardedDate: forwardOrigin?.date ? forwardOrigin.date * 1000 : undefined,
134
+ Timestamp: msg.date ? msg.date * 1000 : undefined,
135
+ WasMentioned: isGroup ? effectiveWasMentioned : undefined,
136
+ MediaPath: contextMedia.length > 0 ? contextMedia[0]?.path : undefined,
137
+ MediaType: contextMedia.length > 0 ? contextMedia[0]?.contentType : undefined,
138
+ MediaUrl: contextMedia.length > 0 ? contextMedia[0]?.path : undefined,
139
+ MediaPaths: contextMedia.length > 0 ? contextMedia.map((m) => m.path) : undefined,
140
+ MediaUrls: contextMedia.length > 0 ? contextMedia.map((m) => m.path) : undefined,
141
+ MediaTypes: contextMedia.length > 0
142
+ ? contextMedia.map((m) => m.contentType).filter(Boolean)
143
+ : undefined,
144
+ Sticker: allMedia[0]?.stickerMetadata,
145
+ StickerMediaIncluded: allMedia[0]?.stickerMetadata ? !stickerCacheHit : undefined,
146
+ ...(locationData ? toLocationContext(locationData) : undefined),
147
+ CommandAuthorized: commandAuthorized,
148
+ MessageThreadId: threadSpec.id,
149
+ IsForum: isForum,
150
+ OriginatingChannel: "telegram",
151
+ OriginatingTo: `telegram:${chatId}`,
152
+ });
153
+ const pinnedMainDmOwner = !isGroup
154
+ ? resolvePinnedMainDmOwnerFromAllowlist({
155
+ dmScope: cfg.session?.dmScope,
156
+ allowFrom: dmAllowFrom,
157
+ normalizeEntry: (entry) => normalizeAllowFrom([entry]).entries[0],
158
+ })
159
+ : null;
160
+ const updateLastRouteSessionKey = resolveInboundLastRouteSessionKey({
161
+ route,
162
+ sessionKey: route.sessionKey,
163
+ });
164
+ await recordInboundSession({
165
+ storePath,
166
+ sessionKey: ctxPayload.SessionKey ?? route.sessionKey,
167
+ ctx: ctxPayload,
168
+ updateLastRoute: !isGroup
169
+ ? {
170
+ sessionKey: updateLastRouteSessionKey,
171
+ channel: "telegram",
172
+ to: `telegram:${chatId}`,
173
+ accountId: route.accountId,
174
+ threadId: dmThreadId != null ? String(dmThreadId) : undefined,
175
+ mainDmOwnerPin: updateLastRouteSessionKey === route.mainSessionKey && pinnedMainDmOwner && senderId
176
+ ? {
177
+ ownerRecipient: pinnedMainDmOwner,
178
+ senderRecipient: senderId,
179
+ onSkip: ({ ownerRecipient, senderRecipient }) => {
180
+ logVerbose(`telegram: skip main-session last route for ${senderRecipient} (pinned owner ${ownerRecipient})`);
181
+ },
182
+ }
183
+ : undefined,
184
+ }
185
+ : undefined,
186
+ onRecordError: (err) => {
187
+ logVerbose(`telegram: failed updating session meta: ${String(err)}`);
188
+ },
189
+ });
190
+ if (replyTarget && shouldLogVerbose()) {
191
+ const preview = replyTarget.body.replace(/\s+/g, " ").slice(0, 120);
192
+ logVerbose(`telegram reply-context: replyToId=${replyTarget.id} replyToSender=${replyTarget.sender} replyToBody="${preview}"`);
193
+ }
194
+ if (forwardOrigin && shouldLogVerbose()) {
195
+ logVerbose(`telegram forward-context: forwardedFrom="${forwardOrigin.from}" type=${forwardOrigin.fromType}`);
196
+ }
197
+ if (shouldLogVerbose()) {
198
+ const preview = body.slice(0, 200).replace(/\n/g, "\\n");
199
+ const mediaInfo = allMedia.length > 1 ? ` mediaCount=${allMedia.length}` : "";
200
+ const topicInfo = resolvedThreadId != null ? ` topic=${resolvedThreadId}` : "";
201
+ logVerbose(`telegram inbound: chatId=${chatId} from=${ctxPayload.From} len=${body.length}${mediaInfo}${topicInfo} preview="${preview}"`);
202
+ }
203
+ return {
204
+ ctxPayload,
205
+ skillFilter,
206
+ };
207
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,117 @@
1
+ import { vi } from "vitest";
2
+ import { registerTelegramNativeCommands } from "./bot-native-commands.js";
3
+ const pluginCommandMocks = vi.hoisted(() => ({
4
+ getPluginCommandSpecs: vi.fn(() => []),
5
+ matchPluginCommand: vi.fn(() => null),
6
+ executePluginCommand: vi.fn(async () => ({ text: "ok" })),
7
+ }));
8
+ export const getPluginCommandSpecs = pluginCommandMocks.getPluginCommandSpecs;
9
+ export const matchPluginCommand = pluginCommandMocks.matchPluginCommand;
10
+ export const executePluginCommand = pluginCommandMocks.executePluginCommand;
11
+ vi.mock("../../../src/plugins/commands.js", () => ({
12
+ getPluginCommandSpecs: pluginCommandMocks.getPluginCommandSpecs,
13
+ matchPluginCommand: pluginCommandMocks.matchPluginCommand,
14
+ executePluginCommand: pluginCommandMocks.executePluginCommand,
15
+ }));
16
+ const deliveryMocks = vi.hoisted(() => ({
17
+ deliverReplies: vi.fn(async () => { }),
18
+ }));
19
+ export const deliverReplies = deliveryMocks.deliverReplies;
20
+ vi.mock("./bot/delivery.js", () => ({ deliverReplies: deliveryMocks.deliverReplies }));
21
+ vi.mock("../../../src/pairing/pairing-store.js", () => ({
22
+ readChannelAllowFromStore: vi.fn(async () => []),
23
+ }));
24
+ export function createNativeCommandTestParams(params = {}) {
25
+ const log = vi.fn();
26
+ return {
27
+ bot: params.bot ??
28
+ {
29
+ api: {
30
+ setMyCommands: vi.fn().mockResolvedValue(undefined),
31
+ sendMessage: vi.fn().mockResolvedValue(undefined),
32
+ },
33
+ command: vi.fn(),
34
+ },
35
+ cfg: params.cfg ?? {},
36
+ runtime: params.runtime ?? { log },
37
+ accountId: params.accountId ?? "default",
38
+ telegramCfg: params.telegramCfg ?? {},
39
+ allowFrom: params.allowFrom ?? [],
40
+ groupAllowFrom: params.groupAllowFrom ?? [],
41
+ replyToMode: params.replyToMode ?? "off",
42
+ textLimit: params.textLimit ?? 4000,
43
+ useAccessGroups: params.useAccessGroups ?? false,
44
+ nativeEnabled: params.nativeEnabled ?? true,
45
+ nativeSkillsEnabled: params.nativeSkillsEnabled ?? false,
46
+ nativeDisabledExplicit: params.nativeDisabledExplicit ?? false,
47
+ resolveGroupPolicy: params.resolveGroupPolicy ??
48
+ (() => ({
49
+ allowlistEnabled: false,
50
+ allowed: true,
51
+ })),
52
+ resolveTelegramGroupConfig: params.resolveTelegramGroupConfig ??
53
+ (() => ({ groupConfig: undefined, topicConfig: undefined })),
54
+ shouldSkipUpdate: params.shouldSkipUpdate ?? (() => false),
55
+ opts: params.opts ?? { token: "token" },
56
+ };
57
+ }
58
+ export function createNativeCommandsHarness(params) {
59
+ const handlers = {};
60
+ const sendMessage = vi.fn(async () => undefined);
61
+ const setMyCommands = vi.fn(async () => undefined);
62
+ const log = vi.fn();
63
+ const bot = {
64
+ api: {
65
+ setMyCommands,
66
+ sendMessage,
67
+ },
68
+ command: (name, handler) => {
69
+ handlers[name] = handler;
70
+ },
71
+ };
72
+ registerTelegramNativeCommands({
73
+ bot: bot,
74
+ cfg: params?.cfg ?? {},
75
+ runtime: params?.runtime ?? { log },
76
+ accountId: "default",
77
+ telegramCfg: params?.telegramCfg ?? {},
78
+ allowFrom: params?.allowFrom ?? [],
79
+ groupAllowFrom: params?.groupAllowFrom ?? [],
80
+ replyToMode: "off",
81
+ textLimit: 4000,
82
+ useAccessGroups: params?.useAccessGroups ?? false,
83
+ nativeEnabled: params?.nativeEnabled ?? true,
84
+ nativeSkillsEnabled: false,
85
+ nativeDisabledExplicit: false,
86
+ resolveGroupPolicy: params?.resolveGroupPolicy ??
87
+ (() => ({
88
+ allowlistEnabled: false,
89
+ allowed: true,
90
+ })),
91
+ resolveTelegramGroupConfig: () => ({
92
+ groupConfig: params?.groupConfig,
93
+ topicConfig: undefined,
94
+ }),
95
+ shouldSkipUpdate: () => false,
96
+ opts: { token: "token" },
97
+ });
98
+ return { handlers, sendMessage, setMyCommands, log, bot };
99
+ }
100
+ export function createTelegramGroupCommandContext(params) {
101
+ return {
102
+ message: {
103
+ chat: { id: -100999, type: "supergroup", is_forum: true },
104
+ from: {
105
+ id: params?.senderId ?? 12345,
106
+ username: params?.username ?? "testuser",
107
+ },
108
+ message_thread_id: params?.threadId ?? 42,
109
+ message_id: 1,
110
+ date: 1700000000,
111
+ },
112
+ match: "",
113
+ };
114
+ }
115
+ export function findNotAuthorizedCalls(sendMessage) {
116
+ return sendMessage.mock.calls.filter((call) => typeof call[1] === "string" && call[1].includes("not authorized"));
117
+ }
@@ -0,0 +1,81 @@
1
+ import { beforeEach, vi } from "vitest";
2
+ import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js";
3
+ export const useSpy = vi.fn();
4
+ export const middlewareUseSpy = vi.fn();
5
+ export const onSpy = vi.fn();
6
+ export const stopSpy = vi.fn();
7
+ export const sendChatActionSpy = vi.fn();
8
+ const apiStub = {
9
+ config: { use: useSpy },
10
+ sendChatAction: sendChatActionSpy,
11
+ setMyCommands: vi.fn(async () => undefined),
12
+ };
13
+ beforeEach(() => {
14
+ resetInboundDedupe();
15
+ });
16
+ vi.mock("grammy", () => ({
17
+ Bot: class {
18
+ token;
19
+ api = apiStub;
20
+ use = middlewareUseSpy;
21
+ on = onSpy;
22
+ command = vi.fn();
23
+ stop = stopSpy;
24
+ catch = vi.fn();
25
+ constructor(token) {
26
+ this.token = token;
27
+ }
28
+ },
29
+ InputFile: class {
30
+ },
31
+ webhookCallback: vi.fn(),
32
+ }));
33
+ vi.mock("@grammyjs/runner", () => ({
34
+ sequentialize: () => vi.fn(),
35
+ }));
36
+ const throttlerSpy = vi.fn(() => "throttler");
37
+ vi.mock("@grammyjs/transformer-throttler", () => ({
38
+ apiThrottler: () => throttlerSpy(),
39
+ }));
40
+ vi.mock("../media/store.js", async (importOriginal) => {
41
+ const actual = await importOriginal();
42
+ return {
43
+ ...actual,
44
+ saveMediaBuffer: vi.fn(async (buffer, contentType) => ({
45
+ id: "media",
46
+ path: "/tmp/telegram-media",
47
+ size: buffer.byteLength,
48
+ contentType: contentType ?? "application/octet-stream",
49
+ })),
50
+ };
51
+ });
52
+ vi.mock("../config/config.js", async (importOriginal) => {
53
+ const actual = await importOriginal();
54
+ return {
55
+ ...actual,
56
+ loadConfig: () => ({
57
+ channels: { telegram: { dmPolicy: "open", allowFrom: ["*"] } },
58
+ }),
59
+ };
60
+ });
61
+ vi.mock("../config/sessions.js", async (importOriginal) => {
62
+ const actual = await importOriginal();
63
+ return {
64
+ ...actual,
65
+ updateLastRoute: vi.fn(async () => undefined),
66
+ };
67
+ });
68
+ vi.mock("../pairing/pairing-store.js", () => ({
69
+ readChannelAllowFromStore: vi.fn(async () => []),
70
+ upsertChannelPairingRequest: vi.fn(async () => ({
71
+ code: "PAIRCODE",
72
+ created: true,
73
+ })),
74
+ }));
75
+ vi.mock("../auto-reply/reply.js", () => {
76
+ const replySpy = vi.fn(async (_ctx, opts) => {
77
+ await opts?.onReplyStart?.();
78
+ return undefined;
79
+ });
80
+ return { getReplyFromConfig: replySpy, __replySpy: replySpy };
81
+ });
@@ -0,0 +1,81 @@
1
+ import { afterEach, beforeAll, beforeEach, expect, vi } from "vitest";
2
+ import * as ssrf from "../../../src/infra/net/ssrf.js";
3
+ import { onSpy, sendChatActionSpy } from "./bot.media.e2e-harness.js";
4
+ export const cacheStickerSpy = vi.fn();
5
+ export const getCachedStickerSpy = vi.fn();
6
+ export const describeStickerImageSpy = vi.fn();
7
+ const resolvePinnedHostname = ssrf.resolvePinnedHostname;
8
+ const lookupMock = vi.fn();
9
+ let resolvePinnedHostnameSpy = null;
10
+ export const TELEGRAM_TEST_TIMINGS = {
11
+ mediaGroupFlushMs: 20,
12
+ textFragmentGapMs: 30,
13
+ };
14
+ const TELEGRAM_BOT_IMPORT_TIMEOUT_MS = process.platform === "win32" ? 180_000 : 150_000;
15
+ let createTelegramBotRef;
16
+ let replySpyRef;
17
+ export async function createBotHandler() {
18
+ return createBotHandlerWithOptions({});
19
+ }
20
+ export async function createBotHandlerWithOptions(options) {
21
+ onSpy.mockClear();
22
+ replySpyRef.mockClear();
23
+ sendChatActionSpy.mockClear();
24
+ const runtimeError = options.runtimeError ?? vi.fn();
25
+ const runtimeLog = options.runtimeLog ?? vi.fn();
26
+ createTelegramBotRef({
27
+ token: "tok",
28
+ testTimings: TELEGRAM_TEST_TIMINGS,
29
+ ...(options.proxyFetch ? { proxyFetch: options.proxyFetch } : {}),
30
+ runtime: {
31
+ log: runtimeLog,
32
+ error: runtimeError,
33
+ exit: () => {
34
+ throw new Error("exit");
35
+ },
36
+ },
37
+ });
38
+ const handler = onSpy.mock.calls.find((call) => call[0] === "message")?.[1];
39
+ expect(handler).toBeDefined();
40
+ return { handler, replySpy: replySpyRef, runtimeError };
41
+ }
42
+ export function mockTelegramFileDownload(params) {
43
+ return vi.spyOn(globalThis, "fetch").mockResolvedValueOnce({
44
+ ok: true,
45
+ status: 200,
46
+ statusText: "OK",
47
+ headers: { get: () => params.contentType },
48
+ arrayBuffer: async () => params.bytes.buffer,
49
+ });
50
+ }
51
+ export function mockTelegramPngDownload() {
52
+ return vi.spyOn(globalThis, "fetch").mockResolvedValue({
53
+ ok: true,
54
+ status: 200,
55
+ statusText: "OK",
56
+ headers: { get: () => "image/png" },
57
+ arrayBuffer: async () => new Uint8Array([0x89, 0x50, 0x4e, 0x47]).buffer,
58
+ });
59
+ }
60
+ beforeEach(() => {
61
+ vi.useRealTimers();
62
+ lookupMock.mockResolvedValue([{ address: "93.184.216.34", family: 4 }]);
63
+ resolvePinnedHostnameSpy = vi
64
+ .spyOn(ssrf, "resolvePinnedHostname")
65
+ .mockImplementation((hostname) => resolvePinnedHostname(hostname, lookupMock));
66
+ });
67
+ afterEach(() => {
68
+ lookupMock.mockClear();
69
+ resolvePinnedHostnameSpy?.mockRestore();
70
+ resolvePinnedHostnameSpy = null;
71
+ });
72
+ beforeAll(async () => {
73
+ ({ createTelegramBot: createTelegramBotRef } = await import("./bot.js"));
74
+ const replyModule = await import("../../../src/auto-reply/reply.js");
75
+ replySpyRef = replyModule.__replySpy;
76
+ }, TELEGRAM_BOT_IMPORT_TIMEOUT_MS);
77
+ vi.mock("./sticker-cache.js", () => ({
78
+ cacheSticker: (...args) => cacheStickerSpy(...args),
79
+ getCachedSticker: (...args) => getCachedStickerSpy(...args),
80
+ describeStickerImage: (...args) => describeStickerImageSpy(...args),
81
+ }));