@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
@@ -327,6 +327,7 @@ describe("runtime call routes — HTTP layer", () => {
327
327
  ensureConversation("conv-get-1");
328
328
 
329
329
  const session = createCallSession({
330
+ direction: "outbound",
330
331
  conversationId: "conv-get-1",
331
332
  provider: "twilio",
332
333
  fromNumber: "+15550001111",
@@ -378,6 +379,7 @@ describe("runtime call routes — HTTP layer", () => {
378
379
  ensureConversation("conv-cancel-1");
379
380
 
380
381
  const session = createCallSession({
382
+ direction: "inbound",
381
383
  conversationId: "conv-cancel-1",
382
384
  provider: "twilio",
383
385
  fromNumber: "+15550001111",
@@ -407,6 +409,7 @@ describe("runtime call routes — HTTP layer", () => {
407
409
  ensureConversation("conv-cancel-2");
408
410
 
409
411
  const session = createCallSession({
412
+ direction: "inbound",
410
413
  conversationId: "conv-cancel-2",
411
414
  provider: "twilio",
412
415
  fromNumber: "+15550001111",
@@ -447,6 +450,7 @@ describe("runtime call routes — HTTP layer", () => {
447
450
  ensureConversation("conv-answer-badjson");
448
451
 
449
452
  const session = createCallSession({
453
+ direction: "inbound",
450
454
  conversationId: "conv-answer-badjson",
451
455
  provider: "twilio",
452
456
  fromNumber: "+15550001111",
@@ -469,6 +473,7 @@ describe("runtime call routes — HTTP layer", () => {
469
473
  ensureConversation("conv-answer-1");
470
474
 
471
475
  const session = createCallSession({
476
+ direction: "inbound",
472
477
  conversationId: "conv-answer-1",
473
478
  provider: "twilio",
474
479
  fromNumber: "+15550001111",
@@ -495,6 +500,7 @@ describe("runtime call routes — HTTP layer", () => {
495
500
  ensureConversation("conv-answer-2");
496
501
 
497
502
  const session = createCallSession({
503
+ direction: "inbound",
498
504
  conversationId: "conv-answer-2",
499
505
  provider: "twilio",
500
506
  fromNumber: "+15550001111",
@@ -517,6 +523,7 @@ describe("runtime call routes — HTTP layer", () => {
517
523
  ensureConversation("conv-answer-3");
518
524
 
519
525
  const session = createCallSession({
526
+ direction: "inbound",
520
527
  conversationId: "conv-answer-3",
521
528
  provider: "twilio",
522
529
  fromNumber: "+15550001111",
@@ -548,6 +555,7 @@ describe("runtime call routes — HTTP layer", () => {
548
555
  ensureConversation("conv-instr-badjson");
549
556
 
550
557
  const session = createCallSession({
558
+ direction: "inbound",
551
559
  conversationId: "conv-instr-badjson",
552
560
  provider: "twilio",
553
561
  fromNumber: "+15550001111",
@@ -570,6 +578,7 @@ describe("runtime call routes — HTTP layer", () => {
570
578
  ensureConversation("conv-instr-empty");
571
579
 
572
580
  const session = createCallSession({
581
+ direction: "inbound",
573
582
  conversationId: "conv-instr-empty",
574
583
  provider: "twilio",
575
584
  fromNumber: "+15550001111",
@@ -596,6 +605,7 @@ describe("runtime call routes — HTTP layer", () => {
596
605
  ensureConversation("conv-instr-missing");
597
606
 
598
607
  const session = createCallSession({
608
+ direction: "inbound",
599
609
  conversationId: "conv-instr-missing",
600
610
  provider: "twilio",
601
611
  fromNumber: "+15550001111",
@@ -640,6 +650,7 @@ describe("runtime call routes — HTTP layer", () => {
640
650
  ensureConversation("conv-instr-ended");
641
651
 
642
652
  const session = createCallSession({
653
+ direction: "inbound",
643
654
  conversationId: "conv-instr-ended",
644
655
  provider: "twilio",
645
656
  fromNumber: "+15550001111",
@@ -668,6 +679,7 @@ describe("runtime call routes — HTTP layer", () => {
668
679
  ensureConversation("conv-instr-no-orch");
669
680
 
670
681
  const session = createCallSession({
682
+ direction: "inbound",
671
683
  conversationId: "conv-instr-no-orch",
672
684
  provider: "twilio",
673
685
  fromNumber: "+15550001111",
@@ -53,9 +53,14 @@ function resetTables() {
53
53
  }
54
54
 
55
55
  /** Wrapper that ensures the FK conversation row exists before creating a session. */
56
- function createTestCallSession(opts: Parameters<typeof createCallSession>[0]) {
56
+ function createTestCallSession(
57
+ opts: Omit<Parameters<typeof createCallSession>[0], "direction"> & {
58
+ direction?: Parameters<typeof createCallSession>[0]["direction"];
59
+ },
60
+ ) {
57
61
  ensureConversation(opts.conversationId);
58
- return createCallSession(opts);
62
+ // Direction only shapes the funnel stamp; these suites test other things.
63
+ return createCallSession({ direction: "inbound", ...opts });
59
64
  }
60
65
 
61
66
  describe("call-store", () => {
@@ -98,6 +98,7 @@ import {
98
98
  clearConversations,
99
99
  setConversation,
100
100
  } from "../daemon/conversation-registry.js";
101
+ import type { TrustContext } from "../daemon/trust-context-types.js";
101
102
  import { getDb } from "../persistence/db-connection.js";
102
103
  import { initializeDb } from "../persistence/db-init.js";
103
104
  import * as deliveryCrud from "../persistence/delivery-crud.js";
@@ -318,7 +319,11 @@ describe("channel-retry-sweep", () => {
318
319
  }
319
320
  | undefined;
320
321
 
322
+ let capturedAuthor: TrustContext | undefined;
323
+ let capturedTrust: TrustContext | undefined;
321
324
  await sweepFailedEvents(async (conversationId, _content, options) => {
325
+ capturedAuthor = options?.author;
326
+ capturedTrust = options?.trustContext;
322
327
  capturedOptions = options as {
323
328
  trustContext?: {
324
329
  trustClass?: string;
@@ -345,6 +350,10 @@ describe("channel-retry-sweep", () => {
345
350
  "principal-1",
346
351
  );
347
352
  expect(capturedOptions?.isInteractive).toBe(c.expectedInteractive);
353
+ // The replay persists the sender's own message, so it names them as
354
+ // the row's author, exactly as live ingress does.
355
+ expect(capturedAuthor?.trustClass).toBe(c.trustClass);
356
+ expect(capturedAuthor).toEqual(capturedTrust);
348
357
 
349
358
  const db = getDb();
350
359
  const row = db
@@ -99,6 +99,7 @@ import {
99
99
  _resetRevealSuccessRegistryForTest,
100
100
  recordRevealSuccess,
101
101
  } from "../runtime/reveal-success-registry.js";
102
+ import { mockUnownedModeSessions } from "./helpers/mock-conversation.js";
102
103
  import {
103
104
  SYNTHETIC_OPAQUE_CREDENTIAL,
104
105
  SYNTHETIC_OPENAI_PROJECT_KEY,
@@ -122,6 +123,7 @@ function createMockDeps(collected: AssistantEvent[]): EventHandlerDeps {
122
123
  emitActivityState: () => {},
123
124
  markWorkspaceTopLevelDirty: () => {},
124
125
  currentTurnSurfaces: [],
126
+ modeSessions: mockUnownedModeSessions(),
125
127
  } as unknown as EventHandlerDeps["ctx"],
126
128
  onEvent: (msg: AssistantEvent) => {
127
129
  collected.push(msg);
@@ -140,9 +140,17 @@ registerSkillTools("app-builder", [mockBundledSkillTool]);
140
140
 
141
141
  // Register CU tools so check() can look them up in the tool registry
142
142
  // instead of falling through to Medium (unknown tool).
143
- import { allComputerUseTools } from "../tools/computer-use/definitions.js";
144
- for (const tool of allComputerUseTools) {
145
- registerTool(tool);
143
+ import { COMPUTER_USE_TOOL_NAMES } from "./test-support/computer-use-skill-harness.js";
144
+ for (const name of COMPUTER_USE_TOOL_NAMES) {
145
+ registerTool({
146
+ name,
147
+ description: name,
148
+ category: "computer-use",
149
+ defaultRiskLevel: RiskLevel.Low,
150
+ executionTarget: "host",
151
+ input_schema: { type: "object", properties: {} },
152
+ execute: async () => ({ content: "ok", isError: false }),
153
+ });
146
154
  }
147
155
 
148
156
  function writeSkill(
@@ -36,7 +36,7 @@ mock.module("../persistence/conversation-crud.js", () => ({
36
36
  content,
37
37
  metadata: options?.metadata,
38
38
  });
39
- return { id: `persisted-${addMessageCalls.length}` };
39
+ return { id: `persisted-${addMessageCalls.length}`, createdAt: 100 };
40
40
  },
41
41
  getConversation: () => null,
42
42
  provenanceFromTrustContext: () => ({}),
@@ -189,6 +189,40 @@ describe("client OS surface metadata persistence", () => {
189
189
  browser_family: "safari",
190
190
  });
191
191
  });
192
+
193
+ test("strips caller ownership and tracks only the inserted structural row", async () => {
194
+ const acceptTurn = mock(() => ({
195
+ id: "session-123",
196
+ mode: "browser" as const,
197
+ }));
198
+ const trackPersistedRow = mock(() => {});
199
+ const ctx = Object.assign(createWebTurnContext("web"), {
200
+ modeSessions: { acceptTurn, trackPersistedRow },
201
+ });
202
+ await persistQueuedMessageBody(ctx, {
203
+ content: "continue",
204
+ requestId: "req-structural",
205
+ activeSurfaceId: "surface-123",
206
+ metadata: {
207
+ modeSession: { id: "spoofed", mode: "computer_use" },
208
+ },
209
+ });
210
+
211
+ expect(lastUserMetadata().modeSession).toBeUndefined();
212
+ expect(acceptTurn).toHaveBeenCalledWith("req-structural", {
213
+ kind: "surface",
214
+ responseId: "surface-123",
215
+ });
216
+ expect(trackPersistedRow).toHaveBeenCalledWith(
217
+ "req-structural",
218
+ "persisted-1",
219
+ 100,
220
+ {
221
+ publishMessagesChanged: true,
222
+ startsDisplayBoundary: false,
223
+ },
224
+ );
225
+ });
192
226
  });
193
227
 
194
228
  /**
@@ -3,7 +3,6 @@ import { resolve } from "node:path";
3
3
  import { afterAll, describe, expect, test } from "bun:test";
4
4
 
5
5
  import { RiskLevel } from "../permissions/types.js";
6
- import { allComputerUseTools } from "../tools/computer-use/definitions.js";
7
6
  import {
8
7
  __resetRegistryForTesting,
9
8
  getTool,
@@ -74,30 +73,6 @@ describe("computer-use skill manifest regression", () => {
74
73
  }
75
74
  });
76
75
 
77
- test("manifest descriptions match core definitions", async () => {
78
- await initializeTools();
79
-
80
- for (const cuTool of allComputerUseTools) {
81
- const manifestTool = manifest.tools.find(
82
- (t: { name: string }) => t.name === cuTool.name,
83
- );
84
- expect(manifestTool).toBeDefined();
85
- expect(manifestTool.description).toBe(cuTool.description);
86
- }
87
- });
88
-
89
- test("manifest input_schema matches core definitions", async () => {
90
- await initializeTools();
91
-
92
- for (const cuTool of allComputerUseTools) {
93
- const manifestTool = manifest.tools.find(
94
- (t: { name: string }) => t.name === cuTool.name,
95
- );
96
- expect(manifestTool).toBeDefined();
97
- expect(manifestTool.input_schema).toEqual(cuTool.input_schema);
98
- }
99
- });
100
-
101
76
  test("CU action tools are not registered as core tools after initializeTools()", async () => {
102
77
  await initializeTools();
103
78
 
@@ -1,246 +1,14 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
 
3
- import {
4
- allComputerUseTools,
5
- computerUseClickTool,
6
- computerUseDoneTool,
7
- computerUseDragTool,
8
- computerUseKeyTool,
9
- computerUseObserveTool,
10
- computerUseOpenAppTool,
11
- computerUseRespondTool,
12
- computerUseRunAppleScriptTool,
13
- computerUseScrollTool,
14
- computerUseTypeTextTool,
15
- computerUseWaitTool,
16
- } from "../tools/computer-use/definitions.js";
17
3
  import { forwardComputerUseProxyTool } from "../tools/computer-use/skill-proxy-bridge.js";
18
4
  import type { ToolContext } from "../tools/types.js";
19
5
 
20
- interface JsonSchema {
21
- type?: string;
22
- required?: string[];
23
- properties?: Record<string, unknown>;
24
- }
25
-
26
- /** Cast a tool definition's input_schema to a usable JSON Schema shape. */
27
- function schema(tool: { input_schema?: object }): JsonSchema {
28
- return tool.input_schema as JsonSchema;
29
- }
30
-
31
6
  const ctx: ToolContext = {
32
7
  workingDir: "/tmp",
33
- conversationId: "test-conversation",
8
+ conversationId: "conv-123",
34
9
  trustClass: "guardian",
35
10
  };
36
11
 
37
- // ── Tool definitions ────────────────────────────────────────────────
38
-
39
- describe("computer-use tool definitions", () => {
40
- test("allComputerUseTools contains 12 tools", () => {
41
- expect(allComputerUseTools.length).toBe(12);
42
- });
43
-
44
- test("all tools belong to computer-use category", () => {
45
- for (const tool of allComputerUseTools) {
46
- expect(tool.category).toBe("computer-use");
47
- }
48
- });
49
-
50
- test("all tools have unique names", () => {
51
- const names = allComputerUseTools.map((t) => t.name);
52
- expect(new Set(names).size).toBe(names.length);
53
- });
54
-
55
- test("all tools have descriptions", () => {
56
- for (const tool of allComputerUseTools) {
57
- expect(tool.description!.length).toBeGreaterThan(0);
58
- }
59
- });
60
- });
61
-
62
- // ── observe ─────────────────────────────────────────────────────────
63
-
64
- describe("computer_use_observe", () => {
65
- test("supports target_client_id", () => {
66
- const props = schema(computerUseObserveTool).properties as Record<
67
- string,
68
- { type: string }
69
- >;
70
- expect(props.target_client_id.type).toBe("string");
71
- });
72
- });
73
-
74
- // ── Unified click tool ──────────────────────────────────────────────
75
-
76
- describe("computer_use_click (unified)", () => {
77
- test("has correct name", () => {
78
- expect(computerUseClickTool.name).toBe("computer_use_click");
79
- });
80
-
81
- test("schema requires reasoning", () => {
82
- expect(schema(computerUseClickTool).required).toContain("reasoning");
83
- });
84
-
85
- test("schema supports click_type enum", () => {
86
- const props = schema(computerUseClickTool).properties as Record<
87
- string,
88
- { type: string; enum?: string[] }
89
- >;
90
- expect(props.click_type.type).toBe("string");
91
- expect(props.click_type.enum).toEqual(["single", "double", "right"]);
92
- });
93
-
94
- test("schema supports element_id and coordinates", () => {
95
- const props = schema(computerUseClickTool).properties as Record<
96
- string,
97
- { type: string }
98
- >;
99
- expect(props.element_id.type).toBe("integer");
100
- expect(props.x.type).toBe("integer");
101
- expect(props.y.type).toBe("integer");
102
- });
103
-
104
- test("execute returns isError when no proxy resolver is configured", async () => {
105
- const result = await computerUseClickTool.execute({}, ctx);
106
- expect(result.isError).toBe(true);
107
- expect(result.content).toContain(
108
- "The Vellum desktop app is needed to view or control your screen",
109
- );
110
- expect(result.content).toContain("https://www.vellum.ai/downloads");
111
- });
112
- });
113
-
114
- // ── type_text ───────────────────────────────────────────────────────
115
-
116
- describe("computer_use_type_text", () => {
117
- test("requires text and reasoning", () => {
118
- expect(schema(computerUseTypeTextTool).required).toContain("text");
119
- expect(schema(computerUseTypeTextTool).required).toContain("reasoning");
120
- });
121
-
122
- test("execute returns isError when no proxy resolver is configured", async () => {
123
- const result = await computerUseTypeTextTool.execute({}, ctx);
124
- expect(result.isError).toBe(true);
125
- expect(result.content).toContain(
126
- "The Vellum desktop app is needed to view or control your screen",
127
- );
128
- expect(result.content).toContain("https://www.vellum.ai/downloads");
129
- });
130
- });
131
-
132
- // ── key ─────────────────────────────────────────────────────────────
133
-
134
- describe("computer_use_key", () => {
135
- test("requires key and reasoning", () => {
136
- expect(schema(computerUseKeyTool).required).toContain("key");
137
- expect(schema(computerUseKeyTool).required).toContain("reasoning");
138
- });
139
-
140
- test("execute returns isError when no proxy resolver is configured", async () => {
141
- const result = await computerUseKeyTool.execute({}, ctx);
142
- expect(result.isError).toBe(true);
143
- expect(result.content).toContain(
144
- "The Vellum desktop app is needed to view or control your screen",
145
- );
146
- expect(result.content).toContain("https://www.vellum.ai/downloads");
147
- });
148
- });
149
-
150
- // ── scroll ──────────────────────────────────────────────────────────
151
-
152
- describe("computer_use_scroll", () => {
153
- test("requires direction, amount, and reasoning", () => {
154
- expect(schema(computerUseScrollTool).required).toContain("direction");
155
- expect(schema(computerUseScrollTool).required).toContain("amount");
156
- expect(schema(computerUseScrollTool).required).toContain("reasoning");
157
- });
158
-
159
- test("direction enum includes up, down, left, right", () => {
160
- const props = schema(computerUseScrollTool).properties as Record<
161
- string,
162
- { enum?: string[] }
163
- >;
164
- expect(props.direction.enum).toEqual(["up", "down", "left", "right"]);
165
- });
166
- });
167
-
168
- // ── drag ────────────────────────────────────────────────────────────
169
-
170
- describe("computer_use_drag", () => {
171
- test("supports source and destination coordinates", () => {
172
- const props = schema(computerUseDragTool).properties as Record<
173
- string,
174
- { type: string }
175
- >;
176
- expect(props.element_id.type).toBe("integer");
177
- expect(props.to_element_id.type).toBe("integer");
178
- expect(props.x.type).toBe("integer");
179
- expect(props.y.type).toBe("integer");
180
- expect(props.to_x.type).toBe("integer");
181
- expect(props.to_y.type).toBe("integer");
182
- });
183
-
184
- test("requires reasoning only", () => {
185
- expect(schema(computerUseDragTool).required).toEqual(["reasoning"]);
186
- });
187
- });
188
-
189
- // ── wait ────────────────────────────────────────────────────────────
190
-
191
- describe("computer_use_wait", () => {
192
- test("requires duration_ms and reasoning", () => {
193
- expect(schema(computerUseWaitTool).required).toContain("duration_ms");
194
- expect(schema(computerUseWaitTool).required).toContain("reasoning");
195
- });
196
- });
197
-
198
- // ── open_app ────────────────────────────────────────────────────────
199
-
200
- describe("computer_use_open_app", () => {
201
- test("requires app_name and reasoning", () => {
202
- expect(schema(computerUseOpenAppTool).required).toContain("app_name");
203
- expect(schema(computerUseOpenAppTool).required).toContain("reasoning");
204
- });
205
- });
206
-
207
- // ── run_applescript ─────────────────────────────────────────────────
208
-
209
- describe("computer_use_run_applescript", () => {
210
- test("requires script and reasoning", () => {
211
- expect(schema(computerUseRunAppleScriptTool).required).toContain("script");
212
- expect(schema(computerUseRunAppleScriptTool).required).toContain(
213
- "reasoning",
214
- );
215
- });
216
-
217
- test("description warns against do shell script", () => {
218
- expect(computerUseRunAppleScriptTool.description).toContain(
219
- "do shell script",
220
- );
221
- expect(computerUseRunAppleScriptTool.description).toContain("blocked");
222
- });
223
- });
224
-
225
- // ── done ────────────────────────────────────────────────────────────
226
-
227
- describe("computer_use_done", () => {
228
- test("requires summary", () => {
229
- expect(schema(computerUseDoneTool).required).toContain("summary");
230
- });
231
- });
232
-
233
- // ── respond ─────────────────────────────────────────────────────────
234
-
235
- describe("computer_use_respond", () => {
236
- test("requires answer and reasoning", () => {
237
- expect(schema(computerUseRespondTool).required).toContain("answer");
238
- expect(schema(computerUseRespondTool).required).toContain("reasoning");
239
- });
240
- });
241
-
242
- // ── skill-proxy-bridge ──────────────────────────────────────────────
243
-
244
12
  describe("forwardComputerUseProxyTool", () => {
245
13
  test("returns error when no proxy resolver available", async () => {
246
14
  const result = await forwardComputerUseProxyTool(
@@ -110,6 +110,45 @@ describe("setImageGenModel — provider derived from model prefix", () => {
110
110
  });
111
111
  });
112
112
 
113
+ describe("setImageGenModel with provider openrouter", () => {
114
+ test("a model change leaves provider openrouter untouched", () => {
115
+ writeConfig({
116
+ services: {
117
+ "image-generation": {
118
+ provider: "openrouter",
119
+ model: "google/gemini-3.1-flash-image-preview",
120
+ },
121
+ },
122
+ });
123
+
124
+ setImageGenModel("openai/gpt-image-2", makeCtx());
125
+
126
+ const raw = readConfig() as {
127
+ services: { "image-generation": { provider: string; model: string } };
128
+ };
129
+ expect(raw.services["image-generation"].model).toBe("openai/gpt-image-2");
130
+ expect(raw.services["image-generation"].provider).toBe("openrouter");
131
+ });
132
+
133
+ test("a google/ slug does not rewrite provider to gemini", () => {
134
+ writeConfig({
135
+ services: {
136
+ "image-generation": {
137
+ provider: "openrouter",
138
+ model: "openai/gpt-image-2",
139
+ },
140
+ },
141
+ });
142
+
143
+ setImageGenModel("google/gemini-3.1-flash-image-preview", makeCtx());
144
+
145
+ const raw = readConfig() as {
146
+ services: { "image-generation": { provider: string; model: string } };
147
+ };
148
+ expect(raw.services["image-generation"].provider).toBe("openrouter");
149
+ });
150
+ });
151
+
113
152
  describe("setImageGenModel with provider vellum", () => {
114
153
  test("a model change leaves provider vellum untouched", () => {
115
154
  writeConfig({
@@ -110,6 +110,22 @@ describe("AssistantConfigSchema", () => {
110
110
  expect(result.services["image-generation"].model).toBe("gpt-image-2");
111
111
  });
112
112
 
113
+ test("accepts openrouter as an image generation provider", () => {
114
+ const result = AssistantConfigSchema.parse({
115
+ services: {
116
+ "image-generation": {
117
+ provider: "openrouter",
118
+ model: "google/gemini-3.1-flash-image-preview",
119
+ },
120
+ },
121
+ });
122
+
123
+ expect(result.services["image-generation"].provider).toBe("openrouter");
124
+ expect(result.services["image-generation"].model).toBe(
125
+ "google/gemini-3.1-flash-image-preview",
126
+ );
127
+ });
128
+
113
129
  test("accepts Tavily as a web search provider", () => {
114
130
  const result = AssistantConfigSchema.parse({
115
131
  services: {
@@ -315,6 +315,30 @@ describe("ConfigWatcher workspace file handlers", () => {
315
315
  expect(evictCallCount).toBe(1);
316
316
  });
317
317
 
318
+ test("config.json change reloads MCP when tools.mcpGlobalMaxTools changes", async () => {
319
+ watcher.initFingerprint({
320
+ tools: { exclude: [], mcpGlobalMaxTools: 50 },
321
+ } as never);
322
+ watcher.refreshConfigFromSources = async () => true;
323
+ watcher.start();
324
+ simulateFileChange(WORKSPACE_DIR, "config.json");
325
+ await new Promise((r) => setTimeout(r, WAIT_MS));
326
+ expect(mcpReloadCallCount).toBe(1);
327
+ expect(evictCallCount).toBe(1);
328
+ });
329
+
330
+ test("config.json change does not reload MCP when the global max is unchanged", async () => {
331
+ watcher.initFingerprint({
332
+ tools: { exclude: [] },
333
+ } as never);
334
+ watcher.refreshConfigFromSources = async () => true;
335
+ watcher.start();
336
+ simulateFileChange(WORKSPACE_DIR, "config.json");
337
+ await new Promise((r) => setTimeout(r, WAIT_MS));
338
+ expect(mcpReloadCallCount).toBe(0);
339
+ expect(evictCallCount).toBe(1);
340
+ });
341
+
318
342
  test("config.json change is suppressed when suppressConfigReload is true", async () => {
319
343
  let refreshCalled = false;
320
344
  watcher.refreshConfigFromSources = async () => {