@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,87 +0,0 @@
1
- import { and, asc, eq, gt, or } from "drizzle-orm";
2
- import { v4 as uuid } from "uuid";
3
-
4
- import { getCachedShareAnalytics } from "../platform/consent-cache.js";
5
- import { getTelemetryDb } from "./db-connection.js";
6
- import { watchdogEvents } from "./schema.js";
7
-
8
- /**
9
- * Input for one `watchdog` telemetry event. Metadata only — never conversation
10
- * content. `value` and `detail` are optional; omitting both yields the minimal
11
- * event (check_name only). `detail` is a JSON bag serialized to text on persist
12
- * and forwarded verbatim on flush.
13
- */
14
- export interface WatchdogEventRecord {
15
- checkName: string;
16
- /** Measured magnitude (block ms, idle ms, ...). Null when the check carries no scalar. */
17
- value?: number | null;
18
- /** Open JSON bag for extra fields (reason codes, secondary numbers, ...). */
19
- detail?: Record<string, unknown> | null;
20
- }
21
-
22
- /** A persisted watchdog event row. */
23
- export interface WatchdogEvent {
24
- id: string;
25
- createdAt: number;
26
- checkName: string;
27
- value: number | null;
28
- /** Raw `detail` JSON text from the row, or null. Parsed by the reporter on flush. */
29
- detail: string | null;
30
- }
31
-
32
- /**
33
- * Record a `watchdog` telemetry event for a watchdog check firing. No-ops when
34
- * usage data collection is disabled (the event is dropped to honor the opt-out,
35
- * matching the rest of telemetry) — so opt-out rows never exist and the
36
- * reporter's standard 0 watermark default is safe.
37
- */
38
- export function recordWatchdogEvent(record: WatchdogEventRecord): void {
39
- if (!getCachedShareAnalytics()) return;
40
- const db = getTelemetryDb();
41
- if (!db) return;
42
- db.insert(watchdogEvents)
43
- .values({
44
- id: uuid(),
45
- createdAt: Date.now(),
46
- checkName: record.checkName,
47
- value: record.value ?? null,
48
- detail: record.detail != null ? JSON.stringify(record.detail) : null,
49
- })
50
- .run();
51
- }
52
-
53
- /**
54
- * Query watchdog events that haven't been reported to telemetry yet.
55
- * Uses a compound cursor (createdAt + id) for reliable watermarking.
56
- */
57
- export function queryUnreportedWatchdogEvents(
58
- afterCreatedAt: number,
59
- afterId: string | undefined,
60
- limit: number,
61
- ): WatchdogEvent[] {
62
- const db = getTelemetryDb();
63
- if (!db) return [];
64
- return db
65
- .select({
66
- id: watchdogEvents.id,
67
- createdAt: watchdogEvents.createdAt,
68
- checkName: watchdogEvents.checkName,
69
- value: watchdogEvents.value,
70
- detail: watchdogEvents.detail,
71
- })
72
- .from(watchdogEvents)
73
- .where(
74
- afterId
75
- ? or(
76
- gt(watchdogEvents.createdAt, afterCreatedAt),
77
- and(
78
- eq(watchdogEvents.createdAt, afterCreatedAt),
79
- gt(watchdogEvents.id, afterId),
80
- ),
81
- )
82
- : gt(watchdogEvents.createdAt, afterCreatedAt),
83
- )
84
- .orderBy(asc(watchdogEvents.createdAt), asc(watchdogEvents.id))
85
- .limit(limit)
86
- .all();
87
- }
@@ -1,118 +0,0 @@
1
- /**
2
- * Shared control surface for the memory jobs worker *process* — the detached
3
- * OS process whose entry point is `worker-process.ts`.
4
- *
5
- * Both the `assistant memory worker` CLI and the daemon lifecycle (when
6
- * `memory.worker.enabled` is set) need to probe, spawn, and stop this process,
7
- * so the PID-file bookkeeping lives here in one place.
8
- */
9
-
10
- import { existsSync, readFileSync, unlinkSync } from "node:fs";
11
-
12
- import { getMemoryWorkerPidPath } from "../util/platform.js";
13
-
14
- export interface MemoryWorkerStatus {
15
- status: "running" | "not_running";
16
- pid?: number;
17
- }
18
-
19
- /**
20
- * Inspect the PID file to determine whether the worker process is alive.
21
- * A stale PID file (pointing at a dead process) is cleaned up and reported
22
- * as not_running.
23
- */
24
- export function probeMemoryWorker(): MemoryWorkerStatus {
25
- const pidPath = getMemoryWorkerPidPath();
26
- if (!existsSync(pidPath)) return { status: "not_running" };
27
-
28
- const raw = readFileSync(pidPath, "utf-8").trim();
29
- const pid = parseInt(raw, 10);
30
- if (!Number.isFinite(pid) || pid <= 0) return { status: "not_running" };
31
-
32
- try {
33
- process.kill(pid, 0);
34
- return { status: "running", pid };
35
- } catch (err: unknown) {
36
- if (
37
- err &&
38
- typeof err === "object" &&
39
- "code" in err &&
40
- err.code === "ESRCH"
41
- ) {
42
- // Stale PID file — clean it up.
43
- try {
44
- unlinkSync(pidPath);
45
- } catch {
46
- // best-effort
47
- }
48
- return { status: "not_running" };
49
- }
50
- throw err;
51
- }
52
- }
53
-
54
- export class MemoryWorkerSpawnError extends Error {}
55
-
56
- /**
57
- * Spawn the memory worker as a detached background process.
58
- *
59
- * If a worker is already running, returns its PID with `alreadyRunning: true`
60
- * rather than spawning a second one. Throws {@link MemoryWorkerSpawnError} if
61
- * the child is spawned but never writes its PID file (i.e. failed to start).
62
- */
63
- export async function spawnMemoryWorkerProcess(): Promise<{
64
- pid: number;
65
- alreadyRunning: boolean;
66
- }> {
67
- const current = probeMemoryWorker();
68
- if (current.status === "running" && current.pid != null) {
69
- return { pid: current.pid, alreadyRunning: true };
70
- }
71
-
72
- const pidPath = getMemoryWorkerPidPath();
73
- const entry = new URL("./worker-process.ts", import.meta.url);
74
-
75
- // Spawn detached so the worker survives the spawning process exiting.
76
- const child = Bun.spawn({
77
- cmd: ["bun", "run", entry.pathname],
78
- stdio: ["ignore", "ignore", "ignore"],
79
- detached: true,
80
- });
81
-
82
- // Unreference so the spawning process doesn't wait for the child.
83
- child.unref();
84
-
85
- // Wait briefly for the PID file to appear (the worker writes it on startup).
86
- let pidWritten = false;
87
- for (let i = 0; i < 10; i++) {
88
- await Bun.sleep(100);
89
- if (existsSync(pidPath)) {
90
- pidWritten = true;
91
- break;
92
- }
93
- }
94
-
95
- if (!pidWritten) {
96
- throw new MemoryWorkerSpawnError(
97
- "Memory worker was spawned but PID file did not appear within 1s",
98
- );
99
- }
100
-
101
- const pid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
102
- return { pid, alreadyRunning: false };
103
- }
104
-
105
- /**
106
- * Send SIGTERM to the worker process if it is actually running.
107
- *
108
- * Returns the status observed before signalling, so callers can report
109
- * whether anything was stopped. Only throws if `process.kill` itself fails
110
- * (e.g. EPERM) — a not-running worker is a no-op.
111
- */
112
- export function stopMemoryWorkerProcess(): MemoryWorkerStatus {
113
- const current = probeMemoryWorker();
114
- if (current.status === "running" && current.pid != null) {
115
- process.kill(current.pid, "SIGTERM");
116
- }
117
- return current;
118
- }
@@ -1,72 +0,0 @@
1
- /**
2
- * Standalone entry point for the memory jobs worker as its own OS process.
3
- *
4
- * Spawned by `assistant memory worker start`. Loads config, starts the
5
- * worker loop, writes a PID file, and stays alive until SIGTERM/SIGINT.
6
- *
7
- * The worker's internal `setTimeout` calls `.unref()`, which is correct
8
- * inside the daemon (don't keep the daemon alive for the worker) but would
9
- * cause this standalone process to exit immediately. A ref'd keep-alive
10
- * interval prevents that.
11
- */
12
-
13
- import { existsSync, unlinkSync, writeFileSync } from "node:fs";
14
-
15
- import { getConfig } from "../config/loader.js";
16
- import { getLogger } from "../util/logger.js";
17
- import { getMemoryWorkerPidPath } from "../util/platform.js";
18
- import { startInProcessMemoryJobsWorker } from "./jobs-worker.js";
19
-
20
- const log = getLogger("memory-worker-process");
21
-
22
- function cleanupPidFile(): void {
23
- const pidPath = getMemoryWorkerPidPath();
24
- try {
25
- if (existsSync(pidPath)) unlinkSync(pidPath);
26
- } catch {
27
- // best-effort
28
- }
29
- }
30
-
31
- async function main(): Promise<void> {
32
- const config = getConfig();
33
- const pidPath = getMemoryWorkerPidPath();
34
-
35
- if (config.memory.enabled === false) {
36
- log.info("Memory is disabled in config; worker process exiting");
37
- process.exit(0);
38
- }
39
-
40
- // Write PID file so `status` and `stop` can find us.
41
- writeFileSync(pidPath, String(process.pid), { flag: "w" });
42
- log.info({ pid: process.pid, pidPath }, "Memory worker process started");
43
-
44
- const worker = startInProcessMemoryJobsWorker();
45
-
46
- // Keep-alive: the worker's setTimeout timers are unref'd, so without
47
- // this interval the process would exit immediately.
48
- const keepAlive = setInterval(() => {}, 60_000);
49
-
50
- const shutdown = (signal: string) => {
51
- log.info({ signal }, "Memory worker process shutting down");
52
- worker.stop();
53
- clearInterval(keepAlive);
54
- cleanupPidFile();
55
- process.exit(0);
56
- };
57
-
58
- process.on("SIGTERM", () => shutdown("SIGTERM"));
59
- process.on("SIGINT", () => shutdown("SIGINT"));
60
-
61
- // Clean up if the process exits unexpectedly through any other path.
62
- process.on("exit", () => {
63
- worker.stop();
64
- cleanupPidFile();
65
- });
66
- }
67
-
68
- void main().catch((err) => {
69
- log.error({ err }, "Memory worker process failed to start");
70
- cleanupPidFile();
71
- process.exit(1);
72
- });
@@ -1,114 +0,0 @@
1
- /**
2
- * Tests for getConnectedChannels connectivity resolution.
3
- *
4
- * Connectivity must mirror destination-resolver's `resolveGuardian`:
5
- * gateway-first, with a LOCAL contacts fallback on ANY per-channel no-match
6
- * (gateway list null OR no active gateway entry for the channel). This keeps a
7
- * channel from being marked connected when it can't be delivered (and
8
- * vice-versa).
9
- */
10
-
11
- import { beforeEach, describe, expect, mock, test } from "bun:test";
12
-
13
- import type { GuardianDelivery } from "@vellumai/gateway-client";
14
-
15
- mock.module("../../util/logger.js", () => ({
16
- getLogger: () =>
17
- new Proxy({} as Record<string, unknown>, { get: () => () => {} }),
18
- truncateForLog: (value: string) => value,
19
- }));
20
-
21
- let deliverableChannels: string[] = [];
22
- let gatewayGuardians: GuardianDelivery[] | null = null;
23
- let localChatId: string | null = null;
24
-
25
- const realConfig = await import("../../channels/config.js");
26
-
27
- mock.module("../../channels/config.js", () => ({
28
- ...realConfig,
29
- getDeliverableChannels: () => deliverableChannels,
30
- }));
31
-
32
- const realReader = await import("../../contacts/guardian-delivery-reader.js");
33
-
34
- mock.module("../../contacts/guardian-delivery-reader.js", () => ({
35
- ...realReader,
36
- getGuardianDelivery: async () => gatewayGuardians,
37
- }));
38
-
39
- const realContactStore = await import("../../contacts/contact-store.js");
40
-
41
- mock.module("../../contacts/contact-store.js", () => ({
42
- ...realContactStore,
43
- findGuardianForChannel: (_channelType: string) =>
44
- localChatId === null
45
- ? null
46
- : { contact: { principalId: "p1" }, channel: { externalChatId: localChatId } },
47
- }));
48
-
49
- const { getConnectedChannels } = await import("../emit-signal.js");
50
-
51
- function gatewayBinding(channelType: string, externalChatId: string): GuardianDelivery {
52
- return { channelType, contactId: "c1", address: "addr", externalChatId, status: "active" };
53
- }
54
-
55
- beforeEach(() => {
56
- deliverableChannels = [];
57
- gatewayGuardians = null;
58
- localChatId = null;
59
- });
60
-
61
- describe("getConnectedChannels gateway-first-then-local connectivity", () => {
62
- test("marks telegram connected from a gateway-only binding", async () => {
63
- deliverableChannels = ["telegram"];
64
- gatewayGuardians = [gatewayBinding("telegram", "123")];
65
- localChatId = null;
66
-
67
- expect(await getConnectedChannels()).toContain("telegram");
68
- });
69
-
70
- test("falls back to a local binding when the gateway is unreachable (null)", async () => {
71
- deliverableChannels = ["telegram"];
72
- gatewayGuardians = null;
73
- localChatId = "456";
74
-
75
- expect(await getConnectedChannels()).toContain("telegram");
76
- });
77
-
78
- test("marks telegram disconnected when neither source has a binding", async () => {
79
- deliverableChannels = ["telegram"];
80
- gatewayGuardians = null;
81
- localChatId = null;
82
-
83
- expect(await getConnectedChannels()).not.toContain("telegram");
84
- });
85
-
86
- test("falls back to local when the gateway responds without that channel", async () => {
87
- // Gateway present but with no active telegram entry ⇒ per-channel no-match,
88
- // so connectivity falls back to the local mirror (mirrors
89
- // destination-resolver's per-channel fallback).
90
- deliverableChannels = ["telegram"];
91
- gatewayGuardians = [];
92
- localChatId = "789";
93
-
94
- expect(await getConnectedChannels()).toContain("telegram");
95
- });
96
-
97
- test("only marks slack connected for D-prefixed (DM) chat IDs", async () => {
98
- deliverableChannels = ["slack"];
99
- gatewayGuardians = [gatewayBinding("slack", "C-public")];
100
- expect(await getConnectedChannels()).not.toContain("slack");
101
-
102
- gatewayGuardians = [gatewayBinding("slack", "D-dm")];
103
- expect(await getConnectedChannels()).toContain("slack");
104
- });
105
-
106
- test("always reports vellum and platform connected", async () => {
107
- deliverableChannels = ["vellum", "platform"];
108
- gatewayGuardians = null;
109
-
110
- const connected = await getConnectedChannels();
111
- expect(connected).toContain("vellum");
112
- expect(connected).toContain("platform");
113
- });
114
- });
@@ -1,256 +0,0 @@
1
- /**
2
- * Verifies resolveDestinations resolves guardian delivery endpoints from the
3
- * gateway-provided guardian list, with shapes identical to the local read, and
4
- * falls back to the local contacts read when the list is null.
5
- */
6
-
7
- import { beforeEach, describe, expect, mock, test } from "bun:test";
8
-
9
- import type { GuardianDelivery } from "@vellumai/gateway-client";
10
-
11
- mock.module("../../util/logger.js", () => ({
12
- getLogger: () =>
13
- new Proxy({} as Record<string, unknown>, {
14
- get: () => () => {},
15
- }),
16
- }));
17
-
18
- // Local fallback read; mocked so the null-list path is deterministic.
19
- let localGuardian:
20
- | { contact: { principalId?: string }; channel: { address: string; externalChatId?: string } }
21
- | null = null;
22
-
23
- mock.module("../../contacts/contact-store.js", () => ({
24
- findGuardianForChannel: (_channelType: string) => localGuardian,
25
- }));
26
-
27
- const { resolveDestinations } = await import("../destination-resolver.js");
28
-
29
- function guardian(
30
- overrides: Partial<GuardianDelivery> & Pick<GuardianDelivery, "channelType" | "address">,
31
- ): GuardianDelivery {
32
- return {
33
- contactId: "contact-1",
34
- status: "active",
35
- ...overrides,
36
- } as GuardianDelivery;
37
- }
38
-
39
- describe("resolveDestinations — gateway guardian list", () => {
40
- beforeEach(() => {
41
- localGuardian = null;
42
- });
43
-
44
- test("vellum carries guardianPrincipalId from the gateway list", () => {
45
- const list = [
46
- guardian({ channelType: "vellum", address: "user@example.com", principalId: "prin-1" }),
47
- ];
48
- const result = resolveDestinations(["vellum"], list);
49
- expect(result.get("vellum")).toEqual({
50
- channel: "vellum",
51
- metadata: { guardianPrincipalId: "prin-1" },
52
- });
53
- });
54
-
55
- test("platform carries guardianPrincipalId from the vellum guardian", () => {
56
- const list = [
57
- guardian({ channelType: "vellum", address: "user@example.com", principalId: "prin-1" }),
58
- ];
59
- const result = resolveDestinations(["platform"], list);
60
- expect(result.get("platform")).toEqual({
61
- channel: "platform",
62
- metadata: { guardianPrincipalId: "prin-1" },
63
- });
64
- });
65
-
66
- test("telegram resolves endpoint and binding context", () => {
67
- const list = [
68
- guardian({
69
- channelType: "telegram",
70
- address: "tg-user",
71
- externalChatId: "12345",
72
- }),
73
- ];
74
- const result = resolveDestinations(["telegram"], list);
75
- expect(result.get("telegram")).toEqual({
76
- channel: "telegram",
77
- endpoint: "12345",
78
- metadata: { externalUserId: "tg-user" },
79
- bindingContext: {
80
- sourceChannel: "telegram",
81
- externalChatId: "12345",
82
- externalUserId: "tg-user",
83
- },
84
- });
85
- });
86
-
87
- test("telegram without externalChatId is omitted", () => {
88
- const list = [guardian({ channelType: "telegram", address: "tg-user" })];
89
- const result = resolveDestinations(["telegram"], list);
90
- expect(result.has("telegram")).toBe(false);
91
- });
92
-
93
- test("slack resolves DM endpoint and binding context", () => {
94
- const list = [
95
- guardian({
96
- channelType: "slack",
97
- address: "slack-user",
98
- externalChatId: "D123",
99
- }),
100
- ];
101
- const result = resolveDestinations(["slack"], list);
102
- expect(result.get("slack")).toEqual({
103
- channel: "slack",
104
- endpoint: "D123",
105
- metadata: { externalUserId: "slack-user" },
106
- bindingContext: {
107
- sourceChannel: "slack",
108
- externalChatId: "D123",
109
- externalUserId: "slack-user",
110
- },
111
- });
112
- });
113
-
114
- test("slack non-DM channel is dropped", () => {
115
- const list = [
116
- guardian({
117
- channelType: "slack",
118
- address: "slack-user",
119
- externalChatId: "C123",
120
- }),
121
- ];
122
- const result = resolveDestinations(["slack"], list);
123
- expect(result.has("slack")).toBe(false);
124
- });
125
-
126
- test("inactive guardian is ignored", () => {
127
- const list = [
128
- guardian({
129
- channelType: "telegram",
130
- address: "tg-user",
131
- externalChatId: "12345",
132
- status: "revoked",
133
- }),
134
- ];
135
- const result = resolveDestinations(["telegram"], list);
136
- expect(result.has("telegram")).toBe(false);
137
- });
138
- });
139
-
140
- describe("resolveDestinations — null list falls back to local read", () => {
141
- beforeEach(() => {
142
- localGuardian = null;
143
- });
144
-
145
- test("telegram resolves from the local contacts read", () => {
146
- localGuardian = {
147
- contact: {},
148
- channel: { address: "tg-user", externalChatId: "12345" },
149
- };
150
- const result = resolveDestinations(["telegram"], null);
151
- expect(result.get("telegram")).toEqual({
152
- channel: "telegram",
153
- endpoint: "12345",
154
- metadata: { externalUserId: "tg-user" },
155
- bindingContext: {
156
- sourceChannel: "telegram",
157
- externalChatId: "12345",
158
- externalUserId: "tg-user",
159
- },
160
- });
161
- });
162
-
163
- test("slack DM resolves from the local contacts read", () => {
164
- localGuardian = {
165
- contact: {},
166
- channel: { address: "slack-user", externalChatId: "D123" },
167
- };
168
- const result = resolveDestinations(["slack"], null);
169
- expect(result.get("slack")).toEqual({
170
- channel: "slack",
171
- endpoint: "D123",
172
- metadata: { externalUserId: "slack-user" },
173
- bindingContext: {
174
- sourceChannel: "slack",
175
- externalChatId: "D123",
176
- externalUserId: "slack-user",
177
- },
178
- });
179
- });
180
-
181
- test("vellum carries principalId from the local contacts read", () => {
182
- localGuardian = {
183
- contact: { principalId: "prin-1" },
184
- channel: { address: "user@example.com" },
185
- };
186
- const result = resolveDestinations(["vellum"], null);
187
- expect(result.get("vellum")).toEqual({
188
- channel: "vellum",
189
- metadata: { guardianPrincipalId: "prin-1" },
190
- });
191
- });
192
- });
193
-
194
- describe("resolveDestinations — gateway yields no channel match falls back to local", () => {
195
- beforeEach(() => {
196
- localGuardian = null;
197
- });
198
-
199
- test("empty gateway list falls back to local telegram binding", () => {
200
- localGuardian = {
201
- contact: {},
202
- channel: { address: "tg-user", externalChatId: "12345" },
203
- };
204
- const result = resolveDestinations(["telegram"], []);
205
- expect(result.get("telegram")).toEqual({
206
- channel: "telegram",
207
- endpoint: "12345",
208
- metadata: { externalUserId: "tg-user" },
209
- bindingContext: {
210
- sourceChannel: "telegram",
211
- externalChatId: "12345",
212
- externalUserId: "tg-user",
213
- },
214
- });
215
- });
216
-
217
- test("gateway list missing the channel falls back to local slack DM", () => {
218
- localGuardian = {
219
- contact: {},
220
- channel: { address: "slack-user", externalChatId: "D123" },
221
- };
222
- // Gateway returns a telegram guardian but no slack entry.
223
- const list = [
224
- guardian({ channelType: "telegram", address: "tg", externalChatId: "999" }),
225
- ];
226
- const result = resolveDestinations(["slack"], list);
227
- expect(result.get("slack")).toEqual({
228
- channel: "slack",
229
- endpoint: "D123",
230
- metadata: { externalUserId: "slack-user" },
231
- bindingContext: {
232
- sourceChannel: "slack",
233
- externalChatId: "D123",
234
- externalUserId: "slack-user",
235
- },
236
- });
237
- });
238
-
239
- test("empty gateway list falls back to local vellum principalId", () => {
240
- localGuardian = {
241
- contact: { principalId: "prin-1" },
242
- channel: { address: "user@example.com" },
243
- };
244
- const result = resolveDestinations(["vellum"], []);
245
- expect(result.get("vellum")).toEqual({
246
- channel: "vellum",
247
- metadata: { guardianPrincipalId: "prin-1" },
248
- });
249
- });
250
-
251
- test("empty gateway list with no local binding omits telegram", () => {
252
- localGuardian = null;
253
- const result = resolveDestinations(["telegram"], []);
254
- expect(result.has("telegram")).toBe(false);
255
- });
256
- });