@vellumai/assistant 0.12.3-staging.1 → 0.12.3-staging.2

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
@@ -0,0 +1,141 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { AssistantTextDeltaEventSchema } from "../api/events/assistant-text-delta.js";
4
+ import { AssistantThinkingDeltaEventSchema } from "../api/events/assistant-thinking-delta.js";
5
+ import { AssistantTurnStartEventSchema } from "../api/events/assistant-turn-start.js";
6
+ import { GenerationHandoffEventSchema } from "../api/events/generation-handoff.js";
7
+ import { MessageCompleteEventSchema } from "../api/events/message-complete.js";
8
+ import { ToolResultEventSchema } from "../api/events/tool-result.js";
9
+ import { ToolUseStartEventSchema } from "../api/events/tool-use-start.js";
10
+ import { UserMessageEchoEventSchema } from "../api/events/user-message-echo.js";
11
+ import {
12
+ ModeSessionDescriptorSchema,
13
+ ModeSessionSchema,
14
+ } from "../api/mode-session.js";
15
+ import { ConversationMessageSchema } from "../api/responses/conversation-message.js";
16
+ import { messageMetadataSchema } from "../persistence/conversation-crud.js";
17
+
18
+ const owner = { mode: "browser", id: "session-123" } as const;
19
+
20
+ describe("mode session wire contract", () => {
21
+ test("accepts canonical membership on history and row-boundary events", () => {
22
+ expect(ModeSessionSchema.parse(owner)).toEqual(owner);
23
+ expect(
24
+ ConversationMessageSchema.parse({
25
+ id: "message-123",
26
+ role: "assistant",
27
+ timestamp: new Date(0).toISOString(),
28
+ attachments: [],
29
+ contentBlocks: [],
30
+ modeSession: owner,
31
+ modeSessionActivity: { firstAt: 100, lastAt: 150 },
32
+ }).modeSession,
33
+ ).toEqual(owner);
34
+
35
+ const boundaryEvents = [
36
+ UserMessageEchoEventSchema.parse({
37
+ type: "user_message_echo",
38
+ text: "Continue",
39
+ modeSession: owner,
40
+ }),
41
+ AssistantTurnStartEventSchema.parse({
42
+ type: "assistant_turn_start",
43
+ messageId: "message-123",
44
+ modeSession: owner,
45
+ }),
46
+ ToolUseStartEventSchema.parse({
47
+ type: "tool_use_start",
48
+ toolName: "browser_navigate",
49
+ input: {},
50
+ modeSession: owner,
51
+ }),
52
+ ToolResultEventSchema.parse({
53
+ type: "tool_result",
54
+ toolName: "browser_navigate",
55
+ result: "Complete",
56
+ modeSession: owner,
57
+ }),
58
+ MessageCompleteEventSchema.parse({
59
+ type: "message_complete",
60
+ modeSession: owner,
61
+ }),
62
+ GenerationHandoffEventSchema.parse({
63
+ type: "generation_handoff",
64
+ queuedCount: 1,
65
+ modeSession: owner,
66
+ }),
67
+ ];
68
+ expect(
69
+ boundaryEvents.every((event) => event.modeSession?.id === owner.id),
70
+ ).toBe(true);
71
+ });
72
+
73
+ test("keeps text and thinking deltas free of session fields", () => {
74
+ expect(
75
+ AssistantTextDeltaEventSchema.parse({
76
+ type: "assistant_text_delta",
77
+ text: "Working",
78
+ modeSession: owner,
79
+ }),
80
+ ).not.toHaveProperty("modeSession");
81
+ expect(
82
+ AssistantThinkingDeltaEventSchema.parse({
83
+ type: "assistant_thinking_delta",
84
+ thinking: "Checking",
85
+ modeSession: owner,
86
+ }),
87
+ ).not.toHaveProperty("modeSession");
88
+ });
89
+
90
+ test("exposes runtime state only for active summaries", () => {
91
+ const summary = {
92
+ id: "session-123",
93
+ conversationId: "conv-123",
94
+ mode: "browser",
95
+ status: "active",
96
+ sourceStartedAt: 100,
97
+ firstIncludedAt: null,
98
+ firstIncludedMessageId: null,
99
+ lastActivityAt: 100,
100
+ lastOwnedMessageId: null,
101
+ endedAt: null,
102
+ endReason: null,
103
+ revision: 1,
104
+ } as const;
105
+ expect(
106
+ ModeSessionDescriptorSchema.parse({
107
+ summary,
108
+ runtimeState: "waiting",
109
+ }).runtimeState,
110
+ ).toBe("waiting");
111
+ expect(
112
+ ModeSessionDescriptorSchema.safeParse({
113
+ summary: {
114
+ ...summary,
115
+ status: "completed",
116
+ endedAt: 120,
117
+ endReason: "settled",
118
+ },
119
+ runtimeState: "finishing",
120
+ }).success,
121
+ ).toBe(false);
122
+ });
123
+
124
+ test("types canonical metadata while preserving unrelated keys", () => {
125
+ expect(
126
+ messageMetadataSchema.parse({
127
+ modeSession: owner,
128
+ futureMetadata: { value: true },
129
+ }),
130
+ ).toEqual({
131
+ modeSession: owner,
132
+ futureMetadata: { value: true },
133
+ });
134
+ expect(
135
+ messageMetadataSchema.parse({
136
+ modeSession: { mode: "unknown", id: "session-123" },
137
+ futureMetadata: { value: true },
138
+ }),
139
+ ).toEqual({ futureMetadata: { value: true } });
140
+ });
141
+ });
@@ -160,6 +160,7 @@ describe("ASK_GUARDIAN notification path", () => {
160
160
  ensureConversation(convId);
161
161
 
162
162
  const session = createCallSession({
163
+ direction: "inbound",
163
164
  conversationId: convId,
164
165
  provider: "twilio",
165
166
  fromNumber: "+15550001111",
@@ -220,6 +221,7 @@ describe("ASK_GUARDIAN notification path", () => {
220
221
  };
221
222
 
222
223
  const session = createCallSession({
224
+ direction: "inbound",
223
225
  conversationId: convId,
224
226
  provider: "twilio",
225
227
  fromNumber: "+15550001111",
@@ -263,6 +265,7 @@ describe("ASK_GUARDIAN notification path", () => {
263
265
  };
264
266
 
265
267
  const session = createCallSession({
268
+ direction: "inbound",
266
269
  conversationId: convId,
267
270
  provider: "twilio",
268
271
  fromNumber: "+15550001111",
@@ -308,6 +311,7 @@ describe("ASK_GUARDIAN notification path", () => {
308
311
  };
309
312
 
310
313
  const session = createCallSession({
314
+ direction: "inbound",
311
315
  conversationId: convId,
312
316
  provider: "twilio",
313
317
  fromNumber: "+15550001111",
@@ -338,6 +342,7 @@ describe("ASK_GUARDIAN notification path", () => {
338
342
  ensureConversation(convId);
339
343
 
340
344
  const session = createCallSession({
345
+ direction: "inbound",
341
346
  conversationId: convId,
342
347
  provider: "twilio",
343
348
  fromNumber: "+15550001111",
@@ -370,6 +375,7 @@ describe("ASK_GUARDIAN notification path", () => {
370
375
  const sharedConvId = "conv-guardian-shared-thread";
371
376
 
372
377
  const session = createCallSession({
378
+ direction: "inbound",
373
379
  conversationId: convId,
374
380
  provider: "twilio",
375
381
  fromNumber: "+15550001111",
@@ -463,6 +469,7 @@ describe("ASK_GUARDIAN notification path", () => {
463
469
  };
464
470
 
465
471
  const session = createCallSession({
472
+ direction: "inbound",
466
473
  conversationId: convId,
467
474
  provider: "twilio",
468
475
  fromNumber: "+15550001111",
@@ -183,7 +183,7 @@ describe("TelegramAdapter", () => {
183
183
 
184
184
  await adapter.send(
185
185
  makePayload({
186
- sourceEventName: "watcher.escalation",
186
+ sourceEventName: "watcher.notification",
187
187
  copy: {
188
188
  title: " ",
189
189
  body: "",
@@ -191,7 +191,7 @@ describe("TelegramAdapter", () => {
191
191
  }),
192
192
  makeDestination(),
193
193
  );
194
- expect(sendCalls[2]?.text).toBe("watcher escalation");
194
+ expect(sendCalls[2]?.text).toBe("watcher notification");
195
195
  });
196
196
 
197
197
  // ── Access request inline keyboard tests ──────────────────────────────
@@ -35,6 +35,7 @@ import type {
35
35
  ChannelDeliveryPayload,
36
36
  ChannelDestination,
37
37
  } from "../notifications/types.js";
38
+ import type { BroadcastMessageOptions } from "../runtime/assistant-event-hub.js";
38
39
 
39
40
  function makePayload(
40
41
  overrides?: Partial<ChannelDeliveryPayload>,
@@ -362,3 +363,36 @@ describe("VellumAdapter update", () => {
362
363
  expect(result.error).toBe("DB write failed");
363
364
  });
364
365
  });
366
+
367
+ describe("VellumAdapter guardian scoping", () => {
368
+ function captureOptions(): {
369
+ adapter: VellumAdapter;
370
+ options: Array<BroadcastMessageOptions | undefined>;
371
+ } {
372
+ const options: Array<BroadcastMessageOptions | undefined> = [];
373
+ const adapter = new VellumAdapter((_msg, _conversationId, opts) => {
374
+ options.push(opts);
375
+ });
376
+ return { adapter, options };
377
+ }
378
+
379
+ test("a guardian-sensitive intent is delivered only to the guardian's connections", async () => {
380
+ const { adapter, options } = captureOptions();
381
+ await adapter.send(
382
+ makePayload({ sourceEventName: "guardian.question", urgency: "high" }),
383
+ makeDestination({ metadata: { guardianPrincipalId: "principal-g" } }),
384
+ );
385
+
386
+ expect(options).toEqual([{ targetActorPrincipalId: "principal-g" }]);
387
+ });
388
+
389
+ test("an ordinary intent is broadcast to every connection", async () => {
390
+ const { adapter, options } = captureOptions();
391
+ await adapter.send(
392
+ makePayload({ sourceEventName: "schedule.notify" }),
393
+ makeDestination({ metadata: { guardianPrincipalId: "principal-g" } }),
394
+ );
395
+
396
+ expect(options).toEqual([{ targetActorPrincipalId: undefined }]);
397
+ });
398
+ });
@@ -292,11 +292,23 @@ describe("serializeProviderSummary", () => {
292
292
  supports_managed_mode: true,
293
293
  managed_service_is_paid: false,
294
294
  feature_flag: null,
295
+ category: "productivity",
295
296
  tenant_host: null,
296
297
  acts_as: "user",
297
298
  });
298
299
  });
299
300
 
301
+ test("files the provider under its seeded category", () => {
302
+ // The category is catalog metadata the seed carries, not a column, so a
303
+ // provider a user registered by hand has none.
304
+ const category = (provider: string) =>
305
+ serializeProviderSummary(makeRow({ provider }))!.category;
306
+
307
+ expect(category("hubspot")).toBe("sales");
308
+ expect(category("calendly")).toBe("meetings");
309
+ expect(category("custom-provider")).toBeNull();
310
+ });
311
+
300
312
  test("exposes the tenant host a per-tenant provider needs at connect", () => {
301
313
  // Shopify's OAuth endpoints live on the merchant's own host, so a client
302
314
  // has to collect it before the managed flow can start. The summary is the
@@ -180,6 +180,7 @@ describe("GET /v1/oauth/providers", () => {
180
180
  "supports_managed_mode",
181
181
  "managed_service_is_paid",
182
182
  "feature_flag",
183
+ "category",
183
184
  "tenant_host",
184
185
  "acts_as",
185
186
  ];
@@ -185,6 +185,7 @@ import {
185
185
  } from "../daemon/conversation-agent-loop-handlers.js";
186
186
  import { readSlackMetadataFromMessageMetadata } from "../messaging/providers/slack/message-metadata.js";
187
187
  import { deliverReplyViaCallback } from "../runtime/channel-reply-delivery.js";
188
+ import { mockUnownedModeSessions } from "./helpers/mock-conversation.js";
188
189
  import { setConfig } from "./helpers/set-config.js";
189
190
 
190
191
  // ── Helpers ────────────────────────────────────────────────────────────────
@@ -216,6 +217,7 @@ function makeDeps(
216
217
  sourceThreadId: overrides.sourceThreadId,
217
218
  },
218
219
  clientTimezone: overrides.clientTimezone,
220
+ modeSessions: mockUnownedModeSessions(),
219
221
  } as unknown as EventHandlerDeps["ctx"],
220
222
  onEvent: (_msg: AssistantEvent) => {},
221
223
  reqId: "test-req-id",
@@ -102,6 +102,7 @@ import {
102
102
  handleLlmCallStarted,
103
103
  handleMessageComplete,
104
104
  } from "../daemon/conversation-agent-loop-handlers.js";
105
+ import { mockUnownedModeSessions } from "./helpers/mock-conversation.js";
105
106
 
106
107
  // ── Helpers ────────────────────────────────────────────────────────────────
107
108
 
@@ -117,6 +118,7 @@ function makeDeps(): EventHandlerDeps {
117
118
  sourceChannel: "vellum",
118
119
  trustClass: "guardian",
119
120
  },
121
+ modeSessions: mockUnownedModeSessions(),
120
122
  } as unknown as EventHandlerDeps["ctx"],
121
123
  onEvent: () => {},
122
124
  reqId: "test-req",
@@ -21,4 +21,9 @@ describe("plugin-api provider access", () => {
21
21
  // registry), not a disjoint, uninitialized module copy.
22
22
  expect(PLUGIN_API_EXPORTS).toContain("getConfiguredProvider");
23
23
  });
24
+
25
+ test("getEffectiveContextWindow is exported and shim-rebound", () => {
26
+ expect(typeof pluginApi.getEffectiveContextWindow).toBe("function");
27
+ expect(PLUGIN_API_EXPORTS).toContain("getEffectiveContextWindow");
28
+ });
24
29
  });
@@ -14,6 +14,7 @@ import {
14
14
 
15
15
  import { credentialKey } from "@vellumai/credential-storage";
16
16
 
17
+ import { PLUGIN_NAME_ENV } from "../plugin-api/plugin-name-env.js";
17
18
  import {
18
19
  CredentialResolutionError,
19
20
  resolveCredential,
@@ -22,8 +23,10 @@ import { runInPluginContext } from "../plugins/plugin-execution-context.js";
22
23
  import * as secureKeys from "../security/secure-keys.js";
23
24
  import {
24
25
  _setMetadataPath,
26
+ type CredentialMetadata,
25
27
  upsertCredentialMetadata,
26
28
  } from "../tools/credentials/metadata-store.js";
29
+ import * as metadataStore from "../tools/credentials/metadata-store.js";
27
30
 
28
31
  // Real metadata store backed by a temp file (no module mocking — a mock.module
29
32
  // on metadata-store / secure-keys would replace the whole module namespace and
@@ -65,6 +68,7 @@ beforeEach(() => {
65
68
 
66
69
  afterEach(() => {
67
70
  getSpy.mockRestore();
71
+ delete process.env[PLUGIN_NAME_ENV];
68
72
  });
69
73
 
70
74
  afterAll(() => {
@@ -145,5 +149,98 @@ describe("resolveCredential", () => {
145
149
  ),
146
150
  ).resolves.toBe("proj-id");
147
151
  });
152
+
153
+ test("scopes resolution from VELLUM_PLUGIN_NAME when ALS is empty", async () => {
154
+ seedCredential("sms", "account_sid", "sid-secret");
155
+ process.env[PLUGIN_NAME_ENV] = "sms";
156
+ await expect(resolveCredential("sms/account_sid")).resolves.toBe(
157
+ "sid-secret",
158
+ );
159
+ });
160
+
161
+ test("blocks another service when identity comes from VELLUM_PLUGIN_NAME", async () => {
162
+ seedCredential("openai", "api_key", "sk-secret");
163
+ process.env[PLUGIN_NAME_ENV] = "sms";
164
+ await expect(resolveCredential("openai/api_key")).rejects.toThrow(
165
+ /out of scope/,
166
+ );
167
+ });
168
+ });
169
+
170
+ describe("live catalog on cache miss", () => {
171
+ function liveRecord(
172
+ service: string,
173
+ field: string,
174
+ ): CredentialMetadata {
175
+ return {
176
+ credentialId: `${service}-${field}`,
177
+ service,
178
+ field,
179
+ allowedTools: [],
180
+ allowedDomains: [],
181
+ createdAt: 1,
182
+ updatedAt: 1,
183
+ };
184
+ }
185
+
186
+ test("consults the live catalog when plugin context is set and the cache misses", async () => {
187
+ const liveSpy = spyOn(
188
+ metadataStore,
189
+ "listCredentialRecordsLive",
190
+ ).mockResolvedValue({
191
+ records: [liveRecord("sms", "account_sid")],
192
+ unreachable: false,
193
+ });
194
+ secureStore.set(credentialKey("sms", "account_sid"), "live-sid");
195
+ process.env[PLUGIN_NAME_ENV] = "sms";
196
+
197
+ try {
198
+ await expect(resolveCredential("sms/account_sid")).resolves.toBe(
199
+ "live-sid",
200
+ );
201
+ expect(liveSpy).toHaveBeenCalledTimes(1);
202
+ } finally {
203
+ liveSpy.mockRestore();
204
+ }
205
+ });
206
+
207
+ test("does not list live records when no plugin is in context", async () => {
208
+ const liveSpy = spyOn(
209
+ metadataStore,
210
+ "listCredentialRecordsLive",
211
+ ).mockResolvedValue({
212
+ records: [liveRecord("sms", "account_sid")],
213
+ unreachable: false,
214
+ });
215
+ secureStore.set(credentialKey("sms", "account_sid"), "live-sid");
216
+
217
+ try {
218
+ await expect(resolveCredential("sms/account_sid")).rejects.toThrow(
219
+ /Credential not found/,
220
+ );
221
+ expect(liveSpy).not.toHaveBeenCalled();
222
+ } finally {
223
+ liveSpy.mockRestore();
224
+ }
225
+ });
226
+
227
+ test("reports an unreachable live catalog instead of not found", async () => {
228
+ const liveSpy = spyOn(
229
+ metadataStore,
230
+ "listCredentialRecordsLive",
231
+ ).mockResolvedValue({
232
+ records: [],
233
+ unreachable: true,
234
+ });
235
+ process.env[PLUGIN_NAME_ENV] = "sms";
236
+
237
+ try {
238
+ await expect(resolveCredential("sms/account_sid")).rejects.toThrow(
239
+ /unreachable/,
240
+ );
241
+ } finally {
242
+ liveSpy.mockRestore();
243
+ }
244
+ });
148
245
  });
149
246
  });
@@ -99,6 +99,8 @@ const BASELINE: Record<string, readonly string[]> = {
99
99
  "../../../../../persistence/schema/index.js",
100
100
  "../../../../../security/untrusted-content.js",
101
101
  "../../../../api/events/memory-recalled.js",
102
+ "../../../../api/events/tool-result.js",
103
+ "../../../../api/remember-tool.js",
102
104
  "../../../../api/responses/memory-v3-selection-log.js",
103
105
  "../../../../config/assistant-feature-flags.js",
104
106
  "../../../../config/default-profile-catalog.js",
@@ -166,6 +168,7 @@ const BASELINE: Record<string, readonly string[]> = {
166
168
  "../../../../util/json.js",
167
169
  "../../../../util/logger.js",
168
170
  "../../../../util/platform.js",
171
+ "../../../api/remember-tool.js",
169
172
  "../../../channels/types.js",
170
173
  "../../../config/loader.js",
171
174
  "../../../config/memory-v3-gate.js",
@@ -272,6 +275,12 @@ const BASELINE: Record<string, readonly string[]> = {
272
275
  "zod",
273
276
  ],
274
277
  "platform-hosted": ["node:fs/promises", "node:path"],
278
+ // Host-internal surface snapshot and task_progress parser. UI surfaces
279
+ // stay host-owned, so there is no plugin-api equivalent.
280
+ "task-progress": [
281
+ "../../../../daemon/conversation-surface-snapshots.js",
282
+ "../../../../runtime/task-progress.js",
283
+ ],
275
284
  session: [
276
285
  "../../../config/loader.js",
277
286
  "../../types.js",
@@ -148,6 +148,7 @@ import { persistQueuedMessageBody } from "../daemon/conversation-messaging.js";
148
148
  import type { MessageQueue } from "../daemon/conversation-queue-manager.js";
149
149
  import type { UserMessageAttachment } from "../daemon/message-protocol.js";
150
150
  import { processMessage } from "../daemon/process-message.js";
151
+ import type { TrustContext } from "../daemon/trust-context-types.js";
151
152
  import type { Message } from "../providers/types.js";
152
153
 
153
154
  function makeTestConversation() {
@@ -554,3 +555,58 @@ describe("processMessage skipUserMessageIndexing", () => {
554
555
  expect(addMessageCalls[0]!.skipIndexing).toBeUndefined();
555
556
  });
556
557
  });
558
+
559
+ describe("processMessage author", () => {
560
+ const author: TrustContext = {
561
+ sourceChannel: "slack",
562
+ trustClass: "trusted_contact",
563
+ requesterContactId: "contact-alice",
564
+ };
565
+
566
+ beforeEach(() => {
567
+ addMessageCalls.length = 0;
568
+ activeConversation = undefined;
569
+ resolveSlashForTest = (content) => ({ kind: "passthrough", content });
570
+ });
571
+
572
+ test("a relayed message names its author on the user row", async () => {
573
+ activeConversation = makeTestConversation();
574
+
575
+ await processMessage("conv-display-content", "the export needs a token", {
576
+ author,
577
+ });
578
+
579
+ expect(addMessageCalls[0]!.role).toBe("user");
580
+ expect(addMessageCalls[0]!.metadata?.provenanceContactId).toBe(
581
+ "contact-alice",
582
+ );
583
+ });
584
+
585
+ test("a message nobody relayed names no author", async () => {
586
+ activeConversation = makeTestConversation();
587
+
588
+ await processMessage("conv-display-content", "kickoff prompt body", {});
589
+
590
+ expect(addMessageCalls[0]!.metadata?.provenanceContactId).toBeUndefined();
591
+ });
592
+
593
+ test("a relayed slash command names its author on the user row, not the reply", async () => {
594
+ resolveSlashForTest = () => ({
595
+ kind: "unknown",
596
+ message: "Unknown slash command.",
597
+ });
598
+ activeConversation = makeTestConversation();
599
+
600
+ await processMessage("conv-display-content", "/missing-command", {
601
+ author,
602
+ });
603
+
604
+ expect(addMessageCalls).toHaveLength(2);
605
+ expect(addMessageCalls[0]!.role).toBe("user");
606
+ expect(addMessageCalls[0]!.metadata?.provenanceContactId).toBe(
607
+ "contact-alice",
608
+ );
609
+ expect(addMessageCalls[1]!.role).toBe("assistant");
610
+ expect(addMessageCalls[1]!.metadata?.provenanceContactId).toBeUndefined();
611
+ });
612
+ });
@@ -116,9 +116,12 @@ function resetState(): void {
116
116
  _conversationMocks.clear();
117
117
  }
118
118
 
119
+ const REACTOR_CONTACT_ID = "contact-reactor";
120
+
119
121
  function seedActiveMember(): void {
120
122
  seedContactChannel({
121
123
  sourceChannel: "slack",
124
+ contactId: REACTOR_CONTACT_ID,
122
125
  externalUserId: SLACK_USER_ID,
123
126
  externalChatId: SLACK_CHANNEL_ID,
124
127
  status: "active",
@@ -276,6 +279,8 @@ describe("Slack reaction event persistence", () => {
276
279
  // filterMessagesForUntrustedActor drops rows with no trust class.
277
280
  expect(envelope.provenanceTrustClass).toBe("trusted_contact");
278
281
  expect(envelope.provenanceSourceChannel).toBe("slack");
282
+ // The reactor wrote this row, so it names them as its author.
283
+ expect(envelope.provenanceContactId).toBe(REACTOR_CONTACT_ID);
279
284
  const slackMetaRaw = envelope.slackMeta;
280
285
  expect(typeof slackMetaRaw).toBe("string");
281
286
 
@@ -220,21 +220,37 @@ describe("requestSecretStandalone channel gate", () => {
220
220
  await promise;
221
221
  });
222
222
 
223
- test("broadcasts for a conversation-less prompt (plain CLI invocation)", async () => {
223
+ test("mints a collection link for a conversation-less prompt (headless exec)", async () => {
224
+ /**
225
+ * A prompt with no conversationId (Doctor's `run_assistant_cli`, a bare
226
+ * shell) has no surface that can render it: clients drop
227
+ * conversation-scoped events without a conversationId and
228
+ * `/v1/pending-interactions` is keyed by conversation. Broadcasting would
229
+ * only sit until the permission timeout, so it must fail fast into the
230
+ * collection-link fallback.
231
+ */
232
+ gatewayMintResult = {
233
+ ok: true,
234
+ token: "tok",
235
+ url: "https://x.test/assistant/credentials/enter#token=tok",
236
+ expiresAt: 1234,
237
+ };
238
+
224
239
  // WHEN a standalone prompt carries no conversationId
225
- const promise = requestSecretStandalone({
240
+ const result = await requestSecretStandalone({
226
241
  service: "stripe",
227
242
  field: "api_key",
228
243
  label: "Stripe API Key",
229
244
  });
230
245
 
231
- // THEN the secret_request is broadcast (desktop/web clients render it)
232
- expect(broadcastMessages).toHaveLength(1);
233
- expect(broadcastMessages[0]!.type).toBe("secret_request");
234
-
235
- const entry = [..._piStore.values()][0];
236
- entry?.rpcResolve?.({ value: "v", delivery: "store" });
237
- await promise;
246
+ // THEN nothing is broadcast or registered and the link is returned
247
+ expect(broadcastMessages).toHaveLength(0);
248
+ expect(_piStore.size).toBe(0);
249
+ expect(result.error).toBe("unsupported_channel");
250
+ expect(result.collectionUrl).toBe(
251
+ "https://x.test/assistant/credentials/enter#token=tok",
252
+ );
253
+ expect(gatewayMintCalls).toHaveLength(1);
238
254
  });
239
255
 
240
256
  test("broadcasts when the conversation is not loaded in the registry", async () => {
@@ -270,7 +270,7 @@ describe("SSE reconnect replay (B7.2)", () => {
270
270
  test("replay excludes events the subscriber is not targeted to receive", async () => {
271
271
  // Stamp three events: two untargeted (seq 1, 3) + one with a
272
272
  // capability target (seq 2, host_bash). A process subscriber
273
- // does NOT match capability targeting (matchesSubscriber requires
273
+ // does NOT match capability targeting (matchesTargeting requires
274
274
  // type=client + matching capability), so the replay filters out
275
275
  // seq 2. The subscriber receives seq 1 and 3.
276
276
  const { conversationId } = getOrCreateConversation("replay-targeting");