@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
@@ -0,0 +1,202 @@
1
+ import { beforeEach, describe, expect, test } from "bun:test";
2
+
3
+ import { getDocumentById } from "../documents/document-store.js";
4
+ import { getSqlite } from "../memory/db-connection.js";
5
+ import { executeDocumentUpdate } from "../tools/document/document-tool.js";
6
+ import type { ToolContext, ToolExecutionResult } from "../tools/types.js";
7
+ import { resetDbForTesting } from "./db-test-helpers.js";
8
+
9
+ function makeContext(overrides: Partial<ToolContext> = {}): ToolContext {
10
+ return {
11
+ workingDir: "/tmp/project",
12
+ conversationId: "conv-current",
13
+ trustClass: "trusted_contact",
14
+ executionChannel: "slack",
15
+ sendToClient: () => {},
16
+ ...overrides,
17
+ };
18
+ }
19
+
20
+ function parseResult<T>(result: ToolExecutionResult): T {
21
+ return JSON.parse(result.content) as T;
22
+ }
23
+
24
+ function bootstrapDocumentTables(): void {
25
+ resetDbForTesting();
26
+ const raw = getSqlite();
27
+ raw.exec(/*sql*/ `
28
+ DROP TABLE IF EXISTS document_conversations;
29
+ DROP TABLE IF EXISTS documents;
30
+ DROP TABLE IF EXISTS conversations;
31
+
32
+ CREATE TABLE conversations (
33
+ id TEXT PRIMARY KEY,
34
+ created_at INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)
35
+ );
36
+
37
+ CREATE TABLE documents (
38
+ surface_id TEXT PRIMARY KEY,
39
+ conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
40
+ title TEXT NOT NULL,
41
+ content TEXT NOT NULL,
42
+ word_count INTEGER NOT NULL DEFAULT 0,
43
+ created_at INTEGER NOT NULL,
44
+ updated_at INTEGER NOT NULL
45
+ );
46
+
47
+ CREATE TABLE document_conversations (
48
+ surface_id TEXT NOT NULL,
49
+ conversation_id TEXT NOT NULL,
50
+ created_at INTEGER NOT NULL,
51
+ PRIMARY KEY (surface_id, conversation_id),
52
+ FOREIGN KEY (surface_id) REFERENCES documents(surface_id) ON DELETE CASCADE
53
+ );
54
+ `);
55
+ }
56
+
57
+ function seedDocument(params: {
58
+ surfaceId: string;
59
+ conversationId: string;
60
+ title: string;
61
+ content: string;
62
+ createdAt: number;
63
+ updatedAt?: number;
64
+ }): void {
65
+ const raw = getSqlite();
66
+ raw
67
+ .query(`INSERT OR IGNORE INTO conversations (id, created_at) VALUES (?, ?)`)
68
+ .run(params.conversationId, params.createdAt);
69
+ raw
70
+ .query(
71
+ `INSERT INTO documents (surface_id, conversation_id, title, content, word_count, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)`,
72
+ )
73
+ .run(
74
+ params.surfaceId,
75
+ params.conversationId,
76
+ params.title,
77
+ params.content,
78
+ params.content.split(/\s+/).filter(Boolean).length,
79
+ params.createdAt,
80
+ params.updatedAt ?? params.createdAt,
81
+ );
82
+ raw
83
+ .query(
84
+ `INSERT OR IGNORE INTO document_conversations (surface_id, conversation_id, created_at) VALUES (?, ?, ?)`,
85
+ )
86
+ .run(params.surfaceId, params.conversationId, params.createdAt);
87
+ }
88
+
89
+ describe("executeDocumentUpdate — default surface_id resolution", () => {
90
+ beforeEach(() => {
91
+ bootstrapDocumentTables();
92
+ });
93
+
94
+ test("appends to the conversation's only document when surface_id is omitted", () => {
95
+ const surfaceId = "doc-only";
96
+ seedDocument({
97
+ surfaceId,
98
+ conversationId: "conv-current",
99
+ title: "Dating in 2026",
100
+ content: "# Dating in 2026\n\nIntro.",
101
+ createdAt: Date.now(),
102
+ });
103
+
104
+ const result = executeDocumentUpdate(
105
+ { content: "## Section two", mode: "append" },
106
+ makeContext(),
107
+ );
108
+
109
+ expect(result.isError).toBe(false);
110
+ const body = parseResult<{ surface_id: string; success: boolean }>(result);
111
+ expect(body.success).toBe(true);
112
+ expect(body.surface_id).toBe(surfaceId);
113
+ expect(getDocumentById(surfaceId)?.content).toBe(
114
+ "# Dating in 2026\n\nIntro.\n\n## Section two",
115
+ );
116
+ });
117
+
118
+ test("targets the most recently updated document when several exist", () => {
119
+ const now = Date.now();
120
+ seedDocument({
121
+ surfaceId: "doc-old",
122
+ conversationId: "conv-current",
123
+ title: "Old",
124
+ content: "old",
125
+ createdAt: now - 10_000,
126
+ updatedAt: now - 10_000,
127
+ });
128
+ seedDocument({
129
+ surfaceId: "doc-fresh",
130
+ conversationId: "conv-current",
131
+ title: "Fresh",
132
+ content: "fresh",
133
+ createdAt: now,
134
+ updatedAt: now,
135
+ });
136
+
137
+ const result = executeDocumentUpdate({ content: "more" }, makeContext());
138
+
139
+ expect(result.isError).toBe(false);
140
+ const body = parseResult<{ surface_id: string }>(result);
141
+ expect(body.surface_id).toBe("doc-fresh");
142
+ expect(getDocumentById("doc-fresh")?.content).toBe("fresh\n\nmore");
143
+ expect(getDocumentById("doc-old")?.content).toBe("old");
144
+ });
145
+
146
+ test("an explicit surface_id still wins over the default", () => {
147
+ const now = Date.now();
148
+ seedDocument({
149
+ surfaceId: "doc-target",
150
+ conversationId: "conv-current",
151
+ title: "Target",
152
+ content: "target",
153
+ createdAt: now - 10_000,
154
+ updatedAt: now - 10_000,
155
+ });
156
+ seedDocument({
157
+ surfaceId: "doc-fresh",
158
+ conversationId: "conv-current",
159
+ title: "Fresh",
160
+ content: "fresh",
161
+ createdAt: now,
162
+ updatedAt: now,
163
+ });
164
+
165
+ const result = executeDocumentUpdate(
166
+ { surface_id: "doc-target", content: "hit" },
167
+ makeContext(),
168
+ );
169
+
170
+ expect(result.isError).toBe(false);
171
+ expect(parseResult<{ surface_id: string }>(result).surface_id).toBe(
172
+ "doc-target",
173
+ );
174
+ expect(getDocumentById("doc-target")?.content).toBe("target\n\nhit");
175
+ expect(getDocumentById("doc-fresh")?.content).toBe("fresh");
176
+ });
177
+
178
+ test("errors helpfully when the conversation has no document", () => {
179
+ const result = executeDocumentUpdate(
180
+ { content: "orphan chunk" },
181
+ makeContext(),
182
+ );
183
+
184
+ expect(result.isError).toBe(true);
185
+ expect(result.content).toContain("no document is open");
186
+ expect(result.content).toContain("document_create");
187
+ });
188
+
189
+ test("still requires content", () => {
190
+ seedDocument({
191
+ surfaceId: "doc-only",
192
+ conversationId: "conv-current",
193
+ title: "X",
194
+ content: "x",
195
+ createdAt: Date.now(),
196
+ });
197
+
198
+ const result = executeDocumentUpdate({ mode: "append" }, makeContext());
199
+ expect(result.isError).toBe(true);
200
+ expect(result.content).toContain("content is required");
201
+ });
202
+ });
@@ -5,7 +5,7 @@ import type {
5
5
  UiSurfaceShowDynamicPage,
6
6
  } from "../daemon/message-protocol.js";
