@poolzin/pool-bot 2026.2.21 → 2026.2.23

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 (378) hide show
  1. package/CHANGELOG.md +25 -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/device-pair/index.ts +2 -2
  326. package/extensions/diagnostics-otel/package.json +1 -1
  327. package/extensions/discord/package.json +1 -1
  328. package/extensions/feishu/package.json +1 -1
  329. package/extensions/google-antigravity-auth/package.json +1 -1
  330. package/extensions/google-gemini-cli-auth/package.json +1 -1
  331. package/extensions/googlechat/package.json +1 -1
  332. package/extensions/imessage/package.json +1 -1
  333. package/extensions/irc/package.json +1 -1
  334. package/extensions/irc/src/accounts.ts +1 -1
  335. package/extensions/irc/src/onboarding.ts +4 -4
  336. package/extensions/line/package.json +1 -1
  337. package/extensions/llm-task/package.json +1 -1
  338. package/extensions/lobster/package.json +1 -1
  339. package/extensions/matrix/CHANGELOG.md +10 -0
  340. package/extensions/matrix/package.json +1 -1
  341. package/extensions/mattermost/package.json +1 -1
  342. package/extensions/memory-core/package.json +1 -1
  343. package/extensions/memory-lancedb/package.json +1 -1
  344. package/extensions/minimax-portal-auth/package.json +1 -1
  345. package/extensions/msteams/CHANGELOG.md +10 -0
  346. package/extensions/msteams/package.json +1 -1
  347. package/extensions/nextcloud-talk/package.json +1 -1
  348. package/extensions/nostr/CHANGELOG.md +10 -0
  349. package/extensions/nostr/package.json +1 -1
  350. package/extensions/open-prose/package.json +1 -1
  351. package/extensions/openai-codex-auth/package.json +1 -1
  352. package/extensions/signal/package.json +1 -1
  353. package/extensions/slack/package.json +1 -1
  354. package/extensions/telegram/package.json +1 -1
  355. package/extensions/tlon/package.json +1 -1
  356. package/extensions/twitch/CHANGELOG.md +10 -0
  357. package/extensions/twitch/package.json +1 -1
  358. package/extensions/voice-call/CHANGELOG.md +10 -0
  359. package/extensions/voice-call/package.json +1 -1
  360. package/extensions/whatsapp/package.json +1 -1
  361. package/extensions/zalo/CHANGELOG.md +10 -0
  362. package/extensions/zalo/package.json +1 -1
  363. package/extensions/zalouser/CHANGELOG.md +10 -0
  364. package/extensions/zalouser/package.json +1 -1
  365. package/package.json +1 -1
  366. package/skills/apple-reminders/SKILL.md +100 -49
  367. package/skills/coding-agent/SKILL.md +34 -28
  368. package/skills/github/SKILL.md +131 -16
  369. package/skills/imsg/SKILL.md +112 -15
  370. package/skills/openhue/SKILL.md +101 -19
  371. package/skills/tmux/SKILL.md +111 -79
  372. package/skills/weather/SKILL.md +88 -25
  373. package/dist/agents/openclaw-tools.js +0 -151
  374. package/dist/agents/tool-security.js +0 -96
  375. package/dist/gateway/url-validation.js +0 -94
  376. package/dist/infra/openclaw-root.js +0 -109
  377. package/dist/infra/tmp-openclaw-dir.js +0 -81
  378. package/dist/media/path-sanitization.js +0 -78
