@vellumai/assistant 0.9.0 → 0.10.0-staging.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 (572) hide show
  1. package/ARCHITECTURE.md +18 -34
  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 +976 -63
  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__/always-loaded-tools-guard.test.ts +2 -3
  28. package/src/__tests__/app-compiler.test.ts +15 -1
  29. package/src/__tests__/app-dir-path-guard.test.ts +0 -1
  30. package/src/__tests__/assistant-feature-flag-guard.test.ts +1 -4
  31. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
  32. package/src/__tests__/auth-fallback-events-store.test.ts +6 -14
  33. package/src/__tests__/avatar-identity-sync.test.ts +2 -27
  34. package/src/__tests__/btw-routes.test.ts +6 -8
  35. package/src/__tests__/call-pointer-messages.test.ts +28 -0
  36. package/src/__tests__/cancel-clears-processing.test.ts +89 -0
  37. package/src/__tests__/channel-approval-routes.test.ts +0 -4
  38. package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -15
  39. package/src/__tests__/checker.test.ts +0 -3
  40. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +3 -4
  41. package/src/__tests__/compactor-image-manifest-trust.test.ts +21 -1
  42. package/src/__tests__/compactor-summary-call-truncation.test.ts +223 -0
  43. package/src/__tests__/config-loader-backfill.test.ts +268 -27
  44. package/src/__tests__/config-schema.test.ts +35 -0
  45. package/src/__tests__/config-watcher.test.ts +0 -18
  46. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -2
  47. package/src/__tests__/contact-store-user-file.test.ts +0 -6
  48. package/src/__tests__/contacts-tools.test.ts +29 -0
  49. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +22 -0
  50. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  51. package/src/__tests__/conversation-agent-loop.test.ts +58 -0
  52. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  53. package/src/__tests__/conversation-lifecycle.test.ts +7 -9
  54. package/src/__tests__/conversation-load-history-repair.test.ts +101 -0
  55. package/src/__tests__/conversation-routes-guardian-reply.test.ts +15 -12
  56. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -3
  57. package/src/__tests__/conversation-title-service.test.ts +62 -0
  58. package/src/__tests__/credential-broker.test.ts +449 -1
  59. package/src/__tests__/credential-execution-shell-lockdown.test.ts +18 -11
  60. package/src/__tests__/credential-execution-tools.test.ts +0 -1
  61. package/src/__tests__/credential-prompt-route.test.ts +4 -4
  62. package/src/__tests__/credential-routes.test.ts +360 -0
  63. package/src/__tests__/credential-security-invariants.test.ts +4 -13
  64. package/src/__tests__/disk-pressure-policy.test.ts +12 -0
  65. package/src/__tests__/disk-usage.test.ts +65 -0
  66. package/src/__tests__/dynamic-page-surface.test.ts +152 -1
  67. package/src/__tests__/fixtures/credential-security-fixtures.ts +2 -33
  68. package/src/__tests__/gateway-flag-listener.test.ts +110 -1
  69. package/src/__tests__/gateway-only-guard.test.ts +3 -7
  70. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  71. package/src/__tests__/guardian-card-withdrawal.test.ts +403 -0
  72. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +5 -3
  73. package/src/__tests__/guardian-grant-minting.test.ts +3 -35
  74. package/src/__tests__/guardian-routing-invariants.test.ts +64 -26
  75. package/src/__tests__/guardian-routing-state.test.ts +0 -1
  76. package/src/__tests__/headless-browser-mode.test.ts +10 -0
  77. package/src/__tests__/headless-browser-navigate.test.ts +8 -3
  78. package/src/__tests__/helpers/create-guardian-binding.ts +0 -1
  79. package/src/__tests__/host-browser-proxy.test.ts +87 -0
  80. package/src/__tests__/identity-routes.test.ts +0 -189
  81. package/src/__tests__/inbound-invite-redemption.test.ts +4 -4
  82. package/src/__tests__/injector-v3-suppression.test.ts +27 -20
  83. package/src/__tests__/internal-telemetry-routes.test.ts +6 -14
  84. package/src/__tests__/invite-redemption-service.test.ts +4 -7
  85. package/src/__tests__/llm-callsite-catalog.test.ts +5 -6
  86. package/src/__tests__/llm-catalog-parity.test.ts +30 -23
  87. package/src/__tests__/llm-resolver.test.ts +70 -24
  88. package/src/__tests__/llm-schema.test.ts +1 -0
  89. package/src/__tests__/managed-profile-guard.test.ts +163 -4
  90. package/src/__tests__/mcp-health-check.test.ts +6 -7
  91. package/src/__tests__/media-stream-server-integration.test.ts +317 -13
  92. package/src/__tests__/oauth-provider-seed-logos.test.ts +4 -6
  93. package/src/__tests__/onboarding-persona-write.test.ts +1 -1
  94. package/src/__tests__/path-policy.test.ts +34 -0
  95. package/src/__tests__/persona-resolver.test.ts +49 -14
  96. package/src/__tests__/plugin-api-model-profiles.test.ts +178 -0
  97. package/src/__tests__/plugin-api-provider.test.ts +24 -0
  98. package/src/__tests__/plugin-tool-contribution.test.ts +6 -3
  99. package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +214 -0
  100. package/src/__tests__/provider-send-message-override-profile.test.ts +76 -0
  101. package/src/__tests__/reaction-persistence.test.ts +150 -29
  102. package/src/__tests__/registry.test.ts +2 -7
  103. package/src/__tests__/relay-server.test.ts +285 -0
  104. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
  105. package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -10
  106. package/src/__tests__/schedule-routes.test.ts +0 -30
  107. package/src/__tests__/schedule-tools.test.ts +2 -18
  108. package/src/__tests__/scheduler-reuse-conversation.test.ts +8 -5
  109. package/src/__tests__/skill-execute-input.test.ts +51 -1
  110. package/src/__tests__/skill-runtime-path.test.ts +2 -3
  111. package/src/__tests__/skills.test.ts +51 -0
  112. package/src/__tests__/slack-notification-approval-card.test.ts +176 -0
  113. package/src/__tests__/slack-reaction-canonical-approval.test.ts +285 -0
  114. package/src/__tests__/subagent-tools.test.ts +266 -0
  115. package/src/__tests__/surface-completion-nudge-hook.test.ts +367 -0
  116. package/src/__tests__/task-progress-nudge-hook.test.ts +1 -1
  117. package/src/__tests__/title-generate-hook.test.ts +100 -3
  118. package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1 -29
  119. package/src/__tests__/token-manager.test.ts +519 -0
  120. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +1 -1
  121. package/src/__tests__/tool-audit-listener.test.ts +7 -7
  122. package/src/__tests__/tool-executor-lifecycle-events.test.ts +6 -3
  123. package/src/__tests__/tool-executor.test.ts +0 -79
  124. package/src/__tests__/trusted-contact-approval-notifier.test.ts +4 -2
  125. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +220 -3
  126. package/src/__tests__/trusted-contact-multichannel.test.ts +3 -3
  127. package/src/__tests__/trusted-contact-verification.test.ts +8 -10
  128. package/src/__tests__/twilio-routes.test.ts +81 -1
  129. package/src/__tests__/voice-invite-redemption.test.ts +2 -3
  130. package/src/__tests__/weak-open-model.test.ts +30 -0
  131. package/src/__tests__/web-search-catalog-parity.test.ts +6 -25
  132. package/src/__tests__/workspace-greetings.test.ts +152 -0
  133. package/src/__tests__/workspace-migration-105-enable-memory-v3-live-for-new-workspaces.test.ts +149 -0
  134. package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +285 -0
  135. package/src/__tests__/workspace-migration-add-send-diagnostics.test.ts +1 -1
  136. package/src/__tests__/workspace-migration-drop-collect-usage-data.test.ts +118 -0
  137. package/src/__tests__/workspace-migration-drop-send-diagnostics.test.ts +118 -0
  138. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +0 -4
  139. package/src/agent/loop.ts +49 -29
  140. package/src/api/README.md +6 -6
  141. package/src/api/events/tool-result.ts +6 -0
  142. package/src/api/events/workflow-completed.ts +53 -0
  143. package/src/api/events/workflow-leaf-finished.ts +38 -0
  144. package/src/api/events/workflow-leaf-started.ts +35 -0
  145. package/src/api/events/workflow-progress.ts +32 -0
  146. package/src/api/events/workflow-started.ts +31 -0
  147. package/src/api/index.ts +40 -0
  148. package/src/api/responses/conversation-message.ts +28 -4
  149. package/src/api/responses/home.ts +26 -4
  150. package/src/api/responses/workflow-journal.ts +53 -0
  151. package/src/approvals/guardian-card-withdrawal.ts +145 -0
  152. package/src/approvals/guardian-decision-primitive.ts +26 -3
  153. package/src/approvals/guardian-request-resolvers.ts +183 -80
  154. package/src/calls/__tests__/channel-admission-reader.test.ts +132 -0
  155. package/src/calls/__tests__/relay-setup-router.test.ts +350 -0
  156. package/src/calls/call-pointer-messages.ts +10 -4
  157. package/src/calls/channel-admission-reader.ts +104 -0
  158. package/src/calls/guardian-dispatch.ts +17 -45
  159. package/src/calls/media-stream-server.ts +84 -2
  160. package/src/calls/relay-access-wait.ts +1 -1
  161. package/src/calls/relay-server.ts +66 -0
  162. package/src/calls/relay-setup-router.ts +82 -1
  163. package/src/calls/twilio-routes.ts +17 -8
  164. package/src/calls/voice-session-bridge.ts +2 -2
  165. package/src/cli/commands/clients.ts +3 -0
  166. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2-compare-render.test.ts +1 -1
  167. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2.test.ts +8 -7
  168. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v3.test.ts +5 -4
  169. package/src/cli/commands/memory/index.ts +30 -0
  170. package/src/cli/commands/{memory-v2-compare-render.ts → memory/memory-v2-compare-render.ts} +1 -1
  171. package/src/cli/commands/{memory-v2.ts → memory/memory-v2.ts} +6 -15
  172. package/src/cli/commands/{memory-v3.ts → memory/memory-v3.ts} +97 -11
  173. package/src/cli/commands/oauth/status.test.ts +36 -0
  174. package/src/cli/commands/oauth/status.ts +23 -3
  175. package/src/cli/commands/plugins.ts +197 -4
  176. package/src/cli/lib/__tests__/diff-plugin.test.ts +443 -0
  177. package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
  178. package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +443 -0
  179. package/src/cli/lib/__tests__/plugin-surfaces.test.ts +111 -0
  180. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +295 -2
  181. package/src/cli/lib/diff-plugin.ts +346 -0
  182. package/src/cli/lib/inspect-plugin.ts +12 -1
  183. package/src/cli/lib/install-from-github.ts +105 -17
  184. package/src/cli/lib/merge-plugin-tree.ts +328 -0
  185. package/src/cli/lib/plugin-fingerprint.ts +14 -0
  186. package/src/cli/lib/plugin-surfaces.ts +104 -0
  187. package/src/cli/lib/upgrade-plugin.ts +298 -10
  188. package/src/cli/program.ts +2 -6
  189. package/src/config/__tests__/sync-gated-profiles.test.ts +368 -0
  190. package/src/config/assistant-feature-flags.ts +22 -7
  191. package/src/config/bundled-skills/contacts/tools/contact-search.ts +0 -1
  192. package/src/config/bundled-skills/messaging/SKILL.md +6 -4
  193. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -8
  194. package/src/config/bundled-skills/subagent/SKILL.md +4 -0
  195. package/src/config/bundled-skills/subagent/TOOLS.json +4 -0
  196. package/src/config/bundled-skills/workflows/SKILL.md +14 -8
  197. package/src/config/bundled-tool-registry.ts +2 -7
  198. package/src/config/call-site-defaults.ts +15 -2
  199. package/src/config/feature-flag-registry.json +46 -31
  200. package/src/config/inference-profile-validation.ts +26 -0
  201. package/src/config/llm-resolver.ts +3 -0
  202. package/src/config/loader.ts +4 -0
  203. package/src/config/memory-v3-gate.ts +11 -0
  204. package/src/config/profile-order.ts +28 -0
  205. package/src/config/schema.ts +8 -6
  206. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  207. package/src/config/schemas/call-site-catalog.ts +7 -0
  208. package/src/config/schemas/channels.ts +11 -0
  209. package/src/config/schemas/elevenlabs.ts +0 -1
  210. package/src/config/schemas/llm.ts +31 -0
  211. package/src/config/schemas/memory-lifecycle.ts +3 -7
  212. package/src/config/schemas/memory-v3.ts +6 -0
  213. package/src/config/schemas/platform.ts +0 -8
  214. package/src/config/schemas/services.ts +18 -0
  215. package/src/config/seed-inference-profiles.ts +109 -44
  216. package/src/config/skills.ts +21 -0
  217. package/src/config/sync-gated-profiles.ts +220 -0
  218. package/src/contacts/contact-store.ts +89 -106
  219. package/src/contacts/contacts-write.ts +5 -22
  220. package/src/contacts/types.ts +0 -1
  221. package/src/context/compactor.ts +88 -54
  222. package/src/context/strip-injections.ts +58 -10
  223. package/src/context/token-estimator.ts +1 -1
  224. package/src/credential-execution/process-manager.ts +55 -14
  225. package/src/credential-execution/prompted-credential.ts +2 -3
  226. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -2
  227. package/src/daemon/config-watcher.ts +0 -4
  228. package/src/daemon/conversation-agent-loop-handlers.ts +2 -0
  229. package/src/daemon/conversation-agent-loop.ts +114 -22
  230. package/src/daemon/conversation-history.ts +1 -1
  231. package/src/daemon/conversation-lifecycle.ts +3 -5
  232. package/src/daemon/conversation-process.ts +13 -5
  233. package/src/daemon/conversation-runtime-assembly.ts +13 -15
  234. package/src/daemon/conversation-slash.ts +2 -23
  235. package/src/daemon/conversation-surfaces.ts +26 -0
  236. package/src/daemon/conversation-tool-setup.ts +27 -14
  237. package/src/daemon/conversation.ts +66 -14
  238. package/src/daemon/disk-pressure-policy.ts +5 -3
  239. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -1
  240. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -1
  241. package/src/daemon/handlers/config-a2a.ts +0 -2
  242. package/src/daemon/handlers/config-channels.ts +15 -16
  243. package/src/daemon/handlers/config-slack-channel.ts +22 -3
  244. package/src/daemon/handlers/conversations.ts +107 -0
  245. package/src/daemon/host-browser-proxy.ts +41 -0
  246. package/src/daemon/lifecycle.ts +55 -27
  247. package/src/daemon/message-provenance.ts +2 -0
  248. package/src/daemon/message-types/contacts.ts +0 -1
  249. package/src/daemon/message-types/conversations.ts +3 -3
  250. package/src/daemon/message-types/sync.ts +0 -1
  251. package/src/daemon/message-types/web-activity.ts +7 -1
  252. package/src/daemon/message-types/workflows.ts +83 -1
  253. package/src/daemon/orphan-reaper.test.ts +0 -19
  254. package/src/daemon/orphan-reaper.ts +2 -24
  255. package/src/daemon/server.ts +0 -10
  256. package/src/daemon/tool-setup-types.ts +4 -0
  257. package/src/daemon/trust-context.ts +1 -1
  258. package/src/events/tool-audit-listener.ts +2 -2
  259. package/src/home/feed-source-enrichment.test.ts +151 -0
  260. package/src/home/feed-source-enrichment.ts +176 -0
  261. package/src/home/relationship-state.ts +2 -4
  262. package/src/instrument.ts +18 -6
  263. package/src/ipc/__tests__/binary-result-ipc.test.ts +81 -0
  264. package/src/ipc/__tests__/clients-list-ipc.test.ts +20 -0
  265. package/src/ipc/assistant-server.ts +37 -4
  266. package/src/ipc/gateway-flag-listener.ts +18 -2
  267. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +5 -16
  268. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +7 -11
  269. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +37 -7
  270. package/src/memory/__tests__/memory-retrospective-job.test.ts +229 -401
  271. package/src/memory/__tests__/onboarding-events-store.test.ts +7 -7
  272. package/src/memory/auth-fallback-events-store.ts +2 -2
  273. package/src/memory/auto-analysis-enqueue.ts +3 -5
  274. package/src/memory/bookmark-crud.ts +1 -2
  275. package/src/memory/canonical-guardian-store.ts +39 -1
  276. package/src/memory/conversation-crud.ts +9 -4
  277. package/src/memory/conversation-key-store.ts +17 -2
  278. package/src/memory/conversation-title-service.ts +64 -7
  279. package/src/memory/db-init.ts +17 -17
  280. package/src/memory/embedding-backend.ts +38 -1
  281. package/src/memory/embedding-billing-breaker.ts +96 -0
  282. package/src/memory/jobs-store.ts +25 -13
  283. package/src/memory/jobs-worker.ts +54 -1
  284. package/src/memory/lifecycle-events-store.ts +2 -2
  285. package/src/memory/memory-retrospective-constants.ts +4 -4
  286. package/src/memory/memory-retrospective-enqueue.ts +31 -6
  287. package/src/memory/memory-retrospective-job.ts +28 -227
  288. package/src/memory/migrations/129-contact-channels-access-fields.ts +18 -9
  289. package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +14 -2
  290. package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +10 -0
  291. package/src/memory/migrations/291-contact-channels-renormalize-addresses.ts +72 -0
  292. package/src/memory/migrations/292-schedule-default-no-reuse-conversation.test.ts +67 -0
  293. package/src/memory/migrations/292-schedule-default-no-reuse-conversation.ts +25 -0
  294. package/src/memory/migrations/293-workflow-journal-leaf-tokens.ts +32 -0
  295. package/src/memory/migrations/294-drop-external-user-id.ts +31 -0
  296. package/src/memory/migrations/295-drop-approval-prompt-ts-tracker.ts +20 -0
  297. package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +110 -0
  298. package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.ts +68 -0
  299. package/src/memory/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +154 -0
  300. package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +31 -0
  301. package/src/memory/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +341 -0
  302. package/src/memory/migrations/__tests__/run-migrations.test.ts +52 -0
  303. package/src/memory/migrations/index.ts +6 -0
  304. package/src/memory/migrations/run-migrations.ts +41 -0
  305. package/src/memory/migrations/validate-migration-state.ts +1 -1
  306. package/src/memory/onboarding-events-store.ts +3 -3
  307. package/src/memory/schema/contacts.ts +0 -5
  308. package/src/memory/skill-loaded-events-store.test.ts +7 -15
  309. package/src/memory/skill-loaded-events-store.ts +2 -2
  310. package/src/memory/tool-executed-events-store.test.ts +7 -7
  311. package/src/memory/turn-trace-store.test.ts +736 -0
  312. package/src/memory/turn-trace-store.ts +364 -0
  313. package/src/memory/v2/__tests__/consolidation-job.test.ts +8 -0
  314. package/src/memory/v2/__tests__/skill-content.test.ts +30 -0
  315. package/src/memory/v2/consolidation-job.ts +2 -2
  316. package/src/memory/v2/skill-content.ts +25 -7
  317. package/src/memory/v2/skill-store.ts +7 -1
  318. package/src/memory/v3-eval/__tests__/eval-packets.test.ts +248 -0
  319. package/src/memory/v3-eval/eval-packets.ts +546 -0
  320. package/src/messaging/providers/slack/adapter.ts +1 -1
  321. package/src/messaging/providers/slack/api.ts +31 -0
  322. package/src/messaging/providers/slack/send.test.ts +114 -2
  323. package/src/messaging/providers/slack/send.ts +30 -7
  324. package/src/messaging/providers/slack/withdraw.test.ts +200 -0
  325. package/src/messaging/providers/slack/withdraw.ts +161 -0
  326. package/src/notifications/AGENTS.md +2 -0
  327. package/src/notifications/access-request-copy.ts +72 -59
  328. package/src/notifications/adapters/shared.ts +29 -0
  329. package/src/notifications/adapters/slack.ts +58 -103
  330. package/src/notifications/adapters/telegram.ts +2 -20
  331. package/src/notifications/approval-card-data.ts +333 -0
  332. package/src/notifications/broadcaster.ts +16 -3
  333. package/src/notifications/canonical-delivery-recorder.ts +139 -0
  334. package/src/notifications/copy-composer.ts +3 -3
  335. package/src/notifications/decision-engine.ts +4 -2
  336. package/src/notifications/destination-resolver.ts +4 -6
  337. package/src/notifications/guardian-question-mode.ts +10 -0
  338. package/src/notifications/home-feed-side-effect.ts +7 -16
  339. package/src/notifications/notification-utils.ts +19 -20
  340. package/src/notifications/signal.ts +79 -43
  341. package/src/notifications/types.ts +98 -121
  342. package/src/oauth/AGENTS.md +5 -24
  343. package/src/permissions/checker.test.ts +51 -0
  344. package/src/permissions/checker.ts +185 -26
  345. package/src/permissions/ipc-risk-types.ts +24 -0
  346. package/src/permissions/question-prompter.test.ts +27 -0
  347. package/src/permissions/question-prompter.ts +4 -0
  348. package/src/platform/client.test.ts +119 -0
  349. package/src/platform/client.ts +66 -0
  350. package/src/platform/consent-cache.test.ts +267 -0
  351. package/src/platform/consent-cache.ts +174 -0
  352. package/src/plugin-api/constants.ts +1 -1
  353. package/src/plugin-api/index.ts +33 -1
  354. package/src/plugin-api/model-profiles.ts +33 -0
  355. package/src/plugin-api/types.ts +50 -2
  356. package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +56 -0
  357. package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +43 -0
  358. package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +137 -0
  359. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +153 -0
  360. package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +138 -0
  361. package/src/plugins/defaults/advisor/__tests__/transcript.test.ts +147 -0
  362. package/src/plugins/defaults/advisor/advisor-gate.ts +29 -0
  363. package/src/plugins/defaults/advisor/advisor-state-store.ts +94 -0
  364. package/src/plugins/defaults/advisor/config.ts +21 -0
  365. package/src/plugins/defaults/advisor/consult.ts +93 -0
  366. package/src/plugins/defaults/advisor/hooks/post-model-call.ts +34 -0
  367. package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +30 -0
  368. package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +19 -0
  369. package/src/plugins/defaults/advisor/package.json +14 -0
  370. package/src/plugins/defaults/advisor/steering.ts +67 -0
  371. package/src/plugins/defaults/advisor/tools/advisor.ts +65 -0
  372. package/src/plugins/defaults/advisor/transcript.ts +76 -0
  373. package/src/plugins/defaults/index.ts +60 -0
  374. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +22 -9
  375. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
  376. package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +64 -0
  377. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +29 -21
  378. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1 -0
  379. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
  380. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +129 -9
  381. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +31 -4
  382. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +77 -2
  383. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +1 -0
  384. package/src/plugins/defaults/memory-v3-shadow/injector.ts +7 -10
  385. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +144 -11
  386. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +32 -20
  387. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +56 -3
  388. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +23 -2
  389. package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +276 -0
  390. package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +22 -0
  391. package/src/plugins/defaults/surface-completion-nudge/nudge-state-store.ts +46 -0
  392. package/src/plugins/defaults/surface-completion-nudge/package.json +14 -0
  393. package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +3 -13
  394. package/src/plugins/defaults/title-generate/hooks/stop.ts +56 -21
  395. package/src/prompts/persona-resolver.ts +14 -4
  396. package/src/prompts/templates/system-sections.ts +7 -2
  397. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  398. package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
  399. package/src/providers/__tests__/retry-callsite.test.ts +176 -0
  400. package/src/providers/atlascloud/client.ts +85 -0
  401. package/src/providers/fetch-provider-catalog.ts +85 -0
  402. package/src/providers/inference/adapter-factory.ts +3 -0
  403. package/src/providers/model-catalog.ts +58 -0
  404. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +33 -0
  405. package/src/providers/openai/chat-completions-provider.ts +7 -0
  406. package/src/providers/openai/responses-provider.ts +10 -0
  407. package/src/providers/provider-send-message.ts +11 -3
  408. package/src/providers/retry.ts +53 -12
  409. package/src/providers/search-provider-catalog.ts +10 -0
  410. package/src/providers/weak-open-model.ts +22 -0
  411. package/src/runtime/AGENTS.md +0 -1
  412. package/src/runtime/__tests__/agent-wake.test.ts +181 -0
  413. package/src/runtime/__tests__/client-health.test.ts +44 -0
  414. package/src/runtime/access-request-helper.ts +21 -53
  415. package/src/runtime/actor-trust-resolver.ts +59 -63
  416. package/src/runtime/agent-wake.ts +52 -0
  417. package/src/runtime/assistant-event-hub.ts +18 -4
  418. package/src/runtime/auth/__tests__/route-policy.test.ts +12 -0
  419. package/src/runtime/auth/require-bound-guardian.ts +1 -4
  420. package/src/runtime/btw-sidechain.ts +3 -6
  421. package/src/runtime/capabilities.test.ts +120 -0
  422. package/src/runtime/capabilities.ts +197 -0
  423. package/src/runtime/channel-approval-types.ts +22 -45
  424. package/src/runtime/channel-invite-transports/telegram.ts +4 -4
  425. package/src/runtime/channel-retry-sweep.ts +1 -0
  426. package/src/runtime/channel-verification-service.ts +3 -3
  427. package/src/runtime/client-health.ts +26 -0
  428. package/src/runtime/confirmation-request-guardian-bridge.ts +38 -29
  429. package/src/runtime/effective-capabilities.test.ts +128 -0
  430. package/src/runtime/effective-capabilities.ts +84 -0
  431. package/src/runtime/guardian-reply-router.ts +106 -21
  432. package/src/runtime/invite-redemption-service.ts +9 -25
  433. package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +123 -0
  434. package/src/runtime/migrations/vbundle-builder.ts +49 -20
  435. package/src/runtime/pending-interactions.ts +15 -0
  436. package/src/runtime/routes/__tests__/client-routes.test.ts +13 -0
  437. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +67 -0
  438. package/src/runtime/routes/__tests__/plugins-routes.test.ts +240 -1
  439. package/src/runtime/routes/app-routes.ts +1 -1
  440. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -2
  441. package/src/runtime/routes/assets/vellum-design-system.css +1959 -0
  442. package/src/runtime/routes/browser-tabs-routes.ts +9 -0
  443. package/src/runtime/routes/btw-routes.ts +1 -27
  444. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +17 -8
  445. package/src/runtime/routes/client-routes.ts +10 -0
  446. package/src/runtime/routes/contact-routes.ts +31 -8
  447. package/src/runtime/routes/conversation-compaction-routes.ts +1 -1
  448. package/src/runtime/routes/conversation-management-routes.ts +80 -1
  449. package/src/runtime/routes/conversation-query-routes.ts +68 -22
  450. package/src/runtime/routes/conversation-routes.ts +39 -14
  451. package/src/runtime/routes/credential-routes.ts +40 -16
  452. package/src/runtime/routes/empty-state-greeting-cache.ts +1 -2
  453. package/src/runtime/routes/events-routes.ts +1 -3
  454. package/src/runtime/routes/guardian-approval-interception.ts +14 -73
  455. package/src/runtime/routes/guardian-approval-prompt.ts +22 -4
  456. package/src/runtime/routes/home-feed-routes.ts +8 -3
  457. package/src/runtime/routes/identity-routes.ts +1 -296
  458. package/src/runtime/routes/inbound-message-handler.ts +214 -228
  459. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +89 -7
  460. package/src/runtime/routes/inbound-stages/admission-policy.test.ts +154 -0
  461. package/src/runtime/routes/inbound-stages/admission-policy.ts +140 -0
  462. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +3 -3
  463. package/src/runtime/routes/inbound-stages/background-dispatch.ts +11 -6
  464. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -2
  465. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +1 -2
  466. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +7 -7
  467. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +47 -28
  468. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +358 -0
  469. package/src/runtime/routes/index.ts +2 -0
  470. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +8 -0
  471. package/src/runtime/routes/integrations/slack/channel.ts +36 -0
  472. package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
  473. package/src/runtime/routes/mcp-auth-routes.ts +233 -41
  474. package/src/runtime/routes/memory-eval-routes.ts +87 -0
  475. package/src/runtime/routes/notification-routes.ts +122 -133
  476. package/src/runtime/routes/platform-routes.ts +2 -2
  477. package/src/runtime/routes/plugins-routes.ts +202 -3
  478. package/src/runtime/routes/schedule-routes.ts +0 -22
  479. package/src/runtime/routes/secret-routes.ts +10 -0
  480. package/src/runtime/routes/surface-action-routes.ts +2 -1
  481. package/src/runtime/routes/tool-call-question-enrichment.test.ts +146 -0
  482. package/src/runtime/routes/tool-call-question-enrichment.ts +66 -0
  483. package/src/runtime/routes/workflow-routes.test.ts +229 -44
  484. package/src/runtime/routes/workflow-routes.ts +131 -29
  485. package/src/runtime/routes/workspace-greetings.ts +55 -0
  486. package/src/runtime/sync/resource-sync-events.ts +1 -11
  487. package/src/runtime/tool-grant-request-helper.ts +18 -16
  488. package/src/runtime/trust-context-resolver.ts +8 -5
  489. package/src/schedule/inference-profile.ts +2 -14
  490. package/src/schedule/schedule-store.ts +1 -1
  491. package/src/schedule/scheduler-types.ts +5 -1
  492. package/src/security/__tests__/provider-key-env-fallback.test.ts +6 -0
  493. package/src/security/secret-patterns.ts +3 -0
  494. package/src/subagent/manager.ts +17 -4
  495. package/src/subagent/types.ts +6 -0
  496. package/src/telemetry/trace-collection-policy.test.ts +28 -0
  497. package/src/telemetry/trace-collection-policy.ts +30 -0
  498. package/src/telemetry/types.ts +89 -0
  499. package/src/telemetry/usage-telemetry-reporter.test.ts +586 -36
  500. package/src/telemetry/usage-telemetry-reporter.ts +148 -41
  501. package/src/tools/AGENTS.md +3 -3
  502. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +31 -0
  503. package/src/tools/browser/browser-execution.ts +30 -19
  504. package/src/tools/document/document-tool.ts +2 -3
  505. package/src/tools/executor.ts +5 -3
  506. package/src/tools/host-terminal/host-shell.ts +5 -4
  507. package/src/tools/memory/register.ts +2 -2
  508. package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +360 -0
  509. package/src/tools/network/__tests__/web-search.test.ts +143 -0
  510. package/src/tools/network/web-fetch.ts +372 -1
  511. package/src/tools/network/web-search-error.ts +1 -1
  512. package/src/tools/network/web-search.ts +213 -10
  513. package/src/tools/permission-checker.ts +4 -3
  514. package/src/tools/registry.ts +20 -0
  515. package/src/tools/schedule/create.ts +7 -12
  516. package/src/tools/schedule/update.ts +4 -11
  517. package/src/tools/shared/filesystem/path-policy.ts +39 -13
  518. package/src/tools/side-effects.ts +2 -17
  519. package/src/tools/skills/execute.ts +33 -0
  520. package/src/tools/subagent/spawn.ts +61 -12
  521. package/src/tools/terminal/shell.ts +10 -4
  522. package/src/tools/tool-approval-handler.ts +18 -13
  523. package/src/tools/tool-manifest.ts +0 -2
  524. package/src/tools/types.ts +9 -0
  525. package/src/tools/ui-surface/definitions.ts +64 -3
  526. package/src/tools/verification-control-plane-policy.ts +3 -1
  527. package/src/tools/workflows/run-workflow.test.ts +8 -18
  528. package/src/tools/workflows/run-workflow.ts +1 -0
  529. package/src/util/disk-usage.ts +78 -23
  530. package/src/util/platform.ts +10 -3
  531. package/src/watcher/telemetry.ts +2 -2
  532. package/src/workflows/capabilities.ts +2 -3
  533. package/src/workflows/engine.test.ts +175 -1
  534. package/src/workflows/engine.ts +82 -0
  535. package/src/workflows/journal-store.test.ts +70 -0
  536. package/src/workflows/journal-store.ts +18 -3
  537. package/src/workflows/run-manager.test.ts +171 -28
  538. package/src/workflows/run-manager.ts +66 -24
  539. package/src/workspace/migrations/105-enable-memory-v3-live-for-new-workspaces.ts +63 -0
  540. package/src/workspace/migrations/106-drop-collect-usage-data.ts +47 -0
  541. package/src/workspace/migrations/107-drop-send-diagnostics.ts +47 -0
  542. package/src/workspace/migrations/108-drop-balanced-economy-profile.ts +129 -0
  543. package/src/workspace/migrations/registry.ts +8 -0
  544. package/src/__tests__/app-control-no-global-cgevent.test.ts +0 -98
  545. package/src/__tests__/credential-security-e2e.test.ts +0 -362
  546. package/src/__tests__/credential-vault-unit.test.ts +0 -1528
  547. package/src/__tests__/credential-vault.test.ts +0 -1706
  548. package/src/__tests__/identity-intro-cache.test.ts +0 -315
  549. package/src/__tests__/secret-onetime-send.test.ts +0 -182
  550. package/src/cli/commands/__tests__/task.test.ts +0 -914
  551. package/src/cli/commands/task.ts +0 -771
  552. package/src/config/bundled-skills/personal-page/SKILL.md +0 -57
  553. package/src/config/bundled-skills/personal-page/TOOLS.json +0 -27
  554. package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +0 -17
  555. package/src/config/preloaded-apps/personal-page/src/components/About.tsx +0 -22
  556. package/src/config/preloaded-apps/personal-page/src/components/App.tsx +0 -16
  557. package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +0 -77
  558. package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +0 -57
  559. package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +0 -28
  560. package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +0 -234
  561. package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +0 -48
  562. package/src/config/preloaded-apps/personal-page/src/components/media.ts +0 -16
  563. package/src/config/preloaded-apps/personal-page/src/index.html +0 -20
  564. package/src/config/preloaded-apps/personal-page/src/main.tsx +0 -7
  565. package/src/config/preloaded-apps/personal-page/src/profile-data.ts +0 -82
  566. package/src/config/preloaded-apps/personal-page/src/styles.css +0 -759
  567. package/src/memory/__tests__/preloaded-apps.test.ts +0 -85
  568. package/src/memory/preloaded-apps.ts +0 -116
  569. package/src/notifications/tool-approval-copy.ts +0 -142
  570. package/src/runtime/routes/approval-prompt-ts-tracker.ts +0 -78
  571. package/src/runtime/routes/identity-intro-cache.ts +0 -172
  572. package/src/tools/credentials/vault.ts +0 -712