7
7
  import { INTERACTIVE_SURFACE_TYPES } from "../daemon/message-protocol.js";
8
- import { uiShowTool } from "../tools/ui-surface/definitions.js";
8
+ import { uiShowTool, uiUpdateTool } from "../tools/ui-surface/definitions.js";
9
9
 
10
10
  // ---------------------------------------------------------------------------
11
11
  // DynamicPageSurfaceData shape
@@ -151,6 +151,57 @@ describe("ui_show dynamic_page app substitute guard", () => {
151
151
  expect(proxied).toBe(false);
152
152
  });
153
153
 
154
+ test("redirects a weak open model to a declarative surface, not 'resend HTML'", async () => {
155
+ let proxied = false;
156
+
157
+ const result = await uiShowTool.execute(
158
+ {
159
+ surface_type: "dynamic_page",
160
+ title: "Fable 5 vs MiniMax M3",
161
+ data: {},
162
+ },
163
+ {
164
+ conversationId: "conversation-123",
165
+ workingDir: "/tmp",
166
+ trustClass: "guardian",
167
+ attribution: {
168
+ resolvedModel: "accounts/fireworks/models/minimax-m3",
169
+ } as never,
170
+ proxyToolResolver: async () => {
171
+ proxied = true;
172
+ return { content: "proxied", isError: false };
173
+ },
174
+ },
175
+ );
176
+
177
+ expect(result.isError).toBe(true);
178
+ expect(result.content).toContain('surface_type: "table"');
179
+ expect(result.content).toContain("work_result");
180
+ expect(result.content).not.toContain("Resend ui_show with the full HTML");
181
+ expect(proxied).toBe(false);
182
+ });
183
+
184
+ test("keeps the resend-HTML hint for a capable model", async () => {
185
+ const result = await uiShowTool.execute(
186
+ {
187
+ surface_type: "dynamic_page",
188
+ title: "Fable 5 vs MiniMax M3",
189
+ data: {},
190
+ },
191
+ {
192
+ conversationId: "conversation-123",
193
+ workingDir: "/tmp",
194
+ trustClass: "guardian",
195
+ attribution: { resolvedModel: "claude-opus-4-8" } as never,
196
+ proxyToolResolver: async () => ({ content: "proxied", isError: false }),
197
+ },
198
+ );
199
+
200
+ expect(result.isError).toBe(true);
201
+ expect(result.content).toContain("Resend ui_show with the full HTML");
202
+ expect(result.content).not.toContain('surface_type: "table"');
203
+ });
204
+
154
205
  test("rejects dynamic_page with whitespace-only html and does not proxy", async () => {
155
206
  let proxied = false;
156
207
 
@@ -300,6 +351,106 @@ describe("ui_show empty card guard", () => {
300
351
  });
301
352
  });
