@vellumai/assistant 0.10.1 → 0.10.2-dev.202606241651.2d2b40d

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 (367) hide show
  1. package/docs/workspace-tools.md +42 -33
  2. package/eslint-rules/cli-no-daemon-internals.js +6 -0
  3. package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +91 -0
  4. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +31 -0
  5. package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +48 -0
  6. package/node_modules/@vellumai/gateway-client/src/index.ts +14 -0
  7. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +17 -0
  8. package/openapi.yaml +74 -1
  9. package/package.json +1 -1
  10. package/scripts/test.sh +36 -15
  11. package/src/__tests__/actor-token-service.test.ts +36 -14
  12. package/src/__tests__/agent-loop-override-profile.test.ts +1 -0
  13. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
  14. package/src/__tests__/agent-wake-override-profile.test.ts +2 -0
  15. package/src/__tests__/annotate-activity-metadata.test.ts +2 -0
  16. package/src/__tests__/annotate-risk-options.test.ts +2 -0
  17. package/src/__tests__/approval-cascade.test.ts +2 -0
  18. package/src/__tests__/background-workers-disk-pressure.test.ts +2 -0
  19. package/src/__tests__/btw-routes.test.ts +2 -0
  20. package/src/__tests__/build-persisted-content.test.ts +2 -0
  21. package/src/__tests__/call-controller.test.ts +19 -0
  22. package/src/__tests__/channel-guardian.test.ts +94 -58
  23. package/src/__tests__/channel-reply-delivery.test.ts +2 -0
  24. package/src/__tests__/compaction-events.test.ts +2 -0
  25. package/src/__tests__/compaction.benchmark.test.ts +2 -0
  26. package/src/__tests__/compactor-call-site-logging.test.ts +2 -0
  27. package/src/__tests__/compactor-low-watermark-cut.test.ts +2 -0
  28. package/src/__tests__/compactor-preserved-tail-count.test.ts +2 -0
  29. package/src/__tests__/compactor-summary-call-truncation.test.ts +2 -0
  30. package/src/__tests__/compactor-web-search-strip.test.ts +2 -0
  31. package/src/__tests__/computer-use-tools.test.ts +13 -0
  32. package/src/__tests__/config-loader-backfill.test.ts +5 -1
  33. package/src/__tests__/config-schema.test.ts +1 -0
  34. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +31 -29
  35. package/src/__tests__/contacts-relay-reads.test.ts +13 -15
  36. package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
  37. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +2 -0
  38. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  39. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
  40. package/src/__tests__/conversation-agent-loop.test.ts +7 -0
  41. package/src/__tests__/conversation-analysis-routes.test.ts +2 -0
  42. package/src/__tests__/conversation-app-control-lifecycle.test.ts +2 -0
  43. package/src/__tests__/conversation-confirmation-signals.test.ts +2 -0
  44. package/src/__tests__/conversation-history-web-search.test.ts +2 -0
  45. package/src/__tests__/conversation-load-history-repair.test.ts +2 -0
  46. package/src/__tests__/conversation-load-history-stripped.test.ts +2 -0
  47. package/src/__tests__/conversation-pairing.test.ts +2 -0
  48. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
  49. package/src/__tests__/conversation-process-callsite.test.ts +2 -0
  50. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
  51. package/src/__tests__/conversation-queue.test.ts +91 -0
  52. package/src/__tests__/conversation-routes-guardian-reply.test.ts +14 -0
  53. package/src/__tests__/conversation-routes-slash-commands.test.ts +14 -0
  54. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  55. package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
  56. package/src/__tests__/conversation-speed-override.test.ts +2 -0
  57. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +65 -0
  58. package/src/__tests__/conversation-title-service.test.ts +2 -0
  59. package/src/__tests__/conversation-tool-setup-attribution.test.ts +47 -0
  60. package/src/__tests__/conversation-usage.test.ts +2 -0
  61. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -0
  62. package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
  63. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
  64. package/src/__tests__/credential-security-invariants.test.ts +0 -1
  65. package/src/__tests__/db-migration-rollback.test.ts +205 -171
  66. package/src/__tests__/db-test-helpers.ts +5 -4
  67. package/src/__tests__/deterministic-verification-control-plane.test.ts +4 -2
  68. package/src/__tests__/disk-pressure-guard.test.ts +41 -0
  69. package/src/__tests__/dm-persistence.test.ts +2 -0
  70. package/src/__tests__/emit-signal-routing-intent.test.ts +10 -5
  71. package/src/__tests__/events-dev-bypass-actor.test.ts +7 -1
  72. package/src/__tests__/filing-service.test.ts +2 -0
  73. package/src/__tests__/guardian-binding-drift-heal.test.ts +75 -10
  74. package/src/__tests__/guardian-dispatch.test.ts +95 -1
  75. package/src/__tests__/guardian-outbound-http.test.ts +13 -0
  76. package/src/__tests__/heartbeat-disk-pressure.test.ts +2 -0
  77. package/src/__tests__/heartbeat-service.test.ts +2 -0
  78. package/src/__tests__/helpers/channel-test-adapter.ts +1 -7
  79. package/src/__tests__/host-app-control-routes.test.ts +24 -30
  80. package/src/__tests__/host-bash-routes.test.ts +31 -41
  81. package/src/__tests__/host-browser-routes.test.ts +26 -32
  82. package/src/__tests__/host-cu-proxy.test.ts +299 -0
  83. package/src/__tests__/host-cu-routes-targeted.test.ts +25 -33
  84. package/src/__tests__/host-file-routes-targeted.test.ts +40 -52
  85. package/src/__tests__/host-transfer-routes-targeted.test.ts +31 -43
  86. package/src/__tests__/http-user-message-parity.test.ts +167 -8
  87. package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
  88. package/src/__tests__/invite-redemption-service.test.ts +43 -0
  89. package/src/__tests__/llm-context-normalization.test.ts +105 -0
  90. package/src/__tests__/llm-usage-store.test.ts +25 -0
  91. package/src/__tests__/media-stream-server-integration.test.ts +127 -0
  92. package/src/__tests__/memory-retrieval-hook.test.ts +2 -0
  93. package/src/__tests__/messaging-send-tool.test.ts +2 -0
  94. package/src/__tests__/migration-import-from-url.test.ts +2 -2
  95. package/src/__tests__/native-web-search.test.ts +2 -0
  96. package/src/__tests__/non-member-access-request.test.ts +189 -17
  97. package/src/__tests__/notification-broadcaster.test.ts +4 -0
  98. package/src/__tests__/notification-decision-recipient-context.test.ts +33 -32
  99. package/src/__tests__/notification-deep-link.test.ts +6 -0
  100. package/src/__tests__/notification-guardian-path.test.ts +19 -0
  101. package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
  102. package/src/__tests__/pending-interactions-resolved-event.test.ts +7 -4
  103. package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
  104. package/src/__tests__/plugin-bootstrap.test.ts +3 -73
  105. package/src/__tests__/plugin-route-contribution.test.ts +4 -17
  106. package/src/__tests__/plugin-tool-contribution.test.ts +3 -18
  107. package/src/__tests__/plugin-types.test.ts +0 -2
  108. package/src/__tests__/process-message-background-slack.test.ts +2 -0
  109. package/src/__tests__/process-message-display-content.test.ts +2 -0
  110. package/src/__tests__/provider-usage-tracking.test.ts +39 -0
  111. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +2 -0
  112. package/src/__tests__/registry.test.ts +3 -0
  113. package/src/__tests__/relay-server.test.ts +694 -25
  114. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
  115. package/src/__tests__/secret-ingress-http.test.ts +14 -0
  116. package/src/__tests__/send-endpoint-busy.test.ts +30 -8
  117. package/src/__tests__/skills.test.ts +44 -0
  118. package/src/__tests__/slack-inbound-verification.test.ts +47 -2
  119. package/src/__tests__/sse-actor-principal-guardian-source.test.ts +102 -0
  120. package/src/__tests__/steer-on-enqueue-question.test.ts +181 -0
  121. package/src/__tests__/stt-hints.test.ts +44 -13
  122. package/src/__tests__/subagent-detail.test.ts +27 -0
  123. package/src/__tests__/subagent-disposal.test.ts +65 -0
  124. package/src/__tests__/subagent-notify-parent.test.ts +2 -0
  125. package/src/__tests__/subagent-spawn-tool-fork.test.ts +2 -0
  126. package/src/__tests__/subagent-tools.test.ts +2 -0
  127. package/src/__tests__/suggestion-routes.test.ts +2 -0
  128. package/src/__tests__/title-generate-hook.test.ts +2 -0
  129. package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -0
  130. package/src/__tests__/tool-executor.test.ts +16 -11
  131. package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
  132. package/src/__tests__/tool-result-metadata-plumbing.test.ts +2 -0
  133. package/src/__tests__/tool-start-timestamp.test.ts +2 -0
  134. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +10 -10
  135. package/src/__tests__/twilio-routes.test.ts +96 -0
  136. package/src/__tests__/verification-control-plane-policy.test.ts +2 -0
  137. package/src/__tests__/web-search-backend-failure.test.ts +2 -0
  138. package/src/__tests__/workspace-tool-loader.test.ts +195 -2
  139. package/src/agent/loop-exclusive-tool.test.ts +150 -0
  140. package/src/agent/loop.ts +56 -0
  141. package/src/api/constants/sse-replay.ts +41 -0
  142. package/src/api/index.ts +6 -0
  143. package/src/api/responses/llm-request-log-entry.ts +25 -0
  144. package/src/api/responses/subagent-detail.ts +17 -0
  145. package/src/calls/__tests__/relay-setup-router.test.ts +262 -4
  146. package/src/calls/call-domain.ts +3 -3
  147. package/src/calls/guardian-dispatch.ts +10 -8
  148. package/src/calls/inbound-trust-reader.ts +17 -1
  149. package/src/calls/media-stream-server.ts +21 -0
  150. package/src/calls/relay-server.ts +167 -50
  151. package/src/calls/relay-setup-router.ts +37 -7
  152. package/src/calls/relay-verification.ts +4 -4
  153. package/src/calls/stt-hints.ts +9 -12
  154. package/src/calls/twilio-routes.ts +14 -4
  155. package/src/cli/commands/__tests__/cache.test.ts +8 -1
  156. package/src/cli/commands/cache.ts +194 -181
  157. package/src/cli/commands/db/__tests__/repair.test.ts +6 -5
  158. package/src/cli/commands/db/status.ts +37 -1
  159. package/src/cli/commands/mcp.ts +252 -218
  160. package/src/cli/commands/memory/__tests__/worker.test.ts +302 -0
  161. package/src/cli/commands/memory/index.ts +2 -0
  162. package/src/cli/commands/memory/worker.ts +175 -0
  163. package/src/cli/commands/plugins.ts +75 -3
  164. package/src/cli/lib/__tests__/install-from-github.test.ts +102 -0
  165. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +160 -1
  166. package/src/cli/lib/list-installed-plugins.ts +179 -1
  167. package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +143 -0
  168. package/src/config/bundled-skills/computer-use/TOOLS.json +6 -1
  169. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +27 -17
  170. package/src/config/bundled-skills/contacts/tools/contact-search.ts +13 -3
  171. package/src/config/feature-flag-registry.json +0 -8
  172. package/src/config/loader.ts +36 -5
  173. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  174. package/src/config/schemas/memory-lifecycle.ts +12 -0
  175. package/src/config/schemas/memory-v3.ts +7 -0
  176. package/src/config/schemas/memory.ts +4 -0
  177. package/src/config/schemas/timeouts.ts +8 -0
  178. package/src/config/seed-inference-profiles.ts +14 -5
  179. package/src/config/skills.ts +27 -5
  180. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +312 -0
  181. package/src/contacts/contacts-write.ts +3 -0
  182. package/src/contacts/guardian-delivery-reader.ts +223 -0
  183. package/src/daemon/conversation-agent-loop.ts +9 -0
  184. package/src/daemon/conversation-process.ts +39 -17
  185. package/src/daemon/conversation-surfaces.ts +8 -0
  186. package/src/daemon/conversation-tool-setup.ts +49 -16
  187. package/src/daemon/conversation.ts +21 -2
  188. package/src/daemon/disk-pressure-guard.ts +12 -2
  189. package/src/daemon/event-loop-watchdog.ts +28 -1
  190. package/src/daemon/external-plugins-bootstrap.ts +4 -34
  191. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +25 -0
  192. package/src/daemon/handlers/__tests__/config-channels.test.ts +225 -0
  193. package/src/daemon/handlers/config-a2a.ts +6 -14
  194. package/src/daemon/handlers/config-channels.ts +78 -22
  195. package/src/daemon/handlers/conversations.ts +77 -0
  196. package/src/daemon/host-cu-proxy.ts +102 -11
  197. package/src/daemon/lifecycle.ts +4 -0
  198. package/src/daemon/memory-v2-startup.test.ts +72 -0
  199. package/src/daemon/memory-v2-startup.ts +87 -19
  200. package/src/daemon/server.ts +0 -4
  201. package/src/daemon/shutdown-handlers.ts +20 -0
  202. package/src/daemon/tool-setup-types.ts +9 -0
  203. package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
  204. package/src/ipc/assistant-server.ts +2 -2
  205. package/src/memory/__tests__/301-create-watchdog-events.test.ts +110 -0
  206. package/src/memory/__tests__/memory-retrospective-job.test.ts +8 -0
  207. package/src/memory/__tests__/prompt-override.test.ts +192 -0
  208. package/src/memory/__tests__/watchdog-events-store.test.ts +161 -0
  209. package/src/memory/conversation-crud.ts +38 -0
  210. package/src/memory/db-connection.ts +22 -3
  211. package/src/memory/db-init.ts +36 -502
  212. package/src/memory/db-singleton.ts +6 -4
  213. package/src/memory/jobs-worker.ts +58 -0
  214. package/src/memory/llm-usage-store.ts +48 -20
  215. package/src/memory/memory-retrospective-job.ts +9 -8
  216. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +13 -3
  217. package/src/memory/migrations/136-drop-assistant-id-columns.ts +52 -27
  218. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +130 -56
  219. package/src/memory/migrations/300-add-processing-started-at.ts +30 -0
  220. package/src/memory/migrations/301-create-watchdog-events.ts +45 -0
  221. package/src/memory/migrations/__tests__/014-backfill-inbox-thread-state.test.ts +108 -0
  222. package/src/memory/migrations/__tests__/136-drop-assistant-id-columns.test.ts +82 -0
  223. package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +224 -0
  224. package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
  225. package/src/memory/migrations/run-migrations.ts +90 -6
  226. package/src/memory/migrations/schema-introspection.ts +14 -0
  227. package/src/memory/migrations/validate-migration-state.ts +101 -66
  228. package/src/memory/prompt-override.ts +129 -0
  229. package/src/memory/schema/conversations.ts +9 -0
  230. package/src/memory/schema/infrastructure.ts +20 -0
  231. package/src/memory/steps.ts +573 -0
  232. package/src/memory/v2/__tests__/cli-command-store.test.ts +25 -0
  233. package/src/memory/v2/__tests__/skill-store.test.ts +80 -0
  234. package/src/memory/v2/cli-command-store.ts +75 -38
  235. package/src/memory/v2/prompts/consolidation.ts +13 -82
  236. package/src/memory/v2/prompts/router.ts +21 -93
  237. package/src/memory/v2/skill-store.ts +68 -31
  238. package/src/memory/watchdog-events-store.ts +87 -0
  239. package/src/memory/worker-control.ts +118 -0
  240. package/src/memory/worker-process.ts +72 -0
  241. package/src/notifications/__tests__/broadcaster.test.ts +16 -8
  242. package/src/notifications/__tests__/connected-channels.test.ts +114 -0
  243. package/src/notifications/__tests__/decision-engine.test.ts +78 -9
  244. package/src/notifications/__tests__/destination-resolver.test.ts +256 -0
  245. package/src/notifications/broadcaster.ts +8 -1
  246. package/src/notifications/decision-engine.ts +15 -7
  247. package/src/notifications/destination-resolver.ts +68 -24
  248. package/src/notifications/emit-signal.ts +39 -14
  249. package/src/onboarding/checkin-event.test.ts +220 -0
  250. package/src/onboarding/checkin-event.ts +321 -0
  251. package/src/onboarding/schedule-checkin.ts +190 -0
  252. package/src/permissions/question-prompter.test.ts +1 -1
  253. package/src/permissions/question-prompter.ts +7 -4
  254. package/src/plugin-api/index.ts +6 -6
  255. package/src/plugin-api/types.ts +3 -5
  256. package/src/plugin-api/vision-support.test.ts +28 -4
  257. package/src/plugin-api/vision-support.ts +66 -31
  258. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +161 -0
  259. package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +106 -0
  260. package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +60 -0
  261. package/src/plugins/defaults/advisor/consult.ts +110 -6
  262. package/src/plugins/defaults/advisor/context-pack.ts +288 -0
  263. package/src/plugins/defaults/advisor/steering.ts +14 -2
  264. package/src/plugins/defaults/advisor/tools/advisor.ts +32 -5
  265. package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +47 -7
  266. package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +10 -11
  267. package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +12 -20
  268. package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +42 -11
  269. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +11 -2
  270. package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +146 -0
  271. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +29 -1
  272. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +8 -1
  273. package/src/plugins/mtime-cache.ts +7 -2
  274. package/src/plugins/types.ts +0 -2
  275. package/src/providers/anthropic/client.ts +5 -0
  276. package/src/providers/call-site-routing.ts +4 -0
  277. package/src/providers/model-catalog.ts +16 -0
  278. package/src/providers/openai/responses-provider.ts +5 -0
  279. package/src/providers/openrouter/client.ts +5 -0
  280. package/src/providers/provider-send-message.ts +4 -0
  281. package/src/providers/ratelimit.ts +4 -0
  282. package/src/providers/retry.ts +4 -0
  283. package/src/providers/types.ts +9 -0
  284. package/src/providers/usage-tracking.ts +4 -0
  285. package/src/runtime/__tests__/channel-verification-service.test.ts +133 -0
  286. package/src/runtime/__tests__/guardian-vellum-migration.test.ts +181 -0
  287. package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +66 -0
  288. package/src/runtime/__tests__/local-principal-trust.test.ts +164 -0
  289. package/src/runtime/__tests__/trust-verdict-consumer.test.ts +335 -3
  290. package/src/runtime/access-request-helper.ts +19 -39
  291. package/src/runtime/actor-trust-resolver.ts +2 -2
  292. package/src/runtime/anchored-guardian.test.ts +156 -0
  293. package/src/runtime/anchored-guardian.ts +135 -0
  294. package/src/runtime/assistant-event-hub.ts +1 -1
  295. package/src/runtime/assistant-stream-state.ts +9 -2
  296. package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +99 -0
  297. package/src/runtime/auth/require-bound-guardian.ts +21 -11
  298. package/src/runtime/channel-verification-service.ts +56 -31
  299. package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
  300. package/src/runtime/guardian-vellum-migration.ts +66 -7
  301. package/src/runtime/invite-redemption-service.ts +50 -18
  302. package/src/runtime/local-actor-identity.ts +76 -11
  303. package/src/runtime/local-principal-trust.ts +52 -0
  304. package/src/runtime/pending-interactions.ts +11 -1
  305. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +56 -5
  306. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
  307. package/src/runtime/routes/__tests__/contact-routes.test.ts +212 -0
  308. package/src/runtime/routes/__tests__/global-search-routes.test.ts +93 -0
  309. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +215 -1
  310. package/src/runtime/routes/browser-routes.ts +1 -1
  311. package/src/runtime/routes/channel-verification-routes.ts +3 -3
  312. package/src/runtime/routes/contact-routes.ts +8 -32
  313. package/src/runtime/routes/conversation-cli-routes.ts +4 -5
  314. package/src/runtime/routes/conversation-list-routes.ts +4 -7
  315. package/src/runtime/routes/conversation-routes.ts +74 -81
  316. package/src/runtime/routes/events-routes.ts +2 -2
  317. package/src/runtime/routes/global-search-routes.ts +3 -1
  318. package/src/runtime/routes/guardian-action-routes.ts +4 -5
  319. package/src/runtime/routes/host-app-control-routes.ts +5 -4
  320. package/src/runtime/routes/host-bash-routes.ts +5 -4
  321. package/src/runtime/routes/host-browser-routes.ts +9 -11
  322. package/src/runtime/routes/host-cu-routes.ts +5 -4
  323. package/src/runtime/routes/host-file-routes.ts +5 -4
  324. package/src/runtime/routes/host-transfer-routes.ts +6 -6
  325. package/src/runtime/routes/http-adapter.ts +1 -1
  326. package/src/runtime/routes/identity-routes.ts +3 -2
  327. package/src/runtime/routes/inbound-message-handler.ts +5 -5
  328. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +97 -5
  329. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +61 -49
  330. package/src/runtime/routes/inbound-stages/background-dispatch.ts +16 -4
  331. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
  332. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +21 -8
  333. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -3
  334. package/src/runtime/routes/index.ts +2 -0
  335. package/src/runtime/routes/llm-context-normalization.ts +71 -0
  336. package/src/runtime/routes/mcp-auth-routes.ts +38 -15
  337. package/src/runtime/routes/migration-rollback-routes.ts +4 -3
  338. package/src/runtime/routes/migration-routes.ts +4 -1
  339. package/src/runtime/routes/onboarding-checkin-routes.ts +86 -0
  340. package/src/runtime/routes/subagents-routes.ts +5 -0
  341. package/src/runtime/routes/surface-action-routes.ts +51 -55
  342. package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
  343. package/src/runtime/services/conversation-serializer.ts +7 -9
  344. package/src/runtime/tool-grant-request-helper.ts +3 -3
  345. package/src/runtime/trust-verdict-consumer.ts +85 -9
  346. package/src/runtime/verification-outbound-actions.ts +18 -18
  347. package/src/signals/user-message.ts +16 -0
  348. package/src/subagent/manager.ts +9 -0
  349. package/src/telemetry/types.ts +34 -1
  350. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
  351. package/src/telemetry/usage-telemetry-reporter.ts +87 -3
  352. package/src/tools/ask-question/ask-question-tool.test.ts +29 -0
  353. package/src/tools/ask-question/ask-question-tool.ts +13 -0
  354. package/src/tools/computer-use/definitions.ts +8 -2
  355. package/src/tools/executor.ts +4 -4
  356. package/src/tools/registry.ts +18 -0
  357. package/src/tools/tool-approval-handler.ts +1 -1
  358. package/src/tools/tool-defaults.ts +9 -2
  359. package/src/tools/types.ts +17 -2
  360. package/src/tools/workspace-tools/loader.ts +348 -244
  361. package/src/util/platform.ts +5 -0
  362. package/src/util/telemetry-db-path.ts +24 -0
  363. package/src/workspace/migrations/017-seed-persona-dirs.ts +3 -34
  364. package/src/workspace/migrations/019-scope-journal-to-guardian.ts +3 -24
  365. package/src/__tests__/workspace-tools-watcher-flag.test.ts +0 -70
  366. package/src/daemon/workspace-tools-watcher.ts +0 -328
  367. package/src/memory/migrations/registry.ts +0 -573
