@vellumai/assistant 0.7.3 → 0.8.1

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 (778) hide show
  1. package/AGENTS.md +11 -0
  2. package/ARCHITECTURE.md +29 -28
  3. package/Dockerfile +6 -4
  4. package/README.md +2 -2
  5. package/__tests__/permissions/gateway-threshold-reader.test.ts +236 -9
  6. package/bun.lock +3 -0
  7. package/docker-entrypoint.sh +16 -0
  8. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  9. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  10. package/eslint.config.mjs +12 -0
  11. package/knip.json +3 -1
  12. package/node_modules/@vellumai/ipc-server-utils/bun.lock +24 -0
  13. package/node_modules/@vellumai/ipc-server-utils/package.json +18 -0
  14. package/node_modules/@vellumai/ipc-server-utils/src/index.ts +6 -0
  15. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +430 -0
  16. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +221 -0
  17. package/node_modules/@vellumai/ipc-server-utils/tsconfig.json +20 -0
  18. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  19. package/openapi.yaml +4126 -959
  20. package/package.json +5 -1
  21. package/scripts/generate-openapi.ts +52 -4
  22. package/scripts/sync-llm-catalog.ts +165 -0
  23. package/scripts/sync-web-search-catalog.ts +107 -0
  24. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  25. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  26. package/src/__tests__/annotate-risk-options.test.ts +291 -0
  27. package/src/__tests__/anthropic-provider.test.ts +92 -2
  28. package/src/__tests__/app-control-flow.test.ts +7 -0
  29. package/src/__tests__/approval-cascade.test.ts +8 -16
  30. package/src/__tests__/approval-routes-http.test.ts +6 -0
  31. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  32. package/src/__tests__/auto-analysis-end-to-end.test.ts +12 -25
  33. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  34. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  35. package/src/__tests__/btw-routes.test.ts +1 -0
  36. package/src/__tests__/call-constants.test.ts +10 -1
  37. package/src/__tests__/call-controller.test.ts +127 -0
  38. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  39. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  40. package/src/__tests__/channel-policy.test.ts +12 -0
  41. package/src/__tests__/checker.test.ts +89 -0
  42. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +88 -30
  43. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  44. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  45. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  46. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  47. package/src/__tests__/config-loader-platform-defaults.test.ts +345 -8
  48. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  49. package/src/__tests__/config-schema.test.ts +14 -3
  50. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  51. package/src/__tests__/config-set-route.test.ts +198 -0
  52. package/src/__tests__/config-watcher.test.ts +6 -0
  53. package/src/__tests__/contacts-tools.test.ts +51 -199
  54. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  55. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  56. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  57. package/src/__tests__/context-search-fanout.test.ts +20 -157
  58. package/src/__tests__/context-search-memory-source.test.ts +3 -26
  59. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  60. package/src/__tests__/context-search-types.test.ts +7 -2
  61. package/src/__tests__/context-window-manager.test.ts +389 -1
  62. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -6
  63. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
  64. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
  65. package/src/__tests__/conversation-agent-loop.test.ts +3 -3
  66. package/src/__tests__/conversation-confirmation-signals.test.ts +5 -13
  67. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  68. package/src/__tests__/conversation-error.test.ts +38 -0
  69. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  70. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  71. package/src/__tests__/conversation-init.benchmark.test.ts +2 -1
  72. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  73. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  74. package/src/__tests__/conversation-process-callsite.test.ts +22 -7
  75. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -6
  76. package/src/__tests__/conversation-runtime-assembly.test.ts +19 -10
  77. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  78. package/src/__tests__/conversation-slash-unknown.test.ts +1 -6
  79. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +170 -9
  80. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  81. package/src/__tests__/conversation-surfaces-data-persist.test.ts +73 -1
  82. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +59 -0
  83. package/src/__tests__/conversation-workspace-injection.test.ts +1 -7
  84. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -7
  85. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  86. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  87. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  88. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  89. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  90. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  91. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  92. package/src/__tests__/filing-service.test.ts +25 -22
  93. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  94. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  95. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  96. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +10 -34
  97. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  98. package/src/__tests__/heartbeat-service.test.ts +50 -233
  99. package/src/__tests__/history-repair.test.ts +89 -0
  100. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  101. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  102. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  103. package/src/__tests__/host-browser-routes.test.ts +325 -33
  104. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  105. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  106. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  107. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  108. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  109. package/src/__tests__/injector-chain.test.ts +24 -16
  110. package/src/__tests__/injector-pkb-v2-silenced.test.ts +10 -7
  111. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  112. package/src/__tests__/install-skill-routing.test.ts +2 -2
  113. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +169 -67
  114. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  115. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  116. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  117. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  118. package/src/__tests__/llm-resolver.test.ts +46 -0
  119. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  120. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  121. package/src/__tests__/mcp-cli.test.ts +182 -220
  122. package/src/__tests__/mcp-health-check.test.ts +56 -27
  123. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  124. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  125. package/src/__tests__/notification-decision-fallback.test.ts +91 -0
  126. package/src/__tests__/notification-decision-strategy.test.ts +22 -0
  127. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  128. package/src/__tests__/oauth-cli.test.ts +38 -1888
  129. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  130. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  131. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  132. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  133. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  134. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  135. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  136. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  137. package/src/__tests__/plugin-types.test.ts +13 -11
  138. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  139. package/src/__tests__/profile-entry-status.test.ts +43 -0
  140. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  141. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  142. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  143. package/src/__tests__/relay-server.test.ts +164 -2
  144. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  145. package/src/__tests__/schedule-retry.test.ts +56 -4
  146. package/src/__tests__/schedule-routes.test.ts +104 -0
  147. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  148. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  149. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  150. package/src/__tests__/scheduler-wake.test.ts +0 -63
  151. package/src/__tests__/secret-allowlist.test.ts +1 -0
  152. package/src/__tests__/secret-prompt-log-hygiene.test.ts +7 -5
  153. package/src/__tests__/secret-prompter-channel-fallback.test.ts +7 -5
  154. package/src/__tests__/secret-response-routing.test.ts +7 -5
  155. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  156. package/src/__tests__/server-history-render.test.ts +82 -0
  157. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  158. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  159. package/src/__tests__/skill-include-graph.test.ts +31 -0
  160. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  161. package/src/__tests__/skill-load-tool.test.ts +42 -16
  162. package/src/__tests__/skills.test.ts +39 -0
  163. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  164. package/src/__tests__/suggestion-routes.test.ts +3 -3
  165. package/src/__tests__/sync-message-contract.test.ts +63 -0
  166. package/src/__tests__/task-scheduler.test.ts +88 -23
  167. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -42
  168. package/src/__tests__/tool-executor.test.ts +155 -0
  169. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  170. package/src/__tests__/usage-cli.test.ts +11 -73
  171. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  172. package/src/__tests__/vercel-config.test.ts +168 -0
  173. package/src/__tests__/voice-session-bridge.test.ts +3 -0
  174. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  175. package/src/__tests__/web-search.test.ts +303 -2
  176. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  177. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  178. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +153 -0
  179. package/src/__tests__/workspace-migration-071-remove-safe-storage-release-note.test.ts +206 -0
  180. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  181. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  182. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  183. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  184. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  185. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  186. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  187. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +15 -27
  188. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  189. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  190. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  191. package/src/acp/resolve-agent.test.ts +25 -0
  192. package/src/acp/resolve-agent.ts +13 -2
  193. package/src/acp/session-manager.ts +14 -0
  194. package/src/agent/loop.ts +11 -0
  195. package/src/approvals/guardian-decision-primitive.ts +0 -13
  196. package/src/approvals/guardian-request-resolvers.ts +19 -102
  197. package/src/calls/call-constants.ts +5 -8
  198. package/src/calls/call-controller.ts +130 -67
  199. package/src/calls/relay-server.ts +42 -1
  200. package/src/calls/relay-setup-router.ts +36 -0
  201. package/src/calls/types.ts +1 -0
  202. package/src/calls/voice-session-bridge.ts +24 -5
  203. package/src/channels/config.ts +14 -1
  204. package/src/channels/types.ts +1 -0
  205. package/src/cli/AGENTS.md +164 -4
  206. package/src/cli/__tests__/notifications.test.ts +54 -0
  207. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  208. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  209. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  210. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  211. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  212. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  213. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  214. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  215. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  216. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  217. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  218. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  219. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  220. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  221. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  222. package/src/cli/commands/__tests__/status.test.ts +249 -0
  223. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  224. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  225. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  226. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  227. package/src/cli/commands/attachment.ts +8 -3
  228. package/src/cli/commands/audit.ts +95 -64
  229. package/src/cli/commands/auth.ts +61 -58
  230. package/src/cli/commands/avatar.ts +276 -390
  231. package/src/cli/commands/backup.ts +409 -505
  232. package/src/cli/commands/bash.ts +9 -5
  233. package/src/cli/commands/browser.ts +28 -9
  234. package/src/cli/commands/cache.ts +9 -4
  235. package/src/cli/commands/changelog.ts +414 -0
  236. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  237. package/src/cli/commands/clients.ts +8 -3
  238. package/src/cli/commands/completions.ts +9 -9
  239. package/src/cli/commands/config.ts +102 -72
  240. package/src/cli/commands/contacts.ts +575 -696
  241. package/src/cli/commands/conversations-defer.ts +17 -69
  242. package/src/cli/commands/conversations-import.ts +90 -253
  243. package/src/cli/commands/conversations.ts +346 -436
  244. package/src/cli/commands/credential-execution.ts +9 -6
  245. package/src/cli/commands/credentials.ts +456 -736
  246. package/src/cli/commands/domain.ts +128 -206
  247. package/src/cli/commands/email.ts +606 -794
  248. package/src/cli/commands/gateway.ts +8 -1
  249. package/src/cli/commands/image-generation.ts +157 -205
  250. package/src/cli/commands/inference-providers.ts +352 -0
  251. package/src/cli/commands/inference-session.ts +415 -0
  252. package/src/cli/commands/inference.ts +87 -65
  253. package/src/cli/commands/keys.ts +8 -3
  254. package/src/cli/commands/mcp.ts +103 -287
  255. package/src/cli/commands/memory-v2.ts +163 -517
  256. package/src/cli/commands/notifications.ts +33 -7
  257. package/src/cli/commands/oauth/apps.ts +292 -261
  258. package/src/cli/commands/oauth/connect.ts +182 -345
  259. package/src/cli/commands/oauth/disconnect.ts +16 -215
  260. package/src/cli/commands/oauth/index.ts +49 -45
  261. package/src/cli/commands/oauth/mode.ts +43 -199
  262. package/src/cli/commands/oauth/ping.ts +17 -125
  263. package/src/cli/commands/oauth/providers.ts +732 -921
  264. package/src/cli/commands/oauth/request.ts +60 -350
  265. package/src/cli/commands/oauth/shared.ts +11 -121
  266. package/src/cli/commands/oauth/status.ts +31 -121
  267. package/src/cli/commands/oauth/token.ts +13 -55
  268. package/src/cli/commands/pending.ts +19 -10
  269. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  270. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  271. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  272. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  273. package/src/cli/commands/platform/connect.ts +16 -80
  274. package/src/cli/commands/platform/disconnect.ts +14 -112
  275. package/src/cli/commands/platform/index.ts +177 -246
  276. package/src/cli/commands/routes.ts +153 -336
  277. package/src/cli/commands/sequence.ts +316 -360
  278. package/src/cli/commands/skills.ts +449 -671
  279. package/src/cli/commands/status.ts +58 -37
  280. package/src/cli/commands/stt.ts +94 -262
  281. package/src/cli/commands/task.ts +14 -40
  282. package/src/cli/commands/trust.ts +8 -3
  283. package/src/cli/commands/tts.ts +162 -167
  284. package/src/cli/commands/ui.ts +35 -42
  285. package/src/cli/commands/usage.ts +188 -126
  286. package/src/cli/commands/watchers.ts +8 -3
  287. package/src/cli/commands/webhooks.ts +99 -193
  288. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  289. package/src/cli/lib/daemon-credential-client.ts +4 -5
  290. package/src/cli/lib/nested-value.ts +44 -0
  291. package/src/cli/lib/open-browser.ts +36 -0
  292. package/src/cli/lib/register-command.ts +19 -0
  293. package/src/cli/lib/time-ago.ts +34 -0
  294. package/src/cli/program.ts +2 -4
  295. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  296. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  297. package/src/cli/utils/conversation-id.ts +30 -0
  298. package/src/cli/utils/parse-duration.ts +41 -0
  299. package/src/config/acp-defaults.test.ts +5 -1
  300. package/src/config/acp-defaults.ts +11 -4
  301. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  302. package/src/config/bundled-skills/app-builder/SKILL.md +1 -3
  303. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  304. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  305. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  306. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  307. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  308. package/src/config/bundled-tool-registry.ts +0 -2
  309. package/src/config/feature-flag-registry.json +17 -17
  310. package/src/config/llm-resolver.ts +16 -1
  311. package/src/config/loader.ts +148 -33
  312. package/src/config/raw-config-utils.ts +2 -30
  313. package/src/config/schema.ts +4 -0
  314. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  315. package/src/config/schemas/call-site-catalog.ts +29 -7
  316. package/src/config/schemas/llm-request-logs.ts +57 -0
  317. package/src/config/schemas/llm.ts +52 -2
  318. package/src/config/schemas/memory-retrospective.ts +48 -0
  319. package/src/config/schemas/memory-v2.ts +33 -2
  320. package/src/config/schemas/memory.ts +4 -0
  321. package/src/config/schemas/services.ts +15 -12
  322. package/src/config/seed-inference-profiles.ts +195 -134
  323. package/src/contacts/contact-store.ts +0 -61
  324. package/src/context/window-manager.ts +191 -5
  325. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +111 -0
  326. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  327. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  328. package/src/daemon/approval-generators.ts +23 -29
  329. package/src/daemon/config-watcher.ts +2 -0
  330. package/src/daemon/conversation-agent-loop-handlers.ts +56 -0
  331. package/src/daemon/conversation-agent-loop.ts +140 -107
  332. package/src/daemon/conversation-error.ts +21 -0
  333. package/src/daemon/conversation-lifecycle.ts +68 -13
  334. package/src/daemon/conversation-process.ts +36 -19
  335. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  336. package/src/daemon/conversation-slash.ts +175 -23
  337. package/src/daemon/conversation-store.ts +17 -10
  338. package/src/daemon/conversation-surfaces.ts +92 -26
  339. package/src/daemon/conversation-tool-setup.ts +33 -19
  340. package/src/daemon/conversation.ts +49 -10
  341. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  342. package/src/daemon/guardian-action-generators.ts +7 -22
  343. package/src/daemon/handlers/config-model.ts +8 -126
  344. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  345. package/src/daemon/handlers/config-vercel.ts +3 -1
  346. package/src/daemon/handlers/shared.ts +26 -0
  347. package/src/daemon/handlers/skills.ts +84 -5
  348. package/src/daemon/history-repair.ts +33 -6
  349. package/src/daemon/host-app-control-proxy.ts +44 -19
  350. package/src/daemon/host-bash-proxy.ts +85 -158
  351. package/src/daemon/host-browser-proxy.ts +97 -36
  352. package/src/daemon/host-cu-proxy.ts +1 -1
  353. package/src/daemon/host-file-proxy.ts +1 -1
  354. package/src/daemon/host-proxy-base.ts +13 -1
  355. package/src/daemon/host-proxy-preactivation.ts +25 -1
  356. package/src/daemon/host-transfer-proxy.ts +2 -2
  357. package/src/daemon/identity-helpers.ts +19 -0
  358. package/src/daemon/lifecycle.ts +128 -114
  359. package/src/daemon/meet-host-supervisor.ts +15 -15
  360. package/src/daemon/memory-v2-startup.ts +62 -14
  361. package/src/daemon/message-protocol.ts +6 -0
  362. package/src/daemon/message-types/bookmarks.ts +18 -0
  363. package/src/daemon/message-types/conversations.ts +12 -9
  364. package/src/daemon/message-types/messages.ts +28 -2
  365. package/src/daemon/message-types/sync.ts +60 -0
  366. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  367. package/src/daemon/pkb-reminder-builder.ts +21 -7
  368. package/src/daemon/process-message.ts +56 -23
  369. package/src/daemon/server.ts +23 -18
  370. package/src/daemon/shutdown-handlers.ts +0 -2
  371. package/src/daemon/tool-setup-types.ts +9 -0
  372. package/src/daemon/tool-side-effects.ts +6 -4
  373. package/src/daemon/wake-target-adapter.ts +11 -0
  374. package/src/documents/document-store.ts +35 -1
  375. package/src/export/transcript-formatter.ts +61 -2
  376. package/src/filing/filing-service.ts +42 -56
  377. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  378. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  379. package/src/heartbeat/heartbeat-service.ts +149 -128
  380. package/src/home/__tests__/feed-types.test.ts +63 -131
  381. package/src/home/__tests__/feed-writer.test.ts +77 -278
  382. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  383. package/src/home/feed-types.ts +19 -73
  384. package/src/home/feed-writer.ts +25 -156
  385. package/src/home/post-connect-feed.ts +1 -3
  386. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  387. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  388. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  389. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  390. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  391. package/src/ipc/assistant-server.ts +148 -42
  392. package/src/ipc/cli-client.ts +370 -50
  393. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  394. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  395. package/src/ipc/skill-routes/events.ts +30 -3
  396. package/src/ipc/skill-server.ts +99 -42
  397. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  398. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  399. package/src/live-voice/live-voice-session-manager.ts +11 -4
  400. package/src/live-voice/live-voice-session.ts +14 -6
  401. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  402. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  403. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  404. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  405. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +10 -57
  406. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  407. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  408. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  409. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  410. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  411. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  412. package/src/memory/bookmark-crud.ts +179 -0
  413. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  414. package/src/memory/context-search/agent-protocol.ts +5 -1
  415. package/src/memory/context-search/agent-runner.ts +60 -85
  416. package/src/memory/context-search/limits.ts +1 -4
  417. package/src/memory/context-search/search.ts +23 -113
  418. package/src/memory/context-search/sources/conversations.ts +18 -6
  419. package/src/memory/context-search/sources/memory-v2.ts +40 -31
  420. package/src/memory/context-search/sources/memory.ts +9 -2
  421. package/src/memory/context-search/sources/workspace.ts +13 -10
  422. package/src/memory/context-search/types.ts +1 -1
  423. package/src/memory/conversation-bootstrap.ts +11 -0
  424. package/src/memory/conversation-crud.ts +312 -10
  425. package/src/memory/conversation-queries.ts +9 -5
  426. package/src/memory/conversation-title-service.ts +1 -0
  427. package/src/memory/conversation-types.ts +16 -0
  428. package/src/memory/db-init.ts +14 -0
  429. package/src/memory/embedding-backend.ts +2 -1
  430. package/src/memory/embedding-runtime-manager.ts +1 -2
  431. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +104 -61
  432. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +11 -26
  433. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  434. package/src/memory/graph/conversation-graph-memory.ts +108 -14
  435. package/src/memory/graph/extraction.ts +4 -0
  436. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  437. package/src/memory/graph/graph-search.test.ts +6 -5
  438. package/src/memory/graph/graph-search.ts +3 -4
  439. package/src/memory/graph/retriever.test.ts +12 -7
  440. package/src/memory/graph/retriever.ts +4 -5
  441. package/src/memory/graph/tool-handlers.ts +20 -11
  442. package/src/memory/graph/tools.ts +48 -9
  443. package/src/memory/indexer.ts +18 -2
  444. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +120 -6
  445. package/src/memory/jobs/embed-concept-page.ts +261 -89
  446. package/src/memory/jobs-store.ts +51 -1
  447. package/src/memory/jobs-worker.ts +60 -7
  448. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  449. package/src/memory/llm-request-log-source-local.ts +26 -0
  450. package/src/memory/llm-request-log-source.ts +97 -0
  451. package/src/memory/llm-request-log-store.ts +1 -1
  452. package/src/memory/memory-retrospective-constants.ts +13 -0
  453. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  454. package/src/memory/memory-retrospective-job.ts +351 -0
  455. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  456. package/src/memory/memory-retrospective-state.ts +162 -0
  457. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  458. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  459. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  460. package/src/memory/message-content.ts +38 -1
  461. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  462. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  463. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  464. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  465. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  466. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  467. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  468. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  469. package/src/memory/migrations/243-provider-connections.ts +68 -0
  470. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  471. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  472. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  473. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  474. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  475. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  476. package/src/memory/migrations/index.ts +7 -0
  477. package/src/memory/pkb/pkb-search.test.ts +6 -5
  478. package/src/memory/pkb/pkb-search.ts +4 -5
  479. package/src/memory/published-pages-store.ts +16 -0
  480. package/src/memory/qdrant-client.ts +3 -0
  481. package/src/memory/schema/bookmarks.ts +38 -0
  482. package/src/memory/schema/conversations.ts +2 -0
  483. package/src/memory/schema/index.ts +2 -0
  484. package/src/memory/schema/inference.ts +29 -0
  485. package/src/memory/schema/memory-core.ts +9 -0
  486. package/src/memory/search/semantic.ts +5 -9
  487. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  488. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  489. package/src/memory/v2/__tests__/activation.test.ts +46 -9
  490. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  491. package/src/memory/v2/__tests__/consolidation-job.test.ts +140 -163
  492. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  493. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  494. package/src/memory/v2/__tests__/injection.test.ts +768 -33
  495. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  496. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  497. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  498. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  499. package/src/memory/v2/__tests__/qdrant.test.ts +382 -9
  500. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  501. package/src/memory/v2/__tests__/router.test.ts +516 -0
  502. package/src/memory/v2/__tests__/sim.test.ts +163 -8
  503. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  504. package/src/memory/v2/__tests__/static-context.test.ts +8 -35
  505. package/src/memory/v2/__tests__/sweep-job.test.ts +114 -33
  506. package/src/memory/v2/activation-store.ts +34 -5
  507. package/src/memory/v2/activation.ts +40 -27
  508. package/src/memory/v2/backfill-jobs.ts +17 -84
  509. package/src/memory/v2/consolidation-job.ts +92 -86
  510. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  511. package/src/memory/v2/injection.ts +466 -115
  512. package/src/memory/v2/migration.ts +117 -20
  513. package/src/memory/v2/page-index.ts +191 -0
  514. package/src/memory/v2/page-store.ts +42 -0
  515. package/src/memory/v2/prompts/consolidation.ts +14 -7
  516. package/src/memory/v2/prompts/router.ts +192 -0
  517. package/src/memory/v2/qdrant.ts +307 -133
  518. package/src/memory/v2/reranker.ts +14 -7
  519. package/src/memory/v2/router.ts +322 -0
  520. package/src/memory/v2/sim.ts +88 -34
  521. package/src/memory/v2/skill-store.ts +118 -29
  522. package/src/memory/v2/static-context.ts +20 -17
  523. package/src/memory/v2/sweep-job.ts +127 -102
  524. package/src/memory/v2/types.ts +16 -5
  525. package/src/memory/validation.ts +13 -0
  526. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  527. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  528. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  529. package/src/notifications/adapters/platform.ts +171 -0
  530. package/src/notifications/conversation-pairing.ts +2 -2
  531. package/src/notifications/copy-composer.ts +61 -12
  532. package/src/notifications/decision-engine.ts +46 -0
  533. package/src/notifications/destination-resolver.ts +21 -0
  534. package/src/notifications/emit-signal.ts +28 -1
  535. package/src/notifications/home-feed-side-effect.ts +111 -0
  536. package/src/notifications/signal.ts +5 -0
  537. package/src/permissions/checker.ts +12 -0
  538. package/src/permissions/gateway-threshold-reader.ts +116 -8
  539. package/src/permissions/ipc-risk-types.ts +2 -0
  540. package/src/permissions/prompter.ts +86 -96
  541. package/src/permissions/secret-prompter.ts +31 -31
  542. package/src/plugin-api/index.ts +13 -0
  543. package/src/plugin-api/package.json +12 -0
  544. package/src/plugin-api/types.ts +62 -0
  545. package/src/plugins/defaults/injectors.ts +20 -5
  546. package/src/plugins/external-plugin-loader.ts +294 -0
  547. package/src/plugins/types.ts +46 -30
  548. package/src/plugins/user-loader.ts +64 -41
  549. package/src/proactive-artifact/job.test.ts +63 -8
  550. package/src/proactive-artifact/job.ts +20 -2
  551. package/src/proactive-artifact/message-copy.ts +18 -1
  552. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  553. package/src/proactive-artifact/trigger-state.ts +4 -0
  554. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  555. package/src/prompts/system-prompt.ts +22 -1
  556. package/src/prompts/templates/SOUL.md +13 -28
  557. package/src/prompts/update-bulletin-job.ts +61 -73
  558. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  559. package/src/providers/__tests__/inference.test.ts +288 -0
  560. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  561. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  562. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  563. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  564. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  565. package/src/providers/anthropic/client.ts +95 -26
  566. package/src/providers/call-site-routing.ts +94 -16
  567. package/src/providers/connection-resolution.ts +163 -0
  568. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  569. package/src/providers/inference/adapter-factory.ts +173 -0
  570. package/src/providers/inference/auth.ts +112 -0
  571. package/src/providers/inference/backfill.ts +196 -0
  572. package/src/providers/inference/connections.ts +356 -0
  573. package/src/providers/inference/resolve-auth.ts +65 -0
  574. package/src/providers/model-catalog.ts +104 -6
  575. package/src/providers/openai/responses-provider.ts +4 -2
  576. package/src/providers/provider-env-vars.ts +17 -7
  577. package/src/providers/provider-secret-catalog.ts +49 -30
  578. package/src/providers/provider-send-message.ts +41 -20
  579. package/src/providers/registry.ts +143 -159
  580. package/src/providers/retry.ts +18 -10
  581. package/src/providers/search-provider-catalog.ts +121 -0
  582. package/src/runtime/AGENTS.md +18 -5
  583. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  584. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  585. package/src/runtime/actor-trust-resolver.ts +32 -10
  586. package/src/runtime/agent-wake.ts +35 -6
  587. package/src/runtime/assistant-event-hub.ts +3 -85
  588. package/src/runtime/auth/route-policy.ts +304 -8
  589. package/src/runtime/auth/same-actor.ts +2 -0
  590. package/src/runtime/background-job-runner.ts +339 -0
  591. package/src/runtime/btw-sidechain.ts +1 -0
  592. package/src/runtime/channel-approvals.ts +3 -2
  593. package/src/runtime/guardian-reply-router.ts +0 -10
  594. package/src/runtime/http-router.ts +36 -1
  595. package/src/runtime/http-server.ts +31 -5
  596. package/src/runtime/http-types.ts +2 -0
  597. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  598. package/src/runtime/middleware/request-logger.ts +62 -1
  599. package/src/runtime/pending-interactions.ts +19 -15
  600. package/src/runtime/pre-first-message-gate.ts +83 -0
  601. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  602. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  603. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  604. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  605. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  606. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  607. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  608. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +147 -0
  609. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  610. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  611. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  612. package/src/runtime/routes/acp-routes.ts +10 -8
  613. package/src/runtime/routes/app-management-routes.ts +228 -3
  614. package/src/runtime/routes/approval-routes.ts +7 -21
  615. package/src/runtime/routes/audit-routes.ts +43 -0
  616. package/src/runtime/routes/auth-routes.ts +72 -0
  617. package/src/runtime/routes/avatar-routes.ts +273 -20
  618. package/src/runtime/routes/backup-routes.ts +406 -2
  619. package/src/runtime/routes/bookmark-routes.ts +154 -0
  620. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  621. package/src/runtime/routes/consolidation-routes.ts +8 -9
  622. package/src/runtime/routes/contact-routes.ts +0 -160
  623. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  624. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  625. package/src/runtime/routes/conversation-query-routes.ts +373 -82
  626. package/src/runtime/routes/conversation-routes.ts +31 -10
  627. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  628. package/src/runtime/routes/credential-routes.ts +540 -0
  629. package/src/runtime/routes/debug-bash-routes.ts +2 -0
  630. package/src/runtime/routes/debug-routes.ts +2 -2
  631. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  632. package/src/runtime/routes/domain-routes.ts +167 -0
  633. package/src/runtime/routes/email-routes.ts +603 -0
  634. package/src/runtime/routes/errors.ts +2 -2
  635. package/src/runtime/routes/events-routes.ts +192 -0
  636. package/src/runtime/routes/filing-routes.ts +2 -3
  637. package/src/runtime/routes/home-feed-routes.ts +6 -78
  638. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  639. package/src/runtime/routes/host-browser-routes.ts +103 -22
  640. package/src/runtime/routes/http-adapter.ts +2 -0
  641. package/src/runtime/routes/identity-routes.ts +5 -0
  642. package/src/runtime/routes/image-generation-routes.ts +99 -0
  643. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  644. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  645. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  646. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -7
  647. package/src/runtime/routes/index.ts +36 -0
  648. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  649. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  650. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  651. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  652. package/src/runtime/routes/inference-send-routes.ts +115 -0
  653. package/src/runtime/routes/integrations/twilio.ts +1 -0
  654. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  655. package/src/runtime/routes/memory-item-routes.test.ts +3 -9
  656. package/src/runtime/routes/memory-item-routes.ts +5 -6
  657. package/src/runtime/routes/memory-v2-routes.ts +105 -404
  658. package/src/runtime/routes/notification-routes.ts +2 -0
  659. package/src/runtime/routes/oauth-apps.ts +112 -7
  660. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  661. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  662. package/src/runtime/routes/oauth-providers.ts +298 -8
  663. package/src/runtime/routes/platform-routes.ts +336 -0
  664. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  665. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  666. package/src/runtime/routes/playground/state.ts +2 -1
  667. package/src/runtime/routes/publish-routes.ts +221 -0
  668. package/src/runtime/routes/schedule-routes.ts +82 -0
  669. package/src/runtime/routes/sequence-routes.ts +291 -0
  670. package/src/runtime/routes/settings-routes.ts +2 -10
  671. package/src/runtime/routes/skills-routes.ts +31 -1
  672. package/src/runtime/routes/stt-routes.ts +240 -3
  673. package/src/runtime/routes/surface-action-routes.ts +43 -7
  674. package/src/runtime/routes/tts-routes.ts +67 -0
  675. package/src/runtime/routes/types.ts +32 -0
  676. package/src/runtime/routes/user-routes-cli.ts +243 -0
  677. package/src/runtime/routes/webhook-routes.ts +165 -0
  678. package/src/runtime/sync/resource-sync-events.ts +25 -0
  679. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  680. package/src/runtime/sync/sync-publisher.ts +21 -0
  681. package/src/schedule/scheduler.ts +200 -123
  682. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  683. package/src/security/secret-patterns.ts +3 -0
  684. package/src/sequence/engine.ts +38 -40
  685. package/src/skills/include-graph.ts +35 -13
  686. package/src/subagent/manager.ts +20 -15
  687. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  688. package/src/tools/browser/browser-execution.ts +15 -4
  689. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  690. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  691. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  692. package/src/tools/browser/cdp-client/factory.ts +66 -5
  693. package/src/tools/browser/runtime-check.ts +77 -0
  694. package/src/tools/document/document-tool.ts +20 -0
  695. package/src/tools/executor.ts +18 -2
  696. package/src/tools/memory/register.test.ts +10 -8
  697. package/src/tools/memory/register.ts +9 -1
  698. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  699. package/src/tools/network/web-search.ts +280 -37
  700. package/src/tools/permission-checker.ts +28 -5
  701. package/src/tools/skills/load.ts +24 -20
  702. package/src/tools/subagent/spawn.ts +3 -3
  703. package/src/tools/terminal/shell.ts +44 -0
  704. package/src/tools/tool-name-aliases.ts +19 -0
  705. package/src/tools/types.ts +19 -1
  706. package/src/usage/attribution.ts +3 -2
  707. package/src/util/pricing.ts +86 -160
  708. package/src/watcher/__tests__/engine.test.ts +301 -0
  709. package/src/watcher/constants.ts +7 -0
  710. package/src/watcher/engine.ts +90 -90
  711. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  712. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  713. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  714. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +4 -62
  715. package/src/workspace/migrations/069-seed-onboarding-threads.ts +34 -0
  716. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +31 -0
  717. package/src/workspace/migrations/071-remove-safe-storage-release-note.ts +111 -0
  718. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  719. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  720. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  721. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  722. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  723. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  724. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  725. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  726. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  727. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  728. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  729. package/src/workspace/migrations/registry.ts +28 -0
  730. package/src/workspace/migrations/runner.ts +13 -2
  731. package/src/workspace/migrations/types.ts +13 -3
  732. package/src/workspace/provider-commit-message-generator.ts +3 -2
  733. package/src/__tests__/context-search-pkb-source.test.ts +0 -492
  734. package/src/__tests__/credentials-cli.test.ts +0 -1225
  735. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  736. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  737. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  738. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  739. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  740. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  741. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  742. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  743. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  744. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  745. package/src/cli/commands/autonomy.ts +0 -365
  746. package/src/cli/commands/memory.ts +0 -424
  747. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -1201
  748. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  749. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  750. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  751. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  752. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  753. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  754. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  755. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  756. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  757. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  758. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  759. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  760. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  761. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  762. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  763. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  764. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  765. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  766. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  767. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  768. package/src/home/assistant-feed-authoring.ts +0 -135
  769. package/src/home/emit-feed-event.ts +0 -169
  770. package/src/home/feed-scheduler.ts +0 -281
  771. package/src/home/platform-gmail-digest.ts +0 -163
  772. package/src/home/rewrite-command-preview.ts +0 -66
  773. package/src/home/rewrite-feed-title.ts +0 -58
  774. package/src/home/rollup-producer.ts +0 -426
  775. package/src/memory/admin.ts +0 -326
  776. package/src/memory/context-search/sources/pkb.ts +0 -477
  777. package/src/memory/graph/compaction.ts +0 -299
  778. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -136,7 +136,11 @@ class MockQdrantClient {
136
136
  limit: params.limit,
137
137
  filter: params.filter,
138
138
  });
