@poolzin/pool-bot 2026.2.25 → 2026.2.26

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 (506) hide show
  1. package/dist/acp/event-mapper.js +87 -22
  2. package/dist/acp/meta.js +12 -6
  3. package/dist/agents/agent-paths.js +8 -9
  4. package/dist/agents/agent-scope.js +7 -5
  5. package/dist/agents/auth-profiles/oauth.js +148 -64
  6. package/dist/agents/auth-profiles/session-override.js +13 -7
  7. package/dist/agents/bash-tools.exec-host-gateway.js +14 -4
  8. package/dist/agents/bash-tools.exec-runtime.js +2 -25
  9. package/dist/agents/bedrock-discovery.js +3 -1
  10. package/dist/agents/byteplus-models.js +97 -0
  11. package/dist/agents/chutes-oauth.js +1 -0
  12. package/dist/agents/cli-runner/helpers.js +4 -0
  13. package/dist/agents/compaction.js +41 -14
  14. package/dist/agents/doubao-models.js +121 -0
  15. package/dist/agents/failover-error.js +2 -0
  16. package/dist/agents/huggingface-models.js +5 -3
  17. package/dist/agents/live-model-filter.js +5 -0
  18. package/dist/agents/minimax-vlm.js +10 -8
  19. package/dist/agents/model-auth.js +6 -0
  20. package/dist/agents/model-catalog.js +3 -1
  21. package/dist/agents/model-selection.js +7 -1
  22. package/dist/agents/models-config.providers.js +93 -11
  23. package/dist/agents/ollama-stream.js +117 -4
  24. package/dist/agents/opencode-zen-models.js +22 -11
  25. package/dist/agents/pi-embedded-helpers/errors.js +55 -33
  26. package/dist/agents/pi-embedded-helpers/messaging-dedupe.js +10 -5
  27. package/dist/agents/pi-embedded-helpers/thinking.js +10 -5
  28. package/dist/agents/pi-embedded-helpers.js +1 -1
  29. package/dist/agents/pi-embedded-runner/compact.js +29 -7
  30. package/dist/agents/pi-embedded-runner/extensions.js +28 -26
  31. package/dist/agents/pi-embedded-runner/google.js +20 -8
  32. package/dist/agents/pi-embedded-runner/run/attempt.js +95 -36
  33. package/dist/agents/pi-embedded-runner/run.js +71 -12
  34. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +11 -2
  35. package/dist/agents/pi-embedded-runner/session-manager-cache.js +11 -7
  36. package/dist/agents/pi-embedded-runner/system-prompt.js +2 -0
  37. package/dist/agents/pi-embedded-runner/thinking.js +42 -0
  38. package/dist/agents/pi-embedded-runner/tool-name-allowlist.js +19 -0
  39. package/dist/agents/pi-embedded-runner/utils.js +7 -10
  40. package/dist/agents/pi-embedded-subscribe.handlers.lifecycle.js +45 -56
  41. package/dist/agents/pi-embedded-subscribe.handlers.tools.js +2 -2
  42. package/dist/agents/pi-embedded-subscribe.js +9 -4
  43. package/dist/agents/pi-embedded-subscribe.tools.js +68 -14
  44. package/dist/agents/pi-embedded-utils.js +3 -0
  45. package/dist/agents/pi-extensions/compaction-safeguard-runtime.js +4 -20
  46. package/dist/agents/pi-extensions/compaction-safeguard.js +75 -33
  47. package/dist/agents/pi-settings.js +40 -0
  48. package/dist/agents/pi-tools.policy.js +2 -1
  49. package/dist/agents/provider/config-loader.js +1 -1
  50. package/dist/agents/sandbox/browser.js +170 -33
  51. package/dist/agents/sandbox/config-hash.js +14 -27
  52. package/dist/agents/sandbox/config.js +21 -2
  53. package/dist/agents/sandbox/constants.js +2 -0
  54. package/dist/agents/sandbox/docker.js +16 -2
  55. package/dist/agents/sandbox/novnc-auth.js +62 -0
  56. package/dist/agents/sandbox/sanitize-env-vars.js +1 -1
  57. package/dist/agents/sandbox/shared.js +10 -6
  58. package/dist/agents/sandbox-paths.js +24 -11
  59. package/dist/agents/schema/clean-for-gemini.js +132 -85
  60. package/dist/agents/session-slug.js +10 -5
  61. package/dist/agents/session-tool-result-guard-wrapper.js +1 -0
  62. package/dist/agents/session-tool-result-guard.js +3 -1
  63. package/dist/agents/session-transcript-repair.js +40 -6
  64. package/dist/agents/skills/bundled-dir.js +19 -5
  65. package/dist/agents/skills/env-overrides.js +124 -43
  66. package/dist/agents/skills/frontmatter.js +6 -6
  67. package/dist/agents/skills/plugin-skills.js +14 -7
  68. package/dist/agents/skills/workspace.js +1 -0
  69. package/dist/agents/subagent-announce.js +251 -49
  70. package/dist/agents/subagent-lifecycle-events.js +19 -0
  71. package/dist/agents/subagent-registry-cleanup.js +31 -0
  72. package/dist/agents/subagent-registry-completion.js +68 -0
  73. package/dist/agents/subagent-registry-queries.js +117 -0
  74. package/dist/agents/subagent-registry-state.js +46 -0
  75. package/dist/agents/subagent-registry.js +252 -221
  76. package/dist/agents/subagent-registry.store.js +1 -0
  77. package/dist/agents/subagent-registry.types.js +1 -0
  78. package/dist/agents/subagent-spawn.js +195 -7
  79. package/dist/agents/system-prompt.js +22 -6
  80. package/dist/agents/test-helpers/fast-coding-tools.js +1 -18
  81. package/dist/agents/test-helpers/fast-core-tools.js +1 -17
  82. package/dist/agents/timeout.js +18 -6
  83. package/dist/agents/tool-call-id.js +1 -1
  84. package/dist/agents/tool-display-common.js +162 -29
  85. package/dist/agents/tool-images.js +82 -9
  86. package/dist/agents/tool-policy.js +51 -26
  87. package/dist/agents/tools/browser-tool.js +2 -2
  88. package/dist/agents/tools/canvas-tool.js +27 -1
  89. package/dist/agents/tools/common.js +45 -0
  90. package/dist/agents/tools/discord-actions-guild.js +4 -1
  91. package/dist/agents/tools/gateway-tool.js +3 -1
  92. package/dist/agents/tools/nodes-utils.js +1 -10
  93. package/dist/agents/tools/sessions-send-helpers.js +12 -6
  94. package/dist/agents/tools/sessions-spawn-tool.js +8 -2
  95. package/dist/agents/tools/subagents-tool.js +2 -1
  96. package/dist/agents/tools/whatsapp-actions.js +10 -2
  97. package/dist/agents/tools/whatsapp-target-auth.js +18 -0
  98. package/dist/agents/transcript-policy.js +22 -8
  99. package/dist/agents/venice-models.js +11 -3
  100. package/dist/auto-reply/commands-registry.data.js +51 -0
  101. package/dist/auto-reply/commands-registry.js +4 -3
  102. package/dist/auto-reply/group-activation.js +10 -5
  103. package/dist/auto-reply/inbound-debounce.js +10 -5
  104. package/dist/auto-reply/reply/abort.js +1 -1
  105. package/dist/auto-reply/reply/agent-runner-execution.js +4 -1
  106. package/dist/auto-reply/reply/bash-command.js +41 -39
  107. package/dist/auto-reply/reply/command-gates.js +25 -0
  108. package/dist/auto-reply/reply/commands-allowlist.js +111 -72
  109. package/dist/auto-reply/reply/commands-bash.js +6 -5
  110. package/dist/auto-reply/reply/commands-config.js +30 -28
  111. package/dist/auto-reply/reply/commands-core.js +2 -1
  112. package/dist/auto-reply/reply/commands-info.js +1 -0
  113. package/dist/auto-reply/reply/commands-models.js +65 -14
  114. package/dist/auto-reply/reply/commands-session.js +237 -82
  115. package/dist/auto-reply/reply/commands-setunset.js +45 -0
  116. package/dist/auto-reply/reply/commands-subagents/action-agents.js +44 -0
  117. package/dist/auto-reply/reply/commands-subagents/action-focus.js +64 -0
  118. package/dist/auto-reply/reply/commands-subagents/action-help.js +4 -0
  119. package/dist/auto-reply/reply/commands-subagents/action-info.js +45 -0
  120. package/dist/auto-reply/reply/commands-subagents/action-kill.js +60 -0
  121. package/dist/auto-reply/reply/commands-subagents/action-list.js +44 -0
  122. package/dist/auto-reply/reply/commands-subagents/action-log.js +29 -0
  123. package/dist/auto-reply/reply/commands-subagents/action-send.js +119 -0
  124. package/dist/auto-reply/reply/commands-subagents/action-spawn.js +52 -0
  125. package/dist/auto-reply/reply/commands-subagents/action-unfocus.js +30 -0
  126. package/dist/auto-reply/reply/commands-subagents/shared.js +303 -0
  127. package/dist/auto-reply/reply/commands-subagents.js +51 -587
  128. package/dist/auto-reply/reply/commands-tts.js +10 -5
  129. package/dist/auto-reply/reply/config-value.js +10 -5
  130. package/dist/auto-reply/reply/directive-handling.model-picker.js +12 -6
  131. package/dist/auto-reply/reply/directive-handling.persist.js +9 -21
  132. package/dist/auto-reply/reply/directive-handling.shared.js +24 -4
  133. package/dist/auto-reply/reply/followup-runner.js +1 -0
  134. package/dist/auto-reply/reply/get-reply-directives-utils.js +23 -14
  135. package/dist/auto-reply/reply/get-reply-directives.js +17 -28
  136. package/dist/auto-reply/reply/get-reply-inline-actions.js +1 -0
  137. package/dist/auto-reply/reply/get-reply.js +71 -12
  138. package/dist/auto-reply/reply/model-selection.js +80 -39
  139. package/dist/auto-reply/reply/queue/enqueue.js +10 -5
  140. package/dist/auto-reply/reply/queue/state.js +13 -12
  141. package/dist/auto-reply/reply/reply-payloads.js +67 -36
  142. package/dist/auto-reply/reply/reply-reference.js +9 -8
  143. package/dist/auto-reply/reply/route-reply.js +15 -8
  144. package/dist/auto-reply/reply/session-reset-prompt.js +1 -1
  145. package/dist/auto-reply/reply/session.js +22 -6
  146. package/dist/auto-reply/reply/strip-inbound-meta.js +147 -0
  147. package/dist/auto-reply/reply/subagents-utils.js +56 -30
  148. package/dist/auto-reply/reply/typing.js +46 -21
  149. package/dist/auto-reply/send-policy.js +14 -7
  150. package/dist/auto-reply/status.js +140 -16
  151. package/dist/auto-reply/templating.js +10 -5
  152. package/dist/auto-reply/thinking.js +7 -16
  153. package/dist/auto-reply/tokens.js +21 -5
  154. package/dist/browser/bridge-server.js +36 -20
  155. package/dist/browser/cdp.helpers.js +7 -14
  156. package/dist/browser/cdp.js +35 -15
  157. package/dist/browser/chrome.profile-decoration.js +7 -4
  158. package/dist/browser/config.js +4 -0
  159. package/dist/browser/extension-relay-auth.js +55 -0
  160. package/dist/browser/extension-relay.js +74 -29
  161. package/dist/browser/navigation-guard.js +9 -1
  162. package/dist/browser/paths.js +77 -0
  163. package/dist/browser/profiles.js +13 -8
  164. package/dist/browser/pw-ai-module.js +10 -5
  165. package/dist/browser/pw-session.js +76 -39
  166. package/dist/browser/pw-tools-core.interactions.js +14 -7
  167. package/dist/browser/pw-tools-core.state.js +12 -6
  168. package/dist/browser/routes/agent.act.js +2 -2
  169. package/dist/browser/server-context.js +7 -0
  170. package/dist/build-info.json +3 -3
  171. package/dist/channels/allow-from.js +2 -1
  172. package/dist/channels/allowlists/resolve-utils.js +43 -19
  173. package/dist/channels/channel-config.js +14 -7
  174. package/dist/channels/draft-stream-loop.js +7 -0
  175. package/dist/channels/model-overrides.js +82 -0
  176. package/dist/channels/plugins/normalize/imessage.js +14 -7
  177. package/dist/channels/plugins/normalize/slack.js +10 -5
  178. package/dist/channels/plugins/normalize/telegram.js +14 -7
  179. package/dist/channels/plugins/outbound/discord.js +80 -8
  180. package/dist/channels/plugins/outbound/signal.js +11 -11
  181. package/dist/channels/plugins/setup-helpers.js +10 -5
  182. package/dist/channels/sender-label.js +14 -7
  183. package/dist/channels/session.js +4 -2
  184. package/dist/channels/status-reactions.js +297 -0
  185. package/dist/cli/banner.js +1 -1
  186. package/dist/cli/browser-cli-actions-input/register.files-downloads.js +65 -56
  187. package/dist/cli/cli-name.js +11 -11
  188. package/dist/cli/cli-utils.js +13 -3
  189. package/dist/cli/command-format.js +1 -1
  190. package/dist/cli/config-cli.js +1 -1
  191. package/dist/cli/daemon-cli/lifecycle-core.js +31 -19
  192. package/dist/cli/daemon-cli/lifecycle.js +64 -2
  193. package/dist/cli/daemon-cli/restart-health.js +126 -0
  194. package/dist/cli/daemon-cli/status.gather.js +9 -13
  195. package/dist/cli/daemon-cli/status.print.js +2 -10
  196. package/dist/cli/deps.js +27 -22
  197. package/dist/cli/gateway-cli/run-loop.js +23 -5
  198. package/dist/cli/node-cli/register.js +14 -5
  199. package/dist/cli/nodes-media-utils.js +7 -2
  200. package/dist/cli/outbound-send-deps.js +2 -9
  201. package/dist/cli/outbound-send-mapping.js +11 -0
  202. package/dist/cli/pairing-cli.js +40 -14
  203. package/dist/cli/plugins-cli.js +34 -41
  204. package/dist/cli/ports.js +11 -10
  205. package/dist/cli/program/command-registry.js +2 -11
  206. package/dist/cli/program/command-tree.js +16 -0
  207. package/dist/cli/program/preaction.js +13 -9
  208. package/dist/cli/program/register.configure.js +3 -18
  209. package/dist/cli/program/register.maintenance.js +2 -2
  210. package/dist/cli/program/register.onboard.js +2 -0
  211. package/dist/cli/program/register.status-health-sessions.js +16 -17
  212. package/dist/cli/program/register.subclis.js +93 -52
  213. package/dist/cli/route.js +11 -7
  214. package/dist/cli/system-cli.js +36 -46
  215. package/dist/cli/update-cli/shared.js +22 -9
  216. package/dist/cli/update-cli/update-command.js +89 -14
  217. package/dist/cli/update-cli/wizard.js +6 -12
  218. package/dist/commands/agent/run-context.js +18 -5
  219. package/dist/commands/agent/session-store.js +17 -4
  220. package/dist/commands/agent.js +22 -2
  221. package/dist/commands/agents.bindings.js +14 -7
  222. package/dist/commands/agents.commands.add.js +13 -9
  223. package/dist/commands/agents.commands.identity.js +12 -6
  224. package/dist/commands/agents.commands.list.js +11 -6
  225. package/dist/commands/agents.config.js +8 -10
  226. package/dist/commands/agents.providers.js +12 -6
  227. package/dist/commands/auth-choice-options.js +103 -75
  228. package/dist/commands/auth-choice.apply.byteplus.js +55 -0
  229. package/dist/commands/auth-choice.apply.js +4 -0
  230. package/dist/commands/auth-choice.apply.minimax.js +61 -13
  231. package/dist/commands/auth-choice.apply.openai.js +3 -1
  232. package/dist/commands/auth-choice.apply.volcengine.js +55 -0
  233. package/dist/commands/auth-choice.preferred-provider.js +2 -0
  234. package/dist/commands/channels/remove.js +13 -6
  235. package/dist/commands/channels/shared.js +4 -14
  236. package/dist/commands/configure.commands.js +14 -0
  237. package/dist/commands/configure.gateway.js +2 -4
  238. package/dist/commands/configure.js +1 -1
  239. package/dist/commands/configure.shared.js +11 -0
  240. package/dist/commands/daemon-install-helpers.js +2 -2
  241. package/dist/commands/dashboard.js +12 -10
  242. package/dist/commands/docs.js +14 -8
  243. package/dist/commands/doctor-config-flow.js +11 -9
  244. package/dist/commands/doctor-legacy-config.js +281 -0
  245. package/dist/commands/doctor-state-integrity.js +99 -23
  246. package/dist/commands/doctor-update.js +12 -9
  247. package/dist/commands/models/list.list-command.js +7 -5
  248. package/dist/commands/models/set-image.js +2 -21
  249. package/dist/commands/node-daemon-install-helpers.js +10 -8
  250. package/dist/commands/onboard-auth.config-minimax.js +54 -80
  251. package/dist/commands/onboard-auth.config-opencode.js +2 -18
  252. package/dist/commands/onboard-auth.credentials.js +90 -13
  253. package/dist/commands/onboard-auth.js +1 -1
  254. package/dist/commands/onboard-auth.models.js +6 -5
  255. package/dist/commands/onboard-hooks.js +1 -1
  256. package/dist/commands/onboard-non-interactive/api-keys.js +14 -7
  257. package/dist/commands/onboard-non-interactive/local/auth-choice.js +64 -49
  258. package/dist/commands/onboard-provider-auth-flags.js +14 -0
  259. package/dist/commands/onboard-remote.js +14 -7
  260. package/dist/commands/onboard.js +11 -13
  261. package/dist/commands/sandbox-display.js +6 -5
  262. package/dist/commands/status-all/diagnosis.js +14 -10
  263. package/dist/commands/status-all/format.js +1 -0
  264. package/dist/commands/status.gateway-probe.js +1 -16
  265. package/dist/commands/systemd-linger.js +12 -6
  266. package/dist/config/agent-limits.js +2 -0
  267. package/dist/config/commands.js +30 -16
  268. package/dist/config/config-paths.js +9 -11
  269. package/dist/config/defaults.js +22 -2
  270. package/dist/config/discord-preview-streaming.js +104 -0
  271. package/dist/config/env-vars.js +37 -8
  272. package/dist/config/includes.js +4 -0
  273. package/dist/config/io.js +97 -12
  274. package/dist/config/legacy.migrations.part-1.js +189 -78
  275. package/dist/config/legacy.shared.js +3 -1
  276. package/dist/config/merge-patch.js +4 -0
  277. package/dist/config/prototype-keys.js +4 -0
  278. package/dist/config/schema.help.js +44 -7
  279. package/dist/config/schema.labels.js +38 -6
  280. package/dist/config/sessions/delivery-info.js +10 -3
  281. package/dist/config/sessions/main-session.js +10 -5
  282. package/dist/config/sessions/session-file.js +33 -0
  283. package/dist/config/sessions/session-key.js +10 -5
  284. package/dist/config/sessions/store.js +1 -1
  285. package/dist/config/sessions.js +1 -0
  286. package/dist/config/zod-schema.agent-runtime.js +11 -0
  287. package/dist/config/zod-schema.js +148 -13
  288. package/dist/config/zod-schema.providers-core.js +78 -4
  289. package/dist/config/zod-schema.providers.js +6 -1
  290. package/dist/config/zod-schema.session.js +41 -2
  291. package/dist/cron/run-log.js +3 -0
  292. package/dist/cron/schedule.js +21 -10
  293. package/dist/cron/service/ops.js +35 -21
  294. package/dist/cron/service/timer.js +116 -16
  295. package/dist/cron/stagger.js +3 -1
  296. package/dist/discord/api.js +12 -6
  297. package/dist/discord/draft-chunking.js +22 -0
  298. package/dist/discord/draft-stream.js +124 -0
  299. package/dist/discord/monitor/agent-components.js +1 -1
  300. package/dist/discord/monitor/commands.js +5 -0
  301. package/dist/discord/monitor/gateway-plugin.js +2 -1
  302. package/dist/discord/monitor/listeners.js +37 -27
  303. package/dist/discord/monitor/message-handler.js +4 -1
  304. package/dist/discord/monitor/message-handler.preflight.js +65 -8
  305. package/dist/discord/monitor/message-handler.process.js +246 -217
  306. package/dist/discord/monitor/message-utils.js +143 -6
  307. package/dist/discord/monitor/model-picker-preferences.js +143 -0
  308. package/dist/discord/monitor/model-picker.js +651 -0
  309. package/dist/discord/monitor/native-command.js +573 -16
  310. package/dist/discord/monitor/provider.allowlist.js +223 -0
  311. package/dist/discord/monitor/provider.js +275 -347
  312. package/dist/discord/monitor/provider.lifecycle.js +100 -0
  313. package/dist/discord/monitor/reply-delivery.js +123 -16
  314. package/dist/discord/monitor/thread-bindings.discord-api.js +215 -0
  315. package/dist/discord/monitor/thread-bindings.js +4 -0
  316. package/dist/discord/monitor/thread-bindings.lifecycle.js +177 -0
  317. package/dist/discord/monitor/thread-bindings.manager.js +423 -0
  318. package/dist/discord/monitor/thread-bindings.messages.js +55 -0
  319. package/dist/discord/monitor/thread-bindings.state.js +358 -0
  320. package/dist/discord/monitor/thread-bindings.types.js +6 -0
  321. package/dist/discord/resolve-users.js +33 -21
  322. package/dist/discord/send.channels.js +15 -0
  323. package/dist/discord/send.js +3 -2
  324. package/dist/discord/send.outbound.js +82 -26
  325. package/dist/discord/send.permissions.js +83 -30
  326. package/dist/discord/send.reactions.js +8 -4
  327. package/dist/discord/token.js +10 -5
  328. package/dist/discord/voice/command.js +263 -0
  329. package/dist/discord/voice/manager.js +531 -0
  330. package/dist/gateway/auth.js +34 -10
  331. package/dist/gateway/call.js +4 -16
  332. package/dist/gateway/client.js +28 -4
  333. package/dist/gateway/config-reload.js +3 -4
  334. package/dist/gateway/control-ui.js +219 -96
  335. package/dist/gateway/hooks-mapping.js +88 -38
  336. package/dist/gateway/http-auth-helpers.js +3 -2
  337. package/dist/gateway/http-endpoint-helpers.js +1 -0
  338. package/dist/gateway/net.js +54 -12
  339. package/dist/gateway/node-invoke-system-run-approval.js +14 -35
  340. package/dist/gateway/node-registry.js +10 -5
  341. package/dist/gateway/openai-http.js +1 -0
  342. package/dist/gateway/openresponses-http.js +1 -0
  343. package/dist/gateway/origin-check.js +1 -18
  344. package/dist/gateway/protocol/index.js +4 -3
  345. package/dist/gateway/protocol/schema/cron.js +1 -0
  346. package/dist/gateway/protocol/schema/devices.js +1 -0
  347. package/dist/gateway/protocol/schema/protocol-schemas.js +2 -1
  348. package/dist/gateway/protocol/schema/sessions.js +6 -0
  349. package/dist/gateway/role-policy.js +17 -0
  350. package/dist/gateway/server/ws-connection/connect-policy.js +37 -0
  351. package/dist/gateway/server/ws-connection/message-handler.js +175 -148
  352. package/dist/gateway/server-chat.js +83 -25
  353. package/dist/gateway/server-constants.js +10 -9
  354. package/dist/gateway/server-cron.js +1 -0
  355. package/dist/gateway/server-http.js +16 -7
  356. package/dist/gateway/server-maintenance.js +20 -5
  357. package/dist/gateway/server-methods/chat.js +10 -6
  358. package/dist/gateway/server-methods/config.js +12 -14
  359. package/dist/gateway/server-methods/devices.js +17 -3
  360. package/dist/gateway/server-methods/models.js +11 -1
  361. package/dist/gateway/server-methods/sessions.js +64 -8
  362. package/dist/gateway/server-methods/usage.js +162 -75
  363. package/dist/gateway/server-node-events.js +29 -0
  364. package/dist/gateway/server-runtime-config.js +34 -13
  365. package/dist/gateway/server-startup-memory.js +17 -11
  366. package/dist/gateway/session-utils.fs.js +32 -34
  367. package/dist/gateway/sessions-resolve.js +17 -5
  368. package/dist/gateway/test-helpers.openai-mock.js +14 -7
  369. package/dist/gateway/tools-invoke-http.js +21 -10
  370. package/dist/hooks/bundled/bootstrap-extra-files/handler.js +3 -1
  371. package/dist/hooks/bundled/command-logger/handler.js +7 -2
  372. package/dist/hooks/bundled/session-memory/handler.js +6 -5
  373. package/dist/hooks/frontmatter.js +6 -6
  374. package/dist/hooks/gmail-watcher.js +11 -6
  375. package/dist/hooks/internal-hooks.js +11 -1
  376. package/dist/hooks/llm-slug-generator.js +4 -1
  377. package/dist/hooks/workspace.js +47 -17
  378. package/dist/imessage/accounts.js +9 -20
  379. package/dist/imessage/monitor/inbound-processing.js +2 -1
  380. package/dist/infra/archive.js +174 -73
  381. package/dist/infra/control-ui-assets.js +14 -6
  382. package/dist/infra/device-pairing.js +108 -29
  383. package/dist/infra/env.js +10 -5
  384. package/dist/infra/exec-approvals-allowlist.js +122 -0
  385. package/dist/infra/exec-approvals-analysis.js +34 -3
  386. package/dist/infra/exec-approvals.js +5 -17
  387. package/dist/infra/exec-safe-bin-policy.js +53 -45
  388. package/dist/infra/fs-safe.js +71 -39
  389. package/dist/infra/gateway-lock.js +6 -2
  390. package/dist/infra/heartbeat-wake.js +6 -12
  391. package/dist/infra/host-env-security-policy.json +19 -0
  392. package/dist/infra/host-env-security.js +66 -0
  393. package/dist/infra/net/ssrf.js +131 -38
  394. package/dist/infra/outbound/bound-delivery-router.js +88 -0
  395. package/dist/infra/outbound/channel-selection.js +12 -6
  396. package/dist/infra/outbound/envelope.js +1 -1
  397. package/dist/infra/outbound/format.js +12 -6
  398. package/dist/infra/outbound/payloads.js +14 -7
  399. package/dist/infra/outbound/session-binding-service.js +123 -0
  400. package/dist/infra/path-guards.js +25 -0
  401. package/dist/infra/provider-usage.fetch.codex.js +7 -15
  402. package/dist/infra/provider-usage.fetch.gemini.js +14 -11
  403. package/dist/infra/provider-usage.fetch.shared.js +30 -1
  404. package/dist/infra/provider-usage.fetch.zai.js +10 -9
  405. package/dist/infra/retry-policy.js +4 -2
  406. package/dist/infra/retry.js +9 -5
  407. package/dist/infra/session-cost-usage.js +107 -59
  408. package/dist/infra/session-maintenance-warning.js +3 -1
  409. package/dist/infra/shell-env.js +98 -34
  410. package/dist/infra/ssh-config.js +12 -6
  411. package/dist/infra/system-run-command.js +49 -4
  412. package/dist/infra/update-channels.js +10 -5
  413. package/dist/line/accounts.js +5 -7
  414. package/dist/line/bot-access.js +8 -20
  415. package/dist/line/bot-handlers.js +3 -1
  416. package/dist/link-understanding/detect.js +15 -7
  417. package/dist/media/constants.js +15 -6
  418. package/dist/media/image-ops.js +7 -0
  419. package/dist/media/local-roots.js +3 -2
  420. package/dist/media-understanding/apply.js +4 -1
  421. package/dist/media-understanding/concurrency.js +8 -20
  422. package/dist/memory/backend-config.js +45 -6
  423. package/dist/memory/embeddings.js +10 -4
  424. package/dist/memory/fs-utils.js +23 -0
  425. package/dist/memory/manager-search.js +12 -6
  426. package/dist/memory/manager-sync-ops.js +12 -2
  427. package/dist/memory/qmd-manager.js +466 -53
  428. package/dist/memory/query-expansion.js +167 -3
  429. package/dist/memory/status-format.js +10 -5
  430. package/dist/memory/sync-memory-files.js +1 -1
  431. package/dist/node-host/invoke-system-run.js +281 -0
  432. package/dist/node-host/invoke.js +55 -337
  433. package/dist/pairing/pairing-store.js +22 -0
  434. package/dist/plugin-sdk/allow-from.js +1 -1
  435. package/dist/plugin-sdk/command-auth.js +3 -1
  436. package/dist/plugin-sdk/index.js +6 -3
  437. package/dist/plugin-sdk/webhook-targets.js +32 -0
  438. package/dist/plugins/bundled-dir.js +9 -6
  439. package/dist/plugins/hooks.js +50 -0
  440. package/dist/plugins/install.js +28 -16
  441. package/dist/plugins/runtime.js +3 -17
  442. package/dist/plugins/update.js +78 -12
  443. package/dist/process/spawn-utils.js +14 -7
  444. package/dist/providers/github-copilot-token.js +11 -6
  445. package/dist/providers/qwen-portal-oauth.js +14 -6
  446. package/dist/routing/account-id.js +30 -0
  447. package/dist/routing/resolve-route.js +3 -7
  448. package/dist/routing/session-key.js +2 -16
  449. package/dist/security/audit-channel.js +93 -2
  450. package/dist/security/audit-extra.async.js +159 -5
  451. package/dist/security/audit-extra.js +1 -1
  452. package/dist/security/audit-extra.sync.js +85 -6
  453. package/dist/security/audit.js +40 -4
  454. package/dist/security/dm-policy-shared.js +44 -0
  455. package/dist/security/external-content.js +26 -6
  456. package/dist/shared/entry-status.js +6 -0
  457. package/dist/shared/frontmatter.js +5 -5
  458. package/dist/shared/node-match.js +11 -4
  459. package/dist/shared/operator-scope-compat.js +8 -3
  460. package/dist/signal/accounts.js +7 -20
  461. package/dist/signal/monitor/event-handler.js +3 -1
  462. package/dist/slack/accounts.js +6 -19
  463. package/dist/slack/actions.js +11 -3
  464. package/dist/slack/monitor/auth.js +1 -1
  465. package/dist/slack/monitor/message-handler/dispatch.js +50 -29
  466. package/dist/slack/monitor/replies.js +15 -7
  467. package/dist/slack/monitor/slash.js +22 -13
  468. package/dist/slack/resolve-channels.js +10 -5
  469. package/dist/slack/send.js +102 -12
  470. package/dist/slack/stream-mode.js +10 -0
  471. package/dist/slack/streaming.js +4 -2
  472. package/dist/telegram/accounts.js +19 -14
  473. package/dist/telegram/bot/helpers.js +3 -5
  474. package/dist/telegram/bot-access.js +35 -36
  475. package/dist/telegram/bot-handlers.js +120 -148
  476. package/dist/telegram/bot-message-context.js +68 -9
  477. package/dist/telegram/bot-message-dispatch.js +155 -90
  478. package/dist/telegram/bot-native-commands.js +16 -0
  479. package/dist/telegram/draft-stream.js +14 -1
  480. package/dist/telegram/inline-buttons.js +5 -15
  481. package/dist/telegram/monitor.js +11 -7
  482. package/dist/telegram/network-config.js +19 -7
  483. package/dist/telegram/send.js +3 -2
  484. package/dist/telegram/sent-message-cache.js +5 -6
  485. package/dist/telegram/status-reaction-variants.js +208 -0
  486. package/dist/telegram/sticker-cache.js +11 -9
  487. package/dist/terminal/theme.js +12 -12
  488. package/dist/tts/tts.js +80 -567
  489. package/dist/tui/components/chat-log.js +41 -8
  490. package/dist/tui/theme/theme.js +10 -12
  491. package/dist/tui/tui-local-shell.js +16 -6
  492. package/dist/tui/tui.js +58 -6
  493. package/dist/utils/account-id.js +2 -4
  494. package/dist/utils/boolean.js +10 -5
  495. package/dist/utils/directive-tags.js +11 -0
  496. package/dist/utils/queue-helpers.js +67 -12
  497. package/dist/web/auto-reply/deliver-reply.js +8 -4
  498. package/dist/web/auto-reply/mentions.js +10 -5
  499. package/dist/web/auto-reply/monitor/group-members.js +14 -7
  500. package/dist/web/auto-reply/monitor/process-message.js +45 -24
  501. package/dist/web/inbound/access-control.js +5 -2
  502. package/dist/web/login-qr.js +12 -6
  503. package/dist/web/media.js +123 -16
  504. package/extensions/bluebubbles/src/monitor-processing.ts +580 -139
  505. package/extensions/bluebubbles/src/monitor.ts +208 -1950
  506. package/package.json +1 -1