302
353
 
354
+ describe("ui_update empty payload guard", () => {
355
+ function makeCtx(onProxy: () => void) {
356
+ return {
357
+ conversationId: "conversation-123",
358
+ workingDir: "/tmp",
359
+ trustClass: "guardian" as const,
360
+ proxyToolResolver: async () => {
361
+ onProxy();
362
+ return { content: "Surface updated", isError: false };
363
+ },
364
+ };
365
+ }
366
+
367
+ test("rejects an empty data object and does not proxy", async () => {
368
+ let proxied = false;
369
+ const result = await uiUpdateTool.execute(
370
+ { surface_id: "surf-1", data: {} },
371
+ makeCtx(() => {
372
+ proxied = true;
373
+ }),
374
+ );
375
+
376
+ expect(result.isError).toBe(true);
377
+ expect(result.content).toContain("empty `data` payload");
378
+ expect(proxied).toBe(false);
379
+ });
380
+
381
+ test("rejects missing data and does not proxy", async () => {
382
+ let proxied = false;
383
+ const result = await uiUpdateTool.execute(
384
+ { surface_id: "surf-1" },
385
+ makeCtx(() => {
386
+ proxied = true;
387
+ }),
388
+ );
389
+
390
+ expect(result.isError).toBe(true);
391
+ expect(proxied).toBe(false);
392
+ });
393
+
394
+ test("rejects data containing only nested empty objects", async () => {
395
+ let proxied = false;
396
+ const result = await uiUpdateTool.execute(
397
+ { surface_id: "surf-1", data: { templateData: {} } },
398
+ makeCtx(() => {
399
+ proxied = true;
400
+ }),
401
+ );
402
+
403
+ expect(result.isError).toBe(true);
404
+ expect(proxied).toBe(false);
405
+ });
406
+
407
+ test("rejects a task_progress update with an empty steps array", async () => {
408
+ let proxied = false;
409
+ const result = await uiUpdateTool.execute(
410
+ { surface_id: "surf-1", data: { templateData: { steps: [] } } },
411
+ makeCtx(() => {
412
+ proxied = true;
413
+ }),
414
+ );
415
+
416
+ expect(result.isError).toBe(true);
417
+ expect(proxied).toBe(false);
418
+ });
419
+
420
+ test("allows a task_progress step update", async () => {
421
+ let proxied = false;
422
+ const result = await uiUpdateTool.execute(
423
+ {
424
+ surface_id: "surf-1",
425
+ data: {
426
+ templateData: {
427
+ steps: [{ label: "Read memo", status: "completed" }],
428
+ },
429
+ },
430
+ },
431
+ makeCtx(() => {
432
+ proxied = true;
433
+ }),
434
+ );
435
+
436
+ expect(result.isError).toBe(false);
437
+ expect(proxied).toBe(true);
438
+ });
439
+
440
+ test("allows a status-only update without resending steps", async () => {
441
+ let proxied = false;
442
+ const result = await uiUpdateTool.execute(
443
+ { surface_id: "surf-1", data: { templateData: { status: "completed" } } },
444
+ makeCtx(() => {
445
+ proxied = true;
446
+ }),
447
+ );
448
+
449
+ expect(result.isError).toBe(false);
450
+ expect(proxied).toBe(true);
451
+ });
452
+ });
453
+
303
454
  // ---------------------------------------------------------------------------
