@poolzin/pool-bot 2026.2.21 → 2026.2.22

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 (369) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/agents/api-key-rotation.js +47 -0
  3. package/dist/agents/apply-patch-update.js +19 -9
  4. package/dist/agents/apply-patch.js +72 -47
  5. package/dist/agents/bash-tools.exec.js +141 -559
  6. package/dist/agents/cli-backends.js +49 -6
  7. package/dist/agents/cli-runner/helpers.js +69 -152
  8. package/dist/agents/cli-runner.js +70 -19
  9. package/dist/agents/identity.js +20 -1
  10. package/dist/agents/image-sanitization.js +9 -0
  11. package/dist/agents/live-auth-keys.js +123 -26
  12. package/dist/agents/live-model-filter.js +13 -4
  13. package/dist/agents/model-catalog.js +40 -9
  14. package/dist/agents/model-forward-compat.js +60 -23
  15. package/dist/agents/model-selection.js +134 -41
  16. package/dist/agents/pi-auth-json.js +2 -2
  17. package/dist/agents/pi-embedded-helpers/bootstrap.js +65 -15
  18. package/dist/agents/pi-embedded-helpers/errors.js +140 -15
  19. package/dist/agents/pi-embedded-helpers/images.js +22 -12
  20. package/dist/agents/pi-embedded-helpers.js +2 -2
  21. package/dist/agents/pi-embedded-runner/abort.js +10 -3
  22. package/dist/agents/pi-embedded-runner/compact.js +230 -32
  23. package/dist/agents/pi-embedded-runner/extra-params.js +203 -12
  24. package/dist/agents/pi-embedded-runner/google.js +109 -19
  25. package/dist/agents/pi-embedded-runner/history.js +35 -17
  26. package/dist/agents/pi-embedded-runner/run/attempt.js +386 -95
  27. package/dist/agents/pi-embedded-runner/run/images.js +81 -55
  28. package/dist/agents/pi-embedded-runner/run/payloads.js +89 -39
  29. package/dist/agents/pi-embedded-runner/run.js +193 -25
  30. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +2 -2
  31. package/dist/agents/pi-embedded-runner/runs.js +17 -8
  32. package/dist/agents/pi-embedded-runner/tool-result-context-guard.js +262 -0
  33. package/dist/agents/pi-embedded-runner.js +1 -1
  34. package/dist/agents/pi-embedded-subscribe.handlers.tools.js +180 -10
  35. package/dist/agents/pi-embedded-subscribe.js +37 -0
  36. package/dist/agents/pi-embedded-subscribe.tools.js +127 -30
  37. package/dist/agents/pi-model-discovery.js +9 -2
  38. package/dist/agents/pi-tool-definition-adapter.js +60 -8
  39. package/dist/agents/pi-tools.before-tool-call.js +1 -1
  40. package/dist/agents/pi-tools.js +113 -94
  41. package/dist/agents/pi-tools.read.js +337 -38
  42. package/dist/agents/poolbot-tools.js +14 -5
  43. package/dist/agents/sandbox/docker.js +10 -5
  44. package/dist/agents/sandbox/registry.js +96 -46
  45. package/dist/agents/sandbox/sanitize-env-vars.js +82 -0
  46. package/dist/agents/sandbox-paths.js +43 -10
  47. package/dist/agents/session-tool-result-guard-wrapper.js +23 -11
  48. package/dist/agents/session-tool-result-guard.js +39 -39
  49. package/dist/agents/session-transcript-repair.js +36 -33
  50. package/dist/agents/session-write-lock.js +62 -44
  51. package/dist/agents/skills/frontmatter.js +49 -88
  52. package/dist/agents/skills/workspace.js +335 -28
  53. package/dist/agents/subagent-announce.js +508 -174
  54. package/dist/agents/subagent-registry.js +45 -4
  55. package/dist/agents/subagent-spawn.js +16 -33
  56. package/dist/agents/system-prompt-report.js +27 -10
  57. package/dist/agents/system-prompt.js +26 -32
  58. package/dist/agents/tool-call-id.js +69 -17
  59. package/dist/agents/tool-display-common.js +1 -1
  60. package/dist/agents/tool-images.js +64 -31
  61. package/dist/agents/tools/canvas-tool.js +17 -11
  62. package/dist/agents/tools/common.js +37 -19
  63. package/dist/agents/tools/cron-tool.js +40 -38
  64. package/dist/agents/tools/gateway.js +70 -2
  65. package/dist/agents/tools/message-tool.js +181 -40
  66. package/dist/agents/tools/nodes-tool.js +128 -36
  67. package/dist/agents/tools/nodes-utils.js +12 -38
  68. package/dist/agents/tools/session-status-tool.js +24 -71
  69. package/dist/agents/tools/sessions-helpers.js +38 -210
  70. package/dist/agents/tools/sessions-spawn-tool.js +28 -198
  71. package/dist/agents/tools/telegram-actions.js +58 -7
  72. package/dist/agents/tools/web-fetch-utils.js +112 -7
  73. package/dist/agents/tools/web-fetch.js +279 -175
  74. package/dist/agents/tools/web-shared.js +71 -8
  75. package/dist/agents/usage.js +25 -16
  76. package/dist/auto-reply/commands-registry.data.js +85 -11
  77. package/dist/auto-reply/dispatch.js +40 -21
  78. package/dist/auto-reply/reply/abort.js +102 -33
  79. package/dist/auto-reply/reply/commands-core.js +82 -33
  80. package/dist/auto-reply/reply/commands-export-session.js +1 -1
  81. package/dist/auto-reply/reply/commands-info.js +41 -12
  82. package/dist/auto-reply/reply/commands-subagents.js +352 -100
  83. package/dist/auto-reply/reply/commands-system-prompt.js +2 -2
  84. package/dist/auto-reply/reply/dispatch-from-config.js +100 -29
  85. package/dist/auto-reply/reply/elevated-unavailable.js +1 -1
  86. package/dist/auto-reply/reply/inbound-meta.js +12 -1
  87. package/dist/auto-reply/reply/mentions.js +18 -11
  88. package/dist/auto-reply/reply/normalize-reply.js +17 -8
  89. package/dist/auto-reply/reply/reply-dispatcher.js +62 -10
  90. package/dist/auto-reply/reply/session.js +102 -21
  91. package/dist/auto-reply/reply/streaming-directives.js +16 -5
  92. package/dist/auto-reply/status.js +73 -50
  93. package/dist/browser/extension-relay.js +3 -3
  94. package/dist/browser/http-auth.js +1 -1
  95. package/dist/browser/paths.js +2 -2
  96. package/dist/build-info.json +3 -3
  97. package/dist/channels/allowlist-match.js +20 -0
  98. package/dist/channels/allowlists/resolve-utils.js +65 -2
  99. package/dist/channels/chat-type.js +8 -4
  100. package/dist/channels/dock.js +127 -35
  101. package/dist/channels/draft-stream-loop.js +6 -2
  102. package/dist/channels/plugins/actions/telegram.js +42 -18
  103. package/dist/channels/plugins/allowlist-match.js +1 -1
  104. package/dist/channels/plugins/group-mentions.js +51 -41
  105. package/dist/channels/plugins/message-action-names.js +2 -0
  106. package/dist/channels/plugins/message-actions.js +24 -5
  107. package/dist/channels/plugins/normalize/discord.js +26 -4
  108. package/dist/channels/plugins/normalize/signal.js +35 -22
  109. package/dist/channels/plugins/onboarding/helpers.js +8 -26
  110. package/dist/channels/plugins/outbound/imessage.js +15 -14
  111. package/dist/channels/registry.js +20 -7
  112. package/dist/cli/acp-cli.js +7 -5
  113. package/dist/cli/browser-cli-extension.js +25 -12
  114. package/dist/cli/browser-cli-state.cookies-storage.js +25 -6
  115. package/dist/cli/browser-cli-state.js +101 -145
  116. package/dist/cli/command-options.js +28 -0
  117. package/dist/cli/completion-cli.js +6 -6
  118. package/dist/cli/cron-cli/register.cron-add.js +25 -1
  119. package/dist/cli/cron-cli/register.cron-edit.js +44 -0
  120. package/dist/cli/cron-cli/shared.js +7 -1
  121. package/dist/cli/daemon-cli/lifecycle-core.js +23 -21
  122. package/dist/cli/daemon-cli/lifecycle.js +23 -247
  123. package/dist/cli/daemon-cli/register-service-commands.js +25 -4
  124. package/dist/cli/daemon-cli.js +1 -0
  125. package/dist/cli/devices-cli.js +33 -20
  126. package/dist/cli/gateway-cli/register.js +37 -105
  127. package/dist/cli/gateway-cli/run.js +49 -11
  128. package/dist/cli/nodes-camera.js +59 -4
  129. package/dist/cli/nodes-cli/register.camera.js +27 -24
  130. package/dist/cli/nodes-cli/rpc.js +21 -38
  131. package/dist/cli/qr-cli.js +2 -2
  132. package/dist/cli/skills-cli.format.js +2 -2
  133. package/dist/cli/update-cli/progress.js +2 -2
  134. package/dist/cli/update-cli/restart-helper.js +28 -7
  135. package/dist/cli/update-cli/shared.js +7 -7
  136. package/dist/cli/update-cli/status.js +1 -1
  137. package/dist/cli/update-cli/update-command.js +14 -8
  138. package/dist/cli/update-cli/wizard.js +2 -2
  139. package/dist/cli/update-cli.js +21 -1027
  140. package/dist/commands/auth-choice.apply.anthropic.js +10 -2
  141. package/dist/commands/channels/add-mutators.js +3 -35
  142. package/dist/commands/channels/add.js +39 -51
  143. package/dist/commands/config-validation.js +1 -1
  144. package/dist/commands/configure.gateway-auth.js +52 -15
  145. package/dist/commands/configure.gateway.js +84 -40
  146. package/dist/commands/doctor-completion.js +3 -3
  147. package/dist/commands/doctor-config-flow.js +536 -16
  148. package/dist/commands/doctor-gateway-services.js +103 -79
  149. package/dist/commands/doctor-memory-search.js +9 -9
  150. package/dist/commands/doctor-platform-notes.js +57 -30
  151. package/dist/commands/doctor-prompter.js +26 -15
  152. package/dist/commands/doctor-session-locks.js +1 -1
  153. package/dist/commands/doctor.js +21 -9
  154. package/dist/commands/model-picker.js +120 -95
  155. package/dist/commands/models/set.js +2 -21
  156. package/dist/commands/models/shared.js +65 -37
  157. package/dist/commands/onboard-helpers.js +81 -39
  158. package/dist/commands/openai-codex-oauth.js +1 -1
  159. package/dist/commands/sessions.js +52 -53
  160. package/dist/commands/status.summary.js +52 -34
  161. package/dist/commands/test-wizard-helpers.js +2 -2
  162. package/dist/config/defaults.js +79 -42
  163. package/dist/config/group-policy.js +50 -18
  164. package/dist/config/includes.js +37 -10
  165. package/dist/config/schema.help.js +5 -4
  166. package/dist/config/schema.hints.js +2 -2
  167. package/dist/config/schema.labels.js +1 -0
  168. package/dist/config/sessions/group.js +12 -11
  169. package/dist/config/sessions/paths.js +137 -11
  170. package/dist/config/sessions/store.js +185 -65
  171. package/dist/config/sessions/types.js +15 -1
  172. package/dist/config/sessions.js +1 -0
  173. package/dist/config/telegram-custom-commands.js +3 -2
  174. package/dist/config/types.js +2 -0
  175. package/dist/config/zod-schema.agent-defaults.js +6 -27
  176. package/dist/config/zod-schema.agent-runtime.js +171 -79
  177. package/dist/config/zod-schema.providers-core.js +138 -65
  178. package/dist/config/zod-schema.session.js +49 -22
  179. package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
  180. package/dist/cron/isolated-agent/run.js +224 -57
  181. package/dist/cron/normalize.js +48 -45
  182. package/dist/cron/run-log.js +14 -0
  183. package/dist/cron/service/jobs.js +190 -28
  184. package/dist/cron/service/normalize.js +29 -11
  185. package/dist/cron/service/store.js +30 -44
  186. package/dist/cron/service/timer.js +182 -96
  187. package/dist/cron/service.js +3 -0
  188. package/dist/cron/stagger.js +37 -0
  189. package/dist/daemon/inspect.js +132 -92
  190. package/dist/daemon/runtime-paths.js +25 -4
  191. package/dist/daemon/service-audit.js +47 -16
  192. package/dist/discord/accounts.js +23 -20
  193. package/dist/discord/monitor/agent-components.js +1115 -219
  194. package/dist/discord/monitor/allow-list.js +114 -34
  195. package/dist/discord/monitor/listeners.js +204 -97
  196. package/dist/discord/monitor/message-handler.js +21 -10
  197. package/dist/discord/monitor/message-handler.preflight.js +195 -101
  198. package/dist/discord/monitor/message-handler.process.js +384 -123
  199. package/dist/discord/monitor/message-utils.js +86 -23
  200. package/dist/discord/monitor/native-command.js +77 -57
  201. package/dist/discord/monitor/provider.js +122 -117
  202. package/dist/discord/monitor/reply-context.js +20 -16
  203. package/dist/discord/monitor/reply-delivery.js +40 -8
  204. package/dist/discord/monitor/rest-fetch.js +22 -0
  205. package/dist/discord/monitor/threading.js +117 -24
  206. package/dist/discord/send.js +2 -1
  207. package/dist/discord/send.outbound.js +124 -11
  208. package/dist/discord/send.shared.js +112 -72
  209. package/dist/discord/voice-message.js +3 -3
  210. package/dist/gateway/auth.js +119 -44
  211. package/dist/gateway/call.js +76 -34
  212. package/dist/gateway/channel-health-monitor.js +57 -50
  213. package/dist/gateway/client.js +63 -29
  214. package/dist/gateway/control-ui-contract.js +1 -1
  215. package/dist/gateway/gateway-config-prompts.shared.js +2 -2
  216. package/dist/gateway/net.js +109 -1
  217. package/dist/gateway/protocol/index.js +5 -8
  218. package/dist/gateway/protocol/schema/agent.js +19 -1
  219. package/dist/gateway/protocol/schema/channels.js +21 -0
  220. package/dist/gateway/protocol/schema/cron.js +43 -30
  221. package/dist/gateway/protocol/schema/protocol-schemas.js +6 -11
  222. package/dist/gateway/protocol/schema/sessions.js +5 -1
  223. package/dist/gateway/protocol/schema.js +0 -1
  224. package/dist/gateway/server/presence-events.js +12 -0
  225. package/dist/gateway/server/ws-connection/message-handler.js +203 -212
  226. package/dist/gateway/server/ws-connection.js +58 -21
  227. package/dist/gateway/server-broadcast.js +18 -13
  228. package/dist/gateway/server-cron.js +177 -10
  229. package/dist/gateway/server-methods/agent-job.js +131 -38
  230. package/dist/gateway/server-methods/send.js +60 -14
  231. package/dist/gateway/server-methods/sessions.js +160 -96
  232. package/dist/gateway/server-methods/system.js +5 -7
  233. package/dist/gateway/server-methods-list.js +8 -0
  234. package/dist/gateway/server-methods.js +24 -8
  235. package/dist/gateway/server-node-events.js +278 -68
  236. package/dist/gateway/session-utils.fs.js +316 -75
  237. package/dist/gateway/session-utils.js +224 -70
  238. package/dist/gateway/sessions-patch.js +63 -20
  239. package/dist/gateway/test-temp-config.js +1 -1
  240. package/dist/gateway/tools-invoke-http.js +118 -70
  241. package/dist/gateway/ws-log.js +135 -107
  242. package/dist/hooks/frontmatter.js +36 -82
  243. package/dist/hooks/install.js +149 -139
  244. package/dist/hooks/internal-hooks.js +29 -4
  245. package/dist/hooks/plugin-hooks.js +2 -1
  246. package/dist/imessage/monitor/deliver.js +10 -4
  247. package/dist/imessage/monitor/monitor-provider.js +138 -375
  248. package/dist/imessage/monitor/runtime.js +4 -8
  249. package/dist/imessage/send.js +65 -19
  250. package/dist/infra/exec-approvals-allowlist.js +7 -0
  251. package/dist/infra/exec-approvals.js +35 -920
  252. package/dist/infra/exec-safe-bin-trust.js +64 -0
  253. package/dist/infra/heartbeat-runner.js +207 -134
  254. package/dist/infra/heartbeat-wake.js +183 -22
  255. package/dist/infra/install-source-utils.js +47 -0
  256. package/dist/infra/net/ssrf.js +170 -36
  257. package/dist/infra/outbound/deliver.js +224 -58
  258. package/dist/infra/outbound/message-action-spec.js +12 -5
  259. package/dist/infra/outbound/outbound-session.js +27 -25
  260. package/dist/infra/poolbot-root.js +32 -22
  261. package/dist/infra/ports.js +14 -11
  262. package/dist/infra/skills-remote.js +48 -37
  263. package/dist/infra/system-events.js +25 -11
  264. package/dist/infra/system-presence.js +26 -33
  265. package/dist/infra/tmp-poolbot-dir.js +81 -2
  266. package/dist/infra/wsl.js +37 -1
  267. package/dist/line/bot-message-context.js +163 -191
  268. package/dist/logging/subsystem.js +59 -22
  269. package/dist/markdown/ir.js +124 -50
  270. package/dist/media/store.js +1 -1
  271. package/dist/media-understanding/runner.entries.js +42 -25
  272. package/dist/media-understanding/runner.js +53 -488
  273. package/dist/memory/embeddings-gemini.js +53 -38
  274. package/dist/memory/manager-embedding-ops.js +48 -69
  275. package/dist/pairing/pairing-store.js +178 -119
  276. package/dist/plugin-sdk/index.js +34 -6
  277. package/dist/plugins/hooks.js +135 -14
  278. package/dist/plugins/install.js +190 -152
  279. package/dist/polls.js +11 -0
  280. package/dist/routing/resolve-route.js +190 -56
  281. package/dist/routing/session-key.js +38 -22
  282. package/dist/runtime.js +35 -9
  283. package/dist/security/audit-channel.js +1 -1
  284. package/dist/sessions/session-key-utils.js +29 -11
  285. package/dist/shared/frontmatter.js +5 -5
  286. package/dist/shared/node-list-types.js +1 -0
  287. package/dist/shared/string-normalization.js +15 -0
  288. package/dist/signal/monitor/event-handler.js +68 -36
  289. package/dist/signal/send.js +29 -37
  290. package/dist/slack/monitor/allow-list.js +10 -11
  291. package/dist/slack/monitor/commands.js +14 -3
  292. package/dist/slack/monitor/events/interactions.js +4 -4
  293. package/dist/slack/monitor/media.js +224 -16
  294. package/dist/slack/monitor/message-handler/dispatch.js +247 -13
  295. package/dist/slack/monitor/message-handler/prepare.js +128 -45
  296. package/dist/slack/monitor/slash.js +357 -144
  297. package/dist/slack/streaming.js +77 -0
  298. package/dist/telegram/accounts.js +40 -13
  299. package/dist/telegram/allowed-updates.js +3 -0
  300. package/dist/telegram/bot/delivery.js +129 -66
  301. package/dist/telegram/bot/helpers.js +136 -122
  302. package/dist/telegram/bot-handlers.js +600 -339
  303. package/dist/telegram/bot-message-context.js +115 -73
  304. package/dist/telegram/bot-message-dispatch.js +235 -104
  305. package/dist/telegram/bot-native-command-menu.js +3 -1
  306. package/dist/telegram/bot-native-commands.js +213 -193
  307. package/dist/telegram/bot.js +24 -132
  308. package/dist/telegram/draft-stream.js +84 -75
  309. package/dist/telegram/format.js +150 -6
  310. package/dist/telegram/send.js +415 -255
  311. package/dist/telegram/targets.js +21 -2
  312. package/dist/telegram/update-offset-store.js +19 -3
  313. package/dist/terminal/restore.js +5 -2
  314. package/dist/test-utils/fetch-mock.js +5 -0
  315. package/dist/version.js +18 -5
  316. package/dist/web/auto-reply/monitor/broadcast.js +7 -3
  317. package/dist/web/auto-reply/monitor/on-message.js +6 -3
  318. package/dist/web/inbound/media.js +34 -8
  319. package/dist/web/inbound/monitor.js +34 -17
  320. package/dist/web/inbound/send-api.js +18 -17
  321. package/dist/web/outbound.js +12 -5
  322. package/dist/wizard/clack-prompter.js +40 -7
  323. package/extensions/bluebubbles/package.json +1 -1
  324. package/extensions/copilot-proxy/package.json +1 -1
  325. package/extensions/diagnostics-otel/package.json +1 -1
  326. package/extensions/discord/package.json +1 -1
  327. package/extensions/feishu/package.json +1 -1
  328. package/extensions/google-antigravity-auth/package.json +1 -1
  329. package/extensions/google-gemini-cli-auth/package.json +1 -1
  330. package/extensions/googlechat/package.json +1 -1
  331. package/extensions/imessage/package.json +1 -1
  332. package/extensions/irc/package.json +1 -1
  333. package/extensions/line/package.json +1 -1
  334. package/extensions/llm-task/package.json +1 -1
  335. package/extensions/lobster/package.json +1 -1
  336. package/extensions/matrix/CHANGELOG.md +5 -0
  337. package/extensions/matrix/package.json +1 -1
  338. package/extensions/mattermost/package.json +1 -1
  339. package/extensions/memory-core/package.json +1 -1
  340. package/extensions/memory-lancedb/package.json +1 -1
  341. package/extensions/minimax-portal-auth/package.json +1 -1
  342. package/extensions/msteams/CHANGELOG.md +5 -0
  343. package/extensions/msteams/package.json +1 -1
  344. package/extensions/nextcloud-talk/package.json +1 -1
  345. package/extensions/nostr/CHANGELOG.md +5 -0
  346. package/extensions/nostr/package.json +1 -1
  347. package/extensions/open-prose/package.json +1 -1
  348. package/extensions/openai-codex-auth/package.json +1 -1
  349. package/extensions/signal/package.json +1 -1
  350. package/extensions/slack/package.json +1 -1
  351. package/extensions/telegram/package.json +1 -1
  352. package/extensions/tlon/package.json +1 -1
  353. package/extensions/twitch/CHANGELOG.md +5 -0
  354. package/extensions/twitch/package.json +1 -1
  355. package/extensions/voice-call/CHANGELOG.md +5 -0
  356. package/extensions/voice-call/package.json +1 -1
  357. package/extensions/whatsapp/package.json +1 -1
  358. package/extensions/zalo/CHANGELOG.md +5 -0
  359. package/extensions/zalo/package.json +1 -1
  360. package/extensions/zalouser/CHANGELOG.md +5 -0
  361. package/extensions/zalouser/package.json +1 -1
  362. package/package.json +1 -1
  363. package/skills/apple-reminders/SKILL.md +100 -49
  364. package/skills/coding-agent/SKILL.md +34 -28
  365. package/skills/github/SKILL.md +131 -16
  366. package/skills/imsg/SKILL.md +112 -15
  367. package/skills/openhue/SKILL.md +101 -19
  368. package/skills/tmux/SKILL.md +111 -79
  369. package/skills/weather/SKILL.md +88 -25
