@vellumai/assistant 0.7.1 → 0.7.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 (535) hide show
  1. package/ARCHITECTURE.md +32 -49
  2. package/Dockerfile +1 -0
  3. package/README.md +1 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
  5. package/bun.lock +26 -26
  6. package/docs/architecture/security.md +20 -0
  7. package/docs/plugins.md +7 -9
  8. package/knip.json +1 -0
  9. package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
  10. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +39 -1
  11. package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
  12. package/node_modules/@vellumai/service-contracts/package.json +2 -0
  13. package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
  14. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
  15. package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
  16. package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
  17. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
  18. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +9 -0
  19. package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
  20. package/node_modules/@vellumai/twilio-client/package.json +18 -0
  21. package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
  22. package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
  23. package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
  24. package/openapi.yaml +565 -12
  25. package/package.json +6 -3
  26. package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
  27. package/src/__tests__/app-bundler.test.ts +170 -1
  28. package/src/__tests__/app-control-flow.test.ts +374 -0
  29. package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
  30. package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
  31. package/src/__tests__/app-executors.test.ts +30 -43
  32. package/src/__tests__/approval-routes-http.test.ts +23 -6
  33. package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
  34. package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
  35. package/src/__tests__/assistant-event-hub.test.ts +109 -2
  36. package/src/__tests__/assistant-event.test.ts +10 -0
  37. package/src/__tests__/assistant-events-sse-hardening.test.ts +7 -2
  38. package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -7
  39. package/src/__tests__/background-shell-host-bash.test.ts +14 -15
  40. package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
  41. package/src/__tests__/btw-routes.test.ts +13 -4
  42. package/src/__tests__/call-controller.test.ts +49 -1
  43. package/src/__tests__/call-domain.test.ts +0 -2
  44. package/src/__tests__/call-routes-http.test.ts +0 -2
  45. package/src/__tests__/channel-readiness-service.test.ts +59 -1
  46. package/src/__tests__/checker.test.ts +3 -4
  47. package/src/__tests__/config-loader-backfill.test.ts +90 -155
  48. package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
  49. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  50. package/src/__tests__/config-set-platform-guard.test.ts +48 -4
  51. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +2 -2
  52. package/src/__tests__/config-watcher.test.ts +2 -2
  53. package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
  54. package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
  55. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  56. package/src/__tests__/conversation-lifecycle.test.ts +36 -0
  57. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
  58. package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
  59. package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
  60. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  61. package/src/__tests__/conversation-slash-commands.test.ts +0 -4
  62. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
  63. package/src/__tests__/conversation-surfaces-app-control.test.ts +317 -0
  64. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
  65. package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
  66. package/src/__tests__/credentials-cli.test.ts +5 -12
  67. package/src/__tests__/cu-unified-flow.test.ts +185 -23
  68. package/src/__tests__/daemon-credential-client.test.ts +101 -19
  69. package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
  70. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  71. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  72. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
  73. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
  74. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
  75. package/src/__tests__/heartbeat-service.test.ts +718 -1
  76. package/src/__tests__/helpers/call-route-handler.ts +7 -1
  77. package/src/__tests__/host-app-control-proxy.test.ts +602 -0
  78. package/src/__tests__/host-app-control-routes.test.ts +263 -0
  79. package/src/__tests__/host-bash-proxy.test.ts +246 -47
  80. package/src/__tests__/host-bash-routes.test.ts +294 -0
  81. package/src/__tests__/host-browser-proxy.test.ts +24 -22
  82. package/src/__tests__/host-browser-routes.test.ts +39 -13
  83. package/src/__tests__/host-cu-proxy.test.ts +41 -52
  84. package/src/__tests__/host-cu-routes-targeted.test.ts +300 -0
  85. package/src/__tests__/host-file-edit-tool.test.ts +47 -1
  86. package/src/__tests__/host-file-proxy-targeted.test.ts +339 -0
  87. package/src/__tests__/host-file-proxy.test.ts +37 -43
  88. package/src/__tests__/host-file-read-tool.test.ts +17 -0
  89. package/src/__tests__/host-file-routes-targeted.test.ts +262 -0
  90. package/src/__tests__/host-file-write-tool.test.ts +42 -1
  91. package/src/__tests__/host-proxy-base.test.ts +312 -0
  92. package/src/__tests__/host-shell-tool.test.ts +22 -4
  93. package/src/__tests__/host-transfer-proxy-targeted.test.ts +583 -0
  94. package/src/__tests__/host-transfer-proxy.test.ts +121 -22
  95. package/src/__tests__/host-transfer-routes-targeted.test.ts +447 -0
  96. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  97. package/src/__tests__/identity-intro-cache.test.ts +29 -0
  98. package/src/__tests__/identity-routes.test.ts +103 -1
  99. package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
  100. package/src/__tests__/inline-command-runner.test.ts +0 -1
  101. package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
  102. package/src/__tests__/integration-status.test.ts +85 -5
  103. package/src/__tests__/intent-routing.test.ts +0 -1
  104. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
  105. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
  106. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
  107. package/src/__tests__/mcp-auth-routes.test.ts +197 -0
  108. package/src/__tests__/mcp-cli.test.ts +338 -2
  109. package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
  110. package/src/__tests__/migration-import-commit-http.test.ts +108 -2
  111. package/src/__tests__/mock-gateway-ipc.ts +1 -0
  112. package/src/__tests__/oauth-cli.test.ts +0 -2
  113. package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
  114. package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
  115. package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
  116. package/src/__tests__/prechat-onboarding-contract.test.ts +3 -1
  117. package/src/__tests__/process-message-background-slack.test.ts +2 -0
  118. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  119. package/src/__tests__/public-ingress-urls.test.ts +97 -0
  120. package/src/__tests__/require-fresh-approval.test.ts +0 -1
  121. package/src/__tests__/retry-backoff.test.ts +87 -0
  122. package/src/__tests__/runtime-events-sse.test.ts +10 -6
  123. package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
  124. package/src/__tests__/schedule-retry.test.ts +715 -0
  125. package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
  126. package/src/__tests__/secret-ingress-http.test.ts +1 -0
  127. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  128. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
  129. package/src/__tests__/skill-feature-flags.test.ts +43 -41
  130. package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
  131. package/src/__tests__/skill-load-inline-command.test.ts +0 -51
  132. package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
  133. package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
  134. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
  135. package/src/__tests__/slack-channel-config.test.ts +9 -14
  136. package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
  137. package/src/__tests__/system-prompt.test.ts +0 -1
  138. package/src/__tests__/telegram-config.test.ts +0 -1
  139. package/src/__tests__/test-preload.ts +8 -0
  140. package/src/__tests__/tool-approval-handler.test.ts +3 -4
  141. package/src/__tests__/tool-audit-listener.test.ts +48 -0
  142. package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
  143. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
  144. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  145. package/src/__tests__/tool-executor.test.ts +0 -1
  146. package/src/__tests__/twilio-config.test.ts +3 -16
  147. package/src/__tests__/twilio-routes.test.ts +3 -5
  148. package/src/__tests__/twilio-validation.test.ts +93 -0
  149. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
  150. package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
  151. package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
  152. package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
  153. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
  154. package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
  155. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
  156. package/src/backup/__tests__/paths.test.ts +0 -22
  157. package/src/backup/__tests__/restore.test.ts +51 -151
  158. package/src/backup/paths.ts +2 -18
  159. package/src/backup/restore.ts +107 -231
  160. package/src/bundler/app-bundler.ts +51 -3
  161. package/src/calls/relay-server.ts +4 -44
  162. package/src/calls/twilio-config.ts +2 -17
  163. package/src/calls/twilio-rest.ts +33 -105
  164. package/src/calls/twilio-routes.ts +11 -12
  165. package/src/channels/types.ts +8 -7
  166. package/src/cli/commands/__tests__/backup.test.ts +6 -277
  167. package/src/cli/commands/__tests__/gateway.test.ts +288 -0
  168. package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
  169. package/src/cli/commands/__tests__/webhooks.test.ts +0 -1
  170. package/src/cli/commands/backup.ts +6 -331
  171. package/src/cli/commands/clients.ts +36 -37
  172. package/src/cli/commands/contacts.ts +73 -0
  173. package/src/cli/commands/conversations.ts +2 -5
  174. package/src/cli/commands/credentials.ts +15 -7
  175. package/src/cli/commands/domain.ts +66 -15
  176. package/src/cli/commands/gateway.ts +183 -0
  177. package/src/cli/commands/keys.ts +9 -6
  178. package/src/cli/commands/mcp.ts +116 -156
  179. package/src/cli/commands/memory-v2.ts +296 -1
  180. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
  181. package/src/cli/commands/platform/__tests__/connect.test.ts +0 -2
  182. package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -2
  183. package/src/cli/commands/platform/__tests__/status.test.ts +13 -15
  184. package/src/cli/commands/platform/disconnect.ts +5 -4
  185. package/src/cli/commands/platform/index.ts +0 -18
  186. package/src/cli/lib/daemon-credential-client.ts +110 -28
  187. package/src/cli/program.ts +2 -0
  188. package/src/config/assistant-feature-flags.ts +67 -10
  189. package/src/config/bundled-skills/acp/SKILL.md +6 -0
  190. package/src/config/bundled-skills/acp/TOOLS.json +1 -22
  191. package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
  192. package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
  193. package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
  194. package/src/config/bundled-skills/app-control/SKILL.md +75 -0
  195. package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
  196. package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
  197. package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
  198. package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
  199. package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
  200. package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
  201. package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
  202. package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
  203. package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
  204. package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
  205. package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
  206. package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
  207. package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
  208. package/src/config/bundled-skills/document/TOOLS.json +0 -8
  209. package/src/config/bundled-skills/followups/TOOLS.json +0 -12
  210. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  211. package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
  212. package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
  213. package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
  214. package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
  215. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +19 -4
  216. package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
  217. package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
  218. package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
  219. package/src/config/bundled-skills/settings/SKILL.md +4 -0
  220. package/src/config/bundled-skills/settings/TOOLS.json +0 -12
  221. package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
  222. package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
  223. package/src/config/bundled-skills/subagent/SKILL.md +6 -2
  224. package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
  225. package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
  226. package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
  227. package/src/config/bundled-tool-registry.ts +21 -0
  228. package/src/config/env-registry.ts +0 -2
  229. package/src/config/env.ts +19 -12
  230. package/src/config/feature-flag-registry.json +21 -133
  231. package/src/config/loader.ts +73 -99
  232. package/src/config/sanitize-for-transfer.ts +2 -0
  233. package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
  234. package/src/config/schemas/__tests__/memory-v2.test.ts +7 -4
  235. package/src/config/schemas/calls.ts +0 -9
  236. package/src/config/schemas/heartbeat.ts +63 -0
  237. package/src/config/schemas/ingress.ts +10 -6
  238. package/src/config/schemas/llm.ts +5 -10
  239. package/src/config/schemas/memory-lifecycle.ts +77 -24
  240. package/src/config/schemas/memory-v2.ts +48 -4
  241. package/src/config/schemas/platform.ts +6 -0
  242. package/src/config/schemas/services.ts +1 -15
  243. package/src/config/schemas/skills.ts +0 -6
  244. package/src/config/seed-inference-profiles.ts +1 -1
  245. package/src/contacts/contact-store.ts +0 -30
  246. package/src/contacts/contacts-write.ts +0 -27
  247. package/src/context/window-manager.ts +1 -2
  248. package/src/credential-execution/feature-gates.ts +10 -10
  249. package/src/credential-execution/process-manager.ts +12 -41
  250. package/src/daemon/__tests__/conversation-tool-setup.test.ts +126 -5
  251. package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
  252. package/src/daemon/config-watcher.ts +4 -3
  253. package/src/daemon/conversation-agent-loop-handlers.ts +21 -3
  254. package/src/daemon/conversation-agent-loop.ts +32 -28
  255. package/src/daemon/conversation-lifecycle.ts +8 -1
  256. package/src/daemon/conversation-process.ts +16 -11
  257. package/src/daemon/conversation-runtime-assembly.ts +2 -2
  258. package/src/daemon/conversation-surfaces.ts +125 -4
  259. package/src/daemon/conversation-tool-setup.ts +16 -55
  260. package/src/daemon/conversation.ts +21 -2
  261. package/src/daemon/doordash-steps.ts +1 -1
  262. package/src/daemon/handlers/shared.ts +4 -1
  263. package/src/daemon/host-app-control-proxy.ts +293 -0
  264. package/src/daemon/host-bash-proxy.ts +84 -74
  265. package/src/daemon/host-browser-proxy.ts +67 -82
  266. package/src/daemon/host-cu-proxy.ts +81 -86
  267. package/src/daemon/host-file-proxy.ts +93 -69
  268. package/src/daemon/host-proxy-base.ts +294 -0
  269. package/src/daemon/host-proxy-preactivation.ts +82 -0
  270. package/src/daemon/host-transfer-proxy.ts +247 -129
  271. package/src/daemon/lifecycle.ts +115 -117
  272. package/src/daemon/message-protocol.ts +3 -8
  273. package/src/daemon/message-types/contacts.ts +23 -1
  274. package/src/daemon/message-types/conversations.ts +11 -8
  275. package/src/daemon/message-types/host-app-control.ts +150 -0
  276. package/src/daemon/message-types/host-bash.ts +4 -0
  277. package/src/daemon/message-types/host-cu.ts +2 -0
  278. package/src/daemon/message-types/host-file.ts +4 -0
  279. package/src/daemon/message-types/host-transfer.ts +3 -0
  280. package/src/daemon/message-types/schedules.ts +8 -3
  281. package/src/daemon/message-types/skills.ts +2 -2
  282. package/src/daemon/process-message.ts +18 -1
  283. package/src/daemon/shutdown-handlers.ts +0 -3
  284. package/src/daemon/tool-setup-types.ts +51 -0
  285. package/src/daemon/tool-side-effects.ts +1 -1
  286. package/src/events/tool-audit-listener.ts +2 -1
  287. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +15 -7
  288. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +216 -0
  289. package/src/heartbeat/heartbeat-run-store.ts +236 -0
  290. package/src/heartbeat/heartbeat-service.ts +280 -49
  291. package/src/home/__tests__/post-connect-feed.test.ts +99 -0
  292. package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
  293. package/src/home/__tests__/suggested-prompts.test.ts +89 -0
  294. package/src/home/post-connect-feed.ts +68 -0
  295. package/src/home/relationship-state-writer.ts +17 -92
  296. package/src/home/suggested-prompts.ts +46 -10
  297. package/src/inbound/public-ingress-urls.ts +32 -34
  298. package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
  299. package/src/ipc/assistant-server.ts +14 -1
  300. package/src/ipc/cli-client.ts +32 -1
  301. package/src/live-voice/live-voice-metrics.ts +10 -10
  302. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
  303. package/src/mcp/mcp-auth-orchestrator.ts +213 -0
  304. package/src/mcp/mcp-auth-state.ts +133 -0
  305. package/src/mcp/mcp-oauth-provider.ts +19 -0
  306. package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
  307. package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
  308. package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
  309. package/src/memory/anisotropy.test.ts +247 -0
  310. package/src/memory/anisotropy.ts +443 -0
  311. package/src/memory/auto-analysis-constants.ts +17 -0
  312. package/src/memory/auto-analysis-guard.ts +5 -15
  313. package/src/memory/canonical-guardian-store.ts +7 -7
  314. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
  315. package/src/memory/context-search/agent-protocol.ts +6 -6
  316. package/src/memory/context-search/agent-runner.ts +32 -7
  317. package/src/memory/context-search/sources/memory-v2.ts +17 -5
  318. package/src/memory/conversation-crud.ts +1 -1
  319. package/src/memory/conversation-key-store.ts +2 -15
  320. package/src/memory/db-init.ts +4 -0
  321. package/src/memory/embedding-backend.ts +9 -21
  322. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +49 -4
  323. package/src/memory/graph/conversation-graph-memory.ts +1 -24
  324. package/src/memory/graph/graph-search.ts +8 -0
  325. package/src/memory/graph/retriever.ts +28 -0
  326. package/src/memory/graph/tools.ts +1 -1
  327. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
  328. package/src/memory/jobs/embed-concept-page.ts +28 -2
  329. package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
  330. package/src/memory/jobs-store.ts +66 -22
  331. package/src/memory/jobs-worker.ts +112 -63
  332. package/src/memory/memory-v2-activation-log-store.ts +1 -1
  333. package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
  334. package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
  335. package/src/memory/migrations/index.ts +5 -0
  336. package/src/memory/migrations/registry.ts +8 -0
  337. package/src/memory/pkb/pkb-search.ts +7 -0
  338. package/src/memory/qdrant-client.ts +50 -20
  339. package/src/memory/schema/infrastructure.ts +15 -0
  340. package/src/memory/search/semantic.ts +7 -0
  341. package/src/memory/sparse-tokenize.ts +49 -0
  342. package/src/memory/v2/__tests__/activation.test.ts +77 -95
  343. package/src/memory/v2/__tests__/injection.test.ts +43 -21
  344. package/src/memory/v2/__tests__/sim.test.ts +166 -6
  345. package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
  346. package/src/memory/v2/__tests__/static-context.test.ts +0 -1
  347. package/src/memory/v2/activation.ts +69 -88
  348. package/src/memory/v2/consolidation-job.ts +3 -5
  349. package/src/memory/v2/constants.ts +7 -0
  350. package/src/memory/v2/injection.ts +86 -53
  351. package/src/memory/v2/prompts/consolidation.ts +312 -91
  352. package/src/memory/v2/qdrant.ts +99 -1
  353. package/src/memory/v2/sim.ts +126 -16
  354. package/src/memory/v2/skill-qdrant.ts +12 -3
  355. package/src/memory/v2/skill-store.ts +16 -1
  356. package/src/memory/v2/sparse-bm25.ts +245 -0
  357. package/src/memory/v2/static-context.ts +6 -5
  358. package/src/messaging/providers/gmail/types.ts +0 -49
  359. package/src/messaging/providers/slack/adapter.ts +1 -31
  360. package/src/messaging/providers/slack/types.ts +0 -32
  361. package/src/notifications/README.md +10 -10
  362. package/src/notifications/broadcaster.ts +1 -1
  363. package/src/notifications/guardian-question-mode.ts +5 -5
  364. package/src/oauth/connect-orchestrator.ts +4 -0
  365. package/src/oauth/credential-token-resolver.ts +1 -3
  366. package/src/oauth/manual-token-connection.ts +0 -4
  367. package/src/outbound-proxy/index.ts +1 -37
  368. package/src/outbound-proxy/logging.ts +1 -1
  369. package/src/outbound-proxy/policy.ts +6 -5
  370. package/src/outbound-proxy/router.ts +2 -1
  371. package/src/permissions/approval-policy.test.ts +6 -275
  372. package/src/permissions/approval-policy.ts +0 -51
  373. package/src/permissions/checker.test.ts +0 -1
  374. package/src/permissions/checker.ts +3 -17
  375. package/src/permissions/gateway-threshold-reader.ts +2 -0
  376. package/src/permissions/prompter.ts +34 -1
  377. package/src/permissions/secret-prompter.ts +6 -2
  378. package/src/prompts/bootstrap-cleanup.ts +27 -0
  379. package/src/prompts/system-prompt.ts +3 -18
  380. package/src/prompts/templates/SOUL.md +13 -1
  381. package/src/providers/speech-to-text/provider-catalog.ts +7 -8
  382. package/src/runtime/assistant-event-hub.ts +118 -96
  383. package/src/runtime/assistant-event.ts +1 -0
  384. package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
  385. package/src/runtime/auth/middleware.ts +0 -96
  386. package/src/runtime/auth/route-policy.ts +19 -0
  387. package/src/runtime/btw-sidechain.ts +2 -3
  388. package/src/runtime/channel-invite-transport.ts +2 -48
  389. package/src/runtime/channel-invite-transports/email.ts +1 -1
  390. package/src/runtime/channel-invite-transports/slack.ts +1 -1
  391. package/src/runtime/channel-invite-transports/telegram.ts +1 -1
  392. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  393. package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
  394. package/src/runtime/channel-invite-types.ts +54 -0
  395. package/src/runtime/channel-readiness-service.ts +32 -13
  396. package/src/runtime/http-server.ts +3 -329
  397. package/src/runtime/http-types.ts +0 -5
  398. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
  399. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
  400. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
  401. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
  402. package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
  403. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  404. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
  405. package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
  406. package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
  407. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
  408. package/src/runtime/migrations/migration-transport.ts +7 -7
  409. package/src/runtime/migrations/vbundle-builder.ts +327 -60
  410. package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
  411. package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
  412. package/src/runtime/migrations/vbundle-importer.ts +245 -68
  413. package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
  414. package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
  415. package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
  416. package/src/runtime/migrations/vbundle-validator.ts +114 -0
  417. package/src/runtime/pending-interactions.ts +35 -9
  418. package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
  419. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
  420. package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
  421. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
  422. package/src/runtime/routes/approval-interception-types.ts +13 -0
  423. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
  424. package/src/runtime/routes/backup-routes.ts +15 -38
  425. package/src/runtime/routes/btw-routes.ts +14 -37
  426. package/src/runtime/routes/client-routes.ts +1 -0
  427. package/src/runtime/routes/contact-prompt-routes.ts +183 -0
  428. package/src/runtime/routes/conversation-query-routes.ts +36 -1
  429. package/src/runtime/routes/conversation-routes.ts +30 -13
  430. package/src/runtime/routes/document-pdf-renderer.ts +165 -0
  431. package/src/runtime/routes/documents-routes.ts +30 -0
  432. package/src/runtime/routes/errors.ts +19 -4
  433. package/src/runtime/routes/events-routes.ts +12 -6
  434. package/src/runtime/routes/gateway-log-routes.ts +79 -0
  435. package/src/runtime/routes/guardian-approval-interception.ts +2 -8
  436. package/src/runtime/routes/heartbeat-routes.ts +103 -38
  437. package/src/runtime/routes/host-app-control-routes.ts +134 -0
  438. package/src/runtime/routes/host-bash-routes.ts +36 -6
  439. package/src/runtime/routes/host-browser-routes.ts +108 -13
  440. package/src/runtime/routes/host-cu-routes.ts +44 -14
  441. package/src/runtime/routes/host-file-routes.ts +33 -10
  442. package/src/runtime/routes/host-transfer-routes.ts +64 -24
  443. package/src/runtime/routes/http-adapter.ts +1 -0
  444. package/src/runtime/routes/identity-intro-cache.ts +30 -0
  445. package/src/runtime/routes/identity-routes.ts +15 -43
  446. package/src/runtime/routes/inbound-message-handler.ts +1 -9
  447. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
  448. package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
  449. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
  450. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
  451. package/src/runtime/routes/index.ts +8 -0
  452. package/src/runtime/routes/mcp-auth-routes.ts +132 -0
  453. package/src/runtime/routes/memory-item-routes.ts +10 -12
  454. package/src/runtime/routes/memory-v2-routes.ts +441 -1
  455. package/src/runtime/routes/migration-routes.ts +96 -0
  456. package/src/runtime/routes/schedule-routes.ts +7 -0
  457. package/src/runtime/verification-templates.ts +4 -7
  458. package/src/schedule/integration-status.ts +66 -2
  459. package/src/schedule/recurrence-engine.ts +4 -1
  460. package/src/schedule/retry-backoff.ts +18 -0
  461. package/src/schedule/retry-policy.ts +82 -0
  462. package/src/schedule/schedule-recovery.ts +64 -0
  463. package/src/schedule/schedule-store.ts +106 -2
  464. package/src/schedule/scheduler-types.ts +25 -0
  465. package/src/schedule/scheduler.ts +63 -38
  466. package/src/security/oauth-callback-registry.ts +8 -0
  467. package/src/sequence/analytics.ts +5 -5
  468. package/src/sequence/engine.ts +1 -1
  469. package/src/skills/catalog-files.ts +2 -8
  470. package/src/skills/include-graph.ts +5 -5
  471. package/src/skills/remote-skill-policy.ts +5 -5
  472. package/src/skills/skill-file-provider.ts +1 -1
  473. package/src/skills/skill-file-types.ts +13 -0
  474. package/src/skills/skillssh-audit-types.ts +28 -0
  475. package/src/skills/skillssh-registry.ts +8 -21
  476. package/src/telemetry/types.ts +2 -0
  477. package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
  478. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  479. package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
  480. package/src/tools/apps/executors.ts +56 -69
  481. package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
  482. package/src/tools/browser/browser-execution.ts +2 -2
  483. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
  484. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
  485. package/src/tools/browser/cdp-client/factory.ts +23 -24
  486. package/src/tools/browser/cdp-client/index.ts +1 -14
  487. package/src/tools/computer-use/definitions.ts +42 -20
  488. package/src/tools/executor.ts +2 -0
  489. package/src/tools/host-filesystem/edit.ts +26 -0
  490. package/src/tools/host-filesystem/read.ts +26 -0
  491. package/src/tools/host-filesystem/transfer.ts +31 -1
  492. package/src/tools/host-filesystem/write.ts +26 -0
  493. package/src/tools/host-terminal/host-shell.ts +58 -0
  494. package/src/tools/schedule/create.ts +6 -0
  495. package/src/tools/schedule/list.ts +2 -0
  496. package/src/tools/schedule/update.ts +10 -0
  497. package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
  498. package/src/tools/shared/filesystem/path-policy.ts +25 -1
  499. package/src/tools/skills/load.ts +0 -32
  500. package/src/tools/tool-approval-handler.ts +1 -5
  501. package/src/tools/types.ts +4 -0
  502. package/src/usage/pricing.ts +1 -1
  503. package/src/workspace/hatched-date.ts +86 -0
  504. package/src/workspace/migrations/003-seed-device-id.ts +1 -1
  505. package/src/workspace/migrations/006-services-config.ts +8 -5
  506. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
  507. package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
  508. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
  509. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
  510. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
  511. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
  512. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
  513. package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
  514. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
  515. package/src/workspace/migrations/AGENTS.md +1 -1
  516. package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
  517. package/src/workspace/migrations/utils.ts +21 -0
  518. package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
  519. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
  520. package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
  521. package/src/__tests__/twilio-rest.test.ts +0 -34
  522. package/src/backup/__tests__/backup-key.test.ts +0 -152
  523. package/src/backup/__tests__/backup-worker.test.ts +0 -782
  524. package/src/backup/__tests__/offsite-writer.test.ts +0 -641
  525. package/src/backup/__tests__/stream-crypt.test.ts +0 -228
  526. package/src/backup/backup-key.ts +0 -137
  527. package/src/backup/backup-worker.ts +0 -472
  528. package/src/backup/offsite-writer.ts +0 -222
  529. package/src/backup/stream-crypt.ts +0 -263
  530. package/src/daemon/message-types/pairing.ts +0 -58
  531. package/src/outbound-proxy/config.ts +0 -20
  532. package/src/outbound-proxy/health.ts +0 -18
  533. package/src/outbound-proxy/types.ts +0 -150
  534. package/src/runtime/capability-tokens.ts +0 -190
  535. package/src/signals/mcp-reload.ts +0 -18