@@ -2,33 +2,20 @@ import { chunkByParagraph, chunkMarkdownTextWithMode, resolveChunkMode, resolveT
2
2
  import { resolveChannelMediaMaxBytes } from "../../channels/plugins/media-limits.js";
3
3
  import { loadChannelOutboundAdapter } from "../../channels/plugins/outbound/load.js";
4
4
  import { resolveMarkdownTableMode } from "../../config/markdown-tables.js";
5
+ import { appendAssistantMessageToSessionTranscript, resolveMirroredTranscriptText, } from "../../config/sessions.js";
6
+ import { createInternalHookEvent, triggerInternalHook } from "../../hooks/internal-hooks.js";
7
+ import { getAgentScopedMediaLocalRoots } from "../../media/local-roots.js";
8
+ import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
5
9
  import { markdownToSignalTextChunks } from "../../signal/format.js";
6
10
  import { sendMessageSignal } from "../../signal/send.js";
7
- import { appendAssistantMessageToSessionTranscript, resolveMirroredTranscriptText, } from "../../config/sessions.js";
11
+ import { throwIfAborted } from "./abort.js";
12
+ import { ackDelivery, enqueueDelivery, failDelivery } from "./delivery-queue.js";
8
13
  import { normalizeReplyPayloadsForDelivery } from "./payloads.js";
9
14
  export { normalizeOutboundPayloads } from "./payloads.js";
10
- function throwIfAborted(abortSignal) {
11
- if (abortSignal?.aborted) {
12
- throw new Error("Outbound delivery aborted");
13
- }
14
- }
15
15
  // Channel docking: outbound delivery delegates to plugin.outbound adapters.
16
16
  async function createChannelHandler(params) {
17
17
  const outbound = await loadChannelOutboundAdapter(params.channel);
18
- if (!outbound?.sendText || !outbound?.sendMedia) {
19
- throw new Error(`Outbound not configured for channel: ${params.channel}`);
20
- }
21
- const handler = createPluginHandler({
22
- outbound,
23
- cfg: params.cfg,
24
- channel: params.channel,
25
- to: params.to,
26
- accountId: params.accountId,
27
- replyToId: params.replyToId,
28
- threadId: params.threadId,
29
- deps: params.deps,
30
- gifPlayback: params.gifPlayback,
31
- });
18
+ const handler = createPluginHandler({ ...params, outbound });
32
19
  if (!handler) {
33
20
  throw new Error(`Outbound not configured for channel: ${params.channel}`);
34
21
  }
@@ -36,59 +23,120 @@ async function createChannelHandler(params) {
36
23
  }
37
24
  function createPluginHandler(params) {
38
25
  const outbound = params.outbound;
39
- if (!outbound?.sendText || !outbound?.sendMedia)
26
+ if (!outbound?.sendText || !outbound?.sendMedia) {
40
27
  return null;
28
+ }
29
+ const baseCtx = createChannelOutboundContextBase(params);
41
30
  const sendText = outbound.sendText;
42
31
  const sendMedia = outbound.sendMedia;
43
32
  const chunker = outbound.chunker ?? null;
44
33
  const chunkerMode = outbound.chunkerMode;
34
+ const resolveCtx = (overrides) => ({
35
+ ...baseCtx,
36
+ replyToId: overrides?.replyToId ?? baseCtx.replyToId,
37
+ threadId: overrides?.threadId ?? baseCtx.threadId,
38
+ });
45
39
  return {
46
40
  chunker,
47
41
  chunkerMode,
48
42
  textChunkLimit: outbound.textChunkLimit,
49
43
  sendPayload: outbound.sendPayload
50
- ? async (payload) => outbound.sendPayload({
51
- cfg: params.cfg,
52
- to: params.to,
44
+ ? async (payload, overrides) => outbound.sendPayload({
45
+ ...resolveCtx(overrides),
53
46
  text: payload.text ?? "",
54
47
  mediaUrl: payload.mediaUrl,
55
- accountId: params.accountId,
56
- replyToId: params.replyToId,
57
- threadId: params.threadId,
58
- gifPlayback: params.gifPlayback,
59
- deps: params.deps,
60
48
  payload,
61
49
  })
62
50
  : undefined,
63
- sendText: async (text) => sendText({
64
- cfg: params.cfg,
65
- to: params.to,
51
+ sendText: async (text, overrides) => sendText({
52
+ ...resolveCtx(overrides),
66
53
  text,
67
- accountId: params.accountId,
68
- replyToId: params.replyToId,
69
- threadId: params.threadId,
70
- gifPlayback: params.gifPlayback,
71
- deps: params.deps,
72
54
  }),
73
- sendMedia: async (caption, mediaUrl) => sendMedia({
74
- cfg: params.cfg,
75
- to: params.to,
55
+ sendMedia: async (caption, mediaUrl, overrides) => sendMedia({
56
+ ...resolveCtx(overrides),
76
57
  text: caption,
77
58
  mediaUrl,
78
- accountId: params.accountId,
79
- replyToId: params.replyToId,
80
- threadId: params.threadId,
81
- gifPlayback: params.gifPlayback,
82
- deps: params.deps,
83
59
  }),
84
60
  };
85
61
  }
62
+ function createChannelOutboundContextBase(params) {
63
+ return {
64
+ cfg: params.cfg,
65
+ to: params.to,
66
+ accountId: params.accountId,
67
+ replyToId: params.replyToId,
68
+ threadId: params.threadId,
69
+ identity: params.identity,
70
+ gifPlayback: params.gifPlayback,
71
+ deps: params.deps,
72
+ silent: params.silent,
73
+ mediaLocalRoots: params.mediaLocalRoots,
74
+ };
75
+ }
76
+ const isAbortError = (err) => err instanceof Error && err.name === "AbortError";
86
77
  export async function deliverOutboundPayloads(params) {
78
+ const { channel, to, payloads } = params;
79
+ // Write-ahead delivery queue: persist before sending, remove after success.
80
+ const queueId = params.skipQueue
81
+ ? null
82
+ : await enqueueDelivery({
83
+ channel,
84
+ to,
85
+ accountId: params.accountId,
86
+ payloads,
87
+ threadId: params.threadId,
88
+ replyToId: params.replyToId,
89
+ bestEffort: params.bestEffort,
90
+ gifPlayback: params.gifPlayback,
91
+ silent: params.silent,
92
+ mirror: params.mirror,
93
+ }).catch(() => null); // Best-effort — don't block delivery if queue write fails.
94
+ // Wrap onError to detect partial failures under bestEffort mode.
95
+ // When bestEffort is true, per-payload errors are caught and passed to onError
96
+ // without throwing — so the outer try/catch never fires. We track whether any
97
+ // payload failed so we can call failDelivery instead of ackDelivery.
98
+ let hadPartialFailure = false;
99
+ const wrappedParams = params.onError
100
+ ? {
101
+ ...params,
102
+ onError: (err, payload) => {
103
+ hadPartialFailure = true;
104
+ params.onError(err, payload);
105
+ },
106
+ }
107
+ : params;
108
+ try {
109
+ const results = await deliverOutboundPayloadsCore(wrappedParams);
110
+ if (queueId) {
111
+ if (hadPartialFailure) {
112
+ await failDelivery(queueId, "partial delivery failure (bestEffort)").catch(() => { });
113
+ }
114
+ else {
115
+ await ackDelivery(queueId).catch(() => { }); // Best-effort cleanup.
116
+ }
117
+ }
118
+ return results;
119
+ }
120
+ catch (err) {
121
+ if (queueId) {
122
+ if (isAbortError(err)) {
123
+ await ackDelivery(queueId).catch(() => { });
124
+ }
125
+ else {
126
+ await failDelivery(queueId, err instanceof Error ? err.message : String(err)).catch(() => { });
127
+ }
128
+ }
129
+ throw err;
130
+ }
131
+ }
132
+ /** Core delivery logic (extracted for queue wrapper). */
133
+ async function deliverOutboundPayloadsCore(params) {
87
134
  const { cfg, channel, to, payloads } = params;
88
135
  const accountId = params.accountId;
89
136
  const deps = params.deps;
90
137
  const abortSignal = params.abortSignal;
91
138
  const sendSignal = params.deps?.sendSignal ?? sendMessageSignal;
139
+ const mediaLocalRoots = getAgentScopedMediaLocalRoots(cfg, params.agentId ?? params.mirror?.agentId);
92
140
  const results = [];
93
141
  const handler = await createChannelHandler({
94
142
  cfg,
@@ -98,7 +146,10 @@ export async function deliverOutboundPayloads(params) {
98
146
  accountId,
99
147
  replyToId: params.replyToId,
100
148
  threadId: params.threadId,
149
+ identity: params.identity,
101
150
  gifPlayback: params.gifPlayback,
151
+ silent: params.silent,
152
+ mediaLocalRoots,
102
153
  });
103
154
  const textLimit = handler.chunker
104
155
  ? resolveTextChunkLimit(cfg, channel, accountId, {
@@ -118,10 +169,10 @@ export async function deliverOutboundPayloads(params) {
118
169
  accountId,
119
170
  })
120
171
  : undefined;
121
- const sendTextChunks = async (text) => {
172
+ const sendTextChunks = async (text, overrides) => {
122
173
  throwIfAborted(abortSignal);
123
174
  if (!handler.chunker || textLimit === undefined) {
124
- results.push(await handler.sendText(text));
175
+ results.push(await handler.sendText(text, overrides));
125
176
  return;
126
177
  }
127
178
  if (chunkMode === "newline") {
@@ -129,15 +180,17 @@ export async function deliverOutboundPayloads(params) {
129
180
  const blockChunks = mode === "markdown"
130
181
  ? chunkMarkdownTextWithMode(text, textLimit, "newline")
131
182
  : chunkByParagraph(text, textLimit);
132
- if (!blockChunks.length && text)
183
+ if (!blockChunks.length && text) {
133
184
  blockChunks.push(text);
185
+ }
134
186
  for (const blockChunk of blockChunks) {
135
187
  const chunks = handler.chunker(blockChunk, textLimit);
136
- if (!chunks.length && blockChunk)
188
+ if (!chunks.length && blockChunk) {
137
189
  chunks.push(blockChunk);
190
+ }
138
191
  for (const chunk of chunks) {
139
192
  throwIfAborted(abortSignal);
140
- results.push(await handler.sendText(chunk));
193
+ results.push(await handler.sendText(chunk, overrides));
141
194
  }
142
195
  }
143
196
  return;
@@ -145,7 +198,7 @@ export async function deliverOutboundPayloads(params) {
145
198
  const chunks = handler.chunker(text, textLimit);
146
199
  for (const chunk of chunks) {
147
200
  throwIfAborted(abortSignal);
148
- results.push(await handler.sendText(chunk));
201
+ results.push(await handler.sendText(chunk, overrides));
149
202
  }
150
203
  };
151
204
  const sendSignalText = async (text, styles) => {
@@ -191,48 +244,161 @@ export async function deliverOutboundPayloads(params) {
191
244
  accountId: accountId ?? undefined,
192
245
  textMode: "plain",
193
246
  textStyles: formatted.styles,
247
+ mediaLocalRoots,
194
248
  })),
195
249
  };
196
250
  };
197
- const normalizedPayloads = normalizeReplyPayloadsForDelivery(payloads);
251
+ const normalizeWhatsAppPayload = (payload) => {
252
+ const hasMedia = Boolean(payload.mediaUrl) || (payload.mediaUrls?.length ?? 0) > 0;
253
+ const rawText = typeof payload.text === "string" ? payload.text : "";
254
+ const normalizedText = rawText.replace(/^(?:[ \t]*\r?\n)+/, "");
255
+ if (!normalizedText.trim()) {
256
+ if (!hasMedia) {
257
+ return null;
258
+ }
259
+ return {
260
+ ...payload,
261
+ text: "",
262
+ };
263
+ }
264
+ return {
265
+ ...payload,
266
+ text: normalizedText,
267
+ };
268
+ };
269
+ const normalizedPayloads = normalizeReplyPayloadsForDelivery(payloads).flatMap((payload) => {
270
+ if (channel !== "whatsapp") {
271
+ return [payload];
272
+ }
273
+ const normalized = normalizeWhatsAppPayload(payload);
274
+ return normalized ? [normalized] : [];
275
+ });
276
+ const hookRunner = getGlobalHookRunner();
277
+ const sessionKeyForInternalHooks = params.mirror?.sessionKey;
198
278
  for (const payload of normalizedPayloads) {
199
279
  const payloadSummary = {
200
280
  text: payload.text ?? "",
201
281
  mediaUrls: payload.mediaUrls ?? (payload.mediaUrl ? [payload.mediaUrl] : []),
202
282
  channelData: payload.channelData,
203
283
  };
284
+ const emitMessageSent = (params) => {
285
+ if (hookRunner?.hasHooks("message_sent")) {
286
+ void hookRunner
287
+ .runMessageSent({
288
+ to,
289
+ content: params.content,
290
+ success: params.success,
291
+ ...(params.error ? { error: params.error } : {}),
292
+ }, {
293
+ channelId: channel,
294
+ accountId: accountId ?? undefined,
295
+ conversationId: to,
296
+ })
297
+ .catch(() => { });
298
+ }
299
+ if (!sessionKeyForInternalHooks) {
300
+ return;
301
+ }
302
+ void triggerInternalHook(createInternalHookEvent("message", "sent", sessionKeyForInternalHooks, {
303
+ to,
304
+ content: params.content,
305
+ success: params.success,
306
+ ...(params.error ? { error: params.error } : {}),
307
+ channelId: channel,
308
+ accountId: accountId ?? undefined,
309
+ conversationId: to,
310
+ messageId: params.messageId,
311
+ })).catch(() => { });
312
+ };
204
313
  try {
205
314
  throwIfAborted(abortSignal);
315
+ // Run message_sending plugin hook (may modify content or cancel)
316
+ let effectivePayload = payload;
317
+ if (hookRunner?.hasHooks("message_sending")) {
318
+ try {
319
+ const sendingResult = await hookRunner.runMessageSending({
320
+ to,
321
+ content: payloadSummary.text,
322
+ metadata: { channel, accountId, mediaUrls: payloadSummary.mediaUrls },
323
+ }, {
324
+ channelId: channel,
325
+ accountId: accountId ?? undefined,
326
+ });
327
+ if (sendingResult?.cancel) {
328
+ continue;
329
+ }
330
+ if (sendingResult?.content != null) {
331
+ effectivePayload = { ...payload, text: sendingResult.content };
332
+ payloadSummary.text = sendingResult.content;
333
+ }
334
+ }
335
+ catch {
336
+ // Don't block delivery on hook failure
337
+ }
338
+ }
206
339
  params.onPayload?.(payloadSummary);
207
- if (handler.sendPayload && payload.channelData) {
208
- results.push(await handler.sendPayload(payload));
340
+ const sendOverrides = {
341
+ replyToId: effectivePayload.replyToId ?? params.replyToId ?? undefined,
342
+ threadId: params.threadId ?? undefined,
343
+ };
344
+ if (handler.sendPayload && effectivePayload.channelData) {
345
+ const delivery = await handler.sendPayload(effectivePayload, sendOverrides);
346
+ results.push(delivery);
347
+ emitMessageSent({
348
+ success: true,
349
+ content: payloadSummary.text,
350
+ messageId: delivery.messageId,
351
+ });
209
352
  continue;
210
353
  }
211
354
  if (payloadSummary.mediaUrls.length === 0) {
355
+ const beforeCount = results.length;
212
356
  if (isSignalChannel) {
213
357
  await sendSignalTextChunks(payloadSummary.text);
214
358
  }
215
359
  else {
216
- await sendTextChunks(payloadSummary.text);
360
+ await sendTextChunks(payloadSummary.text, sendOverrides);
217
361
  }
362
+ const messageId = results.at(-1)?.messageId;
363
+ emitMessageSent({
364
+ success: results.length > beforeCount,
365
+ content: payloadSummary.text,
366
+ messageId,
367
+ });
218
368
  continue;
219
369
  }
220
370
  let first = true;
371
+ let lastMessageId;
221
372
  for (const url of payloadSummary.mediaUrls) {
222
373
  throwIfAborted(abortSignal);
223
374
  const caption = first ? payloadSummary.text : "";
224
375
  first = false;
225
376
  if (isSignalChannel) {
226
- results.push(await sendSignalMedia(caption, url));
377
+ const delivery = await sendSignalMedia(caption, url);
378
+ results.push(delivery);
379
+ lastMessageId = delivery.messageId;
227
380
  }
228
381
  else {
229
- results.push(await handler.sendMedia(caption, url));
382
+ const delivery = await handler.sendMedia(caption, url, sendOverrides);
383
+ results.push(delivery);
384
+ lastMessageId = delivery.messageId;
230
385
  }
231
386
  }
387
+ emitMessageSent({
388
+ success: true,
389
+ content: payloadSummary.text,
390
+ messageId: lastMessageId,
391
+ });
232
392
  }
233
393
  catch (err) {
234
- if (!params.bestEffort)
394
+ emitMessageSent({
395
+ success: false,
396
+ content: payloadSummary.text,
397
+ error: err instanceof Error ? err.message : String(err),
398
+ });
399
+ if (!params.bestEffort) {
235
400
  throw err;
401
+ }
236
402
  params.onError?.(err, payloadSummary);
237
403
  }
238
404
  }
@@ -42,12 +42,14 @@ export const MESSAGE_ACTION_TARGET_MODE = {
42
42
  "category-create": "none",
43
43
  "category-edit": "none",
44
44
  "category-delete": "none",
45
+ "topic-create": "to",
45
46
  "voice-status": "none",
46
47
  "event-list": "none",
47
48
  "event-create": "none",
48
49
  timeout: "none",
49
50
  kick: "none",
50
51
  ban: "none",
52
+ "set-presence": "none",
51
53
  };
52
54
  const ACTION_TARGET_ALIASES = {
53
55
  unsend: ["messageId"],
@@ -64,20 +66,25 @@ export function actionRequiresTarget(action) {
64
66
  }
65
67
  export function actionHasTarget(action, params) {
66
68
  const to = typeof params.to === "string" ? params.to.trim() : "";
67
- if (to)
69
+ if (to) {
68
70
  return true;
71
+ }
69
72
  const channelId = typeof params.channelId === "string" ? params.channelId.trim() : "";
70
- if (channelId)
73
+ if (channelId) {
71
74
  return true;
75
+ }
72
76
  const aliases = ACTION_TARGET_ALIASES[action];
73
- if (!aliases)
77
+ if (!aliases) {
74
78
  return false;
79
+ }
75
80
  return aliases.some((alias) => {
76
81
  const value = params[alias];
77
- if (typeof value === "string")
82
+ if (typeof value === "string") {
78
83
  return value.trim().length > 0;
79
- if (typeof value === "number")
84
+ }
85
+ if (typeof value === "number") {
80
86
  return Number.isFinite(value);
87
+ }
81
88
  return false;
82
89
  });
83
90
  }
@@ -2,7 +2,7 @@ import { getChannelPlugin } from "../../channels/plugins/index.js";
2
2
  import { recordSessionMetaFromInbound, resolveStorePath } from "../../config/sessions.js";
3
3
  import { parseDiscordTarget } from "../../discord/targets.js";
4
4
  import { parseIMessageTarget, normalizeIMessageHandle } from "../../imessage/targets.js";
5
- import { buildAgentSessionKey, } from "../../routing/resolve-route.js";
5
+ import { buildAgentSessionKey } from "../../routing/resolve-route.js";
6
6
  import { resolveThreadSessionKeys } from "../../routing/session-key.js";
7
7
  import { resolveSignalPeerId, resolveSignalRecipient, resolveSignalSender, } from "../../signal/identity.js";
8
8
  import { resolveSlackAccount } from "../../slack/accounts.js";
@@ -55,7 +55,7 @@ function stripKindPrefix(raw) {
55
55
  function inferPeerKind(params) {
56
56
  const resolvedKind = params.resolvedTarget?.kind;
57
57
  if (resolvedKind === "user") {
58
- return "dm";
58
+ return "direct";
59
59
  }
60
60
  if (resolvedKind === "channel") {
61
61
  return "channel";
@@ -70,7 +70,7 @@ function inferPeerKind(params) {
70
70
  }
71
71
  return "group";
72
72
  }
73
- return "dm";
73
+ return "direct";
74
74
  }
75
75
  function buildBaseSessionKey(params) {
76
76
  return buildAgentSessionKey({
@@ -138,7 +138,7 @@ async function resolveSlackSession(params) {
138
138
  return null;
139
139
  }
140
140
  const isDm = parsed.kind === "user";
141
- let peerKind = isDm ? "dm" : "channel";
141
+ let peerKind = isDm ? "direct" : "channel";
142
142
  if (!isDm && /^G/i.test(parsed.id)) {
143
143
  // Slack mpim/group DMs share the G-prefix; detect to align session keys with inbound.
144
144
  const channelType = await resolveSlackChannelType({
@@ -150,7 +150,7 @@ async function resolveSlackSession(params) {
150
150
  peerKind = "group";
151
151
  }
152
152
  if (channelType === "dm") {
153
- peerKind = "dm";
153
+ peerKind = "direct";
154
154
  }
155
155
  }
156
156
  const peer = {
@@ -173,13 +173,13 @@ async function resolveSlackSession(params) {
173
173
  sessionKey: threadKeys.sessionKey,
174
174
  baseSessionKey,
175
175
  peer,
176
- chatType: peerKind === "dm" ? "direct" : "channel",
177
- from: peerKind === "dm"
176
+ chatType: peerKind === "direct" ? "direct" : "channel",
177
+ from: peerKind === "direct"
178
178
  ? `slack:${parsed.id}`
179
179
  : peerKind === "group"
180
180
  ? `slack:group:${parsed.id}`
181
181
  : `slack:channel:${parsed.id}`,
182
- to: peerKind === "dm" ? `user:${parsed.id}` : `channel:${parsed.id}`,
182
+ to: peerKind === "direct" ? `user:${parsed.id}` : `channel:${parsed.id}`,
183
183
  threadId,
184
184
  };
185
185
  }
@@ -190,7 +190,7 @@ function resolveDiscordSession(params) {
190
190
  }
191
191
  const isDm = parsed.kind === "user";
192
192
  const peer = {
193
- kind: isDm ? "dm" : "channel",
193
+ kind: isDm ? "direct" : "channel",
194
194
  id: parsed.id,
195
195
  };
196
196
  const baseSessionKey = buildBaseSessionKey({
@@ -236,7 +236,7 @@ function resolveTelegramSession(params) {
236
236
  params.resolvedTarget.kind !== "user");
237
237
  const peerId = isGroup ? buildTelegramGroupPeerId(chatId, resolvedThreadId) : chatId;
238
238
  const peer = {
239
- kind: isGroup ? "group" : "dm",
239
+ kind: isGroup ? "group" : "direct",
240
240
  id: peerId,
241
241
  };
242
242
  const baseSessionKey = buildBaseSessionKey({
@@ -263,7 +263,7 @@ function resolveWhatsAppSession(params) {
263
263
  }
264
264
  const isGroup = isWhatsAppGroupJid(normalized);
265
265
  const peer = {
266
- kind: isGroup ? "group" : "dm",
266
+ kind: isGroup ? "group" : "direct",
267
267
  id: normalized,
268
268
  };
269
269
  const baseSessionKey = buildBaseSessionKey({
@@ -326,7 +326,7 @@ function resolveSignalSession(params) {
326
326
  });
327
327
  const peerId = sender ? resolveSignalPeerId(sender) : recipient;
328
328
  const displayRecipient = sender ? resolveSignalRecipient(sender) : recipient;
329
- const peer = { kind: "dm", id: peerId };
329
+ const peer = { kind: "direct", id: peerId };
330
330
  const baseSessionKey = buildBaseSessionKey({
331
331
  cfg: params.cfg,
332
332
  agentId: params.agentId,
@@ -350,7 +350,7 @@ function resolveIMessageSession(params) {
350
350
  if (!handle) {
351
351
  return null;
352
352
  }
353
- const peer = { kind: "dm", id: handle };
353
+ const peer = { kind: "direct", id: handle };
354
354
  const baseSessionKey = buildBaseSessionKey({
355
355
  cfg: params.cfg,
356
356
  agentId: params.agentId,
@@ -404,7 +404,7 @@ function resolveMatrixSession(params) {
404
404
  if (!rawId) {
405
405
  return null;
406
406
  }
407
- const peer = { kind: isUser ? "dm" : "channel", id: rawId };
407
+ const peer = { kind: isUser ? "direct" : "channel", id: rawId };
408
408
  const baseSessionKey = buildBaseSessionKey({
409
409
  cfg: params.cfg,
410
410
  agentId: params.agentId,
@@ -436,7 +436,7 @@ function resolveMSTeamsSession(params) {
436
436
  const conversationId = rawId.split(";")[0] ?? rawId;
437
437
  const isChannel = !isUser && /@thread\.tacv2/i.test(conversationId);
438
438
  const peer = {
439
- kind: isUser ? "dm" : isChannel ? "channel" : "group",
439
+ kind: isUser ? "direct" : isChannel ? "channel" : "group",
440
440
  id: conversationId,
441
441
  };
442
442
  const baseSessionKey = buildBaseSessionKey({
@@ -474,7 +474,7 @@ function resolveMattermostSession(params) {
474
474
  if (!rawId) {
475
475
  return null;
476
476
  }
477
- const peer = { kind: isUser ? "dm" : "channel", id: rawId };
477
+ const peer = { kind: isUser ? "direct" : "channel", id: rawId };
478
478
  const baseSessionKey = buildBaseSessionKey({
479
479
  cfg: params.cfg,
480
480
  agentId: params.agentId,
@@ -515,7 +515,7 @@ function resolveBlueBubblesSession(params) {
515
515
  return null;
516
516
  }
517
517
  const peer = {
518
- kind: isGroup ? "group" : "dm",
518
+ kind: isGroup ? "group" : "direct",
519
519
  id: peerId,
520
520
  };
521
521
  const baseSessionKey = buildBaseSessionKey({
@@ -570,7 +570,7 @@ function resolveZaloSession(params) {
570
570
  }
571
571
  const isGroup = trimmed.toLowerCase().startsWith("group:");
572
572
  const peerId = stripKindPrefix(trimmed);
573
- const peer = { kind: isGroup ? "group" : "dm", id: peerId };
573
+ const peer = { kind: isGroup ? "group" : "direct", id: peerId };
574
574
  const baseSessionKey = buildBaseSessionKey({
575
575
  cfg: params.cfg,
576
576
  agentId: params.agentId,
@@ -597,7 +597,7 @@ function resolveZalouserSession(params) {
597
597
  const isGroup = trimmed.toLowerCase().startsWith("group:");
598
598
  const peerId = stripKindPrefix(trimmed);
599
599
  // Keep DM vs group aligned with inbound sessions for Zalo Personal.
600
- const peer = { kind: isGroup ? "group" : "dm", id: peerId };
600
+ const peer = { kind: isGroup ? "group" : "direct", id: peerId };
601
601
  const baseSessionKey = buildBaseSessionKey({
602
602
  cfg: params.cfg,
603
603
  agentId: params.agentId,
@@ -619,7 +619,7 @@ function resolveNostrSession(params) {
619
619
  if (!trimmed) {
620
620
  return null;
621
621
  }
622
- const peer = { kind: "dm", id: trimmed };
622
+ const peer = { kind: "direct", id: trimmed };
623
623
  const baseSessionKey = buildBaseSessionKey({
624
624
  cfg: params.cfg,
625
625
  agentId: params.agentId,
@@ -680,7 +680,7 @@ function resolveTlonSession(params) {
680
680
  else {
681
681
  peerId = normalizeTlonShip(trimmed);
682
682
  }
683
- const peer = { kind: isGroup ? "group" : "dm", id: peerId };
683
+ const peer = { kind: isGroup ? "group" : "direct", id: peerId };
684
684
  const baseSessionKey = buildBaseSessionKey({
685
685
  cfg: params.cfg,
686
686
  agentId: params.agentId,
@@ -728,7 +728,7 @@ function resolveFeishuSession(params) {
728
728
  isGroup = false;
729
729
  }
730
730
  const peer = {
731
- kind: isGroup ? "group" : "dm",
731
+ kind: isGroup ? "group" : "direct",
732
732
  id: trimmed,
733
733
  };
734
734
  const baseSessionKey = buildBaseSessionKey({
@@ -767,9 +767,11 @@ function resolveFallbackSession(params) {
767
767
  channel: params.channel,
768
768
  peer,
769
769
  });
770
- const chatType = peerKind === "dm" ? "direct" : peerKind === "channel" ? "channel" : "group";
771
- const from = peerKind === "dm" ? `${params.channel}:${peerId}` : `${params.channel}:${peerKind}:${peerId}`;
772
- const toPrefix = peerKind === "dm" ? "user" : "channel";
770
+ const chatType = peerKind === "direct" ? "direct" : peerKind === "channel" ? "channel" : "group";
771
+ const from = peerKind === "direct"
772
+ ? `${params.channel}:${peerId}`
773
+ : `${params.channel}:${peerKind}:${peerId}`;
774
+ const toPrefix = peerKind === "direct" ? "user" : "channel";
773
775
  return {
774
776
  sessionKey: baseSessionKey,
775
777
  baseSessionKey,