@vellumai/assistant 0.9.0 → 0.10.0-dev.202606192226.8ed8a6a

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 (624) hide show
  1. package/ARCHITECTURE.md +19 -35
  2. package/bun.lock +7 -8
  3. package/docs/activation-funnel-telemetry.md +28 -22
  4. package/docs/architecture/security.md +29 -28
  5. package/docs/stt-provider-onboarding.md +3 -5
  6. package/docs/workflows-testing.md +13 -44
  7. package/docs/workflows.md +3 -5
  8. package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +47 -0
  9. package/node_modules/@vellumai/ces-client/src/rpc-client.ts +28 -5
  10. package/node_modules/@vellumai/environments/src/seeds.ts +2 -5
  11. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +97 -0
  12. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
  13. package/node_modules/@vellumai/gateway-client/src/index.ts +32 -6
  14. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +119 -0
  15. package/node_modules/@vellumai/gateway-client/src/types.ts +15 -84
  16. package/openapi.yaml +1128 -119
  17. package/package.json +2 -1
  18. package/scripts/sync-llm-catalog.ts +6 -15
  19. package/scripts/sync-web-search-catalog.ts +3 -11
  20. package/src/__tests__/access-request-card-view.test.ts +98 -0
  21. package/src/__tests__/access-request-seed-content-blocks.test.ts +2 -4
  22. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +72 -32
  23. package/src/__tests__/agent-loop-compaction-strip.test.ts +241 -0
  24. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +16 -13
  25. package/src/__tests__/agent-loop-output-hooks.test.ts +69 -0
  26. package/src/__tests__/agent-loop-override-profile.test.ts +25 -0
  27. package/src/__tests__/agent-loop-pushes-post-hook-prompt.test.ts +306 -0
  28. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -3
  29. package/src/__tests__/app-compiler.test.ts +15 -1
  30. package/src/__tests__/app-dir-path-guard.test.ts +0 -1
  31. package/src/__tests__/approval-cascade.test.ts +6 -0
  32. package/src/__tests__/approval-routes-http.test.ts +128 -0
  33. package/src/__tests__/assistant-feature-flag-guard.test.ts +1 -4
  34. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
  35. package/src/__tests__/auth-fallback-events-store.test.ts +6 -14
  36. package/src/__tests__/avatar-identity-sync.test.ts +2 -27
  37. package/src/__tests__/btw-routes.test.ts +6 -8
  38. package/src/__tests__/call-pointer-messages.test.ts +28 -0
  39. package/src/__tests__/cancel-clears-processing.test.ts +89 -0
  40. package/src/__tests__/channel-approval-routes.test.ts +0 -4
  41. package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -15
  42. package/src/__tests__/checker.test.ts +0 -3
  43. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +3 -4
  44. package/src/__tests__/compaction-events.test.ts +6 -0
  45. package/src/__tests__/compactor-image-manifest-trust.test.ts +21 -1
  46. package/src/__tests__/compactor-summary-call-truncation.test.ts +223 -0
  47. package/src/__tests__/config-loader-backfill.test.ts +268 -27
  48. package/src/__tests__/config-schema.test.ts +35 -0
  49. package/src/__tests__/config-watcher.test.ts +0 -18
  50. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -2
  51. package/src/__tests__/contact-store-user-file.test.ts +0 -6
  52. package/src/__tests__/contacts-tools.test.ts +29 -0
  53. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
  54. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +22 -0
  55. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  56. package/src/__tests__/conversation-agent-loop.test.ts +58 -0
  57. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  58. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -0
  59. package/src/__tests__/conversation-lifecycle.test.ts +7 -9
  60. package/src/__tests__/conversation-load-history-repair.test.ts +101 -0
  61. package/src/__tests__/conversation-process-callsite.test.ts +6 -0
  62. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  63. package/src/__tests__/conversation-queue.test.ts +6 -0
  64. package/src/__tests__/conversation-routes-guardian-reply.test.ts +15 -12
  65. package/src/__tests__/conversation-slash-queue.test.ts +6 -0
  66. package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
  67. package/src/__tests__/conversation-speed-override.test.ts +6 -0
  68. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -3
  69. package/src/__tests__/conversation-title-service.test.ts +62 -0
  70. package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -0
  71. package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
  72. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
  73. package/src/__tests__/credential-broker.test.ts +449 -1
  74. package/src/__tests__/credential-execution-shell-lockdown.test.ts +18 -11
  75. package/src/__tests__/credential-execution-tools.test.ts +0 -1
  76. package/src/__tests__/credential-prompt-route.test.ts +4 -4
  77. package/src/__tests__/credential-routes.test.ts +360 -0
  78. package/src/__tests__/credential-security-invariants.test.ts +4 -13
  79. package/src/__tests__/disk-pressure-policy.test.ts +12 -0
  80. package/src/__tests__/disk-pressure-tools.test.ts +41 -1
  81. package/src/__tests__/disk-usage.test.ts +65 -0
  82. package/src/__tests__/document-tool-security.test.ts +9 -6
  83. package/src/__tests__/document-update-default-surface.test.ts +202 -0
  84. package/src/__tests__/dynamic-page-surface.test.ts +152 -1
  85. package/src/__tests__/fixtures/credential-security-fixtures.ts +2 -33
  86. package/src/__tests__/gateway-flag-listener.test.ts +110 -1
  87. package/src/__tests__/gateway-only-guard.test.ts +3 -7
  88. package/src/__tests__/gemini-count-tokens.test.ts +70 -0
  89. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  90. package/src/__tests__/guardian-card-withdrawal.test.ts +403 -0
  91. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +5 -3
  92. package/src/__tests__/guardian-grant-minting.test.ts +3 -35
  93. package/src/__tests__/guardian-routing-invariants.test.ts +64 -26
  94. package/src/__tests__/guardian-routing-state.test.ts +0 -1
  95. package/src/__tests__/headless-browser-mode.test.ts +10 -0
  96. package/src/__tests__/headless-browser-navigate.test.ts +8 -3
  97. package/src/__tests__/helpers/create-guardian-binding.ts +0 -1
  98. package/src/__tests__/host-browser-proxy.test.ts +87 -0
  99. package/src/__tests__/identity-routes.test.ts +0 -189
  100. package/src/__tests__/inbound-invite-redemption.test.ts +4 -4
  101. package/src/__tests__/injector-disk-pressure.test.ts +10 -5
  102. package/src/__tests__/injector-v3-suppression.test.ts +27 -20
  103. package/src/__tests__/internal-telemetry-routes.test.ts +6 -14
  104. package/src/__tests__/invite-redemption-service.test.ts +4 -7
  105. package/src/__tests__/llm-callsite-catalog.test.ts +5 -6
  106. package/src/__tests__/llm-catalog-parity.test.ts +30 -23
  107. package/src/__tests__/llm-resolver.test.ts +70 -24
  108. package/src/__tests__/llm-schema.test.ts +1 -0
  109. package/src/__tests__/managed-profile-guard.test.ts +163 -4
  110. package/src/__tests__/mcp-health-check.test.ts +6 -7
  111. package/src/__tests__/media-stream-server-integration.test.ts +317 -13
  112. package/src/__tests__/oauth-provider-seed-logos.test.ts +4 -6
  113. package/src/__tests__/onboarding-persona-write.test.ts +1 -1
  114. package/src/__tests__/path-policy.test.ts +34 -0
  115. package/src/__tests__/persona-resolver.test.ts +49 -14
  116. package/src/__tests__/plugin-api-model-profiles.test.ts +178 -0
  117. package/src/__tests__/plugin-api-provider.test.ts +24 -0
  118. package/src/__tests__/plugin-tool-contribution.test.ts +6 -3
  119. package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +214 -0
  120. package/src/__tests__/provider-send-message-override-profile.test.ts +76 -0
  121. package/src/__tests__/reaction-persistence.test.ts +150 -29
  122. package/src/__tests__/registry.test.ts +2 -7
  123. package/src/__tests__/relay-server.test.ts +285 -0
  124. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
  125. package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -10
  126. package/src/__tests__/schedule-routes.test.ts +0 -30
  127. package/src/__tests__/schedule-tools.test.ts +2 -18
  128. package/src/__tests__/scheduler-reuse-conversation.test.ts +8 -5
  129. package/src/__tests__/secret-response-routing.test.ts +35 -0
  130. package/src/__tests__/secret-routes-platform-proxy.test.ts +16 -2
  131. package/src/__tests__/skill-execute-input.test.ts +177 -1
  132. package/src/__tests__/skill-load-tool.test.ts +72 -0
  133. package/src/__tests__/skill-runtime-path.test.ts +2 -3
  134. package/src/__tests__/skills.test.ts +51 -0
  135. package/src/__tests__/slack-notification-approval-card.test.ts +176 -0
  136. package/src/__tests__/slack-reaction-canonical-approval.test.ts +285 -0
  137. package/src/__tests__/subagent-tools.test.ts +266 -0
  138. package/src/__tests__/surface-completion-nudge-hook.test.ts +367 -0
  139. package/src/__tests__/system-storage-cleanup-skill.test.ts +56 -0
  140. package/src/__tests__/task-progress-nudge-hook.test.ts +1 -1
  141. package/src/__tests__/title-generate-hook.test.ts +100 -3
  142. package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1 -29
  143. package/src/__tests__/token-manager.test.ts +519 -0
  144. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +1 -1
  145. package/src/__tests__/tool-audit-listener.test.ts +7 -7
  146. package/src/__tests__/tool-executor-lifecycle-events.test.ts +6 -3
  147. package/src/__tests__/tool-executor.test.ts +0 -79
  148. package/src/__tests__/trusted-contact-approval-notifier.test.ts +4 -2
  149. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +220 -3
  150. package/src/__tests__/trusted-contact-multichannel.test.ts +3 -3
  151. package/src/__tests__/trusted-contact-verification.test.ts +8 -10
  152. package/src/__tests__/twilio-routes.test.ts +81 -1
  153. package/src/__tests__/voice-invite-redemption.test.ts +2 -3
  154. package/src/__tests__/weak-open-model.test.ts +30 -0
  155. package/src/__tests__/web-search-catalog-parity.test.ts +6 -25
  156. package/src/__tests__/workspace-greetings.test.ts +152 -0
  157. package/src/__tests__/workspace-migration-105-enable-memory-v3-live-for-new-workspaces.test.ts +149 -0
  158. package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +285 -0
  159. package/src/__tests__/workspace-migration-add-send-diagnostics.test.ts +1 -1
  160. package/src/__tests__/workspace-migration-drop-collect-usage-data.test.ts +118 -0
  161. package/src/__tests__/workspace-migration-drop-send-diagnostics.test.ts +118 -0
  162. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +0 -4
  163. package/src/agent/loop.ts +75 -29
  164. package/src/api/README.md +6 -6
  165. package/src/api/events/tool-result.ts +6 -0
  166. package/src/api/events/workflow-completed.ts +53 -0
  167. package/src/api/events/workflow-leaf-finished.ts +38 -0
  168. package/src/api/events/workflow-leaf-started.ts +35 -0
  169. package/src/api/events/workflow-progress.ts +32 -0
  170. package/src/api/events/workflow-started.ts +31 -0
  171. package/src/api/index.ts +40 -0
  172. package/src/api/responses/conversation-message.ts +28 -4
  173. package/src/api/responses/home.ts +26 -4
  174. package/src/api/responses/workflow-journal.ts +53 -0
  175. package/src/approvals/guardian-card-withdrawal.ts +145 -0
  176. package/src/approvals/guardian-decision-primitive.ts +26 -3
  177. package/src/approvals/guardian-request-resolvers.ts +183 -80
  178. package/src/calls/__tests__/channel-admission-reader.test.ts +132 -0
  179. package/src/calls/__tests__/relay-setup-router.test.ts +350 -0
  180. package/src/calls/call-pointer-messages.ts +10 -4
  181. package/src/calls/channel-admission-reader.ts +104 -0
  182. package/src/calls/guardian-dispatch.ts +17 -45
  183. package/src/calls/media-stream-server.ts +84 -2
  184. package/src/calls/relay-access-wait.ts +1 -1
  185. package/src/calls/relay-server.ts +66 -0
  186. package/src/calls/relay-setup-router.ts +82 -1
  187. package/src/calls/twilio-routes.ts +17 -8
  188. package/src/calls/voice-session-bridge.ts +2 -2
  189. package/src/cli/commands/clients.ts +3 -0
  190. package/src/cli/commands/db/status.ts +37 -3
  191. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2-compare-render.test.ts +1 -1
  192. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2.test.ts +8 -7
  193. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v3.test.ts +5 -4
  194. package/src/cli/commands/memory/index.ts +30 -0
  195. package/src/cli/commands/{memory-v2-compare-render.ts → memory/memory-v2-compare-render.ts} +1 -1
  196. package/src/cli/commands/{memory-v2.ts → memory/memory-v2.ts} +6 -15
  197. package/src/cli/commands/{memory-v3.ts → memory/memory-v3.ts} +97 -11
  198. package/src/cli/commands/oauth/status.test.ts +36 -0
  199. package/src/cli/commands/oauth/status.ts +23 -3
  200. package/src/cli/commands/plugins.ts +400 -14
  201. package/src/cli/lib/__tests__/diff-plugin.test.ts +443 -0
  202. package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
  203. package/src/cli/lib/__tests__/install-from-github.test.ts +31 -0
  204. package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +443 -0
  205. package/src/cli/lib/__tests__/plugin-pin-history.test.ts +162 -0
  206. package/src/cli/lib/__tests__/plugin-surfaces.test.ts +111 -0
  207. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +295 -2
  208. package/src/cli/lib/diff-plugin.ts +346 -0
  209. package/src/cli/lib/inspect-plugin.ts +12 -1
  210. package/src/cli/lib/install-from-github.ts +128 -19
  211. package/src/cli/lib/merge-plugin-tree.ts +328 -0
  212. package/src/cli/lib/plugin-fingerprint.ts +14 -0
  213. package/src/cli/lib/plugin-marketplace.ts +11 -0
  214. package/src/cli/lib/plugin-pin-history.ts +257 -0
  215. package/src/cli/lib/plugin-surfaces.ts +104 -0
  216. package/src/cli/lib/upgrade-plugin.ts +298 -10
  217. package/src/cli/program.ts +2 -6
  218. package/src/config/__tests__/sync-gated-profiles.test.ts +368 -0
  219. package/src/config/assistant-feature-flags.ts +22 -7
  220. package/src/config/bundled-skills/contacts/tools/contact-search.ts +0 -1
  221. package/src/config/bundled-skills/document-editor/SKILL.md +3 -3
  222. package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
  223. package/src/config/bundled-skills/messaging/SKILL.md +6 -4
  224. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -8
  225. package/src/config/bundled-skills/subagent/SKILL.md +4 -0
  226. package/src/config/bundled-skills/subagent/TOOLS.json +4 -0
  227. package/src/config/bundled-skills/system-storage-cleanup/SKILL.md +74 -0
  228. package/src/config/bundled-skills/workflows/SKILL.md +14 -8
  229. package/src/config/bundled-tool-registry.ts +2 -7
  230. package/src/config/call-site-defaults.ts +15 -2
  231. package/src/config/feature-flag-registry.json +46 -31
  232. package/src/config/inference-profile-validation.ts +26 -0
  233. package/src/config/llm-resolver.ts +3 -0
  234. package/src/config/loader.ts +4 -0
  235. package/src/config/memory-v3-gate.ts +11 -0
  236. package/src/config/profile-order.ts +28 -0
  237. package/src/config/schema.ts +8 -6
  238. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  239. package/src/config/schemas/call-site-catalog.ts +7 -0
  240. package/src/config/schemas/channels.ts +11 -0
  241. package/src/config/schemas/elevenlabs.ts +0 -1
  242. package/src/config/schemas/llm.ts +31 -0
  243. package/src/config/schemas/memory-lifecycle.ts +3 -7
  244. package/src/config/schemas/memory-v3.ts +6 -0
  245. package/src/config/schemas/platform.ts +0 -8
  246. package/src/config/schemas/services.ts +18 -0
  247. package/src/config/seed-inference-profiles.ts +109 -44
  248. package/src/config/skills.ts +21 -0
  249. package/src/config/sync-gated-profiles.ts +220 -0
  250. package/src/contacts/contact-store.ts +89 -106
  251. package/src/contacts/contacts-write.ts +5 -22
  252. package/src/contacts/types.ts +0 -1
  253. package/src/context/compactor.ts +88 -54
  254. package/src/context/strip-injections.ts +58 -10
  255. package/src/context/token-estimator.ts +1 -1
  256. package/src/credential-execution/process-manager.ts +55 -14
  257. package/src/credential-execution/prompted-credential.ts +2 -3
  258. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -2
  259. package/src/daemon/__tests__/conversation-tool-setup.test.ts +44 -0
  260. package/src/daemon/config-watcher.ts +0 -4
  261. package/src/daemon/conversation-agent-loop-handlers.ts +2 -0
  262. package/src/daemon/conversation-agent-loop.ts +114 -22
  263. package/src/daemon/conversation-history.ts +1 -1
  264. package/src/daemon/conversation-lifecycle.ts +3 -5
  265. package/src/daemon/conversation-process.ts +13 -5
  266. package/src/daemon/conversation-runtime-assembly.ts +13 -15
  267. package/src/daemon/conversation-slash.ts +2 -23
  268. package/src/daemon/conversation-surfaces.ts +26 -0
  269. package/src/daemon/conversation-tool-setup.ts +53 -19
  270. package/src/daemon/conversation.ts +131 -20
  271. package/src/daemon/disk-pressure-policy.ts +5 -3
  272. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -1
  273. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -1
  274. package/src/daemon/handlers/config-a2a.ts +0 -2
  275. package/src/daemon/handlers/config-channels.ts +15 -16
  276. package/src/daemon/handlers/config-slack-channel.ts +22 -3
  277. package/src/daemon/handlers/conversations.ts +107 -0
  278. package/src/daemon/host-browser-proxy.ts +41 -0
  279. package/src/daemon/lifecycle.ts +55 -27
  280. package/src/daemon/memory-v2-startup.test.ts +131 -0
  281. package/src/daemon/memory-v2-startup.ts +100 -1
  282. package/src/daemon/message-provenance.ts +2 -0
  283. package/src/daemon/message-types/contacts.ts +0 -1
  284. package/src/daemon/message-types/conversations.ts +3 -3
  285. package/src/daemon/message-types/sync.ts +0 -1
  286. package/src/daemon/message-types/web-activity.ts +7 -1
  287. package/src/daemon/message-types/workflows.ts +83 -1
  288. package/src/daemon/orphan-reaper.test.ts +0 -19
  289. package/src/daemon/orphan-reaper.ts +2 -24
  290. package/src/daemon/server.ts +0 -10
  291. package/src/daemon/tool-setup-types.ts +4 -0
  292. package/src/daemon/trust-context.ts +1 -1
  293. package/src/daemon/wake-conversation-ops.ts +1 -0
  294. package/src/events/tool-audit-listener.ts +2 -2
  295. package/src/home/feed-source-enrichment.test.ts +151 -0
  296. package/src/home/feed-source-enrichment.ts +176 -0
  297. package/src/home/relationship-state.ts +2 -4
  298. package/src/instrument.ts +18 -6
  299. package/src/ipc/__tests__/binary-result-ipc.test.ts +81 -0
  300. package/src/ipc/__tests__/clients-list-ipc.test.ts +20 -0
  301. package/src/ipc/assistant-server.ts +37 -4
  302. package/src/ipc/gateway-flag-listener.ts +18 -2
  303. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +5 -16
  304. package/src/memory/__tests__/db-logs-attach.test.ts +122 -0
  305. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +7 -11
  306. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +37 -7
  307. package/src/memory/__tests__/memory-retrospective-job.test.ts +229 -401
  308. package/src/memory/__tests__/onboarding-events-store.test.ts +7 -7
  309. package/src/memory/auth-fallback-events-store.ts +2 -2
  310. package/src/memory/auto-analysis-enqueue.ts +3 -5
  311. package/src/memory/bookmark-crud.ts +1 -2
  312. package/src/memory/canonical-guardian-store.ts +39 -1
  313. package/src/memory/conversation-crud.ts +9 -4
  314. package/src/memory/conversation-key-store.ts +17 -2
  315. package/src/memory/conversation-title-service.ts +64 -7
  316. package/src/memory/db-async-query.ts +20 -2
  317. package/src/memory/db-connection.ts +49 -5
  318. package/src/memory/db-init.ts +17 -17
  319. package/src/memory/embedding-backend.ts +38 -1
  320. package/src/memory/embedding-billing-breaker.ts +96 -0
  321. package/src/memory/jobs-store.ts +25 -13
  322. package/src/memory/jobs-worker.ts +54 -1
  323. package/src/memory/lifecycle-events-store.ts +2 -2
  324. package/src/memory/memory-retrospective-constants.ts +4 -4
  325. package/src/memory/memory-retrospective-enqueue.ts +31 -6
  326. package/src/memory/memory-retrospective-job.ts +28 -227
  327. package/src/memory/migrations/129-contact-channels-access-fields.ts +18 -9
  328. package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +14 -2
  329. package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +10 -0
  330. package/src/memory/migrations/291-contact-channels-renormalize-addresses.ts +72 -0
  331. package/src/memory/migrations/292-schedule-default-no-reuse-conversation.test.ts +67 -0
  332. package/src/memory/migrations/292-schedule-default-no-reuse-conversation.ts +25 -0
  333. package/src/memory/migrations/293-workflow-journal-leaf-tokens.ts +32 -0
  334. package/src/memory/migrations/294-drop-external-user-id.ts +31 -0
  335. package/src/memory/migrations/295-drop-approval-prompt-ts-tracker.ts +20 -0
  336. package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +110 -0
  337. package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.ts +68 -0
  338. package/src/memory/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +154 -0
  339. package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +31 -0
  340. package/src/memory/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +341 -0
  341. package/src/memory/migrations/__tests__/run-migrations.test.ts +52 -0
  342. package/src/memory/migrations/index.ts +6 -0
  343. package/src/memory/migrations/run-migrations.ts +41 -0
  344. package/src/memory/migrations/validate-migration-state.ts +1 -1
  345. package/src/memory/onboarding-events-store.ts +3 -3
  346. package/src/memory/schema/contacts.ts +0 -5
  347. package/src/memory/skill-loaded-events-store.test.ts +7 -15
  348. package/src/memory/skill-loaded-events-store.ts +2 -2
  349. package/src/memory/tool-executed-events-store.test.ts +7 -7
  350. package/src/memory/turn-trace-store.test.ts +736 -0
  351. package/src/memory/turn-trace-store.ts +364 -0
  352. package/src/memory/v2/__tests__/consolidation-job.test.ts +8 -0
  353. package/src/memory/v2/__tests__/skill-content.test.ts +30 -0
  354. package/src/memory/v2/consolidation-job.ts +2 -2
  355. package/src/memory/v2/skill-content.ts +25 -7
  356. package/src/memory/v2/skill-store.ts +7 -1
  357. package/src/memory/v3-eval/__tests__/eval-packets.test.ts +248 -0
  358. package/src/memory/v3-eval/eval-packets.ts +546 -0
  359. package/src/messaging/providers/slack/adapter.ts +1 -1
  360. package/src/messaging/providers/slack/api.ts +31 -0
  361. package/src/messaging/providers/slack/send.test.ts +114 -2
  362. package/src/messaging/providers/slack/send.ts +30 -7
  363. package/src/messaging/providers/slack/withdraw.test.ts +200 -0
  364. package/src/messaging/providers/slack/withdraw.ts +161 -0
  365. package/src/notifications/AGENTS.md +2 -0
  366. package/src/notifications/access-request-copy.ts +72 -59
  367. package/src/notifications/adapters/shared.ts +29 -0
  368. package/src/notifications/adapters/slack.ts +58 -103
  369. package/src/notifications/adapters/telegram.ts +2 -20
  370. package/src/notifications/approval-card-data.ts +333 -0
  371. package/src/notifications/broadcaster.ts +16 -3
  372. package/src/notifications/canonical-delivery-recorder.ts +139 -0
  373. package/src/notifications/copy-composer.ts +3 -3
  374. package/src/notifications/decision-engine.ts +4 -2
  375. package/src/notifications/destination-resolver.ts +4 -6
  376. package/src/notifications/guardian-question-mode.ts +10 -0
  377. package/src/notifications/home-feed-side-effect.ts +7 -16
  378. package/src/notifications/notification-utils.ts +19 -20
  379. package/src/notifications/signal.ts +79 -43
  380. package/src/notifications/types.ts +98 -121
  381. package/src/oauth/AGENTS.md +5 -24
  382. package/src/permissions/checker.test.ts +51 -0
  383. package/src/permissions/checker.ts +185 -26
  384. package/src/permissions/ipc-risk-types.ts +24 -0
  385. package/src/permissions/question-prompter.test.ts +27 -0
  386. package/src/permissions/question-prompter.ts +4 -0
  387. package/src/permissions/secret-prompter.ts +15 -1
  388. package/src/platform/client.test.ts +119 -0
  389. package/src/platform/client.ts +66 -0
  390. package/src/platform/consent-cache.test.ts +267 -0
  391. package/src/platform/consent-cache.ts +174 -0
  392. package/src/plugin-api/constants.ts +1 -1
  393. package/src/plugin-api/index.ts +33 -1
  394. package/src/plugin-api/model-profiles.ts +33 -0
  395. package/src/plugin-api/types.ts +50 -2
  396. package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +56 -0
  397. package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +43 -0
  398. package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +137 -0
  399. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +153 -0
  400. package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +138 -0
  401. package/src/plugins/defaults/advisor/__tests__/transcript.test.ts +147 -0
  402. package/src/plugins/defaults/advisor/advisor-gate.ts +29 -0
  403. package/src/plugins/defaults/advisor/advisor-state-store.ts +94 -0
  404. package/src/plugins/defaults/advisor/config.ts +21 -0
  405. package/src/plugins/defaults/advisor/consult.ts +93 -0
  406. package/src/plugins/defaults/advisor/hooks/post-model-call.ts +34 -0
  407. package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +30 -0
  408. package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +19 -0
  409. package/src/plugins/defaults/advisor/package.json +14 -0
  410. package/src/plugins/defaults/advisor/steering.ts +67 -0
  411. package/src/plugins/defaults/advisor/tools/advisor.ts +65 -0
  412. package/src/plugins/defaults/advisor/transcript.ts +76 -0
  413. package/src/plugins/defaults/compaction/window-manager.ts +18 -0
  414. package/src/plugins/defaults/index.ts +60 -0
  415. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +22 -9
  416. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
  417. package/src/plugins/defaults/memory-retrieval/injectors.ts +4 -4
  418. package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +64 -0
  419. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +29 -21
  420. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1 -0
  421. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
  422. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +129 -9
  423. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +31 -4
  424. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +77 -2
  425. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +1 -0
  426. package/src/plugins/defaults/memory-v3-shadow/injector.ts +7 -10
  427. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +144 -11
  428. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +32 -20
  429. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +56 -3
  430. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +23 -2
  431. package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +276 -0
  432. package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +22 -0
  433. package/src/plugins/defaults/surface-completion-nudge/nudge-state-store.ts +46 -0
  434. package/src/plugins/defaults/surface-completion-nudge/package.json +14 -0
  435. package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +3 -13
  436. package/src/plugins/defaults/title-generate/hooks/stop.ts +56 -21
  437. package/src/prompts/persona-resolver.ts +14 -4
  438. package/src/prompts/templates/system-sections.ts +7 -2
  439. package/src/providers/__tests__/count-tokens-forwarding.test.ts +98 -0
  440. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  441. package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
  442. package/src/providers/__tests__/retry-callsite.test.ts +176 -0
  443. package/src/providers/anthropic/client.ts +230 -175
  444. package/src/providers/atlascloud/client.ts +85 -0
  445. package/src/providers/call-site-routing.ts +10 -0
  446. package/src/providers/fetch-provider-catalog.ts +85 -0
  447. package/src/providers/gemini/client.ts +43 -0
  448. package/src/providers/inference/adapter-factory.ts +3 -0
  449. package/src/providers/model-catalog.ts +58 -0
  450. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +33 -0
  451. package/src/providers/openai/chat-completions-provider.ts +7 -0
  452. package/src/providers/openai/responses-provider.ts +10 -0
  453. package/src/providers/provider-send-message.ts +11 -3
  454. package/src/providers/ratelimit.ts +9 -0
  455. package/src/providers/retry.ts +62 -12
  456. package/src/providers/search-provider-catalog.ts +10 -0
  457. package/src/providers/types.ts +16 -0
  458. package/src/providers/usage-tracking.ts +7 -0
  459. package/src/providers/weak-open-model.ts +22 -0
  460. package/src/runtime/AGENTS.md +0 -1
  461. package/src/runtime/__tests__/agent-wake.test.ts +227 -0
  462. package/src/runtime/__tests__/client-health.test.ts +44 -0
  463. package/src/runtime/access-request-helper.ts +21 -53
  464. package/src/runtime/actor-trust-resolver.ts +59 -63
  465. package/src/runtime/agent-wake.ts +71 -0
  466. package/src/runtime/assistant-event-hub.ts +18 -4
  467. package/src/runtime/auth/__tests__/route-policy.test.ts +12 -0
  468. package/src/runtime/auth/require-bound-guardian.ts +1 -4
  469. package/src/runtime/btw-sidechain.ts +3 -6
  470. package/src/runtime/capabilities.test.ts +120 -0
  471. package/src/runtime/capabilities.ts +197 -0
  472. package/src/runtime/channel-approval-types.ts +22 -45
  473. package/src/runtime/channel-invite-transports/telegram.ts +4 -4
  474. package/src/runtime/channel-retry-sweep.ts +1 -0
  475. package/src/runtime/channel-verification-service.ts +3 -3
  476. package/src/runtime/client-health.ts +26 -0
  477. package/src/runtime/confirmation-request-guardian-bridge.ts +38 -29
  478. package/src/runtime/effective-capabilities.test.ts +128 -0
  479. package/src/runtime/effective-capabilities.ts +84 -0
  480. package/src/runtime/guardian-reply-router.ts +106 -21
  481. package/src/runtime/invite-redemption-service.ts +9 -25
  482. package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +126 -0
  483. package/src/runtime/migrations/vbundle-builder.ts +49 -20
  484. package/src/runtime/pending-interactions.ts +35 -0
  485. package/src/runtime/routes/__tests__/client-routes.test.ts +13 -0
  486. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +67 -0
  487. package/src/runtime/routes/__tests__/plugins-routes.test.ts +383 -1
  488. package/src/runtime/routes/app-routes.ts +1 -1
  489. package/src/runtime/routes/approval-routes.ts +40 -9
  490. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -2
  491. package/src/runtime/routes/assets/vellum-design-system.css +1959 -0
  492. package/src/runtime/routes/browser-tabs-routes.ts +9 -0
  493. package/src/runtime/routes/btw-routes.ts +1 -27
  494. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +17 -8
  495. package/src/runtime/routes/client-routes.ts +10 -0
  496. package/src/runtime/routes/contact-routes.ts +31 -8
  497. package/src/runtime/routes/conversation-compaction-routes.ts +1 -1
  498. package/src/runtime/routes/conversation-management-routes.ts +80 -1
  499. package/src/runtime/routes/conversation-query-routes.ts +68 -22
  500. package/src/runtime/routes/conversation-routes.ts +39 -14
  501. package/src/runtime/routes/credential-routes.ts +40 -16
  502. package/src/runtime/routes/empty-state-greeting-cache.ts +1 -2
  503. package/src/runtime/routes/events-routes.ts +1 -3
  504. package/src/runtime/routes/guardian-approval-interception.ts +14 -73
  505. package/src/runtime/routes/guardian-approval-prompt.ts +22 -4
  506. package/src/runtime/routes/home-feed-routes.ts +8 -3
  507. package/src/runtime/routes/identity-routes.ts +1 -296
  508. package/src/runtime/routes/inbound-message-handler.ts +214 -228
  509. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +89 -7
  510. package/src/runtime/routes/inbound-stages/admission-policy.test.ts +154 -0
  511. package/src/runtime/routes/inbound-stages/admission-policy.ts +140 -0
  512. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +3 -3
  513. package/src/runtime/routes/inbound-stages/background-dispatch.ts +11 -6
  514. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -2
  515. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +1 -2
  516. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +7 -7
  517. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +47 -28
  518. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +358 -0
  519. package/src/runtime/routes/index.ts +2 -0
  520. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +8 -0
  521. package/src/runtime/routes/integrations/slack/channel.ts +36 -0
  522. package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
  523. package/src/runtime/routes/mcp-auth-routes.ts +233 -41
  524. package/src/runtime/routes/memory-eval-routes.ts +87 -0
  525. package/src/runtime/routes/notification-routes.ts +122 -133
  526. package/src/runtime/routes/platform-routes.ts +2 -2
  527. package/src/runtime/routes/plugins-routes.ts +366 -11
  528. package/src/runtime/routes/schedule-routes.ts +0 -22
  529. package/src/runtime/routes/secret-routes.ts +15 -0
  530. package/src/runtime/routes/surface-action-routes.ts +2 -1
  531. package/src/runtime/routes/tool-call-question-enrichment.test.ts +146 -0
  532. package/src/runtime/routes/tool-call-question-enrichment.ts +66 -0
  533. package/src/runtime/routes/workflow-routes.test.ts +229 -44
  534. package/src/runtime/routes/workflow-routes.ts +131 -29
  535. package/src/runtime/routes/workspace-greetings.ts +55 -0
  536. package/src/runtime/sync/resource-sync-events.ts +1 -11
  537. package/src/runtime/tool-grant-request-helper.ts +18 -16
  538. package/src/runtime/trust-context-resolver.ts +8 -5
  539. package/src/schedule/inference-profile.ts +2 -14
  540. package/src/schedule/schedule-store.ts +1 -1
  541. package/src/schedule/scheduler-types.ts +5 -1
  542. package/src/security/__tests__/provider-key-env-fallback.test.ts +6 -0
  543. package/src/security/secret-patterns.ts +3 -0
  544. package/src/subagent/manager.ts +17 -4
  545. package/src/subagent/types.ts +6 -0
  546. package/src/telemetry/trace-collection-policy.test.ts +28 -0
  547. package/src/telemetry/trace-collection-policy.ts +30 -0
  548. package/src/telemetry/types.ts +89 -0
  549. package/src/telemetry/usage-telemetry-reporter.test.ts +586 -36
  550. package/src/telemetry/usage-telemetry-reporter.ts +148 -41
  551. package/src/tools/AGENTS.md +3 -3
  552. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +31 -0
  553. package/src/tools/browser/browser-execution.ts +30 -19
  554. package/src/tools/document/document-tool.ts +30 -6
  555. package/src/tools/executor.ts +5 -3
  556. package/src/tools/host-terminal/host-shell.ts +5 -4
  557. package/src/tools/memory/register.ts +2 -2
  558. package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +360 -0
  559. package/src/tools/network/__tests__/web-search.test.ts +143 -0
  560. package/src/tools/network/web-fetch.ts +372 -1
  561. package/src/tools/network/web-search-error.ts +1 -1
  562. package/src/tools/network/web-search.ts +213 -10
  563. package/src/tools/permission-checker.ts +4 -3
  564. package/src/tools/registry.ts +20 -0
  565. package/src/tools/schedule/create.ts +7 -12
  566. package/src/tools/schedule/update.ts +4 -11
  567. package/src/tools/shared/filesystem/path-policy.ts +39 -13
  568. package/src/tools/side-effects.ts +2 -17
  569. package/src/tools/skills/execute.ts +99 -2
  570. package/src/tools/skills/load.ts +43 -2
  571. package/src/tools/subagent/spawn.ts +64 -15
  572. package/src/tools/terminal/shell.ts +10 -4
  573. package/src/tools/tool-approval-handler.ts +18 -13
  574. package/src/tools/tool-manifest.ts +0 -2
  575. package/src/tools/types.ts +10 -0
  576. package/src/tools/ui-surface/definitions.ts +64 -3
  577. package/src/tools/verification-control-plane-policy.ts +3 -1
  578. package/src/tools/workflows/run-workflow.test.ts +8 -18
  579. package/src/tools/workflows/run-workflow.ts +1 -0
  580. package/src/util/disk-usage.ts +78 -23
  581. package/src/util/logs-db-path.ts +22 -0
  582. package/src/util/platform.ts +10 -3
  583. package/src/watcher/telemetry.ts +2 -2
  584. package/src/workflows/capabilities.ts +2 -3
  585. package/src/workflows/engine.test.ts +175 -1
  586. package/src/workflows/engine.ts +82 -0
  587. package/src/workflows/journal-store.test.ts +70 -0
  588. package/src/workflows/journal-store.ts +18 -3
  589. package/src/workflows/run-manager.test.ts +171 -28
  590. package/src/workflows/run-manager.ts +66 -24
  591. package/src/workspace/migrations/105-enable-memory-v3-live-for-new-workspaces.ts +63 -0
  592. package/src/workspace/migrations/106-drop-collect-usage-data.ts +47 -0
  593. package/src/workspace/migrations/107-drop-send-diagnostics.ts +47 -0
  594. package/src/workspace/migrations/108-drop-balanced-economy-profile.ts +129 -0
  595. package/src/workspace/migrations/registry.ts +8 -0
  596. package/src/__tests__/app-control-no-global-cgevent.test.ts +0 -98
  597. package/src/__tests__/credential-security-e2e.test.ts +0 -362
  598. package/src/__tests__/credential-vault-unit.test.ts +0 -1528
  599. package/src/__tests__/credential-vault.test.ts +0 -1706
  600. package/src/__tests__/identity-intro-cache.test.ts +0 -315
  601. package/src/__tests__/secret-onetime-send.test.ts +0 -182
  602. package/src/cli/commands/__tests__/task.test.ts +0 -914
  603. package/src/cli/commands/task.ts +0 -771
  604. package/src/config/bundled-skills/personal-page/SKILL.md +0 -57
  605. package/src/config/bundled-skills/personal-page/TOOLS.json +0 -27
  606. package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +0 -17
  607. package/src/config/preloaded-apps/personal-page/src/components/About.tsx +0 -22
  608. package/src/config/preloaded-apps/personal-page/src/components/App.tsx +0 -16
  609. package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +0 -77
  610. package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +0 -57
  611. package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +0 -28
  612. package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +0 -234
  613. package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +0 -48
  614. package/src/config/preloaded-apps/personal-page/src/components/media.ts +0 -16
  615. package/src/config/preloaded-apps/personal-page/src/index.html +0 -20
  616. package/src/config/preloaded-apps/personal-page/src/main.tsx +0 -7
  617. package/src/config/preloaded-apps/personal-page/src/profile-data.ts +0 -82
  618. package/src/config/preloaded-apps/personal-page/src/styles.css +0 -759
  619. package/src/memory/__tests__/preloaded-apps.test.ts +0 -85
  620. package/src/memory/preloaded-apps.ts +0 -116
  621. package/src/notifications/tool-approval-copy.ts +0 -142
  622. package/src/runtime/routes/approval-prompt-ts-tracker.ts +0 -78
  623. package/src/runtime/routes/identity-intro-cache.ts +0 -172
  624. package/src/tools/credentials/vault.ts +0 -712
