@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
@@ -1,9 +1,12 @@
1
1
  import { resolveQueueSettings } from "../auto-reply/reply/queue.js";
2
2
  import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
3
+ import { DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH } from "../config/agent-limits.js";
3
4
  import { loadConfig } from "../config/config.js";
4
5
  import { loadSessionStore, resolveAgentIdFromSessionKey, resolveMainSessionKey, resolveStorePath, } from "../config/sessions.js";
5
6
  import { callGateway } from "../gateway/call.js";
6
- import { normalizeMainKey } from "../routing/session-key.js";
7
+ import { createBoundDeliveryRouter } from "../infra/outbound/bound-delivery-router.js";
8
+ import { getGlobalHookRunner } from "../plugins/hook-runner-global.js";
9
+ import { normalizeAccountId, normalizeMainKey } from "../routing/session-key.js";
7
10
  import { defaultRuntime } from "../runtime.js";
8
11
  import { extractTextFromChatContent } from "../shared/chat-content.js";
9
12
  import { deliveryContextFromSession, mergeDeliveryContext, normalizeDeliveryContext, } from "../utils/delivery-context.js";
@@ -12,11 +15,26 @@ import { buildAnnounceIdFromChildRun, buildAnnounceIdempotencyKey, resolveQueueA
12
15
  import { isEmbeddedPiRunActive, queueEmbeddedPiMessage, waitForEmbeddedPiRunEnd, } from "./pi-embedded.js";
13
16
  import { enqueueAnnounce } from "./subagent-announce-queue.js";
14
17
  import { getSubagentDepthFromSessionStore } from "./subagent-depth.js";
18
+ import { readLatestAssistantReply } from "./tools/agent-step.js";
15
19
  import { sanitizeTextContent, extractAssistantText } from "./tools/sessions-helpers.js";
16
20
  function buildCompletionDeliveryMessage(params) {
17
21
  const findingsText = params.findings.trim();
18
22
  const hasFindings = findingsText.length > 0 && findingsText !== "(no output)";
19
- const header = `✅ Subagent ${params.subagentName} finished`;
23
+ const header = (() => {
24
+ if (params.outcome?.status === "error") {
25
+ return params.spawnMode === "session"
26
+ ? `❌ Subagent ${params.subagentName} failed this task (session remains active)`
27
+ : `❌ Subagent ${params.subagentName} failed`;
28
+ }
29
+ if (params.outcome?.status === "timeout") {
30
+ return params.spawnMode === "session"
31
+ ? `⏱️ Subagent ${params.subagentName} timed out on this task (session remains active)`
32
+ : `⏱️ Subagent ${params.subagentName} timed out`;
33
+ }
34
+ return params.spawnMode === "session"
35
+ ? `✅ Subagent ${params.subagentName} completed this task (session remains active)`
36
+ : `✅ Subagent ${params.subagentName} finished`;
37
+ })();
20
38
  if (!hasFindings) {
21
39
  return header;
22
40
  }
@@ -74,6 +92,16 @@ function extractToolResultText(content) {
74
92
  });
75
93
  return joined?.trim() ?? "";
76
94
  }