@@ -1,17 +1,7 @@
1
- import crypto from "node:crypto";
2
1
  import { Type } from "@sinclair/typebox";
3
- import { formatThinkingLevels, normalizeThinkLevel } from "../../auto-reply/thinking.js";
4
- import { loadConfig } from "../../config/config.js";
5
- import { callGateway } from "../../gateway/call.js";
6
- import { isSubagentSessionKey, normalizeAgentId, parseAgentSessionKey, } from "../../routing/session-key.js";
7
- import { normalizeDeliveryContext } from "../../utils/delivery-context.js";
8
- import { resolveAgentConfig } from "../agent-scope.js";
9
- import { AGENT_LANE_SUBAGENT } from "../lanes.js";
10
2
  import { optionalStringEnum } from "../schema/typebox.js";
11
- import { buildSubagentSystemPrompt } from "../subagent-announce.js";
12
- import { registerSubagentRun } from "../subagent-registry.js";
3
+ import { spawnSubagentDirect } from "../subagent-spawn.js";
13
4
  import { jsonResult, readStringParam } from "./common.js";
14
- import { resolveDisplaySessionKey, resolveInternalSessionKey, resolveMainSessionAlias, } from "./sessions-helpers.js";
15
5
  const SessionsSpawnToolSchema = Type.Object({
16
6
  task: Type.String(),
17
7
  label: Type.Optional(Type.String()),
@@ -19,33 +9,10 @@ const SessionsSpawnToolSchema = Type.Object({
19
9
  model: Type.Optional(Type.String()),
20
10
  thinking: Type.Optional(Type.String()),
21
11
  runTimeoutSeconds: Type.Optional(Type.Number({ minimum: 0 })),
22
- // Back-compat alias. Prefer runTimeoutSeconds.
12
+ // Back-compat: older callers used timeoutSeconds for this tool.
23
13
  timeoutSeconds: Type.Optional(Type.Number({ minimum: 0 })),
24
14
  cleanup: optionalStringEnum(["delete", "keep"]),
25
15
  });
26
- function splitModelRef(ref) {
27
- if (!ref)
28
- return { provider: undefined, model: undefined };
29
- const trimmed = ref.trim();
30
- if (!trimmed)
31
- return { provider: undefined, model: undefined };
32
- const [provider, model] = trimmed.split("/", 2);
33
- if (model)
34
- return { provider, model };
35
- return { provider: undefined, model: trimmed };
36
- }
37
- function normalizeModelSelection(value) {
38
- if (typeof value === "string") {
39
- const trimmed = value.trim();
40
- return trimmed || undefined;
41
- }
42
- if (!value || typeof value !== "object")
43
- return undefined;
44
- const primary = value.primary;
45
- if (typeof primary === "string" && primary.trim())
46
- return primary.trim();
47
- return undefined;
48
- }
49
16
  export function createSessionsSpawnTool(opts) {
50
17
  return {
51
18
  label: "Sessions",
@@ -59,174 +26,37 @@ export function createSessionsSpawnTool(opts) {
59
26
  const requestedAgentId = readStringParam(params, "agentId");
60
27
  const modelOverride = readStringParam(params, "model");
61
28
  const thinkingOverrideRaw = readStringParam(params, "thinking");
62
- const cleanup = params.cleanup === "keep" || params.cleanup === "delete"
63
- ? params.cleanup
64
- : "keep";
65
- const requesterOrigin = normalizeDeliveryContext({
66
- channel: opts?.agentChannel,
67
- accountId: opts?.agentAccountId,
68
- to: opts?.agentTo,
69
- threadId: opts?.agentThreadId,
70
- });
71
- const runTimeoutSeconds = (() => {
72
- const explicit = typeof params.runTimeoutSeconds === "number" && Number.isFinite(params.runTimeoutSeconds)
73
- ? Math.max(0, Math.floor(params.runTimeoutSeconds))
29
+ const cleanup = params.cleanup === "keep" || params.cleanup === "delete" ? params.cleanup : "keep";
30
+ // Back-compat: older callers used timeoutSeconds for this tool.
31
+ const timeoutSecondsCandidate = typeof params.runTimeoutSeconds === "number"
32
+ ? params.runTimeoutSeconds
33
+ : typeof params.timeoutSeconds === "number"
34
+ ? params.timeoutSeconds
74
35
  : undefined;
75
- if (explicit !== undefined)
76
- return explicit;
77
- const legacy = typeof params.timeoutSeconds === "number" && Number.isFinite(params.timeoutSeconds)
78
- ? Math.max(0, Math.floor(params.timeoutSeconds))
79
- : undefined;
80
- return legacy ?? 0;
81
- })();
82
- let modelWarning;
83
- let modelApplied = false;
84
- const cfg = loadConfig();
85
- const { mainKey, alias } = resolveMainSessionAlias(cfg);
86
- const requesterSessionKey = opts?.agentSessionKey;
87
- if (typeof requesterSessionKey === "string" && isSubagentSessionKey(requesterSessionKey)) {
88
- return jsonResult({
89
- status: "forbidden",
90
- error: "sessions_spawn is not allowed from sub-agent sessions",
91
- });
92
- }
93
- const requesterInternalKey = requesterSessionKey
94
- ? resolveInternalSessionKey({
95
- key: requesterSessionKey,
96
- alias,
97
- mainKey,
98
- })
99
- : alias;
100
- const requesterDisplayKey = resolveDisplaySessionKey({
101
- key: requesterInternalKey,
102
- alias,
103
- mainKey,
104
- });
105
- const requesterAgentId = normalizeAgentId(opts?.requesterAgentIdOverride ?? parseAgentSessionKey(requesterInternalKey)?.agentId);
106
- const targetAgentId = requestedAgentId
107
- ? normalizeAgentId(requestedAgentId)
108
- : requesterAgentId;
109
- if (targetAgentId !== requesterAgentId) {
110
- const allowAgents = resolveAgentConfig(cfg, requesterAgentId)?.subagents?.allowAgents ?? [];
111
- const allowAny = allowAgents.some((value) => value.trim() === "*");
112
- const normalizedTargetId = targetAgentId.toLowerCase();
113
- const allowSet = new Set(allowAgents
114
- .filter((value) => value.trim() && value.trim() !== "*")
115
- .map((value) => normalizeAgentId(value).toLowerCase()));
116
- if (!allowAny && !allowSet.has(normalizedTargetId)) {
117
- const allowedText = allowAny
118
- ? "*"
119
- : allowSet.size > 0
120
- ? Array.from(allowSet).join(", ")
121
- : "none";
122
- return jsonResult({
123
- status: "forbidden",
124
- error: `agentId is not allowed for sessions_spawn (allowed: ${allowedText})`,
125
- });
126
- }
127
- }
128
- const childSessionKey = `agent:${targetAgentId}:subagent:${crypto.randomUUID()}`;
129
- const spawnedByKey = requesterInternalKey;
130
- const targetAgentConfig = resolveAgentConfig(cfg, targetAgentId);
131
- const resolvedModel = normalizeModelSelection(modelOverride) ??
132
- normalizeModelSelection(targetAgentConfig?.subagents?.model) ??
133
- normalizeModelSelection(cfg.agents?.defaults?.subagents?.model);
134
- let thinkingOverride;
135
- if (thinkingOverrideRaw) {
136
- const normalized = normalizeThinkLevel(thinkingOverrideRaw);
137
- if (!normalized) {
138
- const { provider, model } = splitModelRef(resolvedModel);
139
- const hint = formatThinkingLevels(provider, model);
140
- return jsonResult({
141
- status: "error",
142
- error: `Invalid thinking level "${thinkingOverrideRaw}". Use one of: ${hint}.`,
143
- });
144
- }
145
- thinkingOverride = normalized;
146
- }
147
- if (resolvedModel) {
148
- try {
149
- await callGateway({
150
- method: "sessions.patch",
151
- params: { key: childSessionKey, model: resolvedModel },
152
- timeoutMs: 10_000,
153
- });
154
- modelApplied = true;
155
- }
156
- catch (err) {
157
- const messageText = err instanceof Error ? err.message : typeof err === "string" ? err : "error";
158
- const recoverable = messageText.includes("invalid model") || messageText.includes("model not allowed");
159
- if (!recoverable) {
160
- return jsonResult({
161
- status: "error",
162
- error: messageText,
163
- childSessionKey,
164
- });
165
- }
166
- modelWarning = messageText;
167
- }
168
- }
169
- const childSystemPrompt = buildSubagentSystemPrompt({
170
- requesterSessionKey,
171
- requesterOrigin,
172
- childSessionKey,
173
- label: label || undefined,
36
+ const runTimeoutSeconds = typeof timeoutSecondsCandidate === "number" && Number.isFinite(timeoutSecondsCandidate)
37
+ ? Math.max(0, Math.floor(timeoutSecondsCandidate))
38
+ : undefined;
39
+ const result = await spawnSubagentDirect({
174
40
  task,
175
- });
176
- const childIdem = crypto.randomUUID();
177
- let childRunId = childIdem;
178
- try {
179
- const response = (await callGateway({
180
- method: "agent",
181
- params: {
182
- message: task,
183
- sessionKey: childSessionKey,
184
- channel: requesterOrigin?.channel,
185
- idempotencyKey: childIdem,
186
- deliver: false,
187
- lane: AGENT_LANE_SUBAGENT,
188
- extraSystemPrompt: childSystemPrompt,
189
- thinking: thinkingOverride,
190
- timeout: runTimeoutSeconds > 0 ? runTimeoutSeconds : undefined,
191
- label: label || undefined,
192
- spawnedBy: spawnedByKey,
193
- groupId: opts?.agentGroupId ?? undefined,
194
- groupChannel: opts?.agentGroupChannel ?? undefined,
195
- groupSpace: opts?.agentGroupSpace ?? undefined,
196
- },
197
- timeoutMs: 10_000,
198
- }));
199
- if (typeof response?.runId === "string" && response.runId) {
200
- childRunId = response.runId;
201
- }
202
- }
203
- catch (err) {
204
- const messageText = err instanceof Error ? err.message : typeof err === "string" ? err : "error";
205
- return jsonResult({
206
- status: "error",
207
- error: messageText,
208
- childSessionKey,
209
- runId: childRunId,
210
- });
211
- }
212
- registerSubagentRun({
213
- runId: childRunId,
214
- childSessionKey,
215
- requesterSessionKey: requesterInternalKey,
216
- requesterOrigin,
217
- requesterDisplayKey,
218
- task,
219
- cleanup,
220
41
  label: label || undefined,
42
+ agentId: requestedAgentId,
43
+ model: modelOverride,
44
+ thinking: thinkingOverrideRaw,
221
45
  runTimeoutSeconds,
46
+ cleanup,
47
+ expectsCompletionMessage: true,
48
+ }, {
49
+ agentSessionKey: opts?.agentSessionKey,
50
+ agentChannel: opts?.agentChannel,
51
+ agentAccountId: opts?.agentAccountId,
52
+ agentTo: opts?.agentTo,
53
+ agentThreadId: opts?.agentThreadId,
54
+ agentGroupId: opts?.agentGroupId,
55
+ agentGroupChannel: opts?.agentGroupChannel,
56
+ agentGroupSpace: opts?.agentGroupSpace,
57
+ requesterAgentIdOverride: opts?.requesterAgentIdOverride,
222
58
  });
223
- return jsonResult({
224
- status: "accepted",
225
- childSessionKey,
226
- runId: childRunId,
227
- modelApplied: resolvedModel ? modelApplied : undefined,
228
- warning: modelWarning,
229
- });
59
+ return jsonResult(result);
230
60
  },
231
61
  };
232
62
  }
@@ -1,13 +1,16 @@
1
+ import { createTelegramActionGate } from "../../telegram/accounts.js";
2
+ import { resolveTelegramInlineButtonsScope, resolveTelegramTargetChatType, } from "../../telegram/inline-buttons.js";
1
3
  import { resolveTelegramReactionLevel } from "../../telegram/reaction-level.js";
2
- import { deleteMessageTelegram, editMessageTelegram, reactMessageTelegram, sendMessageTelegram, sendStickerTelegram, } from "../../telegram/send.js";
4
+ import { createForumTopicTelegram, deleteMessageTelegram, editMessageTelegram, reactMessageTelegram, sendMessageTelegram, sendStickerTelegram, } from "../../telegram/send.js";
3
5
  import { getCacheStats, searchStickers } from "../../telegram/sticker-cache.js";
4
6
  import { resolveTelegramToken } from "../../telegram/token.js";
5
- import { resolveTelegramInlineButtonsScope, resolveTelegramTargetChatType, } from "../../telegram/inline-buttons.js";
6
- import { createActionGate, jsonResult, readNumberParam, readReactionParams, readStringOrNumberParam, readStringParam, } from "./common.js";
7
+ import { jsonResult, readNumberParam, readReactionParams, readStringOrNumberParam, readStringParam, } from "./common.js";
8
+ const TELEGRAM_BUTTON_STYLES = ["danger", "success", "primary"];
7
9
  export function readTelegramButtons(params) {
8
10
  const raw = params.buttons;
9
- if (raw == null)
11
+ if (raw == null) {
10
12
  return undefined;
13
+ }
11
14
  if (!Array.isArray(raw)) {
12
15
  throw new Error("buttons must be an array of button rows");
13
16
  }
@@ -31,7 +34,19 @@ export function readTelegramButtons(params) {
31
34
  if (callbackData.length > 64) {
32
35
  throw new Error(`buttons[${rowIndex}][${buttonIndex}] callback_data too long (max 64 chars)`);
33
36
  }
34
- return { text, callback_data: callbackData };
37
+ const styleRaw = button.style;
38
+ const style = typeof styleRaw === "string" ? styleRaw.trim().toLowerCase() : undefined;
39
+ if (styleRaw !== undefined && !style) {
40
+ throw new Error(`buttons[${rowIndex}][${buttonIndex}] style must be string`);
41
+ }
42
+ if (style && !TELEGRAM_BUTTON_STYLES.includes(style)) {
43
+ throw new Error(`buttons[${rowIndex}][${buttonIndex}] style must be one of ${TELEGRAM_BUTTON_STYLES.join(", ")}`);
44
+ }
45
+ return {
46
+ text,
47
+ callback_data: callbackData,
48
+ ...(style ? { style: style } : {}),
49
+ };
35
50
  });
36
51
  });
37
52
  const filtered = rows.filter((row) => row.length > 0);
@@ -40,7 +55,7 @@ export function readTelegramButtons(params) {
40
55
  export async function handleTelegramAction(params, cfg) {
41
56
  const action = readStringParam(params, "action", { required: true });
42
57
  const accountId = readStringParam(params, "accountId");
43
- const isActionEnabled = createActionGate(cfg.channels?.telegram?.actions);
58
+ const isActionEnabled = createTelegramActionGate({ cfg, accountId });
44
59
  if (action === "react") {
45
60
  // Check reaction level first
46
61
  const reactionLevelInfo = resolveTelegramReactionLevel({
@@ -69,11 +84,18 @@ export async function handleTelegramAction(params, cfg) {
69
84
  if (!token) {
70
85
  throw new Error("Telegram bot token missing. Set TELEGRAM_BOT_TOKEN or channels.telegram.botToken.");
71
86
  }
72
- await reactMessageTelegram(chatId ?? "", messageId ?? 0, emoji ?? "", {
87
+ const reactionResult = await reactMessageTelegram(chatId ?? "", messageId ?? 0, emoji ?? "", {
73
88
  token,
74
89
  remove,
75
90
  accountId: accountId ?? undefined,
76
91
  });
92
+ if (!reactionResult.ok) {
93
+ return jsonResult({
94
+ ok: false,
95
+ warning: reactionResult.warning,
96
+ ...(remove || isEmpty ? { removed: true } : { added: emoji }),
97
+ });
98
+ }
77
99
  if (!remove && !isEmpty) {
78
100
  return jsonResult({ ok: true, added: emoji });
79
101
  }
@@ -119,6 +141,7 @@ export async function handleTelegramAction(params, cfg) {
119
141
  const messageThreadId = readNumberParam(params, "messageThreadId", {
120
142
  integer: true,
121
143
  });
144
+ const quoteText = readStringParam(params, "quoteText");
122
145
  const token = resolveTelegramToken(cfg, { accountId }).token;
123
146
  if (!token) {
124
147
  throw new Error("Telegram bot token missing. Set TELEGRAM_BOT_TOKEN or channels.telegram.botToken.");
@@ -130,6 +153,7 @@ export async function handleTelegramAction(params, cfg) {
130
153
  buttons,
131
154
  replyToMessageId: replyToMessageId ?? undefined,
132
155
  messageThreadId: messageThreadId ?? undefined,
156
+ quoteText: quoteText ?? undefined,
133
157
  asVoice: typeof params.asVoice === "boolean" ? params.asVoice : undefined,
134
158
  silent: typeof params.silent === "boolean" ? params.silent : undefined,
135
159
  });
@@ -250,5 +274,32 @@ export async function handleTelegramAction(params, cfg) {
250
274
  const stats = getCacheStats();
251
275
  return jsonResult({ ok: true, ...stats });
252
276
  }
277
+ if (action === "createForumTopic") {
278
+ if (!isActionEnabled("createForumTopic")) {
279
+ throw new Error("Telegram createForumTopic is disabled.");
280
+ }
281
+ const chatId = readStringOrNumberParam(params, "chatId", {
282
+ required: true,
283
+ });
284
+ const name = readStringParam(params, "name", { required: true });
285
+ const iconColor = readNumberParam(params, "iconColor", { integer: true });
286
+ const iconCustomEmojiId = readStringParam(params, "iconCustomEmojiId");
287
+ const token = resolveTelegramToken(cfg, { accountId }).token;
288
+ if (!token) {
289
+ throw new Error("Telegram bot token missing. Set TELEGRAM_BOT_TOKEN or channels.telegram.botToken.");
290
+ }
291
+ const result = await createForumTopicTelegram(chatId ?? "", name, {
292
+ token,
293
+ accountId: accountId ?? undefined,
294
+ iconColor: iconColor ?? undefined,
295
+ iconCustomEmojiId: iconCustomEmojiId ?? undefined,
296
+ });
297
+ return jsonResult({
298
+ ok: true,
299
+ topicId: result.topicId,
300
+ name: result.name,
301
+ chatId: result.chatId,
302
+ });
303
+ }
253
304
  throw new Error(`Unsupported Telegram action: ${action}`);
254
305
  }
@@ -1,3 +1,21 @@
1
+ const READABILITY_MAX_HTML_CHARS = 1_000_000;
2
+ const READABILITY_MAX_ESTIMATED_NESTING_DEPTH = 3_000;
3
+ let readabilityDepsPromise;
4
+ async function loadReadabilityDeps() {
5
+ if (!readabilityDepsPromise) {
6
+ readabilityDepsPromise = Promise.all([import("@mozilla/readability"), import("linkedom")]).then(([readability, linkedom]) => ({
7
+ Readability: readability.Readability,
8
+ parseHTML: linkedom.parseHTML,
9
+ }));
10
+ }
11
+ try {
12
+ return await readabilityDepsPromise;
13
+ }
14
+ catch (error) {
15
+ readabilityDepsPromise = undefined;
16
+ throw error;
17
+ }
18
+ }
1
19
  function decodeEntities(value) {
2
20
  return value
3
21
  .replace(/ /gi, " ")
@@ -29,8 +47,9 @@ export function htmlToMarkdown(html) {
29
47
  .replace(/<noscript[\s\S]*?<\/noscript>/gi, "");
30
48
  text = text.replace(/<a\s+[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, href, body) => {
31
49
  const label = normalizeWhitespace(stripTags(body));
32
- if (!label)
50
+ if (!label) {
33
51
  return href;
52
+ }
34
53
  return `[${label}](${href})`;
35
54
  });
36
55
  text = text.replace(/<h([1-6])[^>]*>([\s\S]*?)<\/h\1>/gi, (_, level, body) => {
@@ -61,10 +80,94 @@ export function markdownToText(markdown) {
61
80
  return normalizeWhitespace(text);
62
81
  }
63
82
  export function truncateText(value, maxChars) {
64
- if (value.length <= maxChars)
83
+ if (value.length <= maxChars) {
65
84
  return { text: value, truncated: false };
85
+ }
66
86
  return { text: value.slice(0, maxChars), truncated: true };
67
87
  }
88
+ function exceedsEstimatedHtmlNestingDepth(html, maxDepth) {
89
+ // Cheap heuristic to skip Readability+DOM parsing on pathological HTML (deep nesting => stack/memory blowups).
90
+ // Not an HTML parser; tuned to catch attacker-controlled "<div><div>..." cases.
91
+ const voidTags = new Set([
92
+ "area",
93
+ "base",
94
+ "br",
95
+ "col",
96
+ "embed",
97
+ "hr",
98
+ "img",
99
+ "input",
100
+ "link",
101
+ "meta",
102
+ "param",
103
+ "source",
104
+ "track",
105
+ "wbr",
106
+ ]);
107
+ let depth = 0;
108
+ const len = html.length;
109
+ for (let i = 0; i < len; i++) {
110
+ if (html.charCodeAt(i) !== 60) {
111
+ continue; // '<'
112
+ }
113
+ const next = html.charCodeAt(i + 1);
114
+ if (next === 33 || next === 63) {
115
+ continue; // <! ...> or <? ...>
116
+ }
117
+ let j = i + 1;
118
+ let closing = false;
119
+ if (html.charCodeAt(j) === 47) {
120
+ closing = true;
121
+ j += 1;
122
+ }
123
+ while (j < len && html.charCodeAt(j) <= 32) {
124
+ j += 1;
125
+ }
126
+ const nameStart = j;
127
+ while (j < len) {
128
+ const c = html.charCodeAt(j);
129
+ const isNameChar = (c >= 65 && c <= 90) || // A-Z
130
+ (c >= 97 && c <= 122) || // a-z
131
+ (c >= 48 && c <= 57) || // 0-9
132
+ c === 58 || // :
133
+ c === 45; // -
134
+ if (!isNameChar) {
135
+ break;
136
+ }
137
+ j += 1;
138
+ }
139
+ const tagName = html.slice(nameStart, j).toLowerCase();
140
+ if (!tagName) {
141
+ continue;
142
+ }
143
+ if (closing) {
144
+ depth = Math.max(0, depth - 1);
145
+ continue;
146
+ }
147
+ if (voidTags.has(tagName)) {
148
+ continue;
149
+ }
150
+ // Best-effort self-closing detection: scan a short window for "/>".
151
+ let selfClosing = false;
152
+ for (let k = j; k < len && k < j + 200; k++) {
153
+ const c = html.charCodeAt(k);
154
+ if (c === 62) {
155
+ if (html.charCodeAt(k - 1) === 47) {
156
+ selfClosing = true;
157
+ }
158
+ break;
159
+ }
160
+ }
161
+ if (selfClosing) {
162
+ continue;
163
+ }
164
+ depth += 1;
165
+ if (depth > maxDepth) {
166
+ return true;
167
+ }
168
+ }
169
+ return false;
170
+ }
68
171
  export async function extractReadableContent(params) {
69
172
  const fallback = () => {
70
173
  const rendered = htmlToMarkdown(params.html);
@@ -74,11 +177,12 @@ export async function extractReadableContent(params) {
74
177
  }
75
178
  return rendered;
76
179
  };
180
+ if (params.html.length > READABILITY_MAX_HTML_CHARS ||
181
+ exceedsEstimatedHtmlNestingDepth(params.html, READABILITY_MAX_ESTIMATED_NESTING_DEPTH)) {
182
+ return fallback();
183
+ }
77
184
  try {
78
- const [{ Readability }, { parseHTML }] = await Promise.all([
79
- import("@mozilla/readability"),
80
- import("linkedom"),
81
- ]);
185
+ const { Readability, parseHTML } = await loadReadabilityDeps();
82
186
  const { document } = parseHTML(params.html);
83
187
  try {
84
188
  document.baseURI = params.url;
@@ -88,8 +192,9 @@ export async function extractReadableContent(params) {
88
192
  }
89
193
  const reader = new Readability(document, { charThreshold: 0 });
90
194
  const parsed = reader.parse();
91
- if (!parsed?.content)
195
+ if (!parsed?.content) {
92
196
  return fallback();
197
+ }
93
198
  const title = parsed.title || undefined;
94
199
  if (params.extractMode === "text") {
95
200
  const text = normalizeWhitespace(parsed.textContent ?? "");