@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
@@ -14,11 +14,6 @@
14
14
  import type { ChannelId } from "../channels/types.js";
15
15
  import { isHttpAuthDisabled } from "../config/env.js";
16
16
  import { findGuardianForChannel } from "../contacts/contact-store.js";
17
- import {
18
- getGuardianDelivery,
19
- guardianForChannel,
20
- peekCachedGuardianDelivery,
21
- } from "../contacts/guardian-delivery-reader.js";
22
17
  import type { TrustContext } from "../daemon/trust-context.js";
23
18
  import { getLogger } from "../util/logger.js";
24
19
  import { DAEMON_INTERNAL_ASSISTANT_ID } from "./assistant-scope.js";
@@ -50,48 +45,13 @@ export function buildLocalAuthContext(conversationId: string): AuthContext {
50
45
  }
51
46
 
52
47
  /**
53
- * Resolve the local vellum guardian's principalId from the gateway.
48
+ * Look up the local vellum guardian's principalId from the contacts table.
54
49
  *
55
- * The gateway owns guardian binding; this reads it through the cached
56
- * `getGuardianDelivery` reader (PR-3 TTL + single-flight) so hot paths don't
57
- * storm the IPC. Falls back to the local contacts table for the bootstrap /
58
- * first-run window where the gateway has no guardian yet or is unreachable
59
- * (the reader returns `null`).
60
- *
61
- * Returns `undefined` when no vellum guardian binding exists in either source
62
- * (e.g. fresh install before bootstrap). Callers should treat that case as
50
+ * Returns `undefined` when no vellum guardian binding exists (e.g. fresh
51
+ * install before bootstrap). Callers should treat that case as
63
52
  * "not yet available" and either fall back or proceed without a principalId.
64
53
  */
