@vellumai/assistant 0.12.2 → 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 (772) hide show
  1. package/.env.example +2 -0
  2. package/AGENTS.md +1 -1
  3. package/ARCHITECTURE.md +43 -29
  4. package/Dockerfile +63 -0
  5. package/docs/architecture/integrations.md +7 -0
  6. package/docs/architecture/memory.md +17 -2
  7. package/docs/architecture/security.md +10 -5
  8. package/docs/architecture/turn-actor.md +2 -0
  9. package/docs/credential-execution-service.md +1 -1
  10. package/docs/desktop-browser-cli.md +50 -5
  11. package/docs/live-voice-task-outcomes.md +100 -0
  12. package/docs/mode-sessions.md +183 -0
  13. package/docs/voice-input-diagnostics.md +58 -0
  14. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +2 -1
  15. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
  16. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  17. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  18. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
  19. package/node_modules/@vellumai/environments/src/shell.test.ts +21 -0
  20. package/node_modules/@vellumai/environments/src/shell.ts +24 -0
  21. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
  22. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
  23. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  24. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  25. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
  26. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -0
  27. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -2
  28. package/node_modules/@vellumai/gateway-client/src/index.ts +4 -1
  29. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +38 -7
  30. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +5 -6
  31. package/node_modules/@vellumai/service-contracts/package.json +2 -1
  32. package/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
  33. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  34. package/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  35. package/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
  36. package/node_modules/@vellumai/slack-text/src/index.ts +4 -8
  37. package/openapi.yaml +716 -16
  38. package/package.json +1 -1
  39. package/scripts/smoke-desktop-browser-cli.ts +11 -26
  40. package/scripts/smoke-desktop-window-theme.ts +2 -3
  41. package/scripts/sync-llm-catalog.ts +3 -0
  42. package/scripts/voice-ttft-spike.ts +2 -2
  43. package/src/__tests__/agent-loop-output-hooks.test.ts +150 -1
  44. package/src/__tests__/agent-loop-provider-error-recording.test.ts +87 -19
  45. package/src/__tests__/agent-loop.test.ts +259 -0
  46. package/src/__tests__/agent-wake-delegation-prompt.test.ts +64 -2
  47. package/src/__tests__/annotate-activity-metadata.test.ts +3 -1
  48. package/src/__tests__/annotate-risk-options.test.ts +2 -0
  49. package/src/__tests__/answered-question-persistence.test.ts +2 -0
  50. package/src/__tests__/anthropic-gateway-shared.test.ts +22 -0
  51. package/src/__tests__/anthropic-provider.test.ts +55 -0
  52. package/src/__tests__/approval-interception-trust-gates.test.ts +40 -0
  53. package/src/__tests__/approval-message-composer.test.ts +1 -118
  54. package/src/__tests__/approval-routes-http.test.ts +3 -0
  55. package/src/__tests__/assistant-event-hub-connection-history.test.ts +111 -0
  56. package/src/__tests__/assistant-event-hub-targeted.test.ts +50 -0
  57. package/src/__tests__/assistant-event-targeting.test.ts +186 -0
  58. package/src/__tests__/assistant-stream-state.test.ts +29 -9
  59. package/src/__tests__/attachments-store.test.ts +22 -3
  60. package/src/__tests__/browser-fill-credential.test.ts +11 -22
  61. package/src/__tests__/btw-routes.test.ts +4 -1
  62. package/src/__tests__/build-persisted-content.test.ts +1 -1
  63. package/src/__tests__/call-conversation-messages.test.ts +5 -0
  64. package/src/__tests__/call-recovery.test.ts +7 -2
  65. package/src/__tests__/call-routes-http.test.ts +12 -0
  66. package/src/__tests__/call-store.test.ts +7 -2
  67. package/src/__tests__/channel-approval.test.ts +9 -14
  68. package/src/__tests__/channel-reply-delivery.test.ts +56 -0
  69. package/src/__tests__/channel-retry-sweep.test.ts +9 -0
  70. package/src/__tests__/chat-credential-redaction.test.ts +23 -0
  71. package/src/__tests__/chat-reveal-guard-priming.test.ts +2 -0
  72. package/src/__tests__/checker.test.ts +11 -3
  73. package/src/__tests__/client-os-metadata-persistence.test.ts +35 -1
  74. package/src/__tests__/computer-use-screenshot-attachments.test.ts +411 -0
  75. package/src/__tests__/computer-use-screenshot-selection.test.ts +50 -0
  76. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +0 -25
  77. package/src/__tests__/computer-use-tools.test.ts +1 -233
  78. package/src/__tests__/config-model-image-provider.test.ts +39 -0
  79. package/src/__tests__/config-schema.test.ts +16 -0
  80. package/src/__tests__/config-watcher.test.ts +24 -0
  81. package/src/__tests__/context-search-agent-runner.test.ts +260 -1
  82. package/src/__tests__/context-search-fanout.test.ts +1 -1
  83. package/src/__tests__/context-search-types.test.ts +7 -7
  84. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +8 -2
  85. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +2 -0
  86. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  87. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
  88. package/src/__tests__/conversation-agent-loop.test.ts +797 -16
  89. package/src/__tests__/conversation-app-control-lifecycle.test.ts +53 -1
  90. package/src/__tests__/conversation-attachments.test.ts +106 -0
  91. package/src/__tests__/conversation-evictor.test.ts +62 -37
  92. package/src/__tests__/conversation-fork-crud.test.ts +191 -0
  93. package/src/__tests__/conversation-history-boundary-repair-failure.test.ts +174 -0
  94. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +2 -0
  95. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
  96. package/src/__tests__/conversation-rendered-delegation-state.test.ts +276 -0
  97. package/src/__tests__/conversation-retry-route.test.ts +22 -0
  98. package/src/__tests__/conversation-routes-disk-view.test.ts +2 -0
  99. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +2 -0
  100. package/src/__tests__/conversation-routes-guardian-reply.test.ts +10 -0
  101. package/src/__tests__/conversation-routes-hidden-queue.test.ts +2 -0
  102. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
  103. package/src/__tests__/conversation-runtime-assembly.test.ts +29 -0
  104. package/src/__tests__/conversation-surface-snapshots.test.ts +543 -0
  105. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +151 -0
  106. package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +63 -1
  107. package/src/__tests__/conversation-tool-setup-attribution.test.ts +23 -0
  108. package/src/__tests__/conversation-undo.test.ts +61 -0
  109. package/src/__tests__/credential-execution-client.test.ts +72 -55
  110. package/src/__tests__/credential-prompt-route.test.ts +35 -3
  111. package/src/__tests__/cu-unified-flow.test.ts +82 -1
  112. package/src/__tests__/db-conversation-tool-surface.test.ts +221 -0
  113. package/src/__tests__/db-mode-sessions-migration.test.ts +175 -0
  114. package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -0
  115. package/src/__tests__/dm-backfill.test.ts +91 -1
  116. package/src/__tests__/document-create-route.test.ts +88 -0
  117. package/src/__tests__/document-sync-tags.test.ts +27 -0
  118. package/src/__tests__/emit-signal-routing-intent.test.ts +142 -2
  119. package/src/__tests__/events-tail-route.test.ts +58 -0
  120. package/src/__tests__/evict-conversations-for-reload.test.ts +57 -8
  121. package/src/__tests__/guardian-action-sweep.test.ts +16 -0
  122. package/src/__tests__/guardian-dispatch.test.ts +13 -0
  123. package/src/__tests__/headless-browser-interactions.test.ts +64 -20
  124. package/src/__tests__/heartbeat-service.test.ts +2 -59
  125. package/src/__tests__/helpers/mock-conversation.ts +21 -0
  126. package/src/__tests__/helpers/native-web-search-harness.ts +2 -0
  127. package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +5 -0
  128. package/src/__tests__/history-repair.test.ts +53 -0
  129. package/src/__tests__/host-cu-proxy.test.ts +46 -2
  130. package/src/__tests__/http-user-message-parity.test.ts +2 -0
  131. package/src/__tests__/image-credentials.test.ts +49 -0
  132. package/src/__tests__/image-service-dispatcher.test.ts +45 -0
  133. package/src/__tests__/inference-profile-session-handler.test.ts +26 -0
  134. package/src/__tests__/interrupt-on-send.test.ts +57 -43
  135. package/src/__tests__/interrupt-turn-note.test.ts +5 -6
  136. package/src/__tests__/list-messages-tool-merge.test.ts +85 -1
  137. package/src/__tests__/llm-catalog-parity.test.ts +27 -4
  138. package/src/__tests__/media-generate-image.test.ts +49 -1
  139. package/src/__tests__/message-provenance-contact-id.test.ts +69 -0
  140. package/src/__tests__/migration-export-to-gcs.test.ts +142 -0
  141. package/src/__tests__/mode-session-history.test.ts +245 -0
  142. package/src/__tests__/mode-session-recovery.test.ts +222 -0
  143. package/src/__tests__/mode-session-wire.test.ts +141 -0
  144. package/src/__tests__/notification-guardian-path.test.ts +7 -0
  145. package/src/__tests__/notification-telegram-adapter.test.ts +2 -2
  146. package/src/__tests__/notification-vellum-adapter.test.ts +34 -0
  147. package/src/__tests__/oauth-apps-routes.test.ts +1 -0
  148. package/src/__tests__/oauth-commands-routes.test.ts +114 -101
  149. package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
  150. package/src/__tests__/oauth-provider-serializer.test.ts +13 -0
  151. package/src/__tests__/oauth-providers-routes.test.ts +3 -0
  152. package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
  153. package/src/__tests__/persist-media-references.test.ts +50 -0
  154. package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
  155. package/src/__tests__/plugin-api-provider.test.ts +5 -0
  156. package/src/__tests__/plugin-api-resolve-credential.test.ts +97 -0
  157. package/src/__tests__/plugin-import-boundary-guard.test.ts +9 -1
  158. package/src/__tests__/process-message-display-content.test.ts +56 -0
  159. package/src/__tests__/reaction-persistence.test.ts +5 -0
  160. package/src/__tests__/request-secret-standalone-channel-gate.test.ts +25 -9
  161. package/src/__tests__/run-conversation-turn-persistence.test.ts +138 -1
  162. package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
  163. package/src/__tests__/schedule-routes.test.ts +20 -0
  164. package/src/__tests__/scheduler-result-notification.test.ts +23 -4
  165. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  166. package/src/__tests__/scripted-turn-metadata-persistence.test.ts +73 -0
  167. package/src/__tests__/secret-ingress-http.test.ts +2 -0
  168. package/src/__tests__/secret-routes-platform-proxy.test.ts +86 -31
  169. package/src/__tests__/secret-routes-scrub.test.ts +22 -27
  170. package/src/__tests__/secret-scanner.test.ts +20 -0
  171. package/src/__tests__/secure-keys-managed-failover.test.ts +8 -0
  172. package/src/__tests__/secure-keys.test.ts +50 -4
  173. package/src/__tests__/send-endpoint-busy.test.ts +163 -1
  174. package/src/__tests__/server-history-render.test.ts +91 -1
  175. package/src/__tests__/server-tool-pairing.test.ts +107 -0
  176. package/src/__tests__/settings-routes.test.ts +50 -1
  177. package/src/__tests__/skill-script-runner-sandbox.test.ts +32 -0
  178. package/src/__tests__/skills.test.ts +5 -4
  179. package/src/__tests__/subagent-fork-notifications.test.ts +1 -2
  180. package/src/__tests__/subagent-manager-notify.test.ts +1 -2
  181. package/src/__tests__/subagent-notify-parent.test.ts +146 -39
  182. package/src/__tests__/subagent-notify-stale-rebuild.test.ts +2 -4
  183. package/src/__tests__/subagent-tool-gate-mode.test.ts +226 -0
  184. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +2 -0
  185. package/src/__tests__/terminal-tools.test.ts +8 -0
  186. package/src/__tests__/thread-backfill.test.ts +53 -0
  187. package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
  188. package/src/__tests__/tool-result-follow-up.test.ts +99 -0
  189. package/src/__tests__/tool-result-metadata-plumbing.test.ts +66 -1
  190. package/src/__tests__/tool-start-timestamp.test.ts +2 -0
  191. package/src/__tests__/twilio-routes.test.ts +1 -0
  192. package/src/__tests__/unicode.test.ts +36 -0
  193. package/src/__tests__/web-search-backend-failure.test.ts +1 -1
  194. package/src/activation/progress-store.test.ts +12 -7
  195. package/src/agent/loop.ts +136 -53
  196. package/src/agent/tool-result-follow-up.ts +70 -0
  197. package/src/api/attachment-provenance.test.ts +68 -0
  198. package/src/api/computer-use-tool.test.ts +55 -0
  199. package/src/api/computer-use-tool.ts +27 -0
  200. package/src/api/events/assistant-outbound-attachment.ts +3 -0
  201. package/src/api/events/assistant-turn-start.ts +3 -0
  202. package/src/api/events/desktop-activity-changed.ts +10 -0
  203. package/src/api/events/generation-handoff.ts +2 -0
  204. package/src/api/events/message-complete.ts +2 -0
  205. package/src/api/events/notification-conversation-created.ts +14 -16
  206. package/src/api/events/notification-intent.ts +4 -2
  207. package/src/api/events/question-request.ts +1 -0
  208. package/src/api/events/tool-result.ts +85 -0
  209. package/src/api/events/tool-use-start.ts +3 -0
  210. package/src/api/events/user-message-echo.ts +3 -0
  211. package/src/api/index.ts +42 -6
  212. package/src/api/mode-session.test.ts +131 -0
  213. package/src/api/mode-session.ts +148 -0
  214. package/src/api/remember-tool.ts +15 -0
  215. package/src/api/responses/conversation-message.ts +9 -0
  216. package/src/approvals/AGENTS.md +4 -2
  217. package/src/approvals/approval-primitive.ts +5 -2
  218. package/src/approvals/scoped-approval-grants.ts +6 -2
  219. package/src/browser/__tests__/operations.test.ts +29 -0
  220. package/src/browser/operation-meta.ts +2 -1
  221. package/src/browser/operations.ts +29 -0
  222. package/src/browser/virtual-desktop-target.ts +2 -9
  223. package/src/bundler/bundle-signer.ts +1 -3
  224. package/src/calls/__tests__/barge-in-guard.test.ts +3 -0
  225. package/src/calls/__tests__/call-controller.test.ts +94 -0
  226. package/src/calls/__tests__/call-funnel-telemetry.test.ts +204 -0
  227. package/src/calls/__tests__/voice-control-protocol.test.ts +15 -0
  228. package/src/calls/__tests__/voice-escalation-judge.test.ts +209 -0
  229. package/src/calls/__tests__/voice-leg-coordinator.test.ts +168 -0
  230. package/src/{live-voice/__tests__/live-voice-metrics.test.ts → calls/__tests__/voice-metrics.test.ts} +32 -38
  231. package/src/calls/__tests__/voice-session-bridge.test.ts +576 -122
  232. package/src/calls/barge-in-guard.ts +5 -0
  233. package/src/calls/call-controller.ts +196 -1
  234. package/src/calls/call-domain.ts +4 -0
  235. package/src/calls/call-store.ts +87 -2
  236. package/src/calls/guardian-action-sweep.ts +22 -8
  237. package/src/calls/media-stream-audio-transcode.ts +1 -3
  238. package/src/calls/typesafe-noul.ts +156 -0
  239. package/src/calls/voice-control-protocol.ts +6 -0
  240. package/src/calls/voice-escalation-judge.ts +145 -0
  241. package/src/calls/voice-escalation-target.ts +10 -0
  242. package/src/calls/voice-leg-coordinator.ts +121 -3
  243. package/src/{live-voice/live-voice-metrics.ts → calls/voice-metrics.ts} +94 -87
  244. package/src/calls/voice-session-bridge.ts +256 -112
  245. package/src/calls/voice-triage-escalate.ts +7 -0
  246. package/src/cli/__tests__/roadmap-cli.test.ts +4 -41
  247. package/src/cli/commands/__tests__/cli-test-harness.ts +21 -3
  248. package/src/cli/commands/__tests__/notifications.test.ts +35 -10
  249. package/src/cli/commands/__tests__/plugins.test.ts +20 -1
  250. package/src/cli/commands/__tests__/schedules.test.ts +14 -0
  251. package/src/cli/commands/bash.help.ts +4 -3
  252. package/src/cli/commands/browser.help.ts +9 -6
  253. package/src/cli/commands/browser.ts +0 -1
  254. package/src/cli/commands/clients.help.ts +46 -0
  255. package/src/cli/commands/clients.ts +116 -0
  256. package/src/cli/commands/credentials.help.ts +9 -4
  257. package/src/cli/commands/notifications.help.ts +16 -2
  258. package/src/cli/commands/notifications.ts +30 -8
  259. package/src/cli/commands/oauth/index.help.ts +10 -0
  260. package/src/cli/commands/oauth/providers.ts +12 -0
  261. package/src/cli/commands/oauth/request.test.ts +179 -2
  262. package/src/cli/commands/oauth/request.ts +41 -10
  263. package/src/cli/commands/plugins.ts +12 -5
  264. package/src/cli/commands/roadmap.help.ts +18 -21
  265. package/src/cli/commands/roadmap.ts +4 -21
  266. package/src/cli/commands/schedules.ts +2 -0
  267. package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
  268. package/src/cli/lib/__tests__/install-from-github.test.ts +41 -0
  269. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +5 -2
  270. package/src/cli/lib/__tests__/local-plugin-upgrade.test.ts +133 -51
  271. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +8 -2
  272. package/src/cli/lib/bundled-marketplace.json +906 -1
  273. package/src/cli/lib/bundled-plugin-packages.json +783 -1
  274. package/src/cli/lib/inspect-plugin.ts +11 -4
  275. package/src/cli/lib/plugin-marketplace.ts +8 -0
  276. package/src/cli/lib/publish-plugin.ts +1 -2
  277. package/src/cli/lib/upgrade-plugin.ts +19 -11
  278. package/src/cli/output.ts +18 -4
  279. package/src/config/__tests__/default-provider.test.ts +6 -0
  280. package/src/config/__tests__/memory-retrospective-schema.test.ts +14 -1
  281. package/src/config/bundled-skills/computer-use/SKILL.md +1 -1
  282. package/src/config/bundled-skills/computer-use/TOOLS.json +89 -1
  283. package/src/config/bundled-skills/image-studio/SKILL.md +17 -2
  284. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +7 -11
  285. package/src/config/bundled-skills/schedule/SKILL.md +6 -6
  286. package/src/config/bundled-skills/sequences/TOOLS.json +1 -5
  287. package/src/config/call-site-defaults.ts +9 -0
  288. package/src/config/feature-flag-registry.json +16 -0
  289. package/src/config/loader.ts +9 -17
  290. package/src/config/platform-identity.ts +8 -8
  291. package/src/config/profile-text-generation.test.ts +51 -0
  292. package/src/config/profile-text-generation.ts +51 -0
  293. package/src/config/schemas/__tests__/memory-v3.test.ts +12 -0
  294. package/src/config/schemas/__tests__/tools.test.ts +31 -0
  295. package/src/config/schemas/call-site-catalog.ts +14 -0
  296. package/src/config/schemas/channels.ts +0 -18
  297. package/src/config/schemas/llm.ts +9 -2
  298. package/src/config/schemas/mcp.ts +6 -1
  299. package/src/config/schemas/memory-retrospective.ts +11 -2
  300. package/src/config/schemas/memory-v3.ts +12 -0
  301. package/src/config/schemas/services.ts +15 -6
  302. package/src/config/schemas/tools.ts +10 -0
  303. package/src/config/session-groups-gate.ts +21 -0
  304. package/src/config/skills.ts +2 -6
  305. package/src/conversations/__tests__/message-consolidation.test.ts +149 -0
  306. package/src/conversations/message-consolidation.ts +102 -5
  307. package/src/credential-execution/ces-connect.test.ts +69 -0
  308. package/src/credential-execution/ces-connect.ts +115 -0
  309. package/src/credential-execution/ces-runtime.ts +55 -93
  310. package/src/credential-execution/executable-discovery.ts +34 -142
  311. package/src/credential-execution/process-manager.test.ts +20 -24
  312. package/src/credential-execution/process-manager.ts +24 -19
  313. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +10 -1
  314. package/src/daemon/__tests__/conversation-tool-setup.test.ts +43 -0
  315. package/src/daemon/__tests__/inference-profile-notification.test.ts +2 -0
  316. package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +36 -0
  317. package/src/daemon/assistant-attachments.ts +20 -12
  318. package/src/daemon/browser-mode-session.test.ts +402 -0
  319. package/src/daemon/browser-mode-session.ts +186 -0
  320. package/src/daemon/chat-credential-redaction.ts +16 -1
  321. package/src/daemon/computer-use-mode-session.test.ts +210 -0
  322. package/src/daemon/computer-use-mode-session.ts +105 -0
  323. package/src/daemon/config-watcher.ts +10 -0
  324. package/src/daemon/conversation-agent-loop-handlers.ts +132 -13
  325. package/src/daemon/conversation-agent-loop.ts +231 -25
  326. package/src/daemon/conversation-attachments.ts +93 -12
  327. package/src/daemon/conversation-evictor.ts +5 -24
  328. package/src/daemon/conversation-history.ts +10 -0
  329. package/src/daemon/conversation-interrupt-repair.ts +4 -43
  330. package/src/daemon/conversation-interrupt.ts +7 -11
  331. package/src/daemon/conversation-messaging.ts +58 -5
  332. package/src/daemon/conversation-mode-session.test.ts +1667 -0
  333. package/src/daemon/conversation-mode-session.ts +1008 -0
  334. package/src/daemon/conversation-process.ts +5 -0
  335. package/src/daemon/conversation-runtime-assembly.ts +10 -20
  336. package/src/daemon/conversation-skill-tools.ts +1 -0
  337. package/src/daemon/conversation-store.ts +4 -4
  338. package/src/daemon/conversation-surface-snapshots.ts +135 -0
  339. package/src/daemon/conversation-surfaces.ts +113 -5
  340. package/src/daemon/conversation-tool-setup.ts +79 -6
  341. package/src/daemon/conversation-turn-finalize.ts +26 -13
  342. package/src/daemon/conversation.ts +215 -58
  343. package/src/daemon/daemon-control.ts +3 -7
  344. package/src/daemon/handlers/config-model.ts +7 -5
  345. package/src/daemon/handlers/shared.ts +55 -16
  346. package/src/daemon/host-cu-proxy.ts +51 -22
  347. package/src/daemon/lifecycle.ts +30 -13
  348. package/src/daemon/mcp-reload-service.ts +1 -1
  349. package/src/daemon/message-protocol.ts +0 -1
  350. package/src/daemon/message-provenance.ts +28 -4
  351. package/src/daemon/message-types/shared.ts +1 -0
  352. package/src/daemon/mode-session-startup-recovery.ts +23 -0
  353. package/src/daemon/mode-session-tracking.ts +54 -0
  354. package/src/daemon/orphan-reaper.ts +4 -3
  355. package/src/daemon/persist-media-references.ts +20 -3
  356. package/src/daemon/process-message.ts +13 -4
  357. package/src/daemon/tool-setup-types.ts +6 -0
  358. package/src/daemon/virtual-desktop-context.ts +21 -0
  359. package/src/daemon/wake-conversation-ops.ts +50 -15
  360. package/src/desktop/__tests__/fake-desktop.ts +1 -0
  361. package/src/desktop/desktop-accessibility-script.ts +88 -0
  362. package/src/desktop/desktop-accessibility.test.ts +160 -0
  363. package/src/desktop/desktop-accessibility.ts +169 -0
  364. package/src/desktop/desktop-automation-lease.test.ts +302 -64
  365. package/src/desktop/desktop-automation-lease.ts +129 -54
  366. package/src/desktop/desktop-browser-endpoint.ts +4 -0
  367. package/src/desktop/desktop-computer-use-routing.test.ts +330 -0
  368. package/src/desktop/desktop-computer-use.test.ts +449 -0
  369. package/src/desktop/desktop-computer-use.ts +502 -0
  370. package/src/desktop/desktop-dependencies.ts +47 -293
  371. package/src/desktop/desktop-display.ts +2 -2
  372. package/src/desktop/desktop-help.ts +15 -0
  373. package/src/desktop/desktop-panel-config.test.ts +13 -3
  374. package/src/desktop/desktop-panel-config.ts +109 -15
  375. package/src/desktop/desktop-session-manager.test.ts +69 -21
  376. package/src/desktop/desktop-session-manager.ts +76 -22
  377. package/src/desktop/desktop-stream-bridge.test.ts +76 -132
  378. package/src/desktop/desktop-stream-bridge.ts +9 -11
  379. package/src/desktop/desktop-wallpaper-renderer.ts +132 -0
  380. package/src/desktop/desktop-wallpaper-worker.ts +17 -0
  381. package/src/desktop/desktop-wallpaper.test.ts +48 -7
  382. package/src/desktop/desktop-wallpaper.ts +34 -102
  383. package/src/desktop/desktop-window-theme.ts +5 -25
  384. package/src/desktop/virtual-desktop-feature.ts +53 -3
  385. package/src/desktop/virtual-desktop-platform.test.ts +5 -9
  386. package/src/documents/document-store.ts +23 -0
  387. package/src/heartbeat/__tests__/heartbeat-service.test.ts +22 -26
  388. package/src/heartbeat/heartbeat-service.ts +5 -33
  389. package/src/ipc/__tests__/browser-ipc.test.ts +215 -6
  390. package/src/ipc/assistant-server.ts +2 -0
  391. package/src/ipc/routes/__tests__/channel-reply-ipc-routes.test.ts +111 -0
  392. package/src/ipc/routes/channel-reply-ipc-routes.ts +73 -0
  393. package/src/live-voice/__tests__/continuation-judge.test.ts +151 -0
  394. package/src/live-voice/__tests__/live-activity-reporter.test.ts +154 -15
  395. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +743 -31
  396. package/src/live-voice/__tests__/live-voice-look-follow-up.test.ts +191 -10
  397. package/src/live-voice/__tests__/live-voice-session-groups-gate.test.ts +87 -0
  398. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +5 -1
  399. package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +41 -0
  400. package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +1017 -9
  401. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +224 -1
  402. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +101 -0
  403. package/src/live-voice/__tests__/live-voice-tts.test.ts +44 -0
  404. package/src/live-voice/__tests__/live-voice-vad.test.ts +939 -75
  405. package/src/live-voice/__tests__/microphone-idle-gate.test.ts +87 -0
  406. package/src/live-voice/__tests__/session-controls.test.ts +23 -0
  407. package/src/live-voice/__tests__/task-outcomes.test.ts +117 -0
  408. package/src/live-voice/__tests__/voice-input-diagnostics.test.ts +117 -0
  409. package/src/live-voice/camera-mode-session.test.ts +265 -0
  410. package/src/live-voice/camera-mode-session.ts +277 -0
  411. package/src/live-voice/continuation-judge.ts +123 -0
  412. package/src/live-voice/live-activity-reporter.ts +115 -6
  413. package/src/live-voice/live-voice-manager.ts +36 -1
  414. package/src/live-voice/live-voice-photo.ts +88 -7
  415. package/src/live-voice/live-voice-session-manager.ts +15 -0
  416. package/src/live-voice/live-voice-session.ts +1443 -747
  417. package/src/live-voice/live-voice-tts.ts +22 -4
  418. package/src/live-voice/microphone-idle-gate.ts +56 -0
  419. package/src/live-voice/protocol.ts +171 -4
  420. package/src/live-voice/session-controls.ts +11 -3
  421. package/src/live-voice/task-outcomes.ts +131 -0
  422. package/src/live-voice/voice-input-diagnostics.ts +117 -0
  423. package/src/mcp/__tests__/manager-tool-caps.test.ts +156 -0
  424. package/src/mcp/__tests__/startup.test.ts +30 -7
  425. package/src/mcp/__tests__/tool-caps.test.ts +134 -0
  426. package/src/mcp/manager.ts +171 -101
  427. package/src/mcp/startup.ts +33 -13
  428. package/src/mcp/tool-caps.ts +184 -0
  429. package/src/media/__tests__/image-models.test.ts +58 -0
  430. package/src/media/image-credentials.ts +5 -0
  431. package/src/media/image-models.ts +52 -0
  432. package/src/media/image-service.ts +8 -0
  433. package/src/media/openrouter-image-service.test.ts +133 -0
  434. package/src/media/openrouter-image-service.ts +153 -0
  435. package/src/media/types.ts +1 -1
  436. package/src/messaging/provider-message-metadata.ts +3 -3
  437. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +65 -11
  438. package/src/messaging/providers/discord/send.ts +4 -17
  439. package/src/messaging/providers/discord/transport.ts +2 -2
  440. package/src/messaging/providers/outlook/client.ts +16 -22
  441. package/src/messaging/providers/telegram-bot/send.test.ts +236 -1
  442. package/src/messaging/providers/telegram-bot/send.ts +10 -7
  443. package/src/messaging/providers/telegram-bot/transport.ts +3 -10
  444. package/src/messaging/providers/whatsapp/send.test.ts +169 -4
  445. package/src/monitoring/__tests__/control.test.ts +17 -5
  446. package/src/monitoring/control.ts +15 -5
  447. package/src/notifications/AGENTS.md +1 -1
  448. package/src/notifications/README.md +83 -99
  449. package/src/notifications/__tests__/broadcaster.test.ts +1 -1
  450. package/src/notifications/__tests__/channel-allowlist.test.ts +39 -0
  451. package/src/notifications/__tests__/copy-composer.test.ts +71 -1
  452. package/src/notifications/__tests__/decision-engine.test.ts +79 -2
  453. package/src/notifications/__tests__/deterministic-checks.test.ts +10 -10
  454. package/src/notifications/__tests__/home-feed-side-effect.test.ts +93 -4
  455. package/src/notifications/__tests__/notification-utils.test.ts +18 -0
  456. package/src/notifications/adapters/macos.ts +37 -46
  457. package/src/notifications/broadcaster.ts +5 -6
  458. package/src/notifications/channel-allowlist.ts +44 -0
  459. package/src/notifications/copy-composer.ts +11 -26
  460. package/src/notifications/decision-engine.ts +24 -14
  461. package/src/notifications/deterministic-checks.ts +1 -1
  462. package/src/notifications/emit-signal.ts +123 -37
  463. package/src/notifications/home-feed-side-effect.ts +9 -7
  464. package/src/notifications/notification-utils.ts +19 -0
  465. package/src/notifications/schedule-result-producer.ts +4 -6
  466. package/src/notifications/signal.ts +4 -19
  467. package/src/notifications/types.ts +15 -0
  468. package/src/oauth/AGENTS.md +2 -0
  469. package/src/oauth/__tests__/identity-verifier.test.ts +36 -1
  470. package/src/oauth/connection-resolver.ts +1 -2
  471. package/src/oauth/identity-verifier.ts +24 -0
  472. package/src/oauth/oauth-store.ts +12 -4
  473. package/src/oauth/provider-serializer.ts +8 -0
  474. package/src/oauth/seed-providers.ts +42 -0
  475. package/src/onboarding/onboarding-events-store.ts +99 -12
  476. package/src/permissions/confirmation-guardian-request.test.ts +16 -0
  477. package/src/permissions/confirmation-guardian-request.ts +2 -3
  478. package/src/permissions/question-prompter.test.ts +31 -0
  479. package/src/permissions/question-prompter.ts +2 -0
  480. package/src/persistence/__tests__/client-connection-events-store.test.ts +322 -0
  481. package/src/persistence/attachments-store.ts +84 -44
  482. package/src/persistence/client-connection-events-store.ts +377 -0
  483. package/src/persistence/conversation-crud.ts +166 -26
  484. package/src/persistence/conversation-mode-sessions.test.ts +424 -0
  485. package/src/persistence/conversation-mode-sessions.ts +460 -0
  486. package/src/persistence/conversation-plugin-facade.ts +30 -0
  487. package/src/persistence/conversation-queries.ts +6 -19
  488. package/src/persistence/conversation-tool-surface.ts +135 -0
  489. package/src/persistence/conversation-types.test.ts +32 -0
  490. package/src/persistence/conversation-types.ts +26 -4
  491. package/src/persistence/llm-usage-store.ts +3 -9
  492. package/src/persistence/message-metadata.ts +25 -0
  493. package/src/persistence/migrations/378-create-conversation-tool-surfaces.test.ts +78 -0
  494. package/src/persistence/migrations/378-create-conversation-tool-surfaces.ts +29 -0
  495. package/src/persistence/migrations/379-oauth-providers-response-ok-field.test.ts +92 -0
  496. package/src/persistence/migrations/379-oauth-providers-response-ok-field.ts +32 -0
  497. package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.test.ts +90 -0
  498. package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.ts +34 -0
  499. package/src/persistence/migrations/381-create-conversation-mode-sessions.ts +41 -0
  500. package/src/persistence/migrations/382-create-client-connection-events.ts +40 -0
  501. package/src/persistence/migrations/__tests__/382-create-client-connection-events.test.ts +56 -0
  502. package/src/persistence/schema/conversation-tool-surfaces.ts +32 -0
  503. package/src/persistence/schema/conversations.ts +67 -0
  504. package/src/persistence/schema/index.ts +1 -0
  505. package/src/persistence/schema/infrastructure.ts +29 -0
  506. package/src/persistence/schema/oauth.ts +1 -0
  507. package/src/persistence/steps.ts +41 -3
  508. package/src/plugin-api/__tests__/plugin-name-env.test.ts +249 -0
  509. package/src/plugin-api/conversation-turn.ts +31 -7
  510. package/src/plugin-api/effective-context-window.ts +33 -0
  511. package/src/plugin-api/index.ts +35 -6
  512. package/src/plugin-api/plugin-channel-turn-trust.test.ts +133 -0
  513. package/src/plugin-api/plugin-channel-turn-trust.ts +71 -0
  514. package/src/plugin-api/plugin-name-env.ts +125 -0
  515. package/src/plugin-api/resolve-credential.ts +79 -20
  516. package/src/plugin-api/vision-support.test.ts +22 -0
  517. package/src/plugin-api/vision-support.ts +17 -5
  518. package/src/plugins/__tests__/active-plugin-env.test.ts +136 -0
  519. package/src/plugins/active-plugin-env.ts +51 -0
  520. package/src/plugins/defaults/index.ts +24 -0
  521. package/src/plugins/defaults/memory/AGENTS.md +39 -5
  522. package/src/plugins/defaults/memory/__tests__/archive-removal-framing.test.ts +64 -0
  523. package/src/plugins/defaults/memory/__tests__/buffer-file.test.ts +365 -0
  524. package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +43 -0
  525. package/src/plugins/defaults/memory/__tests__/conversation-memory-purge.test.ts +1 -0
  526. package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +2 -0
  527. package/src/plugins/defaults/memory/__tests__/fixtures/buffer-appender.ts +17 -0
  528. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +74 -0
  529. package/src/plugins/defaults/memory/__tests__/memory-run-evidence.test.ts +161 -0
  530. package/src/plugins/defaults/memory/__tests__/relocated-memory-test-rows.ts +10 -0
  531. package/src/plugins/defaults/memory/__tests__/worker-control.test.ts +19 -6
  532. package/src/plugins/defaults/memory/buffer-file.ts +354 -0
  533. package/src/plugins/defaults/memory/buffer-format.ts +40 -0
  534. package/src/plugins/defaults/memory/context-search/agent-protocol.ts +9 -12
  535. package/src/plugins/defaults/memory/context-search/agent-runner.ts +77 -22
  536. package/src/plugins/defaults/memory/context-search/format.ts +53 -8
  537. package/src/plugins/defaults/memory/context-search/limits.ts +10 -12
  538. package/src/plugins/defaults/memory/context-search/recall-input.ts +38 -0
  539. package/src/plugins/defaults/memory/context-search/search.ts +8 -14
  540. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +1 -0
  541. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -1
  542. package/src/plugins/defaults/memory/context-search/sources/workspace.ts +2 -1
  543. package/src/plugins/defaults/memory/context-search/types.ts +1 -11
  544. package/src/plugins/defaults/memory/conversation-memory-purge.ts +4 -0
  545. package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +11 -4
  546. package/src/plugins/defaults/memory/graph/capability-seed.ts +1 -2
  547. package/src/plugins/defaults/memory/graph/tool-handlers.ts +13 -63
  548. package/src/plugins/defaults/memory/graph/tools.ts +35 -64
  549. package/src/plugins/defaults/memory/host-utils.ts +0 -10
  550. package/src/plugins/defaults/memory/injectors.ts +4 -3
  551. package/src/plugins/defaults/memory/memory-retrospective-job.ts +72 -183
  552. package/src/plugins/defaults/memory/memory-run-evidence.ts +213 -0
  553. package/src/plugins/defaults/memory/src/memory-eval-routes.ts +2 -3
  554. package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +6 -1
  555. package/src/plugins/defaults/memory/src/memory-item-routes.ts +2 -1
  556. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +407 -99
  557. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +10 -0
  558. package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +107 -7
  559. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +307 -86
  560. package/src/plugins/defaults/memory/substrate/consolidation-tool-surface.ts +34 -0
  561. package/src/plugins/defaults/memory/substrate/page-index.ts +2 -1
  562. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +91 -51
  563. package/src/plugins/defaults/memory/substrate/sweep-job.ts +1 -1
  564. package/src/plugins/defaults/memory/tools.test.ts +124 -9
  565. package/src/plugins/defaults/memory/tools.ts +38 -11
  566. package/src/plugins/defaults/memory/v1/graph/consolidation.ts +2 -2
  567. package/src/plugins/defaults/memory/v1/graph/extraction.ts +2 -1
  568. package/src/plugins/defaults/memory/v1/graph/retriever.ts +1 -1
  569. package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +5 -0
  570. package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +5 -2
  571. package/src/plugins/defaults/memory/v2/reranker.ts +2 -1
  572. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +81 -1
  573. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +87 -0
  574. package/src/plugins/defaults/memory/v3/__tests__/plugin-schema.test.ts +12 -0
  575. package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +332 -15
  576. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +626 -27
  577. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +148 -28
  578. package/src/plugins/defaults/memory/v3/card.ts +2 -1
  579. package/src/plugins/defaults/memory/v3/injector.ts +212 -178
  580. package/src/plugins/defaults/memory/v3/orchestrate.ts +159 -32
  581. package/src/plugins/defaults/memory/v3/plugin-schema.ts +54 -4
  582. package/src/plugins/defaults/memory/v3/pool-log-store.ts +275 -37
  583. package/src/plugins/defaults/memory/v3/pool-select.test.ts +47 -5
  584. package/src/plugins/defaults/memory/v3/pool-select.ts +710 -59
  585. package/src/plugins/defaults/memory/v3/sections.ts +2 -1
  586. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +41 -14
  587. package/src/plugins/defaults/memory/worker-control.ts +15 -5
  588. package/src/plugins/defaults/task-progress/__tests__/registration.test.ts +70 -0
  589. package/src/plugins/defaults/task-progress/__tests__/task-progress-context.test.ts +380 -0
  590. package/src/plugins/defaults/task-progress/hooks/post-compact.ts +19 -0
  591. package/src/plugins/defaults/task-progress/hooks/user-prompt-submit.ts +24 -0
  592. package/src/plugins/defaults/task-progress/package.json +14 -0
  593. package/src/plugins/defaults/task-progress/src/apply-task-progress-context.ts +93 -0
  594. package/src/plugins/defaults/task-progress/src/format-task-progress-context.ts +67 -0
  595. package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +4 -1
  596. package/src/plugins/defaults/tool-result-truncate/terminal.ts +1 -46
  597. package/src/prompts/__tests__/parallel-tasks-section.test.ts +25 -0
  598. package/src/prompts/delegation-gate.ts +57 -0
  599. package/src/prompts/system-prompt.ts +14 -32
  600. package/src/providers/__tests__/context-overflow-error.test.ts +10 -0
  601. package/src/providers/__tests__/search-provider-catalog.test.ts +18 -0
  602. package/src/providers/anthropic/client.ts +10 -1
  603. package/src/providers/anthropic-gateway-shared.ts +6 -0
  604. package/src/providers/fetch-provider-catalog.ts +11 -0
  605. package/src/providers/gemini/client.ts +25 -8
  606. package/src/providers/inference/adapter-factory.ts +6 -0
  607. package/src/providers/jev/client.test.ts +270 -0
  608. package/src/providers/jev/client.ts +534 -0
  609. package/src/providers/model-catalog.ts +59 -3
  610. package/src/providers/openai/__tests__/chat-completions-extra-body.test.ts +94 -1
  611. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +106 -1
  612. package/src/providers/openai/__tests__/chat-template-flatten.test.ts +24 -0
  613. package/src/providers/openai/__tests__/google-thought-signature.test.ts +1 -2
  614. package/src/providers/openai/chat-completions-provider.ts +100 -29
  615. package/src/providers/openai/google-thought-signature.ts +0 -6
  616. package/src/providers/openai/responses-provider.ts +23 -1
  617. package/src/providers/ratelimit.ts +1 -3
  618. package/src/providers/search-provider-catalog.ts +24 -0
  619. package/src/providers/server-tool-pairing.ts +16 -7
  620. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +24 -0
  621. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +7 -1
  622. package/src/providers/speech-to-text/__tests__/vellum-managed-realtime.test.ts +50 -1
  623. package/src/providers/speech-to-text/deepgram-flux-frames.ts +11 -0
  624. package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +13 -0
  625. package/src/providers/types.ts +5 -0
  626. package/src/routes/control.ts +7 -5
  627. package/src/runtime/AGENTS.md +6 -4
  628. package/src/runtime/__tests__/agent-wake.test.ts +94 -1
  629. package/src/runtime/actor-trust-resolver.ts +3 -3
  630. package/src/runtime/agent-wake.ts +32 -5
  631. package/src/runtime/approval-message-composer.ts +3 -69
  632. package/src/runtime/assistant-event-hub.ts +73 -75
  633. package/src/runtime/assistant-event-publish-options.ts +7 -0
  634. package/src/runtime/assistant-event-targeting.ts +79 -0
  635. package/src/runtime/assistant-stream-state.ts +13 -100
  636. package/src/runtime/background-job-runner.ts +5 -5
  637. package/src/runtime/channel-retry-sweep.ts +1 -0
  638. package/src/runtime/guardian-action-message-composer.ts +8 -161
  639. package/src/runtime/guardian-action-service.ts +2 -17
  640. package/src/runtime/guardian-reply-router.ts +29 -40
  641. package/src/runtime/http-server.ts +2 -2
  642. package/src/runtime/http-types.ts +6 -0
  643. package/src/runtime/message-composer-types.ts +3 -61
  644. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +67 -1
  645. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +89 -0
  646. package/src/runtime/migrations/vbundle-builder.ts +24 -1
  647. package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -4
  648. package/src/runtime/migrations/vbundle-import-policy.ts +43 -11
  649. package/src/runtime/migrations/vbundle-importer.ts +4 -1
  650. package/src/runtime/migrations/vbundle-streaming-importer.ts +4 -1
  651. package/src/runtime/migrations/vbundle-validator.ts +1 -0
  652. package/src/runtime/pending-interactions-mode-session.test.ts +62 -0
  653. package/src/runtime/pending-interactions.ts +29 -0
  654. package/src/runtime/routes/__tests__/client-history-routes.test.ts +104 -0
  655. package/src/runtime/routes/__tests__/image-generation-routes.test.ts +97 -0
  656. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +24 -2
  657. package/src/runtime/routes/__tests__/roadmap-routes.test.ts +29 -6
  658. package/src/runtime/routes/browser-context.ts +31 -11
  659. package/src/runtime/routes/browser-routes.ts +43 -4
  660. package/src/runtime/routes/btw-routes.ts +9 -4
  661. package/src/runtime/routes/channel-route-shared.ts +1 -9
  662. package/src/runtime/routes/client-routes.ts +108 -0
  663. package/src/runtime/routes/conversation-management-routes.ts +4 -1
  664. package/src/runtime/routes/conversation-routes.ts +125 -14
  665. package/src/runtime/routes/credential-prompt-routes.ts +4 -3
  666. package/src/runtime/routes/credential-routes.ts +1 -2
  667. package/src/runtime/routes/desktop-setup-routes.test.ts +9 -18
  668. package/src/runtime/routes/desktop-setup-routes.ts +8 -7
  669. package/src/runtime/routes/documents-routes.ts +51 -0
  670. package/src/runtime/routes/email-routes.ts +3 -7
  671. package/src/runtime/routes/events-routes.ts +75 -54
  672. package/src/runtime/routes/guardian-approval-interception.ts +24 -0
  673. package/src/runtime/routes/identity-routes.ts +1 -5
  674. package/src/runtime/routes/image-generation-routes.ts +8 -14
  675. package/src/runtime/routes/inbound-message-handler.ts +37 -41
  676. package/src/runtime/routes/inbound-stages/backfill-sender-provenance.test.ts +168 -0
  677. package/src/runtime/routes/inbound-stages/backfill-sender-provenance.ts +96 -0
  678. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +39 -10
  679. package/src/runtime/routes/inbound-stages/background-dispatch.ts +9 -9
  680. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +2 -0
  681. package/src/runtime/routes/inference-profile-session-handler.ts +11 -1
  682. package/src/runtime/routes/inference-profiles-routes.ts +9 -0
  683. package/src/runtime/routes/llm-context-normalization.ts +1 -7
  684. package/src/runtime/routes/migration-routes.ts +73 -2
  685. package/src/runtime/routes/notification-routes.ts +10 -0
  686. package/src/runtime/routes/oauth-commands-routes.ts +57 -54
  687. package/src/runtime/routes/oauth-providers.ts +11 -0
  688. package/src/runtime/routes/oauth-request-hints.test.ts +246 -0
  689. package/src/runtime/routes/oauth-request-hints.ts +149 -0
  690. package/src/runtime/routes/plugins-routes.ts +6 -0
  691. package/src/runtime/routes/roadmap-routes.ts +47 -8
  692. package/src/runtime/routes/schedule-routes.ts +2 -0
  693. package/src/runtime/routes/secret-routes.ts +99 -119
  694. package/src/runtime/routes/settings-routes.ts +10 -4
  695. package/src/runtime/routes/watcher-routes.ts +1 -3
  696. package/src/runtime/trust-class.test.ts +7 -6
  697. package/src/runtime/trust-class.ts +9 -17
  698. package/src/schedule/__tests__/worker-control.test.ts +36 -5
  699. package/src/schedule/__tests__/worker-mcp-bootstrap.test.ts +107 -0
  700. package/src/schedule/__tests__/worker-mcp-readiness.test.ts +173 -0
  701. package/src/schedule/__tests__/worker-mcp-tools.test.ts +13 -47
  702. package/src/schedule/run-script.ts +2 -2
  703. package/src/schedule/scheduler.ts +47 -11
  704. package/src/schedule/tool-surface-readiness.ts +65 -0
  705. package/src/schedule/worker-control.ts +15 -5
  706. package/src/schedule/worker-mcp.ts +85 -0
  707. package/src/schedule/worker.ts +9 -31
  708. package/src/security/secure-keys.ts +74 -112
  709. package/src/skills/clawhub.ts +3 -8
  710. package/src/skills/managed-store.ts +1 -5
  711. package/src/stt/types.ts +4 -0
  712. package/src/subagent/notify.ts +54 -34
  713. package/src/subagent/parent-notification.ts +6 -0
  714. package/src/telemetry/__tests__/phone-call-funnel.test.ts +72 -0
  715. package/src/telemetry/phone-call-funnel.ts +144 -0
  716. package/src/tools/__tests__/tool-schema-root-combinator-guard.test.ts +81 -0
  717. package/src/tools/ask-question/ask-question-tool.test.ts +167 -5
  718. package/src/tools/ask-question/ask-question-tool.ts +120 -22
  719. package/src/tools/browser/browser-execution.ts +29 -60
  720. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +561 -39
  721. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +435 -39
  722. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +1 -8
  723. package/src/tools/client-os.ts +15 -0
  724. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
  725. package/src/tools/computer-use/target.ts +42 -0
  726. package/src/tools/document/document-tool.ts +13 -18
  727. package/src/tools/execution-target.ts +14 -16
  728. package/src/tools/host-terminal/host-shell.ts +16 -7
  729. package/src/tools/network/__tests__/web-fetch-tinyfish.test.ts +250 -0
  730. package/src/tools/network/__tests__/web-search.test.ts +203 -0
  731. package/src/tools/network/web-fetch.ts +274 -7
  732. package/src/tools/network/web-search.ts +468 -6
  733. package/src/tools/permission-checker.ts +3 -3
  734. package/src/tools/policy-context.ts +3 -1
  735. package/src/tools/shared/filesystem/file-ops-service.ts +1 -31
  736. package/src/tools/shared/shell-output.test.ts +10 -0
  737. package/src/tools/shared/shell-output.ts +14 -2
  738. package/src/tools/skills/load.ts +2 -1
  739. package/src/tools/skills/sandbox-runner.ts +24 -4
  740. package/src/tools/skills/scaffold-managed.ts +2 -1
  741. package/src/tools/skills/skill-script-runner.ts +7 -0
  742. package/src/tools/skills/skill-tool-factory.ts +15 -1
  743. package/src/tools/terminal/__tests__/safe-env.test.ts +44 -4
  744. package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -14
  745. package/src/tools/terminal/safe-env.ts +39 -24
  746. package/src/tools/terminal/sanitized-bash.ts +15 -2
  747. package/src/tools/terminal/shell-launch.test.ts +162 -0
  748. package/src/tools/terminal/shell.test.ts +29 -0
  749. package/src/tools/terminal/shell.ts +15 -7
  750. package/src/tools/tool-approval-handler.ts +5 -1
  751. package/src/tools/tool-types.ts +3 -3
  752. package/src/tools/types.ts +8 -2
  753. package/src/util/__tests__/worker-process-command.test.ts +5 -4
  754. package/src/util/abort-reasons.ts +18 -26
  755. package/src/util/browser-human-verification.ts +14 -0
  756. package/src/util/canonicalize-identity.test.ts +21 -0
  757. package/src/util/canonicalize-identity.ts +16 -0
  758. package/src/util/errors.ts +13 -3
  759. package/src/util/host-process.test.ts +17 -1
  760. package/src/util/host-process.ts +24 -0
  761. package/src/util/provider-error-patterns.ts +3 -0
  762. package/src/util/unicode.ts +29 -0
  763. package/src/util/worker-process.ts +77 -35
  764. package/src/workspace/migrations/157-add-desktop-files-launcher.ts +94 -0
  765. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +4 -10
  766. package/src/workspace/migrations/__tests__/157-add-desktop-files-launcher.test.ts +113 -0
  767. package/src/workspace/migrations/registry.ts +2 -0
  768. package/src/__tests__/computer-use-window-schema.test.ts +0 -24
  769. package/src/api/events/heartbeat-alert.ts +0 -20
  770. package/src/daemon/message-types/web-activity.ts +0 -65
  771. package/src/desktop/desktop-dependencies.test.ts +0 -131
  772. package/src/tools/computer-use/definitions.ts +0 -607