139
- const channel = params.using as "dense" | "sparse";
139
+ // Both `dense` and `summary_dense` consume from the dense queue (and
140
+ // similarly for sparse). The four-channel hybrid query fires them in
141
+ // order: body-dense, body-sparse, summary-dense, summary-sparse — so
142
+ // the queue order matches the call order.
143
+ const channel = params.using.endsWith("sparse") ? "sparse" : "dense";
140
144
  return state.queryResponses[channel].shift() ?? { points: [] };
141
145
  }
142
146
  }
@@ -185,10 +189,18 @@ function configWithWeights(
185
189
  /**
186
190
  * Stage a single Qdrant response that maps each (slug, denseScore?, sparseScore?)
187
191
  * tuple onto the dense or sparse channel, mirroring how `hybridQueryConceptPages`
188
- * merges per-channel hits.
192
+ * merges per-channel hits. Optional `summaryDenseScore` / `summarySparseScore`
193
+ * stage the summary-side channels — pages without those entries fall through
194
+ * to body-only scoring at fusion time.
189
195
  */
190
196
  function stageHybridResponse(
191
- hits: Array<{ slug: string; denseScore?: number; sparseScore?: number }>,
197
+ hits: Array<{
198
+ slug: string;
199
+ denseScore?: number;
200
+ sparseScore?: number;
201
+ summaryDenseScore?: number;
202
+ summarySparseScore?: number;
203
+ }>,
192
204
  ): void {
193
205
  state.queryResponses.dense.push({
194
206
  points: hits
@@ -200,6 +212,20 @@ function stageHybridResponse(
200
212
  .filter((h) => h.sparseScore !== undefined)
201
213
  .map((h) => ({ score: h.sparseScore, payload: { slug: h.slug } })),
202
214
  });
215
+ // The four-channel hybrid query also fires `summary_dense` and
216
+ // `summary_sparse` queries against the same collection. Tests that don't
217
+ // care about summary scores leave those channels empty so the fallback
218
+ // (body-only) path runs.
219
+ state.queryResponses.dense.push({
220
+ points: hits
221
+ .filter((h) => h.summaryDenseScore !== undefined)
222
+ .map((h) => ({ score: h.summaryDenseScore, payload: { slug: h.slug } })),
223
+ });
224
+ state.queryResponses.sparse.push({
225
+ points: hits
226
+ .filter((h) => h.summarySparseScore !== undefined)
227
+ .map((h) => ({ score: h.summarySparseScore, payload: { slug: h.slug } })),
228
+ });
203
229
  }
204
230
 
205
231
  beforeEach(resetState);
@@ -407,7 +433,7 @@ describe("simBatch", () => {
407
433
 
408
434
  const out = await simBatch("query", ["dense-only-page"], config);
409
435
 
410
- // 0.7 * 0.5 + 0.3 * 0 = 0.35
436
+ // cosine 0.5 (positive, passes through); 0.7 * 0.5 + 0.3 * 0 = 0.35
411
437
  expect(out.get("dense-only-page")).toBeCloseTo(0.35, 6);
412
438
  });
413
439
 
@@ -449,6 +475,7 @@ describe("simBatch", () => {
449
475
 
450
476
  const out = await simBatch("query", ["alice", "bob"], config);
451
477
 
478
+ // Positive cosines pass through unchanged.
452
479
  // alice: 0.4 * 0.5 + 0.6 * 1.0 = 0.8
453
480
  // bob: 0.4 * 0.25 + 0.6 * 0.5 = 0.4
454
481
  expect(out.get("alice")).toBeCloseTo(0.8, 6);
@@ -468,15 +495,16 @@ describe("simBatch", () => {
468
495
  expect(out.get("loud-page")).toBe(1);
469
496
  });
470
497
 
471
- test("forwards the candidate slugs as a Qdrant slug-IN filter", async () => {
498
+ test("forwards the candidate slugs as a Qdrant slug-IN filter on every channel", async () => {
472
499
  const config = configWithWeights(0.7, 0.3);
473
500
  stageHybridResponse([]);
474
501
 
475
502
  await simBatch("query", ["alice", "bob", "carol"], config);
476
503
 
477
- // Both channels (dense + sparse) ran with the same slug-restriction
478
- // filter and the same per-channel limit equal to the candidate count.
479
- expect(state.queryCalls).toHaveLength(2);
504
+ // All four channels (body dense + sparse, summary dense + sparse) ran
505
+ // with the same slug-restriction filter and the same per-channel limit
506
+ // equal to the candidate count.
507
+ expect(state.queryCalls).toHaveLength(4);
480
508
  for (const call of state.queryCalls) {
481
509
  expect(call.limit).toBe(3);
482
510
  expect(call.filter).toEqual({
@@ -496,6 +524,133 @@ describe("simBatch", () => {
496
524
  expect(state.sparseCalls).toEqual(["hello world"]);
497
525
  });
498
526
 
527
+ test("takes max(body, summary) per slug — summary higher than body wins", async () => {
528
+ // Body channels return a modest score; summary channels return a much
529
+ // higher score. The max collapses to the summary score.
530
+ const config = configWithWeights(1.0, 0.0);
531
+ stageHybridResponse([
532
+ {
533
+ slug: "alice",
534
+ denseScore: 0.3,
535
+ summaryDenseScore: 0.7,
536
+ },
537
+ ]);
538
+
539
+ const out = await simBatch("query", ["alice"], config);
540
+
541
+ // Positive cosines pass through unchanged: max(0.3, 0.7) = 0.7.
542
+ expect(out.get("alice")).toBeCloseTo(0.7, 6);
543
+ });
544
+
545
+ test("takes max(body, summary) per slug — body higher than summary wins", async () => {
546
+ // Inverse case: body dominates, max stays at body.
547
+ const config = configWithWeights(1.0, 0.0);
548
+ stageHybridResponse([
549
+ {
550
+ slug: "alice",
551
+ denseScore: 0.9,
552
+ summaryDenseScore: 0.4,
553
+ },
554
+ ]);
555
+
556
+ const out = await simBatch("query", ["alice"], config);
557
+
558
+ // Positive cosines pass through unchanged: max(0.9, 0.4) = 0.9.
559
+ expect(out.get("alice")).toBeCloseTo(0.9, 6);
560
+ });
561
+
562
+ test("falls back to body-only when the page has no summary embedding", async () => {
563
+ // Pages predating the summary field have no summary_dense/sparse vectors.
564
+ // Their summary channels return no hits — the max collapses to body.
565
+ const config = configWithWeights(1.0, 0.0);
566
+ stageHybridResponse([
567
+ {
568
+ slug: "legacy-page",
569
+ denseScore: 0.6,
570
+ // summaryDenseScore / summarySparseScore omitted
571
+ },
572
+ ]);
573
+
574
+ const out = await simBatch("query", ["legacy-page"], config);
575
+
576
+ // Positive cosine 0.6 passes through unchanged.
577
+ expect(out.get("legacy-page")).toBeCloseTo(0.6, 6);
578
+ });
579
+
580
+ test("normalizes body and summary sparse channels independently", async () => {
581
+ // Summary sparse scores live on a different scale than body sparse —
582
+ // a small absolute summary-sparse value (1.5) on the only page that
583
+ // has summary signal still normalizes to 1.0 within the summary
584
+ // channel, so the summary-only fused score should win out.
585
+ const config = configWithWeights(0.0, 1.0);
586
+ stageHybridResponse([
587
+ {
588
+ slug: "alice",
589
+ denseScore: 0.0,
590
+ sparseScore: 100, // body sparse max in this batch
591
+ },
592
+ {
593
+ slug: "bob",
594
+ denseScore: 0.0,
595
+ sparseScore: 0.5, // body sparse normalized = 0.005
596
+ summaryDenseScore: 0.0,
597
+ summarySparseScore: 1.5, // summary sparse max in this batch
598
+ },
599
+ ]);
600
+
601
+ const out = await simBatch("query", ["alice", "bob"], config);
602
+
603
+ // Alice has only body. Body sparse normalized to 1.0; sparse_weight=1.0 → 1.0.
604
+ expect(out.get("alice")).toBeCloseTo(1.0, 6);
605
+ // Bob's summary side normalizes its 1.5 (only sparse-bearing summary
606
+ // hit) — a single sparse-bearing hit is below the adaptive-spread
607
+ // floor, so the channel collapses to base weights and the lone
608
+ // sparseNormalized=1.0 hit yields a fused summary score of 1.0.
609
+ // Body side has only bob's tiny sparse=0.5 against the body batch max
610
+ // of 100 → ~0.005. The max picks the summary side.
611
+ expect(out.get("bob")).toBeCloseTo(1.0, 6);
612
+ });
613
+
614
+ test("dense-favored config keeps the dense-strong candidate above the sparse-strong one", async () => {
615
+ // Regression guard: an earlier fix mapped cosines into [0, 1] via
616
+ // `(cos + 1) / 2` before fusion, which halved every pairwise dense
617
+ // difference and silently shifted ranking toward sparse. With dense
618
+ // weighted higher than sparse, the dense-only hit must outrank the
619
+ // sparse-only hit even though sparse normalizes to 1.0.
620
+ const config = configWithWeights(0.7, 0.3);
621
+ stageHybridResponse([
622
+ { slug: "dense-strong", denseScore: 0.5 /* sparseScore omitted */ },
623
+ { slug: "sparse-strong", denseScore: 0.0, sparseScore: 1 },
624
+ ]);
625
+
626
+ const out = await simBatch(
627
+ "query",
628
+ ["dense-strong", "sparse-strong"],
629
+ config,
630
+ );
631
+
632
+ // dense-strong: 0.7 * max(0, 0.5) + 0.3 * 0 = 0.35
633
+ // sparse-strong: 0.7 * max(0, 0.0) + 0.3 * 1.0 = 0.30
634
+ expect(out.get("dense-strong")).toBeCloseTo(0.35, 6);
635
+ expect(out.get("sparse-strong")).toBeCloseTo(0.3, 6);
636
+ expect(out.get("dense-strong")!).toBeGreaterThan(out.get("sparse-strong")!);
637
+ });
638
+
639
+ test("negative cosine maps to a non-negative dense contribution", async () => {
640
+ // Qdrant cosine search returns scores in [-1, 1]. A near-zero or
641
+ // negative cosine must not yield a negative dense contribution that
642
+ // depresses the fused score below the sparse-only floor.
643
+ const config = configWithWeights(0.7, 0.3);
644
+ stageHybridResponse([
645
+ { slug: "anti-match", denseScore: -1.0, sparseScore: 1 },
646
+ ]);
647
+
648
+ const out = await simBatch("query", ["anti-match"], config);
649
+
650
+ // cosine -1 → clamped to 0; sparse-norm = 1.0; fused = 0.7*0 + 0.3*1 = 0.3.
651
+ expect(out.get("anti-match")).toBeCloseTo(0.3, 6);
652
+ });
653
+
499
654
  test("returned scores are always in [0, 1] for arbitrary inputs", async () => {
500
655
  const config = configWithWeights(0.7, 0.3);
501
656
  stageHybridResponse([
@@ -39,11 +39,13 @@ interface UpsertCall {
39
39
  dense: number[];
40
40
  sparse: { indices: number[]; values: number[] };
41
41
  updatedAt: number;
42
+ kind?: string;
42
43
  }
43
44
 
44
45
  interface PruneCall {
45
46
  prefix: string;
46
47
  activeSuffixes: readonly string[];
48
+ options?: { kind?: string };
47
49
  }
48
50
 
49
51
  interface TestState {
@@ -118,8 +120,9 @@ mock.module("../qdrant.js", () => ({
118
120
  pruneSlugsWithPrefixExcept: async (
119
121
  prefix: string,
120
122
  activeSuffixes: readonly string[],
123
+ options?: { kind?: string },
121
124
  ) => {
122
- state.pruneCalls.push({ prefix, activeSuffixes });
125
+ state.pruneCalls.push({ prefix, activeSuffixes, options });
123
126
  },
124
127
  }));
125
128
 
@@ -131,8 +134,12 @@ mock.module("../../../skills/catalog-cache.js", () => ({
131
134
  }));
132
135
 
133
136
  // Imported AFTER all mocks are wired so the module under test sees the stubs.
134
- const { seedV2SkillEntries, getSkillCapability, _resetSkillStoreForTests } =
135
- await import("../skill-store.js");
137
+ const {
138
+ seedV2SkillEntries,
139
+ getSkillCapability,
140
+ listSkillEntries,
141
+ _resetSkillStoreForTests,
142
+ } = await import("../skill-store.js");
136
143
 
137
144
  // ---------------------------------------------------------------------------
138
145
  // Helpers
@@ -467,3 +474,51 @@ describe("getSkillCapability", () => {
467
474
  expect(getSkillCapability("does-not-exist")).toBeNull();
468
475
  });
469
476
  });
477
+
478
+ describe("listSkillEntries", () => {
479
+ test("returns [] when the cache is empty (pre-seed)", () => {
480
+ expect(listSkillEntries()).toEqual([]);
481
+ });
482
+
483
+ test("returns entries sorted by id after seeding", async () => {
484
+ // Insert in non-sorted order to prove the sort happens on read.
485
+ const skillB = makeSummary({ id: "example-skill-b" });
486
+ const skillA = makeSummary({ id: "example-skill-a" });
487
+ state.catalog = [skillB, skillA];
488
+ state.resolved = [
489
+ { summary: skillB, state: "enabled" },
490
+ { summary: skillA, state: "enabled" },
491
+ ];
492
+ state.embedReturn = [
493
+ [0.1, 0.2, 0.3],
494
+ [0.4, 0.5, 0.6],
495
+ ];
496
+
497
+ await seedV2SkillEntries();
498
+
499
+ const list = listSkillEntries();
500
+ expect(list).toHaveLength(2);
501
+ expect(list.map((e) => e.id)).toEqual([
502
+ "example-skill-a",
503
+ "example-skill-b",
504
+ ]);
505
+ });
506
+
507
+ test("mutating the returned array does not affect subsequent calls", async () => {
508
+ const skillA = makeSummary({ id: "example-skill-a" });
509
+ state.catalog = [skillA];
510
+ state.resolved = [{ summary: skillA, state: "enabled" }];
511
+ state.embedReturn = [[0.1, 0.2, 0.3]];
512
+
513
+ await seedV2SkillEntries();
514
+
515
+ const first = listSkillEntries();
516
+ expect(first).toHaveLength(1);
517
+ first.length = 0;
518
+ first.push({ id: "injected", content: "junk" });
519
+
520
+ const second = listSkillEntries();
521
+ expect(second).toHaveLength(1);
522
+ expect(second[0].id).toBe("example-skill-a");
523
+ });
524
+ });
@@ -1,8 +1,6 @@
1
1
  /**
2
2
  * Tests for `readMemoryV2StaticContent` — the loader that powers the
3
- * `memory-v2-static` user-message auto-injection. Mirrors the coverage that
4
- * lived in the deprecated `system-prompt-memory-v2.test.ts`:
5
- * - Returns null when the v2 flag is off.
3
+ * `memory-v2-static` user-message auto-injection.
6
4
  * - Returns null when `config.memory.v2.enabled` is off.
7
5
  * - Reads the four files in canonical order and joins them under headings.
8
6
  * - Skips empty / missing files.
@@ -47,9 +45,7 @@ mock.module("../../../config/loader.js", () => ({
47
45
  setNestedValue: () => {},
48
46
  }));
49
47
 
50
- const { _setOverridesForTesting } =
51
- await import("../../../config/assistant-feature-flags.js");
52
- const { readMemoryV2StaticContent, shouldLoadMemoryV2Static } =
48
+ const { readMemoryV2StaticContent, shouldExposePersonalMemory } =
53
49
  await import("../static-context.js");
54
50
 
55
51
  const MEMORY_FILES = [
@@ -75,18 +71,10 @@ describe("readMemoryV2StaticContent", () => {
75
71
  beforeEach(() => {
76
72
  mkdirSync(TEST_DIR, { recursive: true });
77
73
  configMemoryV2Enabled = true;
78
- _setOverridesForTesting({ "memory-v2-enabled": true });
79
74
  });
80
75
 
81
76
  afterEach(() => {
82
77
  cleanupMemoryDir();
83
- _setOverridesForTesting({});
84
- });
85
-
86
- test("returns null when the feature flag is off", () => {
87
- _setOverridesForTesting({ "memory-v2-enabled": false });
88
- for (const file of MEMORY_FILES) writeMemoryFile(file, `Content ${file}`);
89
- expect(readMemoryV2StaticContent()).toBeNull();
90
78
  });
91
79
 
92
80
  test("returns null when config.memory.v2.enabled is off", () => {
@@ -152,21 +140,10 @@ describe("readMemoryV2StaticContent", () => {
152
140
  });
153
141
  });
154
142
 
155
- describe("shouldLoadMemoryV2Static", () => {
156
- test("blocks all turns until the cadence gate fires", () => {
157
- expect(
158
- shouldLoadMemoryV2Static({
159
- shouldInjectNowAndPkb: false,
160
- sourceChannel: "vellum",
161
- isTrustedActor: true,
162
- }),
163
- ).toBe(false);
164
- });
165
-
143
+ describe("shouldExposePersonalMemory", () => {
166
144
  test("allows guardian-trusted local conversations", () => {
167
145
  expect(
168
- shouldLoadMemoryV2Static({
169
- shouldInjectNowAndPkb: true,
146
+ shouldExposePersonalMemory({
170
147
  sourceChannel: "vellum",
171
148
  isTrustedActor: true,
172
149
  }),
@@ -175,8 +152,7 @@ describe("shouldLoadMemoryV2Static", () => {
175
152
 
176
153
  test("allows local-channel conversations even when trust class is unknown (analyze runs, dev)", () => {
177
154
  expect(
178
- shouldLoadMemoryV2Static({
179
- shouldInjectNowAndPkb: true,
155
+ shouldExposePersonalMemory({
180
156
  sourceChannel: "vellum",
181
157
  isTrustedActor: false,
182
158
  }),
@@ -185,8 +161,7 @@ describe("shouldLoadMemoryV2Static", () => {
185
161
 
186
162
  test("allows turns with no trust context (work-item task runs, internal background)", () => {
187
163
  expect(
188
- shouldLoadMemoryV2Static({
189
- shouldInjectNowAndPkb: true,
164
+ shouldExposePersonalMemory({
190
165
  sourceChannel: undefined,
191
166
  isTrustedActor: false,
192
167
  }),
@@ -204,8 +179,7 @@ describe("shouldLoadMemoryV2Static", () => {
204
179
  test("allows guardian-trusted remote channels (user's own phone/Slack)", () => {
205
180
  for (const channel of REMOTE_CHANNELS) {
206
181
  expect(
207
- shouldLoadMemoryV2Static({
208
- shouldInjectNowAndPkb: true,
182
+ shouldExposePersonalMemory({
209
183
  sourceChannel: channel,
210
184
  isTrustedActor: true,
211
185
  }),
@@ -216,8 +190,7 @@ describe("shouldLoadMemoryV2Static", () => {
216
190
  test("blocks non-guardian remote-channel actors (the leak this gate exists to prevent)", () => {
217
191
  for (const channel of REMOTE_CHANNELS) {
218
192
  expect(
219
- shouldLoadMemoryV2Static({
220
- shouldInjectNowAndPkb: true,
193
+ shouldExposePersonalMemory({
221
194
  sourceChannel: channel,
222
195
  isTrustedActor: false,
223
196
  }),
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * Tests for `assistant/src/memory/v2/sweep-job.ts`.
3
3
  *
4
- * Coverage matrix (from PR 18 acceptance criteria):
5
- * - Flag off → no provider/DB calls, returns 0 (early bail).
6
- * - Flag on + no recent messages → no provider call, returns 0.
7
- * - Flag on + recent messages → provider invoked with rendered prompt;
4
+ * Coverage matrix:
5
+ * - v2 disabled in config → no provider/DB calls, returns 0 (early bail).
6
+ * - sweep_enabled off → no provider call, returns 0.
7
+ * - v2 on + no recent messages → no provider call, returns 0.
8
+ * - v2 on + recent messages → provider invoked with rendered prompt;
8
9
  * each entry is appended to `memory/buffer.md` AND today's archive.
9
10
  * - Tool-call response shape mismatch → returns 0 without writes.
10
11
  * - Empty entries are skipped (the model can't pad the buffer).
@@ -24,7 +25,6 @@ import { tmpdir } from "node:os";
24
25
  import { join } from "node:path";
25
26
  import {
26
27
  afterAll,
27
- afterEach,
28
28
  beforeAll,
29
29
  beforeEach,
30
30
  describe,
@@ -62,6 +62,23 @@ mock.module("../../../providers/provider-send-message.js", () => ({
62
62
  response.content.find((b): b is ToolUseContent => b.type === "tool_use"),
63
63
  }));
64
64
 
65
+ // emitNotificationSignal spy — captures every notification the sweep emits
66
+ // so the failure-path test can assert on `activity.failed` shape and dedupe.
67
+ const emitCalls: Array<Record<string, unknown>> = [];
68
+
69
+ mock.module("../../../notifications/emit-signal.js", () => ({
70
+ emitNotificationSignal: async (params: Record<string, unknown>) => {
71
+ emitCalls.push(params);
72
+ return {
73
+ signalId: "sig-1",
74
+ deduplicated: false,
75
+ dispatched: true,
76
+ reason: "ok",
77
+ deliveryResults: [],
78
+ };
79
+ },
80
+ }));
81
+
65
82
  // Workspace setup — temp dir per test run, pinned via VELLUM_WORKSPACE_DIR
66
83
  // so `getWorkspaceDir()` resolves to the tmpdir.
67
84
  let tmpWorkspace: string;
@@ -85,23 +102,20 @@ afterAll(() => {
85
102
  const { resetDb, getDb } = await import("../../db-connection.js");
86
103
  const { initializeDb } = await import("../../db-init.js");
87
104
  const { messages, conversations } = await import("../../schema.js");
88
- const { _setOverridesForTesting } =
89
- await import("../../../config/assistant-feature-flags.js");
90
105
  const { memoryV2SweepJob } = await import("../sweep-job.js");
91
106
 
92
- // `isAssistantFeatureFlagEnabled` ignores the `config` argument it receives
93
- // (resolution is purely from the overrides + registry caches), so we hand
94
- // the handler a minimal stand-in instead of materializing the full default
107
+ // The handler reads `config.memory.v2.enabled` and `sweep_enabled`, so we
108
+ // hand it a minimal stand-in instead of materializing the full default
95
109
  // config — which would otherwise pull in heavy schemas this test doesn't
96
- // exercise. The handler reads `config.memory.v2.sweep_enabled`, so the
97
- // `flag on` cases need the field set; the `flag off` case bails before
98
- // the check and uses the bare empty stand-in.
110
+ // exercise.
99
111
  const CONFIG = {
100
- memory: { v2: { sweep_enabled: true } },
112
+ memory: { v2: { enabled: true, sweep_enabled: true } },
113
+ } as Parameters<typeof memoryV2SweepJob>[1];
114
+ const CONFIG_V2_OFF = {
115
+ memory: { v2: { enabled: false, sweep_enabled: true } },
101
116
  } as Parameters<typeof memoryV2SweepJob>[1];
102
- const CONFIG_FLAG_OFF = {} as Parameters<typeof memoryV2SweepJob>[1];
103
117
  const CONFIG_SWEEP_OFF = {
104
- memory: { v2: { sweep_enabled: false } },
118
+ memory: { v2: { enabled: true, sweep_enabled: false } },
105
119
  } as Parameters<typeof memoryV2SweepJob>[1];
106
120
 
107
121
  function makeJob(): Parameters<typeof memoryV2SweepJob>[0] {
@@ -169,6 +183,7 @@ function extractFirstUserText(msgs: { content: unknown }[]): string {
169
183
  function seedMessages(
170
184
  conversationId: string,
171
185
  rows: Array<{ role: string; content: string; offsetMs: number }>,
186
+ conversationType: "standard" | "background" | "scheduled" = "standard",
172
187
  ): void {
173
188
  const db = getDb();
174
189
  const now = Date.now();
@@ -178,6 +193,7 @@ function seedMessages(
178
193
  title: null,
179
194
  createdAt: now - 60_000,
180
195
  updatedAt: now,
196
+ conversationType,
181
197
  })
182
198
  .run();
183
199
  for (let i = 0; i < rows.length; i++) {
@@ -203,20 +219,16 @@ beforeEach(() => {
203
219
  mkdirSync(join(tmpWorkspace, "memory"), { recursive: true });
204
220
  providerCalls.length = 0;
205
221
  providerStub = null;
206
- });
207
-
208
- afterEach(() => {
209
- _setOverridesForTesting({});
222
+ emitCalls.length = 0;
210
223
  });
211
224
 
212
225
  // ---------------------------------------------------------------------------
213
226
 
214
- describe("memoryV2SweepJob — flag off", () => {
215
- test("returns 0 without invoking the provider when flag is off", async () => {
216
- _setOverridesForTesting({ "memory-v2-enabled": false });
227
+ describe("memoryV2SweepJob — v2 disabled", () => {
228
+ test("returns 0 without invoking the provider when memory.v2.enabled is false", async () => {
217
229
  providerStub = makeEntriesProvider(["should-not-be-written"]);
218
230
 
219
- const written = await memoryV2SweepJob(makeJob(), CONFIG_FLAG_OFF);
231
+ const written = await memoryV2SweepJob(makeJob(), CONFIG_V2_OFF);
220
232
 
221
233
  expect(written).toBe(0);
222
234
  expect(providerCalls).toHaveLength(0);
@@ -224,9 +236,8 @@ describe("memoryV2SweepJob — flag off", () => {
224
236
  });
225
237
  });
226
238
 
227
- describe("memoryV2SweepJob — flag on, sweep_enabled off", () => {
239
+ describe("memoryV2SweepJob — sweep_enabled off", () => {
228
240
  test("returns 0 without invoking the provider when sweep_enabled is false", async () => {
229
- _setOverridesForTesting({ "memory-v2-enabled": true });
230
241
  // No message seeding required — the sweep_enabled bail short-circuits
231
242
  // before any DB or workspace reads.
232
243
  providerStub = makeEntriesProvider(["should-not-be-written"]);
@@ -239,11 +250,7 @@ describe("memoryV2SweepJob — flag on, sweep_enabled off", () => {
239
250
  });
240
251
  });
241
252
 
242
- describe("memoryV2SweepJob — flag on, no recent messages", () => {
243
- beforeEach(() => {
244
- _setOverridesForTesting({ "memory-v2-enabled": true });
245
- });
246
-
253
+ describe("memoryV2SweepJob — no recent messages", () => {
247
254
  test("returns 0 when no messages exist in the recent window", async () => {
248
255
  providerStub = makeEntriesProvider(["should-not-be-written"]);
249
256
 
@@ -273,9 +280,8 @@ describe("memoryV2SweepJob — flag on, no recent messages", () => {
273
280
  // DB intact long enough for the SQL inserts here to clash.
274
281
  let convCounter = 0;
275
282
 
276
- describe("memoryV2SweepJob — flag on, recent messages", () => {
283
+ describe("memoryV2SweepJob — recent messages", () => {
277
284
  beforeEach(() => {
278
- _setOverridesForTesting({ "memory-v2-enabled": true });
279
285
  seedMessages(`conv-${++convCounter}`, [
280
286
  {
281
287
  role: "user",
@@ -431,6 +437,81 @@ describe("memoryV2SweepJob — flag on, recent messages", () => {
431
437
 
432
438
  expect(written).toBe(0);
433
439
  });
440
+
441
+ test("emits an activity.failed notification when provider.sendMessage throws", async () => {
442
+ // Simulate a transient provider failure once we're past the early
443
+ // bail checks. The sweep must (a) preserve the existing silent-failure
444
+ // contract by returning 0, and (b) surface the failure via the
445
+ // centralized notifications pipeline so the user sees it instead of
446
+ // the failure being silently swallowed.
447
+ providerStub = {
448
+ name: "stub",
449
+ sendMessage: async () => {
450
+ throw new Error("simulated provider failure");
451
+ },
452
+ };
453
+
454
+ const written = await memoryV2SweepJob(makeJob(), CONFIG);
455
+
456
+ expect(written).toBe(0);
457
+ expect(emitCalls).toHaveLength(1);
458
+ const emitted = emitCalls[0]!;
459
+ expect(emitted.sourceEventName).toBe("activity.failed");
460
+ expect(emitted.sourceChannel).toBe("scheduler");
461
+ const day = new Date().toISOString().slice(0, 10);
462
+ expect(emitted.dedupeKey).toBe(`activity-failed:memory.v2.sweep:${day}`);
463
+ const contextPayload = emitted.contextPayload as Record<string, unknown>;
464
+ expect(contextPayload.jobName).toBe("memory.v2.sweep");
465
+ expect(contextPayload.errorKind).toBe("exception");
466
+ expect(contextPayload.errorMessage).toContain("simulated provider failure");
467
+ });
468
+ });
469
+
470
+ describe("memoryV2SweepJob — background/scheduled conversation filter", () => {
471
+ test("excludes background/scheduled conversation content from sweep input", async () => {
472
+ seedMessages(
473
+ `conv-bg-${++convCounter}`,
474
+ [
475
+ {
476
+ role: "assistant",
477
+ content:
478
+ "[heartbeat] internal automation chatter that should not leak",
479
+ offsetMs: -60_000,
480
+ },
481
+ ],
482
+ "background",
483
+ );
484
+ seedMessages(
485
+ `conv-sched-${++convCounter}`,
486
+ [
487
+ {
488
+ role: "assistant",
489
+ content:
490
+ "[scheduled] scheduled-job chatter that should not leak either",
491
+ offsetMs: -45_000,
492
+ },
493
+ ],
494
+ "scheduled",
495
+ );
496
+ seedMessages(`conv-user-${++convCounter}`, [
497
+ {
498
+ role: "user",
499
+ content: "Bob mentioned he prefers dark mode.",
500
+ offsetMs: -30_000,
501
+ },
502
+ ]);
503
+
504
+ providerStub = makeEntriesProvider(["Bob prefers dark mode."]);
505
+
506
+ const written = await memoryV2SweepJob(makeJob(), CONFIG);
507
+
508
+ expect(written).toBe(1);
509
+ expect(providerCalls).toHaveLength(1);
510
+ const [{ userText }] = providerCalls;
511
+ expect(userText).toContain("Bob mentioned he prefers dark mode.");
512
+ expect(userText).not.toContain("internal automation chatter");
513
+ expect(userText).not.toContain("scheduled-job chatter");
514
+ });
434
515
  });
435
516
 
436
517
  function todaysArchiveBasename(now: Date = new Date()): string {