@vellumai/assistant 0.12.3-staging.1 → 0.12.3

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 (560) hide show
  1. package/ARCHITECTURE.md +43 -29
  2. package/Dockerfile +63 -0
  3. package/docs/architecture/security.md +10 -5
  4. package/docs/architecture/turn-actor.md +2 -0
  5. package/docs/desktop-browser-cli.md +45 -4
  6. package/docs/live-voice-task-outcomes.md +100 -0
  7. package/docs/mode-sessions.md +183 -0
  8. package/docs/voice-input-diagnostics.md +58 -0
  9. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +2 -1
  10. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  11. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  12. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
  13. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  14. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  15. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -0
  16. package/node_modules/@vellumai/gateway-client/src/index.ts +4 -1
  17. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +38 -7
  18. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +5 -6
  19. package/node_modules/@vellumai/service-contracts/package.json +2 -1
  20. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  21. package/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  22. package/node_modules/@vellumai/slack-text/src/index.ts +4 -8
  23. package/openapi.yaml +665 -14
  24. package/package.json +1 -1
  25. package/scripts/smoke-desktop-browser-cli.ts +10 -26
  26. package/scripts/smoke-desktop-window-theme.ts +2 -3
  27. package/src/__tests__/agent-loop-output-hooks.test.ts +150 -1
  28. package/src/__tests__/agent-loop-provider-error-recording.test.ts +87 -19
  29. package/src/__tests__/annotate-activity-metadata.test.ts +3 -1
  30. package/src/__tests__/annotate-risk-options.test.ts +2 -0
  31. package/src/__tests__/answered-question-persistence.test.ts +2 -0
  32. package/src/__tests__/anthropic-gateway-shared.test.ts +22 -0
  33. package/src/__tests__/approval-message-composer.test.ts +1 -118
  34. package/src/__tests__/approval-routes-http.test.ts +3 -0
  35. package/src/__tests__/assistant-event-hub-connection-history.test.ts +111 -0
  36. package/src/__tests__/assistant-event-hub-targeted.test.ts +50 -0
  37. package/src/__tests__/assistant-event-targeting.test.ts +186 -0
  38. package/src/__tests__/assistant-stream-state.test.ts +29 -9
  39. package/src/__tests__/browser-fill-credential.test.ts +11 -22
  40. package/src/__tests__/btw-routes.test.ts +4 -1
  41. package/src/__tests__/build-persisted-content.test.ts +1 -1
  42. package/src/__tests__/call-conversation-messages.test.ts +5 -0
  43. package/src/__tests__/call-recovery.test.ts +7 -2
  44. package/src/__tests__/call-routes-http.test.ts +12 -0
  45. package/src/__tests__/call-store.test.ts +7 -2
  46. package/src/__tests__/channel-retry-sweep.test.ts +9 -0
  47. package/src/__tests__/chat-reveal-guard-priming.test.ts +2 -0
  48. package/src/__tests__/checker.test.ts +11 -3
  49. package/src/__tests__/client-os-metadata-persistence.test.ts +35 -1
  50. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +0 -25
  51. package/src/__tests__/computer-use-tools.test.ts +1 -233
  52. package/src/__tests__/config-model-image-provider.test.ts +39 -0
  53. package/src/__tests__/config-schema.test.ts +16 -0
  54. package/src/__tests__/config-watcher.test.ts +24 -0
  55. package/src/__tests__/context-search-agent-runner.test.ts +260 -1
  56. package/src/__tests__/context-search-fanout.test.ts +1 -1
  57. package/src/__tests__/context-search-types.test.ts +7 -7
  58. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +8 -2
  59. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +2 -0
  60. package/src/__tests__/conversation-agent-loop.test.ts +546 -16
  61. package/src/__tests__/conversation-app-control-lifecycle.test.ts +53 -1
  62. package/src/__tests__/conversation-evictor.test.ts +62 -37
  63. package/src/__tests__/conversation-history-boundary-repair-failure.test.ts +174 -0
  64. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +2 -0
  65. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
  66. package/src/__tests__/conversation-retry-route.test.ts +22 -0
  67. package/src/__tests__/conversation-routes-disk-view.test.ts +2 -0
  68. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +2 -0
  69. package/src/__tests__/conversation-routes-guardian-reply.test.ts +10 -0
  70. package/src/__tests__/conversation-routes-hidden-queue.test.ts +2 -0
  71. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
  72. package/src/__tests__/conversation-runtime-assembly.test.ts +29 -0
  73. package/src/__tests__/conversation-surface-snapshots.test.ts +543 -0
  74. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +151 -0
  75. package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +63 -1
  76. package/src/__tests__/conversation-tool-setup-attribution.test.ts +23 -0
  77. package/src/__tests__/conversation-undo.test.ts +61 -0
  78. package/src/__tests__/credential-execution-client.test.ts +6 -6
  79. package/src/__tests__/credential-prompt-route.test.ts +35 -3
  80. package/src/__tests__/cu-unified-flow.test.ts +82 -1
  81. package/src/__tests__/db-mode-sessions-migration.test.ts +175 -0
  82. package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -0
  83. package/src/__tests__/dm-backfill.test.ts +91 -1
  84. package/src/__tests__/document-create-route.test.ts +88 -0
  85. package/src/__tests__/document-sync-tags.test.ts +27 -0
  86. package/src/__tests__/emit-signal-routing-intent.test.ts +142 -2
  87. package/src/__tests__/events-tail-route.test.ts +25 -0
  88. package/src/__tests__/evict-conversations-for-reload.test.ts +57 -8
  89. package/src/__tests__/guardian-action-sweep.test.ts +16 -0
  90. package/src/__tests__/guardian-dispatch.test.ts +13 -0
  91. package/src/__tests__/headless-browser-interactions.test.ts +64 -20
  92. package/src/__tests__/heartbeat-service.test.ts +2 -59
  93. package/src/__tests__/helpers/mock-conversation.ts +21 -0
  94. package/src/__tests__/helpers/native-web-search-harness.ts +2 -0
  95. package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +5 -0
  96. package/src/__tests__/host-cu-proxy.test.ts +46 -2
  97. package/src/__tests__/http-user-message-parity.test.ts +2 -0
  98. package/src/__tests__/image-credentials.test.ts +49 -0
  99. package/src/__tests__/image-service-dispatcher.test.ts +45 -0
  100. package/src/__tests__/inference-profile-session-handler.test.ts +1 -1
  101. package/src/__tests__/interrupt-on-send.test.ts +57 -43
  102. package/src/__tests__/interrupt-turn-note.test.ts +5 -6
  103. package/src/__tests__/llm-catalog-parity.test.ts +2 -2
  104. package/src/__tests__/media-generate-image.test.ts +49 -1
  105. package/src/__tests__/message-provenance-contact-id.test.ts +69 -0
  106. package/src/__tests__/migration-export-to-gcs.test.ts +142 -0
  107. package/src/__tests__/mode-session-history.test.ts +245 -0
  108. package/src/__tests__/mode-session-recovery.test.ts +222 -0
  109. package/src/__tests__/mode-session-wire.test.ts +141 -0
  110. package/src/__tests__/notification-guardian-path.test.ts +7 -0
  111. package/src/__tests__/notification-telegram-adapter.test.ts +2 -2
  112. package/src/__tests__/notification-vellum-adapter.test.ts +34 -0
  113. package/src/__tests__/oauth-provider-serializer.test.ts +12 -0
  114. package/src/__tests__/oauth-providers-routes.test.ts +1 -0
  115. package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
  116. package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
  117. package/src/__tests__/plugin-api-provider.test.ts +5 -0
  118. package/src/__tests__/plugin-api-resolve-credential.test.ts +97 -0
  119. package/src/__tests__/plugin-import-boundary-guard.test.ts +9 -0
  120. package/src/__tests__/process-message-display-content.test.ts +56 -0
  121. package/src/__tests__/reaction-persistence.test.ts +5 -0
  122. package/src/__tests__/request-secret-standalone-channel-gate.test.ts +25 -9
  123. package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
  124. package/src/__tests__/scripted-turn-metadata-persistence.test.ts +73 -0
  125. package/src/__tests__/secret-ingress-http.test.ts +2 -0
  126. package/src/__tests__/secure-keys.test.ts +43 -1
  127. package/src/__tests__/send-endpoint-busy.test.ts +163 -1
  128. package/src/__tests__/server-history-render.test.ts +91 -1
  129. package/src/__tests__/settings-routes.test.ts +50 -1
  130. package/src/__tests__/skill-script-runner-sandbox.test.ts +32 -0
  131. package/src/__tests__/subagent-fork-notifications.test.ts +1 -2
  132. package/src/__tests__/subagent-manager-notify.test.ts +1 -2
  133. package/src/__tests__/subagent-notify-parent.test.ts +146 -39
  134. package/src/__tests__/subagent-notify-stale-rebuild.test.ts +2 -4
  135. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +2 -0
  136. package/src/__tests__/thread-backfill.test.ts +53 -0
  137. package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
  138. package/src/__tests__/tool-result-metadata-plumbing.test.ts +3 -1
  139. package/src/__tests__/tool-start-timestamp.test.ts +2 -0
  140. package/src/__tests__/twilio-routes.test.ts +1 -0
  141. package/src/__tests__/web-search-backend-failure.test.ts +1 -1
  142. package/src/activation/progress-store.test.ts +12 -7
  143. package/src/agent/loop.ts +99 -41
  144. package/src/api/events/assistant-turn-start.ts +3 -0
  145. package/src/api/events/generation-handoff.ts +2 -0
  146. package/src/api/events/message-complete.ts +2 -0
  147. package/src/api/events/notification-conversation-created.ts +14 -16
  148. package/src/api/events/notification-intent.ts +4 -2
  149. package/src/api/events/tool-result.ts +85 -0
  150. package/src/api/events/tool-use-start.ts +3 -0
  151. package/src/api/events/user-message-echo.ts +3 -0
  152. package/src/api/index.ts +31 -6
  153. package/src/api/mode-session.test.ts +131 -0
  154. package/src/api/mode-session.ts +148 -0
  155. package/src/api/remember-tool.ts +15 -0
  156. package/src/api/responses/conversation-message.ts +6 -0
  157. package/src/approvals/AGENTS.md +4 -2
  158. package/src/browser/__tests__/operations.test.ts +29 -0
  159. package/src/browser/operation-meta.ts +2 -1
  160. package/src/browser/operations.ts +29 -0
  161. package/src/browser/virtual-desktop-target.ts +2 -8
  162. package/src/bundler/bundle-signer.ts +1 -3
  163. package/src/calls/__tests__/barge-in-guard.test.ts +3 -0
  164. package/src/calls/__tests__/call-controller.test.ts +94 -0
  165. package/src/calls/__tests__/call-funnel-telemetry.test.ts +204 -0
  166. package/src/calls/__tests__/voice-control-protocol.test.ts +15 -0
  167. package/src/calls/__tests__/voice-escalation-judge.test.ts +209 -0
  168. package/src/calls/__tests__/voice-leg-coordinator.test.ts +168 -0
  169. package/src/{live-voice/__tests__/live-voice-metrics.test.ts → calls/__tests__/voice-metrics.test.ts} +32 -38
  170. package/src/calls/__tests__/voice-session-bridge.test.ts +576 -122
  171. package/src/calls/barge-in-guard.ts +5 -0
  172. package/src/calls/call-controller.ts +196 -1
  173. package/src/calls/call-domain.ts +4 -0
  174. package/src/calls/call-store.ts +87 -2
  175. package/src/calls/guardian-action-sweep.ts +22 -8
  176. package/src/calls/media-stream-audio-transcode.ts +1 -3
  177. package/src/calls/typesafe-noul.ts +156 -0
  178. package/src/calls/voice-control-protocol.ts +6 -0
  179. package/src/calls/voice-escalation-judge.ts +145 -0
  180. package/src/calls/voice-escalation-target.ts +10 -0
  181. package/src/calls/voice-leg-coordinator.ts +121 -3
  182. package/src/{live-voice/live-voice-metrics.ts → calls/voice-metrics.ts} +94 -87
  183. package/src/calls/voice-session-bridge.ts +256 -112
  184. package/src/calls/voice-triage-escalate.ts +7 -0
  185. package/src/cli/__tests__/roadmap-cli.test.ts +4 -41
  186. package/src/cli/commands/__tests__/notifications.test.ts +35 -10
  187. package/src/cli/commands/browser.help.ts +4 -5
  188. package/src/cli/commands/browser.ts +0 -1
  189. package/src/cli/commands/clients.help.ts +46 -0
  190. package/src/cli/commands/clients.ts +116 -0
  191. package/src/cli/commands/credentials.help.ts +6 -1
  192. package/src/cli/commands/notifications.help.ts +16 -2
  193. package/src/cli/commands/notifications.ts +30 -8
  194. package/src/cli/commands/roadmap.help.ts +18 -21
  195. package/src/cli/commands/roadmap.ts +4 -21
  196. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +5 -2
  197. package/src/cli/lib/bundled-marketplace.json +84 -34
  198. package/src/cli/lib/plugin-marketplace.ts +8 -0
  199. package/src/cli/lib/publish-plugin.ts +1 -2
  200. package/src/config/__tests__/default-provider.test.ts +3 -1
  201. package/src/config/__tests__/memory-retrospective-schema.test.ts +14 -1
  202. package/src/config/bundled-skills/computer-use/SKILL.md +1 -1
  203. package/src/config/bundled-skills/computer-use/TOOLS.json +89 -1
  204. package/src/config/bundled-skills/image-studio/SKILL.md +17 -2
  205. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +7 -11
  206. package/src/config/bundled-skills/sequences/TOOLS.json +1 -5
  207. package/src/config/call-site-defaults.ts +9 -0
  208. package/src/config/feature-flag-registry.json +16 -0
  209. package/src/config/profile-text-generation.test.ts +2 -2
  210. package/src/config/schemas/__tests__/tools.test.ts +31 -0
  211. package/src/config/schemas/call-site-catalog.ts +14 -0
  212. package/src/config/schemas/channels.ts +0 -18
  213. package/src/config/schemas/llm.ts +3 -1
  214. package/src/config/schemas/mcp.ts +2 -1
  215. package/src/config/schemas/memory-retrospective.ts +11 -2
  216. package/src/config/schemas/services.ts +15 -6
  217. package/src/config/schemas/tools.ts +10 -0
  218. package/src/config/session-groups-gate.ts +21 -0
  219. package/src/config/skills.ts +2 -6
  220. package/src/conversations/__tests__/message-consolidation.test.ts +149 -0
  221. package/src/conversations/message-consolidation.ts +102 -5
  222. package/src/credential-execution/ces-connect.test.ts +69 -0
  223. package/src/credential-execution/ces-connect.ts +115 -0
  224. package/src/credential-execution/ces-runtime.ts +55 -93
  225. package/src/credential-execution/executable-discovery.ts +1 -11
  226. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +10 -1
  227. package/src/daemon/__tests__/inference-profile-notification.test.ts +2 -0
  228. package/src/daemon/browser-mode-session.test.ts +402 -0
  229. package/src/daemon/browser-mode-session.ts +186 -0
  230. package/src/daemon/computer-use-mode-session.test.ts +210 -0
  231. package/src/daemon/computer-use-mode-session.ts +105 -0
  232. package/src/daemon/config-watcher.ts +10 -0
  233. package/src/daemon/conversation-agent-loop-handlers.ts +58 -10
  234. package/src/daemon/conversation-agent-loop.ts +219 -25
  235. package/src/daemon/conversation-evictor.ts +5 -24
  236. package/src/daemon/conversation-history.ts +10 -0
  237. package/src/daemon/conversation-interrupt-repair.ts +4 -43
  238. package/src/daemon/conversation-interrupt.ts +7 -11
  239. package/src/daemon/conversation-messaging.ts +58 -5
  240. package/src/daemon/conversation-mode-session.test.ts +1667 -0
  241. package/src/daemon/conversation-mode-session.ts +1008 -0
  242. package/src/daemon/conversation-process.ts +5 -0
  243. package/src/daemon/conversation-runtime-assembly.ts +10 -20
  244. package/src/daemon/conversation-skill-tools.ts +1 -0
  245. package/src/daemon/conversation-store.ts +4 -4
  246. package/src/daemon/conversation-surface-snapshots.ts +135 -0
  247. package/src/daemon/conversation-surfaces.ts +113 -5
  248. package/src/daemon/conversation-tool-setup.ts +8 -3
  249. package/src/daemon/conversation.ts +143 -41
  250. package/src/daemon/handlers/config-model.ts +7 -5
  251. package/src/daemon/handlers/shared.ts +55 -16
  252. package/src/daemon/host-cu-proxy.ts +51 -22
  253. package/src/daemon/lifecycle.ts +30 -13
  254. package/src/daemon/message-protocol.ts +0 -1
  255. package/src/daemon/message-provenance.ts +28 -4
  256. package/src/daemon/mode-session-startup-recovery.ts +23 -0
  257. package/src/daemon/mode-session-tracking.ts +54 -0
  258. package/src/daemon/process-message.ts +13 -4
  259. package/src/daemon/virtual-desktop-context.ts +21 -0
  260. package/src/desktop/__tests__/fake-desktop.ts +1 -0
  261. package/src/desktop/desktop-accessibility-script.ts +88 -0
  262. package/src/desktop/desktop-accessibility.test.ts +160 -0
  263. package/src/desktop/desktop-accessibility.ts +169 -0
  264. package/src/desktop/desktop-automation-lease.test.ts +76 -68
  265. package/src/desktop/desktop-automation-lease.ts +41 -50
  266. package/src/desktop/desktop-browser-endpoint.ts +4 -0
  267. package/src/desktop/desktop-computer-use-routing.test.ts +330 -0
  268. package/src/desktop/desktop-computer-use.test.ts +449 -0
  269. package/src/desktop/desktop-computer-use.ts +502 -0
  270. package/src/desktop/desktop-dependencies.ts +47 -293
  271. package/src/desktop/desktop-display.ts +2 -2
  272. package/src/desktop/desktop-panel-config.test.ts +13 -3
  273. package/src/desktop/desktop-panel-config.ts +109 -15
  274. package/src/desktop/desktop-session-manager.test.ts +69 -21
  275. package/src/desktop/desktop-session-manager.ts +76 -22
  276. package/src/desktop/desktop-stream-bridge.test.ts +11 -122
  277. package/src/desktop/desktop-stream-bridge.ts +6 -8
  278. package/src/desktop/desktop-window-theme.ts +5 -25
  279. package/src/desktop/virtual-desktop-feature.ts +52 -2
  280. package/src/desktop/virtual-desktop-platform.test.ts +5 -9
  281. package/src/documents/document-store.ts +23 -0
  282. package/src/heartbeat/__tests__/heartbeat-service.test.ts +22 -26
  283. package/src/heartbeat/heartbeat-service.ts +5 -33
  284. package/src/ipc/__tests__/browser-ipc.test.ts +215 -6
  285. package/src/ipc/assistant-server.ts +2 -0
  286. package/src/ipc/routes/__tests__/channel-reply-ipc-routes.test.ts +111 -0
  287. package/src/ipc/routes/channel-reply-ipc-routes.ts +73 -0
  288. package/src/live-voice/__tests__/continuation-judge.test.ts +151 -0
  289. package/src/live-voice/__tests__/live-activity-reporter.test.ts +154 -15
  290. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +743 -31
  291. package/src/live-voice/__tests__/live-voice-look-follow-up.test.ts +191 -10
  292. package/src/live-voice/__tests__/live-voice-session-groups-gate.test.ts +87 -0
  293. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +5 -1
  294. package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +41 -0
  295. package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +1017 -9
  296. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +224 -1
  297. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +101 -0
  298. package/src/live-voice/__tests__/live-voice-tts.test.ts +44 -0
  299. package/src/live-voice/__tests__/live-voice-vad.test.ts +939 -75
  300. package/src/live-voice/__tests__/microphone-idle-gate.test.ts +87 -0
  301. package/src/live-voice/__tests__/session-controls.test.ts +23 -0
  302. package/src/live-voice/__tests__/task-outcomes.test.ts +117 -0
  303. package/src/live-voice/__tests__/voice-input-diagnostics.test.ts +117 -0
  304. package/src/live-voice/camera-mode-session.test.ts +265 -0
  305. package/src/live-voice/camera-mode-session.ts +277 -0
  306. package/src/live-voice/continuation-judge.ts +123 -0
  307. package/src/live-voice/live-activity-reporter.ts +115 -6
  308. package/src/live-voice/live-voice-manager.ts +36 -1
  309. package/src/live-voice/live-voice-photo.ts +88 -7
  310. package/src/live-voice/live-voice-session-manager.ts +15 -0
  311. package/src/live-voice/live-voice-session.ts +1443 -747
  312. package/src/live-voice/live-voice-tts.ts +22 -4
  313. package/src/live-voice/microphone-idle-gate.ts +56 -0
  314. package/src/live-voice/protocol.ts +171 -4
  315. package/src/live-voice/session-controls.ts +11 -3
  316. package/src/live-voice/task-outcomes.ts +131 -0
  317. package/src/live-voice/voice-input-diagnostics.ts +117 -0
  318. package/src/mcp/__tests__/manager-tool-caps.test.ts +63 -18
  319. package/src/mcp/__tests__/tool-caps.test.ts +28 -1
  320. package/src/mcp/manager.ts +3 -0
  321. package/src/mcp/tool-caps.ts +12 -4
  322. package/src/media/__tests__/image-models.test.ts +58 -0
  323. package/src/media/image-credentials.ts +5 -0
  324. package/src/media/image-models.ts +52 -0
  325. package/src/media/image-service.ts +8 -0
  326. package/src/media/openrouter-image-service.test.ts +133 -0
  327. package/src/media/openrouter-image-service.ts +153 -0
  328. package/src/media/types.ts +1 -1
  329. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +65 -11
  330. package/src/messaging/providers/discord/send.ts +4 -17
  331. package/src/messaging/providers/discord/transport.ts +2 -2
  332. package/src/messaging/providers/outlook/client.ts +16 -22
  333. package/src/messaging/providers/telegram-bot/send.test.ts +236 -1
  334. package/src/messaging/providers/telegram-bot/send.ts +10 -7
  335. package/src/messaging/providers/telegram-bot/transport.ts +3 -10
  336. package/src/messaging/providers/whatsapp/send.test.ts +169 -4
  337. package/src/monitoring/__tests__/control.test.ts +17 -5
  338. package/src/monitoring/control.ts +15 -5
  339. package/src/notifications/AGENTS.md +1 -1
  340. package/src/notifications/README.md +83 -99
  341. package/src/notifications/__tests__/broadcaster.test.ts +1 -1
  342. package/src/notifications/__tests__/channel-allowlist.test.ts +39 -0
  343. package/src/notifications/__tests__/copy-composer.test.ts +1 -1
  344. package/src/notifications/__tests__/decision-engine.test.ts +79 -2
  345. package/src/notifications/__tests__/deterministic-checks.test.ts +10 -10
  346. package/src/notifications/__tests__/home-feed-side-effect.test.ts +93 -4
  347. package/src/notifications/__tests__/notification-utils.test.ts +18 -0
  348. package/src/notifications/adapters/macos.ts +37 -46
  349. package/src/notifications/broadcaster.ts +5 -6
  350. package/src/notifications/channel-allowlist.ts +44 -0
  351. package/src/notifications/copy-composer.ts +0 -23
  352. package/src/notifications/decision-engine.ts +24 -14
  353. package/src/notifications/deterministic-checks.ts +1 -1
  354. package/src/notifications/emit-signal.ts +123 -37
  355. package/src/notifications/home-feed-side-effect.ts +9 -7
  356. package/src/notifications/notification-utils.ts +19 -0
  357. package/src/notifications/signal.ts +4 -19
  358. package/src/notifications/types.ts +15 -0
  359. package/src/oauth/connection-resolver.ts +1 -2
  360. package/src/oauth/oauth-store.ts +1 -3
  361. package/src/oauth/provider-serializer.ts +7 -0
  362. package/src/oauth/seed-providers.ts +30 -0
  363. package/src/onboarding/onboarding-events-store.ts +99 -12
  364. package/src/persistence/__tests__/client-connection-events-store.test.ts +322 -0
  365. package/src/persistence/client-connection-events-store.ts +377 -0
  366. package/src/persistence/conversation-crud.ts +55 -6
  367. package/src/persistence/conversation-mode-sessions.test.ts +424 -0
  368. package/src/persistence/conversation-mode-sessions.ts +460 -0
  369. package/src/persistence/conversation-queries.ts +6 -19
  370. package/src/persistence/llm-usage-store.ts +3 -9
  371. package/src/persistence/message-metadata.ts +25 -0
  372. package/src/persistence/migrations/381-create-conversation-mode-sessions.ts +41 -0
  373. package/src/persistence/migrations/382-create-client-connection-events.ts +40 -0
  374. package/src/persistence/migrations/__tests__/382-create-client-connection-events.test.ts +56 -0
  375. package/src/persistence/schema/conversations.ts +67 -0
  376. package/src/persistence/schema/infrastructure.ts +29 -0
  377. package/src/persistence/steps.ts +17 -0
  378. package/src/plugin-api/__tests__/plugin-name-env.test.ts +249 -0
  379. package/src/plugin-api/effective-context-window.ts +33 -0
  380. package/src/plugin-api/index.ts +24 -5
  381. package/src/plugin-api/plugin-name-env.ts +125 -0
  382. package/src/plugin-api/resolve-credential.ts +79 -20
  383. package/src/plugin-api/vision-support.test.ts +22 -0
  384. package/src/plugin-api/vision-support.ts +17 -5
  385. package/src/plugins/__tests__/active-plugin-env.test.ts +136 -0
  386. package/src/plugins/active-plugin-env.ts +51 -0
  387. package/src/plugins/defaults/index.ts +24 -0
  388. package/src/plugins/defaults/memory/__tests__/archive-removal-framing.test.ts +64 -0
  389. package/src/plugins/defaults/memory/__tests__/worker-control.test.ts +19 -6
  390. package/src/plugins/defaults/memory/context-search/agent-protocol.ts +9 -12
  391. package/src/plugins/defaults/memory/context-search/agent-runner.ts +78 -22
  392. package/src/plugins/defaults/memory/context-search/format.ts +51 -7
  393. package/src/plugins/defaults/memory/context-search/limits.ts +10 -12
  394. package/src/plugins/defaults/memory/context-search/recall-input.ts +38 -0
  395. package/src/plugins/defaults/memory/context-search/search.ts +8 -14
  396. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +1 -0
  397. package/src/plugins/defaults/memory/context-search/types.ts +1 -11
  398. package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +11 -4
  399. package/src/plugins/defaults/memory/graph/tool-handlers.ts +12 -21
  400. package/src/plugins/defaults/memory/graph/tools.ts +35 -64
  401. package/src/plugins/defaults/memory/src/memory-eval-routes.ts +2 -3
  402. package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +5 -0
  403. package/src/plugins/defaults/memory/src/memory-item-routes.ts +2 -1
  404. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +2 -2
  405. package/src/plugins/defaults/memory/tools.test.ts +124 -9
  406. package/src/plugins/defaults/memory/tools.ts +38 -11
  407. package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +165 -27
  408. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +626 -27
  409. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +46 -27
  410. package/src/plugins/defaults/memory/v3/orchestrate.ts +78 -38
  411. package/src/plugins/defaults/memory/v3/pool-log-store.ts +65 -79
  412. package/src/plugins/defaults/memory/v3/pool-select.test.ts +14 -5
  413. package/src/plugins/defaults/memory/v3/pool-select.ts +683 -44
  414. package/src/plugins/defaults/memory/worker-control.ts +15 -5
  415. package/src/plugins/defaults/task-progress/__tests__/registration.test.ts +70 -0
  416. package/src/plugins/defaults/task-progress/__tests__/task-progress-context.test.ts +380 -0
  417. package/src/plugins/defaults/task-progress/hooks/post-compact.ts +19 -0
  418. package/src/plugins/defaults/task-progress/hooks/user-prompt-submit.ts +24 -0
  419. package/src/plugins/defaults/task-progress/package.json +14 -0
  420. package/src/plugins/defaults/task-progress/src/apply-task-progress-context.ts +93 -0
  421. package/src/plugins/defaults/task-progress/src/format-task-progress-context.ts +67 -0
  422. package/src/providers/__tests__/context-overflow-error.test.ts +10 -0
  423. package/src/providers/__tests__/search-provider-catalog.test.ts +18 -0
  424. package/src/providers/anthropic/client.ts +10 -1
  425. package/src/providers/anthropic-gateway-shared.ts +6 -0
  426. package/src/providers/fetch-provider-catalog.ts +11 -0
  427. package/src/providers/gemini/client.ts +25 -8
  428. package/src/providers/inference/adapter-factory.ts +1 -1
  429. package/src/providers/jev/client.test.ts +10 -0
  430. package/src/providers/jev/client.ts +20 -4
  431. package/src/providers/model-catalog.ts +4 -3
  432. package/src/providers/openai/__tests__/chat-completions-extra-body.test.ts +94 -1
  433. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +106 -1
  434. package/src/providers/openai/__tests__/chat-template-flatten.test.ts +24 -0
  435. package/src/providers/openai/__tests__/google-thought-signature.test.ts +1 -2
  436. package/src/providers/openai/chat-completions-provider.ts +100 -29
  437. package/src/providers/openai/google-thought-signature.ts +0 -6
  438. package/src/providers/openai/responses-provider.ts +23 -1
  439. package/src/providers/ratelimit.ts +1 -3
  440. package/src/providers/search-provider-catalog.ts +24 -0
  441. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +24 -0
  442. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +7 -1
  443. package/src/providers/speech-to-text/__tests__/vellum-managed-realtime.test.ts +50 -1
  444. package/src/providers/speech-to-text/deepgram-flux-frames.ts +11 -0
  445. package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +13 -0
  446. package/src/providers/types.ts +5 -0
  447. package/src/routes/control.ts +7 -5
  448. package/src/runtime/AGENTS.md +4 -2
  449. package/src/runtime/actor-trust-resolver.ts +3 -3
  450. package/src/runtime/agent-wake.ts +1 -1
  451. package/src/runtime/approval-message-composer.ts +3 -69
  452. package/src/runtime/assistant-event-hub.ts +73 -75
  453. package/src/runtime/assistant-event-publish-options.ts +7 -0
  454. package/src/runtime/assistant-event-targeting.ts +79 -0
  455. package/src/runtime/assistant-stream-state.ts +13 -100
  456. package/src/runtime/background-job-runner.ts +5 -5
  457. package/src/runtime/channel-retry-sweep.ts +1 -0
  458. package/src/runtime/guardian-action-message-composer.ts +8 -161
  459. package/src/runtime/guardian-reply-router.ts +28 -32
  460. package/src/runtime/http-types.ts +6 -0
  461. package/src/runtime/message-composer-types.ts +3 -61
  462. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +67 -1
  463. package/src/runtime/migrations/vbundle-builder.ts +24 -1
  464. package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -4
  465. package/src/runtime/migrations/vbundle-import-policy.ts +10 -0
  466. package/src/runtime/migrations/vbundle-importer.ts +4 -1
  467. package/src/runtime/migrations/vbundle-streaming-importer.ts +4 -1
  468. package/src/runtime/migrations/vbundle-validator.ts +1 -0
  469. package/src/runtime/pending-interactions-mode-session.test.ts +62 -0
  470. package/src/runtime/pending-interactions.ts +29 -0
  471. package/src/runtime/routes/__tests__/client-history-routes.test.ts +104 -0
  472. package/src/runtime/routes/__tests__/image-generation-routes.test.ts +97 -0
  473. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +1 -1
  474. package/src/runtime/routes/__tests__/roadmap-routes.test.ts +29 -6
  475. package/src/runtime/routes/browser-context.ts +31 -11
  476. package/src/runtime/routes/browser-routes.ts +43 -4
  477. package/src/runtime/routes/btw-routes.ts +9 -4
  478. package/src/runtime/routes/client-routes.ts +108 -0
  479. package/src/runtime/routes/conversation-management-routes.ts +4 -1
  480. package/src/runtime/routes/conversation-routes.ts +113 -27
  481. package/src/runtime/routes/credential-prompt-routes.ts +4 -3
  482. package/src/runtime/routes/credential-routes.ts +1 -2
  483. package/src/runtime/routes/desktop-setup-routes.test.ts +9 -18
  484. package/src/runtime/routes/desktop-setup-routes.ts +4 -6
  485. package/src/runtime/routes/documents-routes.ts +51 -0
  486. package/src/runtime/routes/email-routes.ts +3 -7
  487. package/src/runtime/routes/events-routes.ts +75 -54
  488. package/src/runtime/routes/identity-routes.ts +1 -5
  489. package/src/runtime/routes/image-generation-routes.ts +8 -14
  490. package/src/runtime/routes/inbound-message-handler.ts +35 -38
  491. package/src/runtime/routes/inbound-stages/backfill-sender-provenance.test.ts +168 -0
  492. package/src/runtime/routes/inbound-stages/backfill-sender-provenance.ts +96 -0
  493. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +38 -9
  494. package/src/runtime/routes/inbound-stages/background-dispatch.ts +2 -5
  495. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +2 -0
  496. package/src/runtime/routes/llm-context-normalization.ts +1 -7
  497. package/src/runtime/routes/migration-routes.ts +73 -2
  498. package/src/runtime/routes/notification-routes.ts +10 -0
  499. package/src/runtime/routes/oauth-providers.ts +7 -0
  500. package/src/runtime/routes/plugins-routes.ts +6 -0
  501. package/src/runtime/routes/roadmap-routes.ts +47 -8
  502. package/src/runtime/routes/secret-routes.ts +1 -1
  503. package/src/runtime/routes/settings-routes.ts +10 -4
  504. package/src/runtime/routes/watcher-routes.ts +1 -3
  505. package/src/runtime/trust-class.test.ts +7 -6
  506. package/src/runtime/trust-class.ts +9 -17
  507. package/src/schedule/__tests__/worker-control.test.ts +36 -5
  508. package/src/schedule/worker-control.ts +15 -5
  509. package/src/security/secure-keys.ts +53 -103
  510. package/src/skills/clawhub.ts +3 -8
  511. package/src/skills/managed-store.ts +1 -5
  512. package/src/stt/types.ts +4 -0
  513. package/src/subagent/notify.ts +54 -34
  514. package/src/subagent/parent-notification.ts +6 -0
  515. package/src/telemetry/__tests__/phone-call-funnel.test.ts +72 -0
  516. package/src/telemetry/phone-call-funnel.ts +144 -0
  517. package/src/tools/__tests__/tool-schema-root-combinator-guard.test.ts +81 -0
  518. package/src/tools/ask-question/ask-question-tool.ts +6 -4
  519. package/src/tools/browser/browser-execution.ts +22 -59
  520. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +561 -39
  521. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +435 -39
  522. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +1 -8
  523. package/src/tools/client-os.ts +15 -0
  524. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
  525. package/src/tools/computer-use/target.ts +42 -0
  526. package/src/tools/document/document-tool.ts +13 -18
  527. package/src/tools/execution-target.ts +14 -16
  528. package/src/tools/host-terminal/host-shell.ts +4 -1
  529. package/src/tools/network/__tests__/web-fetch-tinyfish.test.ts +250 -0
  530. package/src/tools/network/__tests__/web-search.test.ts +203 -0
  531. package/src/tools/network/web-fetch.ts +274 -7
  532. package/src/tools/network/web-search.ts +468 -6
  533. package/src/tools/permission-checker.ts +3 -3
  534. package/src/tools/policy-context.ts +3 -1
  535. package/src/tools/skills/load.ts +2 -1
  536. package/src/tools/skills/sandbox-runner.ts +11 -2
  537. package/src/tools/skills/skill-script-runner.ts +7 -0
  538. package/src/tools/skills/skill-tool-factory.ts +15 -1
  539. package/src/tools/terminal/__tests__/safe-env.test.ts +11 -0
  540. package/src/tools/terminal/safe-env.ts +4 -0
  541. package/src/tools/terminal/shell.ts +2 -0
  542. package/src/tools/tool-approval-handler.ts +5 -1
  543. package/src/tools/tool-types.ts +3 -3
  544. package/src/tools/types.ts +8 -2
  545. package/src/util/__tests__/worker-process-command.test.ts +5 -4
  546. package/src/util/abort-reasons.ts +18 -26
  547. package/src/util/canonicalize-identity.test.ts +21 -0
  548. package/src/util/canonicalize-identity.ts +16 -0
  549. package/src/util/errors.ts +13 -3
  550. package/src/util/provider-error-patterns.ts +3 -0
  551. package/src/util/worker-process.ts +77 -35
  552. package/src/workspace/migrations/157-add-desktop-files-launcher.ts +94 -0
  553. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +4 -10
  554. package/src/workspace/migrations/__tests__/157-add-desktop-files-launcher.test.ts +113 -0
  555. package/src/workspace/migrations/registry.ts +2 -0
  556. package/src/__tests__/computer-use-window-schema.test.ts +0 -24
  557. package/src/api/events/heartbeat-alert.ts +0 -20
  558. package/src/daemon/message-types/web-activity.ts +0 -65
  559. package/src/desktop/desktop-dependencies.test.ts +0 -131
  560. package/src/tools/computer-use/definitions.ts +0 -607
