@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,13 +1,13 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import { resolveAllowedModelRef, resolveDefaultModelForAgent } from "../agents/model-selection.js";
3
2
  import { resolveDefaultAgentId } from "../agents/agent-scope.js";
3
+ import { resolveAllowedModelRef, resolveDefaultModelForAgent, resolveSubagentConfiguredModelSelection, } from "../agents/model-selection.js";
4
4
  import { normalizeGroupActivation } from "../auto-reply/group-activation.js";
5
5
  import { formatThinkingLevels, formatXHighModelHint, normalizeElevatedLevel, normalizeReasoningLevel, normalizeThinkLevel, normalizeUsageDisplay, supportsXHighThinking, } from "../auto-reply/thinking.js";
6
6
  import { isSubagentSessionKey, normalizeAgentId, parseAgentSessionKey, } from "../routing/session-key.js";
7
7
  import { applyVerboseOverride, parseVerboseOverride } from "../sessions/level-overrides.js";
8
+ import { applyModelOverrideToSessionEntry } from "../sessions/model-overrides.js";
8
9
  import { normalizeSendPolicy } from "../sessions/send-policy.js";
9
10
  import { parseSessionLabel } from "../sessions/session-label.js";
10
- import { applyModelOverrideToSessionEntry } from "../sessions/model-overrides.js";
11
11
  import { ErrorCodes, errorShape, } from "./protocol/index.js";