@@ -9,10 +9,10 @@
9
9
  import { v4 as uuid } from "uuid";
10
10
  import { z } from "zod";
11
11
 
12
- import { findConversation } from "../../daemon/conversation-registry.js";
13
12
  import { clearAllConversations as clearAllActive } from "../../daemon/handlers/conversations.js";
14
13
  import { formatJson, formatMarkdown } from "../../export/formatter.js";
15
14
  import { ipcCall as ipcCallGateway } from "../../ipc/gateway-client.js";
15
+ import { isConversationProcessing } from "../../memory/conversation-crud.js";
16
16
  import {
17
17
  addMessage,
18
18
  createConversation,
@@ -53,10 +53,9 @@ function handleListCli({ body = {} }: RouteHandlerArgs) {
53
53
  id: c.id,
54
54
  title: c.title,
55
55
  updatedAt: c.updatedAt,
56
- // `isProcessing` mirrors `Conversation.isProcessing()` from the
57
- // in-memory daemon store true when the agent loop is mid-turn.
58
- // Rows not currently in memory (cold / evicted) report `false`.
59
- isProcessing: findConversation(c.id)?.isProcessing() ?? false,
56
+ // Checks in-memory flag first (hot path), falls back to the
57
+ // persisted `processing_started_at` column for cold conversations.
58
+ isProcessing: isConversationProcessing(c.id),
60
59
  })),