package/dist/tts/tts.js CHANGED
@@ -1,20 +1,18 @@
1
+ import { randomBytes } from "node:crypto";
1
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync, mkdtempSync, rmSync, renameSync, unlinkSync, } from "node:fs";
2
- import { tmpdir } from "node:os";
3
3
  import path from "node:path";
4
- import { completeSimple } from "@mariozechner/pi-ai";
5
- import { EdgeTTS } from "node-edge-tts";
6
4
  import { normalizeChannelId } from "../channels/plugins/index.js";
7
5
  import { logVerbose } from "../globals.js";
6
+ import { resolvePreferredPoolbotTmpDir } from "../infra/tmp-poolbot-dir.js";
7
+ import { stripMarkdown } from "../line/markdown-to-line.js";
8
8
  import { isVoiceCompatibleAudio } from "../media/audio.js";
9
9
  import { CONFIG_DIR, resolveUserPath } from "../utils.js";
10
- import { getApiKeyForModel, requireApiKey } from "../agents/model-auth.js";
11
- import { buildModelAliasIndex, resolveDefaultModelForAgent, resolveModelRefFromString, } from "../agents/model-selection.js";
12
- import { resolveModel } from "../agents/pi-embedded-runner/model.js";
10
+ import { edgeTTS, elevenLabsTTS, inferEdgeExtension, isValidOpenAIModel, isValidOpenAIVoice, isValidVoiceId, OPENAI_TTS_MODELS, OPENAI_TTS_VOICES, openaiTTS, parseTtsDirectives, scheduleCleanup, summarizeText, } from "./tts-core.js";
11
+ export { OPENAI_TTS_MODELS, OPENAI_TTS_VOICES } from "./tts-core.js";
13
12
  const DEFAULT_TIMEOUT_MS = 30_000;
