@vellumai/assistant 0.10.2-dev.202606250318.5e7cfb0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (430) hide show
  1. package/bun.lock +0 -20
  2. package/docs/workspace-tools.md +33 -42
  3. package/eslint-rules/cli-no-daemon-internals.js +0 -6
  4. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +0 -31
  5. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +0 -44
  6. package/node_modules/@vellumai/gateway-client/src/index.ts +0 -14
  7. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +0 -17
  8. package/node_modules/@vellumai/service-contracts/package.json +0 -1
  9. package/node_modules/@vellumai/service-contracts/src/index.ts +0 -1
  10. package/openapi.yaml +0 -155
  11. package/package.json +1 -4
  12. package/scripts/test.sh +15 -36
  13. package/src/__tests__/actor-token-service.test.ts +14 -36
  14. package/src/__tests__/agent-loop-override-profile.test.ts +0 -1
  15. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -2
  16. package/src/__tests__/agent-wake-override-profile.test.ts +0 -2
  17. package/src/__tests__/annotate-activity-metadata.test.ts +0 -2
  18. package/src/__tests__/annotate-risk-options.test.ts +0 -2
  19. package/src/__tests__/approval-cascade.test.ts +0 -2
  20. package/src/__tests__/assistant-attachments.test.ts +0 -42
  21. package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
  22. package/src/__tests__/btw-routes.test.ts +0 -2
  23. package/src/__tests__/build-persisted-content.test.ts +0 -2
  24. package/src/__tests__/call-controller.test.ts +0 -19
  25. package/src/__tests__/channel-guardian.test.ts +58 -94
  26. package/src/__tests__/channel-reply-delivery.test.ts +0 -2
  27. package/src/__tests__/compaction-events.test.ts +0 -2
  28. package/src/__tests__/compaction.benchmark.test.ts +0 -2
  29. package/src/__tests__/compactor-call-site-logging.test.ts +0 -2
  30. package/src/__tests__/compactor-low-watermark-cut.test.ts +0 -2
  31. package/src/__tests__/compactor-preserved-tail-count.test.ts +0 -2
  32. package/src/__tests__/compactor-summary-call-truncation.test.ts +0 -2
  33. package/src/__tests__/compactor-web-search-strip.test.ts +0 -2
  34. package/src/__tests__/config-loader-backfill.test.ts +10 -123
  35. package/src/__tests__/config-schema.test.ts +0 -1
  36. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -31
  37. package/src/__tests__/contacts-relay-reads.test.ts +15 -13
  38. package/src/__tests__/conversation-abort-tool-results.test.ts +0 -2
  39. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +0 -2
  40. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +0 -2
  41. package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -2
  42. package/src/__tests__/conversation-agent-loop.test.ts +0 -134
  43. package/src/__tests__/conversation-analysis-routes.test.ts +0 -2
  44. package/src/__tests__/conversation-app-control-lifecycle.test.ts +0 -2
  45. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -2
  46. package/src/__tests__/conversation-history-web-search.test.ts +0 -2
  47. package/src/__tests__/conversation-load-history-repair.test.ts +0 -2
  48. package/src/__tests__/conversation-load-history-stripped.test.ts +0 -2
  49. package/src/__tests__/conversation-pairing.test.ts +0 -2
  50. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +0 -2
  51. package/src/__tests__/conversation-process-callsite.test.ts +0 -2
  52. package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -2
  53. package/src/__tests__/conversation-queue.test.ts +0 -91
  54. package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -14
  55. package/src/__tests__/conversation-routes-slash-commands.test.ts +0 -14
  56. package/src/__tests__/conversation-slash-queue.test.ts +0 -2
  57. package/src/__tests__/conversation-slash-unknown.test.ts +0 -2
  58. package/src/__tests__/conversation-speed-override.test.ts +0 -2
  59. package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -29
  60. package/src/__tests__/conversation-title-service.test.ts +0 -2
  61. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -47
  62. package/src/__tests__/conversation-usage.test.ts +0 -2
  63. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -2
  64. package/src/__tests__/conversation-workspace-injection.test.ts +0 -2
  65. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -2
  66. package/src/__tests__/credential-security-invariants.test.ts +1 -1
  67. package/src/__tests__/db-migration-rollback.test.ts +171 -205
  68. package/src/__tests__/db-test-helpers.ts +4 -5
  69. package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -4
  70. package/src/__tests__/disk-pressure-guard.test.ts +0 -41
  71. package/src/__tests__/dm-persistence.test.ts +0 -2
  72. package/src/__tests__/emit-signal-routing-intent.test.ts +5 -10
  73. package/src/__tests__/events-dev-bypass-actor.test.ts +1 -7
  74. package/src/__tests__/exploration-drift-hook.test.ts +2 -3
  75. package/src/__tests__/filing-service.test.ts +0 -2
  76. package/src/__tests__/guardian-binding-drift-heal.test.ts +10 -75
  77. package/src/__tests__/guardian-dispatch.test.ts +1 -95
  78. package/src/__tests__/guardian-outbound-http.test.ts +0 -13
  79. package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -2
  80. package/src/__tests__/heartbeat-service.test.ts +0 -2
  81. package/src/__tests__/helpers/channel-test-adapter.ts +7 -1
  82. package/src/__tests__/host-app-control-routes.test.ts +30 -24
  83. package/src/__tests__/host-bash-routes.test.ts +41 -31
  84. package/src/__tests__/host-browser-routes.test.ts +32 -26
  85. package/src/__tests__/host-cu-routes-targeted.test.ts +33 -25
  86. package/src/__tests__/host-file-routes-targeted.test.ts +52 -40
  87. package/src/__tests__/host-transfer-routes-targeted.test.ts +43 -31
  88. package/src/__tests__/http-user-message-parity.test.ts +8 -290
  89. package/src/__tests__/inbound-invite-redemption.test.ts +0 -28
  90. package/src/__tests__/inbound-slack-persistence.test.ts +0 -2
  91. package/src/__tests__/invite-redemption-service.test.ts +0 -198
  92. package/src/__tests__/llm-context-normalization.test.ts +0 -105
  93. package/src/__tests__/llm-request-log-error-payload.test.ts +9 -71
  94. package/src/__tests__/llm-usage-store.test.ts +0 -25
  95. package/src/__tests__/mcp-health-check.test.ts +1 -2
  96. package/src/__tests__/media-stream-server-integration.test.ts +0 -127
  97. package/src/__tests__/memory-retrieval-hook.test.ts +0 -2
  98. package/src/__tests__/messaging-send-tool.test.ts +0 -2
  99. package/src/__tests__/migration-import-from-url.test.ts +2 -2
  100. package/src/__tests__/mtime-cache.test.ts +5 -146
  101. package/src/__tests__/native-web-search.test.ts +0 -2
  102. package/src/__tests__/non-member-access-request.test.ts +17 -189
  103. package/src/__tests__/notification-broadcaster.test.ts +0 -4
  104. package/src/__tests__/notification-decision-recipient-context.test.ts +32 -33
  105. package/src/__tests__/notification-deep-link.test.ts +0 -6
  106. package/src/__tests__/notification-guardian-path.test.ts +0 -19
  107. package/src/__tests__/openai-provider.test.ts +12 -22
  108. package/src/__tests__/openai-responses-provider.test.ts +2 -12
  109. package/src/__tests__/outbound-slack-persistence.test.ts +0 -2
  110. package/src/__tests__/pending-interactions-resolved-event.test.ts +4 -7
  111. package/src/__tests__/persistence-secret-redaction.test.ts +0 -2
  112. package/src/__tests__/plugin-bootstrap.test.ts +73 -3
  113. package/src/__tests__/plugin-route-contribution.test.ts +17 -4
  114. package/src/__tests__/plugin-tool-contribution.test.ts +18 -3
  115. package/src/__tests__/plugin-types.test.ts +2 -0
  116. package/src/__tests__/process-message-background-slack.test.ts +0 -2
  117. package/src/__tests__/process-message-display-content.test.ts +0 -2
  118. package/src/__tests__/provider-error-scenarios.test.ts +4 -5
  119. package/src/__tests__/provider-usage-tracking.test.ts +0 -39
  120. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -2
  121. package/src/__tests__/registry.test.ts +1 -4
  122. package/src/__tests__/relay-server.test.ts +25 -694
  123. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -0
  124. package/src/__tests__/secret-ingress-http.test.ts +0 -14
  125. package/src/__tests__/send-endpoint-busy.test.ts +8 -30
  126. package/src/__tests__/skills.test.ts +0 -44
  127. package/src/__tests__/slack-inbound-verification.test.ts +2 -47
  128. package/src/__tests__/stt-hints.test.ts +13 -44
  129. package/src/__tests__/subagent-detail.test.ts +0 -27
  130. package/src/__tests__/subagent-disposal.test.ts +0 -65
  131. package/src/__tests__/subagent-notify-parent.test.ts +0 -2
  132. package/src/__tests__/subagent-role-registry.test.ts +2 -7
  133. package/src/__tests__/subagent-spawn-tool-fork.test.ts +0 -2
  134. package/src/__tests__/subagent-tools.test.ts +0 -2
  135. package/src/__tests__/suggestion-routes.test.ts +0 -2
  136. package/src/__tests__/title-generate-hook.test.ts +0 -2
  137. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -2
  138. package/src/__tests__/tool-executor.test.ts +11 -16
  139. package/src/__tests__/tool-preview-lifecycle.test.ts +0 -2
  140. package/src/__tests__/tool-result-metadata-plumbing.test.ts +0 -2
  141. package/src/__tests__/tool-start-timestamp.test.ts +0 -2
  142. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +10 -10
  143. package/src/__tests__/twilio-routes.test.ts +0 -96
  144. package/src/__tests__/ui-file-upload-surface.test.ts +0 -86
  145. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  146. package/src/__tests__/voice-invite-redemption.test.ts +0 -33
  147. package/src/__tests__/web-search-backend-failure.test.ts +0 -2
  148. package/src/__tests__/workspace-migration-remove-hooks.test.ts +35 -14
  149. package/src/__tests__/workspace-tool-loader.test.ts +2 -195
  150. package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
  151. package/src/agent/loop.ts +0 -56
  152. package/src/api/index.ts +1 -19
  153. package/src/api/responses/llm-request-log-entry.ts +0 -29
  154. package/src/api/responses/subagent-detail.ts +0 -17
  155. package/src/api/surfaces.ts +3 -39
  156. package/src/approvals/guardian-request-resolvers.ts +11 -1
  157. package/src/calls/__tests__/relay-setup-router.test.ts +4 -262
  158. package/src/calls/call-domain.ts +3 -3
  159. package/src/calls/guardian-dispatch.ts +8 -10
  160. package/src/calls/inbound-trust-reader.ts +1 -17
  161. package/src/calls/media-stream-server.ts +0 -21
  162. package/src/calls/relay-server.ts +50 -167
  163. package/src/calls/relay-setup-router.ts +7 -37
  164. package/src/calls/relay-verification.ts +4 -4
  165. package/src/calls/stt-hints.ts +12 -9
  166. package/src/calls/twilio-routes.ts +4 -14
  167. package/src/channels/types.ts +20 -10
  168. package/src/cli/commands/__tests__/cache.test.ts +1 -8
  169. package/src/cli/commands/cache.ts +181 -194
  170. package/src/cli/commands/db/__tests__/repair.test.ts +5 -6
  171. package/src/cli/commands/db/status.ts +1 -37
  172. package/src/cli/commands/mcp.ts +218 -252
  173. package/src/cli/commands/memory/index.ts +0 -2
  174. package/src/cli/commands/plugins.ts +3 -75
  175. package/src/cli/lib/__tests__/install-from-github.test.ts +0 -102
  176. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +1 -160
  177. package/src/cli/lib/list-installed-plugins.ts +1 -179
  178. package/src/config/__tests__/sync-gated-profiles.test.ts +3 -11
  179. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +17 -27
  180. package/src/config/bundled-skills/contacts/tools/contact-search.ts +3 -13
  181. package/src/config/bundled-skills/subagent/SKILL.md +1 -1
  182. package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
  183. package/src/config/feature-flag-registry.json +13 -5
  184. package/src/config/loader.ts +5 -38
  185. package/src/config/schemas/__tests__/memory-v3.test.ts +0 -1
  186. package/src/config/schemas/memory-lifecycle.ts +0 -12
  187. package/src/config/schemas/memory-v3.ts +0 -7
  188. package/src/config/schemas/memory.ts +0 -4
  189. package/src/config/schemas/timeouts.ts +0 -8
  190. package/src/config/seed-inference-profiles.ts +11 -21
  191. package/src/config/skills.ts +5 -27
  192. package/src/config/sync-gated-profiles.ts +13 -12
  193. package/src/contacts/contacts-write.ts +0 -3
  194. package/src/daemon/assistant-attachments.ts +4 -27
  195. package/src/daemon/conversation-agent-loop.ts +0 -28
  196. package/src/daemon/conversation-process.ts +16 -35
  197. package/src/daemon/conversation-surfaces.ts +38 -111
  198. package/src/daemon/conversation-tool-setup.ts +16 -50
  199. package/src/daemon/conversation.ts +1 -13
  200. package/src/daemon/disk-pressure-guard.ts +2 -12
  201. package/src/daemon/event-loop-watchdog.ts +1 -28
  202. package/src/daemon/external-plugins-bootstrap.ts +34 -4
  203. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -25
  204. package/src/daemon/handlers/config-a2a.ts +14 -6
  205. package/src/daemon/handlers/config-channels.ts +22 -78
  206. package/src/daemon/handlers/conversations.ts +0 -77
  207. package/src/daemon/lifecycle.ts +0 -4
  208. package/src/daemon/mcp-reload-service.ts +0 -10
  209. package/src/daemon/memory-v2-startup.test.ts +0 -72
  210. package/src/daemon/memory-v2-startup.ts +19 -87
  211. package/src/daemon/message-types/conversations.ts +0 -2
  212. package/src/daemon/message-types/surfaces.ts +12 -12
  213. package/src/daemon/server.ts +4 -0
  214. package/src/daemon/shutdown-handlers.ts +0 -20
  215. package/src/daemon/tool-setup-types.ts +0 -9
  216. package/src/daemon/workspace-tools-watcher.ts +328 -0
  217. package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
  218. package/src/ipc/assistant-server.ts +2 -2
  219. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
  220. package/src/mcp/client.ts +1 -15
  221. package/src/mcp/mcp-auth-orchestrator.ts +1 -6
  222. package/src/mcp/mcp-oauth-provider.ts +8 -19
  223. package/src/memory/__tests__/memory-retrospective-job.test.ts +0 -8
  224. package/src/memory/conversation-crud.ts +0 -38
  225. package/src/memory/db-connection.ts +3 -22
  226. package/src/memory/db-init.ts +502 -36
  227. package/src/memory/db-singleton.ts +4 -6
  228. package/src/memory/jobs-worker.ts +0 -58
  229. package/src/memory/llm-request-log-store.ts +1 -26
  230. package/src/memory/llm-usage-store.ts +20 -48
  231. package/src/memory/memory-retrospective-job.ts +8 -9
  232. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +56 -130
  233. package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
  234. package/src/memory/migrations/registry.ts +573 -0
  235. package/src/memory/migrations/run-migrations.ts +6 -90
  236. package/src/memory/migrations/validate-migration-state.ts +66 -101
  237. package/src/memory/schema/conversations.ts +0 -9
  238. package/src/memory/schema/infrastructure.ts +0 -20
  239. package/src/memory/v2/__tests__/cli-command-store.test.ts +0 -25
  240. package/src/memory/v2/__tests__/skill-store.test.ts +0 -80
  241. package/src/memory/v2/cli-command-store.ts +38 -75
  242. package/src/memory/v2/prompts/consolidation.ts +82 -13
  243. package/src/memory/v2/prompts/router.ts +93 -21
  244. package/src/memory/v2/skill-store.ts +31 -68
  245. package/src/notifications/__tests__/broadcaster.test.ts +8 -16
  246. package/src/notifications/__tests__/decision-engine.test.ts +9 -78
  247. package/src/notifications/broadcaster.ts +1 -8
  248. package/src/notifications/decision-engine.ts +7 -15
  249. package/src/notifications/destination-resolver.ts +24 -68
  250. package/src/notifications/emit-signal.ts +14 -39
  251. package/src/permissions/question-prompter.test.ts +1 -1
  252. package/src/permissions/question-prompter.ts +4 -7
  253. package/src/plugin-api/index.ts +6 -6
  254. package/src/plugin-api/types.ts +5 -3
  255. package/src/plugin-api/vision-support.test.ts +4 -28
  256. package/src/plugin-api/vision-support.ts +31 -66
  257. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -161
  258. package/src/plugins/defaults/advisor/consult.ts +6 -110
  259. package/src/plugins/defaults/advisor/steering.ts +2 -14
  260. package/src/plugins/defaults/advisor/tools/advisor.ts +5 -32
  261. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +1 -2
  262. package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +7 -47
  263. package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +11 -10
  264. package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +20 -12
  265. package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +11 -42
  266. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +3 -33
  267. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +4 -48
  268. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +8 -4
  269. package/src/plugins/defaults/memory-v3-shadow/injector.ts +15 -43
  270. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +2 -11
  271. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +13 -77
  272. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +11 -12
  273. package/src/plugins/mtime-cache.ts +291 -76
  274. package/src/plugins/pipeline.ts +13 -111
  275. package/src/plugins/types.ts +2 -0
  276. package/src/providers/anthropic/client.ts +0 -5
  277. package/src/providers/call-site-routing.ts +0 -4
  278. package/src/providers/model-catalog.ts +0 -16
  279. package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
  280. package/src/providers/openai/chat-completions-provider.ts +83 -37
  281. package/src/providers/openai/responses-provider.ts +46 -50
  282. package/src/providers/openrouter/client.ts +0 -5
  283. package/src/providers/provider-send-message.ts +0 -4
  284. package/src/providers/ratelimit.ts +0 -4
  285. package/src/providers/retry.ts +0 -4
  286. package/src/providers/types.ts +0 -9
  287. package/src/providers/usage-tracking.ts +0 -4
  288. package/src/runtime/__tests__/trust-verdict-consumer.test.ts +3 -335
  289. package/src/runtime/access-request-helper.ts +39 -19
  290. package/src/runtime/actor-trust-resolver.ts +2 -2
  291. package/src/runtime/assistant-event-hub.ts +1 -1
  292. package/src/runtime/assistant-stream-state.ts +2 -9
  293. package/src/runtime/auth/require-bound-guardian.ts +11 -21
  294. package/src/runtime/channel-verification-service.ts +31 -56
  295. package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
  296. package/src/runtime/guardian-vellum-migration.ts +7 -66
  297. package/src/runtime/invite-redemption-service.ts +187 -198
  298. package/src/runtime/local-actor-identity.ts +11 -76
  299. package/src/runtime/pending-interactions.ts +1 -11
  300. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +5 -56
  301. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
  302. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +0 -187
  303. package/src/runtime/routes/browser-routes.ts +1 -1
  304. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -13
  305. package/src/runtime/routes/channel-verification-routes.ts +3 -3
  306. package/src/runtime/routes/contact-routes.ts +32 -8
  307. package/src/runtime/routes/conversation-cli-routes.ts +5 -4
  308. package/src/runtime/routes/conversation-list-routes.ts +7 -4
  309. package/src/runtime/routes/conversation-query-routes.ts +0 -72
  310. package/src/runtime/routes/conversation-routes.ts +85 -84
  311. package/src/runtime/routes/events-routes.ts +2 -2
  312. package/src/runtime/routes/global-search-routes.ts +1 -3
  313. package/src/runtime/routes/guardian-action-routes.ts +5 -4
  314. package/src/runtime/routes/host-app-control-routes.ts +4 -5
  315. package/src/runtime/routes/host-bash-routes.ts +4 -5
  316. package/src/runtime/routes/host-browser-routes.ts +11 -9
  317. package/src/runtime/routes/host-cu-routes.ts +4 -5
  318. package/src/runtime/routes/host-file-routes.ts +4 -5
  319. package/src/runtime/routes/host-transfer-routes.ts +6 -6
  320. package/src/runtime/routes/http-adapter.ts +1 -1
  321. package/src/runtime/routes/identity-routes.ts +2 -3
  322. package/src/runtime/routes/inbound-message-handler.ts +5 -5
  323. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +5 -97
  324. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +49 -61
  325. package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -16
  326. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
  327. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +8 -21
  328. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +3 -14
  329. package/src/runtime/routes/index.ts +0 -2
  330. package/src/runtime/routes/llm-context-normalization.ts +0 -83
  331. package/src/runtime/routes/mcp-auth-routes.ts +19 -171
  332. package/src/runtime/routes/migration-rollback-routes.ts +3 -4
  333. package/src/runtime/routes/migration-routes.ts +1 -4
  334. package/src/runtime/routes/subagents-routes.ts +0 -5
  335. package/src/runtime/routes/surface-action-routes.ts +56 -42
  336. package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -1
  337. package/src/runtime/services/conversation-serializer.ts +9 -7
  338. package/src/runtime/tool-grant-request-helper.ts +3 -3
  339. package/src/runtime/trust-verdict-consumer.ts +9 -85
  340. package/src/runtime/verification-outbound-actions.ts +18 -18
  341. package/src/signals/user-message.ts +0 -16
  342. package/src/subagent/manager.ts +0 -9
  343. package/src/subagent/types.ts +3 -3
  344. package/src/telemetry/types.ts +1 -34
  345. package/src/telemetry/usage-telemetry-reporter.test.ts +2 -3
  346. package/src/telemetry/usage-telemetry-reporter.ts +3 -87
  347. package/src/tools/ask-question/ask-question-tool.test.ts +0 -29
  348. package/src/tools/ask-question/ask-question-tool.ts +0 -13
  349. package/src/tools/executor.ts +4 -4
  350. package/src/tools/registry.ts +0 -18
  351. package/src/tools/shared/filesystem/path-policy.ts +5 -12
  352. package/src/tools/tool-approval-handler.ts +1 -1
  353. package/src/tools/tool-defaults.ts +2 -9
  354. package/src/tools/tool-manifest.ts +0 -3
  355. package/src/tools/types.ts +2 -17
  356. package/src/tools/workspace-tools/loader.ts +244 -348
  357. package/src/util/errors.ts +1 -26
  358. package/src/util/platform.ts +0 -5
  359. package/src/workflows/library.test.ts +0 -140
  360. package/src/workflows/library.ts +28 -82
  361. package/src/workspace/migrations/017-seed-persona-dirs.ts +34 -3
  362. package/src/workspace/migrations/019-scope-journal-to-guardian.ts +24 -3
  363. package/src/workspace/migrations/048-remove-workspace-hooks.ts +66 -14
  364. package/src/workspace/migrations/registry.ts +0 -2
  365. package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +0 -91
  366. package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +0 -48
  367. package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +0 -28
  368. package/node_modules/@vellumai/service-contracts/src/channels.ts +0 -41
  369. package/src/__tests__/code-search-tool.test.ts +0 -585
  370. package/src/__tests__/guardian-expiry-notifier.test.ts +0 -282
  371. package/src/__tests__/mcp-config-secret-boundary.test.ts +0 -390
  372. package/src/__tests__/plugin-pipeline.test.ts +0 -96
  373. package/src/__tests__/sse-actor-principal-guardian-source.test.ts +0 -102
  374. package/src/__tests__/steer-on-enqueue-question.test.ts +0 -181
  375. package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +0 -208
  376. package/src/agent/loop-exclusive-tool.test.ts +0 -150
  377. package/src/api/constants/sse-replay.ts +0 -41
  378. package/src/api/events/conversation-notice.ts +0 -26
  379. package/src/approvals/guardian-channel-delivery.ts +0 -30
  380. package/src/approvals/guardian-expiry-notifier.ts +0 -148
  381. package/src/cli/commands/memory/__tests__/worker.test.ts +0 -302
  382. package/src/cli/commands/memory/worker.ts +0 -175
  383. package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +0 -143
  384. package/src/config/prune-seeded-callsite-defaults.ts +0 -110
  385. package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -129
  386. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +0 -312
  387. package/src/contacts/__tests__/member-write-relay.test.ts +0 -202
  388. package/src/contacts/guardian-delivery-reader.ts +0 -223
  389. package/src/contacts/member-write-relay.ts +0 -189
  390. package/src/daemon/conversation-notices.ts +0 -60
  391. package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -225
  392. package/src/hooks/hook-loader.ts +0 -341
  393. package/src/mcp/mcp-header-store.ts +0 -134
  394. package/src/memory/__tests__/301-create-watchdog-events.test.ts +0 -110
  395. package/src/memory/__tests__/prompt-override.test.ts +0 -192
  396. package/src/memory/__tests__/watchdog-events-store.test.ts +0 -161
  397. package/src/memory/migrations/300-add-processing-started-at.ts +0 -30
  398. package/src/memory/migrations/301-create-watchdog-events.ts +0 -45
  399. package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +0 -224
  400. package/src/memory/prompt-override.ts +0 -129
  401. package/src/memory/steps.ts +0 -573
  402. package/src/memory/watchdog-events-store.ts +0 -87
  403. package/src/memory/worker-control.ts +0 -118
  404. package/src/memory/worker-process.ts +0 -72
  405. package/src/notifications/__tests__/connected-channels.test.ts +0 -114
  406. package/src/notifications/__tests__/destination-resolver.test.ts +0 -256
  407. package/src/onboarding/checkin-event.test.ts +0 -222
  408. package/src/onboarding/checkin-event.ts +0 -321
  409. package/src/onboarding/schedule-checkin.ts +0 -190
  410. package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +0 -106
  411. package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +0 -60
  412. package/src/plugins/defaults/advisor/context-pack.ts +0 -288
  413. package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +0 -146
  414. package/src/plugins/surface-import.ts +0 -121
  415. package/src/providers/openai/__tests__/api-error-normalization.test.ts +0 -321
  416. package/src/providers/openai/api-error-normalization.ts +0 -270
  417. package/src/runtime/__tests__/channel-verification-service.test.ts +0 -133
  418. package/src/runtime/__tests__/guardian-vellum-migration.test.ts +0 -181
  419. package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +0 -66
  420. package/src/runtime/__tests__/local-principal-trust.test.ts +0 -164
  421. package/src/runtime/anchored-guardian.test.ts +0 -156
  422. package/src/runtime/anchored-guardian.ts +0 -135
  423. package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +0 -99
  424. package/src/runtime/local-principal-trust.ts +0 -52
  425. package/src/runtime/routes/__tests__/contact-routes.test.ts +0 -212
  426. package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -93
  427. package/src/runtime/routes/onboarding-checkin-routes.ts +0 -86
  428. package/src/tools/filesystem/search.ts +0 -543
  429. package/src/util/telemetry-db-path.ts +0 -24
  430. package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +0 -134