61
60
  };
62
61
  }
@@ -10,7 +10,6 @@
10
10
 
11
11
  import { z } from "zod";
12
12
 
13
- import { findConversation } from "../../daemon/conversation-registry.js";
14
13
  import {
15
14
  type Confidence,
16
15
  getAttentionStateByConversationIds,
@@ -18,6 +17,7 @@ import {
18
17
  recordConversationSeenSignal,
19
18
  type SignalType,
20
19
  } from "../../memory/conversation-attention-store.js";
20
+ import { isConversationProcessing } from "../../memory/conversation-crud.js";
21
21
  import {
22
22
  type ConversationRow,
23
23
  getDisplayMetaForConversations,
@@ -270,12 +270,9 @@ function handleListConversations({ queryParams = {} }: RouteHandlerArgs) {
270
270
  attentionState: attentionStates.get(conversation.id),
271
271
  displayMeta: displayMeta.get(conversation.id),
272
272
  parentCache,
273
- // Cold (evicted / never-loaded) rows aren't in the in-memory
274
- // store, so `findConversation` returns `undefined` and they
275
- // report `isProcessing: false` — by definition they aren't
276
- // mid-turn since the agent loop only runs on resident convs.
277
- isProcessing:
278
- findConversation(conversation.id)?.isProcessing() ?? false,
273
+ // Checks in-memory flag first (hot path), falls back to the
274
+ // persisted `processing_started_at` column for cold conversations.
275
+ isProcessing: isConversationProcessing(conversation.id),
279
276
  }),
280
277
  ),