@@ -92,7 +92,7 @@ mock.module("../runtime/channel-verification-service.js", () => ({
92
92
  return null;
93
93
  },
94
94
  createOutboundSession: () => ({
95
- conversationId: "test-session",
95
+ sessionId: "test-session",
96
96
  secret: "123456",
97
97
  }),
98
98
  bindSessionIdentity: () => {},
@@ -108,16 +108,23 @@ mock.module("../runtime/channel-verification-service.js", () => ({
108
108
  }),
109
109
  }));
110
110
 
111
- // Mock gateway client — capture delivery calls
111
+ // Mock gateway client — capture delivery calls. `failDeliveryWhen` lets a test
112
+ // simulate a delivery failure for a specific payload (e.g. a DM that can't be
113
+ // opened) so fallback paths can be exercised.
112
114
  const deliveredReplies: Array<{
113
115
  url: string;
114
116
  payload: Record<string, unknown>;
115
117
  }> = [];
118
+ let failDeliveryWhen: ((payload: Record<string, unknown>) => boolean) | null =
119
+ null;
116
120
  mock.module("../runtime/gateway-client.js", () => ({
117
121
  deliverChannelReply: async (
118
122
  url: string,
119
123
  payload: Record<string, unknown>,
120
124
  ) => {
125
+ if (failDeliveryWhen?.(payload)) {
126
+ throw new Error("simulated delivery failure");
127
+ }
121
128
  deliveredReplies.push({ url, payload });
122
129
  return { ok: true };
123
130
  },
@@ -150,6 +157,7 @@ mock.module("../config/env.js", () => ({
150
157
  import { applyCanonicalGuardianDecision } from "../approvals/guardian-decision-primitive.js";
151
158
  import type { ActorContext } from "../approvals/guardian-request-resolvers.js";
152
159
  import { getResolver } from "../approvals/guardian-request-resolvers.js";
160
+ import { upsertContactChannel } from "../contacts/contacts-write.js";
153
161
  import type { TrustContext } from "../daemon/trust-context.js";
154
162
  import {
155
163
  createCanonicalGuardianRequest,
@@ -564,7 +572,7 @@ describe("(d) unknown actor flow: fail-closed with no interactive approval", ()
564
572
 
565
573
  expect("skipped" in result && result.skipped).toBe(true);
566
574
  if ("skipped" in result) {
567
- expect(result.reason).toBe("not_trusted_contact");
575
+ expect(result.reason).toBe("not_bridgeable_trust_class");
568
576
  }
569
577
  });
570
578
  });
@@ -1088,3 +1096,212 @@ describe("cross-milestone integration checks", () => {
1088
1096
  });
1089
1097
  });
1090
1098
 
1099
+ // ===========================================================================
1100
+ // (g) access_request resolver: requester verification-code delivery
1101
+ //
1102
+ // On approval the requester must receive the 6-digit code so the guardian
1103
+ // never has to relay it by hand. On Slack the code is DM'd straight to the
1104
+ // requester (a private path is guaranteed via their user ID); other channels
1105
+ // keep the courier message because a private path to the requester is not
1106
+ // guaranteed there (e.g. a group chat would leak the secret).
1107
+ // ===========================================================================
1108
+
1109
+ describe("(g) access_request resolver: requester code delivery", () => {
1110
+ const REQUESTER_UID = "U_REQUESTER";
1111
+ const GUARDIAN_UID = "U_GUARDIAN";
1112
+
1113
+ function createAccessRequest(overrides: Record<string, unknown> = {}) {
1114
+ return createCanonicalGuardianRequest({
1115
+ id: `access-req-${Date.now()}-${Math.random().toString(36).slice(2)}`,
1116
+ kind: "access_request",
1117
+ sourceType: "channel",
1118
+ sourceChannel: "slack",
1119
+ conversationId: "conv-access-slack",
1120
+ requesterExternalUserId: REQUESTER_UID,
1121
+ requesterChatId: "C_SHARED_CHANNEL",
1122
+ guardianExternalUserId: GUARDIAN_UID,
1123
+ guardianPrincipalId: "test-principal-id",
1124
+ toolName: "ingress_access_request",
1125
+ expiresAt: Date.now() + 60_000,
1126
+ ...overrides,
1127
+ });
1128
+ }
1129
+
1130
+ beforeEach(() => {
1131
+ resetTables();
1132
+ deliveredReplies.length = 0;
1133
+ emittedSignals.length = 0;
1134
+ failDeliveryWhen = null;
1135
+ });
1136
+
1137
+ test("on-channel Slack approval DMs the verification code to the requester", async () => {
1138
+ const req = createAccessRequest();
1139
+
1140
+ const result = await applyCanonicalGuardianDecision({
1141
+ requestId: req.id,
1142
+ action: "approve_once",
1143
+ actorContext: guardianActor({
1144
+ channel: "slack",
1145
+ actorExternalUserId: GUARDIAN_UID,
1146
+ }),
1147
+ channelDeliveryContext: {
1148
+ replyCallbackUrl:
1149
+ "http://localhost:3000/deliver/slack?threadTs=111.222",
1150
+ guardianChatId: "C_SHARED_CHANNEL",
1151
+ assistantId: "self",
1152
+ },
1153
+ });
1154
+
1155
+ expect(result.applied).toBe(true);
1156
+
1157
+ // The requester receives the actual code in their DM (chatId = user ID),
1158
+ // not a "ask the guardian" courier message.
1159
+ const requesterCodeReply = deliveredReplies.find(
1160
+ (r) =>
1161
+ r.payload.chatId === REQUESTER_UID &&
1162
+ typeof r.payload.text === "string" &&
1163
+ (r.payload.text as string).includes("123456"),
1164
+ );
1165
+ expect(requesterCodeReply).toBeDefined();
1166
+ expect(requesterCodeReply!.payload.text).toContain(
1167
+ "your access request was approved",
1168
+ );
1169
+ // The code DM is durable, never ephemeral.
1170
+ expect(requesterCodeReply!.payload.ephemeral).toBeUndefined();
1171
+ // threadTs (the guardian's channel thread) is stripped for the DM.
1172
+ expect(requesterCodeReply!.url).not.toContain("threadTs");
1173
+
1174
+ // No courier "receive from the guardian" message goes to the requester.
1175
+ const courier = deliveredReplies.find(
1176
+ (r) =>
1177
+ typeof r.payload.text === "string" &&
1178
+ (r.payload.text as string).includes("receive from the guardian"),
1179
+ );
1180
+ expect(courier).toBeUndefined();
1181
+ });
1182
+
1183
+ test("desktop-decided approval DMs the code to the Slack requester via the deliver path", async () => {
1184
+ const req = createAccessRequest();
1185
+
1186
+ const result = await applyCanonicalGuardianDecision({
1187
+ requestId: req.id,
1188
+ action: "approve_once",
1189
+ // Desktop decision: no channelDeliveryContext, actor on the vellum channel.
1190
+ actorContext: guardianActor({
1191
+ channel: "vellum",
1192
+ actorExternalUserId: undefined,
1193
+ }),
1194
+ });
1195
+
1196
+ expect(result.applied).toBe(true);
1197
+
1198
+ const requesterCodeReply = deliveredReplies.find(
1199
+ (r) =>
1200
+ r.payload.chatId === REQUESTER_UID &&
1201
+ typeof r.payload.text === "string" &&
1202
+ (r.payload.text as string).includes("123456"),
1203
+ );
1204
+ expect(requesterCodeReply).toBeDefined();
1205
+ expect(requesterCodeReply!.url).toContain("/deliver/slack");
1206
+ expect(requesterCodeReply!.payload.text).toContain(
1207
+ "your access request was approved",
1208
+ );
1209
+ });
1210
+
1211
+ test("non-Slack channel keeps the courier message and never delivers the code to the requester chat", async () => {
1212
+ const req = createAccessRequest({
1213
+ sourceChannel: "telegram",
1214
+ requesterChatId: "requester-chat-1",
1215
+ conversationId: "conv-access-telegram",
1216
+ });
1217
+
1218
+ const result = await applyCanonicalGuardianDecision({
1219
+ requestId: req.id,
1220
+ action: "approve_once",
1221
+ actorContext: guardianActor({
1222
+ channel: "telegram",
1223
+ actorExternalUserId: GUARDIAN_UID,
1224
+ }),
1225
+ channelDeliveryContext: {
1226
+ replyCallbackUrl: "http://localhost:3000/deliver/telegram",
1227
+ guardianChatId: "guardian-chat-1",
1228
+ assistantId: "self",
1229
+ },
1230
+ });
1231
+
1232
+ expect(result.applied).toBe(true);
1233
+
1234
+ // The requester is told to expect the code from the guardian; the secret is
1235
+ // never delivered to the requester's (possibly group) chat.
1236
+ const requesterReply = deliveredReplies.find(
1237
+ (r) => r.payload.chatId === "requester-chat-1",
1238
+ );
1239
+ expect(requesterReply).toBeDefined();
1240
+ expect(requesterReply!.payload.text).toContain("receive from the guardian");
1241
+ expect(requesterReply!.payload.text).not.toContain("123456");
1242
+ });
1243
+
1244
+ test("Slack shared-channel fallback posts an ephemeral notice to the channel when the DM fails", async () => {
1245
+ const req = createAccessRequest();
1246
+
1247
+ // Make the direct DM (to the U... user ID) fail so the courier fallback runs.
1248
+ failDeliveryWhen = (payload) => payload.chatId === REQUESTER_UID;
1249
+
1250
+ const result = await applyCanonicalGuardianDecision({
1251
+ requestId: req.id,
1252
+ action: "approve_once",
1253
+ actorContext: guardianActor({
1254
+ channel: "slack",
1255
+ actorExternalUserId: GUARDIAN_UID,
1256
+ }),
1257
+ channelDeliveryContext: {
1258
+ replyCallbackUrl:
1259
+ "http://localhost:3000/deliver/slack?threadTs=111.222",
1260
+ guardianChatId: "C_SHARED_CHANNEL",
1261
+ assistantId: "self",
1262
+ },
1263
+ });
1264
+
1265
+ expect(result.applied).toBe(true);
1266
+
1267
+ // The courier notice falls back to an ephemeral message targeting the
1268
+ // originating channel (C...), since chat.postEphemeral needs a channel ID —
1269
+ // not the requester's user ID.
1270
+ const courier = deliveredReplies.find(
1271
+ (r) =>
1272
+ typeof r.payload.text === "string" &&
1273
+ (r.payload.text as string).includes("receive from the guardian"),
1274
+ );
1275
+ expect(courier).toBeDefined();
1276
+ expect(courier!.payload.chatId).toBe("C_SHARED_CHANNEL");
1277
+ expect(courier!.payload.ephemeral).toBe(true);
1278
+ expect(courier!.payload.user).toBe(REQUESTER_UID);
1279
+ });
1280
+
1281
+ test("guardian-facing reply uses the requester's display name, not the raw ID", async () => {
1282
+ // Seed a contact so the resolver can resolve a display name.
1283
+ upsertContactChannel({
1284
+ sourceChannel: "slack",
1285
+ externalUserId: REQUESTER_UID,
1286
+ displayName: "Alice",
1287
+ status: "unverified",
1288
+ });
1289
+
1290
+ const req = createAccessRequest();
1291
+
1292
+ const result = await applyCanonicalGuardianDecision({
1293
+ requestId: req.id,
1294
+ action: "approve_once",
1295
+ // Desktop decision → resolver returns guardianReplyText for assertion.
1296
+ actorContext: guardianActor({
1297
+ channel: "vellum",
1298
+ actorExternalUserId: undefined,
1299
+ }),
1300
+ });
1301
+
1302
+ expect(result.applied).toBe(true);
1303
+ const replyText = result.applied ? result.resolverReplyText : undefined;
1304
+ expect(replyText).toContain("Alice");
1305
+ expect(replyText).not.toContain(REQUESTER_UID);
1306
+ });
1307
+ });
@@ -266,7 +266,7 @@ for (const config of CHANNEL_CONFIGS) {
266
266
 
267
267
  const contactResult = findContactChannel({
268
268
  channelType: config.channel,
269
- externalUserId: config.senderExternalUserId,
269
+ address: config.senderExternalUserId,
270
270
  });
271
271
 
272
272
  expect(contactResult).not.toBeNull();
@@ -288,7 +288,7 @@ for (const config of CHANNEL_CONFIGS) {
288
288
  // Should be found on this channel
289
289
  const sameChanResult = findContactChannel({
290
290
  channelType: config.channel,
291
- externalUserId: config.senderExternalUserId,
291
+ address: config.senderExternalUserId,
292
292
  });
293
293
  expect(sameChanResult).not.toBeNull();
294
294
 
@@ -296,7 +296,7 @@ for (const config of CHANNEL_CONFIGS) {
296
296
  const otherChannel = config.channel === "telegram" ? "slack" : "telegram";
297
297
  const crossChanResult = findContactChannel({
298
298
  channelType: otherChannel,
299
- externalUserId: config.senderExternalUserId,
299
+ address: config.senderExternalUserId,
300
300
  });
301
301
  expect(crossChanResult).toBeNull();
302
302
  });
@@ -102,13 +102,13 @@ describe("trusted contact verification → member activation", () => {
102
102
  // Verify: active member record exists
103
103
  const contactResult = findContactChannel({
104
104
  channelType: "telegram",
105
- externalUserId: "requester-user-123",
105
+ address: "requester-user-123",
106
106
  });
107
107
 
108
108
  expect(contactResult).not.toBeNull();
109
109
  expect(contactResult!.channel.status).toBe("active");
110
110
  expect(contactResult!.channel.policy).toBe("allow");
111
- expect(contactResult!.channel.externalUserId).toBe("requester-user-123");
111
+ expect(contactResult!.channel.address).toBe("requester-user-123");
112
112
  expect(contactResult!.channel.externalChatId).toBe("requester-chat-123");
113
113
  expect(contactResult!.contact.displayName).toBe("Requester Name");
114
114
  expect(contactResult!.channel.type).toBe("telegram");
@@ -236,7 +236,7 @@ describe("trusted contact verification → member activation", () => {
236
236
  // Simulate the ACL check that inbound-message-handler performs
237
237
  const contactResult = findContactChannel({
238
238
  channelType: "telegram",
239
- externalUserId: "requester-user-456",
239
+ address: "requester-user-456",
240
240
  });
241
241
 
242
242
  expect(contactResult).not.toBeNull();
@@ -274,7 +274,7 @@ describe("trusted contact verification → member activation", () => {
274
274
  // Member should be found via contacts
275
275
  const contactResult = findContactChannel({
276
276
  channelType: "telegram",
277
- externalUserId: "user-cross-test",
277
+ address: "user-cross-test",
278
278
  });
279
279
  expect(contactResult).not.toBeNull();
280
280
  expect(contactResult!.channel.status).toBe("active");
@@ -282,7 +282,7 @@ describe("trusted contact verification → member activation", () => {
282
282
  // Member should NOT be found for a different channel type
283
283
  const otherChannel = findContactChannel({
284
284
  channelType: "slack",
285
- externalUserId: "user-cross-test",
285
+ address: "user-cross-test",
286
286
  });
287
287
  expect(otherChannel).toBeNull();
288
288
  });
@@ -306,7 +306,7 @@ describe("trusted contact verification → member activation", () => {
306
306
  // Verify the member is indeed revoked (ACL would reject)
307
307
  const revokedResult = findContactChannel({
308
308
  channelType: "telegram",
309
- externalUserId: "user-revoked",
309
+ address: "user-revoked",
310
310
  });
311
311
  expect(revokedResult).not.toBeNull();
312
312
  expect(revokedResult!.channel.status).toBe("revoked");
@@ -345,7 +345,7 @@ describe("trusted contact verification → member activation", () => {
345
345
  // Verify: member is now active again
346
346
  const reactivatedResult = findContactChannel({
347
347
  channelType: "telegram",
348
- externalUserId: "user-revoked",
348
+ address: "user-revoked",
349
349
  });
350
350
  expect(reactivatedResult).not.toBeNull();
351
351
  expect(reactivatedResult!.channel.status).toBe("active");
@@ -390,9 +390,7 @@ describe("trusted contact verification → member activation", () => {
390
390
  // The original guardian binding should remain intact
391
391
  const guardianResult = findGuardianForChannel("telegram");
392
392
  expect(guardianResult).not.toBeNull();
393
- expect(guardianResult!.channel.externalUserId).toBe(
394
- "guardian-user-original",
395
- );
393
+ expect(guardianResult!.channel.address).toBe("guardian-user-original");
396
394
  });
397
395
 
398
396
  test("guardian inbound verification succeeds but does not create binding", async () => {
@@ -92,8 +92,21 @@ let mockRouteSetupResult: {
92
92
  },
93
93
  };
94
94
 
95
+ // Captures the last context passed to routeSetup so preflight tests can
96
+ // assert the resolved phone admission policy was threaded through.
97
+ let lastRouteSetupCtx: Record<string, unknown> | null = null;
95
98
  mock.module("../calls/relay-setup-router.js", () => ({
96
- routeSetup: () => mockRouteSetupResult,
99
+ routeSetup: (ctx: Record<string, unknown>) => {
100
+ lastRouteSetupCtx = ctx;
101
+ return mockRouteSetupResult;
102
+ },
103
+ }));
104
+
105
+ // Mock the phone channel admission reader used by the media-stream preflight.
106
+ // Tests override mockAdmissionPolicy to exercise floor classification.
107
+ let mockAdmissionPolicy: unknown = null;
108
+ mock.module("../calls/channel-admission-reader.js", () => ({
109
+ getChannelAdmissionPolicy: async () => mockAdmissionPolicy,
97
110
  }));
98
111
 
99
112
  mock.module("../config/env.js", () => ({
@@ -454,6 +467,9 @@ describe("twilio webhook routes", () => {
454
467
  mockTwilioApiValidationBody = JSON.stringify({ sid: "AC_validated" });
455
468
  // Reset STT config to defaults between tests
456
469
  mockConfigObj.services.stt.provider = "deepgram" as any;
470
+ // Reset admission policy + captured routeSetup context between tests
471
+ mockAdmissionPolicy = null;
472
+ lastRouteSetupCtx = null;
457
473
  // Reset routeSetup mock to default normal_call
458
474
  mockRouteSetupResult = {
459
475
  outcome: { action: "normal_call", isInbound: true },
@@ -1228,6 +1244,70 @@ describe("twilio webhook routes", () => {
1228
1244
  expect(twiml).not.toContain("<ConversationRelay");
1229
1245
  });
1230
1246
 
1247
+ test("media-stream: resolves the phone admission floor and threads it into the preflight routeSetup", async () => {
1248
+ mockConfigObj.services.stt.provider = "openai-whisper" as any;
1249
+ mockAdmissionPolicy = "guardian_only";
1250
+ mockRouteSetupResult = {
1251
+ outcome: { action: "normal_call", isInbound: true },
1252
+ resolved: {
1253
+ assistantId: "self",
1254
+ isInbound: true,
1255
+ otherPartyNumber: "+15559998888",
1256
+ actorTrust: { trustClass: "guardian", memberRecord: null },
1257
+ },
1258
+ };
1259
+
1260
+ const session = createTestSession("conv-ms-floor-1", "CA_ms_floor_1");
1261
+ const req = makeVoiceRequest(session.id, { CallSid: "CA_ms_floor_1" });
1262
+
1263
+ const res = await handleVoiceWebhook(req);
1264
+ expect(res.status).toBe(200);
1265
+
1266
+ // The resolved floor was passed into the preflight routeSetup so its
1267
+ // classification matches the real stream-start enforcement.
1268
+ expect(lastRouteSetupCtx).not.toBeNull();
1269
+ expect(lastRouteSetupCtx?.admissionPolicy).toBe("guardian_only");
1270
+ });
1271
+
1272
+ test("media-stream: floor-denied caller classified deny still produces Stream TwiML (deny handled at stream level)", async () => {
1273
+ mockConfigObj.services.stt.provider = "openai-whisper" as any;
1274
+ mockAdmissionPolicy = "guardian_only";
1275
+ // With the floor wired, the real router returns `deny` for a
1276
+ // below-floor trusted_contact caller; the mock reflects that.
1277
+ mockRouteSetupResult = {
1278
+ outcome: {
1279
+ action: "deny",
1280
+ message:
1281
+ "This number is not authorized to reach the assistant right now.",
1282
+ logReason: "Inbound voice admission floor: guardian_only",
1283
+ },
1284
+ resolved: {
1285
+ assistantId: "self",
1286
+ isInbound: true,
1287
+ otherPartyNumber: "+14155550000",
1288
+ actorTrust: { trustClass: "trusted_contact", memberRecord: null },
1289
+ },
1290
+ };
1291
+
1292
+ const session = createTestSession(
1293
+ "conv-ms-floor-deny-1",
1294
+ "CA_ms_floor_deny_1",
1295
+ );
1296
+ const req = makeVoiceRequest(session.id, {
1297
+ CallSid: "CA_ms_floor_deny_1",
1298
+ });
1299
+
1300
+ const res = await handleVoiceWebhook(req);
1301
+ expect(res.status).toBe(200);
1302
+
1303
+ // Policy was threaded; deny is supported on media-stream, so Stream
1304
+ // TwiML is still produced (denial spoken + torn down at stream start).
1305
+ expect(lastRouteSetupCtx?.admissionPolicy).toBe("guardian_only");
1306
+ const twiml = await res.text();
1307
+ expect(twiml).toContain("<Stream");
1308
+ expect(twiml).not.toContain("<ConversationRelay");
1309
+ });
1310
+
1231
1311
  test("media-stream: deny setup proceeds with Stream TwiML (deny is handled at stream level)", async () => {
1232
1312
  mockConfigObj.services.stt.provider = "openai-whisper" as any;
1233
1313
  mockRouteSetupResult = {
@@ -180,7 +180,7 @@ describe("redeemVoiceInviteCode", () => {
180
180
 
181
181
  const channelResult = findContactChannel({
182
182
  channelType: "phone",
183
- externalUserId: phone,
183
+ address: phone,
184
184
  });
185
185
 
186
186
  expect(channelResult).not.toBeNull();
@@ -368,7 +368,6 @@ describe("redeemVoiceInviteCode", () => {
368
368
  {
369
369
  type: "phone",
370
370
  address: phone,
371
- externalUserId: phone,
372
371
  status: "revoked",
373
372
  },
374
373
  ],
@@ -399,7 +398,7 @@ describe("redeemVoiceInviteCode", () => {
399
398
  // Verify the redeemer's phone is now bound to Mom's contact
400
399
  const contactResult = findContactChannel({
401
400
  channelType: "phone",
402
- externalUserId: phone,
401
+ address: phone,
403
402
  });
404
403
  expect(contactResult).not.toBeNull();
405
404
  expect(contactResult!.contact.id).toBe(momContact.id);
@@ -0,0 +1,30 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { isWeakOpenModel } from "../providers/weak-open-model.js";
4
+
5
+ describe("isWeakOpenModel", () => {
6
+ test("matches weak open models across provider naming conventions", () => {
7
+ for (const model of [
8
+ "accounts/fireworks/models/minimax-m3",
9
+ "minimax/minimax-m3",
10
+ "moonshotai/kimi-k2.6",
11
+ "accounts/fireworks/models/kimi-k2p6",
12
+ "deepseek/deepseek-chat",
13
+ "accounts/fireworks/models/glm-5p2",
14
+ ]) {
15
+ expect(isWeakOpenModel(model)).toBe(true);
16
+ }
17
+ });
18
+
19
+ test("does not match capable models", () => {
20
+ for (const model of ["claude-opus-4-8", "claude-sonnet-4-6", "gpt-5.5"]) {
21
+ expect(isWeakOpenModel(model)).toBe(false);
22
+ }
23
+ });
24
+
25
+ test("is false for null/undefined/empty", () => {
26
+ expect(isWeakOpenModel(null)).toBe(false);
27
+ expect(isWeakOpenModel(undefined)).toBe(false);
28
+ expect(isWeakOpenModel("")).toBe(false);
29
+ });
30
+ });
@@ -8,20 +8,15 @@ import {
8
8
  } from "../providers/search-provider-catalog.js";
9
9
 
10
10
  /**
11
- * Parity guard: daemon TS catalog vs the two generated JSON copies.
11
+ * Parity guard: daemon TS catalog vs the generated JSON copy.
12
12
  *
13
13
  * The daemon maintains its canonical search-provider catalog in
14
14
  * `assistant/src/providers/search-provider-catalog.ts`.
15
- * `assistant/scripts/sync-web-search-catalog.ts` writes two byte-identical
16
- * artifacts:
17
- * - `meta/web-search-provider-catalog.json` — primary cross-package artifact.
18
- * - `clients/shared/Resources/web-search-provider-catalog.json` — SwiftPM
19
- * resource bundled into `VellumAssistantShared` (Swift cannot reach
20
- * files outside a target's source directory).
15
+ * `assistant/scripts/sync-web-search-catalog.ts` writes
16
+ * `meta/web-search-provider-catalog.json` — the primary cross-package artifact.
21
17
  *
22
18
  * These tests enforce structural equality between the TS catalog and the
23
- * meta/ copy, plus byte equality between the meta/ copy and the SwiftPM
24
- * mirror. CI fails when any of the three drift.
19
+ * meta/ copy. CI fails when they drift.
25
20
  */
26
21
 
27
22
  interface JsonCatalogEntry {
@@ -46,11 +41,6 @@ const META_JSON_PATH = join(
46
41
  "..",
47
42
  "meta/web-search-provider-catalog.json",
48
43
  );
49
- const SWIFTPM_MIRROR_PATH = join(
50
- process.cwd(),
51
- "..",
52
- "clients/shared/Resources/web-search-provider-catalog.json",
53
- );
54
44
 
55
45
  function loadJsonCatalog(): JsonCatalog {
56
46
  return JSON.parse(readFileSync(META_JSON_PATH, "utf-8"));
@@ -73,7 +63,8 @@ function entryToPlain(
73
63
  if (entry.apiKeyPrefix !== undefined) out.apiKeyPrefix = entry.apiKeyPrefix;
74
64
  if (entry.envVar !== undefined) out.envVar = entry.envVar;
75
65
  if (entry.secretKey !== undefined) out.secretKey = entry.secretKey;
76
- if (entry.fallbackOrder !== undefined) out.fallbackOrder = entry.fallbackOrder;
66
+ if (entry.fallbackOrder !== undefined)
67
+ out.fallbackOrder = entry.fallbackOrder;
77
68
  if (entry.privacyPolicyUrl !== undefined) {
78
69
  out.privacyPolicyUrl = entry.privacyPolicyUrl;
79
70
  }
@@ -95,14 +86,4 @@ describe("web-search catalog parity (TS canonical vs meta/ JSON)", () => {
95
86
  SEARCH_PROVIDER_CATALOG.map((p) => p.id),
96
87
  );
97
88
  });
98
-
99
- test("SwiftPM mirror is byte-identical to meta/ copy", () => {
100
- // The generator writes both files from the same serializer; this guard
101
- // catches any case where one copy is regenerated without the other.
102
- // Byte equality is required because SwiftPM bundles the resource verbatim
103
- // and the meta/ JSON is consumed as a cross-package artifact.
104
- const metaBytes = readFileSync(META_JSON_PATH);
105
- const swiftPmBytes = readFileSync(SWIFTPM_MIRROR_PATH);
106
- expect(swiftPmBytes.equals(metaBytes)).toBe(true);
107
- });
108
89
  });