95
+ function extractInlineTextContent(content) {
96
+ if (!Array.isArray(content)) {
97
+ return "";
98
+ }
99
+ return (extractTextFromChatContent(content, {
100
+ sanitizeText: sanitizeTextContent,
101
+ normalizeText: (text) => text.trim(),
102
+ joinWith: "",
103
+ }) ?? "");
104
+ }
77
105
  function extractSubagentOutputText(message) {
78
106
  if (!message || typeof message !== "object") {
79
107
  return "";
@@ -89,30 +117,36 @@ function extractSubagentOutputText(message) {
89
117
  return sanitizeTextContent(content);
90
118
  }
91
119
  if (Array.isArray(content)) {
92
- return (extractTextFromChatContent(content, {
93
- sanitizeText: sanitizeTextContent,
94
- normalizeText: (text) => text.trim(),
95
- joinWith: "",
96
- }) ?? "");
120
+ return extractInlineTextContent(content);
97
121
  }
98
122
  return "";
99
123
  }
100
124
  if (role === "toolResult" || role === "tool") {
101
125
  return extractToolResultText(message.content);
102
126
  }
103
- if (typeof content === "string") {
104
- return sanitizeTextContent(content);
105
- }
106
- if (Array.isArray(content)) {
107
- return (extractTextFromChatContent(content, {
108
- sanitizeText: sanitizeTextContent,
109
- normalizeText: (text) => text.trim(),
110
- joinWith: "",
111
- }) ?? "");
127
+ if (role == null) {
128
+ if (typeof content === "string") {
129
+ return sanitizeTextContent(content);
130
+ }
131
+ if (Array.isArray(content)) {
132
+ return extractInlineTextContent(content);
133
+ }
112
134
  }
113
135
  return "";
114
136
  }
115
137
  async function readLatestSubagentOutput(sessionKey) {
138
+ try {
139
+ const latestAssistant = await readLatestAssistantReply({
140
+ sessionKey,
141
+ limit: 50,
142
+ });
143
+ if (latestAssistant?.trim()) {
144
+ return latestAssistant;
145
+ }
146
+ }
147
+ catch {
148
+ // Best-effort: fall back to richer history parsing below.
149
+ }
116
150
  const history = await callGateway({
117
151
  method: "chat.history",
118
152
  params: { sessionKey, limit: 50 },
@@ -140,6 +174,26 @@ async function readLatestSubagentOutputWithRetry(params) {
140
174
  }
141
175
  return result;
142
176
  }
177
+ async function waitForSubagentOutputChange(params) {
178
+ const baseline = params.baselineReply.trim();
179
+ if (!baseline) {
180
+ return params.baselineReply;
181
+ }
182
+ const RETRY_INTERVAL_MS = 100;
183
+ const deadline = Date.now() + Math.max(0, Math.min(params.maxWaitMs, 5_000));
184
+ let latest = params.baselineReply;
185
+ while (Date.now() < deadline) {
186
+ const next = await readLatestSubagentOutput(params.sessionKey);
187
+ if (next?.trim()) {
188
+ latest = next;
189
+ if (next.trim() !== baseline) {
190
+ return next;
191
+ }
192
+ }
193
+ await new Promise((resolve) => setTimeout(resolve, RETRY_INTERVAL_MS));
194
+ }
195
+ return latest;
196
+ }
143
197
  function formatDurationShort(valueMs) {
144
198
  if (!valueMs || !Number.isFinite(valueMs) || valueMs <= 0) {
145
199
  return "n/a";
@@ -197,7 +251,7 @@ async function buildCompactAnnounceStatsLine(params) {
197
251
  if (typeof promptCache === "number" && promptCache > ioTotal) {
198
252
  parts.push(`prompt/cache ${formatTokenCount(promptCache)}`);
199
253
  }
200
- return `Stats: ${parts.join(" ")}`;
254
+ return `Stats: ${parts.join(" \u00b7 ")}`;
201
255
  }
202
256
  function resolveAnnounceOrigin(entry, requesterOrigin) {
203
257
  const normalizedRequester = normalizeDeliveryContext(requesterOrigin);
@@ -213,7 +267,100 @@ function resolveAnnounceOrigin(entry, requesterOrigin) {
213
267
  // requesterOrigin (captured at spawn time) reflects the channel the user is
214
268
  // actually on and must take priority over the session entry, which may carry
215
269
  // stale lastChannel / lastTo values from a previous channel interaction.
216
- return mergeDeliveryContext(normalizedRequester, normalizedEntry);
270
+ const entryForMerge = normalizedRequester?.to &&
271
+ normalizedRequester.threadId == null &&
272
+ normalizedEntry?.threadId != null
273
+ ? (() => {
274
+ const { threadId: _ignore, ...rest } = normalizedEntry;
275
+ return rest;
276
+ })()
277
+ : normalizedEntry;
278
+ return mergeDeliveryContext(normalizedRequester, entryForMerge);
279
+ }
280
+ async function resolveSubagentCompletionOrigin(params) {
281
+ const requesterOrigin = normalizeDeliveryContext(params.requesterOrigin);
282
+ const requesterConversation = (() => {
283
+ const channel = requesterOrigin?.channel?.trim().toLowerCase();
284
+ const to = requesterOrigin?.to?.trim();
285
+ const accountId = normalizeAccountId(requesterOrigin?.accountId);
286
+ const threadId = requesterOrigin?.threadId != null && requesterOrigin.threadId !== ""
287
+ ? String(requesterOrigin.threadId).trim()
288
+ : undefined;
289
+ const conversationId = threadId || (to?.startsWith("channel:") ? to.slice("channel:".length) : "");
290
+ if (!channel || !conversationId) {
291
+ return undefined;
292
+ }
293
+ const ref = {
294
+ channel,
295
+ accountId,
296
+ conversationId,
297
+ };
298
+ return ref;
299
+ })();
300
+ const route = createBoundDeliveryRouter().resolveDestination({
301
+ eventKind: "task_completion",
302
+ targetSessionKey: params.childSessionKey,
303
+ requester: requesterConversation,
304
+ failClosed: false,
305
+ });
306
+ if (route.mode === "bound" && route.binding) {
307
+ const boundOrigin = {
308
+ channel: route.binding.conversation.channel,
309
+ accountId: route.binding.conversation.accountId,
310
+ to: `channel:${route.binding.conversation.conversationId}`,
311
+ threadId: route.binding.conversation.conversationId,
312
+ };
313
+ return {
314
+ // Bound target is authoritative; requester hints fill only missing fields.
315
+ origin: mergeDeliveryContext(boundOrigin, requesterOrigin),
316
+ routeMode: "bound",
317
+ };
318
+ }
319
+ const hookRunner = getGlobalHookRunner();
320
+ if (!hookRunner?.hasHooks("subagent_delivery_target")) {
321
+ return {
322
+ origin: requesterOrigin,
323
+ routeMode: "fallback",
324
+ };
325
+ }
326
+ try {
327
+ const result = await hookRunner.runSubagentDeliveryTarget({
328
+ childSessionKey: params.childSessionKey,
329
+ requesterSessionKey: params.requesterSessionKey,
330
+ requesterOrigin,
331
+ childRunId: params.childRunId,
332
+ spawnMode: params.spawnMode,
333
+ expectsCompletionMessage: params.expectsCompletionMessage,
334
+ }, {
335
+ runId: params.childRunId,
336
+ childSessionKey: params.childSessionKey,
337
+ requesterSessionKey: params.requesterSessionKey,
338
+ });
339
+ const hookOrigin = normalizeDeliveryContext(result?.origin);
340
+ if (!hookOrigin) {
341
+ return {
342
+ origin: requesterOrigin,
343
+ routeMode: "fallback",
344
+ };
345
+ }
346
+ if (hookOrigin.channel && !isDeliverableMessageChannel(hookOrigin.channel)) {
347
+ return {
348
+ origin: requesterOrigin,
349
+ routeMode: "fallback",
350
+ };
351
+ }
352
+ // Hook-provided origin should override requester defaults when present.
353
+ return {
354
+ origin: mergeDeliveryContext(hookOrigin, requesterOrigin),
355
+ routeMode: "hook",
356
+ };
357
+ }
358
+ catch {
359
+ return {
360
+ origin: requesterOrigin,
361
+ routeMode: "fallback",
362
+ };
363
+ }
217
364
  }
218
365
  async function sendAnnounce(item) {
219
366
  const requesterDepth = getSubagentDepthFromSessionStore(item.sessionKey);
@@ -346,26 +493,46 @@ async function sendSubagentAnnounceDirectly(params) {
346
493
  if (params.expectsCompletionMessage &&
347
494
  hasCompletionDirectTarget &&
348
495
  params.completionMessage?.trim()) {
349
- const completionThreadId = completionDirectOrigin?.threadId != null && completionDirectOrigin.threadId !== ""
350
- ? String(completionDirectOrigin.threadId)
351
- : undefined;
352
- await callGateway({
353
- method: "send",
354
- params: {
355
- channel: completionChannel,
356
- to: completionTo,
357
- accountId: completionDirectOrigin?.accountId,
358
- threadId: completionThreadId,
359
- sessionKey: canonicalRequesterSessionKey,
360
- message: params.completionMessage,
361
- idempotencyKey: params.directIdempotencyKey,
362
- },
363
- timeoutMs: 15_000,
364
- });
365
- return {
366
- delivered: true,
367
- path: "direct",
368
- };
496
+ const forceBoundSessionDirectDelivery = params.spawnMode === "session" &&
497
+ (params.completionRouteMode === "bound" || params.completionRouteMode === "hook");
498
+ let shouldSendCompletionDirectly = true;
499
+ if (!forceBoundSessionDirectDelivery) {
500
+ let activeDescendantRuns = 0;
501
+ try {
502
+ const { countActiveDescendantRuns } = await import("./subagent-registry.js");
503
+ activeDescendantRuns = Math.max(0, countActiveDescendantRuns(canonicalRequesterSessionKey));
504
+ }
505
+ catch {
506
+ // Best-effort only; when unavailable keep historical direct-send behavior.
507
+ }
508
+ // Keep non-bound completion announcements coordinated via requester
509
+ // session routing while sibling/descendant runs are still active.
510
+ if (activeDescendantRuns > 0) {
511
+ shouldSendCompletionDirectly = false;
512
+ }
513
+ }
514
+ if (shouldSendCompletionDirectly) {
515
+ const completionThreadId = completionDirectOrigin?.threadId != null && completionDirectOrigin.threadId !== ""
516
+ ? String(completionDirectOrigin.threadId)
517
+ : undefined;
518
+ await callGateway({
519
+ method: "send",
520
+ params: {
521
+ channel: completionChannel,
522
+ to: completionTo,
523
+ accountId: completionDirectOrigin?.accountId,
524
+ threadId: completionThreadId,
525
+ sessionKey: canonicalRequesterSessionKey,
526
+ message: params.completionMessage,
527
+ idempotencyKey: params.directIdempotencyKey,
528
+ },
529
+ timeoutMs: 15_000,
530
+ });
531
+ return {
532
+ delivered: true,
533
+ path: "direct",
534
+ };
535
+ }
369
536
  }
370
537
  const directOrigin = normalizeDeliveryContext(params.directOrigin);
371
538
  const threadId = directOrigin?.threadId != null && directOrigin.threadId !== ""
@@ -423,6 +590,8 @@ async function deliverSubagentAnnouncement(params) {
423
590
  completionMessage: params.completionMessage,
424
591
  directIdempotencyKey: params.directIdempotencyKey,
425
592
  completionDirectOrigin: params.completionDirectOrigin,
593
+ completionRouteMode: params.completionRouteMode,
594
+ spawnMode: params.spawnMode,
426
595
  directOrigin: params.directOrigin,
427
596
  requesterIsSubagent: params.requesterIsSubagent,
428
597
  expectsCompletionMessage: params.expectsCompletionMessage,
@@ -456,7 +625,9 @@ export function buildSubagentSystemPrompt(params) {
456
625
  ? params.task.replace(/\s+/g, " ").trim()
457
626
  : "{{TASK_DESCRIPTION}}";
458
627
  const childDepth = typeof params.childDepth === "number" ? params.childDepth : 1;
459
- const maxSpawnDepth = typeof params.maxSpawnDepth === "number" ? params.maxSpawnDepth : 1;
628
+ const maxSpawnDepth = typeof params.maxSpawnDepth === "number"
629
+ ? params.maxSpawnDepth
630
+ : DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH;
460
631
  const canSpawn = childDepth < maxSpawnDepth;
461
632
  const parentLabel = childDepth >= 2 ? "parent orchestrator" : "main agent";
462
633
  const lines = [
@@ -510,9 +681,6 @@ export function buildSubagentSystemPrompt(params) {
510
681
  return lines.join("\n");
511
682
  }
512
683
  function buildAnnounceReplyInstruction(params) {
513
- if (params.expectsCompletionMessage) {
514
- return `A completed ${params.announceType} is ready for user delivery. Convert the result above into your normal assistant voice and send that user-facing update now. Keep this internal context private (don't mention system/log/stats/session details or announce type).`;
515
- }
516
684
  if (params.remainingActiveSubagentRuns > 0) {
517
685
  const activeRunsLabel = params.remainingActiveSubagentRuns === 1 ? "run" : "runs";
518
686
  return `There are still ${params.remainingActiveSubagentRuns} active subagent ${activeRunsLabel} for this session. If they are part of the same workflow, wait for the remaining results before sending a user update. If they are unrelated, respond normally using only the result above.`;
@@ -520,6 +688,9 @@ function buildAnnounceReplyInstruction(params) {
520
688
  if (params.requesterIsSubagent) {
521
689
  return `Convert this completion into a concise internal orchestration update for your parent agent in your own words. Keep this internal context private (don't mention system/log/stats/session details or announce type). If this result is duplicate or no update is needed, reply ONLY: ${SILENT_REPLY_TOKEN}.`;
522
690
  }
691
+ if (params.expectsCompletionMessage) {
692
+ return `A completed ${params.announceType} is ready for user delivery. Convert the result above into your normal assistant voice and send that user-facing update now. Keep this internal context private (don't mention system/log/stats/session details or announce type).`;
693
+ }
523
694
  return `A completed ${params.announceType} is ready for user delivery. Convert the result above into your normal assistant voice and send that user-facing update now. Keep this internal context private (don't mention system/log/stats/session details or announce type), and do not copy the system message verbatim. Reply ONLY: ${SILENT_REPLY_TOKEN} if this exact result was already delivered to the user in this same turn.`;
524
695
  }
525
696
  export async function runSubagentAnnounceFlow(params) {
@@ -540,7 +711,7 @@ export async function runSubagentAnnounceFlow(params) {
540
711
  let outcome = params.outcome;
541
712
  // Lifecycle "end" can arrive before auto-compaction retries finish. If the
542
713
  // subagent is still active, wait for the embedded run to fully settle.
543
- if (!expectsCompletionMessage && childSessionId && isEmbeddedPiRunActive(childSessionId)) {
714
+ if (childSessionId && isEmbeddedPiRunActive(childSessionId)) {
544
715
  const settled = await waitForEmbeddedPiRunEnd(childSessionId, settleTimeoutMs);
545
716
  if (!settled && isEmbeddedPiRunActive(childSessionId)) {
546
717
  // The child run is still active (e.g., compaction retry still in progress).
@@ -603,6 +774,7 @@ export async function runSubagentAnnounceFlow(params) {
603
774
  if (!outcome) {
604
775
  outcome = { status: "unknown" };
605
776
  }
777
+ let requesterDepth = getSubagentDepthFromSessionStore(targetRequesterSessionKey);
606
778
  let activeChildDescendantRuns = 0;
607
779
  try {
608
780
  const { countActiveDescendantRuns } = await import("./subagent-registry.js");
@@ -611,12 +783,19 @@ export async function runSubagentAnnounceFlow(params) {
611
783
  catch {
612
784
  // Best-effort only; fall back to direct announce behavior when unavailable.
613
785
  }
614
- if (!expectsCompletionMessage && activeChildDescendantRuns > 0) {
786
+ if (activeChildDescendantRuns > 0) {
615
787
  // The finished run still has active descendant subagents. Defer announcing
616
788
  // this run until descendants settle so we avoid posting in-progress updates.
617
789
  shouldDeleteChildSession = false;
618
790
  return false;
619
791
  }
792
+ if (requesterDepth >= 1 && reply?.trim()) {
793
+ reply = await waitForSubagentOutputChange({
794
+ sessionKey: params.childSessionKey,
795
+ baselineReply: reply,
796
+ maxWaitMs: Math.max(250, Math.min(params.timeoutMs, 2_000)),
797
+ });
798
+ }
620
799
  // Build status label
621
800
  const statusLabel = outcome.status === "ok"
622
801
  ? "completed successfully"
@@ -633,8 +812,7 @@ export async function runSubagentAnnounceFlow(params) {
633
812
  const findings = reply || "(no output)";
634
813
  let completionMessage = "";
635
814
  let triggerMessage = "";
636
- let requesterDepth = getSubagentDepthFromSessionStore(targetRequesterSessionKey);
637
- let requesterIsSubagent = !expectsCompletionMessage && requesterDepth >= 1;
815
+ let requesterIsSubagent = requesterDepth >= 1;
638
816
  // If the requester subagent has already finished, bubble the announce to its
639
817
  // requester (typically main) so descendant completion is not silently lost.
640
818
  // BUT: only fallback if the parent SESSION is deleted, not just if the current
@@ -691,6 +869,8 @@ export async function runSubagentAnnounceFlow(params) {
691
869
  completionMessage = buildCompletionDeliveryMessage({
692
870
  findings,
693
871
  subagentName,
872
+ spawnMode: params.spawnMode,
873
+ outcome,
694
874
  });
695
875
  const internalSummaryMessage = [
696
876
  `[System Message] [sessionId: ${announceSessionId}] A ${announceType} "${taskLabel}" just ${statusLabel}.`,
@@ -712,6 +892,20 @@ export async function runSubagentAnnounceFlow(params) {
712
892
  const { entry } = loadRequesterSessionEntry(targetRequesterSessionKey);
713
893
  directOrigin = resolveAnnounceOrigin(entry, targetRequesterOrigin);
714
894
  }
895
+ const completionResolution = expectsCompletionMessage && !requesterIsSubagent
896
+ ? await resolveSubagentCompletionOrigin({
897
+ childSessionKey: params.childSessionKey,
898
+ requesterSessionKey: targetRequesterSessionKey,
899
+ requesterOrigin: directOrigin,
900
+ childRunId: params.childRunId,
901
+ spawnMode: params.spawnMode,
902
+ expectsCompletionMessage,
903
+ })
904
+ : {
905
+ origin: targetRequesterOrigin,
906
+ routeMode: "fallback",
907
+ };
908
+ const completionDirectOrigin = completionResolution.origin;
715
909
  // Use a deterministic idempotency key so the gateway dedup cache
716
910
  // catches duplicates if this announce is also queued by the gateway-
717
911
  // level message queue while the main session is busy (#17122).
@@ -722,12 +916,16 @@ export async function runSubagentAnnounceFlow(params) {
722
916
  triggerMessage,
723
917
  completionMessage,
724
918
  summaryLine: taskLabel,
725
- requesterOrigin: targetRequesterOrigin,
726
- completionDirectOrigin: targetRequesterOrigin,
919
+ requesterOrigin: expectsCompletionMessage && !requesterIsSubagent
920
+ ? completionDirectOrigin
921
+ : targetRequesterOrigin,
922
+ completionDirectOrigin,
727
923
  directOrigin,
728
924
  targetRequesterSessionKey,
729
925
  requesterIsSubagent,
730
926
  expectsCompletionMessage: expectsCompletionMessage,
927
+ completionRouteMode: completionResolution.routeMode,
928
+ spawnMode: params.spawnMode,
731
929
  directIdempotencyKey,
732
930
  });
733
931
  didAnnounce = delivery.delivered;
@@ -757,7 +955,11 @@ export async function runSubagentAnnounceFlow(params) {
757
955
  try {
758
956
  await callGateway({
759
957
  method: "sessions.delete",
760
- params: { key: params.childSessionKey, deleteTranscript: true },
958
+ params: {
959
+ key: params.childSessionKey,
960
+ deleteTranscript: true,
961
+ emitLifecycleHooks: false,
962
+ },
761
963
  timeoutMs: 10_000,
762
964
  });
763
965
  }
@@ -0,0 +1,19 @@
1
+ export const SUBAGENT_TARGET_KIND_SUBAGENT = "subagent";
2
+ export const SUBAGENT_TARGET_KIND_ACP = "acp";
3
+ export const SUBAGENT_ENDED_REASON_COMPLETE = "subagent-complete";
4
+ export const SUBAGENT_ENDED_REASON_ERROR = "subagent-error";
5
+ export const SUBAGENT_ENDED_REASON_KILLED = "subagent-killed";
6
+ export const SUBAGENT_ENDED_REASON_SESSION_RESET = "session-reset";
7
+ export const SUBAGENT_ENDED_REASON_SESSION_DELETE = "session-delete";
8
+ export const SUBAGENT_ENDED_OUTCOME_OK = "ok";
9
+ export const SUBAGENT_ENDED_OUTCOME_ERROR = "error";
10
+ export const SUBAGENT_ENDED_OUTCOME_TIMEOUT = "timeout";
11
+ export const SUBAGENT_ENDED_OUTCOME_KILLED = "killed";
12
+ export const SUBAGENT_ENDED_OUTCOME_RESET = "reset";
13
+ export const SUBAGENT_ENDED_OUTCOME_DELETED = "deleted";
14
+ export function resolveSubagentSessionEndedOutcome(reason) {
15
+ if (reason === SUBAGENT_ENDED_REASON_SESSION_RESET) {
16
+ return SUBAGENT_ENDED_OUTCOME_RESET;
17
+ }
18
+ return SUBAGENT_ENDED_OUTCOME_DELETED;
19
+ }
@@ -0,0 +1,31 @@
1
+ import { SUBAGENT_ENDED_REASON_COMPLETE, } from "./subagent-lifecycle-events.js";
2
+ export function resolveCleanupCompletionReason(entry) {
3
+ return entry.endedReason ?? SUBAGENT_ENDED_REASON_COMPLETE;
4
+ }
5
+ function resolveEndedAgoMs(entry, now) {
6
+ return typeof entry.endedAt === "number" ? now - entry.endedAt : 0;
7
+ }
8
+ export function resolveDeferredCleanupDecision(params) {
9
+ const endedAgo = resolveEndedAgoMs(params.entry, params.now);
10
+ if (params.entry.expectsCompletionMessage === true && params.activeDescendantRuns > 0) {
11
+ if (endedAgo > params.announceExpiryMs) {
12
+ return { kind: "give-up", reason: "expiry" };
13
+ }
14
+ return { kind: "defer-descendants", delayMs: params.deferDescendantDelayMs };
15
+ }
16
+ const retryCount = (params.entry.announceRetryCount ?? 0) + 1;
17
+ if (retryCount >= params.maxAnnounceRetryCount || endedAgo > params.announceExpiryMs) {
18
+ return {
19
+ kind: "give-up",
20
+ reason: retryCount >= params.maxAnnounceRetryCount ? "retry-limit" : "expiry",
21
+ retryCount,
22
+ };
23
+ }
24
+ return {
25
+ kind: "retry",
26
+ retryCount,
27
+ resumeDelayMs: params.entry.expectsCompletionMessage === true
28
+ ? params.resolveAnnounceRetryDelayMs(retryCount)
29
+ : undefined,
30
+ };
31
+ }
@@ -0,0 +1,68 @@
1
+ import { getGlobalHookRunner } from "../plugins/hook-runner-global.js";
2
+ import { SUBAGENT_ENDED_OUTCOME_ERROR, SUBAGENT_ENDED_OUTCOME_OK, SUBAGENT_ENDED_OUTCOME_TIMEOUT, SUBAGENT_TARGET_KIND_SUBAGENT, } from "./subagent-lifecycle-events.js";
3
+ export function runOutcomesEqual(a, b) {
4
+ if (!a && !b) {
5
+ return true;
6
+ }
7
+ if (!a || !b) {
8
+ return false;
9
+ }
10
+ if (a.status !== b.status) {
11
+ return false;
12
+ }
13
+ if (a.status === "error" && b.status === "error") {
14
+ return (a.error ?? "") === (b.error ?? "");
15
+ }
16
+ return true;
17
+ }
18
+ export function resolveLifecycleOutcomeFromRunOutcome(outcome) {
19
+ if (outcome?.status === "error") {
20
+ return SUBAGENT_ENDED_OUTCOME_ERROR;
21
+ }
22
+ if (outcome?.status === "timeout") {
23
+ return SUBAGENT_ENDED_OUTCOME_TIMEOUT;
24
+ }
25
+ return SUBAGENT_ENDED_OUTCOME_OK;
26
+ }
27
+ export async function emitSubagentEndedHookOnce(params) {
28
+ const runId = params.entry.runId.trim();
29
+ if (!runId) {
30
+ return false;
31
+ }
32
+ if (params.entry.endedHookEmittedAt) {
33
+ return false;
34
+ }
35
+ if (params.inFlightRunIds.has(runId)) {
36
+ return false;
37
+ }
38
+ params.inFlightRunIds.add(runId);
39
+ try {
40
+ const hookRunner = getGlobalHookRunner();
41
+ if (hookRunner?.hasHooks("subagent_ended")) {
42
+ await hookRunner.runSubagentEnded({
43
+ targetSessionKey: params.entry.childSessionKey,
44
+ targetKind: SUBAGENT_TARGET_KIND_SUBAGENT,
45
+ reason: params.reason,
46
+ sendFarewell: params.sendFarewell,
47
+ accountId: params.accountId,
48
+ runId: params.entry.runId,
49
+ endedAt: params.entry.endedAt,
50
+ outcome: params.outcome,
51
+ error: params.error,
52
+ }, {
53
+ runId: params.entry.runId,
54
+ childSessionKey: params.entry.childSessionKey,
55
+ requesterSessionKey: params.entry.requesterSessionKey,
56
+ });
57
+ }
58
+ params.entry.endedHookEmittedAt = Date.now();
59
+ params.persist();
60
+ return true;
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ finally {
66
+ params.inFlightRunIds.delete(runId);
67
+ }
68
+ }