281
278
  nextOffset,
@@ -50,6 +50,7 @@ import {
50
50
  getCannedFirstGreeting,
51
51
  isWakeUpGreeting,
52
52
  } from "../../daemon/first-greeting.js";
53
+ import { supersedePendingInteractionsOnEnqueue } from "../../daemon/handlers/conversations.js";
53
54
  import {
54
55
  collectAttachmentRefs,
55
56
  type HistoryAttachmentRef,
@@ -67,6 +68,7 @@ import type {
67
68
  HostProxyTransportMetadata,
68
69
  NonHostProxyTransportMetadata,
69
70
  } from "../../daemon/message-types/conversations.js";
71
+ import type { TrustContext } from "../../daemon/trust-context.js";
70
72
  import { HeartbeatService } from "../../heartbeat/heartbeat-service.js";
71
73
  import {
72
74
  writeOnboardingSidecar,
@@ -120,30 +122,27 @@ import {
120
122
  } from "../../util/platform.js";
121
123
  import { silentlyWithLog } from "../../util/silently.js";
122
124
  import { assistantEventHub, broadcastMessage } from "../assistant-event-hub.js";
123
- import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
124
125
  import { getPersistedSeq } from "../assistant-stream-state.js";
125
126
  import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
126
127
  import {
127
128
  type GuardianPendingScope,
128
129
  routeGuardianReply,
129
130
  } from "../guardian-reply-router.js";
130
- import { healGuardianBindingDrift } from "../guardian-vellum-migration.js";
131
+ import { reResolveTrustOnResetDrift } from "../guardian-vellum-migration.js";
131
132
  import type {
132
133
  ApprovalConversationGenerator,
133
134
  RuntimeAttachmentMetadata,
134
135
  RuntimeMessagePayload,
135
136
  SendMessageDeps,
136
137
  } from "../http-types.js";
137
- import { resolveLocalTrustContext } from "../local-actor-identity.js";
138
+ import { findLocalGuardianPrincipalId } from "../local-actor-identity.js";
139
+ import { resolveLocalPrincipalTrustContext } from "../local-principal-trust.js";
138
140
  import * as pendingInteractions from "../pending-interactions.js";
139
141
  import {
140
142
  publishConversationListAndMetadataChanged,
141
143
  publishConversationMessagesChanged,
142
144
  } from "../sync/resource-sync-events.js";
143
- import {
144
- resolveTrustContext,
145
- withSourceChannel,
146
- } from "../trust-context-resolver.js";
145
+ import { withSourceChannel } from "../trust-context-resolver.js";
147
146
  import {
148
147
  BadRequestError,
149
148
  InternalError,
@@ -946,25 +945,28 @@ export function handleListMessages({
946
945
  .filter((block) => block.type !== "text" || block.text.length > 0);
947
946
  }
948
947
 
949
- // Ensure every hydrated attachment has a corresponding content block.
950
- // renderHistoryContent inlines attachment blocks only when it has
951
- // file-block refs with matching DB rows; directives (assistant-authored
952
- // <vellum-attachment/> tags) don't leave a file block after stripping,
953
- // so their attachments end up in the flat `attachments` array but not in
954
- // `contentBlocks`. Append any that are missing so the canonical
955
- // projection is complete.
956
- const existingAttachmentIds = new Set(
957
- contentBlocks
958
- .filter((b): b is Extract<ConversationContentBlock, { type: "attachment" }> => b.type === "attachment")
959
- .map((b) => b.attachment.id),
960
- );
961
- for (const att of msgAttachments) {
962
- if (!existingAttachmentIds.has(att.id)) {
963
- contentBlocks.push({ type: "attachment", attachment: att });
948
+ // Ensure every hydrated attachment has a corresponding content block.
949
+ // renderHistoryContent inlines attachment blocks only when it has
950
+ // file-block refs with matching DB rows; directives (assistant-authored
951
+ // <vellum-attachment/> tags) don't leave a file block after stripping,
952
+ // so their attachments end up in the flat `attachments` array but not in
953
+ // `contentBlocks`. Append any that are missing so the canonical
954
+ // projection is complete.
955
+ const existingAttachmentIds = new Set(
956
+ contentBlocks
957
+ .filter(
958
+ (b): b is Extract<ConversationContentBlock, { type: "attachment" }> =>
959
+ b.type === "attachment",
960
+ )
961
+ .map((b) => b.attachment.id),
962
+ );
963
+ for (const att of msgAttachments) {
964
+ if (!existingAttachmentIds.has(att.id)) {
965
+ contentBlocks.push({ type: "attachment", attachment: att });
966
+ }
964
967
  }
965
- }
966
968
 
967
- const alignedContentOrder = aligned.rewriteContentOrder(contentOrder);
969
+ const alignedContentOrder = aligned.rewriteContentOrder(contentOrder);
968
970
 
969
971
  // Use sentAt (actual event time) for the display timestamp when available,
970
972
  // falling back to createdAt (persistence time). Clients use this display
@@ -1440,56 +1442,65 @@ export async function handleSendMessage(
1440
1442
  conversation.setOnboardingContext(body.onboarding!);
1441
1443
  }
1442
1444
 
1443
- // Resolve guardian context from the AuthContext's actorPrincipalId.
1444
- // The JWT-verified principal is used as the sender identity through
1445
- // the same trust resolution pipeline that channel ingress uses.
1445
+ // Resolve guardian context from the AuthContext's actorPrincipalId via the
1446
+ // gateway guardian binding: a vellum principal is the guardian or nobody.
1446
1447
  if (actorPrincipalId) {
1447
1448
  // Dev bypass (HTTP auth disabled): the synthetic "dev-bypass" principal
1448
- // won't match any guardian binding. Resolve from the local guardian
1449
- // binding instead, which produces the correct guardian trust context.
1449
+ // won't match any guardian binding. Resolve the real guardian principal and
1450
+ // map that through, failing closed to unknown on an empty gateway.
1450
1451
  if (isHttpAuthDisabled() && actorPrincipalId === "dev-bypass") {
1451
- conversation.setTrustContext(resolveLocalTrustContext(sourceChannel));
1452
+ const guardianPrincipalId = await findLocalGuardianPrincipalId();
1453
+ let trustCtx: TrustContext = guardianPrincipalId
1454
+ ? withSourceChannel(
1455
+ sourceChannel,
1456
+ await resolveLocalPrincipalTrustContext({
1457
+ actorPrincipalId: guardianPrincipalId,
1458
+ sourceChannel: "vellum",
1459
+ conversationExternalId: "local",
1460
+ }),
1461
+ )
1462
+ : { trustClass: "unknown", sourceChannel };
1463
+ if (guardianPrincipalId && trustCtx.trustClass === "unknown") {
1464
+ const healed = await reResolveTrustOnResetDrift(
1465
+ guardianPrincipalId,
1466
+ sourceChannel,
1467
+ );
1468
+ if (healed) trustCtx = healed;
1469
+ }
1470
+ conversation.setTrustContext(trustCtx);
1452
1471
  } else {
1453
- const assistantId = DAEMON_INTERNAL_ASSISTANT_ID;
1454
- let trustCtx = resolveTrustContext({
1455
- assistantId,
1456
- sourceChannel: "vellum",
1457
- conversationExternalId: "local",
1458
- actorExternalId: actorPrincipalId,
1459
- });
1472
+ let trustCtx = withSourceChannel(
1473
+ sourceChannel,
1474
+ await resolveLocalPrincipalTrustContext({
1475
+ actorPrincipalId,
1476
+ sourceChannel: "vellum",
1477
+ conversationExternalId: "local",
1478
+ }),
1479
+ );
1460
1480
  if (trustCtx.trustClass === "unknown") {
1461
- // Attempt to heal guardian binding drift: after a DB reset the
1462
- // guardian binding gets a new vellum-principal-* UUID while the
1463
- // client still holds a valid JWT with the old one. The signing
1464
- // key survives the reset, so the JWT is authentic — just stale.
1465
- const healed = healGuardianBindingDrift(actorPrincipalId);
1466
- if (healed) {
1467
- trustCtx = resolveTrustContext({
1468
- assistantId,
1469
- sourceChannel: "vellum",
1470
- conversationExternalId: "local",
1471
- actorExternalId: actorPrincipalId,
1472
- });
1481
+ const healed = await reResolveTrustOnResetDrift(
1482
+ actorPrincipalId,
1483
+ sourceChannel,
1484
+ );
1485
+ if (healed && healed.trustClass !== "unknown") {
1486
+ trustCtx = healed;
1473
1487
  log.info(
1474
- {
1475
- actorPrincipalId: actorPrincipalId,
1476
- trustClass: trustCtx.trustClass,
1477
- },
1478
- "Trust re-resolved after guardian binding drift heal",
1488
+ { actorPrincipalId, trustClass: trustCtx.trustClass },
1489
+ "Trust re-resolved from local mirror after gateway returned unknown",
1479
1490
  );
1480
1491
  } else {
1481
1492
  log.warn(
1482
1493
  {
1483
- actorPrincipalId: actorPrincipalId,
1494
+ actorPrincipalId,
1484
1495
  sourceChannel,
1485
- trustClass: trustCtx.trustClass,
1486
- principalType: principalType,
1496
+ trustClass: "unknown",
1497
+ principalType,
1487
1498
  },
1488
1499
  "JWT-verified actor resolved to unknown trust class — possible guardian binding drift (e.g. DB reset without re-bootstrap)",
1489
1500
  );
1490
1501
  }
1491
1502
  }
1492
- conversation.setTrustContext(withSourceChannel(sourceChannel, trustCtx));
1503
+ conversation.setTrustContext(trustCtx);
1493
1504
  }
1494
1505
  } else {
1495
1506
  // Service principals (svc_gateway) or tokens without an actor ID
@@ -1814,29 +1825,11 @@ export async function handleSendMessage(
1814
1825
  // the client showing "Failed to send" for a message the daemon will
1815
1826
  // process from the queue.
1816
1827
  try {
1817
- if (conversation.hasAnyPendingConfirmation()) {
1818
- // Emit authoritative denial state for each pending request.
1819
- // sendToClient (wired to the SSE hub) delivers these to the client.
1820
- for (const interaction of pendingInteractions.getByConversation(
1821
- mapping.conversationId,
1822
- )) {
1823
- if (interaction.kind === "confirmation") {
1824
- conversation.emitConfirmationStateChanged({
1825
- conversationId: mapping.conversationId,
1826
- requestId: interaction.requestId,
1827
- state: "denied" as const,
1828
- source: "auto_deny" as const,
1829
- });
1830
- // Sync canonical guardian request status so stale "pending" DB
1831
- // records don't get matched by later guardian reply routing.
1832
- resolveCanonicalGuardianRequest(interaction.requestId, "pending", {
1833
- status: "denied",
1834
- });
1835
- }
1836
- }
1837
- conversation.denyAllPendingConfirmations();
1838
- pendingInteractions.removeByConversation(mapping.conversationId);
1839
- }
1828
+ // Supersede interactions left pending by the in-flight turn: auto-deny
1829
+ // confirmations (with canonical/client sync) and steer to the enqueued
1830
+ // message if an ask_question is parked. Centralized so the CLI signal
1831
+ // path (signals/user-message.ts) gets identical handling.
1832
+ supersedePendingInteractionsOnEnqueue(mapping.conversationId, requestId);
1840
1833
 
1841
1834
  // Expire any orphaned canonical requests that survived without a
1842
1835
  // matching in-memory pending interaction (e.g. prompter timeouts).
@@ -43,7 +43,7 @@ import type { ReplaySubscriber } from "../assistant-stream-state.js";
43
43
  import { getReplayWindow } from "../assistant-stream-state.js";
44
44
  import { ACTOR_PRINCIPALS, GATEWAY_PRINCIPALS } from "../auth/route-policy.js";
45
45
  import { DEFAULT_HEARTBEAT_INTERVAL_MS } from "../client-health.js";
46
- import { resolveActorPrincipalIdForLocalGuardian } from "../local-actor-identity.js";
46
+ import { resolveActorPrincipalIdForLocalGuardianSync } from "../local-actor-identity.js";
47
47
  import {
48
48
  BadRequestError,
49
49
  NotFoundError,
@@ -311,7 +311,7 @@ export function handleSubscribeAssistantEvents(
311
311
  // bearer token's AuthContext. May be absent for legacy / service-token
312
312
  // connections that have no principal. See `resolveActorPrincipalId` for the
313
313
  // dev-bypass translation rationale.
314
- const actorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
314
+ const actorPrincipalId = resolveActorPrincipalIdForLocalGuardianSync(
315
315
  rawActorPrincipalId?.trim() || undefined,
316
316
  );
317
317
 
@@ -263,7 +263,9 @@ async function handleGlobalSearch({
263
263
  id: c.id,
264
264
  displayName: c.displayName,
265
265
  notes: c.notes,
266
- lastInteraction: c.lastInteraction,
266
+ // Daemon-native search has no gateway-relayed read; recency orders on
267
+ // contacts.updatedAt, not the channel-derived lastInteraction column.
268
+ lastInteraction: c.updatedAt,
267
269
  }));
268
270
  }
269
271
 
@@ -14,7 +14,6 @@
14
14
  import { z } from "zod";
15
15
 
16
16
  import { isHttpAuthDisabled } from "../../config/env.js";
17
- import { findGuardianForChannel } from "../../contacts/contact-store.js";
18
17
  import {
19
18
  type CanonicalGuardianRequest,
20
19
  listPendingRequestsByConversationScope,
@@ -23,6 +22,7 @@ import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
23
22
  import { processGuardianDecision } from "../guardian-action-service.js";
24
23
  import type { GuardianDecisionPrompt } from "../guardian-decision-types.js";
25
24
  import { buildOneTimeDecisionActions } from "../guardian-decision-types.js";
25
+ import { findLocalGuardianPrincipalId } from "../local-actor-identity.js";
26
26
  import { BadRequestError, NotFoundError } from "./errors.js";
27
27
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
28
28
 
@@ -73,16 +73,15 @@ async function handleGuardianActionDecision({
73
73
  // Resolve the actor's guardian principal ID. The HTTP adapter injects it
74
74
  // from the AuthContext via the x-vellum-actor-principal-id header.
75
75
  // For dev bypass (HTTP auth disabled) the synthetic "dev-bypass" principal
76
- // won't match the real guardian binding, so fall back to the local guardian
77
- // binding to avoid identity_mismatch.
76
+ // won't match the real guardian binding, so resolve the local guardian
77
+ // principal to avoid identity_mismatch.
78
78
  let guardianPrincipalId: string | undefined =
79
79
  headers["x-vellum-actor-principal-id"] ?? undefined;
80
80
  if (
81
81
  isHttpAuthDisabled() &&
82
82
  headers["x-vellum-actor-principal-id"] === "dev-bypass"
83
83
  ) {
84
- const binding = findGuardianForChannel("vellum");
85
- guardianPrincipalId = binding?.contact.principalId ?? undefined;
84
+ guardianPrincipalId = (await findLocalGuardianPrincipalId()) ?? undefined;
86
85
  }
87
86
 
88
87
  const result = await processGuardianDecision({
@@ -39,7 +39,7 @@ const VALID_STATES: ReadonlySet<HostAppControlState> = new Set([
39
39
  // POST /v1/host-app-control-result
40
40
  // ---------------------------------------------------------------------------
41
41
 
42
- function handleHostAppControlResult({ body, headers }: RouteHandlerArgs) {
42
+ async function handleHostAppControlResult({ body, headers }: RouteHandlerArgs) {
43
43
  if (!body || typeof body !== "object") {
44
44
  throw new BadRequestError("Request body is required");
45
45
  }
@@ -95,9 +95,10 @@ function handleHostAppControlResult({ body, headers }: RouteHandlerArgs) {
95
95
  `Client "${submittingClientId}" is not the target for this request (expected "${peeked.targetClientId}"). The targeted client must submit the result.`,
96
96
  );
97
97
  }
98
- const submittingActorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
99
- headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
100
- );
98
+ const submittingActorPrincipalId =
99
+ await resolveActorPrincipalIdForLocalGuardian(
100
+ headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
101
+ );
101
102
  enforceSameActorOrThrow({
102
103
  sourceActorPrincipalId: submittingActorPrincipalId,
103
104
  targetActorPrincipalId: peeked.targetActorPrincipalId,
@@ -26,7 +26,7 @@ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
26
26
  // POST /v1/host-bash-result
27
27
  // ---------------------------------------------------------------------------
28
28
 
29
- function handleHostBashResult({ body, headers }: RouteHandlerArgs) {
29
+ async function handleHostBashResult({ body, headers }: RouteHandlerArgs) {
30
30
  if (!body || typeof body !== "object") {
31
31
  throw new BadRequestError("Request body is required");
32
32
  }
@@ -45,9 +45,10 @@ function handleHostBashResult({ body, headers }: RouteHandlerArgs) {
45
45
 
46
46
  const submittingClientId =
47
47
  headers?.["x-vellum-client-id"]?.trim() || undefined;
48
- const submittingActorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
49
- headers?.["x-vellum-actor-principal-id"]?.trim() || undefined,
50
- );
48
+ const submittingActorPrincipalId =
49
+ await resolveActorPrincipalIdForLocalGuardian(
50
+ headers?.["x-vellum-actor-principal-id"]?.trim() || undefined,
51
+ );
51
52
 
52
53
  const peeked = pendingInteractions.get(requestId);
53
54
  if (!peeked) {
@@ -61,14 +61,14 @@ export type HostBrowserResultResolution =
61
61
  * already authenticated the caller (the HTTP route uses
62
62
  * `requireBoundGuardian`).
63
63
  */
64
- export function resolveHostBrowserResultByRequestId(
64
+ export async function resolveHostBrowserResultByRequestId(
65
65
  frame: {
66
66
  requestId?: unknown;
67
67
  content?: unknown;
68
68
  isError?: unknown;
69
69
  },
70
70
  headers?: Record<string, string | undefined>,
71
- ): HostBrowserResultResolution {
71
+ ): Promise<HostBrowserResultResolution> {
72
72
  const { requestId, content, isError } = frame;
73
73
 
74
74
  if (!requestId || typeof requestId !== "string") {
@@ -127,9 +127,10 @@ export function resolveHostBrowserResultByRequestId(
127
127
  // stream. This prevents a different authenticated user with knowledge of
128
128
  // both the requestId and target clientId from submitting a result on
129
129
  // behalf of the targeted client.
130
- const submittingActorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
131
- headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
132
- );
130
+ const submittingActorPrincipalId =
131
+ await resolveActorPrincipalIdForLocalGuardian(
132
+ headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
133
+ );
133
134
  try {
134
135
  enforceSameActorOrThrow({
135
136
  sourceActorPrincipalId: submittingActorPrincipalId,
@@ -260,12 +261,12 @@ export function resolveHostBrowserSessionInvalidated(frame: {
260
261
  // POST /v1/host-browser-result
261
262
  // ---------------------------------------------------------------------------
262
263
 
263
- function handleHostBrowserResult({ body, headers }: RouteHandlerArgs) {
264
+ async function handleHostBrowserResult({ body, headers }: RouteHandlerArgs) {
264
265
  if (!body || typeof body !== "object") {
265
266
  throw new BadRequestError("Request body is required");
266
267
  }
267
268
 
268
- const resolution = resolveHostBrowserResultByRequestId(
269
+ const resolution = await resolveHostBrowserResultByRequestId(
269
270
  body,
270
271
  headers as Record<string, string | undefined> | undefined,
271
272
  );
@@ -399,10 +400,7 @@ export const ROUTES: RouteDefinition[] = [
399
400
  "Marks the target as invalidated in the runtime-side browser session registry.",
400
401
  tags: ["host"],
401
402
  requestBody: z.object({
402
- targetId: z
403
- .string()
404
- .optional()
405
- .describe("CDP target that was detached"),
403
+ targetId: z.string().optional().describe("CDP target that was detached"),
406
404
  reason: z.string().optional().describe("Detach reason"),
407
405
  clientId: z
408
406
  .string()
@@ -26,7 +26,7 @@ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
26
26
  // POST /v1/host-cu-result
27
27
  // ---------------------------------------------------------------------------
28
28
 
29
- function handleHostCuResult({ body, headers }: RouteHandlerArgs) {
29
+ async function handleHostCuResult({ body, headers }: RouteHandlerArgs) {
30
30
  if (!body || typeof body !== "object") {
31
31
  throw new BadRequestError("Request body is required");
32
32
  }
@@ -95,9 +95,10 @@ function handleHostCuResult({ body, headers }: RouteHandlerArgs) {
95
95
  // stream. This prevents a different authenticated user with knowledge of
96
96
  // both the requestId and target clientId from submitting a result on
97
97
  // behalf of the targeted client.
98
- const submittingActorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
99
- headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
100
- );
98
+ const submittingActorPrincipalId =
99
+ await resolveActorPrincipalIdForLocalGuardian(
100
+ headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
101
+ );
101
102
  enforceSameActorOrThrow({
102
103
  sourceActorPrincipalId: submittingActorPrincipalId,
103
104
  targetActorPrincipalId: peeked.targetActorPrincipalId,
@@ -26,7 +26,7 @@ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
26
26
  // POST /v1/host-file-result
27
27
  // ---------------------------------------------------------------------------
28
28
 
29
- function handleHostFileResult({ body, headers }: RouteHandlerArgs) {
29
+ async function handleHostFileResult({ body, headers }: RouteHandlerArgs) {
30
30
  if (!body || typeof body !== "object") {
31
31
  throw new BadRequestError("Request body is required");
32
32
  }
@@ -76,9 +76,10 @@ function handleHostFileResult({ body, headers }: RouteHandlerArgs) {
76
76
  // match the actor that opened the target client's SSE stream. This blocks
77
77
  // cross-user submissions even if a different user somehow obtains the
78
78
  // target client id.
79
- const submittingActorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
80
- headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
81
- );
79
+ const submittingActorPrincipalId =
80
+ await resolveActorPrincipalIdForLocalGuardian(
81
+ headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
82
+ );
82
83
  enforceSameActorOrThrow({
83
84
  sourceActorPrincipalId: submittingActorPrincipalId,
84
85
  targetActorPrincipalId: peeked.targetActorPrincipalId,
@@ -39,10 +39,10 @@ function findProxyByTransferId(transferId: string) {
39
39
  // GET /v1/transfers/:transferId/content
40
40
  // ---------------------------------------------------------------------------
41
41
 
42
- function handleTransferContentGet({
42
+ async function handleTransferContentGet({
43
43
  pathParams = {},
44
44
  headers = {},
45
- }: RouteHandlerArgs): Uint8Array {
45
+ }: RouteHandlerArgs): Promise<Uint8Array> {
46
46
  const transferId = pathParams.transferId;
47
47
  if (!transferId) {
48
48
  throw new BadRequestError("transferId path parameter is required");
@@ -72,7 +72,7 @@ function handleTransferContentGet({
72
72
  // the value persisted at registration time so a brief reconnect does
73
73
  // not 403 a legitimate fetch.
74
74
  enforceSameActorOrThrow({
75
- sourceActorPrincipalId: resolveActorPrincipalIdForLocalGuardian(
75
+ sourceActorPrincipalId: await resolveActorPrincipalIdForLocalGuardian(
76
76
  headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
77
77
  ),
78
78
  targetActorPrincipalId:
@@ -151,7 +151,7 @@ async function handleTransferContentPut({
151
151
  );
152
152
 
153
153
  enforceSameActorOrThrow({
154
- sourceActorPrincipalId: resolveActorPrincipalIdForLocalGuardian(
154
+ sourceActorPrincipalId: await resolveActorPrincipalIdForLocalGuardian(
155
155
  headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
156
156
  ),
157
157
  targetActorPrincipalId:
@@ -181,7 +181,7 @@ async function handleTransferContentPut({
181
181
  // POST /v1/host-transfer-result
182
182
  // ---------------------------------------------------------------------------
183
183
 
184
- function handleTransferResult({ body, headers }: RouteHandlerArgs) {
184
+ async function handleTransferResult({ body, headers }: RouteHandlerArgs) {
185
185
  if (!body || typeof body !== "object") {
186
186
  throw new BadRequestError("Request body is required");
187
187
  }
@@ -222,7 +222,7 @@ function handleTransferResult({ body, headers }: RouteHandlerArgs) {
222
222
  );
223
223
 
224
224
  enforceSameActorOrThrow({
225
- sourceActorPrincipalId: resolveActorPrincipalIdForLocalGuardian(
225
+ sourceActorPrincipalId: await resolveActorPrincipalIdForLocalGuardian(
226
226
  headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
227
227
  ),
228
228
  targetActorPrincipalId: peeked.targetActorPrincipalId,
@@ -51,7 +51,7 @@ export function routeDefinitionsToHTTPRoutes(
51
51
  handler: async ({ req, url, params, authContext }) => {
52
52
  try {
53
53
  if (r.requireGuardian) {
54
- const guardianError = requireBoundGuardian(authContext);
54
+ const guardianError = await requireBoundGuardian(authContext);
55
55
  if (guardianError) return guardianError;
56
56
  }
57
57
 
@@ -10,7 +10,8 @@ import { z } from "zod";
10
10
  import { getCpuLimit, getIsPlatform } from "../../config/env-registry.js";
11
11
  import { parseIdentityFields } from "../../daemon/handlers/identity.js";
12
12
  import { getProfilerRuntimeStatus } from "../../daemon/profiler-run-store.js";
13
- import { getMaxMigrationVersion } from "../../memory/migrations/registry.js";
13
+ import { getMaxRollbackVersion } from "../../memory/migrations/run-migrations.js";
14
+ import { migrationSteps } from "../../memory/steps.js";
14
15
  import { getCesClient } from "../../security/secure-keys.js";
15
16
  import {
16
17
  getDiskUsageInfo,
@@ -335,7 +336,7 @@ function getDetailedHealth() {
335
336
  memory: getMemoryInfo(),
336
337
  cpu: getCpuInfo(),
337
338
  migrations: {
338
- dbVersion: getMaxMigrationVersion(),
339
+ dbVersion: getMaxRollbackVersion(migrationSteps),
339
340
  lastWorkspaceMigrationId:
340
341
  getLastWorkspaceMigrationId(WORKSPACE_MIGRATIONS),
341
342
  },
@@ -680,7 +680,7 @@ export async function handleChannelInbound({
680
680
  canonicalAssistantId,
681
681
  assistantId,
682
682
  content,
683
- channelId: resolvedMember?.channel.id,
683
+ channelId: resolvedMember?.channelId,
684
684
  });
685
685
  }
686
686
 
@@ -761,7 +761,7 @@ export async function handleChannelInbound({
761
761
  : enforceAdmissionPolicy({
762
762
  sourceChannel,
763
763
  trustClass: trustCtx.trustClass,
764
- memberStatus: resolvedMember?.channel.status,
764
+ memberStatus: resolvedMember?.status,
765
765
  policy: admissionPolicyFromGateway,
766
766
  });
767
767
  if (!admissionResult.admitted) {
@@ -801,7 +801,7 @@ export async function handleChannelInbound({
801
801
  // guardian sees "previously pending" etc.
802
802
  let guardianNotified = false;
803
803
  try {
804
- const accessResult = notifyGuardianOfAccessRequest({
804
+ const accessResult = await notifyGuardianOfAccessRequest({
805
805
  canonicalAssistantId,
806
806
  sourceChannel,
807
807
  conversationExternalId,
@@ -811,7 +811,7 @@ export async function handleChannelInbound({
811
811
  ...(resolvedMember
812
812
  ? {
813
813
  previousMemberStatus: channelStatusToMemberStatus(
814
- resolvedMember.channel.status,
814
+ resolvedMember.status,
815
815
  ),
816
816
  }
817
817
  : {}),
@@ -935,7 +935,7 @@ export async function handleChannelInbound({
935
935
  }
936
936
 
937
937
  // ── Ingress escalation ──
938
- const escalationResponse = handleEscalationIntercept({
938
+ const escalationResponse = await handleEscalationIntercept({
939
939
  resolvedMember,
940
940
  canonicalAssistantId,
941
941
  sourceChannel,