@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,58 +1,71 @@
1
1
  import { getChannelPlugin, normalizeChannelId } from "../channels/plugins/index.js";
2
- import { truncateUtf16Safe } from "../utils.js";
3
2
  import { normalizeTargetForProvider } from "../infra/outbound/target-normalization.js";
3
+ import { MEDIA_TOKEN_RE } from "../media/parse.js";
4
+ import { truncateUtf16Safe } from "../utils.js";
4
5
  const TOOL_RESULT_MAX_CHARS = 8000;
5
6
  const TOOL_ERROR_MAX_CHARS = 400;
6
7
  function truncateToolText(text) {
7
- if (text.length <= TOOL_RESULT_MAX_CHARS)
8
+ if (text.length <= TOOL_RESULT_MAX_CHARS) {
8
9
  return text;
10
+ }
9
11
  return `${truncateUtf16Safe(text, TOOL_RESULT_MAX_CHARS)}\n…(truncated)…`;
10
12
  }
11
13
  function normalizeToolErrorText(text) {
12
14
  const trimmed = text.trim();
13
- if (!trimmed)
15
+ if (!trimmed) {
14
16
  return undefined;
17
+ }
15
18
  const firstLine = trimmed.split(/\r?\n/)[0]?.trim() ?? "";
16
- if (!firstLine)
19
+ if (!firstLine) {
17
20
  return undefined;
21
+ }
18
22
  return firstLine.length > TOOL_ERROR_MAX_CHARS
19
23
  ? `${truncateUtf16Safe(firstLine, TOOL_ERROR_MAX_CHARS)}…`
20
24
  : firstLine;
21
25
  }
22
26
  function readErrorCandidate(value) {
23
- if (typeof value === "string")
27
+ if (typeof value === "string") {
24
28
  return normalizeToolErrorText(value);
25
- if (!value || typeof value !== "object")
29
+ }
30
+ if (!value || typeof value !== "object") {
26
31
  return undefined;
32
+ }
27
33
  const record = value;
28
- if (typeof record.message === "string")
34
+ if (typeof record.message === "string") {
29
35
  return normalizeToolErrorText(record.message);
30
- if (typeof record.error === "string")
36
+ }
37
+ if (typeof record.error === "string") {
31
38
  return normalizeToolErrorText(record.error);
39
+ }
32
40
  return undefined;
33
41
  }
34
42
  function extractErrorField(value) {
35
- if (!value || typeof value !== "object")
43
+ if (!value || typeof value !== "object") {
36
44
  return undefined;
45
+ }
37
46
  const record = value;
38
47
  const direct = readErrorCandidate(record.error) ??
39
48
  readErrorCandidate(record.message) ??
40
49
  readErrorCandidate(record.reason);
41
- if (direct)
50
+ if (direct) {
42
51
  return direct;
52
+ }
43
53
  const status = typeof record.status === "string" ? record.status.trim() : "";
44
54
  return status ? normalizeToolErrorText(status) : undefined;
45
55
  }