@@ -0,0 +1,149 @@
1
+ /**
2
+ * The hint the request doors attach to a provider response, composed from
3
+ * the response and the connection facts alone. The route gathers the facts;
4
+ * nothing here reads a store, a config, or a connection, so a hint's wording
5
+ * is assertable without booting the route.
6
+ *
7
+ * The status hints are an ordered list and the first rule that applies wins.
8
+ * The order is precedence, not coincidence: a provider's own reported failure
9
+ * outranks every status, and an HTML 403 must be judged before the generic
10
+ * 401/403 rule or it is never reached. The missing-scope hint is not a rule
11
+ * in the list; it is prepended to whichever hint applied, or stands alone.
12
+ */
13
+
14
+ export interface RequestHintFacts {
15
+ /** The provider key the request was made under. */
16
+ provider: string;
17
+ status: number;
18
+ headers: Record<string, string>;
19
+ /**
20
+ * The provider's own one-line account of a refusal inside a 2xx, from its
21
+ * declared ok field; absent when the status is the whole verdict.
22
+ */
23
+ reportedFailure?: string;
24
+ /**
25
+ * The channel whose bot credential served the request. Absent when the
26
+ * request acted as a person through their OAuth integration.
27
+ */
28
+ botChannel?: string;
29
+ /** The provider runs in platform-managed mode. */
30
+ managed: boolean;
31
+ /**
32
+ * The base URL the request resolved against: an absolute URL's own origin,
33
+ * otherwise the provider's configured base. Absent when neither is set.
34
+ */
35
+ resolvedBaseUrl?: string;
36
+ /** Required scopes the resolved connection's stored grant lacks. */
37
+ missingScopes: readonly string[];
38
+ }
39
+
40
+ interface RequestHintRule {
41
+ name: string;
42
+ applies(facts: RequestHintFacts): boolean;
43
+ render(facts: RequestHintFacts): string;
44
+ }
45
+
46
+ /** The status hints in precedence order; the first rule that applies wins. */
47
+ export const REQUEST_HINT_RULES: readonly RequestHintRule[] = [
48
+ {
49
+ // The body carries the provider's own error code, so the hint says only
50
+ // why a 2xx is being reported as a failure.
51
+ name: "provider reported failure",
52
+ applies: (facts) => facts.reportedFailure !== undefined,
53
+ render: (facts) =>
54
+ `${facts.reportedFailure} in the response body. The body names the error.`,
55
+ },
56
+ {
57
+ // An API refuses with JSON. A 403 carrying an HTML page is a resource
58
+ // host (a file host, a sign-in page) refusing this identity: the same
59
+ // token is what the API accepts, and the resource is simply not visible
60
+ // to it. Blaming the credential sends the caller off to reconnect one
61
+ // that works.
62
+ name: "resource not visible",
63
+ applies: (facts) => facts.status === 403 && isHtmlResponse(facts.headers),
64
+ render: (facts) => {
65
+ const identity = facts.botChannel
66
+ ? `${facts.botChannel} bot`
67
+ : "connected account";
68
+ const requestHost = hostnameOf(facts.resolvedBaseUrl);
69
+ return (
70
+ `Request returned HTTP 403 with an HTML page${requestHost ? ` from ${requestHost}` : ""}, not an API error. ` +
71
+ `That usually means the ${identity} cannot see this resource: it is not shared with it, or the scope it needs is missing. ` +
72
+ `Check the resource's access before treating the credential as revoked; ` +
73
+ (facts.botChannel
74
+ ? `'assistant channels get ${facts.botChannel}' reports the credential itself.`
75
+ : `'assistant oauth status ${facts.provider}' reports the credential itself.`)
76
+ );
77
+ },
78
+ },
79
+ {
80
+ // The recovery steps follow the credential's kind, not the door the
81
+ // request came through: a channel bot's token was stored by the channel's
82
+ // setup, so the OAuth status and connect commands cannot repair it.
83
+ name: "credential rejected",
84
+ applies: (facts) => facts.status === 401 || facts.status === 403,
85
+ render: (facts) =>
86
+ facts.botChannel
87
+ ? `Request returned HTTP ${facts.status}. The ${facts.botChannel} bot credential was rejected; it may have been revoked or reinstalled with fewer scopes.\n\n` +
88
+ `Run 'assistant channels get ${facts.botChannel}' to re-probe the channel and see what it reports.\n` +
89
+ `To reconnect, run the channel's setup skill again.`
90
+ : facts.managed
91
+ ? `Request returned HTTP ${facts.status}. The OAuth token may be expired or revoked.\n\n` +
92
+ `Run 'assistant oauth status ${facts.provider}' to check connection health.\n` +
93
+ `To reconnect, run 'assistant oauth connect --help'.`
94
+ : `Request returned HTTP ${facts.status}. The OAuth token may be expired or revoked.\n\n` +
95
+ `Run 'assistant oauth status ${facts.provider}' to check connection status.\n` +
96
+ `To reconnect, run 'assistant oauth connect --help'.`,
97
+ },
98
+ {
99
+ // An HTML 404 (rather than a JSON API error) is the signature of a request
100
+ // reaching a valid host but a path that host does not serve, such as a
101
+ // relative path resolved against a base URL that points at the wrong
102
+ // product. Surface the resolved base so the caller can tell where the path
103
+ // landed, and steer them to an absolute URL for non-default services.
104
+ name: "path not served",
105
+ applies: (facts) => facts.status === 404 && isHtmlResponse(facts.headers),
106
+ render: (facts) =>
107
+ `Request returned HTTP ${facts.status} with an HTML body, which usually means ` +
108
+ `the path does not exist on the base URL it resolved against.\n\n` +
109
+ `This request used base URL "${facts.resolvedBaseUrl ?? "(none configured)"}" (relative paths are joined onto it). ` +
110
+ `If you meant a different service on this provider, pass an absolute URL ` +
111
+ `(e.g. https://host/full/path) so the host and full path are set explicitly.`,
112
+ },
113
+ ];
114
+
115
+ /**
116
+ * The hint for one provider response, or undefined when nothing applies.
117
+ * A missing-scope hint is prepended to the status hint, or stands alone: a
118
+ * connection made before a scope was required keeps working for every call
119
+ * that does not need it, so the gap is named on every request.
120
+ */
121
+ export function composeRequestHint(
122
+ facts: RequestHintFacts,
123
+ ): string | undefined {
124
+ const hint = REQUEST_HINT_RULES.find((rule) => rule.applies(facts))?.render(
125
+ facts,
126
+ );
127
+ if (facts.missingScopes.length === 0) {
128
+ return hint;
129
+ }
130
+ const scopeHint =
131
+ `The ${facts.provider} connection is missing required scopes: ${facts.missingScopes.join(", ")}. ` +
132
+ `It was connected before they were required, so calls that need them fail. ` +
133
+ `Reconnect it from Integrations, or run 'assistant oauth connect ${facts.provider}', to grant them.`;
134
+ return hint ? `${scopeHint}\n\n${hint}` : scopeHint;
135
+ }
136
+
137
+ /** True when the response's Content-Type header indicates an HTML body. */
138
+ function isHtmlResponse(headers: Record<string, string>): boolean {
139
+ for (const [key, value] of Object.entries(headers)) {
140
+ if (key.toLowerCase() === "content-type") {
141
+ return value.toLowerCase().includes("text/html");
142
+ }
143
+ }
144
+ return false;
145
+ }
146
+
147
+ function hostnameOf(url: string | undefined): string | undefined {
148
+ return url && URL.canParse(url) ? new URL(url).hostname : undefined;
149
+ }
@@ -226,6 +226,12 @@ const mcpPluginIntegrationSchema = z.object({
226
226
  }),
