@vellumai/assistant 0.10.2 → 0.10.3-dev.202606252046.9075fd5

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 (546) hide show
  1. package/bun.lock +20 -0
  2. package/docs/workspace-tools.md +42 -33
  3. package/eslint-rules/cli-no-daemon-internals.js +6 -0
  4. package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +91 -0
  5. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +31 -0
  6. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +44 -0
  7. package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +48 -0
  8. package/node_modules/@vellumai/gateway-client/src/index.ts +14 -0
  9. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +17 -0
  10. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  11. package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +28 -0
  12. package/node_modules/@vellumai/service-contracts/src/channels.ts +41 -0
  13. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  14. package/openapi.yaml +196 -56
  15. package/package.json +4 -1
  16. package/scripts/test.sh +36 -15
  17. package/src/__tests__/actor-token-service.test.ts +36 -14
  18. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +83 -31
  19. package/src/__tests__/agent-loop-override-profile.test.ts +1 -0
  20. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
  21. package/src/__tests__/agent-wake-override-profile.test.ts +2 -0
  22. package/src/__tests__/annotate-activity-metadata.test.ts +2 -0
  23. package/src/__tests__/annotate-risk-options.test.ts +2 -0
  24. package/src/__tests__/approval-cascade.test.ts +2 -0
  25. package/src/__tests__/assistant-attachments.test.ts +42 -0
  26. package/src/__tests__/background-workers-disk-pressure.test.ts +2 -0
  27. package/src/__tests__/btw-routes.test.ts +2 -0
  28. package/src/__tests__/build-persisted-content.test.ts +2 -0
  29. package/src/__tests__/call-controller.test.ts +19 -0
  30. package/src/__tests__/channel-approval-routes.test.ts +21 -26
  31. package/src/__tests__/channel-delivery-store.test.ts +28 -0
  32. package/src/__tests__/channel-guardian.test.ts +164 -78
  33. package/src/__tests__/channel-inbound-disk-pressure.test.ts +11 -19
  34. package/src/__tests__/channel-reply-delivery.test.ts +2 -0
  35. package/src/__tests__/code-search-tool.test.ts +585 -0
  36. package/src/__tests__/compaction-events.test.ts +2 -0
  37. package/src/__tests__/compaction-ledger-store.test.ts +128 -0
  38. package/src/__tests__/compaction.benchmark.test.ts +2 -0
  39. package/src/__tests__/compactor-call-site-logging.test.ts +2 -0
  40. package/src/__tests__/compactor-low-watermark-cut.test.ts +2 -0
  41. package/src/__tests__/compactor-preserved-tail-count.test.ts +2 -0
  42. package/src/__tests__/compactor-summary-call-truncation.test.ts +2 -0
  43. package/src/__tests__/compactor-web-search-strip.test.ts +2 -0
  44. package/src/__tests__/config-loader-backfill.test.ts +123 -10
  45. package/src/__tests__/config-schema.test.ts +1 -0
  46. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +31 -29
  47. package/src/__tests__/consult-deadline.test.ts +60 -0
  48. package/src/__tests__/contact-store-interaction-info.test.ts +156 -0
  49. package/src/__tests__/contact-store-user-file.test.ts +7 -10
  50. package/src/__tests__/contacts-relay-reads.test.ts +19 -24
  51. package/src/__tests__/contacts-write.test.ts +0 -2
  52. package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
  53. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +2 -0
  54. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  55. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
  56. package/src/__tests__/conversation-agent-loop.test.ts +134 -0
  57. package/src/__tests__/conversation-analysis-routes.test.ts +2 -0
  58. package/src/__tests__/conversation-app-control-lifecycle.test.ts +2 -0
  59. package/src/__tests__/conversation-attention-telegram.test.ts +9 -11
  60. package/src/__tests__/conversation-confirmation-signals.test.ts +2 -0
  61. package/src/__tests__/conversation-fork-crud.test.ts +354 -24
  62. package/src/__tests__/conversation-history-web-search.test.ts +2 -0
  63. package/src/__tests__/conversation-load-history-repair.test.ts +2 -0
  64. package/src/__tests__/conversation-load-history-stripped.test.ts +2 -0
  65. package/src/__tests__/conversation-pairing.test.ts +2 -0
  66. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
  67. package/src/__tests__/conversation-process-callsite.test.ts +2 -0
  68. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
  69. package/src/__tests__/conversation-queue.test.ts +91 -0
  70. package/src/__tests__/conversation-routes-guardian-reply.test.ts +14 -0
  71. package/src/__tests__/conversation-routes-slash-commands.test.ts +14 -0
  72. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  73. package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
  74. package/src/__tests__/conversation-speed-override.test.ts +2 -0
  75. package/src/__tests__/conversation-surfaces-task-progress.test.ts +29 -0
  76. package/src/__tests__/conversation-title-service.test.ts +2 -0
  77. package/src/__tests__/conversation-tool-setup-attribution.test.ts +47 -0
  78. package/src/__tests__/conversation-usage.test.ts +2 -0
  79. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -0
  80. package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
  81. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
  82. package/src/__tests__/credential-security-invariants.test.ts +1 -1
  83. package/src/__tests__/db-compaction-events-migration.test.ts +129 -0
  84. package/src/__tests__/db-migration-rollback.test.ts +205 -171
  85. package/src/__tests__/db-test-helpers.ts +5 -4
  86. package/src/__tests__/delete-propagation.test.ts +5 -3
  87. package/src/__tests__/deterministic-verification-control-plane.test.ts +4 -2
  88. package/src/__tests__/disk-pressure-guard.test.ts +41 -0
  89. package/src/__tests__/dm-backfill.test.ts +6 -4
  90. package/src/__tests__/dm-persistence.test.ts +2 -0
  91. package/src/__tests__/emit-signal-routing-intent.test.ts +7 -6
  92. package/src/__tests__/events-dev-bypass-actor.test.ts +7 -1
  93. package/src/__tests__/exploration-drift-hook.test.ts +3 -2
  94. package/src/__tests__/filing-service.test.ts +2 -0
  95. package/src/__tests__/guardian-binding-drift-heal.test.ts +104 -19
  96. package/src/__tests__/guardian-dispatch.test.ts +140 -1
  97. package/src/__tests__/guardian-expiry-notifier.test.ts +282 -0
  98. package/src/__tests__/guardian-outbound-http.test.ts +13 -0
  99. package/src/__tests__/guardian-routing-state.test.ts +6 -10
  100. package/src/__tests__/heartbeat-disk-pressure.test.ts +2 -0
  101. package/src/__tests__/heartbeat-service.test.ts +2 -0
  102. package/src/__tests__/helpers/channel-test-adapter.ts +46 -19
  103. package/src/__tests__/helpers/create-guardian-binding.ts +15 -23
  104. package/src/__tests__/helpers/mock-logger.ts +1 -0
  105. package/src/__tests__/helpers/seed-contact-channel.ts +96 -0
  106. package/src/__tests__/host-app-control-routes.test.ts +24 -30
  107. package/src/__tests__/host-bash-routes.test.ts +31 -41
  108. package/src/__tests__/host-browser-routes.test.ts +26 -32
  109. package/src/__tests__/host-cu-routes-targeted.test.ts +25 -33
  110. package/src/__tests__/host-file-routes-targeted.test.ts +40 -52
  111. package/src/__tests__/host-transfer-routes-targeted.test.ts +31 -43
  112. package/src/__tests__/http-user-message-parity.test.ts +290 -8
  113. package/src/__tests__/inbound-invite-redemption.test.ts +115 -10
  114. package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
  115. package/src/__tests__/invite-redemption-service.test.ts +471 -53
  116. package/src/__tests__/invite-routes-http.test.ts +34 -0
  117. package/src/__tests__/invite-service-ipc.test.ts +65 -2
  118. package/src/__tests__/llm-context-normalization.test.ts +105 -0
  119. package/src/__tests__/llm-request-log-error-payload.test.ts +71 -9
  120. package/src/__tests__/llm-usage-store.test.ts +25 -0
  121. package/src/__tests__/mcp-config-secret-boundary.test.ts +392 -0
  122. package/src/__tests__/mcp-health-check.test.ts +2 -1
  123. package/src/__tests__/media-stream-server-integration.test.ts +127 -0
  124. package/src/__tests__/memory-retrieval-hook.test.ts +2 -0
  125. package/src/__tests__/messaging-send-tool.test.ts +2 -0
  126. package/src/__tests__/migration-import-from-url.test.ts +2 -2
  127. package/src/__tests__/mtime-cache.test.ts +275 -5
  128. package/src/__tests__/native-web-search.test.ts +2 -0
  129. package/src/__tests__/non-member-access-request.test.ts +191 -17
  130. package/src/__tests__/notification-broadcaster.test.ts +4 -0
  131. package/src/__tests__/notification-decision-recipient-context.test.ts +33 -32
  132. package/src/__tests__/notification-deep-link.test.ts +6 -0
  133. package/src/__tests__/notification-guardian-path.test.ts +19 -0
  134. package/src/__tests__/onboarding-persona-write.test.ts +52 -22
  135. package/src/__tests__/openai-provider.test.ts +22 -12
  136. package/src/__tests__/openai-responses-provider.test.ts +12 -2
  137. package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
  138. package/src/__tests__/pending-interactions-resolved-event.test.ts +7 -4
  139. package/src/__tests__/persist-onboarding-artifacts.test.ts +1 -0
  140. package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
  141. package/src/__tests__/persona-resolver.test.ts +75 -45
  142. package/src/__tests__/plugin-bootstrap.test.ts +21 -83
  143. package/src/__tests__/plugin-disabled-state.test.ts +190 -0
  144. package/src/__tests__/plugin-pipeline.test.ts +96 -0
  145. package/src/__tests__/plugin-route-contribution.test.ts +6 -19
  146. package/src/__tests__/plugin-tool-contribution.test.ts +5 -20
  147. package/src/__tests__/plugin-types.test.ts +2 -4
  148. package/src/__tests__/process-message-background-slack.test.ts +2 -0
  149. package/src/__tests__/process-message-display-content.test.ts +2 -0
  150. package/src/__tests__/provider-error-scenarios.test.ts +5 -4
  151. package/src/__tests__/provider-usage-tracking.test.ts +39 -0
  152. package/src/__tests__/reaction-intercept-cold-cache-warm.test.ts +135 -0
  153. package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +158 -0
  154. package/src/__tests__/reaction-persistence.test.ts +51 -4
  155. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +2 -0
  156. package/src/__tests__/registry.test.ts +4 -1
  157. package/src/__tests__/relay-server.test.ts +758 -32
  158. package/src/__tests__/runtime-attachment-metadata.test.ts +9 -12
  159. package/src/__tests__/secret-ingress-http.test.ts +14 -0
  160. package/src/__tests__/send-endpoint-busy.test.ts +30 -8
  161. package/src/__tests__/settings-routes.test.ts +32 -0
  162. package/src/__tests__/skills.test.ts +44 -0
  163. package/src/__tests__/slack-inbound-verification.test.ts +47 -2
  164. package/src/__tests__/sse-actor-principal-guardian-source.test.ts +79 -0
  165. package/src/__tests__/steer-on-enqueue-question.test.ts +181 -0
  166. package/src/__tests__/stt-hints.test.ts +49 -15
  167. package/src/__tests__/subagent-detail.test.ts +27 -0
  168. package/src/__tests__/subagent-disposal.test.ts +65 -0
  169. package/src/__tests__/subagent-fork-prompt-role.test.ts +195 -0
  170. package/src/__tests__/subagent-fork-spawn.test.ts +6 -7
  171. package/src/__tests__/subagent-notify-parent.test.ts +2 -0
  172. package/src/__tests__/subagent-role-registry.test.ts +24 -6
  173. package/src/__tests__/subagent-spawn-and-await.test.ts +546 -0
  174. package/src/__tests__/subagent-spawn-tool-fork.test.ts +2 -0
  175. package/src/__tests__/subagent-tools.test.ts +398 -1
  176. package/src/__tests__/suggestion-routes.test.ts +2 -0
  177. package/src/__tests__/thread-backfill.test.ts +3 -3
  178. package/src/__tests__/title-generate-hook.test.ts +2 -0
  179. package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -0
  180. package/src/__tests__/tool-executor.test.ts +16 -11
  181. package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
  182. package/src/__tests__/tool-result-metadata-plumbing.test.ts +2 -0
  183. package/src/__tests__/tool-start-timestamp.test.ts +2 -0
  184. package/src/__tests__/trusted-contact-approval-notifier.test.ts +37 -51
  185. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +12 -12
  186. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -7
  187. package/src/__tests__/trusted-contact-multichannel.test.ts +16 -7
  188. package/src/__tests__/trusted-contact-verification.test.ts +79 -54
  189. package/src/__tests__/twilio-routes.test.ts +96 -0
  190. package/src/__tests__/ui-file-upload-surface.test.ts +86 -0
  191. package/src/__tests__/verification-control-plane-policy.test.ts +2 -0
  192. package/src/__tests__/voice-guardian-cold-cache-warm.test.ts +137 -0
  193. package/src/__tests__/voice-invite-redemption.test.ts +216 -20
  194. package/src/__tests__/web-search-backend-failure.test.ts +2 -0
  195. package/src/__tests__/workspace-migration-102-preserve-heartbeat-enabled-for-existing-workspaces.test.ts +3 -3
  196. package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +208 -0
  197. package/src/__tests__/workspace-migration-112-remove-advisor-callsite-override.test.ts +170 -0
  198. package/src/__tests__/workspace-migration-drop-user-md.test.ts +196 -238
  199. package/src/__tests__/workspace-migration-remove-hooks.test.ts +14 -35
  200. package/src/__tests__/workspace-tool-loader.test.ts +195 -2
  201. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +35 -47
  202. package/src/agent/loop-exclusive-tool.test.ts +154 -0
  203. package/src/agent/loop-native-web-search.test.ts +200 -0
  204. package/src/agent/loop.ts +164 -1
  205. package/src/api/constants/sse-replay.ts +41 -0
  206. package/src/api/events/conversation-notice.ts +26 -0
  207. package/src/api/index.ts +19 -1
  208. package/src/api/responses/llm-request-log-entry.ts +29 -0
  209. package/src/api/responses/subagent-detail.ts +17 -0
  210. package/src/api/surfaces.ts +39 -3
  211. package/src/approvals/guardian-channel-delivery.ts +30 -0
  212. package/src/approvals/guardian-expiry-notifier.ts +148 -0
  213. package/src/approvals/guardian-request-resolvers.ts +17 -15
  214. package/src/calls/__tests__/relay-setup-router.test.ts +267 -17
  215. package/src/calls/call-domain.ts +3 -3
  216. package/src/calls/guardian-dispatch.ts +14 -9
  217. package/src/calls/inbound-trust-reader.ts +24 -2
  218. package/src/calls/media-stream-server.ts +21 -0
  219. package/src/calls/relay-access-wait.ts +6 -6
  220. package/src/calls/relay-server.ts +188 -51
  221. package/src/calls/relay-setup-router.ts +47 -17
  222. package/src/calls/relay-verification.ts +4 -4
  223. package/src/calls/stt-hints.ts +9 -12
  224. package/src/calls/twilio-routes.ts +14 -4
  225. package/src/channels/types.ts +10 -20
  226. package/src/cli/commands/__tests__/cache.test.ts +8 -1
  227. package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -0
  228. package/src/cli/commands/cache.ts +194 -181
  229. package/src/cli/commands/contacts.ts +10 -7
  230. package/src/cli/commands/db/__tests__/repair.test.ts +6 -5
  231. package/src/cli/commands/db/status.ts +37 -1
  232. package/src/cli/commands/mcp.ts +252 -218
  233. package/src/cli/commands/memory/__tests__/worker.test.ts +432 -0
  234. package/src/cli/commands/memory/index.ts +2 -0
  235. package/src/cli/commands/memory/worker.ts +242 -0
  236. package/src/cli/commands/plugins.ts +125 -13
  237. package/src/cli/lib/__tests__/install-from-github.test.ts +102 -0
  238. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +160 -1
  239. package/src/cli/lib/__tests__/publish-plugin.test.ts +404 -0
  240. package/src/cli/lib/list-installed-plugins.ts +179 -1
  241. package/src/cli/lib/publish-plugin.ts +633 -0
  242. package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +143 -0
  243. package/src/config/__tests__/sync-gated-profiles.test.ts +16 -10
  244. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +27 -17
  245. package/src/config/bundled-skills/contacts/tools/contact-search.ts +13 -3
  246. package/src/config/bundled-skills/subagent/SKILL.md +17 -2
  247. package/src/config/bundled-skills/subagent/TOOLS.json +5 -4
  248. package/src/config/call-site-defaults.ts +0 -6
  249. package/src/config/feature-flag-registry.json +5 -13
  250. package/src/config/llm-resolver.ts +0 -3
  251. package/src/config/loader.ts +38 -5
  252. package/src/config/prune-seeded-callsite-defaults.ts +110 -0
  253. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  254. package/src/config/schemas/call-site-catalog.ts +0 -7
  255. package/src/config/schemas/heartbeat.ts +2 -5
  256. package/src/config/schemas/llm.ts +3 -12
  257. package/src/config/schemas/memory-lifecycle.ts +12 -0
  258. package/src/config/schemas/memory-v3.ts +7 -0
  259. package/src/config/schemas/memory.ts +4 -0
  260. package/src/config/schemas/timeouts.ts +8 -0
  261. package/src/config/seed-inference-profiles.ts +30 -34
  262. package/src/config/skills.ts +27 -5
  263. package/src/config/sync-gated-profiles.ts +12 -16
  264. package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +128 -0
  265. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +312 -0
  266. package/src/contacts/__tests__/member-write-relay.test.ts +226 -0
  267. package/src/contacts/contact-store.ts +27 -237
  268. package/src/contacts/contacts-write.ts +18 -55
  269. package/src/contacts/gateway-channel-read.ts +51 -0
  270. package/src/contacts/guardian-delivery-reader.ts +223 -0
  271. package/src/contacts/member-write-relay.ts +183 -0
  272. package/src/contacts/types.ts +3 -15
  273. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +35 -0
  274. package/src/daemon/__tests__/conversation-tool-setup.test.ts +0 -44
  275. package/src/daemon/assistant-attachments.ts +27 -4
  276. package/src/daemon/conversation-agent-loop.ts +28 -0
  277. package/src/daemon/conversation-notices.ts +60 -0
  278. package/src/daemon/conversation-process.ts +35 -16
  279. package/src/daemon/conversation-surfaces.ts +111 -38
  280. package/src/daemon/conversation-tool-setup.ts +71 -30
  281. package/src/daemon/conversation.ts +23 -1
  282. package/src/daemon/disk-pressure-guard.ts +12 -2
  283. package/src/daemon/event-loop-watchdog.ts +28 -1
  284. package/src/daemon/external-plugins-bootstrap.ts +17 -41
  285. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +0 -1
  286. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -2
  287. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +25 -2
  288. package/src/daemon/handlers/__tests__/config-channels.test.ts +220 -0
  289. package/src/daemon/handlers/config-a2a.ts +6 -14
  290. package/src/daemon/handlers/config-channels.ts +67 -26
  291. package/src/daemon/handlers/conversations.ts +77 -0
  292. package/src/daemon/lifecycle.ts +16 -0
  293. package/src/daemon/mcp-reload-service.ts +10 -0
  294. package/src/daemon/memory-v2-startup.test.ts +72 -0
  295. package/src/daemon/memory-v2-startup.ts +87 -19
  296. package/src/daemon/message-types/conversations.ts +2 -0
  297. package/src/daemon/message-types/surfaces.ts +12 -12
  298. package/src/daemon/server.ts +0 -4
  299. package/src/daemon/shutdown-handlers.ts +20 -0
  300. package/src/daemon/tool-setup-types.ts +9 -0
  301. package/src/heartbeat/heartbeat-service.ts +5 -0
  302. package/src/home/relationship-state-writer.ts +5 -0
  303. package/src/hooks/hook-loader.ts +341 -0
  304. package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
  305. package/src/ipc/assistant-server.ts +2 -2
  306. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +1 -0
  307. package/src/mcp/client.ts +15 -1
  308. package/src/mcp/mcp-auth-orchestrator.ts +6 -1
  309. package/src/mcp/mcp-header-store.ts +134 -0
  310. package/src/mcp/mcp-oauth-provider.ts +19 -8
  311. package/src/memory/__tests__/301-create-watchdog-events.test.ts +110 -0
  312. package/src/memory/__tests__/memory-retrospective-job.test.ts +8 -0
  313. package/src/memory/__tests__/prompt-override.test.ts +192 -0
  314. package/src/memory/__tests__/watchdog-events-store.test.ts +161 -0
  315. package/src/memory/compaction-ledger-store.ts +107 -0
  316. package/src/memory/conversation-crud.ts +129 -61
  317. package/src/memory/db-connection.ts +22 -3
  318. package/src/memory/db-init.ts +37 -503
  319. package/src/memory/db-singleton.ts +6 -4
  320. package/src/memory/jobs-worker.ts +104 -0
  321. package/src/memory/llm-request-log-store.ts +26 -1
  322. package/src/memory/llm-usage-store.ts +48 -20
  323. package/src/memory/memory-retrospective-job.ts +14 -8
  324. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +152 -56
  325. package/src/memory/migrations/300-add-processing-started-at.ts +30 -0
  326. package/src/memory/migrations/301-create-watchdog-events.ts +45 -0
  327. package/src/memory/migrations/302-create-compaction-events.ts +107 -0
  328. package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +297 -0
  329. package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
  330. package/src/memory/migrations/run-migrations.ts +106 -10
  331. package/src/memory/migrations/validate-migration-state.ts +105 -67
  332. package/src/memory/prompt-override.ts +129 -0
  333. package/src/memory/schema/contacts.ts +6 -2
  334. package/src/memory/schema/conversations.ts +37 -0
  335. package/src/memory/schema/infrastructure.ts +20 -0
  336. package/src/memory/steps.ts +1294 -0
  337. package/src/memory/v2/__tests__/cli-command-store.test.ts +25 -0
  338. package/src/memory/v2/__tests__/skill-store.test.ts +80 -0
  339. package/src/memory/v2/cli-command-store.ts +75 -38
  340. package/src/memory/v2/prompts/consolidation.ts +13 -82
  341. package/src/memory/v2/prompts/router.ts +21 -93
  342. package/src/memory/v2/skill-store.ts +68 -31
  343. package/src/memory/watchdog-events-store.ts +87 -0
  344. package/src/memory/worker-control.ts +204 -0
  345. package/src/memory/worker-process.ts +89 -0
  346. package/src/messaging/channel-binding-metadata.ts +31 -0
  347. package/src/messaging/provider-types.ts +8 -0
  348. package/src/messaging/providers/slack/binding-metadata.ts +60 -0
  349. package/src/notifications/__tests__/broadcaster.test.ts +8 -8
  350. package/src/notifications/__tests__/connected-channels.test.ts +86 -0
  351. package/src/notifications/__tests__/decision-engine.test.ts +78 -9
  352. package/src/notifications/__tests__/destination-resolver.test.ts +151 -0
  353. package/src/notifications/broadcaster.ts +8 -1
  354. package/src/notifications/decision-engine.ts +15 -7
  355. package/src/notifications/destination-resolver.ts +53 -25
  356. package/src/notifications/emit-signal.ts +34 -15
  357. package/src/onboarding/checkin-event.test.ts +222 -0
  358. package/src/onboarding/checkin-event.ts +321 -0
  359. package/src/onboarding/schedule-checkin.ts +190 -0
  360. package/src/permissions/question-prompter.test.ts +1 -1
  361. package/src/permissions/question-prompter.ts +7 -4
  362. package/src/plugin-api/index.ts +12 -12
  363. package/src/plugin-api/types.ts +12 -14
  364. package/src/plugin-api/vision-support.test.ts +28 -4
  365. package/src/plugin-api/vision-support.ts +66 -31
  366. package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +2 -2
  367. package/src/plugins/defaults/empty-response/hooks/stop.ts +2 -2
  368. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +4 -3
  369. package/src/plugins/defaults/history-repair/hooks/post-model-call.ts +2 -2
  370. package/src/plugins/defaults/history-repair/hooks/stop.ts +2 -2
  371. package/src/plugins/defaults/history-repair/hooks/user-prompt-submit.ts +2 -2
  372. package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +47 -7
  373. package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +12 -13
  374. package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +14 -22
  375. package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +42 -11
  376. package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +2 -2
  377. package/src/plugins/defaults/image-recovery/hooks/stop.ts +2 -2
  378. package/src/plugins/defaults/index.ts +0 -35
  379. package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +2 -2
  380. package/src/plugins/defaults/max-tokens-continue/hooks/stop.ts +2 -2
  381. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +2 -2
  382. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
  383. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +33 -3
  384. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +48 -4
  385. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +4 -8
  386. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +2 -2
  387. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +2 -2
  388. package/src/plugins/defaults/memory-v3-shadow/injector.ts +43 -15
  389. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +11 -2
  390. package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +146 -0
  391. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +77 -13
  392. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +12 -11
  393. package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +2 -2
  394. package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +2 -2
  395. package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +2 -2
  396. package/src/plugins/defaults/title-generate/hooks/stop.ts +2 -2
  397. package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +2 -2
  398. package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +2 -2
  399. package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +2 -2
  400. package/src/plugins/disabled-state.ts +31 -0
  401. package/src/plugins/external-plugin-loader.ts +2 -2
  402. package/src/plugins/mtime-cache.ts +186 -330
  403. package/src/plugins/pipeline.ts +111 -13
  404. package/src/plugins/registry.ts +59 -16
  405. package/src/plugins/surface-import.ts +121 -0
  406. package/src/plugins/types.ts +7 -9
  407. package/src/prompts/persona-resolver.ts +43 -11
  408. package/src/providers/anthropic/client.ts +5 -0
  409. package/src/providers/call-site-routing.ts +45 -0
  410. package/src/providers/model-catalog.ts +16 -0
  411. package/src/providers/openai/__tests__/api-error-normalization.test.ts +321 -0
  412. package/src/providers/openai/api-error-normalization.ts +270 -0
  413. package/src/providers/openai/chat-completions-provider.ts +37 -83
  414. package/src/providers/openai/responses-provider.ts +50 -46
  415. package/src/providers/openrouter/client.ts +5 -0
  416. package/src/providers/provider-send-message.ts +10 -0
  417. package/src/providers/ratelimit.ts +10 -0
  418. package/src/providers/registry.ts +1 -1
  419. package/src/providers/retry.ts +10 -0
  420. package/src/providers/types.ts +22 -0
  421. package/src/providers/usage-tracking.ts +10 -0
  422. package/src/runtime/__tests__/channel-verification-service.test.ts +133 -0
  423. package/src/runtime/__tests__/guardian-vellum-migration.test.ts +184 -0
  424. package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +66 -0
  425. package/src/runtime/__tests__/local-principal-trust.test.ts +162 -0
  426. package/src/runtime/__tests__/member-verdict-cache.test.ts +119 -0
  427. package/src/runtime/__tests__/trust-verdict-consumer.test.ts +402 -123
  428. package/src/runtime/access-request-helper.ts +18 -39
  429. package/src/runtime/actor-trust-resolver.ts +46 -19
  430. package/src/runtime/anchored-guardian.test.ts +109 -0
  431. package/src/runtime/anchored-guardian.ts +86 -0
  432. package/src/runtime/assistant-event-hub.ts +1 -1
  433. package/src/runtime/assistant-stream-state.ts +9 -2
  434. package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +99 -0
  435. package/src/runtime/auth/require-bound-guardian.ts +21 -11
  436. package/src/runtime/channel-verification-service.ts +56 -31
  437. package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
  438. package/src/runtime/guardian-vellum-migration.ts +69 -8
  439. package/src/runtime/invite-redemption-service.ts +213 -187
  440. package/src/runtime/local-actor-identity.test.ts +108 -0
  441. package/src/runtime/local-actor-identity.ts +85 -13
  442. package/src/runtime/local-principal-trust.ts +52 -0
  443. package/src/runtime/member-verdict-cache.ts +0 -0
  444. package/src/runtime/pending-interactions.ts +11 -1
  445. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +56 -5
  446. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
  447. package/src/runtime/routes/__tests__/contact-routes.test.ts +305 -0
  448. package/src/runtime/routes/__tests__/global-search-routes.test.ts +92 -0
  449. package/src/runtime/routes/__tests__/http-adapter-actor-header.test.ts +129 -0
  450. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +188 -0
  451. package/src/runtime/routes/browser-routes.ts +1 -1
  452. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +13 -5
  453. package/src/runtime/routes/channel-verification-routes.ts +3 -3
  454. package/src/runtime/routes/contact-routes.ts +48 -57
  455. package/src/runtime/routes/conversation-cli-routes.ts +4 -5
  456. package/src/runtime/routes/conversation-list-routes.ts +4 -7
  457. package/src/runtime/routes/conversation-query-routes.ts +72 -0
  458. package/src/runtime/routes/conversation-routes.ts +84 -85
  459. package/src/runtime/routes/events-routes.ts +2 -2
  460. package/src/runtime/routes/global-search-routes.ts +3 -1
  461. package/src/runtime/routes/guardian-action-routes.ts +4 -5
  462. package/src/runtime/routes/host-app-control-routes.ts +5 -4
  463. package/src/runtime/routes/host-bash-routes.ts +5 -4
  464. package/src/runtime/routes/host-browser-routes.ts +9 -11
  465. package/src/runtime/routes/host-cu-routes.ts +5 -4
  466. package/src/runtime/routes/host-file-routes.ts +5 -4
  467. package/src/runtime/routes/host-transfer-routes.ts +6 -6
  468. package/src/runtime/routes/http-adapter.ts +16 -1
  469. package/src/runtime/routes/identity-routes.ts +3 -2
  470. package/src/runtime/routes/inbound-message-handler.ts +5 -5
  471. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +97 -5
  472. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +61 -59
  473. package/src/runtime/routes/inbound-stages/background-dispatch.ts +13 -5
  474. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
  475. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +21 -8
  476. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -3
  477. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +19 -0
  478. package/src/runtime/routes/index.ts +2 -0
  479. package/src/runtime/routes/llm-context-normalization.ts +83 -0
  480. package/src/runtime/routes/mcp-auth-routes.ts +171 -19
  481. package/src/runtime/routes/migration-rollback-routes.ts +4 -3
  482. package/src/runtime/routes/migration-routes.ts +4 -1
  483. package/src/runtime/routes/onboarding-checkin-routes.ts +86 -0
  484. package/src/runtime/routes/settings-routes.ts +8 -3
  485. package/src/runtime/routes/subagents-routes.ts +5 -0
  486. package/src/runtime/routes/surface-action-routes.ts +42 -56
  487. package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
  488. package/src/runtime/services/conversation-serializer.ts +13 -58
  489. package/src/runtime/tool-grant-request-helper.ts +3 -3
  490. package/src/runtime/trust-verdict-consumer.ts +111 -40
  491. package/src/runtime/verification-outbound-actions.ts +18 -18
  492. package/src/signals/user-message.ts +16 -0
  493. package/src/subagent/__tests__/consult-prompt.test.ts +35 -0
  494. package/src/{plugins/defaults/advisor/__tests__/transcript.test.ts → subagent/__tests__/consult-transcript.test.ts} +47 -10
  495. package/src/{plugins/defaults/advisor/steering.ts → subagent/consult-prompt.ts} +22 -32
  496. package/src/{plugins/defaults/advisor/transcript.ts → subagent/consult-transcript.ts} +18 -8
  497. package/src/subagent/index.ts +1 -1
  498. package/src/subagent/manager.ts +254 -33
  499. package/src/subagent/types.ts +11 -4
  500. package/src/telemetry/types.ts +34 -1
  501. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
  502. package/src/telemetry/usage-telemetry-reporter.ts +87 -3
  503. package/src/tools/ask-question/ask-question-tool.test.ts +29 -0
  504. package/src/tools/ask-question/ask-question-tool.ts +13 -0
  505. package/src/tools/executor.ts +4 -4
  506. package/src/tools/filesystem/search.ts +543 -0
  507. package/src/tools/registry.ts +38 -0
  508. package/src/tools/shared/filesystem/path-policy.ts +12 -5
  509. package/src/tools/subagent/consult-deadline.ts +49 -0
  510. package/src/tools/subagent/spawn.ts +234 -5
  511. package/src/tools/tool-approval-handler.ts +1 -1
  512. package/src/tools/tool-defaults.ts +9 -2
  513. package/src/tools/tool-manifest.ts +3 -0
  514. package/src/tools/types.ts +131 -25
  515. package/src/tools/workspace-tools/loader.ts +348 -244
  516. package/src/util/errors.ts +26 -1
  517. package/src/util/logger.ts +9 -0
  518. package/src/util/platform.ts +19 -0
  519. package/src/util/telemetry-db-path.ts +24 -0
  520. package/src/workflows/library.test.ts +140 -0
  521. package/src/workflows/library.ts +82 -28
  522. package/src/workspace/migrations/017-seed-persona-dirs.ts +3 -34
  523. package/src/workspace/migrations/019-scope-journal-to-guardian.ts +3 -24
  524. package/src/workspace/migrations/031-drop-user-md.ts +232 -148
  525. package/src/workspace/migrations/048-remove-workspace-hooks.ts +14 -66
  526. package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +134 -0
  527. package/src/workspace/migrations/112-remove-advisor-callsite-override.ts +64 -0
  528. package/src/workspace/migrations/registry.ts +4 -0
  529. package/src/__tests__/workspace-tools-watcher-flag.test.ts +0 -70
  530. package/src/daemon/workspace-tools-watcher.ts +0 -328
  531. package/src/memory/migrations/registry.ts +0 -573
  532. package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +0 -56
  533. package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +0 -43
  534. package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +0 -137
  535. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -153
  536. package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +0 -138
  537. package/src/plugins/defaults/advisor/advisor-gate.ts +0 -29
  538. package/src/plugins/defaults/advisor/advisor-state-store.ts +0 -94
  539. package/src/plugins/defaults/advisor/config.ts +0 -21
  540. package/src/plugins/defaults/advisor/consult.ts +0 -93
  541. package/src/plugins/defaults/advisor/hooks/post-model-call.ts +0 -34
  542. package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +0 -30
  543. package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +0 -19
  544. package/src/plugins/defaults/advisor/package.json +0 -14
  545. package/src/plugins/defaults/advisor/tools/advisor.ts +0 -65
  546. package/src/providers/openai/__tests__/api-error-detail.test.ts +0 -120