304
455
  // task_progress ui_show appends the update hint to its return value
305
456
  // ---------------------------------------------------------------------------
@@ -29,25 +29,6 @@ export interface ContextInjectionCase {
29
29
  }
30
30
 
31
31
  export const contextInjectionCases: ContextInjectionCase[] = [
32
- {
33
- label: "credential_store store action output",
34
- vector: "tool_output",
35
- tool: "credential_store",
36
- input: {
37
- action: "store",
38
- service: "github",
39
- field: "token",
40
- value: TEST_CREDENTIAL,
41
- },
42
- forbiddenValue: TEST_CREDENTIAL,
43
- },
44
- {
45
- label: "credential_store list action output",
46
- vector: "tool_output",
47
- tool: "credential_store",
48
- input: { action: "list" },
49
- forbiddenValue: TEST_CREDENTIAL,
50
- },
51
32
  {
52
33
  label: "browser_fill_credential result",
53
34
  vector: "tool_output",
@@ -59,18 +40,6 @@ export const contextInjectionCases: ContextInjectionCase[] = [
59
40
  },
60
41
  forbiddenValue: TEST_CREDENTIAL,
61
42
  },
62
- {
63
- label: "confirmation_request payload for credential_store",
64
- vector: "confirmation_payload",
65
- tool: "credential_store",
66
- input: {
67
- action: "store",
68
- service: "github",
69
- field: "token",
70
- value: TEST_CREDENTIAL,
71
- },
72
- forbiddenValue: TEST_CREDENTIAL,
73
- },
74
43
  ];
75
44
 
76
45
  // ---------------------------------------------------------------------------