@@ -1,14 +1,14 @@
1
1
  /**
2
- * Verifies that the `memory-v3-live` cache-anchor signal surfaces on every
3
- * `SendMessageOptions.config` the loop emits. When the flag is on, the latest
2
+ * Verifies that the memory-v3-live cache-anchor signal surfaces on every
3
+ * `SendMessageOptions.config` the loop emits. When v3-live is on, the latest
4
4
  * user message carries a volatile `<memory>` block, so the loop sets
5
5
  * `providerConfig.mutableLatestUserMessage` to tell the provider to anchor its
6
6
  * long-TTL cache breakpoint on the most recent STABLE message instead.
7
7
  *
8
- * The loop reads the flag directly where it assembles `providerConfig`, so the
9
- * signal is sourced from the flag rather than a run option. When the flag is
10
- * off the field is omitted (not `false`/`undefined`) so the wire stays
11
- * byte-identical to today.
8
+ * The loop reads `config.memory.v3.live` directly where it assembles
9
+ * `providerConfig`, so the signal is sourced from config rather than a run
10
+ * option. When v3-live is off the field is omitted (not `false`/`undefined`) so
11
+ * the wire stays byte-identical to today.
12
12
  */
13
13
 
14
14
  import { afterEach, describe, expect, mock, test } from "bun:test";