227
227
  logo: z.string(),
228
228
  oauthProvider: z.string().optional(),
229
+ category: z
230
+ .string()
231
+ .optional()
232
+ .describe(
233
+ "Where the integrations catalog files the entry: a slug from the shared integration-category vocabulary, passed through as the catalog declares it.",
234
+ ),
229
235
  });
230
236
 
231
237
  const pluginSearchMatchSchema = z.object({
@@ -379,16 +379,55 @@ const createRequestSchema = z.object({
379
379
  tags: z.array(z.string()).optional().describe("Tag slugs"),
380
380
  });
381
381
 
382
+ /** Item fields the roadmap service reserves for staff on an update. */
383
+ const STAFF_ONLY_UPDATE_FIELDS = new Set(["status", "tags"]);
384
+
385
+ function listFields(fields: string[]): string {
386
+ return `${fields.join(", ")} ${fields.length === 1 ? "is" : "are"}`;
387
+ }
388
+
389
+ /**
390
+ * Why an update carrying fields other than title and description is refused.
391
+ * A staff-only field and an unknown one need different remedies, so each is
392
+ * named for what it is.
393
+ */
394
+ function unsupportedUpdateFieldsMessage(keys: string[]): string {
395
+ const staffOnly = keys.filter((k) => STAFF_ONLY_UPDATE_FIELDS.has(k));
396
+ const unknown = keys.filter((k) => !STAFF_ONLY_UPDATE_FIELDS.has(k));
397
+ const reasons = [
398
+ ...(staffOnly.length > 0
399
+ ? [`${listFields(staffOnly)} set by Vellum staff`]
400
+ : []),
401
+ ...(unknown.length > 0
402
+ ? [`${listFields(unknown)} not a roadmap update field`]
403
+ : []),
404
+ ];
405
+ return `An assistant can change only an item's title and description; ${reasons.join("; ")}.`;
406
+ }
407
+
408
+ /**
409
+ * Only the fields the roadmap service lets this assistant change. An
410
+ * assistant is always the author tier there, never staff, and an author may
411
+ * edit only an open item's title and description; status and tags are staff
412
+ * triage and answer 403. Strict, so a caller that sends anything else learns
413
+ * why here instead of from the upstream refusal.
414
+ */
382
415
  const updateRequestSchema = z
383
- .object({
384
- title: z.string().optional(),
385
- description: z.string().optional(),
386
- status: z.string().optional(),
387
- tags: z.array(z.string()).optional().describe("Tag slugs"),
388
- })
416
+ .strictObject(
417
+ {
418
+ title: z.string().optional(),
419
+ description: z.string().optional(),
420
+ },
421
+ {
422
+ error: (issue) =>
423
+ issue.code === "unrecognized_keys"
424
+ ? unsupportedUpdateFieldsMessage(issue.keys)
425
+ : undefined,
426
+ },
427
+ )
389
428
  .refine(
390
429
  (patch) => Object.values(patch).some((v) => v !== undefined),
391
- "At least one of title, description, status or tags is required.",
430
+ "At least one of title or description is required.",
392
431
  );
393
432
 
394
433
  type RoadmapItem = z.infer<typeof itemSchema>;
@@ -684,7 +723,7 @@ export const ROUTES: RouteDefinition[] = [
684
723
  },
685
724
  summary: "Update a roadmap item",
686
725
  description:
687
- "Updates a roadmap item. At least one field is required; the roadmap service decides which items this assistant may edit.",
726
+ "Updates the title or description of a roadmap item this assistant filed, while the item is still open. Status and tags are set by Vellum staff.",
688
727
  tags: ["roadmap"],
689
728
  pathParams: SLUG_PARAM,
690
729
  requestBody: updateRequestSchema,
@@ -213,6 +213,7 @@ const scheduleSchema = z.object({
213
213
  mode: z.enum(["notify", "execute", "script", "wake", "workflow"]),
214
214
  status: z.enum(["active", "firing", "fired", "cancelled"]),
215
215
  routingIntent: z.enum(["single_channel", "multi_channel", "all_channels"]),
216
+ quiet: z.boolean(),
216
217
  reuseConversation: z.boolean(),
217
218
  wakeConversationId: z.string().nullable(),
218
219
  workflowName: z.string().nullable(),
@@ -381,6 +382,7 @@ function serializeSchedule(
381
382
  mode: j.mode,
382
383
  status: j.status,
383
384
  routingIntent: j.routingIntent,
385
+ quiet: j.quiet,
384
386
  reuseConversation: j.reuseConversation,
385
387
  wakeConversationId: j.wakeConversationId,
386
388
  workflowName: j.workflowName,
@@ -16,10 +16,7 @@ import {
16
16
  } from "../../acp/acp-credentials.js";
17
17
  import {
18
18
  getPlatformAssistantId,
19
- setPlatformAssistantId,
20
19
  setPlatformBaseUrl,
21
- setPlatformOrganizationId,
22
- setPlatformUserId,
23
20
  } from "../../config/env.js";
24
21
  import { getConfig } from "../../config/loader.js";
25
22
  import { maybeDefaultSpeechToManaged } from "../../config/managed-speech-defaults.js";
@@ -41,6 +38,7 @@ import {
41
38
  refreshProvidersAfterSecretChange,
42
39
  refreshProvidersForRotatedCredential,
43
40
  } from "../../providers/inference/credential-rotation.js";
41
+ import { validateJevApiKey } from "../../providers/jev/client.js";
44
42
  import { validateMinimaxApiKey } from "../../providers/minimax/client.js";
45
43
  import { validateOpenAIApiKey } from "../../providers/openai/client.js";
46
44
  import { validatePoolsideApiKey } from "../../providers/poolside/client.js";
@@ -79,6 +77,48 @@ const log = getLogger("runtime-http");
79
77
  const CES_READY_POLL_INTERVAL_MS = 500;
80
78
  const CES_READY_POLL_TIMEOUT_MS = 30_000;
81
79
 
80
+ const WRITABLE_VELLUM_CREDENTIAL_FIELDS = [
81
+ "assistant_api_key",
82
+ "webhook_secret",
83
+ "platform_base_url",
84
+ ] as const;
85
+
86
+ function isWritableVellumCredentialField(field: string): boolean {
87
+ return (WRITABLE_VELLUM_CREDENTIAL_FIELDS as readonly string[]).includes(
88
+ field,
89
+ );
90
+ }
91
+
92
+ async function persistCredential(
93
+ service: string,
94
+ field: string,
95
+ value: string,
96
+ ): Promise<void> {
97
+ const key = credentialKey(service, field);
98
+ const stored = await setSecureKeyAsync(key, value);
99
+ if (!stored) {
100
+ throw new InternalError(
101
+ `Failed to store credential in secure storage (backend: ${getActiveBackendName()})`,
102
+ );
103
+ }
104
+ if (!isNonSecretPlatformField(service, field)) {
105
+ try {
106
+ const scrubbed = await scrubStoredCredentialFromTranscripts(value);
107
+ log.info(
108
+ { service, field, ...scrubbed },
109
+ "Credential stored; scrubbed value from recent transcripts",
110
+ );
111
+ } catch (err) {
112
+ log.warn(
113
+ { err, service, field },
114
+ "Credential stored, but transcript scrub failed",
115
+ );
116
+ }
117
+ }
118
+ upsertCredentialMetadata(service, field, {});
119
+ await syncManualTokenConnection(service);
120
+ }
121
+
82
122
  let apiKeyGeneration = 0;
83
123
 
84
124
  async function queueApiKeyPropagation(
@@ -263,6 +303,15 @@ async function handleAddSecret({ body }: RouteHandlerArgs) {
263
303
  );
264
304
  return { success: false, error: validation.reason };
265
305
  }
306
+ } else if (name === "typesafe") {
307
+ const validation = await validateJevApiKey(value);
308
+ if (!validation.valid) {
309
+ log.warn(
310
+ { provider: name, reason: validation.reason },
311
+ "API key validation failed",
312
+ );
313
+ return { success: false, error: validation.reason };
314
+ }
266
315
  }
267
316
 
268
317
  const stored = await setSecureKeyAsync(
@@ -307,10 +356,50 @@ async function handleAddSecret({ body }: RouteHandlerArgs) {
307
356
  'For credential type, name must be in "service:field" format (e.g. "github:api_token")',
308
357
  );
309
358
  }
310
- assertMetadataWritable();
311
359
  const service = name.slice(0, colonIdx);
312
360
  const field = name.slice(colonIdx + 1);
313
361
 
362
+ if (service === "vellum") {
363
+ if (!isWritableVellumCredentialField(field)) {
364
+ throw new BadRequestError(
365
+ `Unknown vellum credential: ${field}. Allowed fields: ${WRITABLE_VELLUM_CREDENTIAL_FIELDS.join(", ")}`,
366
+ );
367
+ }
368
+ assertMetadataWritable();
369
+ await persistCredential(service, field, value);
370
+ if (field === "platform_base_url") {
371
+ setPlatformBaseUrl(value);
372
+ }
373
+ if (isPlatformManagedCredential(service, field)) {
374
+ await refreshProvidersAfterSecretChange();
375
+ // Close the first-boot race where the startup capability seed ran before
376
+ // the managed embedding credential was provisioned, leaving skill/CLI
377
+ // pages unseeded until restart. Detached, must not block the response.
378
+ void maybeReseedCapabilitiesAfterManagedCredential(getConfig());
379
+ if (field === "assistant_api_key") {
380
+ await notifyCesOfAssistantApiKeyUpdate(value, getCesClient());
381
+ }
382
+ } else {
383
+ await refreshProvidersForRotatedCredential(service, field);
384
+ }
385
+ if (field === "assistant_api_key" || field === "platform_base_url") {
386
+ // Managed-speech availability needs the API key, the assistant ID,
387
+ // and the base URL. Fire on each write that completes a piece of
388
+ // that set; the hook no-ops until the connection is complete.
389
+ // Detached, must not block the response.
390
+ void maybeDefaultSpeechToManaged();
391
+ // Same last-write-wins shape: the startup syncs no-op before live
392
+ // registration, so re-enqueue them here. Both dedup and no-op until
393
+ // the client and assistant id exist.
394
+ syncWorkspaceIdentityToPlatform();
395
+ syncAvatarToPlatform();
396
+ }
397
+ log.info({ service, field }, "Credential added via HTTP");
398
+ return { success: true, type, name };
399
+ }
400
+
401
+ assertMetadataWritable();
402
+
314
403
  // Reject an Anthropic API key pasted into the ACP OAuth-token field (a 401
315
404
  // footgun) as a 400 rather than letting it persist and fail at runtime.
316
405
  if (service === ACP_SERVICE) {
@@ -324,104 +413,8 @@ async function handleAddSecret({ body }: RouteHandlerArgs) {
324
413
  }
325
414
  }
326
415
 
327
- const key = credentialKey(service, field);
328
-
329
- const TRIMMED_IDENTITY_FIELDS = new Set([
330
- "platform_assistant_id",
331
- "platform_organization_id",
332
- "platform_user_id",
333
- ]);
334
- const isTrimmedIdentity =
335
- service === "vellum" && TRIMMED_IDENTITY_FIELDS.has(field);
336
- const effectiveValue = isTrimmedIdentity ? value.trim() : value;
337
-
338
- if (isTrimmedIdentity && effectiveValue === "") {
339
- const deleteResult = await deleteSecureKeyAsync(key);
340
- if (deleteResult === "error") {
341
- throw new InternalError(
342
- `Failed to delete stale credential from secure storage: ${service}:${field}`,
343
- );
344
- }
345
- if (field === "platform_assistant_id") {
346
- setPlatformAssistantId(undefined);
347
- } else if (field === "platform_organization_id") {
348
- setPlatformOrganizationId(undefined);
349
- } else if (field === "platform_user_id") {
350
- setPlatformUserId(undefined);
351
- }
352
- deleteCredentialMetadata(service, field);
353
- } else {
354
- const stored = await setSecureKeyAsync(key, effectiveValue);
355
- if (!stored) {
356
- throw new InternalError(
357
- `Failed to store credential in secure storage (backend: ${getActiveBackendName()})`,
358
- );
359
- }
360
- if (!isNonSecretPlatformField(service, field)) {
361
- // Same seam as the api_key branch: the scrub runs immediately after
362
- // the secure-store write, before side effects that can throw. The
363
- // value IS stored at this point; the scrub is best-effort hygiene
364
- // and must stay invisible to the caller. Counts only — never the
365
- // value.
366
- try {
367
- const scrubbed =
368
- await scrubStoredCredentialFromTranscripts(effectiveValue);
369
- log.info(
370
- { service, field, ...scrubbed },
371
- "Credential stored; scrubbed value from recent transcripts",
372
- );
373
- } catch (err) {
374
- log.warn(
375
- { err, service, field },
376
- "Credential stored, but transcript scrub failed",
377
- );
378
- }
379
- }
380
- upsertCredentialMetadata(service, field, {});
381
- await syncManualTokenConnection(service);
382
- if (service === "vellum" && field === "platform_base_url") {
383
- setPlatformBaseUrl(effectiveValue);
384
- }
385
- if (service === "vellum" && field === "platform_assistant_id") {
386
- setPlatformAssistantId(effectiveValue || undefined);
387
- }
388
- if (service === "vellum" && field === "platform_organization_id") {
389
- setPlatformOrganizationId(effectiveValue || undefined);
390
- }
391
- if (service === "vellum" && field === "platform_user_id") {
392
- setPlatformUserId(effectiveValue || undefined);
393
- }
394
- }
395
- if (isPlatformManagedCredential(service, field)) {
396
- await refreshProvidersAfterSecretChange();
397
- // Close the first-boot race where the startup capability seed ran before
398
- // the managed embedding credential was provisioned, leaving skill/CLI
399
- // pages unseeded until restart. Detached — must not block the response.
400
- void maybeReseedCapabilitiesAfterManagedCredential(getConfig());
401
- if (service === "vellum" && field === "assistant_api_key") {
402
- await notifyCesOfAssistantApiKeyUpdate(value, getCesClient());
403
- }
404
- } else if (!isTrimmedIdentity) {
405
- await refreshProvidersForRotatedCredential(service, field);
406
- }
407
- if (
408
- service === "vellum" &&
409
- (field === "assistant_api_key" ||
410
- field === "platform_assistant_id" ||
411
- field === "platform_base_url")
412
- ) {
413
- // Managed-speech availability needs the API key, the assistant ID,
414
- // and the base URL, and the CLI connect path stores all three
415
- // concurrently — fire on each so the last write to land triggers the
416
- // defaulting; the hook no-ops until the connection is complete.
417
- // Detached — must not block the response.
418
- void maybeDefaultSpeechToManaged();
419
- // Same last-write-wins shape: the startup syncs no-op before live
420
- // registration, so re-enqueue them here. Both dedup and no-op until
421
- // the client and assistant id exist.
422
- syncWorkspaceIdentityToPlatform();
423
- syncAvatarToPlatform();
424
- }
416
+ await persistCredential(service, field, value);
417
+ await refreshProvidersForRotatedCredential(service, field);
425
418
  log.info({ service, field }, "Credential added via HTTP");
426
419
  return { success: true, type, name };
427
420
  }
@@ -464,8 +457,7 @@ async function handleReadSecret({ body }: RouteHandlerArgs) {
464
457
  try {
465
458
  let accountKey: string;
466
459
  let prefetchedResult:
467
- | Awaited<ReturnType<typeof getSecureKeyResultAsync>>
468
- | undefined;
460
+ Awaited<ReturnType<typeof getSecureKeyResultAsync>> | undefined;
469
461
 
470
462
  if (type === "api_key") {
471
463
  if (
@@ -609,6 +601,9 @@ async function handleDeleteSecret({ body }: RouteHandlerArgs) {
609
601
  );
610
602
  }
611
603
  const service = name.slice(0, colonIdx);
604
+ if (service === "vellum") {
605
+ throw new BadRequestError("Vellum credentials cannot be deleted");
606
+ }
612
607
  const field = name.slice(colonIdx + 1);
613
608
  assertMetadataWritable();
614
609
  const key = credentialKey(service, field);
@@ -624,21 +619,6 @@ async function handleDeleteSecret({ body }: RouteHandlerArgs) {
624
619
  );
625
620
  }
626
621
  deleteCredentialMetadata(service, field);
627
- if (service === "vellum" && field === "platform_base_url") {
628
- setPlatformBaseUrl(undefined);
629
- }
630
- if (service === "vellum" && field === "platform_assistant_id") {
631
- setPlatformAssistantId(undefined);
632
- }
633
- if (service === "vellum" && field === "platform_organization_id") {
634
- setPlatformOrganizationId(undefined);
635
- }
636
- if (service === "vellum" && field === "platform_user_id") {
637
- setPlatformUserId(undefined);
638
- }
639
- if (isPlatformManagedCredential(service, field)) {
640
- await refreshProvidersAfterSecretChange();
641
- }
642
622
  invalidateConnectionsAfterCredentialDelete(affectedConnections);
643
623
  log.info({ service, field }, "Credential deleted via HTTP");
644
624
  return { success: true, type, name };
@@ -662,10 +662,16 @@ async function handleToolPermissionSimulate({ body = {} }: RouteHandlerArgs) {
662
662
  const manifestOverride = resolveManifestOverride(toolName);
663
663
  // Permission Simulator path: registered tool wins, then explicit
664
664
  // manifest override, then the standard inference rules.
665
- const executionTarget =
666
- getTool(toolName)?.executionTarget ??
667
- manifestOverride?.execution_target ??
668
- resolveExecutionTarget({ name: toolName });
665
+ const tool = getTool(toolName);
666
+ const executionTarget = resolveExecutionTarget(
667
+ {
668
+ name: toolName,
669
+ executionTarget:
670
+ tool?.executionTarget ?? manifestOverride?.execution_target,
671
+ getExecutionTarget: tool?.getExecutionTarget,
672
+ },
673
+ input,
674
+ );
669
675
  const executionContext =
670
676
  isInteractive === false ? "headless" : "conversation";
671
677
  const policyContext = { executionTarget, executionContext } as const;
@@ -86,7 +86,7 @@ function handleWatcherCreate({ body = {} }: RouteHandlerArgs) {
86
86
  const credentialService =
87
87
  credentialServiceOverride ?? provider.requiredCredentialService;
88
88
 
89
- const watcher = createWatcher({
89
+ return createWatcher({
90
90
  name,
91
91
  providerId,
92
92
  actionPrompt,
@@ -94,8 +94,6 @@ function handleWatcherCreate({ body = {} }: RouteHandlerArgs) {
94
94
  pollIntervalMs,
95
95
  configJson: config ? JSON.stringify(config) : null,
96
96
  });
97
-
98
- return watcher;
99
97
  }
100
98
 
101
99
  function handleWatcherList({ body = {} }: RouteHandlerArgs) {
@@ -1,11 +1,12 @@
1
1
  import { afterEach, describe, expect, test } from "bun:test";
2
2
 
3
+ import { TRUST_CLASS_VALUES } from "@vellumai/gateway-client";
4
+
3
5
  import { resolveCapabilities } from "./capabilities.js";
4
6
  import {
5
7
  derivePersonaTrustFlags,
6
8
  isContactTrustClass,
7
9
  type PersonaTrustFlags,
8
- trustClassSchema,
9
10
  } from "./trust-class.js";
10
11
 
11
12
  describe("isContactTrustClass", () => {
@@ -27,7 +28,7 @@ describe("isContactTrustClass", () => {
27
28
  test("agrees with derivePersonaTrustFlags for every trust class", () => {
28
29
  // The predicate and the persona flags encode the same grouping; pin them
29
30
  // together so neither can drift without failing here.
30
- for (const trustClass of trustClassSchema.options) {
31
+ for (const trustClass of TRUST_CLASS_VALUES) {
31
32
  expect(isContactTrustClass(trustClass)).toBe(
32
33
  derivePersonaTrustFlags(trustClass).isTrustedContact,
33
34
  );
@@ -46,7 +47,7 @@ describe("derivePersonaTrustFlags", () => {
46
47
  });
47
48
 
48
49
  test("trusted_contact and unverified_contact derive identical contact flags", () => {
49
- // The admission-only equivalence documented on trustClassSchema: the two
50
+ // The admission-only equivalence documented in trust-class.ts: the two
50
51
  // classes must never drift apart at the persona layer.
51
52
  const expected: PersonaTrustFlags = {
52
53
  trustClass: "trusted_contact",
@@ -82,9 +83,9 @@ describe("derivePersonaTrustFlags", () => {
82
83
  });
83
84
 
84
85
  test("exactly one flag is true for every trust class", () => {
85
- // Iterates the Zod enum so a newly added class is covered automatically
86
+ // Iterates the canonical class list so a newly added class is covered
86
87
  // (the helper itself won't compile until the new class gets a case).
87
- for (const trustClass of trustClassSchema.options) {
88
+ for (const trustClass of TRUST_CLASS_VALUES) {
88
89
  const flags = derivePersonaTrustFlags(trustClass);
89
90
  const trueCount = [
90
91
  flags.isGuardian,
@@ -128,7 +129,7 @@ describe("derivePersonaTrustFlags", () => {
128
129
  isTrustedContact: "social-engineering-defense",
129
130
  isStranger: "stranger-warning",
130
131
  };
131
- for (const trustClass of trustClassSchema.options) {
132
+ for (const trustClass of TRUST_CLASS_VALUES) {
132
133
  const flags = derivePersonaTrustFlags(trustClass);
133
134
  const guidance = resolveCapabilities(trustClass).promptTrustGuidance;
134
135
  for (const [flag, expected] of Object.entries(guidanceByFlag)) {
@@ -1,10 +1,9 @@
1
1
  /**
2
- * Trust classification for an inbound actor — the single source of truth for
3
- * both the {@link TrustClass} type and the Zod enum ({@link trustClassSchema})
4
- * that validates it in persisted message metadata.
5
- *
6
- * Kept as a leaf module (imports only `zod`) so the runtime trust layer and the
7
- * persistence schema can share one definition without a circular import.
2
+ * The daemon's reading of an inbound actor's trust class. The vocabulary
3
+ * itself ({@link TrustClass}, `TrustClassSchema`) belongs to the gateway,
4
+ * which classifies every actor; it lives in `@vellumai/gateway-client`
5
+ * (`trust-verdict-contract.ts`) and is re-exported here, never redeclared.
6
+ * This module holds what the daemon derives from a class:
8
7
  *
9
8
  * - `'guardian'`: The sender matches the active guardian binding for this
10
9
  * (assistant, channel). Guardians have full control-plane access and
@@ -21,21 +20,14 @@
21
20
  * actors are fail-closed with no escalation path.
22
21
  */
23
22
 
24
- import { z } from "zod";
25
-
26
- export const trustClassSchema = z.enum([
27
- "guardian",
28
- "trusted_contact",
29
- "unverified_contact",
30
- "unknown",
31
- ]);
23
+ import type { TrustClass } from "@vellumai/gateway-client";
32
24
 
33
- export type TrustClass = z.infer<typeof trustClassSchema>;
25
+ export type { TrustClass };
34
26
 
35
27
  /**
36
28
  * Whether a trust class names a known non-guardian contact — the
37
29
  * `trusted_contact` / `unverified_contact` pair whose admission-only
38
- * equivalence is documented on {@link trustClassSchema}.
30
+ * equivalence is documented in this module's header.
39
31
  *
40
32
  * Accepts a raw string (not just `TrustClass`) because several call sites
41
33
  * classify trust classes read back from persisted turn metadata, which may
@@ -75,7 +67,7 @@ export interface PersonaTrustFlags {
75
67
  * needs the opposite default — fail closed, so a turn that never resolved an
76
68
  * actor still renders the guardrail rather than a guardian exemption.
77
69
  * - `unverified_contact` derives identically to `trusted_contact`, making the
78
- * admission-only equivalence documented on {@link trustClassSchema}
70
+ * admission-only equivalence documented in this module's header
79
71
  * executable in one place.
80
72
  * - The switch is exhaustive with no default: adding a `TrustClass` member is a
81
73
  * compile error here, forcing a deliberate persona decision for the new