@@ -1,443 +0,0 @@
1
- /**
2
- * E2E smoke test for the cloud-hosted `host_browser_request` round-trip.
3
- *
4
- * Boots the runtime HTTP server in-process, opens a mock chrome-extension
5
- * WebSocket against `/v1/browser-relay`, and drives
6
- * `HostBrowserProxy.instance.request()` end-to-end:
7
- *
8
- * proxy.request()
9
- * → sendToExtension (routed via assistant event hub)
10
- * → mock extension WebSocket receives host_browser_request
11
- * → mock CDP handler (Browser.getVersion fake)
12
- * → POST /v1/host-browser-result (or WS host_browser_result frame)
13
- * → resolveHostBrowserResultByRequestId → proxy.resolve()
14
- * → request() resolves
15
- *
16
- * Covers:
17
- * - Happy path: Browser.getVersion round-trips and returns the fake
18
- * product string.
19
- * - Abort: an aborted AbortSignal resolves with "Aborted" and the mock
20
- * extension receives a host_browser_cancel frame.
21
- * - Timeout: if the mock extension receives the frame but never
22
- * POSTs a result, the proxy's setTimeout path fires and surfaces
23
- * a "timed out waiting for client response" error.
24
- *
25
- * The test runs entirely in Bun + loopback WebSocket/fetch — no real
26
- * Chrome required.
27
- */
28
- import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
29
-
30
- // ── Module mocks (must be declared before the real imports below) ────
31
-
32
- mock.module("../util/logger.js", () => ({
33
- getLogger: () =>
34
- new Proxy({} as Record<string, unknown>, {
35
- get: () => () => {},
36
- }),
37
- }));
38
-
39
- mock.module("../config/loader.js", () => ({
40
- getConfig: () => ({
41
- ui: {},
42
- model: "test",
43
- provider: "test",
44
- memory: { enabled: false },
45
- rateLimit: { maxRequestsPerMinute: 0 },
46
- secretDetection: { enabled: false },
47
- contextWindow: { maxInputTokens: 200000 },
48
- services: {
49
- inference: {
50
- mode: "your-own",
51
- provider: "anthropic",
52
- model: "claude-opus-4-6",
53
- },
54
- "image-generation": {
55
- mode: "your-own",
56
- provider: "gemini",
57
- model: "gemini-3.1-flash-image-preview",
58
- },
59
- "web-search": { mode: "your-own", provider: "inference-provider-native" },
60
- },
61
- }),
62
- }));
63
-
64
- // ── Real imports (after mocks) ──────────────────────────────────────
65
-
66
- import { HostBrowserProxy } from "../daemon/host-browser-proxy.js";
67
- import { getDb } from "../memory/db-connection.js";
68
- import { initializeDb } from "../memory/db-init.js";
69
- import { assistantEventHub } from "../runtime/assistant-event-hub.js";
70
- import { mintToken } from "../runtime/auth/token-service.js";
71
- import { RuntimeHttpServer } from "../runtime/http-server.js";
72
-
73
- initializeDb();
74
-
75
- // ── Helpers ─────────────────────────────────────────────────────────
76
-
77
- /**
78
- * Mint an actor-bound JWT for the given guardianId. The WebSocket
79
- * upgrade handler parses `sub=actor:<assistantId>:<actorPrincipalId>`
80
- * and treats `actorPrincipalId` as the guardianId.
81
- */
82
- function mintActorToken(guardianId: string): string {
83
- return mintToken({
84
- aud: "vellum-daemon",
85
- sub: `actor:self:${guardianId}`,
86
- scope_profile: "actor_client_v1",
87
- policy_epoch: 1,
88
- ttlSeconds: 3600,
89
- });
90
- }
91
-
92
- // ── Tests ───────────────────────────────────────────────────────────
93
-
94
- describe("host_browser cloud-hosted e2e round-trip", () => {
95
- let server: RuntimeHttpServer;
96
- let port: number;
97
- let runtimeBaseUrl: string;
98
-
99
- beforeEach(async () => {
100
- const db = getDb();
101
- db.run("DELETE FROM contact_channels");
102
- db.run("DELETE FROM contacts");
103
- HostBrowserProxy.reset();
104
-
105
- port = 19800 + Math.floor(Math.random() * 200);
106
- runtimeBaseUrl = `http://127.0.0.1:${port}`;
107
- server = new RuntimeHttpServer({ port });
108
- await server.start();
109
- });
110
-
111
- afterEach(async () => {
112
- await server?.stop();
113
- HostBrowserProxy.reset();
114
- });
115
-
116
- test("happy path: Browser.getVersion round-trips through the mock extension", async () => {
117
- const guardianId = `test-guardian-${crypto.randomUUID()}`;
118
- const token = mintActorToken(guardianId);
119
-
120
- const { createMockChromeExtension } =
121
- await import("./fixtures/mock-chrome-extension.js");
122
- const mockExt = createMockChromeExtension({
123
- runtimeBaseUrl,
124
- token,
125
- });
126
- await mockExt.start();
127
- await mockExt.waitForConnection();
128
- await waitForRegistryEntry(guardianId);
129
-
130
- const proxy = HostBrowserProxy.instance;
131
-
132
- const result = await proxy.request(
133
- { cdpMethod: "Browser.getVersion" },
134
- "conv-happy",
135
- );
136
-
137
- expect(result.isError).toBe(false);
138
- expect(result.content).toContain("Chrome/MockTest");
139
-
140
- const received = mockExt.receivedRequests();
141
- expect(received).toHaveLength(1);
142
- expect(received[0].cdpMethod).toBe("Browser.getVersion");
143
- expect(typeof received[0].requestId).toBe("string");
144
- expect(received[0].conversationId).toBe("conv-happy");
145
-
146
- await mockExt.stop();
147
- });
148
-
149
- test("happy path (WS result transport): Browser.getVersion round-trips when the extension returns the result over the same WS", async () => {
150
- const guardianId = `test-guardian-${crypto.randomUUID()}`;
151
- const token = mintActorToken(guardianId);
152
-
153
- const { createMockChromeExtension } =
154
- await import("./fixtures/mock-chrome-extension.js");
155
- const mockExt = createMockChromeExtension({
156
- runtimeBaseUrl,
157
- token,
158
- resultTransport: "ws",
159
- });
160
- await mockExt.start();
161
- await mockExt.waitForConnection();
162
- await waitForRegistryEntry(guardianId);
163
-
164
- const proxy = HostBrowserProxy.instance;
165
-
166
- const result = await proxy.request(
167
- { cdpMethod: "Browser.getVersion" },
168
- "conv-happy-ws",
169
- );
170
-
171
- expect(result.isError).toBe(false);
172
- expect(result.content).toContain("Chrome/MockTest");
173
-
174
- const received = mockExt.receivedRequests();
175
- expect(received).toHaveLength(1);
176
- expect(received[0].cdpMethod).toBe("Browser.getVersion");
177
- expect(received[0].conversationId).toBe("conv-happy-ws");
178
-
179
- expect(proxy.hasPendingRequest(received[0].requestId)).toBe(false);
180
-
181
- await mockExt.stop();
182
- });
183
-
184
- test("abort: AbortSignal resolves to 'Aborted' and extension receives host_browser_cancel", async () => {
185
- const guardianId = `test-guardian-${crypto.randomUUID()}`;
186
- const token = mintActorToken(guardianId);
187
-
188
- const { createMockChromeExtension } =
189
- await import("./fixtures/mock-chrome-extension.js");
190
- const mockExt = createMockChromeExtension({
191
- runtimeBaseUrl,
192
- token,
193
- cdpHandler: () => new Promise(() => {}),
194
- });
195
- await mockExt.start();
196
- await mockExt.waitForConnection();
197
- await waitForRegistryEntry(guardianId);
198
-
199
- const proxy = HostBrowserProxy.instance;
200
-
201
- const controller = new AbortController();
202
- const resultPromise = proxy.request(
203
- { cdpMethod: "Browser.getVersion" },
204
- "conv-abort",
205
- controller.signal,
206
- );
207
-
208
- await waitFor(() => mockExt.receivedRequests().length === 1);
209
-
210
- controller.abort();
211
- const result = await resultPromise;
212
-
213
- expect(result.content).toBe("Aborted");
214
- expect(result.isError).toBe(true);
215
-
216
- await waitFor(() => mockExt.receivedCancels().length === 1);
217
- const cancels = mockExt.receivedCancels();
218
- expect(cancels).toHaveLength(1);
219
- expect(cancels[0].requestId).toBe(mockExt.receivedRequests()[0].requestId);
220
-
221
- await mockExt.stop();
222
- });
223
-
224
- test("abort: late /v1/host-browser-result POST after cancel is ignored (no ghost completion)", async () => {
225
- const guardianId = `test-guardian-${crypto.randomUUID()}`;
226
- const token = mintActorToken(guardianId);
227
-
228
- const { createMockChromeExtension } =
229
- await import("./fixtures/mock-chrome-extension.js");
230
- const mockExt = createMockChromeExtension({
231
- runtimeBaseUrl,
232
- token,
233
- cdpHandler: () => new Promise(() => {}),
234
- });
235
- await mockExt.start();
236
- await mockExt.waitForConnection();
237
- await waitForRegistryEntry(guardianId);
238
-
239
- const proxy = HostBrowserProxy.instance;
240
-
241
- let resolveCount = 0;
242
- const controller = new AbortController();
243
- const resultPromise = proxy
244
- .request(
245
- { cdpMethod: "Browser.getVersion" },
246
- "conv-abort-late",
247
- controller.signal,
248
- )
249
- .then((r) => {
250
- resolveCount += 1;
251
- return r;
252
- });
253
-
254
- await waitFor(() => mockExt.receivedRequests().length === 1);
255
- const pendingRequestId = mockExt.receivedRequests()[0].requestId;
256
-
257
- controller.abort();
258
- const result = await resultPromise;
259
- expect(result.content).toBe("Aborted");
260
- expect(result.isError).toBe(true);
261
- expect(resolveCount).toBe(1);
262
-
263
- // Manually submit a late result for the same requestId —
264
- // simulating a non-compliant client that failed to honour the
265
- // cancel envelope. The runtime must accept the POST without error
266
- // and the proxy must NOT resolve the caller a second time.
267
- const lateResp = await fetch(`${runtimeBaseUrl}/v1/host-browser-result`, {
268
- method: "POST",
269
- headers: {
270
- "Content-Type": "application/json",
271
- Authorization: `Bearer ${token}`,
272
- },
273
- body: JSON.stringify({
274
- requestId: pendingRequestId,
275
- content: JSON.stringify({ product: "Chrome/LateResult" }),
276
- isError: false,
277
- }),
278
- });
279
- await lateResp.body?.cancel();
280
-
281
- await new Promise((r) => setTimeout(r, 20));
282
- expect(resolveCount).toBe(1);
283
-
284
- await mockExt.stop();
285
- });
286
-
287
- test("timeout: proxy.request resolves with timeout error when client never responds", async () => {
288
- const guardianId = `test-guardian-${crypto.randomUUID()}`;
289
- const token = mintActorToken(guardianId);
290
-
291
- const { createMockChromeExtension } =
292
- await import("./fixtures/mock-chrome-extension.js");
293
- const mockExt = createMockChromeExtension({
294
- runtimeBaseUrl,
295
- token,
296
- cdpHandler: () => new Promise(() => {}),
297
- });
298
- await mockExt.start();
299
- await mockExt.waitForConnection();
300
- await waitForRegistryEntry(guardianId);
301
-
302
- const proxy = HostBrowserProxy.instance;
303
-
304
- const resultPromise = proxy.request(
305
- { cdpMethod: "Browser.getVersion", timeout_seconds: 0.5 },
306
- "conv-timeout",
307
- );
308
-
309
- await waitFor(() => mockExt.receivedRequests().length === 1);
310
-
311
- const result = await resultPromise;
312
-
313
- expect(result.isError).toBe(true);
314
- expect(result.content).toContain("timed out");
315
-
316
- expect(mockExt.receivedRequests()).toHaveLength(1);
317
- expect(mockExt.receivedRequests()[0].cdpMethod).toBe("Browser.getVersion");
318
-
319
- await mockExt.stop();
320
- });
321
- });
322
-
323
- // ── macOS message ingress with connected extension ──────────────────
324
-
325
- describe("macOS message ingress with connected extension", () => {
326
- let server: RuntimeHttpServer;
327
- let port: number;
328
- let runtimeBaseUrl: string;
329
-
330
- beforeEach(async () => {
331
- const db = getDb();
332
- db.run("DELETE FROM contact_channels");
333
- db.run("DELETE FROM contacts");
334
- HostBrowserProxy.reset();
335
-
336
- port = 20000 + Math.floor(Math.random() * 200);
337
- runtimeBaseUrl = `http://127.0.0.1:${port}`;
338
- server = new RuntimeHttpServer({ port });
339
- await server.start();
340
- });
341
-
342
- afterEach(async () => {
343
- await server?.stop();
344
- HostBrowserProxy.reset();
345
- });
346
-
347
- test("macOS turn routes Browser.getVersion through the registry-backed extension", async () => {
348
- const guardianId = `test-guardian-macos-${crypto.randomUUID()}`;
349
- const token = mintActorToken(guardianId);
350
-
351
- const { createMockChromeExtension } =
352
- await import("./fixtures/mock-chrome-extension.js");
353
- const mockExt = createMockChromeExtension({
354
- runtimeBaseUrl,
355
- token,
356
- });
357
- await mockExt.start();
358
- await mockExt.waitForConnection();
359
- await waitForRegistryEntry(guardianId);
360
-
361
- const proxy = HostBrowserProxy.instance;
362
-
363
- const result = await proxy.request(
364
- { cdpMethod: "Browser.getVersion" },
365
- "conv-macos-ext",
366
- );
367
-
368
- expect(result.isError).toBe(false);
369
- expect(result.content).toContain("Chrome/MockTest");
370
-
371
- const received = mockExt.receivedRequests();
372
- expect(received).toHaveLength(1);
373
- expect(received[0].cdpMethod).toBe("Browser.getVersion");
374
- expect(received[0].conversationId).toBe("conv-macos-ext");
375
-
376
- await mockExt.stop();
377
- });
378
-
379
- test("macOS turn with extension disconnected mid-conversation rejects (proxy detects unavailability)", async () => {
380
- const guardianId = `test-guardian-macos-disco-${crypto.randomUUID()}`;
381
- const token = mintActorToken(guardianId);
382
-
383
- const { createMockChromeExtension } =
384
- await import("./fixtures/mock-chrome-extension.js");
385
- const mockExt = createMockChromeExtension({
386
- runtimeBaseUrl,
387
- token,
388
- });
389
- await mockExt.start();
390
- await mockExt.waitForConnection();
391
- await waitForRegistryEntry(guardianId);
392
-
393
- mockExt.forceDisconnect();
394
-
395
- await waitFor(
396
- () =>
397
- assistantEventHub.getMostRecentClientByCapability("host_browser") ==
398
- null,
399
- );
400
-
401
- const proxy = HostBrowserProxy.instance;
402
-
403
- try {
404
- await proxy.request(
405
- { cdpMethod: "Browser.getVersion", timeout_seconds: 0.5 },
406
- "conv-macos-disco",
407
- );
408
- expect(true).toBe(false); // Should not reach here
409
- } catch {
410
- // Expected: the send failed because the extension is disconnected.
411
- }
412
-
413
- await mockExt.stop();
414
- });
415
- });
416
-
417
- // ── Local wait helpers ──────────────────────────────────────────────
418
-
419
- async function waitFor(
420
- predicate: () => boolean,
421
- timeoutMs = 2000,
422
- ): Promise<void> {
423
- const deadline = Date.now() + timeoutMs;
424
- while (!predicate()) {
425
- if (Date.now() > deadline) {
426
- throw new Error(
427
- `waitFor: predicate did not become true within ${timeoutMs}ms`,
428
- );
429
- }
430
- await new Promise((r) => setTimeout(r, 10));
431
- }
432
- }
433
-
434
- async function waitForRegistryEntry(
435
- _guardianId: string,
436
- timeoutMs = 2000,
437
- ): Promise<void> {
438
- await waitFor(
439
- () =>
440
- assistantEventHub.getMostRecentClientByCapability("host_browser") != null,
441
- timeoutMs,
442
- );
443
- }
@@ -1,226 +0,0 @@
1
- /**
2
- * End-to-end smoke test for the self-hosted **capability-token**
3
- * WebSocket round-trip over `/v1/browser-relay`.
4
- *
5
- * This file is the Phase 3 complement to `host-browser-e2e-cloud.test.ts`:
6
- * it exercises the same mock-chrome-extension → runtime → HostBrowserProxy
7
- * path, but the extension authenticates with a capability token minted
8
- * by `mintHostBrowserCapability()` instead of a guardian-bound JWT.
9
- *
10
- * Invariants covered:
11
- *
12
- * 1. `/v1/browser-relay` accepts capability tokens directly.
13
- * 2. The WS upgrade handler derives the registry-key guardianId from
14
- * the capability claims so host_browser_request frames route
15
- * back to the right connection.
16
- * 3. A full `Browser.getVersion` request round-trips through the
17
- * mock fixture and resolves on the proxy side.
18
- *
19
- * If this test fails, the self-hosted transport cutover is broken.
20
- */
21
-
22
- import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
23
-
24
- // ── Module mocks (must be declared before the real imports below) ────
25
-
26
- mock.module("../util/logger.js", () => ({
27
- getLogger: () =>
28
- new Proxy({} as Record<string, unknown>, {
29
- get: () => () => {},
30
- }),
31
- }));
32
-
33
- mock.module("../config/loader.js", () => ({
34
- getConfig: () => ({
35
- ui: {},
36
- model: "test",
37
- provider: "test",
38
- memory: { enabled: false },
39
- rateLimit: { maxRequestsPerMinute: 0 },
40
- secretDetection: { enabled: false },
41
- contextWindow: { maxInputTokens: 200000 },
42
- services: {
43
- inference: {
44
- mode: "your-own",
45
- provider: "anthropic",
46
- model: "claude-opus-4-6",
47
- },
48
- "image-generation": {
49
- mode: "your-own",
50
- provider: "gemini",
51
- model: "gemini-3.1-flash-image-preview",
52
- },
53
- "web-search": { mode: "your-own", provider: "inference-provider-native" },
54
- },
55
- }),
56
- }));
57
-
58
- // ── Real imports (after mocks) ──────────────────────────────────────
59
-
60
- import { HostBrowserProxy } from "../daemon/host-browser-proxy.js";
61
- import { getDb } from "../memory/db-connection.js";
62
- import { initializeDb } from "../memory/db-init.js";
63
- import { assistantEventHub } from "../runtime/assistant-event-hub.js";
64
- import { mintToken } from "../runtime/auth/token-service.js";
65
- import {
66
- mintHostBrowserCapability,
67
- resetCapabilityTokenSecretForTests,
68
- setCapabilityTokenSecretForTests,
69
- } from "../runtime/capability-tokens.js";
70
- import { RuntimeHttpServer } from "../runtime/http-server.js";
71
-
72
- initializeDb();
73
-
74
- function mintSseToken(guardianId: string): string {
75
- return mintToken({
76
- aud: "vellum-daemon",
77
- sub: `actor:self:${guardianId}`,
78
- scope_profile: "actor_client_v1",
79
- policy_epoch: 1,
80
- ttlSeconds: 3600,
81
- });
82
- }
83
-
84
- // ── Tests ───────────────────────────────────────────────────────────
85
-
86
- describe("host_browser self-hosted capability-token e2e round-trip", () => {
87
- let server: RuntimeHttpServer;
88
- let port: number;
89
- let runtimeBaseUrl: string;
90
-
91
- beforeEach(async () => {
92
- setCapabilityTokenSecretForTests(Buffer.alloc(32, 0xab));
93
-
94
- const db = getDb();
95
- db.run("DELETE FROM contact_channels");
96
- db.run("DELETE FROM contacts");
97
- HostBrowserProxy.reset();
98
-
99
- port = 19600 + Math.floor(Math.random() * 200);
100
- runtimeBaseUrl = `http://127.0.0.1:${port}`;
101
- server = new RuntimeHttpServer({ port });
102
- await server.start();
103
- });
104
-
105
- afterEach(async () => {
106
- await server?.stop();
107
- HostBrowserProxy.reset();
108
- resetCapabilityTokenSecretForTests();
109
- });
110
-
111
- test("capability token round-trips Browser.getVersion over WS result transport", async () => {
112
- const guardianId = `self-hosted-guardian-${crypto.randomUUID()}`;
113
- const { token } = mintHostBrowserCapability(guardianId);
114
-
115
- const { createMockChromeExtension } =
116
- await import("./fixtures/mock-chrome-extension.js");
117
- const mockExt = createMockChromeExtension({
118
- runtimeBaseUrl,
119
- token,
120
- sseToken: mintSseToken(guardianId),
121
- resultTransport: "ws",
122
- });
123
- await mockExt.start();
124
- await mockExt.waitForConnection();
125
- await waitForRegistryEntry(guardianId);
126
-
127
- const proxy = HostBrowserProxy.instance;
128
-
129
- const result = await proxy.request(
130
- { cdpMethod: "Browser.getVersion" },
131
- "conv-cap-happy-ws",
132
- );
133
-
134
- expect(result.isError).toBe(false);
135
- expect(result.content).toContain("Chrome/MockTest");
136
-
137
- const received = mockExt.receivedRequests();
138
- expect(received).toHaveLength(1);
139
- expect(received[0].cdpMethod).toBe("Browser.getVersion");
140
- expect(received[0].conversationId).toBe("conv-cap-happy-ws");
141
-
142
- await mockExt.stop();
143
- });
144
-
145
- test("capability token round-trips Browser.getVersion over HTTP POST fallback", async () => {
146
- const guardianId = `self-hosted-guardian-${crypto.randomUUID()}`;
147
- const { token } = mintHostBrowserCapability(guardianId);
148
-
149
- const { createMockChromeExtension } =
150
- await import("./fixtures/mock-chrome-extension.js");
151
- const mockExt = createMockChromeExtension({
152
- runtimeBaseUrl,
153
- token,
154
- sseToken: mintSseToken(guardianId),
155
- resultTransport: "http",
156
- });
157
- await mockExt.start();
158
- await mockExt.waitForConnection();
159
- await waitForRegistryEntry(guardianId);
160
-
161
- const proxy = HostBrowserProxy.instance;
162
-
163
- const result = await proxy.request(
164
- { cdpMethod: "Browser.getVersion" },
165
- "conv-cap-happy-http",
166
- );
167
-
168
- expect(result.isError).toBe(false);
169
- expect(result.content).toContain("Chrome/MockTest");
170
-
171
- const received = mockExt.receivedRequests();
172
- expect(received).toHaveLength(1);
173
- expect(received[0].cdpMethod).toBe("Browser.getVersion");
174
- expect(received[0].conversationId).toBe("conv-cap-happy-http");
175
-
176
- await mockExt.stop();
177
- });
178
-
179
- test("an invalid capability token is rejected with 401", async () => {
180
- const { createMockChromeExtension } =
181
- await import("./fixtures/mock-chrome-extension.js");
182
- const mockExt = createMockChromeExtension({
183
- runtimeBaseUrl,
184
- token: "totally-bogus-not-a-real-token",
185
- });
186
- let started = false;
187
- try {
188
- await mockExt.start();
189
- started = true;
190
- await mockExt.waitForConnection(500);
191
- } catch {
192
- // expected — SSE or WS auth rejects the bad token
193
- }
194
- // The extension must not reach a fully-connected state.
195
- expect(started).toBe(false);
196
- await mockExt.stop();
197
- });
198
- });
199
-
200
- // ── Local wait helpers ──────────────────────────────────────────────
201
-
202
- async function waitFor(
203
- predicate: () => boolean,
204
- timeoutMs = 2000,
205
- ): Promise<void> {
206
- const deadline = Date.now() + timeoutMs;
207
- while (!predicate()) {
208
- if (Date.now() > deadline) {
209
- throw new Error(
210
- `waitFor: predicate did not become true within ${timeoutMs}ms`,
211
- );
212
- }
213
- await new Promise((r) => setTimeout(r, 10));
214
- }
215
- }
216
-
217
- async function waitForRegistryEntry(
218
- _guardianId: string,
219
- timeoutMs = 2000,
220
- ): Promise<void> {
221
- await waitFor(
222
- () =>
223
- assistantEventHub.getMostRecentClientByCapability("host_browser") != null,
224
- timeoutMs,
225
- );
226
- }