@@ -87,8 +56,8 @@ export interface DirectReadCase {
87
56
 
88
57
  export const directReadCases: DirectReadCase[] = [
89
58
  {
90
- label: "vault.ts getCredentialValue",
91
- modulePath: "tools/credentials/vault",
59
+ label: "broker.ts getCredentialValue",
60
+ modulePath: "tools/credentials/broker",
92
61
  exportName: "getCredentialValue",
93
62
  },
94
63
  ];
@@ -25,12 +25,14 @@ mock.module("../ipc/socket-path.js", () => ({
25
25
  // Track calls to refreshOverridesFromGateway
26
26
  // ---------------------------------------------------------------------------
27
27
  let refreshCallCount = 0;
28
+ let refreshReturnsLoaded = true;
28
29
 
29
30
  mock.module("../config/assistant-feature-flags.js", () => ({
30
31
  refreshOverridesFromGateway: async () => {
31
32
  refreshCallCount++;
33
+ return refreshReturnsLoaded;
32
34
  },
33
- initFeatureFlagOverrides: async () => {},
35
+ initFeatureFlagOverrides: async () => true,
34
36
  clearFeatureFlagOverridesCache: () => {},
35
37
  isAssistantFeatureFlagEnabled: () => true,
36
38
  }));
@@ -60,6 +62,32 @@ mock.module("../tools/registry.js", () => ({
60
62
  },
61
63
  }));
62
64
 
65
+ // ---------------------------------------------------------------------------
66
+ // Track reconcileFlagGatedProfiles calls and let each test control whether it
67
+ // reports a config change, so we can assert the listener broadcasts only when
68
+ // the managed profile set actually changes.
69
+ // ---------------------------------------------------------------------------
70
+ let reconcileCallCount = 0;
71
+ let reconcileReturns = false;
72
+
73
+ mock.module("../config/sync-gated-profiles.js", () => ({
74
+ reconcileFlagGatedProfiles: () => {
75
+ reconcileCallCount++;
76
+ return reconcileReturns;
77
+ },
78
+ }));
79
+
80
+ // ---------------------------------------------------------------------------
81
+ // Track publishConfigChanged so we can assert the picker-refresh broadcast.
82
+ // ---------------------------------------------------------------------------
83
+ let configChangedCount = 0;
84
+
85
+ mock.module("../runtime/sync/resource-sync-events.js", () => ({
86
+ publishConfigChanged: () => {
87
+ configChangedCount++;
88
+ },
89
+ }));
90
+
63
91
  // ---------------------------------------------------------------------------
64
92
  // Dynamic imports (after mock.module)
65
93
  // ---------------------------------------------------------------------------
@@ -115,8 +143,12 @@ describe("gateway-flag-listener", () => {
115
143
  beforeEach(() => {
116
144
  mkdirSync(testRoot, { recursive: true });
117
145
  refreshCallCount = 0;
146
+ refreshReturnsLoaded = true;
118
147
  syncToolsCallCount = 0;
119
148
  publishedTagSets = [];
149
+ reconcileCallCount = 0;
150
+ reconcileReturns = false;
151
+ configChangedCount = 0;
120
152
  testServer = createTestServer();
121
153
  });
122
154
 
@@ -180,6 +212,83 @@ describe("gateway-flag-listener", () => {
180
212
  ]);
181
213
  });
182
214
 
215
+ test("reconciles flag-gated profiles and broadcasts config_changed when the profile set changes", async () => {
216
+ reconcileReturns = true;
217
+ await new Promise<void>((resolve) => {
218
+ testServer.server.listen(socketPath, resolve);
219
+ });
220
+
221
+ startGatewayFlagListener();
222
+ await testServer.waitForClient();
223
+ await new Promise((r) => setTimeout(r, 100));
224
+
225
+ // Connect path reconciles once and, since it reports a change, broadcasts.
226
+ expect(reconcileCallCount).toBe(1);
227
+ expect(configChangedCount).toBe(1);
228
+
229
+ testServer.emit("feature_flags_changed");
230
+ await new Promise((r) => setTimeout(r, 100));
231
+
232
+ expect(reconcileCallCount).toBe(2);
233
+ expect(configChangedCount).toBe(2);
234
+ });
235
+
236
+ test("reconciles but does not broadcast config_changed when the profile set is unchanged", async () => {
237
+ reconcileReturns = false;
238
+ await new Promise<void>((resolve) => {
239
+ testServer.server.listen(socketPath, resolve);
240
+ });
241
+
242
+ startGatewayFlagListener();
243
+ await testServer.waitForClient();
244
+ await new Promise((r) => setTimeout(r, 100));
245
+
246
+ testServer.emit("feature_flags_changed");
247
+ await new Promise((r) => setTimeout(r, 100));
248
+
249
+ expect(reconcileCallCount).toBeGreaterThanOrEqual(2);
250
+ expect(configChangedCount).toBe(0);
251
+ });
252
+
253
+ test("does not reconcile profiles when the refresh reports flags did not load", async () => {
254
+ reconcileReturns = true;
255
+ refreshReturnsLoaded = false;
256
+ await new Promise<void>((resolve) => {
257
+ testServer.server.listen(socketPath, resolve);
258
+ });
259
+
260
+ startGatewayFlagListener();
261
+ await testServer.waitForClient();
262
+ await new Promise((r) => setTimeout(r, 100));
263
+
264
+ // Tool sync stays unconditional; the profile reconcile/broadcast are gated.
265
+ expect(syncToolsCallCount).toBe(1);
266
+ expect(reconcileCallCount).toBe(0);
267
+ expect(configChangedCount).toBe(0);
268
+
269
+ testServer.emit("feature_flags_changed");
270
+ await new Promise((r) => setTimeout(r, 100));
271
+
272
+ expect(syncToolsCallCount).toBe(2);
273
+ expect(reconcileCallCount).toBe(0);
274
+ expect(configChangedCount).toBe(0);
275
+ });
276
+
277
+ test("reconciles profiles when the refresh reports flags loaded", async () => {
278
+ reconcileReturns = true;
279
+ refreshReturnsLoaded = true;
280
+ await new Promise<void>((resolve) => {
281
+ testServer.server.listen(socketPath, resolve);
282
+ });
283
+
284
+ startGatewayFlagListener();
285
+ await testServer.waitForClient();
286
+ await new Promise((r) => setTimeout(r, 100));
287
+
288
+ expect(reconcileCallCount).toBe(1);
289
+ expect(configChangedCount).toBe(1);
290
+ });
291
+
183
292
  test("ignores non-flag events", async () => {
184
293
  await new Promise<void>((resolve) => {
185
294
  testServer.server.listen(socketPath, resolve);
@@ -23,11 +23,7 @@ const ALLOWLIST = new Set([
23
23
 
24
24
  // --- Intentional local daemon-control paths ---
25
25
  "assistant/src/cli/commands/conversations.ts", // CLI wipe talks to runtime directly
26
- "clients/shared/Network/DaemonClient.swift",
27
- "clients/shared/App/Auth/PlatformOAuthService.swift", // comment explaining runtimeUrl vs platformUrl
28
- "clients/macos/vellum-assistant/App/AppDelegate.swift",
29
- "clients/macos/vellum-assistant/Features/Settings/SettingsConnectTab.swift",
30
- "apps/macos/src/main/bundle-flow.ts", // Electron main calls the local gateway (gatewayPort) with a Guardian token to scan bundles
26
+ "clients/macos/src/main/bundle-flow.ts", // Electron main calls the local gateway (gatewayPort) with a Guardian token to scan bundles
31
27
  ".claude/skills/update/SKILL.md", // daemon health check script
32
28
 
33
29
  // --- Test fixtures that poll the daemon directly (gateway may require auth) ---
@@ -87,12 +83,12 @@ function isGatewayInternal(filePath: string): boolean {
87
83
 
88
84
  /** Additional files allowed for the interpolated-port check only (use gateway port, not runtime). */
89
85
  const INTERPOLATED_PORT_ALLOWLIST = new Set([
90
- "apps/macos/src/main/bundle-flow.ts",
86
+ "clients/macos/src/main/bundle-flow.ts",
91
87
  // Electron main bridges the host proxy to a local assistant's gateway
92
88
  // (gatewayPort) over loopback with a Guardian-minted gateway token — same
93
89
  // class as bundle-flow.ts. Added with #34049 (host proxy for cloud/managed
94
90
  // assistants); the allowlist entry was missed there.
95
- "apps/macos/src/main/host-proxy-router.ts",
91
+ "clients/macos/src/main/host-proxy-router.ts",
96
92
  ]);
97
93
 
98
94
  /** Shared violation filter: exempt test files, gateway internals, and allowlisted paths. */
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Coverage for GeminiProvider.countInputTokens — the real Gemini tokenizer via
3
+ * `models.countTokens`. Mirrors generateContent's composition (contents +
4
+ * systemInstruction + tool function declarations); throws when the endpoint
5
+ * returns no `totalTokens` so the daemon falls back to the local estimate.
6
+ */
7
+ import { describe, expect, mock, test } from "bun:test";
8
+
9
+ let lastCountParams: Record<string, unknown> | undefined;
10
+ let countResult: { totalTokens?: number } = { totalTokens: 1234 };
11
+
12
+ mock.module("@google/genai", () => ({
13
+ GoogleGenAI: class {
14
+ constructor() {}
15
+ models = {
16
+ countTokens: async (params: Record<string, unknown>) => {
17
+ lastCountParams = params;
18
+ return countResult;
19
+ },
20
+ };
21
+ },
22
+ ApiError: class extends Error {},
23
+ ThinkingLevel: {
24
+ MINIMAL: "MINIMAL",
25
+ LOW: "LOW",
26
+ MEDIUM: "MEDIUM",
27
+ HIGH: "HIGH",
28
+ },
29
+ }));
30
+
31
+ import { GeminiProvider } from "../providers/gemini/client.js";
32
+ import type { Message, ToolDefinition } from "../providers/types.js";
33
+
34
+ const messages: Message[] = [
35
+ { role: "user", content: [{ type: "text", text: "hello" }] },
36
+ ];
37
+ const tools: ToolDefinition[] = [
38
+ { name: "lookup", description: "d", input_schema: { type: "object" } },
39
+ ];
40
+
41
+ describe("GeminiProvider.countInputTokens", () => {
42
+ test("returns totalTokens and forwards model + system + tools", async () => {
43
+ countResult = { totalTokens: 1234 };
44
+ const provider = new GeminiProvider("key", "gemini-3-flash-preview");
45
+
46
+ const count = await provider.countInputTokens(
47
+ messages,
48
+ "sys prompt",
49
+ tools,
50
+ );
51
+
52
+ expect(count).toBe(1234);
53
+ expect(lastCountParams?.model).toBe("gemini-3-flash-preview");
54
+ const config = lastCountParams?.config as Record<string, unknown>;
55
+ expect(config.systemInstruction).toBe("sys prompt");
56
+ const cfgTools = config.tools as Array<{
57
+ functionDeclarations: Array<{ name: string }>;
58
+ }>;
59
+ expect(cfgTools[0].functionDeclarations[0].name).toBe("lookup");
60
+ expect(Array.isArray(lastCountParams?.contents)).toBe(true);
61
+ });
62
+
63
+ test("throws when the endpoint returns no totalTokens (caller falls back)", async () => {
64
+ countResult = {};
65
+ const provider = new GeminiProvider("key", "gemini-3-flash-preview");
66
+ await expect(
67
+ provider.countInputTokens(messages, "sys", undefined),
68
+ ).rejects.toThrow();
69
+ });
70
+ });
@@ -44,7 +44,7 @@ describe("healGuardianBindingDrift", () => {
44
44
  const guardian = findGuardianForChannel("vellum");
45
45
  expect(guardian).not.toBeNull();
46
46
  expect(guardian!.contact.principalId).toBe("vellum-principal-old-uuid");
47
- expect(guardian!.channel.externalUserId).toBe("vellum-principal-old-uuid");
47
+ expect(guardian!.channel.address).toBe("vellum-principal-old-uuid");
48
48
  });
49
49
 
50
50
  test("no-op when principals already match", () => {