@poolzin/pool-bot 2026.1.39 → 2026.2.1

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 (511) hide show
  1. package/assets/chrome-extension/README.md +3 -3
  2. package/assets/chrome-extension/background.js +5 -5
  3. package/assets/chrome-extension/manifest.json +3 -3
  4. package/assets/chrome-extension/options.html +4 -4
  5. package/assets/chrome-extension/options.js +1 -1
  6. package/dist/acp/client.js +3 -3
  7. package/dist/acp/types.js +1 -1
  8. package/dist/agents/agent-paths.js +3 -3
  9. package/dist/agents/auth-profiles/paths.js +3 -3
  10. package/dist/agents/bash-tools.exec.js +76 -25
  11. package/dist/agents/cli-runner/helpers.js +10 -12
  12. package/dist/agents/cli-runner.js +2 -2
  13. package/dist/agents/cloudflare-ai-gateway.js +31 -0
  14. package/dist/agents/compaction.js +16 -2
  15. package/dist/agents/context-window-guard.js +13 -10
  16. package/dist/agents/context.js +4 -4
  17. package/dist/agents/docs-path.js +1 -1
  18. package/dist/agents/identity.js +47 -7
  19. package/dist/agents/memory-search.js +25 -8
  20. package/dist/agents/minimax-vlm.js +1 -1
  21. package/dist/agents/model-auth.js +12 -1
  22. package/dist/agents/model-catalog.js +4 -4
  23. package/dist/agents/model-selection.js +31 -4
  24. package/dist/agents/models-config.js +3 -3
  25. package/dist/agents/models-config.providers.js +147 -39
  26. package/dist/agents/pi-embedded-block-chunker.js +117 -42
  27. package/dist/agents/pi-embedded-helpers/errors.js +183 -78
  28. package/dist/agents/pi-embedded-helpers/openai.js +1 -1
  29. package/dist/agents/pi-embedded-helpers.js +1 -1
  30. package/dist/agents/pi-embedded-runner/compact.js +9 -8
  31. package/dist/agents/pi-embedded-runner/model.js +63 -4
  32. package/dist/agents/pi-embedded-runner/run/attempt.js +27 -17
  33. package/dist/agents/pi-embedded-runner/run.js +203 -50
  34. package/dist/agents/pi-embedded-runner/system-prompt.js +10 -2
  35. package/dist/agents/pi-embedded-runner/tool-result-truncation.js +275 -0
  36. package/dist/agents/pi-embedded-runner/utils.js +1 -1
  37. package/dist/agents/pi-embedded-subscribe.js +118 -29
  38. package/dist/agents/pi-model-discovery.js +10 -0
  39. package/dist/agents/pi-tool-definition-adapter.js +50 -9
  40. package/dist/agents/pi-tools.before-tool-call.js +67 -0
  41. package/dist/agents/pi-tools.js +20 -10
  42. package/dist/agents/pi-tools.read.js +2 -2
  43. package/dist/agents/poolbot-tools.js +15 -10
  44. package/dist/agents/sandbox-paths.js +31 -0
  45. package/dist/agents/session-file-repair.js +83 -0
  46. package/dist/agents/session-tool-result-guard.js +94 -15
  47. package/dist/agents/session-transcript-repair.js +68 -0
  48. package/dist/agents/shell-utils.js +51 -0
  49. package/dist/agents/skills/bundled-context.js +23 -0
  50. package/dist/agents/skills/bundled-dir.js +41 -7
  51. package/dist/agents/skills/frontmatter.js +1 -1
  52. package/dist/agents/skills/workspace.js +2 -2
  53. package/dist/agents/skills-install.js +60 -23
  54. package/dist/agents/subagent-announce.js +79 -34
  55. package/dist/agents/system-prompt.js +28 -4
  56. package/dist/agents/together-models.js +127 -0
  57. package/dist/agents/tool-images.js +1 -1
  58. package/dist/agents/tool-policy.conformance.js +14 -0
  59. package/dist/agents/tool-policy.js +25 -1
  60. package/dist/agents/tools/browser-tool.js +3 -3
  61. package/dist/agents/tools/cron-tool.js +166 -19
  62. package/dist/agents/tools/discord-actions-presence.js +78 -0
  63. package/dist/agents/tools/image-tool.js +2 -2
  64. package/dist/agents/tools/memory-tool.js +93 -5
  65. package/dist/agents/tools/message-tool.js +56 -2
  66. package/dist/agents/tools/sessions-history-tool.js +69 -1
  67. package/dist/agents/tools/web-search.js +211 -42
  68. package/dist/agents/usage.js +23 -1
  69. package/dist/agents/workspace-run.js +67 -0
  70. package/dist/agents/workspace-templates.js +44 -0
  71. package/dist/auto-reply/command-auth.js +121 -6
  72. package/dist/auto-reply/commands-registry.data.js +1 -1
  73. package/dist/auto-reply/envelope.js +50 -72
  74. package/dist/auto-reply/reply/commands-compact.js +1 -0
  75. package/dist/auto-reply/reply/commands-context-report.js +3 -2
  76. package/dist/auto-reply/reply/commands-context.js +1 -0
  77. package/dist/auto-reply/reply/commands-models.js +107 -60
  78. package/dist/auto-reply/reply/commands-ptt.js +171 -0
  79. package/dist/auto-reply/reply/commands-session.js +2 -2
  80. package/dist/auto-reply/reply/get-reply-run.js +16 -5
  81. package/dist/auto-reply/reply/groups.js +1 -1
  82. package/dist/auto-reply/reply/inbound-context.js +9 -1
  83. package/dist/auto-reply/reply/inbound-meta.js +130 -0
  84. package/dist/auto-reply/reply/model-selection.js +3 -3
  85. package/dist/auto-reply/reply/untrusted-context.js +15 -0
  86. package/dist/auto-reply/status.js +1 -1
  87. package/dist/auto-reply/thinking.js +88 -43
  88. package/dist/browser/bridge-server.js +13 -0
  89. package/dist/browser/cdp.helpers.js +38 -24
  90. package/dist/browser/client-fetch.js +51 -8
  91. package/dist/browser/config.js +2 -11
  92. package/dist/browser/extension-relay.js +104 -43
  93. package/dist/browser/pw-ai.js +1 -1
  94. package/dist/browser/pw-session.js +143 -8
  95. package/dist/browser/pw-tools-core.interactions.js +125 -27
  96. package/dist/browser/pw-tools-core.responses.js +1 -1
  97. package/dist/browser/pw-tools-core.state.js +1 -1
  98. package/dist/browser/routes/agent.act.js +86 -41
  99. package/dist/browser/routes/dispatcher.js +4 -4
  100. package/dist/browser/screenshot.js +1 -1
  101. package/dist/browser/server-context.js +2 -2
  102. package/dist/browser/server.js +13 -0
  103. package/dist/build-info.json +3 -3
  104. package/dist/canvas-host/a2ui.js +3 -3
  105. package/dist/channels/plugins/catalog.js +2 -2
  106. package/dist/channels/plugins/onboarding/imessage.js +1 -1
  107. package/dist/channels/plugins/onboarding/signal.js +1 -1
  108. package/dist/channels/plugins/onboarding/slack.js +4 -4
  109. package/dist/channels/plugins/onboarding/whatsapp.js +3 -3
  110. package/dist/channels/plugins/pairing-message.js +1 -1
  111. package/dist/channels/reply-prefix.js +8 -1
  112. package/dist/cli/browser-cli-extension.js +2 -2
  113. package/dist/cli/cron-cli/register.cron-add.js +61 -40
  114. package/dist/cli/cron-cli/register.cron-edit.js +60 -34
  115. package/dist/cli/cron-cli/shared.js +56 -41
  116. package/dist/cli/dns-cli.js +26 -14
  117. package/dist/cli/docs-cli.js +1 -1
  118. package/dist/cli/gateway-cli/dev.js +1 -1
  119. package/dist/cli/gateway-cli/register.js +37 -19
  120. package/dist/cli/memory-cli.js +30 -20
  121. package/dist/cli/nodes-cli/register.canvas.js +1 -1
  122. package/dist/cli/parse-bytes.js +37 -0
  123. package/dist/cli/plugins-cli.js +1 -1
  124. package/dist/cli/run-main.js +2 -2
  125. package/dist/cli/security-cli.js +1 -1
  126. package/dist/cli/tagline.js +1 -1
  127. package/dist/cli/update-cli.js +173 -52
  128. package/dist/cli/webhooks-cli.js +5 -5
  129. package/dist/commands/agent.js +1 -0
  130. package/dist/commands/agents.commands.add.js +1 -1
  131. package/dist/commands/auth-choice.apply.api-providers.js +305 -17
  132. package/dist/commands/auth-choice.apply.js +4 -1
  133. package/dist/commands/auth-choice.apply.plugin-provider.js +2 -2
  134. package/dist/commands/auth-choice.apply.xai.js +63 -0
  135. package/dist/commands/auth-choice.preferred-provider.js +7 -1
  136. package/dist/commands/configure.wizard.js +1 -1
  137. package/dist/commands/dashboard.js +1 -1
  138. package/dist/commands/docs.js +1 -1
  139. package/dist/commands/doctor-config-flow.js +61 -5
  140. package/dist/commands/doctor-gateway-services.js +3 -3
  141. package/dist/commands/doctor-state-migrations.js +1 -1
  142. package/dist/commands/doctor-update.js +3 -3
  143. package/dist/commands/doctor.js +1 -1
  144. package/dist/commands/health.js +1 -1
  145. package/dist/commands/model-allowlist.js +29 -0
  146. package/dist/commands/model-picker.js +2 -1
  147. package/dist/commands/models/list.probe.js +2 -2
  148. package/dist/commands/models/list.registry.js +4 -4
  149. package/dist/commands/models/list.status-command.js +44 -24
  150. package/dist/commands/models/shared.js +15 -0
  151. package/dist/commands/onboard-auth.config-core.js +366 -28
  152. package/dist/commands/onboard-auth.credentials.js +71 -9
  153. package/dist/commands/onboard-auth.js +3 -3
  154. package/dist/commands/onboard-auth.models.js +26 -24
  155. package/dist/commands/onboard-custom.js +384 -0
  156. package/dist/commands/onboard-non-interactive/local/auth-choice-inference.js +35 -0
  157. package/dist/commands/onboard-non-interactive/local/auth-choice.js +146 -9
  158. package/dist/commands/onboard-skills.js +63 -38
  159. package/dist/commands/openai-model-default.js +41 -0
  160. package/dist/commands/status-all/report-lines.js +1 -1
  161. package/dist/commands/status.command.js +1 -1
  162. package/dist/commands/uninstall.js +3 -3
  163. package/dist/compat/legacy-names.js +1 -1
  164. package/dist/config/defaults.js +3 -2
  165. package/dist/config/io.js +3 -3
  166. package/dist/config/paths.js +136 -35
  167. package/dist/config/plugin-auto-enable.js +21 -5
  168. package/dist/config/redact-snapshot.js +153 -0
  169. package/dist/config/schema.field-metadata.js +590 -0
  170. package/dist/config/schema.js +3 -3
  171. package/dist/config/sessions/store.js +291 -23
  172. package/dist/config/types.memory.js +1 -0
  173. package/dist/config/version.js +4 -4
  174. package/dist/config/zod-schema.agent-defaults.js +3 -0
  175. package/dist/config/zod-schema.agent-runtime.js +13 -2
  176. package/dist/config/zod-schema.providers-core.js +142 -0
  177. package/dist/config/zod-schema.session.js +3 -0
  178. package/dist/cron/delivery.js +57 -0
  179. package/dist/cron/isolated-agent/delivery-target.js +18 -3
  180. package/dist/cron/isolated-agent/helpers.js +22 -5
  181. package/dist/cron/isolated-agent/run.js +171 -63
  182. package/dist/cron/isolated-agent/session.js +2 -0
  183. package/dist/cron/normalize.js +356 -28
  184. package/dist/cron/parse.js +10 -5
  185. package/dist/cron/run-log.js +35 -10
  186. package/dist/cron/schedule.js +41 -6
  187. package/dist/cron/service/jobs.js +208 -35
  188. package/dist/cron/service/ops.js +72 -16
  189. package/dist/cron/service/state.js +2 -0
  190. package/dist/cron/service/store.js +386 -14
  191. package/dist/cron/service/timer.js +390 -147
  192. package/dist/cron/session-reaper.js +86 -0
  193. package/dist/cron/store.js +23 -8
  194. package/dist/cron/validate-timestamp.js +43 -0
  195. package/dist/daemon/constants.js +7 -7
  196. package/dist/daemon/inspect.js +6 -6
  197. package/dist/daemon/systemd-unit.js +1 -1
  198. package/dist/discord/monitor/agent-components.js +438 -0
  199. package/dist/discord/monitor/allow-list.js +28 -5
  200. package/dist/discord/monitor/gateway-registry.js +29 -0
  201. package/dist/discord/monitor/native-command.js +44 -23
  202. package/dist/discord/monitor/sender-identity.js +45 -0
  203. package/dist/discord/pluralkit.js +27 -0
  204. package/dist/discord/send.outbound.js +92 -5
  205. package/dist/discord/send.shared.js +60 -23
  206. package/dist/discord/targets.js +84 -1
  207. package/dist/entry.js +15 -9
  208. package/dist/extensionAPI.js +8 -0
  209. package/dist/gateway/control-ui.js +8 -1
  210. package/dist/gateway/hooks-mapping.js +3 -0
  211. package/dist/gateway/hooks.js +65 -0
  212. package/dist/gateway/live-image-probe.js +1 -66
  213. package/dist/gateway/net.js +96 -31
  214. package/dist/gateway/node-command-policy.js +50 -15
  215. package/dist/gateway/openai-http.js +2 -2
  216. package/dist/gateway/openresponses-http.js +4 -4
  217. package/dist/gateway/origin-check.js +56 -0
  218. package/dist/gateway/protocol/client-info.js +9 -0
  219. package/dist/gateway/protocol/index.js +9 -2
  220. package/dist/gateway/protocol/schema/agents-models-skills.js +71 -1
  221. package/dist/gateway/protocol/schema/cron.js +22 -10
  222. package/dist/gateway/protocol/schema/protocol-schemas.js +16 -2
  223. package/dist/gateway/protocol/schema/sessions.js +12 -0
  224. package/dist/gateway/server/hooks.js +1 -1
  225. package/dist/gateway/server-broadcast.js +26 -9
  226. package/dist/gateway/server-chat.js +112 -23
  227. package/dist/gateway/server-discovery-runtime.js +10 -2
  228. package/dist/gateway/server-discovery.js +2 -2
  229. package/dist/gateway/server-http.js +110 -12
  230. package/dist/gateway/server-methods/agent-timestamp.js +60 -0
  231. package/dist/gateway/server-methods/agents.js +321 -2
  232. package/dist/gateway/server-methods/usage.js +559 -16
  233. package/dist/gateway/server-runtime-state.js +22 -8
  234. package/dist/gateway/server-startup-memory.js +16 -0
  235. package/dist/gateway/server.impl.js +7 -3
  236. package/dist/gateway/session-utils.fs.js +23 -25
  237. package/dist/gateway/session-utils.js +20 -10
  238. package/dist/gateway/sessions-patch.js +7 -22
  239. package/dist/gateway/test-helpers.server.js +35 -2
  240. package/dist/hooks/frontmatter.js +1 -1
  241. package/dist/hooks/hooks-status.js +1 -1
  242. package/dist/hooks/install.js +2 -2
  243. package/dist/hooks/loader.js +1 -1
  244. package/dist/hooks/workspace.js +3 -3
  245. package/dist/imessage/constants.js +2 -0
  246. package/dist/imessage/monitor/deliver.js +4 -1
  247. package/dist/imessage/monitor/monitor-provider.js +51 -1
  248. package/dist/index.js +2 -2
  249. package/dist/infra/bonjour-discovery.js +131 -70
  250. package/dist/infra/bonjour.js +3 -3
  251. package/dist/infra/control-ui-assets.js +134 -12
  252. package/dist/infra/errors.js +12 -0
  253. package/dist/infra/exec-approvals.js +266 -57
  254. package/dist/infra/format-time/format-datetime.js +79 -0
  255. package/dist/infra/format-time/format-duration.js +81 -0
  256. package/dist/infra/format-time/format-relative.js +80 -0
  257. package/dist/infra/heartbeat-runner.js +140 -49
  258. package/dist/infra/home-dir.js +54 -0
  259. package/dist/infra/net/fetch-guard.js +122 -0
  260. package/dist/infra/net/ssrf.js +65 -29
  261. package/dist/infra/outbound/abort.js +14 -0
  262. package/dist/infra/outbound/message-action-runner.js +77 -13
  263. package/dist/infra/outbound/outbound-session.js +143 -37
  264. package/dist/infra/path-env.js +3 -3
  265. package/dist/infra/poolbot-root.js +43 -1
  266. package/dist/infra/provider-usage.fetch.minimax.js +1 -1
  267. package/dist/infra/restart.js +1 -1
  268. package/dist/infra/session-cost-usage.js +631 -41
  269. package/dist/infra/state-migrations.js +317 -47
  270. package/dist/infra/tailscale.js +1 -1
  271. package/dist/infra/update-global.js +35 -0
  272. package/dist/infra/update-runner.js +149 -43
  273. package/dist/infra/warning-filter.js +65 -0
  274. package/dist/infra/widearea-dns.js +30 -9
  275. package/dist/logging/redact-identifier.js +12 -0
  276. package/dist/macos/relay.js +2 -2
  277. package/dist/media/fetch.js +81 -58
  278. package/dist/media/input-files.js +1 -1
  279. package/dist/media/mime.js +4 -0
  280. package/dist/media/png-encode.js +74 -0
  281. package/dist/media-understanding/apply.js +403 -3
  282. package/dist/media-understanding/attachments.js +38 -27
  283. package/dist/media-understanding/defaults.js +16 -0
  284. package/dist/media-understanding/providers/deepgram/audio.js +22 -14
  285. package/dist/media-understanding/providers/google/audio.js +24 -17
  286. package/dist/media-understanding/providers/google/video.js +24 -17
  287. package/dist/media-understanding/providers/image.js +4 -4
  288. package/dist/media-understanding/providers/index.js +4 -1
  289. package/dist/media-understanding/providers/openai/audio.js +22 -14
  290. package/dist/media-understanding/providers/shared.js +16 -11
  291. package/dist/media-understanding/providers/zai/index.js +6 -0
  292. package/dist/media-understanding/runner.js +158 -90
  293. package/dist/memory/backend-config.js +207 -0
  294. package/dist/memory/batch-voyage.js +277 -0
  295. package/dist/memory/embeddings-voyage.js +75 -0
  296. package/dist/memory/embeddings.js +29 -17
  297. package/dist/memory/internal.js +101 -18
  298. package/dist/memory/manager.js +155 -48
  299. package/dist/memory/search-manager.js +173 -0
  300. package/dist/memory/session-files.js +9 -3
  301. package/dist/memory/types.js +1 -0
  302. package/dist/node-host/runner.js +36 -26
  303. package/dist/node-host/with-timeout.js +27 -0
  304. package/dist/pairing/pairing-messages.js +1 -1
  305. package/dist/plugins/commands.js +5 -1
  306. package/dist/plugins/config-state.js +86 -7
  307. package/dist/plugins/discovery.js +1 -1
  308. package/dist/plugins/install.js +2 -2
  309. package/dist/plugins/source-display.js +51 -0
  310. package/dist/plugins/update.js +1 -1
  311. package/dist/process/exec.js +20 -2
  312. package/dist/routing/resolve-route.js +12 -0
  313. package/dist/routing/session-key.js +15 -0
  314. package/dist/runtime.js +2 -0
  315. package/dist/security/audit-extra.async.js +601 -0
  316. package/dist/security/audit-extra.js +2 -830
  317. package/dist/security/audit-extra.sync.js +505 -0
  318. package/dist/security/audit.js +2 -2
  319. package/dist/security/channel-metadata.js +34 -0
  320. package/dist/security/external-content.js +88 -6
  321. package/dist/security/skill-scanner.js +330 -0
  322. package/dist/sessions/session-key-utils.js +7 -0
  323. package/dist/shared/text/reasoning-tags.js +52 -7
  324. package/dist/signal/monitor/event-handler.js +80 -1
  325. package/dist/slack/monitor/media.js +85 -15
  326. package/dist/tailscale/detect.js +145 -0
  327. package/dist/telegram/bot/helpers.js +109 -28
  328. package/dist/telegram/bot-handlers.js +144 -3
  329. package/dist/telegram/bot-message-context.js +38 -11
  330. package/dist/telegram/bot-message-dispatch.js +48 -15
  331. package/dist/telegram/bot-native-commands.js +86 -29
  332. package/dist/telegram/bot.js +30 -29
  333. package/dist/telegram/model-buttons.js +163 -0
  334. package/dist/telegram/monitor.js +110 -85
  335. package/dist/telegram/send.js +129 -47
  336. package/dist/terminal/restore.js +45 -0
  337. package/dist/test-helpers/state-dir-env.js +16 -0
  338. package/dist/test-helpers/workspace.js +11 -0
  339. package/dist/test-utils/channel-plugins.js +82 -0
  340. package/dist/test-utils/ports.js +73 -0
  341. package/dist/tts/tts.js +12 -6
  342. package/dist/tui/tui-session-actions.js +166 -54
  343. package/dist/utils/fetch-timeout.js +20 -0
  344. package/dist/utils/normalize-secret-input.js +19 -0
  345. package/dist/utils/shell-argv.js +61 -0
  346. package/dist/utils/transcript-tools.js +58 -0
  347. package/dist/utils.js +55 -14
  348. package/dist/version.js +42 -5
  349. package/dist/web/qr-image.js +1 -61
  350. package/dist/wizard/onboarding.finalize.js +7 -7
  351. package/dist/wizard/onboarding.js +3 -3
  352. package/docs/RELEASE_WORKFOTS_COMPARISON.md +3 -3
  353. package/docs/_config.yml +2 -2
  354. package/docs/_layouts/default.html +9 -9
  355. package/docs/concepts/typebox.md +1 -1
  356. package/docs/docs.json +1 -1
  357. package/docs/northflank.mdx +7 -7
  358. package/docs/railway.mdx +3 -3
  359. package/docs/render.mdx +5 -5
  360. package/docs/start/lore.md +2 -2
  361. package/extensions/bluebubbles/index.ts +2 -2
  362. package/extensions/bluebubbles/package.json +1 -1
  363. package/extensions/bluebubbles/src/accounts.ts +8 -8
  364. package/extensions/bluebubbles/src/actions.test.ts +22 -22
  365. package/extensions/bluebubbles/src/actions.ts +5 -5
  366. package/extensions/bluebubbles/src/attachments.ts +2 -2
  367. package/extensions/bluebubbles/src/channel.ts +16 -16
  368. package/extensions/bluebubbles/src/chat.ts +2 -2
  369. package/extensions/bluebubbles/src/media-send.ts +2 -2
  370. package/extensions/bluebubbles/src/monitor.test.ts +46 -46
  371. package/extensions/bluebubbles/src/monitor.ts +5 -5
  372. package/extensions/bluebubbles/src/onboarding.ts +7 -7
  373. package/extensions/bluebubbles/src/reactions.ts +2 -2
  374. package/extensions/bluebubbles/src/send.ts +2 -2
  375. package/extensions/copilot-proxy/README.md +1 -1
  376. package/extensions/copilot-proxy/package.json +1 -1
  377. package/extensions/diagnostics-otel/index.ts +2 -2
  378. package/extensions/diagnostics-otel/package.json +1 -1
  379. package/extensions/diagnostics-otel/src/service.ts +3 -3
  380. package/extensions/discord/index.ts +2 -2
  381. package/extensions/discord/package.json +1 -1
  382. package/extensions/google-antigravity-auth/README.md +1 -1
  383. package/extensions/google-antigravity-auth/index.ts +1 -1
  384. package/extensions/google-antigravity-auth/package.json +1 -1
  385. package/extensions/google-gemini-cli-auth/README.md +1 -1
  386. package/extensions/google-gemini-cli-auth/oauth.ts +1 -1
  387. package/extensions/google-gemini-cli-auth/package.json +1 -1
  388. package/extensions/googlechat/index.ts +3 -3
  389. package/extensions/googlechat/package.json +1 -1
  390. package/extensions/googlechat/src/accounts.ts +8 -8
  391. package/extensions/googlechat/src/actions.ts +6 -6
  392. package/extensions/googlechat/src/channel.ts +21 -21
  393. package/extensions/googlechat/src/monitor.ts +8 -8
  394. package/extensions/googlechat/src/onboarding.ts +10 -10
  395. package/extensions/imessage/index.ts +2 -2
  396. package/extensions/imessage/package.json +1 -1
  397. package/extensions/line/index.ts +2 -2
  398. package/extensions/line/package.json +1 -1
  399. package/extensions/line/src/card-command.ts +2 -2
  400. package/extensions/line/src/channel.logout.test.ts +4 -4
  401. package/extensions/line/src/channel.sendPayload.test.ts +8 -8
  402. package/extensions/line/src/channel.ts +3 -3
  403. package/extensions/llm-task/README.md +3 -3
  404. package/extensions/llm-task/index.ts +2 -2
  405. package/extensions/llm-task/package.json +1 -1
  406. package/extensions/llm-task/src/llm-task-tool.ts +4 -4
  407. package/extensions/lobster/README.md +6 -6
  408. package/extensions/lobster/index.ts +2 -2
  409. package/extensions/lobster/src/lobster-tool.test.ts +4 -4
  410. package/extensions/lobster/src/lobster-tool.ts +2 -2
  411. package/extensions/matrix/index.ts +2 -2
  412. package/extensions/matrix/package.json +1 -1
  413. package/extensions/matrix/src/matrix/client/config.ts +1 -1
  414. package/extensions/matrix/src/matrix/monitor/handler.ts +1 -1
  415. package/extensions/matrix/src/onboarding.ts +1 -1
  416. package/extensions/mattermost/index.ts +2 -2
  417. package/extensions/mattermost/package.json +1 -1
  418. package/extensions/mattermost/src/mattermost/accounts.ts +8 -8
  419. package/extensions/mattermost/src/mattermost/monitor-helpers.ts +5 -5
  420. package/extensions/mattermost/src/mattermost/monitor.ts +2 -2
  421. package/extensions/mattermost/src/onboarding-helpers.ts +3 -3
  422. package/extensions/mattermost/src/onboarding.ts +2 -2
  423. package/extensions/memory-core/index.ts +2 -2
  424. package/extensions/memory-core/package.json +1 -1
  425. package/extensions/memory-lancedb/index.ts +3 -3
  426. package/extensions/memory-lancedb/package.json +1 -1
  427. package/extensions/msteams/index.ts +2 -2
  428. package/extensions/msteams/package.json +1 -1
  429. package/extensions/msteams/src/channel.directory.test.ts +2 -2
  430. package/extensions/msteams/src/channel.ts +2 -2
  431. package/extensions/msteams/src/graph-upload.ts +4 -4
  432. package/extensions/msteams/src/monitor-handler.ts +2 -2
  433. package/extensions/msteams/src/monitor.ts +2 -2
  434. package/extensions/msteams/src/onboarding.ts +9 -9
  435. package/extensions/msteams/src/reply-dispatcher.ts +2 -2
  436. package/extensions/msteams/src/send-context.ts +2 -2
  437. package/extensions/msteams/src/send.ts +4 -4
  438. package/extensions/nextcloud-talk/index.ts +2 -2
  439. package/extensions/nextcloud-talk/package.json +1 -1
  440. package/extensions/nextcloud-talk/src/channel.ts +7 -7
  441. package/extensions/nextcloud-talk/src/inbound.ts +7 -7
  442. package/extensions/nextcloud-talk/src/onboarding.ts +1 -1
  443. package/extensions/nostr/README.md +2 -2
  444. package/extensions/nostr/index.ts +5 -5
  445. package/extensions/nostr/package.json +1 -1
  446. package/extensions/nostr/src/types.ts +4 -4
  447. package/extensions/open-prose/index.ts +2 -2
  448. package/extensions/qwen-portal-auth/README.md +1 -1
  449. package/extensions/signal/index.ts +2 -2
  450. package/extensions/signal/package.json +1 -1
  451. package/extensions/slack/index.ts +2 -2
  452. package/extensions/slack/package.json +1 -1
  453. package/extensions/telegram/index.ts +2 -2
  454. package/extensions/telegram/package.json +1 -1
  455. package/extensions/telegram/src/channel.ts +2 -2
  456. package/extensions/tlon/README.md +2 -2
  457. package/extensions/tlon/index.ts +2 -2
  458. package/extensions/tlon/package.json +1 -1
  459. package/extensions/tlon/src/channel.ts +13 -13
  460. package/extensions/tlon/src/monitor/index.ts +3 -3
  461. package/extensions/tlon/src/onboarding.ts +3 -3
  462. package/extensions/tlon/src/types.ts +3 -3
  463. package/extensions/twitch/README.md +1 -1
  464. package/extensions/twitch/index.ts +2 -2
  465. package/extensions/twitch/package.json +1 -1
  466. package/extensions/twitch/src/config.ts +3 -3
  467. package/extensions/twitch/src/monitor.ts +3 -3
  468. package/extensions/twitch/src/onboarding.ts +9 -9
  469. package/extensions/twitch/src/outbound.test.ts +2 -2
  470. package/extensions/twitch/src/plugin.test.ts +2 -2
  471. package/extensions/twitch/src/plugin.ts +8 -8
  472. package/extensions/twitch/src/send.test.ts +2 -2
  473. package/extensions/twitch/src/send.ts +4 -4
  474. package/extensions/twitch/src/token.test.ts +8 -8
  475. package/extensions/twitch/src/token.ts +3 -3
  476. package/extensions/twitch/src/twitch-client.ts +3 -3
  477. package/extensions/twitch/src/types.ts +3 -3
  478. package/extensions/twitch/src/utils/markdown.ts +1 -1
  479. package/extensions/voice-call/README.md +3 -3
  480. package/extensions/voice-call/package.json +1 -1
  481. package/extensions/voice-call/src/core-bridge.ts +2 -2
  482. package/extensions/voice-call/src/response-generator.ts +1 -1
  483. package/extensions/whatsapp/index.ts +2 -2
  484. package/extensions/whatsapp/package.json +1 -1
  485. package/extensions/zalo/README.md +1 -1
  486. package/extensions/zalo/index.ts +2 -2
  487. package/extensions/zalo/package.json +1 -1
  488. package/extensions/zalo/src/accounts.ts +8 -8
  489. package/extensions/zalo/src/actions.ts +4 -4
  490. package/extensions/zalo/src/channel.directory.test.ts +2 -2
  491. package/extensions/zalo/src/channel.ts +18 -18
  492. package/extensions/zalo/src/monitor.ts +9 -9
  493. package/extensions/zalo/src/monitor.webhook.test.ts +2 -2
  494. package/extensions/zalo/src/onboarding.ts +24 -24
  495. package/extensions/zalo/src/send.ts +2 -2
  496. package/extensions/zalouser/README.md +2 -2
  497. package/extensions/zalouser/index.ts +2 -2
  498. package/extensions/zalouser/package.json +1 -1
  499. package/extensions/zalouser/src/accounts.ts +9 -9
  500. package/extensions/zalouser/src/channel.ts +24 -24
  501. package/extensions/zalouser/src/monitor.ts +4 -4
  502. package/extensions/zalouser/src/onboarding.ts +28 -28
  503. package/package.json +13 -251
  504. package/skills/nano-banana-pro/scripts/generate_image.py +1 -1
  505. package/skills/tmux/scripts/find-sessions.sh +1 -1
  506. package/CHANGELOG.md +0 -102
  507. package/README-header.png +0 -0
  508. package/git-hooks/pre-commit +0 -4
  509. package/scripts/format-staged.js +0 -148
  510. package/scripts/postinstall.js +0 -300
  511. package/scripts/setup-git-hooks.js +0 -96
