@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
@@ -69,10 +69,38 @@ import {
69
69
  describe("conversation-title-service", () => {
70
70
  beforeEach(() => {
71
71
  mockRunBtwSidechain.mockClear();
72
+ mockRunBtwSidechain.mockImplementation(
73
+ async (_params: Record<string, unknown>) => ({
74
+ text: "Project kickoff",
75
+ hadTextDeltas: true,
76
+ response: {
77
+ content: [{ type: "text", text: "Project kickoff" }],
78
+ model: "test-model",
79
+ usage: { inputTokens: 10, outputTokens: 5 },
80
+ stopReason: "end_turn",
81
+ },
82
+ }),
83
+ );
72
84
  mockGetConversation.mockClear();
85
+ mockGetConversation.mockImplementation(
86
+ (_conversationId: string) =>
87
+ ({
88
+ title: "Generating title...",
89
+ isAutoTitle: 1,
90
+ }) as {
91
+ title: string;
92
+ isAutoTitle: number;
93
+ },
94
+ );
73
95
  mockGetMessages.mockClear();
96
+ mockGetMessages.mockImplementation(() => [
97
+ { role: "user", content: "first message" },
98
+ { role: "assistant", content: "first reply" },
99
+ { role: "user", content: "follow-up" },
100
+ ]);
74
101
  mockUpdateConversationTitle.mockClear();
75
102
  mockGetConfiguredProvider.mockClear();
103
+ mockGetConfiguredProvider.mockImplementation(async () => null);
76
104
  mockPublishConversationTitleChanged.mockClear();
77
105
  });
78
106
 
@@ -232,6 +260,30 @@ describe("conversation-title-service", () => {
232
260
  );
233
261
  });
234
262
 
263
+ test("fallback retry skips regeneration after a successful initial title", async () => {
264
+ mockGetConversation.mockReturnValueOnce({
265
+ title: "Project kickoff",
266
+ isAutoTitle: 1,
267
+ });
268
+
269
+ const provider = {
270
+ name: "test-provider",
271
+ sendMessage: mock(async () => {
272
+ throw new Error("should not call directly");
273
+ }),
274
+ };
275
+
276
+ const result = await regenerateConversationTitle({
277
+ conversationId: "conv-1",
278
+ provider,
279
+ onlyIfReplaceable: true,
280
+ });
281
+
282
+ expect(result).toEqual({ title: "Project kickoff", updated: false });
283
+ expect(mockRunBtwSidechain).not.toHaveBeenCalled();
284
+ expect(mockUpdateConversationTitle).not.toHaveBeenCalled();
285
+ });
286
+
235
287
  test("rejects meta-failure outputs like 'Missing Context' and uses fallback", async () => {
236
288
  mockRunBtwSidechain.mockImplementationOnce(async () => ({
237
289
  text: "Missing Context",
@@ -482,6 +534,16 @@ describe("conversation-title-service", () => {
482
534
 
483
535
  // Both calls went through — failure didn't break the chain
484
536
  expect(mockRunBtwSidechain).toHaveBeenCalledTimes(2);
537
+ const firstUpdate = (
538
+ mockUpdateConversationTitle.mock.calls as unknown as Array<
539
+ [string, string, number?]
540
+ >
541
+ ).find((c) => c[0] === "conv-1");
542
+ expect(firstUpdate).toEqual([
543
+ "conv-1",
544
+ "Untitled Conversation",
545
+ AUTO_TITLE_DETERMINISTIC,
546
+ ]);
485
547
  // Second conversation got a proper title
486
548
  const secondUpdate = (
487
549
  mockUpdateConversationTitle.mock.calls as unknown as string[][]
@@ -139,6 +139,12 @@ mock.module("../memory/retrieval-budget.js", () => ({
139
139
 
140
140
  mock.module("../plugins/defaults/compaction/window-manager.js", () => ({
141
141
  ContextWindowManager: class {
142
+ estimateInputTokens() {
143
+ return 0;
144
+ }
145
+ get tokenCountInputs() {
146
+ return { systemPrompt: "", tools: undefined };
147
+ }
142
148
  constructor() {}
143
149
  updateConfig() {}
144
150
  shouldCompact() {
@@ -178,6 +178,12 @@ mock.module("../memory/retrieval-budget.js", () => ({
178
178
  }));
179
179
  mock.module("../plugins/defaults/compaction/window-manager.js", () => ({
180
180
  ContextWindowManager: class {
181
+ estimateInputTokens() {
182
+ return 0;
183
+ }
184
+ get tokenCountInputs() {
185
+ return { systemPrompt: "", tools: undefined };
186
+ }
181
187
  updateConfig() {}
182
188
  shouldCompact() {
183
189
  return { needed: false, estimatedTokens: 0 };
@@ -175,6 +175,12 @@ mock.module("../memory/retrieval-budget.js", () => ({
175
175
  }));
176
176
  mock.module("../plugins/defaults/compaction/window-manager.js", () => ({
177
177
  ContextWindowManager: class {
178
+ estimateInputTokens() {
179
+ return 0;
180
+ }
181
+ get tokenCountInputs() {
182
+ return { systemPrompt: "", tools: undefined };
183
+ }
178
184
  updateConfig() {}
179
185
  shouldCompact() {
180
186
  return { needed: false, estimatedTokens: 0 };
@@ -1,14 +1,24 @@
1
- import { mkdtempSync, rmSync } from "node:fs";
1
+ import { randomBytes } from "node:crypto";
2
+ import { existsSync, mkdirSync, mkdtempSync, rmSync } from "node:fs";
2
3
  import { tmpdir } from "node:os";
3
4
  import { join } from "node:path";
4
5
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
5
6
 
6
7
  import { credentialKey } from "../security/credential-key.js";
8
+ import { _resetBackend, setSecureKeyAsync } from "../security/secure-keys.js";
7
9
  import { CredentialBroker } from "../tools/credentials/broker.js";
8
10
  import {
9
11
  _setMetadataPath,
10
12
  upsertCredentialMetadata,
11
13
  } from "../tools/credentials/metadata-store.js";
14
+ import { BROWSER_FILL_CAPABILITY } from "../tools/credentials/tool-policy.js";
15
+ import { setStorePathForTesting } from "./encrypted-store-test-helpers.js";
16
+
17
+ const TEST_DIR = join(
18
+ tmpdir(),
19
+ `vellum-broker-test-${randomBytes(4).toString("hex")}`,
20
+ );
21
+ const STORE_PATH = join(TEST_DIR, "keys.enc");
12
22
 
13
23
  describe("CredentialBroker", () => {
14
24
  let broker: CredentialBroker;
@@ -222,3 +232,441 @@ describe("CredentialBroker", () => {
222
232
  });
223
233
  });
224
234
  });
235
+
236
+ // ---------------------------------------------------------------------------
237
+ // Behavior that reads stored secret values, exercised against the encrypted
238
+ // store backend (transient injection, multi-template serverUseById, revokeAll,
239
+ // and canonical/legacy capability-key resolution).
240
+ // ---------------------------------------------------------------------------
241
+
242
+ describe("CredentialBroker (encrypted store backend)", () => {
243
+ let broker: CredentialBroker;
244
+
245
+ beforeEach(() => {
246
+ if (existsSync(TEST_DIR)) rmSync(TEST_DIR, { recursive: true });
247
+ mkdirSync(TEST_DIR, { recursive: true });
248
+ setStorePathForTesting(STORE_PATH);
249
+ _resetBackend();
250
+ _setMetadataPath(join(TEST_DIR, "metadata.json"));
251
+ broker = new CredentialBroker();
252
+ });
253
+
254
+ afterEach(() => {
255
+ _setMetadataPath(null);
256
+ setStorePathForTesting(null);
257
+ _resetBackend();
258
+ rmSync(TEST_DIR, { recursive: true, force: true });
259
+ });
260
+
261
+ describe("transient credentials", () => {
262
+ test("consume returns transient value and deletes it", () => {
263
+ // GIVEN a credential with metadata and an injected one-time transient value
264
+ upsertCredentialMetadata("svc", "key", { allowedTools: ["tool1"] });
265
+ broker.injectTransient("svc", "key", "one-time-secret");
266
+
267
+ // WHEN the credential is authorized and consumed
268
+ const auth = broker.authorize({
269
+ service: "svc",
270
+ field: "key",
271
+ toolName: "tool1",
272
+ });
273
+ expect(auth.authorized).toBe(true);
274
+ if (!auth.authorized) return;
275
+ const result = broker.consume(auth.token.tokenId);
276
+
277
+ // THEN the transient value is returned alongside the storage key
278
+ expect(result.success).toBe(true);
279
+ expect(result.value).toBe("one-time-secret");
280
+ expect(result.storageKey).toBe(credentialKey("svc", "key"));
281
+
282
+ // AND a subsequent authorize+consume no longer has the transient value
283
+ const auth2 = broker.authorize({
284
+ service: "svc",
285
+ field: "key",
286
+ toolName: "tool1",
287
+ });
288
+ expect(auth2.authorized).toBe(true);
289
+ if (!auth2.authorized) return;
290
+ const result2 = broker.consume(auth2.token.tokenId);
291
+ expect(result2.success).toBe(true);
292
+ expect(result2.value).toBeUndefined();
293
+ });
294
+
295
+ test("browserFill uses transient value when available", async () => {
296
+ // GIVEN a credential with a transient value and no stored value
297
+ upsertCredentialMetadata("github", "token", {
298
+ allowedTools: ["browser_fill_credential"],
299
+ });
300
+ broker.injectTransient("github", "token", "transient-ghp-123");
301
+
302
+ // WHEN browserFill runs
303
+ let filledValue: string | undefined;
304
+ const result = await broker.browserFill({
305
+ service: "github",
306
+ field: "token",
307
+ toolName: "browser_fill_credential",
308
+ fill: async (v) => {
309
+ filledValue = v;
310
+ },
311
+ });
312
+
313
+ // THEN the transient value is filled
314
+ expect(result.success).toBe(true);
315
+ expect(filledValue).toBe("transient-ghp-123");
316
+ });
317
+
318
+ test("browserFill consumes transient value — second fill falls back to stored", async () => {
319
+ // GIVEN a credential with both a stored value and a transient value
320
+ upsertCredentialMetadata("github", "token", {
321
+ allowedTools: ["browser_fill_credential"],
322
+ });
323
+ await setSecureKeyAsync(credentialKey("github", "token"), "stored-value");
324
+ broker.injectTransient("github", "token", "transient-value");
325
+
326
+ // WHEN browserFill runs twice
327
+ let filled1: string | undefined;
328
+ await broker.browserFill({
329
+ service: "github",
330
+ field: "token",
331
+ toolName: "browser_fill_credential",
332
+ fill: async (v) => {
333
+ filled1 = v;
334
+ },
335
+ });
336
+ let filled2: string | undefined;
337
+ await broker.browserFill({
338
+ service: "github",
339
+ field: "token",
340
+ toolName: "browser_fill_credential",
341
+ fill: async (v) => {
342
+ filled2 = v;
343
+ },
344
+ });
345
+
346
+ // THEN the first fill uses the transient and the second falls back to stored
347
+ expect(filled1).toBe("transient-value");
348
+ expect(filled2).toBe("stored-value");
349
+ });
350
+
351
+ test("browserFill preserves transient value on fill failure", async () => {
352
+ // GIVEN a credential with a transient value
353
+ upsertCredentialMetadata("github", "token", {
354
+ allowedTools: ["browser_fill_credential"],
355
+ });
356
+ broker.injectTransient("github", "token", "transient-preserved");
357
+
358
+ // WHEN the first fill throws
359
+ const result1 = await broker.browserFill({
360
+ service: "github",
361
+ field: "token",
362
+ toolName: "browser_fill_credential",
363
+ fill: async () => {
364
+ throw new Error("Playwright timeout");
365
+ },
366
+ });
367
+ expect(result1.success).toBe(false);
368
+ let filled: string | undefined;
369
+ const result2 = await broker.browserFill({
370
+ service: "github",
371
+ field: "token",
372
+ toolName: "browser_fill_credential",
373
+ fill: async (v) => {
374
+ filled = v;
375
+ },
376
+ });
377
+
378
+ // THEN the transient value survives for the second fill
379
+ expect(result2.success).toBe(true);
380
+ expect(filled).toBe("transient-preserved");
381
+ });
382
+
383
+ test("serverUse uses transient value when available", async () => {
384
+ // GIVEN a credential with a transient value
385
+ upsertCredentialMetadata("vercel", "api_token", {
386
+ allowedTools: ["deploy"],
387
+ });
388
+ broker.injectTransient("vercel", "api_token", "transient-vercel-tok");
389
+
390
+ // WHEN serverUse runs
391
+ const result = await broker.serverUse({
392
+ service: "vercel",
393
+ field: "api_token",
394
+ toolName: "deploy",
395
+ execute: async (v) => {
396
+ expect(v).toBe("transient-vercel-tok");
397
+ return "deployed";
398
+ },
399
+ });
400
+
401
+ // THEN the transient value is used for execution
402
+ expect(result.success).toBe(true);
403
+ expect(result.result).toBe("deployed");
404
+ });
405
+
406
+ test("serverUse consumes transient — subsequent call has no value without stored key", async () => {
407
+ // GIVEN a credential with only a transient value (no stored value)
408
+ upsertCredentialMetadata("vercel", "api_token", {
409
+ allowedTools: ["deploy"],
410
+ });
411
+ broker.injectTransient("vercel", "api_token", "transient-only");
412
+
413
+ // WHEN serverUse runs twice
414
+ await broker.serverUse({
415
+ service: "vercel",
416
+ field: "api_token",
417
+ toolName: "deploy",
418
+ execute: async () => "ok",
419
+ });
420
+ const result = await broker.serverUse({
421
+ service: "vercel",
422
+ field: "api_token",
423
+ toolName: "deploy",
424
+ execute: async () => {
425
+ throw new Error("should not be called");
426
+ },
427
+ });
428
+
429
+ // THEN the second call fails because no stored value remains
430
+ expect(result.success).toBe(false);
431
+ expect(result.reason).toContain("no stored value");
432
+ });
433
+
434
+ test("injectTransient replaces previous transient for same key", () => {
435
+ // GIVEN two transient values injected for the same credential
436
+ upsertCredentialMetadata("svc", "key", { allowedTools: ["t"] });
437
+ broker.injectTransient("svc", "key", "first");
438
+ broker.injectTransient("svc", "key", "second");
439
+
440
+ // WHEN the credential is authorized and consumed
441
+ const auth = broker.authorize({
442
+ service: "svc",
443
+ field: "key",
444
+ toolName: "t",
445
+ });
446
+ if (!auth.authorized) return;
447
+ const result = broker.consume(auth.token.tokenId);
448
+
449
+ // THEN the most recent transient value wins
450
+ expect(result.value).toBe("second");
451
+ });
452
+
453
+ test("transient value for one credential does not affect another", () => {
454
+ // GIVEN a transient value injected for svcA only
455
+ upsertCredentialMetadata("svcA", "key", { allowedTools: ["t"] });
456
+ upsertCredentialMetadata("svcB", "key", { allowedTools: ["t"] });
457
+ broker.injectTransient("svcA", "key", "val-a");
458
+
459
+ // WHEN both credentials are authorized and consumed
460
+ const authB = broker.authorize({
461
+ service: "svcB",
462
+ field: "key",
463
+ toolName: "t",
464
+ });
465
+ if (!authB.authorized) return;
466
+ const resultB = broker.consume(authB.token.tokenId);
467
+ const authA = broker.authorize({
468
+ service: "svcA",
469
+ field: "key",
470
+ toolName: "t",
471
+ });
472
+ if (!authA.authorized) return;
473
+ const resultA = broker.consume(authA.token.tokenId);
474
+
475
+ // THEN only svcA carries the transient value
476
+ expect(resultB.success).toBe(true);
477
+ expect(resultB.value).toBeUndefined();
478
+ expect(resultA.value).toBe("val-a");
479
+ });
480
+ });
481
+
482
+ describe("serverUseById edge cases", () => {
483
+ test("serverUseById with multiple injection templates returns all", async () => {
484
+ // GIVEN a credential with two injection templates and a stored value
485
+ const meta = upsertCredentialMetadata("multi", "api_key", {
486
+ allowedTools: ["proxy"],
487
+ injectionTemplates: [
488
+ {
489
+ hostPattern: "*.fal.ai",
490
+ injectionType: "header",
491
+ headerName: "Authorization",
492
+ valuePrefix: "Key ",
493
+ },
494
+ {
495
+ hostPattern: "gateway.fal.ai",
496
+ injectionType: "header",
497
+ headerName: "X-Fal-Key",
498
+ },
499
+ ],
500
+ });
501
+ await setSecureKeyAsync(
502
+ credentialKey("multi", "api_key"),
503
+ "multi-secret",
504
+ );
505
+
506
+ // WHEN serverUseById resolves the credential by id
507
+ const result = await broker.serverUseById({
508
+ credentialId: meta.credentialId,
509
+ requestingTool: "proxy",
510
+ });
511
+
512
+ // THEN both injection templates are returned without leaking the secret
513
+ expect(result.success).toBe(true);
514
+ if (!result.success) return;
515
+ expect(result.injectionTemplates).toHaveLength(2);
516
+ expect(result.injectionTemplates[0].hostPattern).toBe("*.fal.ai");
517
+ expect(result.injectionTemplates[1].hostPattern).toBe("gateway.fal.ai");
518
+ expect(JSON.stringify(result)).not.toContain("multi-secret");
519
+ });
520
+ });
521
+
522
+ describe("revokeAll", () => {
523
+ test("revokeAll clears all tokens and subsequent consume fails", () => {
524
+ // GIVEN two active tokens for a credential
525
+ upsertCredentialMetadata("svc", "key", { allowedTools: ["t1", "t2"] });
526
+ const a1 = broker.authorize({
527
+ service: "svc",
528
+ field: "key",
529
+ toolName: "t1",
530
+ });
531
+ const a2 = broker.authorize({
532
+ service: "svc",
533
+ field: "key",
534
+ toolName: "t2",
535
+ });
536
+ expect(broker.activeTokenCount).toBe(2);
537
+
538
+ // WHEN revokeAll is called
539
+ broker.revokeAll();
540
+
541
+ // THEN the token count is zero and consuming either token fails
542
+ expect(broker.activeTokenCount).toBe(0);
543
+ if (a1.authorized) {
544
+ expect(broker.consume(a1.token.tokenId).success).toBe(false);
545
+ }
546
+ if (a2.authorized) {
547
+ expect(broker.consume(a2.token.tokenId).success).toBe(false);
548
+ }
549
+ });
550
+
551
+ test("revokeAll on empty broker is a no-op", () => {
552
+ // GIVEN a broker with no active tokens
553
+ expect(broker.activeTokenCount).toBe(0);
554
+
555
+ // WHEN revokeAll is called
556
+ broker.revokeAll();
557
+
558
+ // THEN the token count remains zero
559
+ expect(broker.activeTokenCount).toBe(0);
560
+ });
561
+ });
562
+
563
+ describe("canonical capability key", () => {
564
+ test("authorize succeeds with canonical key when metadata has canonical key", () => {
565
+ // GIVEN metadata allowing the canonical browser-fill capability key
566
+ upsertCredentialMetadata("github", "token", {
567
+ allowedTools: [BROWSER_FILL_CAPABILITY],
568
+ });
569
+
570
+ // WHEN authorizing with the canonical key
571
+ const result = broker.authorize({
572
+ service: "github",
573
+ field: "token",
574
+ toolName: BROWSER_FILL_CAPABILITY,
575
+ });
576
+
577
+ // THEN authorization succeeds
578
+ expect(result.authorized).toBe(true);
579
+ });
580
+
581
+ test("authorize succeeds with canonical key when metadata has legacy alias", () => {
582
+ // GIVEN metadata stored under the legacy browser_fill_credential alias
583
+ upsertCredentialMetadata("github", "token", {
584
+ allowedTools: ["browser_fill_credential"],
585
+ });
586
+
587
+ // WHEN authorizing with the canonical key
588
+ const result = broker.authorize({
589
+ service: "github",
590
+ field: "token",
591
+ toolName: BROWSER_FILL_CAPABILITY,
592
+ });
593
+
594
+ // THEN authorization succeeds
595
+ expect(result.authorized).toBe(true);
596
+ });
597
+
598
+ test("authorize succeeds with legacy alias when metadata has canonical key", () => {
599
+ // GIVEN metadata allowing the canonical capability key
600
+ upsertCredentialMetadata("github", "token", {
601
+ allowedTools: [BROWSER_FILL_CAPABILITY],
602
+ });
603
+
604
+ // WHEN authorizing with the legacy alias
605
+ const result = broker.authorize({
606
+ service: "github",
607
+ field: "token",
608
+ toolName: "browser_fill_credential",
609
+ });
610
+
611
+ // THEN authorization succeeds
612
+ expect(result.authorized).toBe(true);
613
+ });
614
+
615
+ test("serverUse with canonical key works when metadata has legacy alias", async () => {
616
+ // GIVEN metadata stored under the legacy alias with a stored value
617
+ upsertCredentialMetadata("vercel", "api_token", {
618
+ allowedTools: ["browser_fill_credential"],
619
+ });
620
+ await setSecureKeyAsync(
621
+ credentialKey("vercel", "api_token"),
622
+ "vercel-tok",
623
+ );
624
+
625
+ // WHEN serverUse runs with the canonical key
626
+ const result = await broker.serverUse({
627
+ service: "vercel",
628
+ field: "api_token",
629
+ toolName: BROWSER_FILL_CAPABILITY,
630
+ execute: async (v) => v,
631
+ });
632
+
633
+ // THEN execution succeeds with the stored value
634
+ expect(result.success).toBe(true);
635
+ expect(result.result).toBe("vercel-tok");
636
+ });
637
+
638
+ test("non-aliased tool names are unaffected by alias resolution", () => {
639
+ // GIVEN metadata allowing a non-aliased custom tool
640
+ upsertCredentialMetadata("svc", "key", {
641
+ allowedTools: ["custom_tool"],
642
+ });
643
+
644
+ // WHEN authorizing with that custom tool
645
+ const result = broker.authorize({
646
+ service: "svc",
647
+ field: "key",
648
+ toolName: "custom_tool",
649
+ });
650
+
651
+ // THEN authorization succeeds
652
+ expect(result.authorized).toBe(true);
653
+ });
654
+
655
+ test("non-aliased tool denied when only canonical key is allowed", () => {
656
+ // GIVEN metadata allowing only the canonical capability key
657
+ upsertCredentialMetadata("svc", "key", {
658
+ allowedTools: [BROWSER_FILL_CAPABILITY],
659
+ });
660
+
661
+ // WHEN authorizing with an unrelated tool
662
+ const result = broker.authorize({
663
+ service: "svc",
664
+ field: "key",
665
+ toolName: "unrelated_tool",
666
+ });
667
+
668
+ // THEN authorization is denied
669
+ expect(result.authorized).toBe(false);
670
+ });
671
+ });
672
+ });
@@ -11,27 +11,33 @@
11
11
 
12
12
  import { describe, expect, test } from "bun:test";
13
13
 
14
- import { isUntrustedTrustClass } from "../runtime/actor-trust-resolver.js";
14
+ import { resolveCapabilities } from "../runtime/capabilities.js";
15
15
 
16
16
  // ---------------------------------------------------------------------------
17
17
  // Trust class categorization (foundational for lockdown decisions)
18
18
  // ---------------------------------------------------------------------------
19
19
 
20
20
  describe("trust class categorization for CES lockdown", () => {
21
- test("guardian is not untrusted", () => {
22
- expect(isUntrustedTrustClass("guardian")).toBe(false);
21
+ test("guardian runs an unsandboxed shell", () => {
22
+ expect(resolveCapabilities("guardian").canRunUnsandboxedShell).toBe(true);
23
23
  });
24
24
 
25
- test("trusted_contact is untrusted", () => {
26
- expect(isUntrustedTrustClass("trusted_contact")).toBe(true);
25
+ test("trusted_contact shell is sandboxed", () => {
26
+ expect(resolveCapabilities("trusted_contact").canRunUnsandboxedShell).toBe(false);
27
27
  });
28
28
 
29
- test("unknown is untrusted", () => {
30
- expect(isUntrustedTrustClass("unknown")).toBe(true);
29
+ test("unverified_contact shell is sandboxed", () => {
30
+ expect(resolveCapabilities("unverified_contact").canRunUnsandboxedShell).toBe(
31
+ false,
32
+ );
31
33
  });
32
34
 
33
- test("undefined is untrusted", () => {
34
- expect(isUntrustedTrustClass(undefined)).toBe(true);
35
+ test("unknown shell is sandboxed", () => {
36
+ expect(resolveCapabilities("unknown").canRunUnsandboxedShell).toBe(false);
37
+ });
38
+
39
+ test("undefined shell is sandboxed", () => {
40
+ expect(resolveCapabilities(undefined).canRunUnsandboxedShell).toBe(false);
35
41
  });
36
42
  });
37
43
 
@@ -91,7 +97,7 @@ describe("VELLUM_UNTRUSTED_SHELL env flag", () => {
91
97
  describe("CES shell lockdown activation", () => {
92
98
  test("lockdown is active only when both flag is enabled AND actor is untrusted", () => {
93
99
  // Simulates the condition used in shell.ts:
94
- // const shellLockdownActive = isCesShellLockdownEnabled(config) && isUntrustedTrustClass(context.trustClass);
100
+ // const shellLockdownActive = isCesShellLockdownEnabled(config) && !resolveCapabilities(context.trustClass).canRunUnsandboxedShell;
95
101
  const cases: Array<{
96
102
  flagEnabled: boolean;
97
103
  trustClass: "guardian" | "trusted_contact" | "unknown";
@@ -106,7 +112,8 @@ describe("CES shell lockdown activation", () => {
106
112
  ];
107
113
 
108
114
  for (const { flagEnabled, trustClass, expected } of cases) {
109
- const active = flagEnabled && isUntrustedTrustClass(trustClass);
115
+ const active =
116
+ flagEnabled && !resolveCapabilities(trustClass).canRunUnsandboxedShell;
110
117
  expect(active).toBe(expected);
111
118
  }
112
119
  });
@@ -136,7 +136,6 @@ describe("secure tool installation is separate from credential grants", () => {
136
136
  test("manage_secure_command_tool does not share tool name with grant tools", () => {
137
137
  // The tool name must not collide with existing credential grant tools
138
138
  const grantToolNames = [
139
- "credential_store",
140
139
  "credential_grant",
141
140
  "credential_revoke",
142
141
  "credential_list",
@@ -110,6 +110,7 @@ function slackResult(
110
110
  hasAppToken: false,
111
111
  hasUserToken: false,
112
112
  connected: false,
113
+ threadMode: "mention_only",
113
114
  ...overrides,
114
115
  };
115
116
  }
@@ -138,10 +139,9 @@ describe("credentials/prompt route", () => {
138
139
 
139
140
  test("forwards usageDescription as the prompt purpose and to metadata", async () => {
140
141
  /**
141
- * The CLI `credentials prompt` command exposes `--usage-description` to
142
- * match the credential_store tool's prompt action. The route must thread
143
- * it to the secure prompt (as `purpose`, shown to the user) and persist it
144
- * to credential metadata (as `usageDescription`).
142
+ * The CLI `credentials prompt` command exposes `--usage-description`. The
143
+ * route must thread it to the secure prompt (as `purpose`, shown to the
144
+ * user) and persist it to credential metadata (as `usageDescription`).
145
145
  */
146
146
  // GIVEN the credentials/prompt route is registered
147
147
  expect(promptRoute).toBeDefined();