12
12
  function invalid(message) {
13
13
  return { ok: false, error: errorShape(ErrorCodes.INVALID_REQUEST, message) };
@@ -39,6 +39,9 @@ export async function applySessionsPatchToStore(params) {
39
39
  const parsedAgent = parseAgentSessionKey(storeKey);
40
40
  const sessionAgentId = normalizeAgentId(parsedAgent?.agentId ?? resolveDefaultAgentId(cfg));
41
41
  const resolvedDefault = resolveDefaultModelForAgent({ cfg, agentId: sessionAgentId });
42
+ const subagentModelHint = isSubagentSessionKey(storeKey)
43
+ ? resolveSubagentConfiguredModelSelection({ cfg, agentId: sessionAgentId })
44
+ : undefined;
42
45
  const existing = store[storeKey];
43
46
  const next = existing
44
47
  ? {
@@ -49,13 +52,15 @@ export async function applySessionsPatchToStore(params) {
49
52
  if ("spawnedBy" in patch) {
50
53
  const raw = patch.spawnedBy;
51
54
  if (raw === null) {
52
- if (existing?.spawnedBy)
55
+ if (existing?.spawnedBy) {
53
56
  return invalid("spawnedBy cannot be cleared once set");
57
+ }
54
58
  }
55
59
  else if (raw !== undefined) {
56
60
  const trimmed = String(raw).trim();
57
- if (!trimmed)
61
+ if (!trimmed) {
58
62
  return invalid("invalid spawnedBy: empty");
63
+ }
59
64
  if (!isSubagentSessionKey(storeKey)) {
60
65
  return invalid("spawnedBy is only supported for subagent:* sessions");
61
66
  }
@@ -65,6 +70,28 @@ export async function applySessionsPatchToStore(params) {
65
70
  next.spawnedBy = trimmed;
66
71
  }
67
72
  }
73
+ if ("spawnDepth" in patch) {
74
+ const raw = patch.spawnDepth;
75
+ if (raw === null) {
76
+ if (typeof existing?.spawnDepth === "number") {
77
+ return invalid("spawnDepth cannot be cleared once set");
78
+ }
79
+ }
80
+ else if (raw !== undefined) {
81
+ if (!isSubagentSessionKey(storeKey)) {
82
+ return invalid("spawnDepth is only supported for subagent:* sessions");
83
+ }
84
+ const numeric = Number(raw);
85
+ if (!Number.isInteger(numeric) || numeric < 0) {
86
+ return invalid("invalid spawnDepth (use an integer >= 0)");
87
+ }
88
+ const normalized = numeric;
89
+ if (typeof existing?.spawnDepth === "number" && existing.spawnDepth !== normalized) {
90
+ return invalid("spawnDepth cannot be changed once set");
91
+ }
92
+ next.spawnDepth = normalized;
93
+ }
94
+ }
68
95
  if ("label" in patch) {
69
96
  const raw = patch.label;
70
97
  if (raw === null) {
@@ -72,11 +99,13 @@ export async function applySessionsPatchToStore(params) {
72
99
  }
73
100
  else if (raw !== undefined) {
74
101
  const parsed = parseSessionLabel(raw);
75
- if (!parsed.ok)
102
+ if (!parsed.ok) {
76
103
  return invalid(parsed.error);
104
+ }
77
105
  for (const [key, entry] of Object.entries(store)) {
78
- if (key === storeKey)
106
+ if (key === storeKey) {
79
107
  continue;
108
+ }
80
109
  if (entry?.label === parsed.label) {
81
110
  return invalid(`label already in use: ${parsed.label}`);
82
111
  }
@@ -87,6 +116,7 @@ export async function applySessionsPatchToStore(params) {
87
116
  if ("thinkingLevel" in patch) {
88
117
  const raw = patch.thinkingLevel;
89
118
  if (raw === null) {
119
+ // Clear the override and fall back to model default
90
120
  delete next.thinkingLevel;
91
121
  }
92
122
  else if (raw !== undefined) {
@@ -102,8 +132,9 @@ export async function applySessionsPatchToStore(params) {
102
132
  if ("verboseLevel" in patch) {
103
133
  const raw = patch.verboseLevel;
104
134
  const parsed = parseVerboseOverride(raw);
105
- if (!parsed.ok)
135
+ if (!parsed.ok) {
106
136
  return invalid(parsed.error);
137
+ }
107
138
  applyVerboseOverride(next, parsed.value);
108
139
  }
109
140
  if ("reasoningLevel" in patch) {
@@ -116,10 +147,12 @@ export async function applySessionsPatchToStore(params) {
116
147
  if (!normalized) {
117
148
  return invalid('invalid reasoningLevel (use "on"|"off"|"stream")');
118
149
  }
119
- if (normalized === "off")
150
+ if (normalized === "off") {
120
151
  delete next.reasoningLevel;
121
- else
152
+ }
153
+ else {
122
154
  next.reasoningLevel = normalized;
155
+ }
123
156
  }
124
157
  }
125
158
  if ("responseUsage" in patch) {
@@ -129,12 +162,15 @@ export async function applySessionsPatchToStore(params) {
129
162
  }
130
163
  else if (raw !== undefined) {
131
164
  const normalized = normalizeUsageDisplay(String(raw));
132
- if (!normalized)
165
+ if (!normalized) {
133
166
  return invalid('invalid responseUsage (use "off"|"tokens"|"full")');
134
- if (normalized === "off")
167
+ }
168
+ if (normalized === "off") {
135
169
  delete next.responseUsage;
136
- else
170
+ }
171
+ else {
137
172
  next.responseUsage = normalized;
173
+ }
138
174
  }
139
175
  }
140
176
  if ("elevatedLevel" in patch) {
@@ -144,8 +180,9 @@ export async function applySessionsPatchToStore(params) {
144
180
  }
145
181
  else if (raw !== undefined) {
146
182
  const normalized = normalizeElevatedLevel(String(raw));
147
- if (!normalized)
183
+ if (!normalized) {
148
184
  return invalid('invalid elevatedLevel (use "on"|"off"|"ask"|"full")');
185
+ }
149
186
  // Persist "off" explicitly so patches can override defaults.
150
187
  next.elevatedLevel = normalized;
151
188
  }
@@ -157,8 +194,9 @@ export async function applySessionsPatchToStore(params) {
157
194
  }
158
195
  else if (raw !== undefined) {
159
196
  const normalized = normalizeExecHost(String(raw));
160
- if (!normalized)
197
+ if (!normalized) {
161
198
  return invalid('invalid execHost (use "sandbox"|"gateway"|"node")');
199
+ }
162
200
  next.execHost = normalized;
163
201
  }
164
202
  }
@@ -169,8 +207,9 @@ export async function applySessionsPatchToStore(params) {
169
207
  }
170
208
  else if (raw !== undefined) {
171
209
  const normalized = normalizeExecSecurity(String(raw));
172
- if (!normalized)
210
+ if (!normalized) {
173
211
  return invalid('invalid execSecurity (use "deny"|"allowlist"|"full")');
212
+ }
174
213
  next.execSecurity = normalized;
175
214
  }
176
215
  }
@@ -181,8 +220,9 @@ export async function applySessionsPatchToStore(params) {
181
220
  }
182
221
  else if (raw !== undefined) {
183
222
  const normalized = normalizeExecAsk(String(raw));
184
- if (!normalized)
223
+ if (!normalized) {
185
224
  return invalid('invalid execAsk (use "off"|"on-miss"|"always")');
225
+ }
186
226
  next.execAsk = normalized;
187
227
  }
188
228
  }
@@ -193,8 +233,9 @@ export async function applySessionsPatchToStore(params) {
193
233
  }
194
234
  else if (raw !== undefined) {
195
235
  const trimmed = String(raw).trim();
196
- if (!trimmed)
236
+ if (!trimmed) {
197
237
  return invalid("invalid execNode: empty");
238
+ }
198
239
  next.execNode = trimmed;
199
240
  }
200
241
  }
@@ -212,8 +253,9 @@ export async function applySessionsPatchToStore(params) {
212
253
  }
213
254
  else if (raw !== undefined) {
214
255
  const trimmed = String(raw).trim();
215
- if (!trimmed)
256
+ if (!trimmed) {
216
257
  return invalid("invalid model: empty");
258
+ }
217
259
  if (!params.loadGatewayModelCatalog) {
218
260
  return {
219
261
  ok: false,
@@ -226,7 +268,7 @@ export async function applySessionsPatchToStore(params) {
226
268
  catalog,
227
269
  raw: trimmed,
228
270
  defaultProvider: resolvedDefault.provider,
229
- defaultModel: resolvedDefault.model,
271
+ defaultModel: subagentModelHint ?? resolvedDefault.model,
230
272
  });
231
273
  if ("error" in resolved) {
232
274
  return invalid(resolved.error);
@@ -260,8 +302,9 @@ export async function applySessionsPatchToStore(params) {
260
302
  }
261
303
  else if (raw !== undefined) {
262
304
  const normalized = normalizeSendPolicy(String(raw));
263
- if (!normalized)
305
+ if (!normalized) {
264
306
  return invalid('invalid sendPolicy (use "allow"|"deny")');
307
+ }
265
308
  next.sendPolicy = normalized;
266
309
  }
267
310
  }
@@ -4,7 +4,7 @@ import path from "node:path";
4
4
  export async function withTempConfig(params) {
5
5
  const prevConfigPath = process.env.POOLBOT_CONFIG_PATH;
6
6
  const prevDisableCache = process.env.POOLBOT_DISABLE_CONFIG_CACHE;
7
- const dir = await mkdtemp(path.join(os.tmpdir(), params.prefix ?? "openclaw-test-config-"));
7
+ const dir = await mkdtemp(path.join(os.tmpdir(), params.prefix ?? "poolbot-test-config-"));
8
8
  const configPath = path.join(dir, "poolbot.json");
9
9
  process.env.POOLBOT_CONFIG_PATH = configPath;
10
10
  process.env.POOLBOT_DISABLE_CONFIG_CACHE = "1";
@@ -1,41 +1,90 @@
1
1
  import { createPoolBotTools } from "../agents/poolbot-tools.js";
2
- import { filterToolsByPolicy, resolveEffectiveToolPolicy, resolveGroupToolPolicy, resolveSubagentToolPolicy, } from "../agents/pi-tools.policy.js";
3
- import { buildPluginToolGroups, collectExplicitAllowlist, expandPolicyWithPluginGroups, normalizeToolName, resolveToolProfilePolicy, stripPluginOnlyAllowlist, } from "../agents/tool-policy.js";
2
+ import { resolveEffectiveToolPolicy, resolveGroupToolPolicy, resolveSubagentToolPolicy, } from "../agents/pi-tools.policy.js";
3
+ import { applyToolPolicyPipeline, buildDefaultToolPolicyPipelineSteps, } from "../agents/tool-policy-pipeline.js";
4
+ import { collectExplicitAllowlist, mergeAlsoAllowPolicy, resolveToolProfilePolicy, } from "../agents/tool-policy.js";
5
+ import { ToolInputError } from "../agents/tools/common.js";
4
6
  import { loadConfig } from "../config/config.js";
5
7
  import { resolveMainSessionKey } from "../config/sessions.js";
6
8
  import { logWarn } from "../logger.js";
9
+ import { isTestDefaultMemorySlotDisabled } from "../plugins/config-state.js";
7
10
  import { getPluginToolMeta } from "../plugins/tools.js";
8
11
  import { isSubagentSessionKey } from "../routing/session-key.js";
12
+ import { DEFAULT_GATEWAY_HTTP_TOOL_DENY } from "../security/dangerous-tools.js";
9
13
  import { normalizeMessageChannel } from "../utils/message-channel.js";
10
14
  import { authorizeGatewayConnect } from "./auth.js";
15
+ import { readJsonBodyOrError, sendGatewayAuthFailure, sendInvalidRequest, sendJson, sendMethodNotAllowed, } from "./http-common.js";
11
16
  import { getBearerToken, getHeader } from "./http-utils.js";
12
- import { readJsonBodyOrError, sendInvalidRequest, sendJson, sendMethodNotAllowed, sendUnauthorized, } from "./http-common.js";
13
17
  const DEFAULT_BODY_BYTES = 2 * 1024 * 1024;
18
+ const MEMORY_TOOL_NAMES = new Set(["memory_search", "memory_get"]);
14
19
  function resolveSessionKeyFromBody(body) {
15
- if (typeof body.sessionKey === "string" && body.sessionKey.trim())
20
+ if (typeof body.sessionKey === "string" && body.sessionKey.trim()) {
16
21
  return body.sessionKey.trim();
22
+ }
17
23
  return undefined;
18
24
  }
25
+ function resolveMemoryToolDisableReasons(cfg) {
26
+ if (!process.env.VITEST) {
27
+ return [];
28
+ }
29
+ const reasons = [];
30
+ const plugins = cfg.plugins;
31
+ const slotRaw = plugins?.slots?.memory;
32
+ const slotDisabled = slotRaw === null || (typeof slotRaw === "string" && slotRaw.trim().toLowerCase() === "none");
33
+ const pluginsDisabled = plugins?.enabled === false;
34
+ const defaultDisabled = isTestDefaultMemorySlotDisabled(cfg);
35
+ if (pluginsDisabled) {
36
+ reasons.push("plugins.enabled=false");
37
+ }
38
+ if (slotDisabled) {
39
+ reasons.push(slotRaw === null ? "plugins.slots.memory=null" : 'plugins.slots.memory="none"');
40
+ }
41
+ if (!pluginsDisabled && !slotDisabled && defaultDisabled) {
42
+ reasons.push("memory plugin disabled by test default");
43
+ }
44
+ return reasons;
45
+ }
19
46
  function mergeActionIntoArgsIfSupported(params) {
20
47
  const { toolSchema, action, args } = params;
21
- if (!action)
48
+ if (!action) {
22
49
  return args;
23
- if (args.action !== undefined)
50
+ }
51
+ if (args.action !== undefined) {
24
52
  return args;
53
+ }
25
54
  // TypeBox schemas are plain objects; many tools define an `action` property.
26
55
  const schemaObj = toolSchema;
27
56
  const hasAction = Boolean(schemaObj &&
28
57
  typeof schemaObj === "object" &&
29
58
  schemaObj.properties &&
30
59
  "action" in schemaObj.properties);
31
- if (!hasAction)
60
+ if (!hasAction) {
32
61
  return args;
62
+ }
33
63
  return { ...args, action };
34
64
  }
65
+ function getErrorMessage(err) {
66
+ if (err instanceof Error) {
67
+ return err.message || String(err);
68
+ }
69
+ if (typeof err === "string") {
70
+ return err;
71
+ }
72
+ return String(err);
73
+ }
74
+ function isToolInputError(err) {
75
+ if (err instanceof ToolInputError) {
76
+ return true;
77
+ }
78
+ return (typeof err === "object" &&
79
+ err !== null &&
80
+ "name" in err &&
81
+ err.name === "ToolInputError");
82
+ }
35
83
  export async function handleToolsInvokeHttpRequest(req, res, opts) {
36
84
  const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
37
- if (url.pathname !== "/tools/invoke")
85
+ if (url.pathname !== "/tools/invoke") {
38
86
  return false;
87
+ }
39
88
  if (req.method !== "POST") {
40
89
  sendMethodNotAllowed(res, "POST");
41
90
  return true;
@@ -47,25 +96,42 @@ export async function handleToolsInvokeHttpRequest(req, res, opts) {
47
96
  connectAuth: token ? { token, password: token } : null,
48
97
  req,
49
98
  trustedProxies: opts.trustedProxies ?? cfg.gateway?.trustedProxies,
99
+ rateLimiter: opts.rateLimiter,
50
100
  });
51
101
  if (!authResult.ok) {
52
- sendUnauthorized(res);
102
+ sendGatewayAuthFailure(res, authResult);
53
103
  return true;
54
104
  }
55
105
  const bodyUnknown = await readJsonBodyOrError(req, res, opts.maxBodyBytes ?? DEFAULT_BODY_BYTES);
56
- if (bodyUnknown === undefined)
106
+ if (bodyUnknown === undefined) {
57
107
  return true;
108
+ }
58
109
  const body = (bodyUnknown ?? {});
59
110
  const toolName = typeof body.tool === "string" ? body.tool.trim() : "";
60
111
  if (!toolName) {
61
112
  sendInvalidRequest(res, "tools.invoke requires body.tool");
62
113
  return true;
63
114
  }
115
+ if (process.env.VITEST && MEMORY_TOOL_NAMES.has(toolName)) {
116
+ const reasons = resolveMemoryToolDisableReasons(cfg);
117
+ if (reasons.length > 0) {
118
+ const suffix = reasons.length > 0 ? ` (${reasons.join(", ")})` : "";
119
+ sendJson(res, 400, {
120
+ ok: false,
121
+ error: {
122
+ type: "invalid_request",
123
+ message: `memory tools are disabled in tests${suffix}. ` +
124
+ 'Enable by setting plugins.slots.memory="memory-core" (and ensure plugins.enabled is not false).',
125
+ },
126
+ });
127
+ return true;
128
+ }
129
+ }
64
130
  const action = typeof body.action === "string" ? body.action.trim() : undefined;
65
131
  const argsRaw = body.args;
66
- const args = (argsRaw && typeof argsRaw === "object" && !Array.isArray(argsRaw)
132
+ const args = argsRaw && typeof argsRaw === "object" && !Array.isArray(argsRaw)
67
133
  ? argsRaw
68
- : {});
134
+ : {};
69
135
  const rawSessionKey = resolveSessionKeyFromBody(body);
70
136
  const sessionKey = !rawSessionKey || rawSessionKey === "main" ? resolveMainSessionKey(cfg) : rawSessionKey;
71
137
  // Resolve message channel/account hints (optional headers) for policy inheritance.
@@ -74,13 +140,8 @@ export async function handleToolsInvokeHttpRequest(req, res, opts) {
74
140
  const { agentId, globalPolicy, globalProviderPolicy, agentPolicy, agentProviderPolicy, profile, providerProfile, profileAlsoAllow, providerProfileAlsoAllow, } = resolveEffectiveToolPolicy({ config: cfg, sessionKey });
75
141
  const profilePolicy = resolveToolProfilePolicy(profile);
76
142
  const providerProfilePolicy = resolveToolProfilePolicy(providerProfile);
77
- const mergeAlsoAllow = (policy, alsoAllow) => {
78
- if (!policy?.allow || !Array.isArray(alsoAllow) || alsoAllow.length === 0)
79
- return policy;
80
- return { ...policy, allow: Array.from(new Set([...policy.allow, ...alsoAllow])) };
81
- };
82
- const profilePolicyWithAlsoAllow = mergeAlsoAllow(profilePolicy, profileAlsoAllow);
83
- const providerProfilePolicyWithAlsoAllow = mergeAlsoAllow(providerProfilePolicy, providerProfileAlsoAllow);
143
+ const profilePolicyWithAlsoAllow = mergeAlsoAllowPolicy(profilePolicy, profileAlsoAllow);
144
+ const providerProfilePolicyWithAlsoAllow = mergeAlsoAllowPolicy(providerProfilePolicy, providerProfileAlsoAllow);
84
145
  const groupPolicy = resolveGroupToolPolicy({
85
146
  config: cfg,
86
147
  sessionKey,
@@ -107,58 +168,35 @@ export async function handleToolsInvokeHttpRequest(req, res, opts) {
107
168
  subagentPolicy,
108
169
  ]),
109
170
  });
110
- const coreToolNames = new Set(allTools
111
- .filter((tool) => !getPluginToolMeta(tool))
112
- .map((tool) => normalizeToolName(tool.name))
113
- .filter(Boolean));
114
- const pluginGroups = buildPluginToolGroups({
171
+ const subagentFiltered = applyToolPolicyPipeline({
172
+ // oxlint-disable-next-line typescript/no-explicit-any
115
173
  tools: allTools,
174
+ // oxlint-disable-next-line typescript/no-explicit-any
116
175
  toolMeta: (tool) => getPluginToolMeta(tool),
176
+ warn: logWarn,
177
+ steps: [
178
+ ...buildDefaultToolPolicyPipelineSteps({
179
+ profilePolicy: profilePolicyWithAlsoAllow,
180
+ profile,
181
+ providerProfilePolicy: providerProfilePolicyWithAlsoAllow,
182
+ providerProfile,
183
+ globalPolicy,
184
+ globalProviderPolicy,
185
+ agentPolicy,
186
+ agentProviderPolicy,
187
+ groupPolicy,
188
+ agentId,
189
+ }),
190
+ { policy: subagentPolicy, label: "subagent tools.allow" },
191
+ ],
117
192
  });
118
- const resolvePolicy = (policy, label) => {
119
- const resolved = stripPluginOnlyAllowlist(policy, pluginGroups, coreToolNames);
120
- if (resolved.unknownAllowlist.length > 0) {
121
- const entries = resolved.unknownAllowlist.join(", ");
122
- const suffix = resolved.strippedAllowlist
123
- ? "Ignoring allowlist so core tools remain available. Use tools.alsoAllow for additive plugin tool enablement."
124
- : "These entries won't match any tool unless the plugin is enabled.";
125
- logWarn(`tools: ${label} allowlist contains unknown entries (${entries}). ${suffix}`);
126
- }
127
- return expandPolicyWithPluginGroups(resolved.policy, pluginGroups);
128
- };
129
- const profilePolicyExpanded = resolvePolicy(profilePolicyWithAlsoAllow, profile ? `tools.profile (${profile})` : "tools.profile");
130
- const providerProfileExpanded = resolvePolicy(providerProfilePolicyWithAlsoAllow, providerProfile ? `tools.byProvider.profile (${providerProfile})` : "tools.byProvider.profile");
131
- const globalPolicyExpanded = resolvePolicy(globalPolicy, "tools.allow");
132
- const globalProviderExpanded = resolvePolicy(globalProviderPolicy, "tools.byProvider.allow");
133
- const agentPolicyExpanded = resolvePolicy(agentPolicy, agentId ? `agents.${agentId}.tools.allow` : "agent tools.allow");
134
- const agentProviderExpanded = resolvePolicy(agentProviderPolicy, agentId ? `agents.${agentId}.tools.byProvider.allow` : "agent tools.byProvider.allow");
135
- const groupPolicyExpanded = resolvePolicy(groupPolicy, "group tools.allow");
136
- const subagentPolicyExpanded = expandPolicyWithPluginGroups(subagentPolicy, pluginGroups);
137
- const toolsFiltered = profilePolicyExpanded
138
- ? filterToolsByPolicy(allTools, profilePolicyExpanded)
139
- : allTools;
140
- const providerProfileFiltered = providerProfileExpanded
141
- ? filterToolsByPolicy(toolsFiltered, providerProfileExpanded)
142
- : toolsFiltered;
143
- const globalFiltered = globalPolicyExpanded
144
- ? filterToolsByPolicy(providerProfileFiltered, globalPolicyExpanded)
145
- : providerProfileFiltered;
146
- const globalProviderFiltered = globalProviderExpanded
147
- ? filterToolsByPolicy(globalFiltered, globalProviderExpanded)
148
- : globalFiltered;
149
- const agentFiltered = agentPolicyExpanded
150
- ? filterToolsByPolicy(globalProviderFiltered, agentPolicyExpanded)
151
- : globalProviderFiltered;
152
- const agentProviderFiltered = agentProviderExpanded
153
- ? filterToolsByPolicy(agentFiltered, agentProviderExpanded)
154
- : agentFiltered;
155
- const groupFiltered = groupPolicyExpanded
156
- ? filterToolsByPolicy(agentProviderFiltered, groupPolicyExpanded)
157
- : agentProviderFiltered;
158
- const subagentFiltered = subagentPolicyExpanded
159
- ? filterToolsByPolicy(groupFiltered, subagentPolicyExpanded)
160
- : groupFiltered;
161
- const tool = subagentFiltered.find((t) => t.name === toolName);
193
+ // Gateway HTTP-specific deny list applies to ALL sessions via HTTP.
194
+ const gatewayToolsCfg = cfg.gateway?.tools;
195
+ const defaultGatewayDeny = DEFAULT_GATEWAY_HTTP_TOOL_DENY.filter((name) => !gatewayToolsCfg?.allow?.includes(name));
196
+ const gatewayDenyNames = defaultGatewayDeny.concat(Array.isArray(gatewayToolsCfg?.deny) ? gatewayToolsCfg.deny : []);
197
+ const gatewayDenySet = new Set(gatewayDenyNames);
198
+ const gatewayFiltered = subagentFiltered.filter((t) => !gatewayDenySet.has(t.name));
199
+ const tool = gatewayFiltered.find((t) => t.name === toolName);
162
200
  if (!tool) {
163
201
  sendJson(res, 404, {
164
202
  ok: false,
@@ -168,17 +206,27 @@ export async function handleToolsInvokeHttpRequest(req, res, opts) {
168
206
  }
169
207
  try {
170
208
  const toolArgs = mergeActionIntoArgsIfSupported({
209
+ // oxlint-disable-next-line typescript/no-explicit-any
171
210
  toolSchema: tool.parameters,
172
211
  action,
173
212
  args,
174
213
  });
214
+ // oxlint-disable-next-line typescript/no-explicit-any
175
215
  const result = await tool.execute?.(`http-${Date.now()}`, toolArgs);
176
216
  sendJson(res, 200, { ok: true, result });
177
217
  }
178
218
  catch (err) {
179
- sendJson(res, 400, {
219
+ if (isToolInputError(err)) {
220
+ sendJson(res, 400, {
221
+ ok: false,
222
+ error: { type: "tool_error", message: getErrorMessage(err) || "invalid tool arguments" },
223
+ });
224
+ return true;
225
+ }
226
+ logWarn(`tools-invoke: tool execution failed: ${String(err)}`);
227
+ sendJson(res, 500, {
180
228
  ok: false,
181
- error: { type: "tool_error", message: err instanceof Error ? err.message : String(err) },
229
+ error: { type: "tool_error", message: "tool execution failed" },
182
230
  });
183
231
  }
184
232
  return true;