14
13
  const DEFAULT_TTS_MAX_LENGTH = 1500;
15
14
  const DEFAULT_TTS_SUMMARIZE = true;
16
15
  const DEFAULT_MAX_TEXT_LENGTH = 4096;
17
- const TEMP_FILE_CLEANUP_DELAY_MS = 5 * 60 * 1000; // 5 minutes
18
16
  const DEFAULT_ELEVENLABS_BASE_URL = "https://api.elevenlabs.io";
19
17
  const DEFAULT_ELEVENLABS_VOICE_ID = "pMsXgVXv3BLzUgSXRplE";
20
18
  const DEFAULT_ELEVENLABS_MODEL_ID = "eleven_multilingual_v2";
@@ -51,8 +49,9 @@ const TELEPHONY_OUTPUT = {
51
49
  const TTS_AUTO_MODES = new Set(["off", "always", "inbound", "tagged"]);
52
50
  let lastTtsAttempt;
53
51
  export function normalizeTtsAutoMode(value) {
54
- if (typeof value !== "string")
52
+ if (typeof value !== "string") {
55
53
  return undefined;
54
+ }
56
55
  const normalized = value.trim().toLowerCase();
57
56
  if (TTS_AUTO_MODES.has(normalized)) {
58
57
  return normalized;
@@ -73,11 +72,12 @@ function resolveModelOverridePolicy(overrides) {
73
72
  allowSeed: false,
74
73
  };
75
74
  }
76
- const allow = (value) => value ?? true;
75
+ const allow = (value, defaultValue = true) => value ?? defaultValue;
77
76
  return {
78
77
  enabled: true,
79
78
  allowText: allow(overrides?.allowText),
80
- allowProvider: allow(overrides?.allowProvider),
79
+ // Provider switching is higher-impact than voice/style tweaks; keep opt-in.
80
+ allowProvider: allow(overrides?.allowProvider, false),
81
81
  allowVoice: allow(overrides?.allowVoice),
82
82
  allowModelId: allow(overrides?.allowModelId),
83
83
  allowVoiceSettings: allow(overrides?.allowVoiceSettings),
@@ -139,17 +139,20 @@ export function resolveTtsConfig(cfg) {
139
139
  };
140
140
  }
141
141
  export function resolveTtsPrefsPath(config) {
142
- if (config.prefsPath?.trim())
142
+ if (config.prefsPath?.trim()) {
143
143
  return resolveUserPath(config.prefsPath.trim());
144
- const envPath = process.env.POOLBOT_TTS_PREFS?.trim() || process.env.CLAWDBOT_TTS_PREFS?.trim();
145
- if (envPath)
144
+ }
145
+ const envPath = process.env.POOLBOT_TTS_PREFS?.trim();
146
+ if (envPath) {
146
147
  return resolveUserPath(envPath);
148
+ }
147
149
  return path.join(CONFIG_DIR, "settings", "tts.json");
148
150
  }
149
151
  function resolveTtsAutoModeFromPrefs(prefs) {
150
152
  const auto = normalizeTtsAutoMode(prefs.tts?.auto);
151
- if (auto)
153
+ if (auto) {
152
154
  return auto;
155
+ }
153
156
  if (typeof prefs.tts?.enabled === "boolean") {
154
157
  return prefs.tts.enabled ? "always" : "off";
155
158
  }
@@ -157,19 +160,22 @@ function resolveTtsAutoModeFromPrefs(prefs) {
157
160
  }
158
161
  export function resolveTtsAutoMode(params) {
159
162
  const sessionAuto = normalizeTtsAutoMode(params.sessionAuto);
160
- if (sessionAuto)
163
+ if (sessionAuto) {
161
164
  return sessionAuto;
165
+ }
162
166
  const prefsAuto = resolveTtsAutoModeFromPrefs(readPrefs(params.prefsPath));
163
- if (prefsAuto)
167
+ if (prefsAuto) {
164
168
  return prefsAuto;
169
+ }
165
170
  return params.config.auto;
166
171
  }
167
172
  export function buildTtsSystemPromptHint(cfg) {
168
173
  const config = resolveTtsConfig(cfg);
169
174
  const prefsPath = resolveTtsPrefsPath(config);
170
175
  const autoMode = resolveTtsAutoMode({ config, prefsPath });
171
- if (autoMode === "off")
176
+ if (autoMode === "off") {
172
177
  return undefined;
178
+ }
173
179
  const maxLength = getTtsMaxLength(prefsPath);
174
180
  const summarize = isSummarizationEnabled(prefsPath) ? "on" : "off";
175
181
  const autoHint = autoMode === "inbound"
@@ -188,8 +194,9 @@ export function buildTtsSystemPromptHint(cfg) {
188
194
  }
189
195
  function readPrefs(prefsPath) {
190
196
  try {
191
- if (!existsSync(prefsPath))
197
+ if (!existsSync(prefsPath)) {
192
198
  return {};
199
+ }
193
200
  return JSON.parse(readFileSync(prefsPath, "utf8"));
194
201
  }
195
202
  catch {
@@ -197,8 +204,8 @@ function readPrefs(prefsPath) {
197
204
  }
198
205
  }
199
206
  function atomicWriteFileSync(filePath, content) {
200
- const tmpPath = `${filePath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
201
- writeFileSync(tmpPath, content);
207
+ const tmpPath = `${filePath}.tmp.${Date.now()}.${randomBytes(8).toString("hex")}`;
208
+ writeFileSync(tmpPath, content, { mode: 0o600 });
202
209
  try {
203
210
  renameSync(tmpPath, filePath);
204
211
  }
@@ -234,14 +241,18 @@ export function setTtsEnabled(prefsPath, enabled) {
234
241
  }
235
242
  export function getTtsProvider(config, prefsPath) {
236
243
  const prefs = readPrefs(prefsPath);
237
- if (prefs.tts?.provider)
244
+ if (prefs.tts?.provider) {
238
245
  return prefs.tts.provider;
239
- if (config.providerSource === "config")
246
+ }
247
+ if (config.providerSource === "config") {
240
248
  return config.provider;
241
- if (resolveTtsApiKey(config, "openai"))
249
+ }
250
+ if (resolveTtsApiKey(config, "openai")) {
242
251
  return "openai";
243
- if (resolveTtsApiKey(config, "elevenlabs"))
252
+ }
253
+ if (resolveTtsApiKey(config, "elevenlabs")) {
244
254
  return "elevenlabs";
255
+ }
245
256
  return "edge";
246
257
  }
247
258
  export function setTtsProvider(prefsPath, provider) {
@@ -274,8 +285,9 @@ export function setLastTtsAttempt(entry) {
274
285
  lastTtsAttempt = entry;
275
286
  }
276
287
  function resolveOutputFormat(channelId) {
277
- if (channelId === "telegram")
288
+ if (channelId === "telegram") {
278
289
  return TELEGRAM_OUTPUT;
290
+ }
279
291
  return DEFAULT_OUTPUT;
280
292
  }
281
293
  function resolveChannelId(channel) {
@@ -298,518 +310,17 @@ export function resolveTtsProviderOrder(primary) {
298
310
  return [primary, ...TTS_PROVIDERS.filter((provider) => provider !== primary)];
299
311
  }
300
312
  export function isTtsProviderConfigured(config, provider) {
301
- if (provider === "edge")
313
+ if (provider === "edge") {
302
314
  return config.edge.enabled;
303
- return Boolean(resolveTtsApiKey(config, provider));
304
- }
305
- function isValidVoiceId(voiceId) {
306
- return /^[a-zA-Z0-9]{10,40}$/.test(voiceId);
307
- }
308
- function normalizeElevenLabsBaseUrl(baseUrl) {
309
- const trimmed = baseUrl.trim();
310
- if (!trimmed)
311
- return DEFAULT_ELEVENLABS_BASE_URL;
312
- return trimmed.replace(/\/+$/, "");
313
- }
314
- function requireInRange(value, min, max, label) {
315
- if (!Number.isFinite(value) || value < min || value > max) {
316
- throw new Error(`${label} must be between ${min} and ${max}`);
317
- }
318
- }
319
- function assertElevenLabsVoiceSettings(settings) {
320
- requireInRange(settings.stability, 0, 1, "stability");
321
- requireInRange(settings.similarityBoost, 0, 1, "similarityBoost");
322
- requireInRange(settings.style, 0, 1, "style");
323
- requireInRange(settings.speed, 0.5, 2, "speed");
324
- }
325
- function normalizeLanguageCode(code) {
326
- const trimmed = code?.trim();
327
- if (!trimmed)
328
- return undefined;
329
- const normalized = trimmed.toLowerCase();
330
- if (!/^[a-z]{2}$/.test(normalized)) {
331
- throw new Error("languageCode must be a 2-letter ISO 639-1 code (e.g. en, de, fr)");
332
- }
333
- return normalized;
334
- }
335
- function normalizeApplyTextNormalization(mode) {
336
- const trimmed = mode?.trim();
337
- if (!trimmed)
338
- return undefined;
339
- const normalized = trimmed.toLowerCase();
340
- if (normalized === "auto" || normalized === "on" || normalized === "off")
341
- return normalized;
342
- throw new Error("applyTextNormalization must be one of: auto, on, off");
343
- }
344
- function normalizeSeed(seed) {
345
- if (seed == null)
346
- return undefined;
347
- const next = Math.floor(seed);
348
- if (!Number.isFinite(next) || next < 0 || next > 4_294_967_295) {
349
- throw new Error("seed must be between 0 and 4294967295");
350
- }
351
- return next;
352
- }
353
- function parseBooleanValue(value) {
354
- const normalized = value.trim().toLowerCase();
355
- if (["true", "1", "yes", "on"].includes(normalized))
356
- return true;
357
- if (["false", "0", "no", "off"].includes(normalized))
358
- return false;
359
- return undefined;
360
- }
361
- function parseNumberValue(value) {
362
- const parsed = Number.parseFloat(value);
363
- return Number.isFinite(parsed) ? parsed : undefined;
364
- }
365
- function parseTtsDirectives(text, policy) {
366
- if (!policy.enabled) {
367
- return { cleanedText: text, overrides: {}, warnings: [], hasDirective: false };
368
- }
369
- const overrides = {};
370
- const warnings = [];
371
- let cleanedText = text;
372
- let hasDirective = false;
373
- const blockRegex = /\[\[tts:text\]\]([\s\S]*?)\[\[\/tts:text\]\]/gi;
374
- cleanedText = cleanedText.replace(blockRegex, (_match, inner) => {
375
- hasDirective = true;
376
- if (policy.allowText && overrides.ttsText == null) {
377
- overrides.ttsText = inner.trim();
378
- }
379
- return "";
380
- });
381
- const directiveRegex = /\[\[tts:([^\]]+)\]\]/gi;
382
- cleanedText = cleanedText.replace(directiveRegex, (_match, body) => {
383
- hasDirective = true;
384
- const tokens = body.split(/\s+/).filter(Boolean);
385
- for (const token of tokens) {
386
- const eqIndex = token.indexOf("=");
387
- if (eqIndex === -1)
388
- continue;
389
- const rawKey = token.slice(0, eqIndex).trim();
390
- const rawValue = token.slice(eqIndex + 1).trim();
391
- if (!rawKey || !rawValue)
392
- continue;
393
- const key = rawKey.toLowerCase();
394
- try {
395
- switch (key) {
396
- case "provider":
397
- if (!policy.allowProvider)
398
- break;
399
- if (rawValue === "openai" || rawValue === "elevenlabs" || rawValue === "edge") {
400
- overrides.provider = rawValue;
401
- }
402
- else {
403
- warnings.push(`unsupported provider "${rawValue}"`);
404
- }
405
- break;
406
- case "voice":
407
- case "openai_voice":
408
- case "openaivoice":
409
- if (!policy.allowVoice)
410
- break;
411
- if (isValidOpenAIVoice(rawValue)) {
412
- overrides.openai = { ...overrides.openai, voice: rawValue };
413
- }
414
- else {
415
- warnings.push(`invalid OpenAI voice "${rawValue}"`);
416
- }
417
- break;
418
- case "voiceid":
419
- case "voice_id":
420
- case "elevenlabs_voice":
421
- case "elevenlabsvoice":
422
- if (!policy.allowVoice)
423
- break;
424
- if (isValidVoiceId(rawValue)) {
425
- overrides.elevenlabs = { ...overrides.elevenlabs, voiceId: rawValue };
426
- }
427
- else {
428
- warnings.push(`invalid ElevenLabs voiceId "${rawValue}"`);
429
- }
430
- break;
431
- case "model":
432
- case "modelid":
433
- case "model_id":
434
- case "elevenlabs_model":
435
- case "elevenlabsmodel":
436
- case "openai_model":
437
- case "openaimodel":
438
- if (!policy.allowModelId)
439
- break;
440
- if (isValidOpenAIModel(rawValue)) {
441
- overrides.openai = { ...overrides.openai, model: rawValue };
442
- }
443
- else {
444
- overrides.elevenlabs = { ...overrides.elevenlabs, modelId: rawValue };
445
- }
446
- break;
447
- case "stability":
448
- if (!policy.allowVoiceSettings)
449
- break;
450
- {
451
- const value = parseNumberValue(rawValue);
452
- if (value == null) {
453
- warnings.push("invalid stability value");
454
- break;
455
- }
456
- requireInRange(value, 0, 1, "stability");
457
- overrides.elevenlabs = {
458
- ...overrides.elevenlabs,
459
- voiceSettings: { ...overrides.elevenlabs?.voiceSettings, stability: value },
460
- };
461
- }
462
- break;
463
- case "similarity":
464
- case "similarityboost":
465
- case "similarity_boost":
466
- if (!policy.allowVoiceSettings)
467
- break;
468
- {
469
- const value = parseNumberValue(rawValue);
470
- if (value == null) {
471
- warnings.push("invalid similarityBoost value");
472
- break;
473
- }
474
- requireInRange(value, 0, 1, "similarityBoost");
475
- overrides.elevenlabs = {
476
- ...overrides.elevenlabs,
477
- voiceSettings: { ...overrides.elevenlabs?.voiceSettings, similarityBoost: value },
478
- };
479
- }
480
- break;
481
- case "style":
482
- if (!policy.allowVoiceSettings)
483
- break;
484
- {
485
- const value = parseNumberValue(rawValue);
486
- if (value == null) {
487
- warnings.push("invalid style value");
488
- break;
489
- }
490
- requireInRange(value, 0, 1, "style");
491
- overrides.elevenlabs = {
492
- ...overrides.elevenlabs,
493
- voiceSettings: { ...overrides.elevenlabs?.voiceSettings, style: value },
494
- };
495
- }
496
- break;
497
- case "speed":
498
- if (!policy.allowVoiceSettings)
499
- break;
500
- {
501
- const value = parseNumberValue(rawValue);
502
- if (value == null) {
503
- warnings.push("invalid speed value");
504
- break;
505
- }
506
- requireInRange(value, 0.5, 2, "speed");
507
- overrides.elevenlabs = {
508
- ...overrides.elevenlabs,
509
- voiceSettings: { ...overrides.elevenlabs?.voiceSettings, speed: value },
510
- };
511
- }
512
- break;
513
- case "speakerboost":
514
- case "speaker_boost":
515
- case "usespeakerboost":
516
- case "use_speaker_boost":
517
- if (!policy.allowVoiceSettings)
518
- break;
519
- {
520
- const value = parseBooleanValue(rawValue);
521
- if (value == null) {
522
- warnings.push("invalid useSpeakerBoost value");
523
- break;
524
- }
525
- overrides.elevenlabs = {
526
- ...overrides.elevenlabs,
527
- voiceSettings: { ...overrides.elevenlabs?.voiceSettings, useSpeakerBoost: value },
528
- };
529
- }
530
- break;
531
- case "normalize":
532
- case "applytextnormalization":
533
- case "apply_text_normalization":
534
- if (!policy.allowNormalization)
535
- break;
536
- overrides.elevenlabs = {
537
- ...overrides.elevenlabs,
538
- applyTextNormalization: normalizeApplyTextNormalization(rawValue),
539
- };
540
- break;
541
- case "language":
542
- case "languagecode":
543
- case "language_code":
544
- if (!policy.allowNormalization)
545
- break;
546
- overrides.elevenlabs = {
547
- ...overrides.elevenlabs,
548
- languageCode: normalizeLanguageCode(rawValue),
549
- };
550
- break;
551
- case "seed":
552
- if (!policy.allowSeed)
553
- break;
554
- overrides.elevenlabs = {
555
- ...overrides.elevenlabs,
556
- seed: normalizeSeed(Number.parseInt(rawValue, 10)),
557
- };
558
- break;
559
- default:
560
- break;
561
- }
562
- }
563
- catch (err) {
564
- warnings.push(err.message);
565
- }
566
- }
567
- return "";
568
- });
569
- return {
570
- cleanedText,
571
- ttsText: overrides.ttsText,
572
- hasDirective,
573
- overrides,
574
- warnings,
575
- };
576
- }
577
- export const OPENAI_TTS_MODELS = ["gpt-4o-mini-tts", "tts-1", "tts-1-hd"];
578
- /**
579
- * Custom OpenAI-compatible TTS endpoint.
580
- * When set, model/voice validation is relaxed to allow non-OpenAI models.
581
- * Example: OPENAI_TTS_BASE_URL=http://localhost:8880/v1
582
- *
583
- * Note: Read at runtime (not module load) to support config.env loading.
584
- */
585
- function getOpenAITtsBaseUrl() {
586
- return (process.env.OPENAI_TTS_BASE_URL?.trim() || "https://api.openai.com/v1").replace(/\/+$/, "");
587
- }
588
- function isCustomOpenAIEndpoint() {
589
- return getOpenAITtsBaseUrl() !== "https://api.openai.com/v1";
590
- }
591
- export const OPENAI_TTS_VOICES = [
592
- "alloy",
593
- "ash",
594
- "coral",
595
- "echo",
596
- "fable",
597
- "onyx",
598
- "nova",
599
- "sage",
600
- "shimmer",
601
- ];
602
- function isValidOpenAIModel(model) {
603
- // Allow any model when using custom endpoint (e.g., Kokoro, LocalAI)
604
- if (isCustomOpenAIEndpoint())
605
- return true;
606
- return OPENAI_TTS_MODELS.includes(model);
607
- }
608
- function isValidOpenAIVoice(voice) {
609
- // Allow any voice when using custom endpoint (e.g., Kokoro Chinese voices)
610
- if (isCustomOpenAIEndpoint())
611
- return true;
612
- return OPENAI_TTS_VOICES.includes(voice);
613
- }
614
- function resolveSummaryModelRef(cfg, config) {
615
- const defaultRef = resolveDefaultModelForAgent({ cfg });
616
- const override = config.summaryModel?.trim();
617
- if (!override)
618
- return { ref: defaultRef, source: "default" };
619
- const aliasIndex = buildModelAliasIndex({ cfg, defaultProvider: defaultRef.provider });
620
- const resolved = resolveModelRefFromString({
621
- raw: override,
622
- defaultProvider: defaultRef.provider,
623
- aliasIndex,
624
- });
625
- if (!resolved)
626
- return { ref: defaultRef, source: "default" };
627
- return { ref: resolved.ref, source: "summaryModel" };
628
- }
629
- function isTextContentBlock(block) {
630
- return block.type === "text";
631
- }
632
- async function summarizeText(params) {
633
- const { text, targetLength, cfg, config, timeoutMs } = params;
634
- if (targetLength < 100 || targetLength > 10_000) {
635
- throw new Error(`Invalid targetLength: ${targetLength}`);
636
- }
637
- const startTime = Date.now();
638
- const { ref } = resolveSummaryModelRef(cfg, config);
639
- const resolved = resolveModel(ref.provider, ref.model, undefined, cfg);
640
- if (!resolved.model) {
641
- throw new Error(resolved.error ?? `Unknown summary model: ${ref.provider}/${ref.model}`);
642
- }
643
- const apiKey = requireApiKey(await getApiKeyForModel({ model: resolved.model, cfg }), ref.provider);
644
- try {
645
- const controller = new AbortController();
646
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
647
- try {
648
- const res = await completeSimple(resolved.model, {
649
- messages: [
650
- {
651
- role: "user",
652
- content: `You are an assistant that summarizes texts concisely while keeping the most important information. ` +
653
- `Summarize the text to approximately ${targetLength} characters. Maintain the original tone and style. ` +
654
- `Reply only with the summary, without additional explanations.\n\n` +
655
- `<text_to_summarize>\n${text}\n</text_to_summarize>`,
656
- timestamp: Date.now(),
657
- },
658
- ],
659
- }, {
660
- apiKey,
661
- maxTokens: Math.ceil(targetLength / 2),
662
- temperature: 0.3,
663
- signal: controller.signal,
664
- });
665
- const summary = res.content
666
- .filter(isTextContentBlock)
667
- .map((block) => block.text.trim())
668
- .filter(Boolean)
669
- .join(" ")
670
- .trim();
671
- if (!summary) {
672
- throw new Error("No summary returned");
673
- }
674
- return {
675
- summary,
676
- latencyMs: Date.now() - startTime,
677
- inputLength: text.length,
678
- outputLength: summary.length,
679
- };
680
- }
681
- finally {
682
- clearTimeout(timeout);
683
- }
684
- }
685
- catch (err) {
686
- const error = err;
687
- if (error.name === "AbortError") {
688
- throw new Error("Summarization timed out", { cause: err });
689
- }
690
- throw err;
691
- }
692
- }
693
- function scheduleCleanup(tempDir, delayMs = TEMP_FILE_CLEANUP_DELAY_MS) {
694
- const timer = setTimeout(() => {
695
- try {
696
- rmSync(tempDir, { recursive: true, force: true });
697
- }
698
- catch {
699
- // ignore cleanup errors
700
- }
701
- }, delayMs);
702
- timer.unref();
703
- }
704
- async function elevenLabsTTS(params) {
705
- const { text, apiKey, baseUrl, voiceId, modelId, outputFormat, seed, applyTextNormalization, languageCode, voiceSettings, timeoutMs, } = params;
706
- if (!isValidVoiceId(voiceId)) {
707
- throw new Error("Invalid voiceId format");
708
- }
709
- assertElevenLabsVoiceSettings(voiceSettings);
710
- const normalizedLanguage = normalizeLanguageCode(languageCode);
711
- const normalizedNormalization = normalizeApplyTextNormalization(applyTextNormalization);
712
- const normalizedSeed = normalizeSeed(seed);
713
- const controller = new AbortController();
714
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
715
- try {
716
- const url = new URL(`${normalizeElevenLabsBaseUrl(baseUrl)}/v1/text-to-speech/${voiceId}`);
717
- if (outputFormat) {
718
- url.searchParams.set("output_format", outputFormat);
719
- }
720
- const response = await fetch(url.toString(), {
721
- method: "POST",
722
- headers: {
723
- "xi-api-key": apiKey,
724
- "Content-Type": "application/json",
725
- Accept: "audio/mpeg",
726
- },
727
- body: JSON.stringify({
728
- text,
729
- model_id: modelId,
730
- seed: normalizedSeed,
731
- apply_text_normalization: normalizedNormalization,
732
- language_code: normalizedLanguage,
733
- voice_settings: {
734
- stability: voiceSettings.stability,
735
- similarity_boost: voiceSettings.similarityBoost,
736
- style: voiceSettings.style,
737
- use_speaker_boost: voiceSettings.useSpeakerBoost,
738
- speed: voiceSettings.speed,
739
- },
740
- }),
741
- signal: controller.signal,
742
- });
743
- if (!response.ok) {
744
- throw new Error(`ElevenLabs API error (${response.status})`);
745
- }
746
- return Buffer.from(await response.arrayBuffer());
747
- }
748
- finally {
749
- clearTimeout(timeout);
750
- }
751
- }
752
- async function openaiTTS(params) {
753
- const { text, apiKey, model, voice, responseFormat, timeoutMs } = params;
754
- if (!isValidOpenAIModel(model)) {
755
- throw new Error(`Invalid model: ${model}`);
756
- }
757
- if (!isValidOpenAIVoice(voice)) {
758
- throw new Error(`Invalid voice: ${voice}`);
759
- }
760
- const controller = new AbortController();
761
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
762
- try {
763
- const response = await fetch(`${getOpenAITtsBaseUrl()}/audio/speech`, {
764
- method: "POST",
765
- headers: {
766
- Authorization: `Bearer ${apiKey}`,
767
- "Content-Type": "application/json",
768
- },
769
- body: JSON.stringify({
770
- model,
771
- input: text,
772
- voice,
773
- response_format: responseFormat,
774
- }),
775
- signal: controller.signal,
776
- });
777
- if (!response.ok) {
778
- throw new Error(`OpenAI TTS API error (${response.status})`);
779
- }
780
- return Buffer.from(await response.arrayBuffer());
781
- }
782
- finally {
783
- clearTimeout(timeout);
784
315
  }
316
+ return Boolean(resolveTtsApiKey(config, provider));
785
317
  }
786
- function inferEdgeExtension(outputFormat) {
787
- const normalized = outputFormat.toLowerCase();
788
- if (normalized.includes("webm"))
789
- return ".webm";
790
- if (normalized.includes("ogg"))
791
- return ".ogg";
792
- if (normalized.includes("opus"))
793
- return ".opus";
794
- if (normalized.includes("wav") || normalized.includes("riff") || normalized.includes("pcm")) {
795
- return ".wav";
318
+ function formatTtsProviderError(provider, err) {
319
+ const error = err instanceof Error ? err : new Error(String(err));
320
+ if (error.name === "AbortError") {
321
+ return `${provider}: request timed out`;
796
322
  }
797
- return ".mp3";
798
- }
799
- async function edgeTTS(params) {
800
- const { text, outputPath, config, timeoutMs } = params;
801
- const tts = new EdgeTTS({
802
- voice: config.voice,
803
- lang: config.lang,
804
- outputFormat: config.outputFormat,
805
- saveSubtitles: config.saveSubtitles,
806
- proxy: config.proxy,
807
- rate: config.rate,
808
- pitch: config.pitch,
809
- volume: config.volume,
810
- timeout: config.timeoutMs ?? timeoutMs,
811
- });
812
- await tts.ttsPromise(text, outputPath);
323
+ return `${provider}: ${error.message}`;
813
324
  }
814
325
  export async function textToSpeech(params) {
815
326
  const config = resolveTtsConfig(params.cfg);
@@ -826,16 +337,18 @@ export async function textToSpeech(params) {
826
337
  const overrideProvider = params.overrides?.provider;
827
338
  const provider = overrideProvider ?? userProvider;
828
339
  const providers = resolveTtsProviderOrder(provider);
829
- let lastError;
340
+ const errors = [];
830
341
  for (const provider of providers) {
831
342
  const providerStart = Date.now();
832
343
  try {
833
344
  if (provider === "edge") {
834
345
  if (!config.edge.enabled) {
835
- lastError = "edge: disabled";
346
+ errors.push("edge: disabled");
836
347
  continue;
837
348
  }
838
- const tempDir = mkdtempSync(path.join(tmpdir(), "tts-"));
349
+ const tempRoot = resolvePreferredPoolbotTmpDir();
350
+ mkdirSync(tempRoot, { recursive: true, mode: 0o700 });
351
+ const tempDir = mkdtempSync(path.join(tempRoot, "tts-"));
839
352
  let edgeOutputFormat = resolveEdgeOutputFormat(config);
840
353
  const fallbackEdgeOutputFormat = edgeOutputFormat !== DEFAULT_EDGE_OUTPUT_FORMAT ? DEFAULT_EDGE_OUTPUT_FORMAT : undefined;
841
354
  const attemptEdgeTts = async (outputFormat) => {
@@ -896,7 +409,7 @@ export async function textToSpeech(params) {
896
409
  }
897
410
  const apiKey = resolveTtsApiKey(config, provider);
898
411
  if (!apiKey) {
899
- lastError = `No API key for ${provider}`;
412
+ errors.push(`${provider}: no API key`);
900
413
  continue;
901
414
  }
902
415
  let audioBuffer;
@@ -937,7 +450,9 @@ export async function textToSpeech(params) {
937
450
  });
938
451
  }
939
452
  const latencyMs = Date.now() - providerStart;
940
- const tempDir = mkdtempSync(path.join(tmpdir(), "tts-"));
453
+ const tempRoot = resolvePreferredPoolbotTmpDir();
454
+ mkdirSync(tempRoot, { recursive: true, mode: 0o700 });
455
+ const tempDir = mkdtempSync(path.join(tempRoot, "tts-"));
941
456
  const audioPath = path.join(tempDir, `voice-${Date.now()}${output.extension}`);
942
457
  writeFileSync(audioPath, audioBuffer);
943
458
  scheduleCleanup(tempDir);
@@ -951,18 +466,12 @@ export async function textToSpeech(params) {
951
466
  };
952
467
  }
953
468
  catch (err) {
954
- const error = err;
955
- if (error.name === "AbortError") {
956
- lastError = `${provider}: request timed out`;
957
- }
958
- else {
959
- lastError = `${provider}: ${error.message}`;
960
- }
469
+ errors.push(formatTtsProviderError(provider, err));
961
470
  }
962
471
  }
963
472
  return {
964
473
  success: false,
965
- error: `TTS conversion failed: ${lastError || "no providers available"}`,
474
+ error: `TTS conversion failed: ${errors.join("; ") || "no providers available"}`,
966
475
  };
967
476
  }
968
477
  export async function textToSpeechTelephony(params) {
@@ -976,17 +485,17 @@ export async function textToSpeechTelephony(params) {
976
485
  }
977
486
  const userProvider = getTtsProvider(config, prefsPath);
978
487
  const providers = resolveTtsProviderOrder(userProvider);
979
- let lastError;
488
+ const errors = [];
980
489
  for (const provider of providers) {
981
490
  const providerStart = Date.now();
982
491
  try {
983
492
  if (provider === "edge") {
984
- lastError = "edge: unsupported for telephony";
493
+ errors.push("edge: unsupported for telephony");
985
494
  continue;
986
495
  }
987
496
  const apiKey = resolveTtsApiKey(config, provider);
988
497
  if (!apiKey) {
989
- lastError = `No API key for ${provider}`;
498
+ errors.push(`${provider}: no API key`);
990
499
  continue;
991
500
  }
992
501
  if (provider === "elevenlabs") {
@@ -1032,18 +541,12 @@ export async function textToSpeechTelephony(params) {
1032
541
  };
1033
542
  }
1034
543
  catch (err) {
1035
- const error = err;
1036
- if (error.name === "AbortError") {
1037
- lastError = `${provider}: request timed out`;
1038
- }
1039
- else {
1040
- lastError = `${provider}: ${error.message}`;
1041
- }
544
+ errors.push(formatTtsProviderError(provider, err));
1042
545
  }
1043
546
  }
1044
547
  return {
1045
548
  success: false,
1046
- error: `TTS conversion failed: ${lastError || "no providers available"}`,
549
+ error: `TTS conversion failed: ${errors.join("; ") || "no providers available"}`,
1047
550
  };
1048
551
  }
1049
552
  export async function maybeApplyTtsToPayload(params) {
@@ -1054,8 +557,9 @@ export async function maybeApplyTtsToPayload(params) {
1054
557
  prefsPath,
1055
558
  sessionAuto: params.ttsAuto,
1056
559
  });
1057
- if (autoMode === "off")
560
+ if (autoMode === "off") {
1058
561
  return params.payload;
562
+ }
1059
563
  const text = params.payload.text ?? "";
1060
564
  const directives = parseTtsDirectives(text, config.modelOverrides);
1061
565
  if (directives.warnings.length > 0) {
@@ -1071,32 +575,37 @@ export async function maybeApplyTtsToPayload(params) {
1071
575
  ...params.payload,
1072
576
  text: visibleText.length > 0 ? visibleText : undefined,
1073
577
  };
1074
- if (autoMode === "tagged" && !directives.hasDirective)
578
+ if (autoMode === "tagged" && !directives.hasDirective) {
1075
579
  return nextPayload;
1076
- if (autoMode === "inbound" && params.inboundAudio !== true)
580
+ }
581
+ if (autoMode === "inbound" && params.inboundAudio !== true) {
1077
582
  return nextPayload;
583
+ }
1078
584
  const mode = config.mode ?? "final";
1079
- if (mode === "final" && params.kind && params.kind !== "final")
585
+ if (mode === "final" && params.kind && params.kind !== "final") {
1080
586
  return nextPayload;
1081
- if (!ttsText.trim())
587
+ }
588
+ if (!ttsText.trim()) {
1082
589
  return nextPayload;
1083
- if (params.payload.mediaUrl || (params.payload.mediaUrls?.length ?? 0) > 0)
590
+ }
591
+ if (params.payload.mediaUrl || (params.payload.mediaUrls?.length ?? 0) > 0) {
1084
592
  return nextPayload;
1085
- if (text.includes("MEDIA:"))
593
+ }
594
+ if (text.includes("MEDIA:")) {
1086
595
  return nextPayload;
1087
- if (ttsText.trim().length < 10)
596
+ }
597
+ if (ttsText.trim().length < 10) {
1088
598
  return nextPayload;
599
+ }
1089
600
  const maxLength = getTtsMaxLength(prefsPath);
1090
601
  let textForAudio = ttsText.trim();
1091
602
  let wasSummarized = false;
1092
603
  if (textForAudio.length > maxLength) {
1093
604
  if (!isSummarizationEnabled(prefsPath)) {
1094
- // Truncate text when summarization is disabled
1095
605
  logVerbose(`TTS: truncating long text (${textForAudio.length} > ${maxLength}), summarization disabled.`);
1096
606
  textForAudio = `${textForAudio.slice(0, maxLength - 3)}...`;
1097
607
  }
1098
608
  else {
1099
- // Summarize text when enabled
1100
609
  try {
1101
610
  const summary = await summarizeText({
1102
611
  text: textForAudio,
@@ -1119,6 +628,10 @@ export async function maybeApplyTtsToPayload(params) {
1119
628
  }
1120
629
  }
1121
630
  }
631
+ textForAudio = stripMarkdown(textForAudio).trim(); // strip markdown for TTS (### → "hashtag" etc.)
632
+ if (textForAudio.length < 10) {
633
+ return nextPayload;
634
+ }
1122
635
  const ttsStart = Date.now();
1123
636
  const result = await textToSpeech({
1124
637
  text: textForAudio,