@@ -13,8 +13,8 @@
13
13
  * - never re-throw — the caller always gets a structured result and decides
14
14
  * whether to alert further
15
15
  *
16
- * Producers that have their own bespoke failure UX (e.g. heartbeat's existing
17
- * alerter banner) can opt out of the failure-emit via
16
+ * Producers whose failure alerting is owned elsewhere (e.g. the scheduler's
17
+ * retry policy) can opt out of the failure-emit via
18
18
  * `suppressFailureNotifications`.
19
19
  */
20
20
 
@@ -104,9 +104,9 @@ export interface RunBackgroundJobOptions {
104
104
  timeoutMs: number;
105
105
  /**
106
106
  * When true, failures do NOT emit an `activity.failed` notification.
107
- * Use for jobs whose failure alerting is owned elsewhere: heartbeat's
108
- * alerter banner, and the scheduler's retry policy (which alerts once,
109
- * when retries are exhausted, instead of once per attempt).
107
+ * Use for jobs whose failure alerting is owned elsewhere, such as the
108
+ * scheduler's retry policy (which alerts once, when retries are
109
+ * exhausted, instead of once per attempt).
110
110
  */
111
111
  suppressFailureNotifications?: boolean;
112
112
  /** Conversation grouping id. Defaults to `"system:background"`. */
@@ -547,6 +547,7 @@ export async function sweepFailedEvents(
547
547
  },
548
548
  assistantId,
549
549
  trustContext,
550
+ author: trustContext,
550
551
  isInteractive:
551
552
  resolveRoutingStateFromRuntime(trustContext).promptWaitingAllowed,
552
553
  onEvent: observeAgentEvent,
@@ -1,182 +1,29 @@
1
1
  /**
2
- * Layered guardian action message composition system.
2
+ * Guardian action message composition.
3
3
  *
4
- * Generates user-visible copy for guardian action scenarios through a
5
- * priority chain:
6
- * 1. Generator-produced text (when provided by daemon)
7
- * 2. Deterministic fallback templates (natural, scenario-specific messages)
8
- *
9
- * Follows the same pattern as approval-message-composer.ts.
4
+ * Returns the deterministic, voice-friendly copy for a guardian action
5
+ * notice. The only notice left is the one the expiry sweep
6
+ * (`calls/guardian-action-sweep.ts`) sends to each place a guardian request
7
+ * was delivered once the request expires unanswered.
10
8
  */
11
- import type {
12
- ComposeGuardianActionMessageOptions,
13
- GuardianActionMessageContext,
14
- } from "./message-composer-types.js";
9
+ import type { GuardianActionMessageContext } from "./message-composer-types.js";
15
10
 
16
11
  export type {
17
- ComposeGuardianActionMessageOptions,
18
12
  GuardianActionMessageContext,
19
13
  GuardianActionMessageScenario,
20
14
  } from "./message-composer-types.js";
21
15
 
22
- // ---------------------------------------------------------------------------
23
- // Public API
24
- // ---------------------------------------------------------------------------
25
-
26
- /**
27
- * Compose user-facing guardian action copy using the daemon-injected generator
28
- * when available, with deterministic fallback for reliability.
29
- *
30
- * The generator parameter is the daemon-provided function that knows about
31
- * providers. When absent (or in test env), only the deterministic fallback
32
- * is used.
33
- */
34
- export async function composeGuardianActionMessageGenerative(
35
- context: GuardianActionMessageContext,
36
- options: ComposeGuardianActionMessageOptions = {},
37
- ): Promise<string> {
38
- const fallbackText =
39
- options.fallbackText?.trim() || getGuardianActionFallbackMessage(context);
40
-
41
- if (process.env.NODE_ENV === "test") {
42
- return fallbackText;
43
- }
44
-
45
- return fallbackText;
46
- }
47
-
48
- /** @internal Exported for use by the daemon-injected generator implementation. */
49
- export function includesRequiredKeywords(
50
- text: string,
51
- requiredKeywords: string[] | undefined,
52
- ): boolean {
53
- if (!requiredKeywords || requiredKeywords.length === 0) {
54
- return true;
55
- }
56
- return requiredKeywords.every((keyword) => {
57
- const re = new RegExp(`\\b${RegExp.escape(keyword)}\\b`, "i");
58
- return re.test(text);
59
- });
60
- }
61
-
62
- // ---------------------------------------------------------------------------
63
- // Deterministic fallback templates
64
- // ---------------------------------------------------------------------------
65
-
66
- /**
67
- * Return a scenario-specific deterministic fallback message.
68
- *
69
- * Each template produces natural, conversational text suitable for voice
70
- * delivery.
71
- */
72
- export function getGuardianActionFallbackMessage(
16
+ /** Compose the user-facing copy for a guardian action notice. */
17
+ export function composeGuardianActionMessage(
73
18
  context: GuardianActionMessageContext,
74
19
  ): string {
75
- const listedCodes = formatGuardianRequestCodes(context.requestCodes);
76
-
77
20
  switch (context.scenario) {
78
- case "caller_timeout_acknowledgment":
79
- return context.guardianIdentifier
80
- ? `I wasn't able to reach ${context.guardianIdentifier} right now. I'm sorry about that.`
81
- : "I wasn't able to reach the guardian right now. I'm sorry about that.";
82
-
83
- case "caller_timeout_continue":
84
- return "Would you like me to leave a message for them to get back to you, or is there anything else I can help with?";
85
-
86
- case "guardian_late_answer_followup":
87
- return context.callerIdentifier
88
- ? `${context.callerIdentifier} called earlier with a question, but I wasn't able to connect them. Would you like to call them back?`
89
- : "Someone called earlier with a question, but I wasn't able to connect them. Would you like to call them back?";
90
-
91
- case "guardian_followup_dispatching":
92
- return context.followupAction
93
- ? `Got it, I'll ${context.followupAction} now.`
94
- : "Got it, I'm taking care of that now.";
95
-
96
- case "guardian_followup_completed":
97
- return context.followupAction
98
- ? `Done! I've ${context.followupAction} successfully.`
99
- : "Done! That's been taken care of.";
100
-
101
- case "guardian_followup_failed":
102
- return context.failureReason
103
- ? `I'm sorry, I wasn't able to complete that. ${context.failureReason}`
104
- : "I'm sorry, I wasn't able to complete that. Please try again later.";
105
-
106
- case "guardian_followup_declined_ack":
107
- return "No problem. Let me know if you change your mind or need anything else.";
108
-
109
- case "guardian_followup_clarification":
110
- return "Sorry, I didn't quite catch that. Would you like to call them back or skip it for now?";
111
-
112
- case "guardian_pending_disambiguation":
113
- return listedCodes
114
- ? `You have multiple pending guardian questions. Please prefix your reply with the reference code (${listedCodes}) so I know which question you're answering.`
115
- : "You have multiple pending guardian questions. Please prefix your reply with the reference code so I know which question you're answering.";
116
-
117
- case "guardian_expired_disambiguation":
118
- return listedCodes
119
- ? `You have multiple expired guardian questions. Please prefix your reply with the reference code (${listedCodes}) so I know which question you're answering.`
120
- : "You have multiple expired guardian questions. Please prefix your reply with the reference code so I know which question you're answering.";
121
-
122
- case "guardian_followup_disambiguation":
123
- return listedCodes
124
- ? `You have multiple pending follow-up questions. Please prefix your reply with the reference code (${listedCodes}) so I know which question you're responding to.`
125
- : "You have multiple pending follow-up questions. Please prefix your reply with the reference code so I know which question you're responding to.";
126
-
127
- case "guardian_stale_answered":
128
- return "This question has already been answered from another channel.";
129
-
130
21
  case "guardian_stale_expired":
131
22
  return "That request has already expired. No further action is needed.";
132
23
 
133
- case "guardian_stale_followup":
134
- return "It looks like this follow-up has already been handled. No further action is needed.";
135
-
136
- case "guardian_stale_superseded":
137
- return "This request is no longer active. The call has ended and no further action is needed.";
138
-
139
- case "guardian_unknown_code":
140
- return context.unknownCode
141
- ? `I don't recognize the code "${context.unknownCode}". Please check the reference code and try again.`
142
- : "I don't recognize that reference code. Please check the code and try again.";
143
-
144
- case "guardian_auto_matched":
145
- return "Got it, routing your answer to the active request.";
146
-
147
- case "guardian_superseded_remap":
148
- return context.questionText
149
- ? `Got it! Your answer has been applied to the current active request: "${context.questionText}"`
150
- : "Got it! Your answer has been applied to the current active request on the call.";
151
-
152
- case "followup_call_started":
153
- return context.counterpartyPhone
154
- ? `Got it! I'm calling ${context.counterpartyPhone} back now to relay your answer.`
155
- : "Got it! I'm calling them back now to relay your answer.";
156
-
157
- case "followup_action_failed":
158
- return context.failureReason
159
- ? `I'm sorry, I wasn't able to complete that. ${context.failureReason}`
160
- : "I'm sorry, something went wrong and I couldn't complete that action. Please try again later.";
161
-
162
- case "guardian_answer_delivery_failed":
163
- return "I wasn't able to deliver your answer to the call. The call may have ended. Please try again or follow up directly.";
164
-
165
24
  default: {
166
25
  const _exhaustive: never = context.scenario;
167
26
  return `Guardian action update. ${String(_exhaustive)}`;
168
27
  }
169
28
  }
170
29
  }
171
-
172
- function formatGuardianRequestCodes(
173
- requestCodes: string[] | undefined,
174
- ): string {
175
- if (!Array.isArray(requestCodes)) {
176
- return "";
177
- }
178
- const cleaned = requestCodes
179
- .map((code) => code.trim())
180
- .filter((code) => code.length > 0);
181
- return cleaned.join(", ");
182
- }
@@ -1,13 +1,24 @@
1
1
  /**
2
- * Shared guardian reply router for inbound channel messages.
2
+ * Shared guardian reply router.
3
3
  *
4
- * Provides a single entry point (`routeGuardianReply`) for all inbound
5
- * guardian reply processing across Telegram and WhatsApp. Routes
4
+ * Provides a single entry point (`routeGuardianReply`) for every guardian
5
+ * reply typed in the app (`daemon/conversation-process.ts`,
6
+ * `routes/conversation-routes.ts`) and every reply or button press arriving
7
+ * on a channel (`routes/inbound-stages/guardian-reply-intercept.ts`). App
8
+ * card buttons decide through `processGuardianDecision()` instead. Routes
6
9
  * through a priority-ordered pipeline:
7
10
  *
8
- * 1. Deterministic callback/ref parsing (button presses with `apr:<requestId>:<action>`)
11
+ * 1. Deterministic callback/ref parsing (channel button presses with `apr:<requestId>:<action>`)
9
12
  * 2. Request code parsing (6-char alphanumeric prefix matching)
10
- * 3. NL classification via the conversational approval engine
13
+ * 2.5. Invite handoff: "open invite flow" with a pending access request
14
+ * passes through to the normal assistant turn
15
+ * 2.55. Bare-text answer to the single pending question, in the
16
+ * conversation it was asked in
17
+ * 2.6. Explicit approve/reject phrase: applied when exactly one request is
18
+ * pending, answered with a disambiguation reply when several are
19
+ * 3. NL classification via the conversational approval engine, only when
20
+ * the caller passes an `approvalConversationGenerator` (app sessions do
21
+ * not, so for them 2.6 is the last plain-text stage)
11
22
  *
12
23
  * All decisions flow through `applyGuardianDecision`, which handles identity
13
24
  * validation, expiry checks, the atomic gateway CAS+outcome commit,
@@ -317,17 +328,8 @@ function notConsumed(): GuardianReplyResult {
317
328
  // ---------------------------------------------------------------------------
318
329
 
319
330
  /**
320
- * Route an inbound guardian reply through the guardian decision pipeline.
321
- *
322
- * This is the single entry point for all inbound guardian reply processing.
323
- * It handles messages from any channel (Telegram, WhatsApp) and
324
- * routes through priority-ordered matching:
325
- *
326
- * 1. Deterministic callback parsing (button presses)
327
- * 2. Request code parsing (6-char alphanumeric prefix)
328
- * 3. NL classification via the conversational approval engine
329
- *
330
- * All decisions flow through `applyGuardianDecision`.
331
+ * Route a guardian reply through the priority-ordered pipeline described in
332
+ * the file header. All decisions flow through `applyGuardianDecision`.
331
333
  */
332
334
  export async function routeGuardianReply(
333
335
  ctx: GuardianReplyContext,
@@ -388,7 +390,7 @@ export async function routeGuardianReply(
388
390
  const request = await getGuardianRequestOrNull(answerTap.requestId);
389
391
  if (
390
392
  request &&
391
- resolveRequestInstructionMode(request) === "answer" &&
393
+ resolveGuardianInstructionModeForRequest(request) === "answer" &&
392
394
  parseQuestionAnswerActionId(answerTap.token) &&
393
395
  !request.callSessionId &&
394
396
  hasLiveQuestionInteraction(request.id)
@@ -581,7 +583,7 @@ export async function routeGuardianReply(
581
583
  if (messageText.length > 0 && pendingRequests.length === 1) {
582
584
  const soleRequest = pendingRequests[0];
583
585
  if (
584
- resolveRequestInstructionMode(soleRequest) === "answer" &&
586
+ resolveGuardianInstructionModeForRequest(soleRequest) === "answer" &&
585
587
  !soleRequest.callSessionId &&
586
588
  soleRequest.sourceConversationId === conversationId &&
587
589
  hasLiveQuestionInteraction(soleRequest.id)
@@ -663,11 +665,11 @@ export async function routeGuardianReply(
663
665
  );
664
666
 
665
667
  if (engineResult.disposition === "keep_pending") {
666
- // When the engine returns keep_pending with multiple pending requests,
667
- // this likely means the NL classification understood a decision intent
668
- // but runApprovalConversationTurn fail-closed because no targetRequestId
669
- // was provided. In this case, produce a disambiguation reply instead of
670
- // a generic "I couldn't process that" message.
668
+ // keep_pending covers model indecision and every fail-closed path in
669
+ // runApprovalConversationTurn (generator error, malformed output, a
670
+ // decision without the targetRequestId that multi-pending requires).
671
+ // With several requests pending, answer with a disambiguation reply
672
+ // instead of a generic "I couldn't process that" message.
671
673
  if (pendingRequestsForClassification.length > 1) {
672
674
  log.info(
673
675
  {
@@ -1005,12 +1007,6 @@ function inferActionFromText(
1005
1007
  return "approve_once";
1006
1008
  }
1007
1009
 
1008
- function resolveRequestInstructionMode(
1009
- request?: Pick<GuardianRequestWire, "kind" | "toolName"> | null,
1010
- ): "approval" | "answer" {
1011
- return resolveGuardianInstructionModeForRequest(request);
1012
- }
1013
-
1014
1010
  // ---------------------------------------------------------------------------
1015
1011
  // Failure reason reply text
1016
1012
  // ---------------------------------------------------------------------------
@@ -1044,7 +1040,7 @@ function failureReplyText(
1044
1040
  return "Something went wrong with this request on our end, so I couldn't apply your decision.";
1045
1041
  case "invalid_action":
1046
1042
  return buildGuardianInvalidActionReply(
1047
- resolveRequestInstructionMode(request),
1043
+ resolveGuardianInstructionModeForRequest(request),
1048
1044
  requestCode ?? undefined,
1049
1045
  );
1050
1046
  default:
@@ -1063,7 +1059,7 @@ function failureReplyText(
1063
1059
  */
1064
1060
  function composeCodeOnlyClarification(request: GuardianRequestWire): string {
1065
1061
  const code = request.requestCode ?? "unknown";
1066
- const mode = resolveRequestInstructionMode(request);
1062
+ const mode = resolveGuardianInstructionModeForRequest(request);
1067
1063
  return buildGuardianCodeOnlyClarification(mode, {
1068
1064
  requestCode: code,
1069
1065
  questionText: request.questionText,
@@ -1087,7 +1083,7 @@ function composeDisambiguationReply(
1087
1083
  const lines: string[] = [];
1088
1084
  const requestsWithMode = pendingRequests.map((request) => ({
1089
1085
  request,
1090
- mode: resolveRequestInstructionMode(request),
1086
+ mode: resolveGuardianInstructionModeForRequest(request),
1091
1087
  }));
1092
1088
 
1093
1089
  if (engineReplyText) {
@@ -70,6 +70,12 @@ export interface RuntimeMessageConversationOptions {
70
70
  };
71
71
  assistantId?: string;
72
72
  trustContext?: TrustContext;
73
+ /**
74
+ * The person whose own inbound message this turn persists. Channel ingress
75
+ * and its retry replay pass the sender's trust; it names the persisted user
76
+ * row's author (`PersistMessageOptions.author`).
77
+ */
78
+ author?: TrustContext;
73
79
  /**
74
80
  * Whether this turn should permit interactive approval prompts.
75
81
  * Channel ingress sets this true so confirmations can be resolved
@@ -13,36 +13,18 @@ export type ApprovalMessageScenario =
13
13
  | "standard_prompt"
14
14
  | "guardian_prompt"
15
15
  | "reminder_prompt"
16
- | "guardian_delivery_failed"
17
- | "guardian_request_forwarded"
18
- | "guardian_disambiguation"
19
16
  | "guardian_identity_mismatch"
20
17
  | "request_pending_guardian"
21
- | "guardian_decision_outcome"
22
- | "guardian_expired_requester"
23
- | "guardian_expired_guardian"
24
- | "guardian_verify_success"
25
18
  | "guardian_verify_failed"
26
19
  | "guardian_verify_challenge_setup"
27
- | "guardian_verify_status_bound"
28
- | "guardian_verify_status_unbound"
29
- | "guardian_deny_no_identity"
30
- | "guardian_deny_no_binding"
31
- | "requester_cancel"
32
- | "approval_already_resolved"
33
- | "guardian_text_unavailable";
20
+ | "approval_already_resolved";
34
21
 
35
22
  export interface ApprovalMessageContext {
36
23
  scenario: ApprovalMessageScenario;
37
24
  channel?: string;
38
25
  toolName?: string;
39
26
  requesterIdentifier?: string;
40
- guardianIdentifier?: string;
41
- pendingCount?: number;
42
- decision?: "approved" | "denied";
43
27
  richUi?: boolean;
44
- /** Pre-existing assistant text to reuse (macOS parity). */
45
- assistantPreface?: string;
46
28
  verifyCommand?: string;
47
29
  ttlSeconds?: number;
48
30
  failureReason?: string;
@@ -77,49 +59,9 @@ export type ApprovalCopyGenerator = (
77
59
  // Guardian action message types
78
60
  // ---------------------------------------------------------------------------
79
61
 
80
- export type GuardianActionMessageScenario =
81
- | "caller_timeout_acknowledgment"
82
- | "caller_timeout_continue"
83
- | "guardian_late_answer_followup"
84
- | "guardian_followup_dispatching"
85
- | "guardian_followup_completed"
86
- | "guardian_followup_failed"
87
- | "guardian_followup_declined_ack"
88
- | "guardian_followup_clarification"
89
- | "guardian_pending_disambiguation"
90
- | "guardian_expired_disambiguation"
91
- | "guardian_followup_disambiguation"
92
- | "guardian_stale_answered"
93
- | "guardian_stale_expired"
94
- | "guardian_stale_followup"
95
- | "guardian_stale_superseded"
96
- | "guardian_superseded_remap"
97
- | "guardian_unknown_code"
98
- | "guardian_auto_matched"
99
- | "followup_call_started"
100
- | "followup_action_failed"
101
- | "guardian_answer_delivery_failed";
62
+ /** The one guardian-action notice still sent: a request expired unanswered. */
63
+ export type GuardianActionMessageScenario = "guardian_stale_expired";
102
64
 
103
65
  export interface GuardianActionMessageContext {
104
66
  scenario: GuardianActionMessageScenario;
105
- channel?: string;
106
- questionText?: string;
107
- callerIdentifier?: string;
108
- guardianIdentifier?: string;
109
- lateAnswerText?: string;
110
- followupAction?: string;
111
- failureReason?: string;
112
- counterpartyPhone?: string;
113
- requestCodes?: string[];
114
- /** The code the guardian provided that was not recognized. */
115
- unknownCode?: string;
116
- /** The code of the active request that supersedes the one the guardian targeted. */
117
- activeRequestCode?: string;
118
- }
119
-
120
- export interface ComposeGuardianActionMessageOptions {
121
- fallbackText?: string;
122
- requiredKeywords?: string[];
123
- maxTokens?: number;
124
- timeoutMs?: number;
125
67
  }
@@ -33,7 +33,10 @@ import { Readable } from "node:stream";
33
33
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
34
34
 
35
35
  import { buildVBundle } from "../vbundle-builder.js";
36
- import { DefaultPathResolver } from "../vbundle-import-analyzer.js";
36
+ import {
37
+ analyzeImport,
38
+ DefaultPathResolver,
39
+ } from "../vbundle-import-analyzer.js";
37
40
  import { commitImport } from "../vbundle-importer.js";
38
41
  import { streamCommitImport } from "../vbundle-streaming-importer.js";
39
42
  import { defaultV1Options } from "./v1-test-helpers.js";
@@ -416,4 +419,67 @@ describe("vbundle import parity (buffer vs streaming)", () => {
416
419
  expect(bufferMap.has("marker.txt")).toBe(true);
417
420
  expect(streamMap.has("marker.txt")).toBe(true);
418
421
  });
422
+
423
+ test("F — debug-profile gateway entry: both importers drain it and write nothing", async () => {
424
+ const configJson = JSON.stringify({ version: 1 });
425
+ const { archive, manifest } = buildVBundle({
426
+ files: [
427
+ { path: "workspace/data/db/assistant.db", data: new Uint8Array(8) },
428
+ {
429
+ path: "workspace/config.json",
430
+ data: new TextEncoder().encode(configJson),
431
+ },
432
+ {
433
+ path: "gateway/export.tar.gz",
434
+ data: new TextEncoder().encode("not-a-real-tarball"),
435
+ },
436
+ ],
437
+ ...defaultV1Options(),
438
+ });
439
+
440
+ // Preflight must not block on the gateway entry, or the CLI would
441
+ // refuse the restore before either importer runs.
442
+ const preflight = analyzeImport({
443
+ manifest,
444
+ pathResolver: new DefaultPathResolver(bufferWs),
445
+ });
446
+ expect(preflight.can_import).toBe(true);
447
+ expect(preflight.conflicts).toEqual([]);
448
+
449
+ mkdirSync(bufferWs, { recursive: true });
450
+ mkdirSync(streamWs, { recursive: true });
451
+
452
+ const bufferResult = commitImport({
453
+ archiveData: archive,
454
+ pathResolver: new DefaultPathResolver(bufferWs),
455
+ workspaceDir: bufferWs,
456
+ });
457
+ const streamResult = await streamCommitImport({
458
+ source: Readable.from([Buffer.from(archive)]),
459
+ pathResolver: new DefaultPathResolver(streamWs),
460
+ workspaceDir: streamWs,
461
+ });
462
+ if (!bufferResult.ok || !streamResult.ok) {
463
+ throw new Error("import unexpectedly failed");
464
+ }
465
+
466
+ const bufferMap = walkDiskTree(bufferWs);
467
+ const streamMap = walkDiskTree(streamWs);
468
+
469
+ expect(streamMap).toEqual(bufferMap);
470
+ expect(bufferMap.has("config.json")).toBe(true);
471
+ expect(bufferMap.has("data/db/assistant.db")).toBe(true);
472
+ for (const relPath of bufferMap.keys()) {
473
+ expect(relPath.startsWith("gateway")).toBe(false);
474
+ }
475
+ // Skipped silently, like a retired path: counted, but no
476
+ // "no known disk target" warning.
477
+ for (const { report } of [bufferResult, streamResult]) {
478
+ expect(report.warnings).toEqual([]);
479
+ const gateway = report.files.find(
480
+ (f) => f.path === "gateway/export.tar.gz",
481
+ );
482
+ expect(gateway?.action).toBe("skipped");
483
+ }
484
+ });
419
485
  });
@@ -71,6 +71,12 @@ export interface VBundleExportOptions {
71
71
  include_logs: boolean;
72
72
  include_browser_state: boolean;
73
73
  include_memory_vectors: boolean;
74
+ /**
75
+ * Debug profile: the bundle carries `gateway/export.tar.gz`, the gateway's
76
+ * database and recent logs, for Vellum staff to inspect. Absent on
77
+ * ordinary migration bundles.
78
+ */
79
+ include_gateway?: boolean;
74
80
  }
75
81
 
76
82
  export interface BuildVBundleOptions {
@@ -697,6 +703,11 @@ export interface BuildExportVBundleOptions {
697
703
  checkpoint?: () => void | Promise<void>;
698
704
  /** Optional credential entries to include in the archive under credentials/ prefix. */
699
705
  credentials?: Array<{ account: string; value: string }>;
706
+ /**
707
+ * Extra in-memory entries at exact archive paths, outside `workspace/`.
708
+ * The debug profile uses this for `gateway/export.tar.gz`.
709
+ */
710
+ extraFiles?: Array<{ archivePath: string; data: Uint8Array }>;
700
711
  }
701
712
 
702
713
  /**
@@ -722,6 +733,7 @@ export function buildExportVBundle(
722
733
  checkpoint,
723
734
  workspaceDir,
724
735
  credentials,
736
+ extraFiles,
725
737
  } = options;
726
738
 
727
739
  // Flush WAL to the main database file before reading so the export
@@ -732,6 +744,9 @@ export function buildExportVBundle(
732
744
  }
733
745
 
734
746
  const files: VBundleFileEntry[] = [];
747
+ for (const extra of extraFiles ?? []) {
748
+ files.push({ path: extra.archivePath, data: extra.data });
749
+ }
735
750
 
736
751
  // Walk the entire workspace directory, including binary files (DB,
737
752
  // attachments) but skipping large/regenerable subdirectories.
@@ -1176,6 +1191,7 @@ export async function streamExportVBundle(
1176
1191
  checkpoint,
1177
1192
  workspaceDir,
1178
1193
  credentials,
1194
+ extraFiles,
1179
1195
  } = options;
1180
1196
 
1181
1197
  // Flush WAL to the main database file before reading. Awaiting allows
@@ -1236,8 +1252,15 @@ export async function streamExportVBundle(
1236
1252
  });
1237
1253
  }
1238
1254
 
1239
- // Build in-memory entries for credentials (not disk-backed)
1255
+ // Build in-memory entries for credentials and any extra files (not disk-backed)
1240
1256
  const inMemoryEntries: InMemoryEntry[] = [];
1257
+ for (const extra of extraFiles ?? []) {
1258
+ inMemoryEntries.push({
1259
+ archivePath: extra.archivePath,
1260
+ data: extra.data,
1261
+ size: extra.data.length,
1262
+ });
1263
+ }
1241
1264
  if (credentials?.length) {
1242
1265
  for (const { account, value } of credentials) {
1243
1266
  const data = new TextEncoder().encode(value);
@@ -19,7 +19,10 @@ import { join, resolve } from "node:path";
19
19
 
20
20
  import { resolveGuardianPersonaPath } from "../../prompts/persona-resolver.js";
21
21
  import { getLogger } from "../../util/logger.js";
22
- import { isRetiredArchivePath } from "./vbundle-import-policy.js";
22
+ import {
23
+ isGatewayArchivePath,
24
+ isRetiredArchivePath,
25
+ } from "./vbundle-import-policy.js";
23
26
  import type { ManifestType } from "./vbundle-validator.js";
24
27
 
25
28
  const log = getLogger("vbundle-import-analyzer");
@@ -123,7 +126,10 @@ export class DefaultPathResolver implements PathResolver {
123
126
  // must never resolve to a disk target — resolving would write them
124
127
  // back into the workspace on import. The analyzer and both importers
125
128
  // turn the resulting null into a silent non-blocking skip.
126
- if (isRetiredArchivePath(archivePath)) {
129
+ if (
130
+ isRetiredArchivePath(archivePath) ||
131
+ isGatewayArchivePath(archivePath)
132
+ ) {
127
133
  return null;
128
134
  }
129
135
 
@@ -297,10 +303,13 @@ export function analyzeImport(
297
303
  // Retired-feature file from a legacy bundle: nothing consumes it
298
304
  // anymore, so drop it silently instead of blocking the restore with
299
305
  // an UNKNOWN_ARCHIVE_PATH conflict.
300
- if (isRetiredArchivePath(fileEntry.path)) {
306
+ if (
307
+ isRetiredArchivePath(fileEntry.path) ||
308
+ isGatewayArchivePath(fileEntry.path)
309
+ ) {
301
310
  log.info(
302
311
  { path: fileEntry.path },
303
- "Retired archive path in legacy bundle — will be skipped on import",
312
+ "Archive path is not workspace data — will be skipped on import",
304
313
  );
305
314
  files.push({
306
315
  path: fileEntry.path,
@@ -57,6 +57,16 @@ export function isRetiredArchivePath(archivePath: string): boolean {
57
57
  return RETIRED_ARCHIVE_PATHS.has(archivePath);
58
58
  }
59
59
 
60
+ /**
61
+ * `gateway/` holds the gateway's own database and logs, added by the debug
62
+ * export profile for Vellum staff to open on a debug clone. It is never
63
+ * part of a workspace, so preflight and both importers skip it silently,
64
+ * the same way they skip retired paths.
65
+ */
66
+ export function isGatewayArchivePath(archivePath: string): boolean {
67
+ return archivePath.startsWith("gateway/");
68
+ }
69
+
60
70
  export function isConfigArchivePath(archivePath: string): boolean {
61
71
  return CONFIG_ARCHIVE_PATHS.has(archivePath);
62
72
  }
@@ -340,7 +340,10 @@ export function commitImport(options: ImportCommitOptions): ImportCommitResult {
340
340
  sha256: fileEntry.sha256,
341
341
  backup_path: null,
342
342
  });
343
- if (!policy.isRetiredArchivePath(fileEntry.path)) {
343
+ if (
344
+ !policy.isRetiredArchivePath(fileEntry.path) &&
345
+ !policy.isGatewayArchivePath(fileEntry.path)
346
+ ) {
344
347
  warnings.push(
345
348
  `Skipped "${fileEntry.path}": no known disk target for this archive path`,
346
349
  );