46
56
  export function sanitizeToolResult(result) {
47
- if (!result || typeof result !== "object")
57
+ if (!result || typeof result !== "object") {
48
58
  return result;
59
+ }
49
60
  const record = result;
50
61
  const content = Array.isArray(record.content) ? record.content : null;
51
- if (!content)
62
+ if (!content) {
52
63
  return record;
64
+ }
53
65
  const sanitized = content.map((item) => {
54
- if (!item || typeof item !== "object")
66
+ if (!item || typeof item !== "object") {
55
67
  return item;
68
+ }
56
69
  const entry = item;
57
70
  const type = typeof entry.type === "string" ? entry.type : undefined;
58
71
  if (type === "text" && typeof entry.text === "string") {
@@ -70,58 +83,138 @@ export function sanitizeToolResult(result) {
70
83
  return { ...record, content: sanitized };
71
84
  }
72
85
  export function extractToolResultText(result) {
73
- if (!result || typeof result !== "object")
86
+ if (!result || typeof result !== "object") {
74
87
  return undefined;
88
+ }
75
89
  const record = result;
76
90
  const content = Array.isArray(record.content) ? record.content : null;
77
- if (!content)
91
+ if (!content) {
78
92
  return undefined;
93
+ }
79
94
  const texts = content
80
95
  .map((item) => {
81
- if (!item || typeof item !== "object")
96
+ if (!item || typeof item !== "object") {
82
97
  return undefined;
98
+ }
83
99
  const entry = item;
84
- if (entry.type !== "text" || typeof entry.text !== "string")
100
+ if (entry.type !== "text" || typeof entry.text !== "string") {
85
101
  return undefined;
102
+ }
86
103
  const trimmed = entry.text.trim();
87
104
  return trimmed ? trimmed : undefined;
88
105
  })
89
106
  .filter((value) => Boolean(value));
90
- if (texts.length === 0)
107
+ if (texts.length === 0) {
91
108
  return undefined;
109
+ }
92
110
  return texts.join("\n");
93
111
  }
112
+ /**
113
+ * Extract media file paths from a tool result.
114
+ *
115
+ * Strategy (first match wins):
116
+ * 1. Parse `MEDIA:` tokens from text content blocks (all Pool Bot tools).
117
+ * 2. Fall back to `details.path` when image content exists (Pool Bot imageResult).
118
+ *
119
+ * Returns an empty array when no media is found (e.g. Pi SDK `read` tool
120
+ * returns base64 image data but no file path; those need a different delivery
121
+ * path like saving to a temp file).
122
+ */
123
+ export function extractToolResultMediaPaths(result) {
124
+ if (!result || typeof result !== "object") {
125
+ return [];
126
+ }
127
+ const record = result;
128
+ const content = Array.isArray(record.content) ? record.content : null;
129
+ if (!content) {
130
+ return [];
131
+ }
132
+ // Extract MEDIA: paths from text content blocks.
133
+ const paths = [];
134
+ let hasImageContent = false;
135
+ for (const item of content) {
136
+ if (!item || typeof item !== "object") {
137
+ continue;
138
+ }
139
+ const entry = item;
140
+ if (entry.type === "image") {
141
+ hasImageContent = true;
142
+ continue;
143
+ }
144
+ if (entry.type === "text" && typeof entry.text === "string") {
145
+ // Only parse lines that start with MEDIA: (after trimming) to avoid
146
+ // false-matching placeholders like <media:audio> or mid-line mentions.
147
+ // Mirrors the line-start guard in splitMediaFromOutput (media/parse.ts).
148
+ for (const line of entry.text.split("\n")) {
149
+ if (!line.trimStart().startsWith("MEDIA:")) {
150
+ continue;
151
+ }
152
+ MEDIA_TOKEN_RE.lastIndex = 0;
153
+ let match;
154
+ while ((match = MEDIA_TOKEN_RE.exec(line)) !== null) {
155
+ const p = match[1]
156
+ ?.replace(/^[`"'[{(]+/, "")
157
+ .replace(/[`"'\]})\\,]+$/, "")
158
+ .trim();
159
+ if (p && p.length <= 4096) {
160
+ paths.push(p);
161
+ }
162
+ }
163
+ }
164
+ }
165
+ }
166
+ if (paths.length > 0) {
167
+ return paths;
168
+ }
169
+ // Fall back to details.path when image content exists but no MEDIA: text.
170
+ if (hasImageContent) {
171
+ const details = record.details;
172
+ const p = typeof details?.path === "string" ? details.path.trim() : "";
173
+ if (p) {
174
+ return [p];
175
+ }
176
+ }
177
+ return [];
178
+ }
94
179
  export function isToolResultError(result) {
95
- if (!result || typeof result !== "object")
180
+ if (!result || typeof result !== "object") {
96
181
  return false;
182
+ }
97
183
  const record = result;
98
184
  const details = record.details;
99
- if (!details || typeof details !== "object")
185
+ if (!details || typeof details !== "object") {
100
186
  return false;
187
+ }
101
188
  const status = details.status;
102
- if (typeof status !== "string")
189
+ if (typeof status !== "string") {
103
190
  return false;
191
+ }
104
192
  const normalized = status.trim().toLowerCase();
105
193
  return normalized === "error" || normalized === "timeout";
106
194
  }
107
195
  export function extractToolErrorMessage(result) {
108
- if (!result || typeof result !== "object")
196
+ if (!result || typeof result !== "object") {
109
197
  return undefined;
198
+ }
110
199
  const record = result;
111
200
  const fromDetails = extractErrorField(record.details);
112
- if (fromDetails)
201
+ if (fromDetails) {
113
202
  return fromDetails;
203
+ }
114
204
  const fromRoot = extractErrorField(record);
115
- if (fromRoot)
205
+ if (fromRoot) {
116
206
  return fromRoot;
207
+ }
117
208
  const text = extractToolResultText(result);
118
- if (!text)
209
+ if (!text) {
119
210
  return undefined;
211
+ }
120
212
  try {
121
213
  const parsed = JSON.parse(text);
122
214
  const fromJson = extractErrorField(parsed);
123
- if (fromJson)
215
+ if (fromJson) {
124
216
  return fromJson;
217
+ }
125
218
  }
126
219
  catch {
127
220
  // Fall through to first-line text fallback.
@@ -134,11 +227,13 @@ export function extractMessagingToolSend(toolName, args) {
134
227
  const accountIdRaw = typeof args.accountId === "string" ? args.accountId.trim() : undefined;
135
228
  const accountId = accountIdRaw ? accountIdRaw : undefined;
136
229
  if (toolName === "message") {
137
- if (action !== "send" && action !== "thread-reply")
230
+ if (action !== "send" && action !== "thread-reply") {
138
231
  return undefined;
232
+ }
139
233
  const toRaw = typeof args.to === "string" ? args.to : undefined;
140
- if (!toRaw)
234
+ if (!toRaw) {
141
235
  return undefined;
236
+ }
142
237
  const providerRaw = typeof args.provider === "string" ? args.provider.trim() : "";
143
238
  const channelRaw = typeof args.channel === "string" ? args.channel.trim() : "";
144
239
  const providerHint = providerRaw || channelRaw;
@@ -148,12 +243,14 @@ export function extractMessagingToolSend(toolName, args) {
148
243
  return to ? { tool: toolName, provider, accountId, to } : undefined;
149
244
  }
150
245
  const providerId = normalizeChannelId(toolName);
151
- if (!providerId)
246
+ if (!providerId) {
152
247
  return undefined;
248
+ }
153
249
  const plugin = getChannelPlugin(providerId);
154
250
  const extracted = plugin?.actions?.extractToolSend?.({ args });
155
- if (!extracted?.to)
251
+ if (!extracted?.to) {
156
252
  return undefined;
253
+ }
157
254
  const to = normalizeTargetForProvider(providerId, extracted.to);
158
255
  return to
159
256
  ? {
@@ -1,9 +1,16 @@
1
- import { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
2
1
  import path from "node:path";
2
+ import { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
3
3
  export { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
4
+ function createAuthStorage(AuthStorageLike, path) {
5
+ const withFactory = AuthStorageLike;
6
+ if (typeof withFactory.create === "function") {
7
+ return withFactory.create(path);
8
+ }
9
+ return new AuthStorageLike(path);
10
+ }
4
11
  // Compatibility helpers for pi-coding-agent 0.50+ (discover* helpers removed).
5
12
  export function discoverAuthStorage(agentDir) {
6
- return new AuthStorage(path.join(agentDir, "auth.json"));
13
+ return createAuthStorage(AuthStorage, path.join(agentDir, "auth.json"));
7
14
  }
8
15
  export function discoverModels(authStorage, agentDir) {
9
16
  return new ModelRegistry(authStorage, path.join(agentDir, "models.json"));
@@ -1,6 +1,7 @@
1
1
  import { logDebug, logError } from "../logger.js";
2
+ import { getGlobalHookRunner } from "../plugins/hook-runner-global.js";
2
3
  import { isPlainObject } from "../utils.js";
3
- import { runBeforeToolCallHook } from "./pi-tools.before-tool-call.js";
4
+ import { consumeAdjustedParamsForToolCall, isToolWrappedWithBeforeToolCallHook, runBeforeToolCallHook, } from "./pi-tools.before-tool-call.js";
4
5
  import { normalizeToolName } from "./tool-policy.js";
5
6
  import { jsonResult } from "./tools/common.js";
6
7
  function isAbortSignal(value) {
@@ -8,8 +9,11 @@ function isAbortSignal(value) {
8
9
  }
9
10
  function isLegacyToolExecuteArgs(args) {
10
11
  const third = args[2];
11
- const fourth = args[3];
12
- return isAbortSignal(third) || typeof fourth === "function";
12
+ const fifth = args[4];
13
+ if (typeof third === "function") {
14
+ return true;
15
+ }
16
+ return isAbortSignal(fifth);
13
17
  }
14
18
  function describeToolExecutionError(err) {
15
19
  if (err instanceof Error) {
@@ -20,7 +24,7 @@ function describeToolExecutionError(err) {
20
24
  }
21
25
  function splitToolExecuteArgs(args) {
22
26
  if (isLegacyToolExecuteArgs(args)) {
23
- const [toolCallId, params, signal, onUpdate] = args;
27
+ const [toolCallId, params, onUpdate, _ctx, signal] = args;
24
28
  return {
25
29
  toolCallId,
26
30
  params,
@@ -28,7 +32,7 @@ function splitToolExecuteArgs(args) {
28
32
  signal,
29
33
  };
30
34
  }
31
- const [toolCallId, params, onUpdate, _ctx, signal] = args;
35
+ const [toolCallId, params, signal, onUpdate] = args;
32
36
  return {
33
37
  toolCallId,
34
38
  params,
@@ -40,6 +44,7 @@ export function toToolDefinitions(tools) {
40
44
  return tools.map((tool) => {
41
45
  const name = tool.name || "tool";
42
46
  const normalizedName = normalizeToolName(name);
47
+ const beforeHookWrapped = isToolWrappedWithBeforeToolCallHook(tool);
43
48
  return {
44
49
  name,
45
50
  label: tool.label ?? name,
@@ -47,8 +52,38 @@ export function toToolDefinitions(tools) {
47
52
  parameters: tool.parameters,
48
53
  execute: async (...args) => {
49
54
  const { toolCallId, params, onUpdate, signal } = splitToolExecuteArgs(args);
55
+ let executeParams = params;
50
56
  try {
51
- return await tool.execute(toolCallId, params, signal, onUpdate);
57
+ if (!beforeHookWrapped) {
58
+ const hookOutcome = await runBeforeToolCallHook({
59
+ toolName: name,
60
+ params,
61
+ toolCallId,
62
+ });
63
+ if (hookOutcome.blocked) {
64
+ throw new Error(hookOutcome.reason);
65
+ }
66
+ executeParams = hookOutcome.params;
67
+ }
68
+ const result = await tool.execute(toolCallId, executeParams, signal, onUpdate);
69
+ const afterParams = beforeHookWrapped
70
+ ? (consumeAdjustedParamsForToolCall(toolCallId) ?? executeParams)
71
+ : executeParams;
72
+ // Call after_tool_call hook
73
+ const hookRunner = getGlobalHookRunner();
74
+ if (hookRunner?.hasHooks("after_tool_call")) {
75
+ try {
76
+ await hookRunner.runAfterToolCall({
77
+ toolName: name,
78
+ params: isPlainObject(afterParams) ? afterParams : {},
79
+ result,
80
+ }, { toolName: name });
81
+ }
82
+ catch (hookErr) {
83
+ logDebug(`after_tool_call hook failed: tool=${normalizedName} error=${String(hookErr)}`);
84
+ }
85
+ }
86
+ return result;
52
87
  }
53
88
  catch (err) {
54
89
  if (signal?.aborted) {
@@ -60,16 +95,34 @@ export function toToolDefinitions(tools) {
60
95
  if (name === "AbortError") {
61
96
  throw err;
62
97
  }
98
+ if (beforeHookWrapped) {
99
+ consumeAdjustedParamsForToolCall(toolCallId);
100
+ }
63
101
  const described = describeToolExecutionError(err);
64
102
  if (described.stack && described.stack !== described.message) {
65
103
  logDebug(`tools: ${normalizedName} failed stack:\n${described.stack}`);
66
104
  }
67
105
  logError(`[tools] ${normalizedName} failed: ${described.message}`);
68
- return jsonResult({
106
+ const errorResult = jsonResult({
69
107
  status: "error",
70
108
  tool: normalizedName,
71
109
  error: described.message,
72
110
  });
111
+ // Call after_tool_call hook for errors too
112
+ const hookRunner = getGlobalHookRunner();
113
+ if (hookRunner?.hasHooks("after_tool_call")) {
114
+ try {
115
+ await hookRunner.runAfterToolCall({
116
+ toolName: normalizedName,
117
+ params: isPlainObject(params) ? params : {},
118
+ error: described.message,
119
+ }, { toolName: normalizedName });
120
+ }
121
+ catch (hookErr) {
122
+ logDebug(`after_tool_call hook failed: tool=${normalizedName} error=${String(hookErr)}`);
123
+ }
124
+ }
125
+ return errorResult;
73
126
  }
74
127
  },
75
128
  };
@@ -84,7 +137,6 @@ export function toClientToolDefinitions(tools, onClientToolCall, hookContext) {
84
137
  name: func.name,
85
138
  label: func.name,
86
139
  description: func.description ?? "",
87
- // oxlint-disable-next-line typescript/no-explicit-any
88
140
  parameters: func.parameters,
89
141
  execute: async (...args) => {
90
142
  const { toolCallId, params } = splitToolExecuteArgs(args);
@@ -187,7 +187,7 @@ export function wrapToolWithBeforeToolCallHook(tool, ctx) {
187
187
  };
188
188
  Object.defineProperty(wrappedTool, BEFORE_TOOL_CALL_WRAPPED, {
189
189
  value: true,
190
- enumerable: false,
190
+ enumerable: true,
191
191
  });
192
192
  return wrappedTool;
193
193
  }