@@ -19,11 +19,14 @@ mock.module("../util/logger.js", () => ({
19
19
  getLogger: () => makeMockLogger(),
20
20
  }));
21
21
 
22
+ // AgentLoop reads the v3-live gate (`config.memory.v3.live`) via
23
+ // `isMemoryV3Live` to decide the cache-anchor signal; drive it per-test.
24
+ let memoryV3LiveSlot = false;
25
+ mock.module("../config/memory-v3-gate.js", () => ({
26
+ isMemoryV3Live: () => memoryV3LiveSlot,
27
+ }));
28
+
22
29
  import { AgentLoop } from "../agent/loop.js";
23
- import {
24
- clearCachedOverrides,
25
- setCachedOverrides,
26
- } from "../config/feature-flag-cache.js";
27
30
  import type {
28
31
  Message,
29
32
  Provider,
@@ -82,12 +85,12 @@ function makeRecordingProvider(responses: ProviderResponse[]): {
82
85
 
83
86
  describe("AgentLoop.run — mutableLatestUserMessage from memory-v3-live", () => {
84
87
  afterEach(() => {
85
- clearCachedOverrides();
88
+ memoryV3LiveSlot = false;
86
89
  });
87
90
 
88
91
  test("sets mutableLatestUserMessage on every LLM call when memory-v3-live is on (multi-turn)", async () => {
89
92
  // GIVEN memory-v3-live is enabled
90
- setCachedOverrides({ "memory-v3-live": true }, { fromGateway: true });
93
+ memoryV3LiveSlot = true;
91
94
 
92
95
  // AND a provider that records the config of each LLM call across a tool round-trip
93
96
  const { provider, configs } = makeRecordingProvider([
@@ -131,7 +134,7 @@ describe("AgentLoop.run — mutableLatestUserMessage from memory-v3-live", () =>
131
134
 
132
135
  test("omits mutableLatestUserMessage when memory-v3-live is off (flag-off byte-identity)", async () => {
133
136
  // GIVEN memory-v3-live is off (no override; registry default is false)
134
- clearCachedOverrides();
137
+ memoryV3LiveSlot = false;
135
138
 
136
139
  // AND a provider that records the config of each LLM call
137
140
  const { provider, configs } = makeRecordingProvider([textResponse("hi")]);
@@ -365,6 +365,75 @@ describe("agent loop output hooks", () => {
365
365
  expect(calls[0].systemPrompt).toContain("[EDITED]");
366
366
  });
367
367
 
368
+ test("pre-model-call routes the call to the hook's chosen inference profile", async () => {
369
+ // GIVEN a hook that selects an inference profile for the user-facing call
370
+ registerOutputHookPlugin({
371
+ preModelCall: (ctx) => {
372
+ if (ctx.callSite !== "mainAgent") return;
373
+ ctx.modelProfile = "fast-profile";
374
+ },
375
+ });
376
+ const { provider, calls } = createMockProvider([textResponse("hi")]);
377
+ const loop = new AgentLoop({
378
+ provider: provider,
379
+ systemPrompt: "system",
380
+ conversationId: "test-conversation",
381
+ });
382
+
383
+ // WHEN the loop issues the user-facing provider call
384
+ await loop.run({
385
+ requestId: "test-request",
386
+ messages: [userMessage],
387
+ onEvent: collect([]),
388
+ callSite: "mainAgent",
389
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
390
+ });
391
+
392
+ // THEN the provider call carries the hook's profile as the override
393
+ expect(calls[0].options?.config?.overrideProfile).toBe("fast-profile");
394
+ });
395
+
396
+ test("pre-model-call seeds modelProfile from the resolved override and clearing it drops the override", async () => {
397
+ // GIVEN a hook that observes the seeded override and then clears it
398
+ let seeded: string | null | undefined;
399
+ registerOutputHookPlugin({
400
+ preModelCall: (ctx) => {
401
+ seeded = ctx.modelProfile;
402
+ ctx.modelProfile = null;
403
+ },
404
+ });
405
+ const { provider, calls } = createMockProvider([textResponse("hi")]);
406
+ const loop = new AgentLoop({
407
+ provider: provider,
408
+ systemPrompt: "system",
409
+ conversationId: "test-conversation",
410
+ });
411
+
412
+ // WHEN the loop runs with an ad-hoc override profile
413
+ await loop.run({
414
+ requestId: "test-request",
415
+ messages: [userMessage],
416
+ onEvent: collect([]),
417
+ callSite: "mainAgent",
418
+ overrideProfile: "seed-profile",
419
+ trust: { sourceChannel: "vellum", trustClass: "unknown" },
420
+ });
421
+
422
+ // THEN the hook saw the loop's resolved override
423
+ expect(seeded).toBe("seed-profile");
424
+ // AND clearing it sends no override on the provider call
425
+ expect(calls[0].options?.config?.overrideProfile).toBeUndefined();
426
+ });
427
+
428
+ // Context-window sizing and overflow recovery read the profile resolved
429
+ // before the hook runs, so a hook routing to a smaller-window profile does
430
+ // not resize the budget gate for that call. Tracked for a follow-up that
431
+ // resolves the routed profile ahead of the context-sizing gate.
432
+ test.todo(
433
+ "pre-model-call routing resizes the context-window budget for the routed profile",
434
+ () => {},
435
+ );
436
+
368
437
  test("fail-open: a hook that mutates in place AND then throws cannot corrupt the persisted content", async () => {
369
438
  // The hook mutates the array it receives before throwing. If the loop
370
439
  // handed the hook the real `assistantMessage.content` array, the
@@ -195,6 +195,7 @@ interface CapturedRunAgentLoopOptions {
195
195
  titleText?: string;
196
196
  callSite?: string;
197
197
  overrideProfile?: string;
198
+ forceOverrideProfile?: boolean;
198
199
  }
199
200
 
200
201
  const capturedRunAgentLoopOptions: CapturedRunAgentLoopOptions[] = [];
@@ -323,6 +324,29 @@ describe("SubagentManager.spawn — overrideProfile inheritance", () => {
323
324
  const captured = capturedRunAgentLoopOptions[0];
324
325
  expect(captured.callSite).toBe("subagentSpawn");
325
326
  expect(captured.overrideProfile).toBe("fast");
327
+ expect("forceOverrideProfile" in captured).toBe(false);
328
+ });
329
+
330
+ test("forwards forced overrideProfile from SubagentConfig into runAgentLoop", async () => {
331
+ capturedRunAgentLoopOptions.length = 0;
332
+
333
+ const manager = new SubagentManager();
334
+ await manager.spawn(
335
+ {
336
+ parentConversationId: "parent-forced",
337
+ label: "child",
338
+ objective: "do the thing",
339
+ overrideProfile: "fast",
340
+ forceOverrideProfile: true,
341
+ },
342
+ () => {},
343
+ );
344
+
345
+ expect(capturedRunAgentLoopOptions).toHaveLength(1);
346
+ const captured = capturedRunAgentLoopOptions[0];
347
+ expect(captured.callSite).toBe("subagentSpawn");
348
+ expect(captured.overrideProfile).toBe("fast");
349
+ expect(captured.forceOverrideProfile).toBe(true);
326
350
  });
327
351
 
328
352
  test("omits overrideProfile when SubagentConfig does not set it", async () => {
@@ -344,6 +368,7 @@ describe("SubagentManager.spawn — overrideProfile inheritance", () => {
344
368
  // Field must be absent rather than carrying `undefined`, mirroring the
345
369
  // agent loop's "field omitted when unset" contract.
346
370
  expect("overrideProfile" in captured).toBe(false);
371
+ expect("forceOverrideProfile" in captured).toBe(false);
347
372
  });
348
373
  });
349
374
 
@@ -28,7 +28,7 @@ afterAll(() => {
28
28
  });
29
29
 
30
30
  describe("always-loaded tool count", () => {
31
- test("should be exactly 11 with recall occupying the existing slot", async () => {
31
+ test("should be exactly 10 with recall occupying the existing slot", async () => {
32
32
  await initializeTools();
33
33
  const allDefs = getAllToolDefinitions();
34
34
 
@@ -52,7 +52,6 @@ describe("always-loaded tool count", () => {
52
52
  // path would allow unchecked host command execution.
53
53
  const expectedNames = [
54
54
  "bash",
55
- "credential_store",
56
55
  "file_edit",
57
56
  "file_read",
58
57
  "file_write",
@@ -66,6 +65,6 @@ describe("always-loaded tool count", () => {
66
65
 
67
66
  expect(activeNames).toEqual(expectedNames);
68
67
  expect(activeNames.filter((name) => name === "recall")).toHaveLength(1);
69
- expect(activeTools.length).toBe(11);
68
+ expect(activeTools.length).toBe(10);
70
69
  });
71
70
  });
@@ -2,9 +2,17 @@ import { existsSync } from "node:fs";
2
2
  import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
3
3
  import { tmpdir } from "node:os";
4
4
  import { join } from "node:path";
5
- import { afterAll, beforeAll, describe, expect, test } from "bun:test";
5
+ import {
6
+ afterAll,
7
+ beforeAll,
8
+ describe,
9
+ expect,
10
+ setDefaultTimeout,
11
+ test,
12
+ } from "bun:test";
6
13
 
7
14
  import { compileApp } from "../bundler/app-compiler.js";
15
+ import { ensureCompilerTools } from "../bundler/compiler-tools.js";
8
16
  import {
9
17
  ALLOWED_PACKAGES,
10
18
  getCacheDir,
@@ -19,8 +27,14 @@ import {
19
27
 
20
28
  let tempDir: string;
21
29
 
30
+ // Compiler-tool download (esbuild + preact from npm) can take 10s+ on a cold
31
+ // CI cache. Raise the file-level default so beforeAll isn't killed mid-install.
32
+ // Each test file runs in its own process, so this doesn't leak.
33
+ setDefaultTimeout(30_000);
34
+
22
35
  beforeAll(async () => {
23
36
  tempDir = await mkdtemp(join(tmpdir(), "app-compiler-test-"));
37
+ await ensureCompilerTools();
24
38
  });
25
39
 
26
40
  afterAll(async () => {
@@ -20,7 +20,6 @@ const ALLOWLIST = new Set([
20
20
  "assistant/src/memory/app-git-service.ts", // uses getAppsDir for git repo root, not per-app paths
21
21
  "assistant/src/daemon/app-source-watcher.ts", // uses getAppsDir for recursive fs.watch root, not per-app paths
22
22
  "assistant/src/tools/filesystem/write.ts", // uses getAppsDir as an exemption root for the artifact-HTML guard, not per-app paths
23
- "assistant/src/memory/preloaded-apps.ts", // seeds fixed-slug apps (id === dirName by construction) and writes the definition JSON, which app-store has no fixed-id helper for
24
23
  ]);
25
24
 
26
25
  function isTestFile(filePath: string): boolean {
@@ -60,10 +60,7 @@ const CANONICAL_KEY_RE = /^[a-z0-9][a-z0-9-]*$/;
60
60
  * Keep this list minimal — only files that genuinely need to reference
61
61
  * the legacy format for backward compatibility.
62
62
  */
63
- const LEGACY_KEY_ALLOWLIST = new Set([
64
- // macOS client: fallback reads from legacy config section
65
- "clients/macos/vellum-assistant/Features/Settings/SettingsAccountTab.swift",
66
- ]);
63
+ const LEGACY_KEY_ALLOWLIST = new Set<string>([]);
67
64
 
68
65
  function isTestFile(filePath: string): boolean {
69
66
  return (
@@ -58,8 +58,6 @@ function loadRegistry(): Registry {
58
58
  const LEGACY_KEY_ALLOWLIST = new Set([
59
59
  // Type definitions documenting the legacy format
60
60
  "assistant/src/config/types.ts",
61
- // macOS client: fallback reads from legacy config section
62
- "clients/macos/vellum-assistant/Features/Settings/SettingsAccountTab.swift",
63
61
  ]);
64
62
 
65
63
  function isTestFile(filePath: string): boolean {
@@ -7,18 +7,10 @@ mock.module("../util/logger.js", () => ({
7
7
  }),
8
8
  }));
9
9
 
10
- let collectUsageData = true;
10
+ let shareAnalytics = true;
11
11
 
12
- mock.module("../config/loader.js", () => ({
13
- getConfig: () => ({
14
- ui: {},
15
- model: "test",
16
- provider: "test",
17
- memory: { enabled: false },
18
- rateLimit: { maxRequestsPerMinute: 0 },
19
- secretDetection: { enabled: false },
20
- collectUsageData,
21
- }),
12
+ mock.module("../platform/consent-cache.js", () => ({
13
+ getCachedShareAnalytics: () => shareAnalytics,
22
14
  }));
23
15
 
24
16
  import {
@@ -53,7 +45,7 @@ const SAMPLE: AuthFallbackCount[] = [
53
45
 
54
46
  describe("auth-fallback-events-store", () => {
55
47
  beforeEach(() => {
56
- collectUsageData = true;
48
+ shareAnalytics = true;
57
49
  resetTable();
58
50
  });
59
51
 
@@ -78,8 +70,8 @@ describe("auth-fallback-events-store", () => {
78
70
  });
79
71
  });
80
72
 
81
- test("honors the collectUsageData opt-out (records nothing)", () => {
82
- collectUsageData = false;
73
+ test("honors the share_analytics opt-out (records nothing)", () => {
74
+ shareAnalytics = false;
83
75
  const recorded = recordAuthFallbackCounts(1000, 2000, SAMPLE);
84
76
  expect(recorded).toBe(0);
85
77
  expect(queryUnreportedAuthFallbackEvents(0, undefined, 100).length).toBe(0);
@@ -4,10 +4,7 @@ import { SYNC_TAGS } from "../daemon/message-types/sync.js";
4
4
  import type { AssistantEvent } from "../runtime/assistant-event.js";
5
5
  import { assistantEventHub } from "../runtime/assistant-event-hub.js";
6
6
  import { ROUTES as AVATAR_ROUTES } from "../runtime/routes/avatar-routes.js";
7
- import {
8
- publishIdentityChanged,
9
- publishIdentityIntroChanged,
10
- } from "../runtime/sync/resource-sync-events.js";
7
+ import { publishIdentityChanged } from "../runtime/sync/resource-sync-events.js";
11
8
 
12
9
  async function waitFor(predicate: () => boolean): Promise<void> {
13
10
  const deadline = Date.now() + 500;
@@ -81,29 +78,7 @@ describe("avatar and identity sync events", () => {
81
78
  });
82
79
  expect(received[1].message).toEqual({
83
80
  type: "sync_changed",
84
- tags: [SYNC_TAGS.assistantIdentity, SYNC_TAGS.assistantIdentityIntro],
85
- });
86
- } finally {
87
- subscription.dispose();
88
- }
89
- });
90
-
91
- test("identity intro changes emit only the identity intro sync tag", async () => {
92
- const received: AssistantEvent[] = [];
93
- const subscription = assistantEventHub.subscribe({
94
- type: "process",
95
- callback: (event) => {
96
- received.push(event);
97
- },
98
- });
99
-
100
- try {
101
- publishIdentityIntroChanged();
102
- await waitFor(() => received.length === 1);
103
-
104
- expect(received[0].message).toEqual({
105
- type: "sync_changed",
106
- tags: [SYNC_TAGS.assistantIdentityIntro],
81
+ tags: [SYNC_TAGS.assistantIdentity],
107
82
  });
108
83
  } finally {
109
84
  subscription.dispose();
@@ -78,10 +78,8 @@ mock.module("../prompts/persona-resolver.js", () => ({
78
78
  resolveUserSlug: () => null,
79
79
  }));
80
80
 
81
- mock.module("../runtime/routes/identity-intro-cache.js", () => ({
82
- getCachedIntro: () => null,
83
- readWorkspaceIdentityIntro: () => null,
84
- setCachedIntro: () => {},
81
+ mock.module("../runtime/routes/workspace-greetings.js", () => ({
82
+ readWorkspaceGreetings: () => null,
85
83
  }));
86
84
 
87
85
  // Mock getOrCreateConversation from conversation-store so the handler
@@ -345,13 +343,13 @@ describe("POST /v1/btw", () => {
345
343
  expect(options!.config!.callSite).toBe("emptyStateGreeting");
346
344
  });
347
345
 
348
- test("identity intro requests pass callSite: 'identityIntro'", async () => {
346
+ test("generic requests pass the default callSite", async () => {
349
347
  const provider = makeMockProvider();
350
348
  const session = makeMockSession(provider);
351
349
  mockGetOrCreateConversation.mockImplementationOnce(async () => session);
352
350
 
353
351
  const { result } = await callHandler({
354
- conversationKey: "identity-intro",
352
+ conversationKey: "profile-intro",
355
353
  content: "Generate an intro",
356
354
  });
357
355
  await readStream(result as ReadableStream<Uint8Array>);
@@ -361,7 +359,7 @@ describe("POST /v1/btw", () => {
361
359
  expect(options!.config!.callSite).toBe("identityIntro");
362
360
  });
363
361
 
364
- test("identity intro requests do not synthesize a static name greeting", async () => {
362
+ test("generic requests do not synthesize a static name greeting", async () => {
365
363
  const identityPath = join(getWorkspaceDir(), "IDENTITY.md");
366
364
  writeFileSync(
367
365
  identityPath,
@@ -375,7 +373,7 @@ describe("POST /v1/btw", () => {
375
373
  mockGetOrCreateConversation.mockImplementationOnce(async () => session);
376
374
 
377
375
  const { result } = await callHandler({
378
- conversationKey: "identity-intro",
376
+ conversationKey: "profile-intro",
379
377
  content: "Generate an intro",
380
378
  });
381
379
  const text = await readStream(result as ReadableStream<Uint8Array>);
@@ -343,6 +343,34 @@ describe("addPointerMessage", () => {
343
343
  expect(processorCalled).toBe(true);
344
344
  });
345
345
 
346
+ test("unverified_contact provenance round-trips through the metadata schema and is treated as trusted audience", async () => {
347
+ // Persisted unverified_contact metadata must survive the schema parse so
348
+ // downstream consumers (e.g. memory write gate, pointer audience trust)
349
+ // see the durable trust snapshot rather than a silently-dropped undefined.
350
+ const convId = "conv-ptr-uvc-provenance";
351
+ ensureConversation(convId);
352
+ await addMessage(convId, "user", "hello", {
353
+ metadata: { provenanceTrustClass: "unverified_contact" },
354
+ });
355
+
356
+ // Confirm the durable snapshot round-trips through the schema parser.
357
+ const { getConversationRecentProvenanceTrustClass } = await import(
358
+ "../memory/conversation-crud.js"
359
+ );
360
+ expect(getConversationRecentProvenanceTrustClass(convId)).toBe(
361
+ "unverified_contact",
362
+ );
363
+
364
+ // And that pointer-audience trust treats it identically to trusted_contact.
365
+ let processorCalled = false;
366
+ setPointerMessageProcessor(async () => {
367
+ processorCalled = true;
368
+ });
369
+
370
+ await addPointerMessage(convId, "completed", "+15559876543");
371
+ expect(processorCalled).toBe(true);
372
+ });
373
+
346
374
  test("unknown provenance trust class does not grant trusted audience", () => {
347
375
  const convId = "conv-ptr-unknown-provenance";
348
376
  ensureConversation(convId);
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Cancel contract: a user cancel raises the conversation's AbortController and
3
+ * defers clearing the `processing` flag to the in-flight turn's `finally`.
4
+ *
5
+ * `cancelGeneration` no longer force-clears `processing` itself. Abort now
6
+ * propagates into the provider call and tool execution — and is backed by the
7
+ * agent loop's abort watchdog — so a cancelled turn always reaches its
8
+ * `finally` within a bounded time and tears down its own state there. The
9
+ * watchdog-driven path (turn reaches `finally`, processing clears) is covered
10
+ * by `conversation-agent-loop.test.ts`; this file pins the handler-side
11
+ * contract: cancel signals abort and leaves the flag to the turn.
12
+ */
13
+ import { afterEach, describe, expect, test } from "bun:test";
14
+
15
+ import type { Conversation } from "../daemon/conversation.js";
16
+ import {
17
+ deleteConversation,
18
+ setConversation,
19
+ } from "../daemon/conversation-registry.js";
20
+ import { cancelGeneration } from "../daemon/handlers/conversations.js";
21
+
22
+ interface CancelledConversation {
23
+ isProcessing: () => boolean;
24
+ setProcessingCalls: () => boolean[];
25
+ abortCount: () => number;
26
+ }
27
+
28
+ /**
29
+ * Register a conversation whose in-flight turn is processing. The fake records
30
+ * abort calls and any `setProcessing` writes so the test can assert that
31
+ * `cancelGeneration` signals abort without flipping the flag itself.
32
+ */
33
+ function registerProcessingTurn(id: string): CancelledConversation {
34
+ let processing = true;
35
+ let abortCount = 0;
36
+ const setProcessingCalls: boolean[] = [];
37
+ const fake = {
38
+ isProcessing: () => processing,
39
+ setProcessing: (value: boolean) => {
40
+ setProcessingCalls.push(value);
41
+ processing = value;
42
+ },
43
+ abort: () => {
44
+ abortCount += 1;
45
+ },
46
+ };
47
+ setConversation(id, fake as unknown as Conversation);
48
+ return {
49
+ isProcessing: () => processing,
50
+ setProcessingCalls: () => setProcessingCalls,
51
+ abortCount: () => abortCount,
52
+ };
53
+ }
54
+
55
+ describe("cancelGeneration", () => {
56
+ const conversationId = "cancel-clears-processing-test-conversation";
57
+
58
+ afterEach(() => {
59
+ deleteConversation(conversationId);
60
+ });
61
+
62
+ test("raises abort and defers clearing processing to the turn's finally", () => {
63
+ // GIVEN a registered conversation that is processing
64
+ const fake = registerProcessingTurn(conversationId);
65
+ expect(fake.isProcessing()).toBe(true);
66
+
67
+ // WHEN the user cancels generation
68
+ const cancelled = cancelGeneration(conversationId);
69
+
70
+ // THEN the cancel is acknowledged
71
+ expect(cancelled).toBe(true);
72
+ // AND the abort signal is raised on the conversation
73
+ expect(fake.abortCount()).toBe(1);
74
+ // AND cancelGeneration does NOT force-clear the flag itself — the in-flight
75
+ // turn's `finally` owns that teardown once abort drives it there.
76
+ expect(fake.setProcessingCalls()).not.toContain(false);
77
+ expect(fake.isProcessing()).toBe(true);
78
+ });
79
+
80
+ test("returns false for a conversation that is not registered", () => {
81
+ // GIVEN no conversation registered under the id
82
+
83
+ // WHEN the user cancels generation for the unknown id
84
+ const cancelled = cancelGeneration("cancel-clears-processing-unknown-id");
85
+
86
+ // THEN the cancel reports that nothing was found
87
+ expect(cancelled).toBe(false);
88
+ });
89
+ });
@@ -224,14 +224,12 @@ function ensureTestContact(): void {
224
224
  {
225
225
  type: "telegram",
226
226
  address: "telegram-user-default",
227
- externalUserId: "telegram-user-default",
228
227
  status: "active",
229
228
  policy: "allow",
230
229
  },
231
230
  {
232
231
  type: "slack",
233
232
  address: "slack-user-default",
234
- externalUserId: "slack-user-default",
235
233
  status: "active",
236
234
  policy: "allow",
237
235
  },
@@ -2054,7 +2052,6 @@ describe("requester cancel of guardian-gated pending request", () => {
2054
2052
  {
2055
2053
  type: "telegram",
2056
2054
  address: "requester-cancel-user",
2057
- externalUserId: "requester-cancel-user",
2058
2055
  status: "active",
2059
2056
  policy: "allow",
2060
2057
  },
@@ -2981,7 +2978,6 @@ describe("trusted-contact self-approval blocked before guardian approval row exi
2981
2978
  {
2982
2979
  type: "telegram",
2983
2980
  address: "tc-selfapproval-user",
2984
- externalUserId: "tc-selfapproval-user",
2985
2981
  status: "active",
2986
2982
  policy: "allow",
2987
2983
  },
@@ -97,7 +97,6 @@ function seedTrustedContact(policy: "allow" | "escalate" = "allow"): void {
97
97
  {
98
98
  type: "telegram",
99
99
  address: "telegram-user-1",
100
- externalUserId: "telegram-user-1",
101
100
  status: "active",
102
101
  policy,
103
102
  },
@@ -237,14 +236,13 @@ describe("channel inbound disk pressure gate", () => {
237
236
  expect(db.select().from(messages).all()).toHaveLength(0);
238
237
  });
239
238
 
240
- test("blocks non-guardian Slack reactions before persistence while locked", async () => {
239
+ test("blocks non-guardian Slack reactions silently (no reply) before persistence while locked", async () => {
241
240
  upsertContact({
242
241
  displayName: "Example Slack User",
243
242
  channels: [
244
243
  {
245
244
  type: "slack",
246
245
  address: "slack-user-1",
247
- externalUserId: "slack-user-1",
248
246
  status: "active",
249
247
  policy: "allow",
250
248
  },
@@ -276,18 +274,10 @@ describe("channel inbound disk pressure gate", () => {
276
274
  reason: "trusted-contact",
277
275
  });
278
276
  expect(processMessage).not.toHaveBeenCalled();
279
- expect(deliverChannelReplyMock.mock.calls).toEqual([
280
- [
281
- "https://gateway.test/deliver/slack",
282
- {
283
- chatId: "slack-channel-1",
284
- text: expectedRemoteBlockReply,
285
- assistantId: "self",
286
- ephemeral: true,
287
- user: "slack-user-1",
288
- },
289
- ],
290
- ]);
277
+ // Reactions are blocked silently during disk pressure: a passive signal
278
+ // has nothing to "try again", so no block reply is delivered (unlike the
279
+ // message path, which does reply).
280
+ expect(deliverChannelReplyMock).not.toHaveBeenCalled();
291
281
 
292
282
  const db = getDb();
293
283
  const event = db
@@ -790,9 +790,6 @@ describe("Permission Checker", () => {
790
790
  const workingDir = join(homedir(), "projects", "myapp");
791
791
  expect(generateScopeOptions(workingDir, "web_fetch")).toHaveLength(0);
792
792
  expect(generateScopeOptions(workingDir, "skill_load")).toHaveLength(0);
793
- expect(generateScopeOptions(workingDir, "credential_store")).toHaveLength(
794
- 0,
795
- );
796
793
  expect(
797
794
  generateScopeOptions(workingDir, "computer_use_click"),
798
795
  ).toHaveLength(0);
@@ -52,7 +52,7 @@ mock.module("../memory/v2/skill-store.js", () => ({
52
52
  // ---------------------------------------------------------------------------
53
53
 
54
54
  const { registerMemoryV2Command } =
55
- await import("../cli/commands/memory-v2.js");
55
+ await import("../cli/commands/memory/memory-v2.js");
56
56
  const { ROUTES: memoryV2Routes, MEMORY_V2_DISABLED_CODE } =
57
57
  await import("../runtime/routes/memory-v2-routes.js");
58
58
  const { RouteError } = await import("../runtime/routes/errors.js");
@@ -68,9 +68,8 @@ function buildProgram(): Command {
68
68
  writeErr: () => {},
69
69
  writeOut: () => {},
70
70
  });
71
- // The registrar creates the `memory` parent itself, so callers don't
72
- // need to stub one.
73
- registerMemoryV2Command(program);
71
+ const memory = program.command("memory");
72
+ registerMemoryV2Command(memory);
74
73
  return program;
75
74
  }
76
75