@@ -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
 
@@ -96,6 +96,21 @@ export function routeDefinitionsToHTTPRoutes(
96
96
  headers[key] = value;
97
97
  });
98
98
 
99
+ // Strip any caller-supplied identity headers before deriving them
100
+ // from the verified AuthContext. On the HTTP path the actor identity
101
+ // always comes from the validated JWT — never from inbound headers —
102
+ // so a request that carries these headers is either confused or
103
+ // hostile. Without this, a caller whose token carries no
104
+ // actorPrincipalId (svc_gateway / svc_daemon / local principals) could
105
+ // spoof another principal — e.g. the guardian — by setting the header
106
+ // explicitly, because the override below only fires when the context
107
+ // supplies a value. Handlers that gate on principal identity (surface
108
+ // action `apr:*` guardian decisions, guardian actions, host proxies)
109
+ // would then apply a decision as the impersonated principal. Mirrors
110
+ // the gateway IPC proxy (gateway/src/http/routes/ipc-runtime-proxy.ts).
111
+ delete headers["x-vellum-actor-principal-id"];
112
+ delete headers["x-vellum-principal-type"];
113
+
99
114
  // Inject auth context fields so transport-agnostic handlers can
100
115
  // resolve trust context without importing auth internals.
101
116
  if (authContext?.actorPrincipalId) {
@@ -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,
@@ -19,14 +19,28 @@ mock.module("../../../util/logger.js", () => ({
19
19
  }));
20
20
 
21
21
  // Track contact-store reads to prove findContactChannel is NOT used on the
22
- // verdict path. findGuardianForChannel is still called by resolveGuardianLabel.
22
+ // verdict path.
23
23
  const findContactChannelCalls: unknown[] = [];
24
24
  mock.module("../../../contacts/contact-store.js", () => ({
25
25
  findContactChannel: (params: unknown) => {
26
26
  findContactChannelCalls.push(params);
27
27
  return null;
28
28
  },
29
- findGuardianForChannel: () => null,
29
+ }));
30
+
31
+ // resolveGuardianLabel resolves the guardian via the gateway delivery reader.
32
+ let guardianDeliveryList: Array<Record<string, unknown>> = [];
33
+ mock.module("../../../contacts/guardian-delivery-reader.js", () => ({
34
+ getGuardianDelivery: async () => guardianDeliveryList,
35
+ guardianForChannel: (
36
+ list: Array<Record<string, unknown>>,
37
+ channelType: string,
38
+ ) => list.find((g) => g.channelType === channelType && g.status === "active"),
39
+ }));
40
+
41
+ mock.module("../../../prompts/user-reference.js", () => ({
42
+ resolveGuardianName: (displayName?: string | null) =>
43
+ displayName && displayName.trim().length > 0 ? displayName.trim() : "my human",
30
44
  }));
31
45
 
32
46
  const deliverReplyCalls: Array<{ url: string; payload: unknown }> = [];
@@ -126,6 +140,7 @@ beforeEach(() => {
126
140
  deliverReplyCalls.length = 0;
127
141
  accessRequestCalls.length = 0;
128
142
  inviteTokenForTest = undefined;
143
+ guardianDeliveryList = [];
129
144
  });
130
145
 
131
146
  afterEach(() => {
@@ -140,8 +155,8 @@ describe("enforceIngressAcl — verdict-sourced member resolution", () => {
140
155
 
141
156
  expect(result.earlyResponse).toBeUndefined();
142
157
  expect(result.resolvedMember).not.toBeNull();
143
- expect(result.resolvedMember!.channel.status).toBe("active");
144
- expect(result.resolvedMember!.channel.policy).toBe("allow");
158
+ expect(result.resolvedMember!.status).toBe("active");
159
+ expect(result.resolvedMember!.policy).toBe("allow");
145
160
  // Member came from the verdict, never the local contact store.
146
161
  expect(findContactChannelCalls.length).toBe(0);
147
162
  });
@@ -156,7 +171,8 @@ describe("enforceIngressAcl — verdict-sourced member resolution", () => {
156
171
  );
157
172
 
158
173
  expect(result.earlyResponse).toBeUndefined();
159
- expect(result.resolvedMember!.contact.role).toBe("guardian");
174
+ expect(result.resolvedMember).not.toBeNull();
175
+ expect(result.resolvedMember!.status).toBe("active");
160
176
  expect(findContactChannelCalls.length).toBe(0);
161
177
  });
162
178
  });