65
- export async function findLocalGuardianPrincipalId(): Promise<
66
- string | undefined
67
- > {
68
- const list = await getGuardianDelivery({ channelTypes: ["vellum"] });
69
- if (list) {
70
- const principalId = guardianForChannel(list, "vellum")?.principalId;
71
- if (principalId) return principalId;
72
- }
73
-
74
- return findLocalGuardianPrincipalIdFromStore();
75
- }
76
-
77
- /**
78
- * Synchronous read of the vellum guardian's principalId for paths that cannot
79
- * await {@link findLocalGuardianPrincipalId} — namely the SSE eager-subscribe
80
- * path (`events-routes`), which registers before the stream is created.
81
- *
82
- * Reads the same gateway-owned binding as the async path via a sync, IO-free
83
- * snapshot of the guardian-delivery cache (kept fresh by the async hot paths
84
- * and event-driven invalidation), so SSE registers the SAME principal the
85
- * send/result routes resolve. Falls back to the local store when the cache is
86
- * cold — the same fallback the async path lands on during bootstrap.
87
- */
88
- export function findLocalGuardianPrincipalIdFromStore(): string | undefined {
89
- const cached = peekCachedGuardianDelivery({ channelTypes: ["vellum"] });
90
- if (cached) {
91
- const principalId = guardianForChannel(cached, "vellum")?.principalId;
92
- if (principalId) return principalId;
93
- }
94
-
54
+ export function findLocalGuardianPrincipalId(): string | undefined {
95
55
  return findGuardianForChannel("vellum")?.contact.principalId ?? undefined;
96
56
  }
97
57
 
@@ -116,35 +76,12 @@ export function findLocalGuardianPrincipalIdFromStore(): string | undefined {
116
76
  * yet (e.g. fresh install before bootstrap); callers must treat this the
117
77
  * same as a missing principal.
118
78
  */
119
- export async function resolveActorPrincipalIdForLocalGuardian(
120
- rawHeader: string | undefined,
121
- ): Promise<string | undefined> {
122
- if (rawHeader !== "dev-bypass" || !isHttpAuthDisabled()) return rawHeader;
123
-
124
- const guardianPrincipalId = await findLocalGuardianPrincipalId();
125
- if (guardianPrincipalId) return guardianPrincipalId;
126
-
127
- log.warn(
128
- "dev-bypass actor principal received but no vellum guardian binding found; returning undefined",
129
- );
130
- return undefined;
131
- }
132
-
133
- /**
134
- * Synchronous variant of {@link resolveActorPrincipalIdForLocalGuardian} for
135
- * the SSE eager-subscribe path, which registers before the response stream is
136
- * created and cannot await. Resolves the guardian from the IO-free gateway
137
- * cache snapshot first (same source the async path reads), falling back to the
138
- * local store when the cache is cold — so SSE registers the SAME principal the
139
- * send/result routes resolve and host-proxy targeting matches the same-user
140
- * client even when the local contact row is stale.
141
- */
142
- export function resolveActorPrincipalIdForLocalGuardianSync(
79
+ export function resolveActorPrincipalIdForLocalGuardian(
143
80
  rawHeader: string | undefined,
144
81
  ): string | undefined {
145
82
  if (rawHeader !== "dev-bypass" || !isHttpAuthDisabled()) return rawHeader;
146
83
 
147
- const guardianPrincipalId = findLocalGuardianPrincipalIdFromStore();
84
+ const guardianPrincipalId = findLocalGuardianPrincipalId();
148
85
  if (guardianPrincipalId) return guardianPrincipalId;
149
86
 
150
87
  log.warn(
@@ -165,12 +102,12 @@ export function resolveActorPrincipalIdForLocalGuardianSync(
165
102
  * bootstrap), falls back to a minimal guardian context so the local
166
103
  * user is not incorrectly denied.
167
104
  */
168
- export async function resolveLocalTrustContext(
105
+ export function resolveLocalTrustContext(
169
106
  sourceChannel: ChannelId = "vellum",
170
- ): Promise<TrustContext> {
107
+ ): TrustContext {
171
108
  const assistantId = DAEMON_INTERNAL_ASSISTANT_ID;
172
109
 
173
- const guardianPrincipalId = await findLocalGuardianPrincipalId();
110
+ const guardianPrincipalId = findLocalGuardianPrincipalId();
174
111
  if (guardianPrincipalId) {
175
112
  const trustCtx = resolveTrustContext({
176
113
  assistantId,
@@ -202,12 +139,10 @@ export async function resolveLocalTrustContext(
202
139
  * downstream code to resolve guardian context using the same
203
140
  * `authContext.actorPrincipalId` path as HTTP sessions.
204
141
  */
205
- export async function resolveLocalAuthContext(
206
- conversationId: string,
207
- ): Promise<AuthContext> {
142
+ export function resolveLocalAuthContext(conversationId: string): AuthContext {
208
143
  const authContext = buildLocalAuthContext(conversationId);
209
144
 
210
- const guardianPrincipalId = await findLocalGuardianPrincipalId();
145
+ const guardianPrincipalId = findLocalGuardianPrincipalId();
211
146
  if (guardianPrincipalId) {
212
147
  return { ...authContext, actorPrincipalId: guardianPrincipalId };
213
148
  }
@@ -229,15 +229,6 @@ export function getByConversation(
229
229
  * /v1/host-browser-result, /v1/host-app-control-result, or
230
230
  * /v1/host-transfer-result after completing the operation, get a 404, and the
231
231
  * proxy timer would fire with a spurious timeout error.
232
- *
233
- * `question` interactions are also skipped: a new message supersedes an open
234
- * ask_question by steering to it (see the enqueue path in
235
- * conversation-routes.ts), which aborts the parked turn and settles the
236
- * question via its abort signal. Clearing the entry here instead would drop it
237
- * without settling the prompt's Promise (questions carry no `rpcResolve`
238
- * fallback like secrets do) and would strip the steer of the entry it needs to
239
- * fire — which can co-occur with a confirmation, since one model response can
240
- * open both tools concurrently.
241
232
  */
242
233
  export function removeByConversation(
243
234
  conversationId: string,
@@ -253,8 +244,7 @@ export function removeByConversation(
253
244
  interaction.kind !== "host_browser" &&
254
245
  interaction.kind !== "host_app_control" &&
255
246
  interaction.kind !== "host_transfer" &&
256
- interaction.kind !== "acp_confirmation" &&
257
- interaction.kind !== "question"
247
+ interaction.kind !== "acp_confirmation"
258
248
  ) {
259
249
  // resolve() clears the stored timer and detaches abort listeners.
260
250
  resolve(requestId, state);
@@ -10,7 +10,6 @@
10
10
 
11
11
  import { beforeEach, describe, expect, mock, test } from "bun:test";
12
12
 
13
- import type { GuardianDelivery } from "@vellumai/gateway-client";
14
13
  import { IpcCallError } from "@vellumai/gateway-client/ipc-client";
15
14
 
16
15
  type IpcCall = { method: string; params?: Record<string, unknown> };
@@ -74,16 +73,8 @@ mock.module("../../channel-verification-service.js", () => ({
74
73
  getGuardianBinding: mock(() => guardianBinding),
75
74
  }));
76
75
 
77
- // Contact-store lookup that resolves the guardian's channel to downgrade. The
78
- // channel carries the type/address/externalChatId the gateway delivery is
79
- // matched against (see deliveryForChannel).
80
- let contactChannel: {
81
- id: string;
82
- status: string;
83
- type: string;
84
- address: string;
85
- externalChatId: string;
86
- } | null = null;
76
+ // Contact-store lookup that resolves the guardian's channel to downgrade.
77
+ let contactChannel: { id: string; status: string } | null = null;
87
78
  const actualContactStore = await import("../../../contacts/contact-store.js");
88
79
  mock.module("../../../contacts/contact-store.js", () => ({
89
80
  ...actualContactStore,
@@ -92,20 +83,6 @@ mock.module("../../../contacts/contact-store.js", () => ({
92
83
  ),
93
84
  }));
94
85
 
95
- // Gateway delivery (ACL source of truth). The revoke gate relays only when the
96
- // matching delivery is live (active/pending/unverified); already-revoked or a
97
- // missing delivery short-circuits the relay.
98
- let guardianDeliveries: GuardianDelivery[] | null = null;
99
- mock.module("../../../contacts/guardian-delivery-reader.js", () => ({
100
- getGuardianDelivery: mock(async (input?: { channelTypes?: string[] }) => {
101
- if (guardianDeliveries == null) return null;
102
- if (!input?.channelTypes) return guardianDeliveries;
103
- return guardianDeliveries.filter((g) =>
104
- input.channelTypes!.includes(g.channelType),
105
- );
106
- }),
107
- }));
108
-
109
86
  // Guard: the contact-channel ACL write moves to the gateway relay and must
110
87
  // never run locally. The assistant-owned guardian-binding teardown
111
88
  // (revokeGuardianBinding) still runs locally — assert it is invoked.
@@ -145,24 +122,7 @@ describe("verification revoke relay", () => {
145
122
  guardianExternalUserId: "guardian-user",
146
123
  guardianDeliveryChatId: "chat-1",
147
124
  };
148
- contactChannel = {
149
- id: "ch1",
150
- status: "active",
151
- type: "telegram",
152
- address: "guardian-user",
153
- externalChatId: "chat-1",
154
- };
155
- // Gateway delivery is live by default, so the revoke relay fires.
156
- guardianDeliveries = [
157
- {
158
- channelType: "telegram",
159
- contactId: "c1",
160
- address: "guardian-user",
161
- externalChatId: "chat-1",
162
- status: "active",
163
- verifiedAt: 1700000000,
164
- },
165
- ];
125
+ contactChannel = { id: "ch1", status: "active" };
166
126
  ipcCallPersistentMock.mockClear();
167
127
  cancelOutboundMock.mockClear();
168
128
  revokePendingSessionsMock.mockClear();
@@ -303,19 +263,8 @@ describe("verification revoke relay", () => {
303
263
  expect(result.bound).toBe(false);
304
264
  });
305
265
 
306
- test("skips the relay when the gateway delivery is already revoked", async () => {
307
- // The gateway (source of truth) already shows the channel revoked, so the
308
- // redundant relay is skipped even though session/binding teardown runs.
309
- guardianDeliveries = [
310
- {
311
- channelType: "telegram",
312
- contactId: "c1",
313
- address: "guardian-user",
314
- externalChatId: "chat-1",
315
- status: "revoked",
316
- verifiedAt: 1700000000,
317
- },
318
- ];
266
+ test("skips the relay when the resolved channel is already revoked", async () => {
267
+ contactChannel = { id: "ch1", status: "revoked" };
319
268
 
320
269
  await revokeHandler({ body: { channel: "telegram" } });
321
270
 
@@ -24,7 +24,7 @@ mock.module("../../../daemon/handlers/config-channels.js", () => ({
24
24
  verifyTrustedContactCalls.push([contactChannelId, assistantId]);
25
25
  return verifyTrustedContactImpl(contactChannelId, assistantId);
26
26
  },
27
- createInboundChallenge: async () => ({ success: true }),
27
+ createInboundChallenge: () => ({ success: true }),
28
28
  getVerificationStatus: () => ({ success: true }),
29
29
  revokeVerificationForChannel: () => ({ success: true }),
30
30
  }));
@@ -25,7 +25,6 @@ interface StubConversation {
25
25
  handleSurfaceActionThrows?: Error;
26
26
  handleSurfaceUndoCalled?: boolean;
27
27
  handleSurfaceUndoThrows?: Error;
28
- trustContext?: { trustClass: string; sourceChannel: string };
29
28
  surfaceActionCalls: Array<{
30
29
  surfaceId: string;
31
30
  actionId: string;
@@ -44,47 +43,6 @@ const findBySurfaceCalls: string[] = [];
44
43
  const getOrCreateCalls: string[] = [];
45
44
  const rawGetCalls: Array<{ sql: string; params: unknown[] }> = [];
46
45
 
47
- // Gateway guardian-delivery list (shared by the route's dev-bypass lookup and
48
- // the local-principal-trust mapper): null = unreachable, [] = no guardian.
49
- let mockGuardianList: Array<Record<string, unknown>> | null = [];
50
- let httpAuthDisabled = false;
51
-
52
- // Stub for the shared reset-drift helper. The route under test only consumes
53
- // its result (a guardian TrustContext or null); the gate itself is covered in
54
- // runtime/__tests__/guardian-vellum-migration.test.ts. Tests set
55
- // `mockReResolve` per case and read `reResolveCalls` to assert routing.
56
- const reResolveCalls: string[] = [];
57
- let mockReResolve: { trustClass: string; sourceChannel: string } | null = null;
58
-
59
- mock.module("../../../contacts/guardian-delivery-reader.js", () => ({
60
- getGuardianDelivery: (_input?: { channelTypes?: string[] }) =>
61
- Promise.resolve(mockGuardianList),
62
- peekCachedGuardianDelivery: () => mockGuardianList ?? undefined,
63
- guardianForChannel: (
64
- list: Array<Record<string, unknown>>,
65
- channelType: string,
66
- ) => list.find((g) => g.channelType === channelType && g.status === "active"),
67
- }));
68
-
69
- mock.module("../../../contacts/contact-store.js", () => ({
70
- findGuardianForChannel: (_channelType: string) => null,
71
- findContactByAddress: () => null,
72
- }));
73
-
74
- mock.module("../../../config/env.js", () => ({
75
- isHttpAuthDisabled: () => httpAuthDisabled,
76
- }));
77
-
78
- mock.module("../../guardian-vellum-migration.js", () => ({
79
- reResolveTrustOnResetDrift: async (
80
- incomingPrincipalId: string,
81
- _sourceChannel: string,
82
- ) => {
83
- reResolveCalls.push(incomingPrincipalId);
84
- return mockReResolve;
85
- },
86
- }));
87
-
88
46
  mock.module("../../../daemon/conversation-registry.js", () => ({
89
47
  findConversation: (id: string) => {
90
48
  findConvCalls.push(id);
@@ -164,9 +122,6 @@ function makeStub(id: string): StubConversation {
164
122
  stub.handleSurfaceUndoCalled = true;
165
123
  if (stub.handleSurfaceUndoThrows) throw stub.handleSurfaceUndoThrows;
166
124
  },
167
- setTrustContext: (ctx: { trustClass: string; sourceChannel: string }) => {
168
- stub.trustContext = ctx;
169
- },
170
125
  });
171
126
  return stub;
172
127
  }
@@ -184,10 +139,6 @@ beforeEach(() => {
184
139
  findBySurfaceCalls.length = 0;
185
140
  getOrCreateCalls.length = 0;
186
141
  rawGetCalls.length = 0;
187
- mockGuardianList = [];
188
- httpAuthDisabled = false;
189
- reResolveCalls.length = 0;
190
- mockReResolve = null;
191
142
  });
192
143
 
193
144
  // ---------------------------------------------------------------------------
@@ -386,30 +337,6 @@ describe("triggerSurfaceAction handler", () => {
386
337
  ]);
387
338
  });
388
339
 
389
- test("resolves dev-bypass to the guardian principal before threading the turn", async () => {
390
- httpAuthDisabled = true;
391
- mockGuardianList = [guardianDelivery(GUARDIAN_PRINCIPAL)];
392
- const live = makeStub("conv-dev-thread");
393
- memoryBySurface = live;
394
-
395
- const handler = findHandler("triggerSurfaceAction");
396
- await handler({
397
- body: { surfaceId: "surf-dt", actionId: "act-dt" },
398
- headers: { "x-vellum-actor-principal-id": "dev-bypass" },
399
- });
400
-
401
- // dev-bypass is translated so the surface turn matches the SSE host-proxy
402
- // client's registered guardian principal (CU/app-control same-actor check).
403
- expect(live.surfaceActionCalls).toEqual([
404
- {
405
- surfaceId: "surf-dt",
406
- actionId: "act-dt",
407
- data: undefined,
408
- sourceActorPrincipalId: GUARDIAN_PRINCIPAL,
409
- },
410
- ]);
411
- });
412
-
413
340
  test("propagates accepted=false rejection as BadRequestError", async () => {
414
341
  const live = makeStub("conv-reject");
415
342
  live.handleSurfaceActionResult = {
@@ -435,120 +362,6 @@ describe("triggerSurfaceAction handler", () => {
435
362
  });
436
363
  });
437
364
 
438
- // ---------------------------------------------------------------------------
439
- // Trust context resolution
440
- // ---------------------------------------------------------------------------
441
-
442
- const GUARDIAN_PRINCIPAL = "principal-guardian";
443
- // Daemon-minted vellum-principal-* ids: the DB-reset drift signature. The
444
- // gateway rebinds to a fresh id while the client still holds a JWT for the old.
445
- const VELLUM_PRINCIPAL_OLD = "vellum-principal-old";
446
- const VELLUM_PRINCIPAL_NEW = "vellum-principal-new";
447
-
448
- function guardianDelivery(principalId: string): Record<string, unknown> {
449
- return {
450
- channelType: "vellum",
451
- contactId: "contact-1",
452
- principalId,
453
- address: "guardian-address",
454
- externalChatId: "guardian-chat",
455
- status: "active",
456
- };
457
- }
458
-
459
- // A guardian TrustContext the stubbed helper hands back on a recovered drift.
460
- function guardianCtx(): { trustClass: string; sourceChannel: string } {
461
- return { trustClass: "guardian", sourceChannel: "vellum" };
462
- }
463
-
464
- describe("triggerSurfaceAction trust context", () => {
465
- test("guardian principal → guardian from the gateway binding, helper not called", async () => {
466
- mockGuardianList = [guardianDelivery(GUARDIAN_PRINCIPAL)];
467
- const live = makeStub("conv-guardian");
468
- memoryBySurface = live;
469
-
470
- const handler = findHandler("triggerSurfaceAction");
471
- await handler({
472
- body: { surfaceId: "surf-g", actionId: "act-g" },
473
- headers: { "x-vellum-actor-principal-id": GUARDIAN_PRINCIPAL },
474
- });
475
-
476
- expect(live.trustContext?.trustClass).toBe("guardian");
477
- expect(live.trustContext?.sourceChannel).toBe("vellum");
478
- // First-pass resolve already granted guardian, so the drift helper is skipped.
479
- expect(reResolveCalls).toEqual([]);
480
- });
481
-
482
- test("unknown principal: helper consulted, null result stays unknown (fail closed)", async () => {
483
- mockGuardianList = [guardianDelivery(GUARDIAN_PRINCIPAL)];
484
- mockReResolve = null;
485
- const live = makeStub("conv-unknown");
486
- memoryBySurface = live;
487
-
488
- const handler = findHandler("triggerSurfaceAction");
489
- await handler({
490
- body: { surfaceId: "surf-u", actionId: "act-u" },
491
- headers: { "x-vellum-actor-principal-id": VELLUM_PRINCIPAL_OLD },
492
- });
493
-
494
- expect(reResolveCalls).toEqual([VELLUM_PRINCIPAL_OLD]);
495
- expect(live.trustContext?.trustClass).toBe("unknown");
496
- });
497
-
498
- test("reset drift: helper returns guardian → route adopts it", async () => {
499
- mockGuardianList = [guardianDelivery(VELLUM_PRINCIPAL_NEW)];
500
- mockReResolve = guardianCtx();
501
- const live = makeStub("conv-drift");
502
- memoryBySurface = live;
503
-
504
- const handler = findHandler("triggerSurfaceAction");
505
- await handler({
506
- body: { surfaceId: "surf-d", actionId: "act-d" },
507
- headers: { "x-vellum-actor-principal-id": VELLUM_PRINCIPAL_OLD },
508
- });
509
-
510
- expect(reResolveCalls).toEqual([VELLUM_PRINCIPAL_OLD]);
511
- expect(live.trustContext?.trustClass).toBe("guardian");
512
- });
513
-
514
- test("dev-bypass resolves the real guardian principal from the gateway, helper not called", async () => {
515
- httpAuthDisabled = true;
516
- mockGuardianList = [guardianDelivery(GUARDIAN_PRINCIPAL)];
517
- const live = makeStub("conv-dev");
518
- memoryBySurface = live;
519
-
520
- const handler = findHandler("triggerSurfaceAction");
521
- await handler({
522
- body: { surfaceId: "surf-dev", actionId: "act-dev" },
523
- headers: { "x-vellum-actor-principal-id": "dev-bypass" },
524
- });
525
-
526
- // The synthetic dev-bypass principal is translated to the real guardian,
527
- // yielding a guardian trust context without consulting the drift helper.
528
- expect(live.trustContext?.trustClass).toBe("guardian");
529
- expect(reResolveCalls).toEqual([]);
530
- });
531
-
532
- test("dev-bypass with an empty gateway: helper null result → unknown (fail closed)", async () => {
533
- httpAuthDisabled = true;
534
- // The gateway has no active binding, so dev-bypass cannot translate to a
535
- // real guardian; the first-pass resolve is unknown and the helper, returning
536
- // null, leaves trust unknown.
537
- mockGuardianList = [];
538
- mockReResolve = null;
539
- const live = makeStub("conv-dev-fallback");
540
- memoryBySurface = live;
541
-
542
- const handler = findHandler("triggerSurfaceAction");
543
- await handler({
544
- body: { surfaceId: "surf-devf", actionId: "act-devf" },
545
- headers: { "x-vellum-actor-principal-id": "dev-bypass" },
546
- });
547
-
548
- expect(live.trustContext?.trustClass).toBe("unknown");
549
- });
550
- });
551
-
552
365
  // ---------------------------------------------------------------------------
553
366
  // undoSurfaceAction
554
367
  // ---------------------------------------------------------------------------
@@ -92,7 +92,7 @@ async function handleBrowserExecute({
92
92
  // register with (dev-bypass otherwise mismatches).
93
93
  const headerActor =
94
94
  headers["x-vellum-actor-principal-id"]?.trim() || undefined;
95
- const sourceActorPrincipalId = await resolveActorPrincipalIdForLocalGuardian(
95
+ const sourceActorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
96
96
  conversation?.getTurnActorPrincipalId() ?? headerActor,
97
97
  );
98
98
 
@@ -8,16 +8,13 @@
8
8
  * requester.
9
9
  *
10
10
  * This sweep operates on the unified canonical domain
11
- * (`canonical_guardian_requests`). On expiry it transitions the request status
12
- * (the single source of truth), withdraws the approval cards on every surface,
13
- * notifies the requester that their request expired, and releases any in-memory
14
- * pending interaction. Requester notices are delivered straight to the
15
- * requester's channel — not the guardian-facing notification pipeline — and the
16
- * guardian stays passive, since the withdrawn card already reflects expiry.
11
+ * (`canonical_guardian_requests`) and does not auto-deny pending interactions
12
+ * or deliver channel notices the canonical request status transition is the
13
+ * single source of truth, and consumers (resolvers, clients polling prompts)
14
+ * observe the expired status directly.
17
15
  */
18
16
 
19
17
  import { withdrawGuardianRequestCards } from "../../approvals/guardian-card-withdrawal.js";
20
- import { notifyExpiredGuardianRequest } from "../../approvals/guardian-expiry-notifier.js";
21
18
  import {
22
19
  listCanonicalGuardianRequests,
23
20
  resolveCanonicalGuardianRequest,
@@ -42,7 +39,7 @@ let sweepInProgress = false;
42
39
  * concurrent decision that wins the race is never overwritten by the
43
40
  * sweep. Returns the count of requests transitioned to expired.
44
41
  */
45
- export async function sweepExpiredCanonicalGuardianRequests(): Promise<number> {
42
+ async function sweepExpiredCanonicalGuardianRequests(): Promise<number> {
46
43
  const pending = listCanonicalGuardianRequests({ status: "pending" });
47
44
  const now = Date.now();
48
45
  let expiredCount = 0;
@@ -79,11 +76,6 @@ export async function sweepExpiredCanonicalGuardianRequests(): Promise<number> {
79
76
  request: resolved,
80
77
  status: "expired",
81
78
  });
82
-
83
- // Notify the requester their request expired and release any in-memory
84
- // pending interaction. Best-effort and non-throwing, like the card
85
- // withdrawal above.
86
- await notifyExpiredGuardianRequest(resolved);
87
79
  }
88
80
  }
89
81
 
@@ -179,7 +179,7 @@ export async function handleCreateVerificationSession({
179
179
  }
180
180
 
181
181
  // Inbound challenge path
182
- const result = await createInboundChallenge(channel, rebind, conversationId);
182
+ const result = createInboundChallenge(channel, rebind, conversationId);
183
183
  if (!result.success) {
184
184
  throw new BadRequestError(
185
185
  (result as { message?: string }).message ??
@@ -192,12 +192,12 @@ export async function handleCreateVerificationSession({
192
192
  /**
193
193
  * GET /v1/channel-verification-sessions/status
194
194
  */
195
- async function handleGetVerificationStatus({
195
+ function handleGetVerificationStatus({
196
196
  queryParams = {},
197
197
  body = {},
198
198
  }: RouteHandlerArgs) {
199
199
  const channel = (queryParams.channel ?? (body as Record<string, unknown>).channel) as ChannelId | undefined;
200
- return await getVerificationStatus(channel);
200
+ return getVerificationStatus(channel);
201
201
  }
202
202
 
203
203
  /**
@@ -17,6 +17,8 @@ import { IpcCallError } from "@vellumai/gateway-client/ipc-client";
17
17
  import { z } from "zod";
18
18
 
19
19
  import {
20
+ getAssistantContactMetadata,
21
+ getContact,
20
22
  listContacts,
21
23
  mergeContacts,
22
24
  searchContacts,
@@ -137,10 +139,9 @@ const contactSchema = z.object({
137
139
 
138
140
  /**
139
141
  * Relay a non-search contact list read to the gateway (source of truth for ACL
140
- * fields). Shared by the GET `contacts` list and the `search_contacts`
141
- * no-filter case so both serve gateway-sourced data consistently. Fail-closed:
142
- * a relay failure surfaces as an error rather than reading ACL from the
143
- * assistant DB.
142
+ * fields), falling back to the assistant DB on IPC failure. Shared by the GET
143
+ * `contacts` list and the `search_contacts` no-filter case so both serve
144
+ * gateway-sourced data consistently.
144
145
  */
145
146
  async function relayListContacts(
146
147
  limit: number,
@@ -157,7 +158,15 @@ async function relayListContacts(
157
158
  contacts: contacts.map(prepareContactResponse),
158
159
  };
159
160
  } catch (err) {
160
- rethrowGatewayError(err);
161
+ log.warn(
162
+ { err },
163
+ "relayListContacts: gateway relay failed; falling back to assistant DB",
164
+ );
165
+ const contacts = listContacts(limit, role);
166
+ return {
167
+ ok: true,
168
+ contacts: contacts.map(prepareContactResponse),
169
+ };
161
170
  }
162
171
  }
163
172
 
@@ -231,10 +240,25 @@ export async function handleGetContact(contactId: string) {
231
240
  assistantMetadata: assistantMetadata ?? undefined,
232
241
  };
233
242
  } catch (err) {
234
- // A clean not-found is a real 404. Any other relay failure fails closed
235
- // rather than reading ACL from the assistant DB.
243
+ // A clean not-found is a real 404 don't fall back or mask it.
236
244
  if (err instanceof NotFoundError) throw err;
237
- rethrowGatewayError(err);
245
+ log.warn(
246
+ { err, contactId },
247
+ "handleGetContact: gateway relay failed; falling back to assistant DB",
248
+ );
249
+ const contact = getContact(contactId);
250
+ if (!contact) {
251
+ throw new NotFoundError(`Contact "${contactId}" not found`);
252
+ }
253
+ const assistantMeta =
254
+ contact.contactType === "assistant"
255
+ ? getAssistantContactMetadata(contact.id)
256
+ : undefined;
257
+ return {
258
+ ok: true,
259
+ contact: prepareContactResponse(contact),
260
+ assistantMetadata: assistantMeta ?? undefined,
261
+ };
238
262
  }
239
263
  }
240
264
 
@@ -9,10 +9,10 @@
9
9
  import { v4 as uuid } from "uuid";
10
10
  import { z } from "zod";
11
11
 
12
+ import { findConversation } from "../../daemon/conversation-registry.js";
12
13
  import { clearAllConversations as clearAllActive } from "../../daemon/handlers/conversations.js";
13
14
  import { formatJson, formatMarkdown } from "../../export/formatter.js";
14
15
  import { ipcCall as ipcCallGateway } from "../../ipc/gateway-client.js";
15
- import { isConversationProcessing } from "../../memory/conversation-crud.js";
16
16
  import {
17
17
  addMessage,
18
18
  createConversation,
@@ -53,9 +53,10 @@ function handleListCli({ body = {} }: RouteHandlerArgs) {
53
53
  id: c.id,
54
54
  title: c.title,
55
55
  updatedAt: c.updatedAt,
56
- // Checks in-memory flag first (hot path), falls back to the
57
- // persisted `processing_started_at` column for cold conversations.
58
- isProcessing: isConversationProcessing(c.id),
56
+ // `isProcessing` mirrors `Conversation.isProcessing()` from the
57
+ // in-memory daemon store true when the agent loop is mid-turn.
58
+ // Rows not currently in memory (cold / evicted) report `false`.
59
+ isProcessing: findConversation(c.id)?.isProcessing() ?? false,
59
60
  })),
60
61
  };
61
62
  }