@@ -11,6 +11,7 @@ import { formatLocationText, toLocationContext } from "../channels/location.js";
11
11
  import { recordInboundSession } from "../channels/session.js";
12
12
  import { formatCliCommand } from "../cli/command-format.js";
13
13
  import { readSessionUpdatedAt, resolveStorePath } from "../config/sessions.js";
14
+ import { loadConfig } from "../config/config.js";
14
15
  import { logVerbose, shouldLogVerbose } from "../globals.js";
15
16
  import { recordChannelActivity } from "../infra/channel-activity.js";
16
17
  import { resolveAgentRoute } from "../routing/resolve-route.js";
@@ -20,7 +21,7 @@ import { resolveMentionGatingWithBypass } from "../channels/mention-gating.js";
20
21
  import { resolveControlCommandGate } from "../channels/command-gating.js";
21
22
  import { logInboundDrop } from "../channels/logging.js";
22
23
  import { withTelegramApiErrorLogging } from "./api-logging.js";
23
- import { buildGroupLabel, buildSenderLabel, buildSenderName, buildTelegramGroupFrom, buildTelegramGroupPeerId, buildTypingThreadParams, expandTextLinks, normalizeForwardedContext, describeReplyTarget, extractTelegramLocation, hasBotMention, resolveTelegramForumThreadId, } from "./bot/helpers.js";
24
+ import { buildGroupLabel, buildSenderLabel, buildSenderName, buildTelegramGroupFrom, buildTelegramGroupPeerId, buildTelegramParentPeer, buildTypingThreadParams, expandTextLinks, normalizeForwardedContext, describeReplyTarget, extractTelegramLocation, hasBotMention, resolveTelegramThreadSpec, } from "./bot/helpers.js";
24
25
  import { firstDefined, isSenderAllowed, normalizeAllowFromWithStore, resolveSenderAllowMatch, } from "./bot-access.js";