@@ -249,6 +265,82 @@ describe("enforceIngressAcl — fail-closed on absent verdict", () => {
249
265
  });
250
266
  });
251
267
 
268
+ describe("enforceIngressAcl — fail-closed on resolutionFailed verdict", () => {
269
+ test("resolutionFailed verdict → not_a_member deny, does not flow to intercepts", async () => {
270
+ inviteTokenForTest = "iv_token123";
271
+ const result = await enforceIngressAcl(
272
+ makeParams({
273
+ sourceMetadata: withVerdict({
274
+ trustClass: "unknown",
275
+ canonicalSenderId: "sender-1",
276
+ resolutionFailed: true,
277
+ }),
278
+ effectiveAdmissionPolicy: "strangers",
279
+ }),
280
+ );
281
+
282
+ expect(result.earlyResponse).toBeDefined();
283
+ expect(result.earlyResponse!.reason).toBe("not_a_member");
284
+ expect(result.resolvedMember).toBeNull();
285
+ // Distinct from a stranger: no invite redemption, onboarding, or
286
+ // guardian notification fires.
287
+ expect(result.earlyResponse!.inviteRedemption).toBeUndefined();
288
+ expect(deliverReplyCalls.length).toBe(0);
289
+ expect(accessRequestCalls.length).toBe(0);
290
+ expect(findContactChannelCalls.length).toBe(0);
291
+ });
292
+
293
+ test("real unknown stranger (no resolutionFailed) still redeems via intercept", async () => {
294
+ inviteTokenForTest = "iv_token123";
295
+ const result = await enforceIngressAcl(
296
+ makeParams({
297
+ sourceMetadata: withVerdict({
298
+ trustClass: "unknown",
299
+ canonicalSenderId: "sender-1",
300
+ }),
301
+ }),
302
+ );
303
+
304
+ expect(result.earlyResponse!.inviteRedemption).toBe("redeemed");
305
+ expect(result.resolvedMember).toBeNull();
306
+ });
307
+ });
308
+
309
+ describe("enforceIngressAcl — deny copy names the gateway guardian", () => {
310
+ test("non-member deny reply uses the guardian displayName from the gateway list", async () => {
311
+ guardianDeliveryList = [
312
+ {
313
+ channelType: "vellum",
314
+ contactId: "c-1",
315
+ principalId: "p-anchor",
316
+ displayName: "Alice Guardian",
317
+ address: "p-anchor",
318
+ status: "active",
319
+ },
320
+ ];
321
+
322
+ const result = await enforceIngressAcl(
323
+ makeParams({
324
+ sourceMetadata: withVerdict({
325
+ trustClass: "unknown",
326
+ canonicalSenderId: "stranger-1",
327
+ }),
328
+ }),
329
+ );
330
+
331
+ expect(result.earlyResponse!.reason).toBe("not_a_member");
332
+ const denyReply = deliverReplyCalls.find((c) =>
333
+ String((c.payload as { text?: string }).text ?? "").includes(
334
+ "tried talking to me",
335
+ ),
336
+ );
337
+ expect(denyReply).toBeDefined();
338
+ expect((denyReply!.payload as { text: string }).text).toContain(
339
+ "Alice Guardian",
340
+ );
341
+ });
342
+ });
343
+
252
344
  describe("enforceIngressAcl — fail-closed on malformed member verdict", () => {
253
345
  test("member identity + unknown policy → not_a_member deny even under strangers", async () => {
254
346
  const result = await enforceIngressAcl(