@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,176 @@
1
+ /**
2
+ * Read-time enrichment of home-feed items with their source-conversation
3
+ * classification.
4
+ *
5
+ * The activity feed surfaces notifications produced by many background
6
+ * flows — the periodic heartbeat, memory-consolidation passes, each
7
+ * recurring schedule, auto-analysis runs, etc. Clients let the user filter
8
+ * the feed by that producer, so every item is tagged with:
9
+ *
10
+ * - `sourceType` — coarse producer category.
11
+ * - `sourceKey` — stable filter id (`schedule:<id>` per schedule,
12
+ * otherwise the `sourceType`).
13
+ * - `sourceLabel` — human-readable display (a schedule's name, or a
14
+ * static label such as "Heartbeat").
15
+ *
16
+ * The classification is derived from the source conversation's `source`
17
+ * column (and, for schedules, its name) rather than persisted onto the
18
+ * feed item. Resolving at read time keeps labels fresh across schedule
19
+ * renames and retroactively classifies items written before this feature
20
+ * existed, with no migration.
21
+ *
22
+ * The lookups are injectable so the enrichment can be unit-tested without
23
+ * a live database; production callers use the defaults.
24
+ */
25
+
26
+ import {
27
+ type FeedItem,
28
+ type FeedItemSourceType,
29
+ } from "../api/responses/home.js";
30
+ import { AUTO_ANALYSIS_SOURCE } from "../memory/auto-analysis-constants.js";
31
+ import { getConversation } from "../memory/conversation-crud.js";
32
+ import {
33
+ MEMORY_RETROSPECTIVE_FORK_SOURCE,
34
+ MEMORY_RETROSPECTIVE_SOURCE,
35
+ } from "../memory/memory-retrospective-constants.js";
36
+ import { getSchedule } from "../schedule/schedule-store.js";
37
+
38
+ /** Minimal source-conversation shape the enrichment needs. */
39
+ interface ConversationSourceRow {
40
+ source: string;
41
+ scheduleJobId: string | null;
42
+ }
43
+
44
+ export interface FeedSourceEnrichmentDeps {
45
+ /** Resolve the source columns for a conversation, or null when missing. */
46
+ getConversationRow?: (id: string) => ConversationSourceRow | null;
47
+ /** Resolve a schedule's display name, or null when missing. */
48
+ getScheduleName?: (id: string) => string | null;
49
+ }
50
+
51
+ /**
52
+ * Map a conversation's `source` column to a coarse feed source type.
53
+ * Mechanical mapping over the known producer sources; anything else
54
+ * (including the broadcaster's paired `"notification"` delivery
55
+ * conversations) falls through to `"other"`.
56
+ */
57
+ export function classifyConversationSource(
58
+ source: string | null | undefined,
59
+ ): FeedItemSourceType {
60
+ switch (source) {
61
+ case "heartbeat":
62
+ return "heartbeat";
63
+ case MEMORY_RETROSPECTIVE_SOURCE:
64
+ case MEMORY_RETROSPECTIVE_FORK_SOURCE:
65
+ return "memory_consolidation";
66
+ case "schedule":
67
+ return "schedule";
68
+ case AUTO_ANALYSIS_SOURCE:
69
+ return "auto_analysis";
70
+ case "user":
71
+ case "home-feed":
72
+ return "user";
73
+ default:
74
+ return "other";
75
+ }
76
+ }
77
+
78
+ /** Static display labels for non-schedule source types. */
79
+ const STATIC_SOURCE_LABELS: Record<
80
+ Exclude<FeedItemSourceType, "schedule">,
81
+ string
82
+ > = {
83
+ heartbeat: "Heartbeat",
84
+ memory_consolidation: "Memory consolidation",
85
+ auto_analysis: "Auto-analysis",
86
+ user: "Conversation",
87
+ other: "Other",
88
+ };
89
+
90
+ function defaultGetConversationRow(id: string): ConversationSourceRow | null {
91
+ try {
92
+ const row = getConversation(id);
93
+ return row
94
+ ? { source: row.source, scheduleJobId: row.scheduleJobId }
95
+ : null;
96
+ } catch {
97
+ return null;
98
+ }
99
+ }
100
+
101
+ function defaultGetScheduleName(id: string): string | null {
102
+ try {
103
+ return getSchedule(id)?.name ?? null;
104
+ } catch {
105
+ return null;
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Return a copy of each feed item enriched with `sourceType`, `sourceKey`,
111
+ * and `sourceLabel`. Conversation and schedule lookups are memoized across
112
+ * the batch so each distinct source is resolved at most once.
113
+ */
114
+ export function enrichFeedItemsWithSource(
115
+ items: FeedItem[],
116
+ deps: FeedSourceEnrichmentDeps = {},
117
+ ): FeedItem[] {
118
+ if (items.length === 0) return items;
119
+
120
+ const getConversationRow =
121
+ deps.getConversationRow ?? defaultGetConversationRow;
122
+ const getScheduleName = deps.getScheduleName ?? defaultGetScheduleName;
123
+
124
+ const convCache = new Map<string, ConversationSourceRow | null>();
125
+ const resolveConv = (id: string): ConversationSourceRow | null => {
126
+ if (!convCache.has(id)) convCache.set(id, getConversationRow(id));
127
+ return convCache.get(id) ?? null;
128
+ };
129
+
130
+ const scheduleNameCache = new Map<string, string | null>();
131
+ const resolveScheduleName = (id: string): string | null => {
132
+ if (!scheduleNameCache.has(id)) {
133
+ scheduleNameCache.set(id, getScheduleName(id));
134
+ }
135
+ return scheduleNameCache.get(id) ?? null;
136
+ };
137
+
138
+ return items.map((item) => {
139
+ const row = item.conversationId ? resolveConv(item.conversationId) : null;
140
+ const sourceType = classifyConversationSource(row?.source);
141
+
142
+ const metadataScheduleId =
143
+ typeof item.metadata?.scheduleId === "string"
144
+ ? item.metadata.scheduleId
145
+ : undefined;
146
+ const scheduleId = metadataScheduleId ?? row?.scheduleJobId ?? undefined;
147
+
148
+ let sourceKey: string;
149
+ let sourceLabel: string;
150
+ if (sourceType === "schedule" && scheduleId) {
151
+ sourceKey = `schedule:${scheduleId}`;
152
+ sourceLabel = resolveScheduleName(scheduleId) ?? "Scheduled";
153
+ } else if (sourceType === "schedule") {
154
+ sourceKey = "schedule";
155
+ sourceLabel = "Scheduled";
156
+ } else {
157
+ sourceKey = sourceType;
158
+ sourceLabel = STATIC_SOURCE_LABELS[sourceType];
159
+ }
160
+
161
+ // Surface the scheduleId in metadata when it was recovered from the
162
+ // source conversation so clients have a single place to read it.
163
+ const metadata =
164
+ scheduleId !== undefined && metadataScheduleId === undefined
165
+ ? { ...(item.metadata ?? {}), scheduleId }
166
+ : item.metadata;
167
+
168
+ return {
169
+ ...item,
170
+ sourceType,
171
+ sourceKey,
172
+ sourceLabel,
173
+ ...(metadata ? { metadata } : {}),
174
+ };
175
+ });
176
+ }
@@ -5,10 +5,8 @@
5
5
  * relationship with the user: which tier they're at, what facts the
6
6
  * assistant has learned about them, and which capabilities are unlocked.
7
7
  *
8
- * The TypeScript types here are the source of truth. A structurally
9
- * identical Swift definition lives at
10
- * `clients/shared/Models/RelationshipState.swift` — any change here must
11
- * be mirrored there (and the contract test guards the default list).
8
+ * The TypeScript types here are the source of truth; the contract test
9
+ * guards the default list.
12
10
  */
13
11
 
14
12
  export const RELATIONSHIP_STATE_VERSION = 1 as const;
package/src/instrument.ts CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  getPlatformUserId,
8
8
  getSentryDsn,
9
9
  } from "./config/env.js";
10
+ import { getCachedShareDiagnostics } from "./platform/consent-cache.js";
10
11
  import { APP_VERSION, COMMIT_SHA } from "./version.js";
11
12
 
12
13
  /** Patterns that match sensitive data in Sentry event values. */
@@ -41,9 +42,11 @@ function redactObject(obj: unknown): unknown {
41
42
  /**
42
43
  * Call after dotenv has loaded so SENTRY_DSN_ASSISTANT is available.
43
44
  * Initializes Sentry when the DSN is set; no-ops when empty/unset so
44
- * local dev builds don't send crash reports. If the user later opts out
45
- * via the sendDiagnostics config key (or VELLUM_DEV=1), call closeSentry()
46
- * after config is loaded to stop future event capturing.
45
+ * local dev builds don't send crash reports. Events are dropped by
46
+ * beforeSend until the platform share_diagnostics consent confirms opt-in
47
+ * (re-read from the consent cache per event, so a revocation takes effect
48
+ * within one refresh cycle); VELLUM_DEV=1 and legacyDiagnosticsOptOut
49
+ * hard-disable via closeSentry() after config loads.
47
50
  */
48
51
  export function initSentry(): void {
49
52
  const dsn = getSentryDsn();
@@ -54,6 +57,14 @@ export function initSentry(): void {
54
57
  dist: COMMIT_SHA,
55
58
  environment: process.env.VELLUM_ENVIRONMENT ?? "production",
56
59
  sendDefaultPii: false,
60
+ // Fail-closed: suppress client-report pings (discarded-event counts) so an
61
+ // assistant with unconfirmed share_diagnostics consent stays network-silent.
62
+ sendClientReports: false,
63
+ // Drop the default ProcessSession integration: it starts a release-health
64
+ // session on init and flushes a session envelope on process exit (a network
65
+ // request not covered by the beforeSend event gate), violating fail-closed.
66
+ integrations: (defaults) =>
67
+ defaults.filter((i) => i.name !== "ProcessSession"),
57
68
  serverName: hostname(),
58
69
  initialScope: {
59
70
  tags: {
@@ -77,6 +88,7 @@ export function initSentry(): void {
77
88
  },
78
89
  },
79
90
  beforeSend(event) {
91
+ if (!getCachedShareDiagnostics()) return null;
80
92
  if (event.exception?.values) {
81
93
  event.exception.values = event.exception.values.map((ex) => ({
82
94
  ...ex,
@@ -101,9 +113,9 @@ export function initSentry(): void {
101
113
  }
102
114
 
103
115
  /**
104
- * Stop capturing future Sentry events. Called after config loads when the
105
- * user has disabled sendDiagnostics so that early-startup crashes are
106
- * still captured but subsequent events are suppressed.
116
+ * Stop capturing future Sentry events. Called after config loads for the
117
+ * legacyDiagnosticsOptOut local opt-out (or VELLUM_DEV=1) to hard-disable
118
+ * crash reporting independent of the share_diagnostics consent gate.
107
119
  */
108
120
  export async function closeSentry(): Promise<void> {
109
121
  await Sentry.close();
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Unit tests for how `AssistantIpcServer.sendResult` handles a binary or
3
+ * streaming handler result over the IPC transport.
4
+ *
5
+ * A `RouteResponse` (or a bare `Uint8Array` / `ReadableStream` / `Blob`)
6
+ * wraps raw bytes that can't be carried as a JSON `result` field. Rather than
7
+ * silently serialize the body into garbage, the server reports a structured
8
+ * `BINARY_UNSUPPORTED_OVER_IPC` error; the gateway IPC proxy uses that signal
9
+ * to fall back to the HTTP proxy, which streams binary responses correctly.
10
+ */
11
+
12
+ import { describe, expect, test } from "bun:test";
13
+
14
+ import { RouteResponse } from "../../runtime/routes/types.js";
15
+ import { AssistantIpcServer } from "../assistant-server.js";
16
+
17
+ /**
18
+ * `sendResult` is private; access it through an interface cast so the test
19
+ * exercises the real production path without a test-only API on the class.
20
+ */
21
+ type PrivateApi = {
22
+ sendResult(
23
+ socket: unknown,
24
+ reader: unknown,
25
+ requestId: string,
26
+ value: unknown,
27
+ ): void;
28
+ };
29
+
30
+ /**
31
+ * Drive `sendResult` with a capturing socket in legacy (newline-delimited
32
+ * JSON) mode — the same wire shape the gateway's IPC client speaks — and
33
+ * return the parsed response envelope.
34
+ */
35
+ function captureSendResult(value: unknown): Record<string, unknown> {
36
+ const server = new AssistantIpcServer() as unknown as PrivateApi;
37
+ const writes: string[] = [];
38
+ const socket = {
39
+ destroyed: false,
40
+ write: (chunk: string) => {
41
+ writes.push(chunk);
42
+ return true;
43
+ },
44
+ };
45
+ const reader = { isLegacy: true };
46
+
47
+ server.sendResult(socket, reader, "req-1", value);
48
+
49
+ expect(writes).toHaveLength(1);
50
+ return JSON.parse(writes[0]) as Record<string, unknown>;
51
+ }
52
+
53
+ describe("AssistantIpcServer.sendResult binary handling", () => {
54
+ test("a binary RouteResponse is reported as BINARY_UNSUPPORTED_OVER_IPC", () => {
55
+ const env = captureSendResult(
56
+ new RouteResponse(new Uint8Array([137, 80, 78, 71]), {
57
+ "content-type": "image/png",
58
+ }),
59
+ );
60
+
61
+ expect(env.id).toBe("req-1");
62
+ expect(env.statusCode).toBe(421);
63
+ expect(env.errorCode).toBe("BINARY_UNSUPPORTED_OVER_IPC");
64
+ // The binary body must never be JSON-serialized into a `result` field.
65
+ expect("result" in env).toBe(false);
66
+ });
67
+
68
+ test("a bare Uint8Array result is also reported as unsupported", () => {
69
+ const env = captureSendResult(new Uint8Array([1, 2, 3]));
70
+
71
+ expect(env.errorCode).toBe("BINARY_UNSUPPORTED_OVER_IPC");
72
+ expect("result" in env).toBe(false);
73
+ });
74
+
75
+ test("a plain JSON result still serializes into `result`", () => {
76
+ const env = captureSendResult({ ok: true, count: 2 });
77
+
78
+ expect(env.result).toEqual({ ok: true, count: 2 });
79
+ expect(env.errorCode).toBeUndefined();
80
+ });
81
+ });
@@ -166,4 +166,24 @@ describe("assistant clients list over IPC — same-user filter", () => {
166
166
  const ids = parsed.clients.map((c) => c.clientId).sort();
167
167
  expect(ids).toEqual(["client-other", "client-self"]);
168
168
  });
169
+
170
+ test("--json output carries the degraded flag (false for fresh clients)", async () => {
171
+ registerClient({
172
+ clientId: "client-self-1",
173
+ actorPrincipalId: "guardian-local",
174
+ });
175
+
176
+ await startServer();
177
+
178
+ const { stdout } = await runAssistantCommandFull(
179
+ "clients",
180
+ "list",
181
+ "--json",
182
+ );
183
+ const parsed = JSON.parse(stdout.trim()) as {
184
+ clients: Array<{ clientId: string; degraded?: boolean }>;
185
+ };
186
+ expect(parsed.clients).toHaveLength(1);
187
+ expect(parsed.clients[0].degraded).toBe(false);
188
+ });
169
189
  });
@@ -31,10 +31,7 @@
31
31
  import { existsSync, unlinkSync } from "node:fs";
32
32
  import { createServer, type Server, type Socket } from "node:net";
33
33
 
34
- import {
35
- ensureSocketDir,
36
- SocketWatchdog,
37
- } from "@vellumai/ipc-server-utils";
34
+ import { ensureSocketDir, SocketWatchdog } from "@vellumai/ipc-server-utils";
38
35
 
39
36
  import { findLocalGuardianPrincipalId } from "../runtime/local-actor-identity.js";
40
37
  import { RouteError } from "../runtime/routes/errors.js";
@@ -43,6 +40,7 @@ import type {
43
40
  RouteDefinition,
44
41
  RouteHandlerArgs,
45
42
  } from "../runtime/routes/types.js";
43
+ import { RouteResponse } from "../runtime/routes/types.js";
46
44
  import { getLogger } from "../util/logger.js";
47
45
  import {
48
46
  type IpcEnvelope,
@@ -134,6 +132,26 @@ function isIpcBinaryResponse(value: unknown): value is IpcBinaryResponse {
134
132
  );
135
133
  }
136
134
 
135
+ /**
136
+ * A handler result whose body is raw bytes or a stream rather than a JSON
137
+ * value — `RouteResponse` (e.g. `workspace/file/content` returns a
138
+ * `Bun.file`), or a bare `Uint8Array` / `ReadableStream` / `Blob`.
139
+ *
140
+ * These cannot be carried as a JSON `result` field, so over the IPC
141
+ * transport they are reported as a structured error rather than silently
142
+ * JSON-serialized into garbage. Distinct from the `IpcBinaryResponse` /
143
+ * `IpcStreamingResponse` wrappers, which are explicit binary envelopes the
144
+ * framing protocol does transmit.
145
+ */
146
+ function isNonJsonIpcResult(value: unknown): boolean {
147
+ return (
148
+ value instanceof RouteResponse ||
149
+ value instanceof Uint8Array ||
150
+ value instanceof ReadableStream ||
151
+ value instanceof Blob
152
+ );
153
+ }
154
+
137
155
  // ---------------------------------------------------------------------------
138
156
  // Server
139
157
  // ---------------------------------------------------------------------------
@@ -401,6 +419,8 @@ export class AssistantIpcServer {
401
419
  * Route a handler result to the appropriate send path:
402
420
  * - IpcStreamingResponse → chunked binary frames
403
421
  * - IpcBinaryResponse → single binary frame with content-length
422
+ * - A raw binary/stream result (RouteResponse, Uint8Array, ...) → structured
423
+ * BINARY_UNSUPPORTED_OVER_IPC error (the transport can't carry it as JSON)
404
424
  * - Everything else → JSON response
405
425
  */
406
426
  private sendResult(
@@ -420,6 +440,19 @@ export class AssistantIpcServer {
420
440
  },
421
441
  };
422
442
  this.sendResponse(socket, reader, envelope, value.binary);
443
+ } else if (isNonJsonIpcResult(value)) {
444
+ // A binary/streaming handler result (e.g. a file-content RouteResponse
445
+ // wrapping a Bun.file) cannot be carried as a JSON `result`. Report a
446
+ // structured error instead of silently serializing it into garbage; the
447
+ // gateway IPC proxy treats this code as a signal to retry over HTTP,
448
+ // which streams binary correctly.
449
+ this.sendResponse(socket, reader, {
450
+ id: requestId,
451
+ error:
452
+ "Binary/streaming responses are not supported over the IPC transport; use HTTP",
453
+ statusCode: 421,
454
+ errorCode: "BINARY_UNSUPPORTED_OVER_IPC",
455
+ });
423
456
  } else {
424
457
  this.sendResponse(socket, reader, { id: requestId, result: value });
425
458
  }
@@ -1,7 +1,9 @@
1
1
  import { connect, type Socket } from "node:net";
2
2
 
3
3
  import { refreshOverridesFromGateway } from "../config/assistant-feature-flags.js";
4
+ import { reconcileFlagGatedProfiles } from "../config/sync-gated-profiles.js";
4
5
  import { SYNC_TAGS } from "../daemon/message-types/sync.js";
6
+ import { publishConfigChanged } from "../runtime/sync/resource-sync-events.js";
5
7
  import { publishSyncInvalidation } from "../runtime/sync/sync-publisher.js";
6
8
  import { syncFlagGatedTools } from "../tools/registry.js";
7
9
  import { getLogger } from "../util/logger.js";
@@ -19,11 +21,25 @@ const log = getLogger("gateway-flag-listener");
19
21
  * they live in a flag-gated bundled skill surfaced via `skill_load` against the
20
22
  * live flag cache, so they need no registry sync here. `syncFlagGatedTools` is
21
23
  * idempotent and enable-only, so re-running it on every refresh is safe; it also
22
- * never throws (it logs internally).
24
+ * never throws (it logs internally). After tools sync, `reconcileFlagGatedProfiles`
25
+ * adds or removes the flag-gated managed profile (OS Beta); when it reports a
26
+ * change a `config_changed` broadcast refreshes the profile picker on clients.
27
+ * The profile reconcile runs only when the refresh confirmed flags loaded from
28
+ * the gateway — a transient IPC failure leaves the cache unset and resolves
29
+ * `os-beta` to its registry default `false`, which would remove the user's
30
+ * profile and reset their selection. Tool sync tolerates the default and stays
31
+ * unconditional.
23
32
  */
24
33
  function refreshFlagsAndSyncTools(context: string): void {
25
34
  refreshOverridesFromGateway()
26
- .then(() => syncFlagGatedTools())
35
+ .then(async (loaded) => {
36
+ await syncFlagGatedTools();
37
+ if (loaded && reconcileFlagGatedProfiles()) {
38
+ // Reuse the config-changed broadcast clients already consume so the
39
+ // profile picker reflects the added/removed managed profile.
40
+ publishConfigChanged();
41
+ }
42
+ })
27
43
  .catch((err) => {
28
44
  log.warn(
29
45
  { err },
@@ -76,17 +76,6 @@ mock.module("../jobs-store.js", () => ({
76
76
  },
77
77
  }));
78
78
 
79
- // Mirror production semantics from `isUntrustedTrustClass` in
80
- // actor-trust-resolver.ts: anything that isn't `guardian` is untrusted.
81
- // Keeping these in sync guards the compaction trust boundary — a drifting
82
- // mock would let regressions pass as false positives.
83
- mock.module("../../runtime/actor-trust-resolver.js", () => ({
84
- isUntrustedTrustClass: (trustClass: string | undefined) =>
85
- trustClass === "trusted_contact" ||
86
- trustClass === "unknown" ||
87
- trustClass === undefined,
88
- }));
89
-
90
79
  import {
91
80
  enqueueAutoAnalysisIfEnabled,
92
81
  enqueueAutoAnalysisOnCompaction,
@@ -315,9 +304,9 @@ describe("enqueueAutoAnalysisOnCompaction", () => {
315
304
  });
316
305
 
317
306
  test("undefined trust class — skips (fail-closed when trust is unresolved)", () => {
318
- // `isUntrustedTrustClass(undefined)` is true in production, so
319
- // compaction-triggered analysis must NOT fire when the caller cannot
320
- // establish a trust class.
307
+ // `resolveCapabilities(undefined).canAccessMemory` is false in
308
+ // production, so compaction-triggered analysis must NOT fire when the
309
+ // caller cannot establish a trust class.
321
310
  enqueueAutoAnalysisOnCompaction("c1", undefined);
322
311
 
323
312
  expect(enqueueCalls).toHaveLength(0);
@@ -332,8 +321,8 @@ describe("enqueueAutoAnalysisOnCompaction", () => {
332
321
  });
333
322
 
334
323
  test("trusted_contact trust class — skips (only guardian is trusted)", () => {
335
- // trusted_contact is in the untrusted set per production
336
- // `isUntrustedTrustClass`, so compaction-triggered analysis must NOT
324
+ // trusted_contact lacks `canAccessMemory` per production
325
+ // `resolveCapabilities`, so compaction-triggered analysis must NOT
337
326
  // fire. Only `guardian` passes the gate.
338
327
  enqueueAutoAnalysisOnCompaction("c1", "trusted_contact");
339
328
 
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Tests for the secondary append-only database file wiring (PR 1).
3
+ *
4
+ * What this locks in:
5
+ * 1. Opening the connection ATTACHes `assistant-logs.db` as the `logs`
6
+ * schema and creates the file on disk.
7
+ * 2. The attached schema runs in WAL mode (its own `-wal`, independent of
8
+ * the main DB) — the regression that lets a heavy append-only table
9
+ * bloat the *main* WAL is exactly what this split exists to prevent.
10
+ * 3. A table created in the `logs` schema lives in the separate file, not
11
+ * in `main` — proving the physical split rather than just an alias.
12
+ * 4. `runAsyncSqlite({ dbPath })` targets the given file via the sqlite3
13
+ * CLI backend, leaving the main DB untouched.
14
+ */
15
+ import { existsSync } from "node:fs";
16
+ import { tmpdir } from "node:os";
17
+ import { join } from "node:path";
18
+ import { describe, expect, test } from "bun:test";
19
+
20
+ import { removeTestDbFiles } from "../../__tests__/assert-not-live-db.js";
21
+
22
+ const { getSqlite, LOGS_DB_SCHEMA } = await import("../db-connection.js");
23
+ const { initializeDb } = await import("../db-init.js");
24
+ const { runAsyncSqlite } = await import("../db-async-query.js");
25
+ const { getLogsDbPath } = await import("../../util/logs-db-path.js");
26
+ const { findSqlite3 } = await import("../../util/sqlite3-runtime.js");
27
+
28
+ initializeDb();
29
+
30
+ const sqlite3Available = findSqlite3() !== undefined;
31
+
32
+ describe("logs database attachment", () => {
33
+ test("ATTACHes the logs file as the logs schema and creates it on disk", () => {
34
+ // Touch the connection so the attach runs.
35
+ getSqlite();
36
+ expect(existsSync(getLogsDbPath())).toBe(true);
37
+
38
+ const attached = getSqlite()
39
+ .query<{ name: string; file: string }, []>("PRAGMA database_list")
40
+ .all();
41
+ const logsEntry = attached.find((e) => e.name === LOGS_DB_SCHEMA);
42
+ expect(logsEntry).toBeDefined();
43
+ expect(logsEntry?.file).toBe(getLogsDbPath());
44
+ });
45
+
46
+ test("the attached schema runs in WAL mode", () => {
47
+ const mode = getSqlite()
48
+ .query<
49
+ { journal_mode: string },
50
+ []
51
+ >(`PRAGMA ${LOGS_DB_SCHEMA}.journal_mode`)
52
+ .get();
53
+ expect(mode?.journal_mode).toBe("wal");
54
+ });
55
+
56
+ test("a table created in the logs schema lives in the logs file, not main", () => {
57
+ const sqlite = getSqlite();
58
+ sqlite.exec(
59
+ `CREATE TABLE IF NOT EXISTS ${LOGS_DB_SCHEMA}.attach_probe (id INTEGER PRIMARY KEY)`,
60
+ );
61
+ try {
62
+ const inLogs = sqlite
63
+ .query<
64
+ { name: string },
65
+ []
66
+ >(`SELECT name FROM ${LOGS_DB_SCHEMA}.sqlite_master WHERE name = 'attach_probe'`)
67
+ .get();
68
+ expect(inLogs?.name).toBe("attach_probe");
69
+
70
+ const inMain = sqlite
71
+ .query<
72
+ { name: string },
73
+ []
74
+ >(`SELECT name FROM main.sqlite_master WHERE name = 'attach_probe'`)
75
+ .get();
76
+ expect(inMain).toBeNull();
77
+ } finally {
78
+ sqlite.exec(`DROP TABLE ${LOGS_DB_SCHEMA}.attach_probe`);
79
+ }
80
+ });
81
+
82
+ test.if(sqlite3Available)(
83
+ "runAsyncSqlite({ dbPath }) targets the given file, not the main DB",
84
+ async () => {
85
+ const targetPath = join(tmpdir(), `vellum-async-dbpath-${Date.now()}.db`);
86
+ try {
87
+ const result = await runAsyncSqlite(
88
+ "CREATE TABLE dbpath_probe (x INTEGER); INSERT INTO dbpath_probe VALUES (42); SELECT changes();",
89
+ { dbPath: targetPath, forceBackend: "sqlite3-cli" },
90
+ );
91
+ expect(result.ok).toBe(true);
92
+ expect(result.backend).toBe("sqlite3-cli");
93
+
94
+ // The target file got the table…
95
+ const { Database } = await import("bun:sqlite");
96
+ const probe = new Database(targetPath, { readonly: true });
97
+ try {
98
+ const row = probe
99
+ .query<
100
+ { name: string },
101
+ []
102
+ >("SELECT name FROM sqlite_master WHERE name = 'dbpath_probe'")
103
+ .get();
104
+ expect(row?.name).toBe("dbpath_probe");
105
+ } finally {
106
+ probe.close();
107
+ }
108
+
109
+ // …and the main DB did not.
110
+ const inMain = getSqlite()
111
+ .query<
112
+ { name: string },
113
+ []
114
+ >("SELECT name FROM main.sqlite_master WHERE name = 'dbpath_probe'")
115
+ .get();
116
+ expect(inMain).toBeNull();
117
+ } finally {
118
+ removeTestDbFiles(targetPath);
119
+ }
120
+ },
121
+ );
122
+ });
@@ -48,14 +48,12 @@ mock.module("../../config/assistant-feature-flags.js", () => ({
48
48
  isAssistantFeatureFlagEnabled: () => true,
49
49
  }));
50
50
 
51
- // Stub trust resolver — never claim the actor is untrusted in tests.
52
- mock.module("../../runtime/actor-trust-resolver.js", () => ({
53
- isUntrustedTrustClass: () => false,
54
- }));
55
-
56
51
  // Stub the conversation-source lookup so the recursion guards in the
57
52
  // retrospective and auto-analysis paths fall through to the enqueue.
53
+ // `getConversation` returning null keeps `isLowYieldRetrospectiveSource`
54
+ // false, so the retrospective is enqueued rather than skipped.
58
55
  mock.module("../conversation-crud.js", () => ({
56
+ getConversation: () => null,
59
57
  getConversationSource: () => null,
60
58
  reserveMessage: mock(async () => ({ id: "msg-reserve" })),
61
59
  }));
@@ -117,12 +115,10 @@ mock.module("../db-connection.js", () => ({
117
115
 
118
116
  // Now load the real modules under test.
119
117
  const { isMemoryEnabled } = await import("../jobs-store.js");
120
- const { enqueueAutoAnalysisIfEnabled } = await import(
121
- "../auto-analysis-enqueue.js"
122
- );
123
- const { enqueueMemoryRetrospectiveIfEnabled } = await import(
124
- "../memory-retrospective-enqueue.js"
125
- );
118
+ const { enqueueAutoAnalysisIfEnabled } =
119
+ await import("../auto-analysis-enqueue.js");
120
+ const { enqueueMemoryRetrospectiveIfEnabled } =
121
+ await import("../memory-retrospective-enqueue.js");
126
122
 
127
123
  beforeEach(() => {
128
124
  dbInserts.length = 0;