@@ -1,164 +0,0 @@
1
- import { beforeEach, describe, expect, mock, test } from "bun:test";
2
-
3
- import type { ChannelId } from "../../channels/types.js";
4
-
5
- // Gateway guardian-delivery list: null = couldn't determine (gateway
6
- // unreachable), [] = authoritatively no guardian, one active entry = bound.
7
- let mockGuardianList: Array<Record<string, unknown>> | null = [];
8
-
9
- mock.module("../../contacts/guardian-delivery-reader.js", () => ({
10
- getGuardianDelivery: (_input?: { channelTypes?: string[] }) =>
11
- Promise.resolve(mockGuardianList),
12
- }));
13
-
14
- // Local-resolver guardian binding, used to construct the expected guardian
15
- // TrustContext via the existing resolver and prove equivalence.
16
- let mockGuardianRecord: {
17
- contact: Record<string, unknown>;
18
- channel: Record<string, unknown>;
19
- } | null = null;
20
-
21
- mock.module("../../contacts/contact-store.js", () => ({
22
- findGuardianForChannel: (_channelType: string) => mockGuardianRecord,
23
- findContactByAddress: (_channelType: string, _address: string) => null,
24
- }));
25
-
26
- const { resolveLocalPrincipalTrustContext } = await import(
27
- "../local-principal-trust.js"
28
- );
29
- const { resolveActorTrust, toTrustContext } = await import(
30
- "../actor-trust-resolver.js"
31
- );
32
-
33
- const SOURCE_CHANNEL: ChannelId = "vellum";
34
- const CONVERSATION_ID = "conv-1";
35
- const GUARDIAN_PRINCIPAL_ID = "principal-guardian";
36
- const GUARDIAN_ADDRESS = "guardian-address";
37
- const GUARDIAN_CHAT_ID = "guardian-chat";
38
-
39
- describe("resolveLocalPrincipalTrustContext", () => {
40
- beforeEach(() => {
41
- mockGuardianList = [];
42
- mockGuardianRecord = null;
43
- });
44
-
45
- test("principal matching the gateway guardian → guardian ctx", async () => {
46
- mockGuardianList = [
47
- {
48
- channelType: "vellum",
49
- contactId: "contact-1",
50
- principalId: GUARDIAN_PRINCIPAL_ID,
51
- address: GUARDIAN_ADDRESS,
52
- externalChatId: GUARDIAN_CHAT_ID,
53
- status: "active",
54
- },
55
- ];
56
-
57
- const ctx = await resolveLocalPrincipalTrustContext({
58
- actorPrincipalId: GUARDIAN_PRINCIPAL_ID,
59
- sourceChannel: SOURCE_CHANNEL,
60
- conversationExternalId: CONVERSATION_ID,
61
- });
62
-
63
- expect(ctx.trustClass).toBe("guardian");
64
- expect(ctx.guardianPrincipalId).toBe(GUARDIAN_PRINCIPAL_ID);
65
- expect(ctx.guardianExternalUserId).toBe(GUARDIAN_ADDRESS);
66
- expect(ctx.guardianChatId).toBe(GUARDIAN_CHAT_ID);
67
- expect(ctx.requesterExternalUserId).toBe(GUARDIAN_PRINCIPAL_ID);
68
- expect(ctx.requesterChatId).toBe(CONVERSATION_ID);
69
- expect(ctx.sourceChannel).toBe(SOURCE_CHANNEL);
70
- });
71
-
72
- test("guardian ctx is equivalent to the prior toTrustContext output", async () => {
73
- // The actor IS the guardian: its principal id is the guardian binding's
74
- // address (vellum canonicalization is pass-through) so the local resolver
75
- // classifies it guardian and we can compare the two outputs directly.
76
- mockGuardianList = [
77
- {
78
- channelType: "vellum",
79
- contactId: "contact-1",
80
- principalId: GUARDIAN_ADDRESS,
81
- address: GUARDIAN_ADDRESS,
82
- externalChatId: GUARDIAN_CHAT_ID,
83
- status: "active",
84
- },
85
- ];
86
- mockGuardianRecord = {
87
- contact: { id: "contact-1", principalId: GUARDIAN_ADDRESS },
88
- channel: {
89
- type: "vellum",
90
- address: GUARDIAN_ADDRESS,
91
- externalChatId: GUARDIAN_CHAT_ID,
92
- status: "active",
93
- },
94
- };
95
-
96
- const expected = toTrustContext(
97
- resolveActorTrust({
98
- assistantId: "assistant-1",
99
- sourceChannel: SOURCE_CHANNEL,
100
- conversationExternalId: CONVERSATION_ID,
101
- actorExternalId: GUARDIAN_ADDRESS,
102
- }),
103
- CONVERSATION_ID,
104
- );
105
-
106
- const actual = await resolveLocalPrincipalTrustContext({
107
- actorPrincipalId: GUARDIAN_ADDRESS,
108
- sourceChannel: SOURCE_CHANNEL,
109
- conversationExternalId: CONVERSATION_ID,
110
- });
111
-
112
- expect(actual).toEqual(expected);
113
- });
114
-
115
- test("non-matching principal → unknown ctx", async () => {
116
- mockGuardianList = [
117
- {
118
- channelType: "vellum",
119
- contactId: "contact-1",
120
- principalId: GUARDIAN_PRINCIPAL_ID,
121
- address: GUARDIAN_ADDRESS,
122
- externalChatId: GUARDIAN_CHAT_ID,
123
- status: "active",
124
- },
125
- ];
126
-
127
- const ctx = await resolveLocalPrincipalTrustContext({
128
- actorPrincipalId: "principal-other",
129
- sourceChannel: SOURCE_CHANNEL,
130
- conversationExternalId: CONVERSATION_ID,
131
- });
132
-
133
- expect(ctx.trustClass).toBe("unknown");
134
- expect(ctx.requesterExternalUserId).toBe("principal-other");
135
- expect(ctx.requesterChatId).toBe(CONVERSATION_ID);
136
- expect(ctx.sourceChannel).toBe(SOURCE_CHANNEL);
137
- expect(ctx.guardianPrincipalId).toBeUndefined();
138
- });
139
-
140
- test("empty guardian list → unknown ctx", async () => {
141
- mockGuardianList = [];
142
-
143
- const ctx = await resolveLocalPrincipalTrustContext({
144
- actorPrincipalId: GUARDIAN_PRINCIPAL_ID,
145
- sourceChannel: SOURCE_CHANNEL,
146
- conversationExternalId: CONVERSATION_ID,
147
- });
148
-
149
- expect(ctx.trustClass).toBe("unknown");
150
- });
151
-
152
- test("null guardian list (gateway unreachable) → unknown (fail closed)", async () => {
153
- mockGuardianList = null;
154
-
155
- const ctx = await resolveLocalPrincipalTrustContext({
156
- actorPrincipalId: GUARDIAN_PRINCIPAL_ID,
157
- sourceChannel: SOURCE_CHANNEL,
158
- conversationExternalId: CONVERSATION_ID,
159
- });
160
-
161
- expect(ctx.trustClass).toBe("unknown");
162
- expect(ctx.requesterExternalUserId).toBe(GUARDIAN_PRINCIPAL_ID);
163
- });
164
- });
@@ -1,156 +0,0 @@
1
- /**
2
- * Unit tests for `resolveAnchoredGuardian`.
3
- *
4
- * Covers the gateway arms (source-channel match validated against the vellum
5
- * anchor, vellum-anchor fallback), the LOCAL-store fallback when the gateway
6
- * list is empty, and the cosmetic `requireAnchorPrincipal` guard.
7
- */
8
- import { afterEach, describe, expect, mock, test } from "bun:test";
9
-
10
- import type { GuardianDelivery } from "@vellumai/gateway-client";
11
-
12
- // Local store fallback is mocked so we can drive both arms deterministically.
13
- let localGuardians: Record<
14
- string,
15
- { contact: { principalId: string | null; displayName: string }; channel: { address: string; type: string } } | null
16
- > = {};
17
- mock.module("../contacts/contact-store.js", () => ({
18
- findGuardianForChannel: (channelType: string) =>
19
- localGuardians[channelType] ?? null,
20
- }));
21
-
22
- const { resolveAnchoredGuardian } = await import("./anchored-guardian.js");
23
-
24
- function gw(g: Partial<GuardianDelivery> & { channelType: string; address: string }): GuardianDelivery {
25
- return {
26
- contactId: `c-${g.channelType}`,
27
- status: "active",
28
- ...g,
29
- };
30
- }
31
-
32
- afterEach(() => {
33
- localGuardians = {};
34
- });
35
-
36
- describe("resolveAnchoredGuardian — gateway arm", () => {
37
- test("source-channel guardian matching the anchor wins", () => {
38
- const result = resolveAnchoredGuardian({
39
- guardians: [
40
- gw({ channelType: "vellum", address: "v-addr", principalId: "p-anchor", displayName: "Vellum" }),
41
- gw({ channelType: "telegram", address: "tg-addr", principalId: "p-anchor", displayName: "Alice" }),
42
- ],
43
- sourceChannel: "telegram",
44
- });
45
- expect(result).toEqual({
46
- principalId: "p-anchor",
47
- address: "tg-addr",
48
- displayName: "Alice",
49
- channelType: "telegram",
50
- source: "source-channel-contact",
51
- });
52
- });
53
-
54
- test("source-channel guardian NOT matching the anchor falls back to vellum-anchor", () => {
55
- const result = resolveAnchoredGuardian({
56
- guardians: [
57
- gw({ channelType: "vellum", address: "v-addr", principalId: "p-anchor", displayName: "Vellum" }),
58
- gw({ channelType: "telegram", address: "tg-addr", principalId: "p-other", displayName: "Stale" }),
59
- ],
60
- sourceChannel: "telegram",
61
- });
62
- expect(result).toEqual({
63
- principalId: "p-anchor",
64
- address: "v-addr",
65
- displayName: "Vellum",
66
- channelType: "vellum",
67
- source: "vellum-anchor",
68
- });
69
- });
70
-
71
- test("no source-channel guardian falls back to vellum-anchor", () => {
72
- const result = resolveAnchoredGuardian({
73
- guardians: [
74
- gw({ channelType: "vellum", address: "v-addr", principalId: "p-anchor", displayName: "Vellum" }),
75
- ],
76
- sourceChannel: "telegram",
77
- });
78
- expect(result?.source).toBe("vellum-anchor");
79
- expect(result?.principalId).toBe("p-anchor");
80
- });
81
- });
82
-
83
- describe("resolveAnchoredGuardian — local fallback", () => {
84
- test("gateway empty + local source-channel match returns the local record", () => {
85
- localGuardians = {
86
- vellum: { contact: { principalId: "p-local", displayName: "LocalVellum" }, channel: { address: "lv-addr", type: "vellum" } },
87
- telegram: { contact: { principalId: "p-local", displayName: "LocalAlice" }, channel: { address: "ltg-addr", type: "telegram" } },
88
- };
89
- const result = resolveAnchoredGuardian({
90
- guardians: null,
91
- sourceChannel: "telegram",
92
- useLocalFallback: true,
93
- });
94
- expect(result).toEqual({
95
- principalId: "p-local",
96
- address: "ltg-addr",
97
- displayName: "LocalAlice",
98
- channelType: "telegram",
99
- source: "source-channel-contact",
100
- });
101
- });
102
-
103
- test("gateway empty + only local vellum returns the local vellum-anchor", () => {
104
- localGuardians = {
105
- vellum: { contact: { principalId: "p-local", displayName: "LocalVellum" }, channel: { address: "lv-addr", type: "vellum" } },
106
- };
107
- const result = resolveAnchoredGuardian({
108
- guardians: null,
109
- sourceChannel: "telegram",
110
- useLocalFallback: true,
111
- });
112
- expect(result?.source).toBe("vellum-anchor");
113
- expect(result?.address).toBe("lv-addr");
114
- });
115
-
116
- test("gateway empty + no local + fallback disabled returns null", () => {
117
- const result = resolveAnchoredGuardian({
118
- guardians: null,
119
- sourceChannel: "telegram",
120
- });
121
- expect(result).toBeNull();
122
- });
123
-
124
- test("nothing anywhere returns null", () => {
125
- const result = resolveAnchoredGuardian({
126
- guardians: [],
127
- sourceChannel: "telegram",
128
- useLocalFallback: true,
129
- });
130
- expect(result).toBeNull();
131
- });
132
- });
133
-
134
- describe("resolveAnchoredGuardian — requireAnchorPrincipal (cosmetic label)", () => {
135
- test("vellum guardian with a null principal degrades to null", () => {
136
- const result = resolveAnchoredGuardian({
137
- guardians: [
138
- gw({ channelType: "vellum", address: "v-addr", principalId: null, displayName: "Vellum" }),
139
- ],
140
- sourceChannel: "telegram",
141
- requireAnchorPrincipal: true,
142
- });
143
- expect(result).toBeNull();
144
- });
145
-
146
- test("without requireAnchorPrincipal a null-principal vellum still resolves", () => {
147
- const result = resolveAnchoredGuardian({
148
- guardians: [
149
- gw({ channelType: "vellum", address: "v-addr", principalId: null, displayName: "Vellum" }),
150
- ],
151
- sourceChannel: "telegram",
152
- });
153
- expect(result?.source).toBe("vellum-anchor");
154
- expect(result?.principalId).toBeNull();
155
- });
156
- });
@@ -1,135 +0,0 @@
1
- /**
2
- * Shared anchored-guardian resolution.
3
- *
4
- * Resolves the guardian identity for an inbound access request using the
5
- * assistant's vellum principal as the trust anchor: a source-channel guardian
6
- * is only accepted when its principal matches the anchor, otherwise the vellum
7
- * anchor identity is used. This blocks stale or cross-assistant contacts from
8
- * being bound to a request.
9
- *
10
- * Gateway-first: resolves from the gateway delivery list, then falls back to
11
- * the LOCAL dual-written binding when the gateway read is empty/unavailable
12
- * (restart, timeout, malformed IPC). The local fallback is transitional and is
13
- * removed in a later step.
14
- */
15
-
16
- import type { GuardianDelivery } from "@vellumai/gateway-client";
17
-
18
- import type { ChannelId } from "../channels/types.js";
19
- import { findGuardianForChannel } from "../contacts/contact-store.js";
20
- import { guardianForChannel } from "../contacts/guardian-delivery-reader.js";
21
- import type { GuardianResolutionSource } from "../notifications/signal.js";
22
-
23
- /** Resolved guardian identity, anchored on the assistant's vellum principal. */
24
- export interface AnchoredGuardian {
25
- principalId: string | null;
26
- address: string;
27
- displayName: string | null;
28
- channelType: string;
29
- source: GuardianResolutionSource;
30
- }
31
-
32
- export interface ResolveAnchoredGuardianInput {
33
- /** Gateway delivery list; `null` when the gateway read failed/was empty. */
34
- guardians: GuardianDelivery[] | null;
35
- sourceChannel: ChannelId;
36
- /**
37
- * Fall back to the LOCAL dual-written binding when the gateway arm resolves
38
- * nothing. Access-request enables this to avoid an undecidable request; the
39
- * cosmetic guardian-label path leaves it off so a missing gateway read
40
- * degrades gracefully to the default reference.
41
- */
42
- useLocalFallback?: boolean;
43
- /**
44
- * Require a non-null anchor principal for the vellum-anchor arm. When the
45
- * vellum guardian has no principal, return `null` instead of a vellum-anchor
46
- * record. Matches the cosmetic label path, which degrades to the default
47
- * reference when the anchor principal is absent.
48
- */
49
- requireAnchorPrincipal?: boolean;
50
- }
51
-
52
- /**
53
- * Resolve the anchored guardian for `sourceChannel`, or `null` when none can be
54
- * resolved. Gateway source-channel match → that record; gateway anchor-only →
55
- * vellum-anchor; gateway empty + local has it → local fallback record.
56
- */
57
- export function resolveAnchoredGuardian(
58
- input: ResolveAnchoredGuardianInput,
59
- ): AnchoredGuardian | null {
60
- const { sourceChannel, useLocalFallback, requireAnchorPrincipal } = input;
61
- const guardians = input.guardians ?? [];
62
-
63
- const vellumGuardian = guardianForChannel(guardians, "vellum");
64
- const anchorPrincipalId = vellumGuardian?.principalId;
65
-
66
- let resolved: AnchoredGuardian | null = null;
67
-
68
- // Source-channel guardian, but only when it maps to the assistant's anchored
69
- // principal. This blocks cross-assistant/stale binding selection.
70
- const sourceGuardian = guardianForChannel(guardians, sourceChannel);
71
- if (
72
- anchorPrincipalId &&
73
- sourceGuardian &&
74
- sourceGuardian.principalId === anchorPrincipalId
75
- ) {
76
- resolved = {
77
- principalId: sourceGuardian.principalId,
78
- address: sourceGuardian.address,
79
- displayName: sourceGuardian.displayName ?? null,
80
- channelType: sourceGuardian.channelType,
81
- source: "source-channel-contact",
82
- };
83
- } else if (vellumGuardian && !(requireAnchorPrincipal && !anchorPrincipalId)) {
84
- // Source-channel resolution did not match the anchor → use the anchored
85
- // vellum identity.
86
- resolved = {
87
- principalId: anchorPrincipalId ?? null,
88
- address: vellumGuardian.address,
89
- displayName: vellumGuardian.displayName ?? null,
90
- channelType: "vellum",
91
- source: "vellum-anchor",
92
- };
93
- }
94
-
95
- // Gateway resolved a principal — done.
96
- if (resolved?.principalId) {
97
- return resolved;
98
- }
99
-
100
- if (!useLocalFallback) {
101
- return resolved;
102
- }
103
-
104
- // Fallback: gateway read was empty/unavailable (or carried no principal), so
105
- // resolve from the LOCAL dual-written binding to avoid an undecidable
106
- // request. A local match overwrites the principal-less gateway record; with
107
- // no local match the gateway record (if any) is retained.
108
- const localVellum = findGuardianForChannel("vellum");
109
- const localAnchorPrincipalId = localVellum?.contact.principalId;
110
- const localSource = findGuardianForChannel(sourceChannel);
111
- if (
112
- localAnchorPrincipalId &&
113
- localSource &&
114
- localSource.contact.principalId === localAnchorPrincipalId
115
- ) {
116
- return {
117
- principalId: localSource.contact.principalId,
118
- address: localSource.channel.address,
119
- displayName: localSource.contact.displayName,
120
- channelType: localSource.channel.type,
121
- source: "source-channel-contact",
122
- };
123
- }
124
- if (localVellum) {
125
- return {
126
- principalId: localAnchorPrincipalId ?? null,
127
- address: localVellum.channel.address,
128
- displayName: localVellum.contact.displayName,
129
- channelType: "vellum",
130
- source: "vellum-anchor",
131
- };
132
- }
133
-
134
- return resolved;
135
- }
@@ -1,99 +0,0 @@
1
- import { beforeEach, describe, expect, mock, test } from "bun:test";
2
-
3
- import type { GuardianDelivery } from "@vellumai/gateway-client";
4
-
5
- let mockGuardians: GuardianDelivery[] | null = null;
6
- let authDisabled = false;
7
-
8
- mock.module("../../../contacts/guardian-delivery-reader.js", () => ({
9
- getGuardianDelivery: async () => mockGuardians,
10
- // Real active-status selector so the auth gate enforces status==="active".
11
- guardianForChannel: (list: GuardianDelivery[], channelType: string) =>
12
- list.find((g) => g.channelType === channelType && g.status === "active"),
13
- }));
14
-
15
- mock.module("../../../config/env.js", () => ({
16
- isHttpAuthDisabled: () => authDisabled,
17
- }));
18
-
19
- import { requireBoundGuardian } from "../require-bound-guardian.js";
20
- import type { AuthContext } from "../types.js";
21
-
22
- function ctx(actorPrincipalId?: string): AuthContext {
23
- return {
24
- subject: "sub",
25
- principalType: "actor",
26
- assistantId: "self",
27
- actorPrincipalId,
28
- scopeProfile: "actor_client_v1",
29
- scopes: new Set(),
30
- policyEpoch: 0,
31
- };
32
- }
33
-
34
- function guardian(principalId: string): GuardianDelivery {
35
- return {
36
- channelType: "vellum",
37
- contactId: "guardian-contact",
38
- principalId,
39
- address: principalId,
40
- status: "active",
41
- };
42
- }
43
-
44
- describe("requireBoundGuardian", () => {
45
- beforeEach(() => {
46
- mockGuardians = null;
47
- authDisabled = false;
48
- });
49
-
50
- test("admits the bound guardian", async () => {
51
- mockGuardians = [guardian("vellum-principal-abc")];
52
- const result = await requireBoundGuardian(ctx("vellum-principal-abc"));
53
- expect(result).toBeNull();
54
- });
55
-
56
- test("denies a non-guardian actor", async () => {
57
- mockGuardians = [guardian("vellum-principal-abc")];
58
- const result = await requireBoundGuardian(ctx("vellum-principal-other"));
59
- expect(result).not.toBeNull();
60
- expect(result!.status).toBe(403);
61
- });
62
-
63
- test("denies when actor principal is missing", async () => {
64
- mockGuardians = [guardian("vellum-principal-abc")];
65
- const result = await requireBoundGuardian(ctx(undefined));
66
- expect(result).not.toBeNull();
67
- expect(result!.status).toBe(403);
68
- });
69
-
70
- test("fails closed on a null list (gateway unreachable)", async () => {
71
- mockGuardians = null;
72
- const result = await requireBoundGuardian(ctx("vellum-principal-abc"));
73
- expect(result).not.toBeNull();
74
- expect(result!.status).toBe(403);
75
- });
76
-
77
- test("denies when no vellum guardian is bound", async () => {
78
- mockGuardians = [];
79
- const result = await requireBoundGuardian(ctx("vellum-principal-abc"));
80
- expect(result).not.toBeNull();
81
- expect(result!.status).toBe(403);
82
- });
83
-
84
- test("denies a non-active (revoked) vellum row matching the actor", async () => {
85
- mockGuardians = [
86
- { ...guardian("vellum-principal-abc"), status: "revoked" },
87
- ];
88
- const result = await requireBoundGuardian(ctx("vellum-principal-abc"));
89
- expect(result).not.toBeNull();
90
- expect(result!.status).toBe(403);
91
- });
92
-
93
- test("dev bypass admits when auth is disabled", async () => {
94
- authDisabled = true;
95
- mockGuardians = null;
96
- const result = await requireBoundGuardian(ctx(undefined));
97
- expect(result).toBeNull();
98
- });
99
- });
@@ -1,52 +0,0 @@
1
- /**
2
- * Derives a local principal's {@link TrustContext} from the gateway guardian
3
- * binding. Fails closed to unknown on a missing or null read.
4
- */
5
-
6
- import type { ChannelId } from "../channels/types.js";
7
- import { getGuardianDelivery } from "../contacts/guardian-delivery-reader.js";
8
- import type { TrustContext } from "../daemon/trust-context.js";
9
- import { canonicalizeInboundIdentity } from "../util/canonicalize-identity.js";
10
-
11
- export interface ResolveLocalPrincipalTrustInput {
12
- actorPrincipalId: string;
13
- sourceChannel: ChannelId;
14
- conversationExternalId: string;
15
- }
16
-
17
- /** Guardian match → guardian ctx; miss or null read → unknown (fail closed). */
18
- export async function resolveLocalPrincipalTrustContext(
19
- input: ResolveLocalPrincipalTrustInput,
20
- ): Promise<TrustContext> {
21
- const unknownContext: TrustContext = {
22
- sourceChannel: input.sourceChannel,
23
- trustClass: "unknown",
24
- requesterExternalUserId: input.actorPrincipalId,
25
- requesterChatId: input.conversationExternalId,
26
- };
27
-
28
- // Fail closed: a null read means the gateway is unreachable — never grant
29
- // guardian on a miss.
30
- const guardians = await getGuardianDelivery({ channelTypes: ["vellum"] });
31
- if (!guardians) return unknownContext;
32
-
33
- const guardian = guardians.find(
34
- (g) => g.principalId === input.actorPrincipalId,
35
- );
36
- if (!guardian) return unknownContext;
37
-
38
- return {
39
- sourceChannel: input.sourceChannel,
40
- trustClass: "guardian",
41
- guardianChatId: guardian.externalChatId ?? input.conversationExternalId,
42
- guardianExternalUserId:
43
- canonicalizeInboundIdentity(input.sourceChannel, guardian.address) ??
44
- undefined,
45
- guardianPrincipalId: guardian.principalId ?? undefined,
46
- // Mirror toTrustContext: with no username the requester identifier is the
47
- // canonical sender id, which for a vellum principal is actorPrincipalId.
48
- requesterIdentifier: input.actorPrincipalId,
49
- requesterExternalUserId: input.actorPrincipalId,
50
- requesterChatId: input.conversationExternalId,
51
- };
52
- }