25
26
  import { upsertTelegramPairingRequest } from "./pairing-store.js";
26
27
  async function resolveStickerVisionSupport(params) {
@@ -50,23 +51,28 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
50
51
  const isGroup = msg.chat.type === "group" || msg.chat.type === "supergroup";
51
52
  const messageThreadId = msg.message_thread_id;
52
53
  const isForum = msg.chat.is_forum === true;
53
- const resolvedThreadId = resolveTelegramForumThreadId({
54
+ const threadSpec = resolveTelegramThreadSpec({
55
+ isGroup,
54
56
  isForum,
55
57
  messageThreadId,
56
58
  });
59
+ const resolvedThreadId = threadSpec.scope === "forum" ? threadSpec.id : undefined;
60
+ const replyThreadId = threadSpec.id;
57
61
  const { groupConfig, topicConfig } = resolveTelegramGroupConfig(chatId, resolvedThreadId);
58
62
  const peerId = isGroup ? buildTelegramGroupPeerId(chatId, resolvedThreadId) : String(chatId);
63
+ const parentPeer = buildTelegramParentPeer({ isGroup, resolvedThreadId, chatId });
59
64
  const route = resolveAgentRoute({
60
- cfg,
65
+ cfg: loadConfig(),
61
66
  channel: "telegram",
62
67
  accountId: account.accountId,
63
68
  peer: {
64
69
  kind: isGroup ? "group" : "dm",
65
70
  id: peerId,
66
71
  },
72
+ parentPeer,
67
73
  });
68
74
  const baseSessionKey = route.sessionKey;
69
- const dmThreadId = !isGroup ? resolvedThreadId : undefined;
75
+ const dmThreadId = threadSpec.scope === "dm" ? threadSpec.id : undefined;
70
76
  const threadKeys = dmThreadId != null
71
77
  ? resolveThreadSessionKeys({ baseSessionKey, threadId: String(dmThreadId) })
72
78
  : null;
@@ -90,14 +96,14 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
90
96
  const sendTyping = async () => {
91
97
  await withTelegramApiErrorLogging({
92
98
  operation: "sendChatAction",
93
- fn: () => bot.api.sendChatAction(chatId, "typing", buildTypingThreadParams(resolvedThreadId)),
99
+ fn: () => bot.api.sendChatAction(chatId, "typing", buildTypingThreadParams(replyThreadId)),
94
100
  });
95
101
  };
96
102
  const sendRecordVoice = async () => {
97
103
  try {
98
104
  await withTelegramApiErrorLogging({
99
105
  operation: "sendChatAction",
100
- fn: () => bot.api.sendChatAction(chatId, "record_voice", buildTypingThreadParams(resolvedThreadId)),
106
+ fn: () => bot.api.sendChatAction(chatId, "record_voice", buildTypingThreadParams(replyThreadId)),
101
107
  });
102
108
  }
103
109
  catch (err) {
@@ -109,7 +115,8 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
109
115
  if (dmPolicy === "disabled")
110
116
  return null;
111
117
  if (dmPolicy !== "open") {
112
- const candidate = String(chatId);
118
+ const senderUserId = msg.from?.id != null ? String(msg.from.id) : null;
119
+ const candidate = senderUserId ?? String(chatId);
113
120
  const senderUsername = msg.from?.username ?? "";
114
121
  const allowMatch = resolveSenderAllowMatch({
115
122
  allow: effectiveDmAllow,
@@ -131,7 +138,8 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
131
138
  });
132
139
  if (created) {
133
140
  logger.info({
134
- chatId: candidate,
141
+ chatId: String(chatId),
142
+ senderUserId: senderUserId ?? undefined,
135
143
  username: from?.username,
136
144
  firstName: from?.first_name,
137
145
  lastName: from?.last_name,
@@ -141,7 +149,7 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
141
149
  await withTelegramApiErrorLogging({
142
150
  operation: "sendMessage",
143
151
  fn: () => bot.api.sendMessage(chatId, [
144
- "Moltbot: access not configured.",
152
+ "Poolbot: access not configured.",
145
153
  "",
146
154
  `Your Telegram user id: ${telegramUserId}`,
147
155
  "",
@@ -201,6 +209,8 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
201
209
  placeholder = "<media:image>";
202
210
  else if (msg.video)
203
211
  placeholder = "<media:video>";
212
+ else if (msg.video_note)
213
+ placeholder = "<media:video>";
204
214
  else if (msg.audio || msg.voice)
205
215
  placeholder = "<media:audio>";
206
216
  else if (msg.document)
@@ -326,7 +336,9 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
326
336
  const replyTarget = describeReplyTarget(msg);
327
337
  const forwardOrigin = normalizeForwardedContext(msg);
328
338
  const replySuffix = replyTarget
329
- ? `\n\n[Replying to ${replyTarget.sender}${replyTarget.id ? ` id:${replyTarget.id}` : ""}]\n${replyTarget.body}\n[/Replying]`
339
+ ? replyTarget.kind === "quote"
340
+ ? `\n\n[Quoting ${replyTarget.sender}${replyTarget.id ? ` id:${replyTarget.id}` : ""}]\n"${replyTarget.body}"\n[/Quoting]`
341
+ : `\n\n[Replying to ${replyTarget.sender}${replyTarget.id ? ` id:${replyTarget.id}` : ""}]\n${replyTarget.body}\n[/Replying]`
330
342
  : "";
331
343
  const forwardPrefix = forwardOrigin
332
344
  ? `[Forwarded from ${forwardOrigin.from}${forwardOrigin.date ? ` at ${new Date(forwardOrigin.date * 1000).toISOString()}` : ""}]\n`
@@ -383,9 +395,17 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
383
395
  ].filter((entry) => Boolean(entry));
384
396
  const groupSystemPrompt = systemPromptParts.length > 0 ? systemPromptParts.join("\n\n") : undefined;
385
397
  const commandBody = normalizeCommandBody(rawBody, { botUsername });
398
+ const inboundHistory = isGroup && historyKey && historyLimit > 0
399
+ ? (groupHistories.get(historyKey) ?? []).map((entry) => ({
400
+ sender: entry.sender,
401
+ body: entry.body,
402
+ timestamp: entry.timestamp,
403
+ }))
404
+ : undefined;
386
405
  const ctxPayload = finalizeInboundContext({
387
406
  Body: combinedBody,
388
407
  RawBody: rawBody,
408
+ BodyForAgent: bodyText,
389
409
  CommandBody: commandBody,
390
410
  From: isGroup ? buildTelegramGroupFrom(chatId, resolvedThreadId) : `telegram:${chatId}`,
391
411
  To: `telegram:${chatId}`,
@@ -404,12 +424,15 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
404
424
  ReplyToId: replyTarget?.id,
405
425
  ReplyToBody: replyTarget?.body,
406
426
  ReplyToSender: replyTarget?.sender,
427
+ ReplyToIsQuote: replyTarget?.kind === "quote" ? true : undefined,
407
428
  ForwardedFrom: forwardOrigin?.from,
408
429
  ForwardedFromType: forwardOrigin?.fromType,
409
430
  ForwardedFromId: forwardOrigin?.fromId,
410
431
  ForwardedFromUsername: forwardOrigin?.fromUsername,
411
432
  ForwardedFromTitle: forwardOrigin?.fromTitle,
412
433
  ForwardedFromSignature: forwardOrigin?.fromSignature,
434
+ ForwardedFromChatType: forwardOrigin?.fromChatType,
435
+ ForwardedFromMessageId: forwardOrigin?.fromMessageId,
413
436
  ForwardedDate: forwardOrigin?.date ? forwardOrigin.date * 1000 : undefined,
414
437
  Timestamp: msg.date ? msg.date * 1000 : undefined,
415
438
  WasMentioned: isGroup ? effectiveWasMentioned : undefined,
@@ -435,7 +458,8 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
435
458
  Sticker: allMedia[0]?.stickerMetadata,
436
459
  ...(locationData ? toLocationContext(locationData) : undefined),
437
460
  CommandAuthorized: commandAuthorized,
438
- MessageThreadId: resolvedThreadId,
461
+ InboundHistory: inboundHistory,
462
+ MessageThreadId: threadSpec.id,
439
463
  IsForum: isForum,
440
464
  // Originating channel for reply routing.
441
465
  OriginatingChannel: "telegram",
@@ -451,6 +475,7 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
451
475
  channel: "telegram",
452
476
  to: String(chatId),
453
477
  accountId: route.accountId,
478
+ threadId: dmThreadId != null ? String(dmThreadId) : undefined,
454
479
  }
455
480
  : undefined,
456
481
  onRecordError: (err) => {
@@ -477,6 +502,8 @@ export const buildTelegramMessageContext = async ({ primaryCtx, allMedia, storeA
477
502
  chatId,
478
503
  isGroup,
479
504
  resolvedThreadId,
505
+ threadSpec,
506
+ replyThreadId,
480
507
  isForum,
481
508
  historyKey,
482
509
  historyLimit,
@@ -1,7 +1,7 @@
1
- // @ts-nocheck
2
- import { EmbeddedBlockChunker } from "../agents/pi-embedded-block-chunker.js";
1
+ import { resolveAgentDir } from "../agents/agent-scope.js";
3
2
  import { findModelInCatalog, loadModelCatalog, modelSupportsVision, } from "../agents/model-catalog.js";
4
3
  import { resolveDefaultModelForAgent } from "../agents/model-selection.js";
4
+ import { EmbeddedBlockChunker } from "../agents/pi-embedded-block-chunker.js";
5
5
  import { resolveChunkMode } from "../auto-reply/chunk.js";
6
6
  import { clearHistoryEntriesIfEnabled } from "../auto-reply/reply/history.js";
7
7
  import { dispatchReplyWithBufferedBlockDispatcher } from "../auto-reply/reply/provider-dispatcher.js";
@@ -9,13 +9,13 @@ import { removeAckReactionAfterReply } from "../channels/ack-reactions.js";
9
9
  import { logAckFailure, logTypingFailure } from "../channels/logging.js";
10
10
  import { createReplyPrefixContext } from "../channels/reply-prefix.js";
11
11
  import { createTypingCallbacks } from "../channels/typing.js";
12
- import { danger, logVerbose } from "../globals.js";
13
12
  import { resolveMarkdownTableMode } from "../config/markdown-tables.js";
13
+ import { danger, logVerbose } from "../globals.js";
14
14
  import { deliverReplies } from "./bot/delivery.js";
15
15
  import { resolveTelegramDraftStreamingChunking } from "./draft-chunking.js";
16
16
  import { createTelegramDraftStream } from "./draft-stream.js";
17
17
  import { cacheSticker, describeStickerImage } from "./sticker-cache.js";
18
- import { resolveAgentDir } from "../agents/agent-scope.js";
18
+ const EMPTY_RESPONSE_FALLBACK = "No response generated. Please try again.";
19
19
  async function resolveStickerVisionSupport(cfg, agentId) {
20
20
  try {
21
21
  const catalog = await loadModelCatalog({ config: cfg });
@@ -118,7 +118,7 @@ export const dispatchTelegramMessage = async ({ context, bot, cfg, runtime, repl
118
118
  // Handle uncached stickers: get a dedicated vision description before dispatch
119
119
  // This ensures we cache a raw description rather than a conversational response
120
120
  const sticker = ctxPayload.Sticker;
121
- if (sticker?.fileUniqueId && ctxPayload.MediaPath) {
121
+ if (sticker?.fileId && sticker.fileUniqueId && ctxPayload.MediaPath) {
122
122
  const agentDir = resolveAgentDir(cfg, route.agentId);
123
123
  const stickerSupportsVision = await resolveStickerVisionSupport(cfg, route.agentId);
124
124
  let description = sticker.cachedDescription ?? null;
@@ -150,18 +150,28 @@ export const dispatchTelegramMessage = async ({ context, bot, cfg, runtime, repl
150
150
  ctxPayload.MediaTypes = undefined;
151
151
  }
152
152
  // Cache the description for future encounters
153
- cacheSticker({
154
- fileId: sticker.fileId,
155
- fileUniqueId: sticker.fileUniqueId,
156
- emoji: sticker.emoji,
157
- setName: sticker.setName,
158
- description,
159
- cachedAt: new Date().toISOString(),
160
- receivedFrom: ctxPayload.From,
161
- });
162
- logVerbose(`telegram: cached sticker description for ${sticker.fileUniqueId}`);
153
+ if (sticker.fileId) {
154
+ cacheSticker({
155
+ fileId: sticker.fileId,
156
+ fileUniqueId: sticker.fileUniqueId,
157
+ emoji: sticker.emoji,
158
+ setName: sticker.setName,
159
+ description,
160
+ cachedAt: new Date().toISOString(),
161
+ receivedFrom: ctxPayload.From,
162
+ });
163
+ logVerbose(`telegram: cached sticker description for ${sticker.fileUniqueId}`);
164
+ }
165
+ else {
166
+ logVerbose(`telegram: skipped sticker cache (missing fileId)`);
167
+ }
163
168
  }
164
169
  }
170
+ // TODO: pass replyQuoteText to deliverReplies once delivery.ts supports it
171
+ const _replyQuoteText = ctxPayload.ReplyToIsQuote && ctxPayload.ReplyToBody
172
+ ? ctxPayload.ReplyToBody.trim() || undefined
173
+ : undefined;
174
+ void _replyQuoteText;
165
175
  const { queuedFinal } = await dispatchReplyWithBufferedBlockDispatcher({
166
176
  ctx: ctxPayload,
167
177
  cfg,
@@ -219,7 +229,30 @@ export const dispatchTelegramMessage = async ({ context, bot, cfg, runtime, repl
219
229
  },
220
230
  });
221
231
  draftStream?.stop();
232
+ let sentFallback = false;
222
233
  if (!queuedFinal) {
234
+ try {
235
+ await deliverReplies({
236
+ replies: [{ text: EMPTY_RESPONSE_FALLBACK }],
237
+ chatId: String(chatId),
238
+ token: opts.token,
239
+ runtime,
240
+ bot,
241
+ replyToMode,
242
+ textLimit,
243
+ messageThreadId: resolvedThreadId,
244
+ tableMode,
245
+ chunkMode,
246
+ linkPreview: telegramCfg.linkPreview,
247
+ });
248
+ sentFallback = true;
249
+ }
250
+ catch {
251
+ // Fallback delivery failed; proceed without it
252
+ }
253
+ }
254
+ const hasFinalResponse = queuedFinal || sentFallback;
255
+ if (!hasFinalResponse) {
223
256
  if (isGroup && historyKey) {
224
257
  clearHistoryEntriesIfEnabled({ historyMap: groupHistories, historyKey, limit: historyLimit });
225
258
  }
@@ -1,23 +1,23 @@
1
- import { resolveEffectiveMessagesConfig } from "../agents/identity.js";
2
1
  import { resolveChunkMode } from "../auto-reply/chunk.js";
3
2
  import { buildCommandTextFromArgs, findCommandByNativeName, listNativeCommandSpecs, listNativeCommandSpecsForConfig, parseCommandArgs, resolveCommandArgMenu, } from "../auto-reply/commands-registry.js";
4
- import { listSkillCommandsForAgents } from "../auto-reply/skill-commands.js";
5
- import { resolveTelegramCustomCommands } from "../config/telegram-custom-commands.js";
6
- import { dispatchReplyWithBufferedBlockDispatcher } from "../auto-reply/reply/provider-dispatcher.js";
7
3
  import { finalizeInboundContext } from "../auto-reply/reply/inbound-context.js";
8
- import { danger, logVerbose } from "../globals.js";
4
+ import { dispatchReplyWithBufferedBlockDispatcher } from "../auto-reply/reply/provider-dispatcher.js";
5
+ import { listSkillCommandsForAgents } from "../auto-reply/skill-commands.js";
6
+ import { resolveCommandAuthorizedFromAuthorizers } from "../channels/command-gating.js";
7
+ import { createReplyPrefixContext } from "../channels/reply-prefix.js";
9
8
  import { resolveMarkdownTableMode } from "../config/markdown-tables.js";
10
- import { withTelegramApiErrorLogging } from "./api-logging.js";
9
+ import { resolveTelegramCustomCommands } from "../config/telegram-custom-commands.js";
11
10
  import { normalizeTelegramCommandName, TELEGRAM_COMMAND_NAME_PATTERN, } from "../config/telegram-custom-commands.js";
11
+ import { danger, logVerbose } from "../globals.js";
12
+ import { readChannelAllowFromStore } from "../pairing/pairing-store.js";
13
+ import { executePluginCommand, getPluginCommandSpecs, matchPluginCommand, } from "../plugins/commands.js";
12
14
  import { resolveAgentRoute } from "../routing/resolve-route.js";
13
15
  import { resolveThreadSessionKeys } from "../routing/session-key.js";
14
- import { resolveCommandAuthorizedFromAuthorizers } from "../channels/command-gating.js";
15
- import { executePluginCommand, getPluginCommandSpecs, matchPluginCommand, } from "../plugins/commands.js";
16
+ import { withTelegramApiErrorLogging } from "./api-logging.js";
17
+ import { firstDefined, isSenderAllowed, normalizeAllowFromWithStore } from "./bot-access.js";
16
18
  import { deliverReplies } from "./bot/delivery.js";
19
+ import { buildTelegramThreadParams, buildSenderName, buildTelegramGroupFrom, buildTelegramGroupPeerId, resolveTelegramForumThreadId, } from "./bot/helpers.js";
17
20
  import { buildInlineKeyboard } from "./send.js";
18
- import { buildSenderName, buildTelegramGroupFrom, buildTelegramGroupPeerId, resolveTelegramForumThreadId, } from "./bot/helpers.js";
19
- import { firstDefined, isSenderAllowed, normalizeAllowFromWithStore } from "./bot-access.js";
20
- import { readTelegramAllowFromStore } from "./pairing-store.js";
21
21
  async function resolveTelegramCommandAuth(params) {
22
22
  const { msg, bot, cfg, telegramCfg, allowFrom, groupAllowFrom, useAccessGroups, resolveGroupPolicy, resolveTelegramGroupConfig, requireAuth, } = params;
23
23
  const chatId = msg.chat.id;
@@ -28,7 +28,7 @@ async function resolveTelegramCommandAuth(params) {
28
28
  isForum,
29
29
  messageThreadId,
30
30
  });
31
- const storeAllowFrom = await readTelegramAllowFromStore().catch(() => []);
31
+ const storeAllowFrom = await readChannelAllowFromStore("telegram").catch(() => []);
32
32
  const { groupConfig, topicConfig } = resolveTelegramGroupConfig(chatId, resolvedThreadId);
33
33
  const groupAllowOverride = firstDefined(topicConfig?.allowFrom, groupConfig?.allowFrom);
34
34
  const effectiveGroupAllow = normalizeAllowFromWithStore({
@@ -69,7 +69,7 @@ async function resolveTelegramCommandAuth(params) {
69
69
  }
70
70
  if (isGroup && useAccessGroups) {
71
71
  const defaultGroupPolicy = cfg.channels?.defaults?.groupPolicy;
72
- const groupPolicy = telegramCfg.groupPolicy ?? defaultGroupPolicy ?? "open";
72
+ const groupPolicy = firstDefined(topicConfig?.groupPolicy, groupConfig?.groupPolicy, telegramCfg.groupPolicy, defaultGroupPolicy, "open");
73
73
  if (groupPolicy === "disabled") {
74
74
  await withTelegramApiErrorLogging({
75
75
  operation: "sendMessage",
@@ -134,7 +134,13 @@ async function resolveTelegramCommandAuth(params) {
134
134
  };
135
135
  }
136
136
  export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, telegramCfg, allowFrom, groupAllowFrom, replyToMode, textLimit, useAccessGroups, nativeEnabled, nativeSkillsEnabled, nativeDisabledExplicit, resolveGroupPolicy, resolveTelegramGroupConfig, shouldSkipUpdate, opts, }) => {
137
- const skillCommands = nativeEnabled && nativeSkillsEnabled ? listSkillCommandsForAgents({ cfg }) : [];
137
+ const boundRoute = nativeEnabled && nativeSkillsEnabled
138
+ ? resolveAgentRoute({ cfg, channel: "telegram", accountId })
139
+ : null;
140
+ const boundAgentIds = boundRoute && boundRoute.matchedBy.startsWith("binding.") ? [boundRoute.agentId] : null;
141
+ const skillCommands = nativeEnabled && nativeSkillsEnabled
142
+ ? listSkillCommandsForAgents(boundAgentIds ? { cfg, agentIds: boundAgentIds } : { cfg })
143
+ : [];
138
144
  const nativeCommands = nativeEnabled
139
145
  ? listNativeCommandSpecsForConfig(cfg, { skillCommands, provider: "telegram" })
140
146
  : [];
@@ -180,7 +186,7 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
180
186
  existingCommands.add(normalized);
181
187
  pluginCommands.push({ command: normalized, description });
182
188
  }
183
- const allCommands = [
189
+ const allCommandsFull = [
184
190
  ...nativeCommands.map((command) => ({
185
191
  command: command.name,
186
192
  description: command.description,
@@ -188,12 +194,39 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
188
194
  ...pluginCommands,
189
195
  ...customCommands,
190
196
  ];
191
- if (allCommands.length > 0) {
192
- void withTelegramApiErrorLogging({
193
- operation: "setMyCommands",
197
+ // Telegram Bot API limits commands to 100 per scope.
198
+ // Truncate with a warning rather than failing with BOT_COMMANDS_TOO_MUCH.
199
+ const TELEGRAM_MAX_COMMANDS = 100;
200
+ if (allCommandsFull.length > TELEGRAM_MAX_COMMANDS) {
201
+ runtime.log?.(`telegram: truncating ${allCommandsFull.length} commands to ${TELEGRAM_MAX_COMMANDS} (Telegram Bot API limit)`);
202
+ }
203
+ const allCommands = allCommandsFull.slice(0, TELEGRAM_MAX_COMMANDS);
204
+ // Clear stale commands before registering new ones to prevent
205
+ // leftover commands from deleted skills persisting across restarts.
206
+ // Chain delete → set so a late-resolving delete cannot wipe newly registered commands.
207
+ const registerCommands = () => {
208
+ if (allCommands.length > 0) {
209
+ withTelegramApiErrorLogging({
210
+ operation: "setMyCommands",
211
+ runtime,
212
+ fn: () => bot.api.setMyCommands(allCommands),
213
+ }).catch(() => { });
214
+ }
215
+ };
216
+ if (typeof bot.api.deleteMyCommands === "function") {
217
+ withTelegramApiErrorLogging({
218
+ operation: "deleteMyCommands",
194
219
  runtime,
195
- fn: () => bot.api.setMyCommands(allCommands),
196
- }).catch(() => { });
220
+ fn: () => bot.api.deleteMyCommands(),
221
+ })
222
+ .catch(() => { })
223
+ .then(registerCommands)
224
+ .catch(() => { });
225
+ }
226
+ else {
227
+ registerCommands();
228
+ }
229
+ if (allCommands.length > 0) {
197
230
  if (typeof bot.command !== "function") {
198
231
  logVerbose("telegram: bot.command unavailable; skipping native handlers");
199
232
  }
@@ -201,10 +234,12 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
201
234
  for (const command of nativeCommands) {
202
235
  bot.command(command.name, async (ctx) => {
203
236
  const msg = ctx.message;
204
- if (!msg)
237
+ if (!msg) {
205
238
  return;
206
- if (shouldSkipUpdate(ctx))
239
+ }
240
+ if (shouldSkipUpdate(ctx)) {
207
241
  return;
242
+ }
208
243
  const auth = await resolveTelegramCommandAuth({
209
244
  msg,
210
245
  bot,
@@ -217,9 +252,12 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
217
252
  resolveTelegramGroupConfig,
218
253
  requireAuth: true,
219
254
  });
220
- if (!auth)
255
+ if (!auth) {
221
256
  return;
257
+ }
222
258
  const { chatId, isGroup, isForum, resolvedThreadId, senderId, senderUsername, groupConfig, topicConfig, commandAuthorized, } = auth;
259
+ const messageThreadId = msg.message_thread_id;
260
+ const threadParams = buildTelegramThreadParams(resolvedThreadId) ?? {};
223
261
  const commandDefinition = findCommandByNativeName(command.name, "telegram");
224
262
  const rawText = ctx.match?.trim() ?? "";
225
263
  const commandArgs = commandDefinition
@@ -261,7 +299,7 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
261
299
  runtime,
262
300
  fn: () => bot.api.sendMessage(chatId, title, {
263
301
  ...(replyMarkup ? { reply_markup: replyMarkup } : {}),
264
- ...(resolvedThreadId != null ? { message_thread_id: resolvedThreadId } : {}),
302
+ ...threadParams,
265
303
  }),
266
304
  });
267
305
  return;
@@ -276,9 +314,13 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
276
314
  },
277
315
  });
278
316
  const baseSessionKey = route.sessionKey;
279
- const dmThreadId = !isGroup ? resolvedThreadId : undefined;
317
+ // DMs: use raw messageThreadId for thread sessions (not resolvedThreadId which is for forums)
318
+ const dmThreadId = !isGroup ? messageThreadId : undefined;
280
319
  const threadKeys = dmThreadId != null
281
- ? resolveThreadSessionKeys({ baseSessionKey, threadId: String(dmThreadId) })
320
+ ? resolveThreadSessionKeys({
321
+ baseSessionKey,
322
+ threadId: String(dmThreadId),
323
+ })
282
324
  : null;
283
325
  const sessionKey = threadKeys?.sessionKey ?? baseSessionKey;
284
326
  const tableMode = resolveMarkdownTableMode({
@@ -299,6 +341,7 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
299
341
  : (buildSenderName(msg) ?? String(senderId || chatId));
300
342
  const ctxPayload = finalizeInboundContext({
301
343
  Body: prompt,
344
+ BodyForAgent: prompt,
302
345
  RawBody: prompt,
303
346
  CommandBody: prompt,
304
347
  CommandArgs: commandArgs,
@@ -318,6 +361,7 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
318
361
  CommandAuthorized: commandAuthorized,
319
362
  CommandSource: "native",
320
363
  SessionKey: `telegram:slash:${senderId || chatId}`,
364
+ AccountId: route.accountId,
321
365
  CommandTargetSessionKey: sessionKey,
322
366
  MessageThreadId: resolvedThreadId,
323
367
  IsForum: isForum,
@@ -329,12 +373,16 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
329
373
  ? !telegramCfg.blockStreaming
330
374
  : undefined;
331
375
  const chunkMode = resolveChunkMode(cfg, "telegram", route.accountId);
376
+ const { onModelSelected, ...prefixOptions } = createReplyPrefixContext({
377
+ cfg,
378
+ agentId: route.agentId,
379
+ });
332
380
  await dispatchReplyWithBufferedBlockDispatcher({
333
381
  ctx: ctxPayload,
334
382
  cfg,
335
383
  dispatcherOptions: {
336
- responsePrefix: resolveEffectiveMessagesConfig(cfg, route.agentId).responsePrefix,
337
- deliver: async (payload) => {
384
+ ...prefixOptions,
385
+ deliver: async (payload, _info) => {
338
386
  await deliverReplies({
339
387
  replies: [payload],
340
388
  chatId: String(chatId),
@@ -356,6 +404,7 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
356
404
  replyOptions: {
357
405
  skillFilter,
358
406
  disableBlockStreaming,
407
+ onModelSelected,
359
408
  },
360
409
  });
361
410
  });
@@ -393,7 +442,11 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
393
442
  });
394
443
  if (!auth)
395
444
  return;
396
- const { resolvedThreadId, senderId, commandAuthorized } = auth;
445
+ const { resolvedThreadId, senderId, commandAuthorized, isGroup } = auth;
446
+ const from = isGroup
447
+ ? buildTelegramGroupFrom(chatId, resolvedThreadId)
448
+ : `telegram:${chatId}`;
449
+ const to = `telegram:${chatId}`;
397
450
  const result = await executePluginCommand({
398
451
  command: match.command,
399
452
  args: match.args,
@@ -402,6 +455,10 @@ export const registerTelegramNativeCommands = ({ bot, cfg, runtime, accountId, t
402
455
  isAuthorizedSender: commandAuthorized,
403
456
  commandBody,
404
457
  config: cfg,
458
+ from,
459
+ to,
460
+ accountId,
461
+ messageThreadId: resolvedThreadId,
405
462
  });
406
463
  const tableMode = resolveMarkdownTableMode({
407
464
  cfg,
@@ -17,9 +17,8 @@ import { enqueueSystemEvent } from "../infra/system-events.js";
17
17
  import { getChildLogger } from "../logging.js";
18
18
  import { withTelegramApiErrorLogging } from "./api-logging.js";
19
19
  import { resolveAgentRoute } from "../routing/resolve-route.js";
20
- import { resolveThreadSessionKeys } from "../routing/session-key.js";
21
20
  import { resolveTelegramAccount } from "./accounts.js";
22
- import { buildTelegramGroupPeerId, resolveTelegramForumThreadId, resolveTelegramStreamMode, } from "./bot/helpers.js";
21
+ import { buildTelegramGroupPeerId, buildTelegramParentPeer, resolveTelegramForumThreadId, resolveTelegramStreamMode, } from "./bot/helpers.js";
23
22
  import { registerTelegramHandlers } from "./bot-handlers.js";
24
23
  import { createTelegramMessageProcessor } from "./bot-message.js";
25
24
  import { registerTelegramNativeCommands } from "./bot-native-commands.js";
@@ -45,11 +44,12 @@ export function getTelegramSequentialKey(ctx) {
45
44
  return `telegram:${chatId}:control`;
46
45
  return "telegram:control";
47
46
  }
47
+ const isGroup = msg?.chat?.type === "group" || msg?.chat?.type === "supergroup";
48
+ const messageThreadId = msg?.message_thread_id;
48
49
  const isForum = msg?.chat?.is_forum;
49
- const threadId = resolveTelegramForumThreadId({
50
- isForum,
51
- messageThreadId: msg?.message_thread_id,
52
- });
50
+ const threadId = isGroup
51
+ ? resolveTelegramForumThreadId({ isForum, messageThreadId })
52
+ : messageThreadId;
53
53
  if (typeof chatId === "number") {
54
54
  return threadId != null ? `telegram:${chatId}:topic:${threadId}` : `telegram:${chatId}`;
55
55
  }
@@ -73,14 +73,15 @@ export function createTelegramBot(opts) {
73
73
  network: telegramCfg.network,
74
74
  });
75
75
  const shouldProvideFetch = Boolean(fetchImpl);
76
+ // grammY's ApiClientOptions types still track `node-fetch` types; Node 22+ global fetch
77
+ // (undici) is structurally compatible at runtime but not assignable in TS.
78
+ const fetchForClient = fetchImpl;
76
79
  const timeoutSeconds = typeof telegramCfg?.timeoutSeconds === "number" && Number.isFinite(telegramCfg.timeoutSeconds)
77
80
  ? Math.max(1, Math.floor(telegramCfg.timeoutSeconds))
78
81
  : undefined;
79
82
  const client = shouldProvideFetch || timeoutSeconds
80
83
  ? {
81
- ...(shouldProvideFetch && fetchImpl
82
- ? { fetch: fetchImpl }
83
- : {}),
84
+ ...(shouldProvideFetch && fetchImpl ? { fetch: fetchForClient } : {}),
84
85
  ...(timeoutSeconds ? { timeoutSeconds } : {}),
85
86
  }
86
87
  : undefined;
@@ -193,19 +194,22 @@ export function createTelegramBot(opts) {
193
194
  const logger = getChildLogger({ module: "telegram-auto-reply" });
194
195
  let botHasTopicsEnabled;
195
196
  const resolveBotTopicsEnabled = async (ctx) => {
196
- const fromCtx = ctx?.me;
197
- if (typeof fromCtx?.has_topics_enabled === "boolean") {
198
- botHasTopicsEnabled = fromCtx.has_topics_enabled;
197
+ if (typeof ctx?.me?.has_topics_enabled === "boolean") {
198
+ botHasTopicsEnabled = ctx.me.has_topics_enabled;
199
199
  return botHasTopicsEnabled;
200
200
  }
201
201
  if (typeof botHasTopicsEnabled === "boolean")
202
202
  return botHasTopicsEnabled;
203
+ if (typeof bot.api.getMe !== "function") {
204
+ botHasTopicsEnabled = false;
205
+ return botHasTopicsEnabled;
206
+ }
203
207
  try {
204
- const me = (await withTelegramApiErrorLogging({
208
+ const me = await withTelegramApiErrorLogging({
205
209
  operation: "getMe",
206
210
  runtime,
207
211
  fn: () => bot.api.getMe(),
208
- }));
212
+ });
209
213
  botHasTopicsEnabled = Boolean(me?.has_topics_enabled);
210
214
  }
211
215
  catch (err) {
@@ -340,28 +344,25 @@ export function createTelegramBot(opts) {
340
344
  senderLabel = `id:${user.id}`;
341
345
  }
342
346
  senderLabel = senderLabel || "unknown";
343
- // Extract forum thread info (similar to message processing)
344
- const messageThreadId = reaction.message_thread_id;
345
- const isForum = reaction.chat.is_forum === true;
346
- const resolvedThreadId = resolveTelegramForumThreadId({
347
- isForum,
348
- messageThreadId,
349
- });
350
- // Resolve agent route for session
347
+ // Reactions target a specific message_id; the Telegram Bot API does not include
348
+ // message_thread_id on MessageReactionUpdated, so we route to the chat-level
349
+ // session (forum topic routing is not available for reactions).
351
350
  const isGroup = reaction.chat.type === "group" || reaction.chat.type === "supergroup";
351
+ const isForum = reaction.chat.is_forum === true;
352
+ const resolvedThreadId = isForum
353
+ ? resolveTelegramForumThreadId({ isForum, messageThreadId: undefined })
354
+ : undefined;
352
355
  const peerId = isGroup ? buildTelegramGroupPeerId(chatId, resolvedThreadId) : String(chatId);
356
+ const parentPeer = buildTelegramParentPeer({ isGroup, resolvedThreadId, chatId });
357
+ // Fresh config for bindings lookup; other routing inputs are payload-derived.
353
358
  const route = resolveAgentRoute({
354
- cfg,
359
+ cfg: loadConfig(),
355
360
  channel: "telegram",
356
361
  accountId: account.accountId,
357
362
  peer: { kind: isGroup ? "group" : "dm", id: peerId },
363
+ parentPeer,
358
364
  });
359
- const baseSessionKey = route.sessionKey;
360
- const dmThreadId = !isGroup ? resolvedThreadId : undefined;
361
- const threadKeys = dmThreadId != null
362
- ? resolveThreadSessionKeys({ baseSessionKey, threadId: String(dmThreadId) })
363
- : null;
364
- const sessionKey = threadKeys?.sessionKey ?? baseSessionKey;
365
+ const sessionKey = route.sessionKey;
365
366
  // Enqueue system event for each added reaction
366
367
  for (const r of addedReactions) {
367
368
  const emoji = r.emoji;