@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
@@ -82,15 +82,44 @@ export async function save(
82
82
  * The child row inherits everInjected as-is so previously-attached slugs are
83
83
  * not re-injected on the child's first turn — matching the v1 semantics where
84
84
  * a fork carries over all in-context memories.
85
+ *
86
+ * Synchronous so it can run inside the bun:sqlite transaction that wraps
87
+ * `forkConversation()` — keeping the state copy atomic with the message and
88
+ * attachment copies.
85
89
  */
86
- export async function fork(
90
+ export function forkActivationState(
87
91
  database: DrizzleDb,
88
92
  parentConversationId: string,
89
93
  newConversationId: string,
90
- ): Promise<void> {
91
- const parent = await hydrate(database, parentConversationId);
92
- if (!parent) return;
93
- await save(database, newConversationId, parent);
94
+ ): void {
95
+ const row = database
96
+ .select()
97
+ .from(activationState)
98
+ .where(eq(activationState.conversationId, parentConversationId))
99
+ .get();
100
+ if (!row) return;
101
+
102
+ database
103
+ .insert(activationState)
104
+ .values({
105
+ conversationId: newConversationId,
106
+ messageId: row.messageId,
107
+ stateJson: row.stateJson,
108
+ everInjectedJson: row.everInjectedJson,
109
+ currentTurn: row.currentTurn,
110
+ updatedAt: row.updatedAt,
111
+ })
112
+ .onConflictDoUpdate({
113
+ target: activationState.conversationId,
114
+ set: {
115
+ messageId: row.messageId,
116
+ stateJson: row.stateJson,
117
+ everInjectedJson: row.everInjectedJson,
118
+ currentTurn: row.currentTurn,
119
+ updatedAt: row.updatedAt,
120
+ },
121
+ })
122
+ .run();
94
123
  }
95
124
 
96
125
  /**
@@ -36,15 +36,13 @@
36
36
 
37
37
  import type { AssistantConfig } from "../../config/types.js";
38
38
  import { applyCorrectionIfCalibrated } from "../anisotropy.js";
39
- import {
40
- embedWithBackend,
41
- generateSparseEmbedding,
42
- } from "../embedding-backend.js";
39
+ import { embedWithBackend } from "../embedding-backend.js";
43
40
  import { clampUnitInterval } from "../validation.js";
44
41
  import type { EdgeIndex } from "./edge-index.js";
45
42
  import { hybridQueryConceptPages } from "./qdrant.js";
46
43
  import { rerankCandidates } from "./reranker.js";
47
44
  import { simBatch } from "./sim.js";
45
+ import { generateBm25QueryEmbedding } from "./sparse-bm25.js";
48
46
  import type { ActivationState, EverInjectedEntry } from "./types.js";
49
47
 
50
48
  /**
@@ -125,12 +123,13 @@ export async function selectCandidates(
125
123
 
126
124
  // (2) ANN top-50 against the concatenated turn text. Pure whitespace joins
127
125
  // (no separators) keep the embedding behavior aligned with how callers
128
- // would naturally read the three texts together.
126
+ // would naturally read the three texts together. Whitespace-only channels
127
+ // contribute no semantic content, so trim before deciding whether to embed.
129
128
  const annQueryText = [userText, assistantText, nowText]
130
- .filter((s) => s.length > 0)
129
+ .filter((s) => s.trim().length > 0)
131
130
  .join("\n");
132
131
 
133
- if (annQueryText.length > 0) {
132
+ if (annQueryText.trim().length > 0) {
134
133
  throwIfAborted(signal);
135
134
  const denseResult = await embedWithBackend(config, [annQueryText], {
136
135
  signal,
@@ -141,7 +140,7 @@ export async function selectCandidates(
141
140
  denseResult.model,
142
141
  );
143
142
  throwIfAborted(signal);
144
- const sparse = generateSparseEmbedding(annQueryText);
143
+ const sparse = generateBm25QueryEmbedding(annQueryText);
145
144
  const limit =
146
145
  config.memory.v2.ann_candidate_limit ?? UNLIMITED_ANN_CANDIDATE_LIMIT;
147
146
  const hits = await hybridQueryConceptPages(dense, sparse, limit);
@@ -202,17 +201,19 @@ interface ComputeOwnActivationResult {
202
201
  * + c_user · sim_u + c_assistant · sim_a + c_now · sim_n
203
202
  * + c_user · α · r_norm_u + c_assistant · α · r_norm_a
204
203
  * over the candidate set, where the rerank terms only fire for slugs that
205
- * land in the unified top-K-by-pre-rerank-A_o window. Returns a sparse map
206
- * keyed by slug; slugs whose computed value rounds to 0 are still included
207
- * so callers can see the candidate set explicitly. Also returns a per-slug
208
- * breakdown of the raw inputs (decayed prior + raw sims + rerank deltas) so
209
- * callers can render contribution diagnostics without re-running the math.
204
+ * land in the unified top-K window. The pool is ranked by the rerank-eligible
205
+ * channels alone (`c_user · sim_u + c_assistant · sim_a`) so prior- or
206
+ * NOW-heavy slugs which can't gain from rerank don't starve out
207
+ * genuinely user/assistant-relevant slugs. Returns a sparse map keyed by
208
+ * slug; slugs whose computed value rounds to 0 are still included so callers
209
+ * can see the candidate set explicitly. Also returns a per-slug breakdown of
210
+ * the raw inputs (decayed prior + raw sims + rerank deltas) so callers can
211
+ * render contribution diagnostics without re-running the math.
210
212
  *
211
213
  * The three `simBatch` calls run concurrently — they hit independent named
212
214
  * vectors and embed independent query texts. Cross-encoder rerank then runs
213
- * once on the unified top-K (selected by pre-rerank A_o, not per-channel
214
- * fused sim) so an entry strong in both channels can't double-boost itself
215
- * past entries that only land in one channel.
215
+ * once on the unified top-K so an entry strong in both channels can't
216
+ * double-boost itself past entries that only land in one channel.
216
217
  */
217
218
  export async function computeOwnActivation(
218
219
  params: ComputeOwnActivationParams,
@@ -248,8 +249,16 @@ export async function computeOwnActivation(
248
249
  simU: number;
249
250
  simA: number;
250
251
  simN: number;
251
- /** Pre-rerank A_o; ranking signal for the unified rerank pool. */
252
+ /** Pre-rerank A_o; full sum used for the final activation value. */
252
253
  preRerank: number;
254
+ /**
255
+ * Ranking signal for the unified rerank pool — only the channels that
256
+ * actually participate in rerank (user + assistant). Excluding
257
+ * `priorContribution` and `c_now * simN` prevents prior- or NOW-heavy
258
+ * slugs from consuming the rerank budget despite being ineligible for
259
+ * cross-encoder gains.
260
+ */
261
+ rerankPoolScore: number;
253
262
  }
254
263
  const inputs: SlugInputs[] = slugList.map((slug) => {
255
264
  const prev = priorState?.state[slug] ?? 0;
@@ -257,23 +266,24 @@ export async function computeOwnActivation(
257
266
  const simA = simAssistant.get(slug) ?? 0;
258
267
  const simN = simNow.get(slug) ?? 0;
259
268
  const priorContribution = d * prev;
269
+ const rerankPoolScore = c_user * simU + c_assistant * simA;
260
270
  return {
261
271
  slug,
262
272
  priorContribution,
263
273
  simU,
264
274
  simA,
265
275
  simN,
266
- preRerank:
267
- priorContribution + c_user * simU + c_assistant * simA + c_now * simN,
276
+ preRerank: priorContribution + rerankPoolScore + c_now * simN,
277
+ rerankPoolScore,
268
278
  };
269
279
  });
270
280
 
271
- // Unified top-K by pre-rerank A_o. Both channels rerank against the **same**
272
- // slug set, so a slug strong on user can't crowd out one strong on assistant
273
- // by virtue of appearing in both per-channel top-Ks. Both channel queries
274
- // ride in a single `rerankCandidates` call so the worker tokenizes and
275
- // forward-passes them together — half the per-call overhead of two
276
- // serialised round-trips.
281
+ // Unified top-K by rerank-eligible signal only. Both channels rerank against
282
+ // the **same** slug set, so a slug strong on user can't crowd out one strong
283
+ // on assistant by virtue of appearing in both per-channel top-Ks. Both
284
+ // channel queries ride in a single `rerankCandidates` call so the worker
285
+ // tokenizes and forward-passes them together — half the per-call overhead
286
+ // of two serialised round-trips.
277
287
  let userRerankBoost: ReadonlyMap<string, number> = new Map();
278
288
  let assistantRerankBoost: ReadonlyMap<string, number> = new Map();
279
289
  let inPoolSet: ReadonlySet<string> = new Set();
@@ -282,17 +292,20 @@ export async function computeOwnActivation(
282
292
  throwIfAborted(signal);
283
293
  const topSlugs = inputs
284
294
  .slice()
285
- .sort((a, b) => b.preRerank - a.preRerank)
295
+ .sort((a, b) => b.rerankPoolScore - a.rerankPoolScore)
286
296
  .slice(0, rerankCfg.top_k)
287
297
  .map((e) => e.slug);
288
298
  if (topSlugs.length > 0) {
289
- inPoolSet = new Set(topSlugs);
290
299
  const [userScores, assistantScores] = await rerankCandidates(
291
300
  [userText, assistantText],
292
301
  topSlugs,
293
302
  config,
294
303
  );
295
304
  throwIfAborted(signal);
305
+ // Build the pool from slugs the cross-encoder actually scored, so a
306
+ // backend failure (which yields empty maps) doesn't mislabel candidates
307
+ // as `inRerankPool` in the inspector.
308
+ inPoolSet = new Set([...userScores.keys(), ...assistantScores.keys()]);
296
309
  userRerankBoost = normalizeRerankScores(userScores, rerankCfg.alpha);
297
310
  assistantRerankBoost = normalizeRerankScores(
298
311
  assistantScores,
@@ -7,8 +7,7 @@
7
7
  //
8
8
  // - `memory_v2_migrate` — one-shot v1→v2 synthesis (PR 16).
9
9
  // - `memory_v2_reembed` — fan out an `embed_concept_page` job
10
- // per slug, plus four reserved-slug jobs for the meta files
11
- // (`__essentials__`, `__threads__`, `__recent__`, `__buffer__`).
10
+ // per concept-page slug.
12
11
  // - `memory_v2_activation_recompute` — recompute persisted activation
13
12
  // state for every conversation, no rendering. Used after consolidation
14
13
  // replaces or deletes pages that other conversations still reference.
@@ -19,9 +18,6 @@
19
18
  // the same code paths exercised by tests of those modules run unchanged when
20
19
  // a backfill kicks them off.
21
20
 
22
- import { readFile } from "node:fs/promises";
23
- import { join } from "node:path";
24
-
25
21
  import type { AssistantConfig } from "../../config/types.js";
26
22
  import { getLogger } from "../../util/logger.js";
27
23
  import { getWorkspaceDir } from "../../util/platform.js";
@@ -30,6 +26,7 @@ import { listConversations } from "../conversation-queries.js";
30
26
  import { getDb } from "../db-connection.js";
31
27
  import { enqueueEmbedConceptPageJob } from "../jobs/embed-concept-page.js";
32
28
  import type { MemoryJob } from "../jobs-store.js";
29
+ import { stringifyMessageContent } from "../message-content.js";
33
30
  import {
34
31
  computeOwnActivation,
35
32
  selectCandidates,
@@ -41,25 +38,11 @@ import {
41
38
  MigrationAlreadyAppliedError,
42
39
  runMemoryV2Migration,
43
40
  } from "./migration.js";
41
+ import { loadNowText } from "./now-text.js";
44
42
  import { listPages } from "./page-store.js";
45
43
 
46
44
  const log = getLogger("memory-v2-backfill");
47
45
 
48
- /**
49
- * Reserved slugs the reembed job enqueues alongside the concept-page slugs.
50
- * These name the four prose meta files (essentials/threads/recent/buffer)
51
- * loaded into the system prompt by PR 11. Embedding them is forward-looking
52
- * — the existing `embed-concept-page` handler treats unknown slugs as
53
- * deletions (a no-op when no embedding exists), so enqueueing here is safe
54
- * regardless of whether the meta files are ever embedded for retrieval.
55
- */
56
- export const META_FILE_SLUGS = [
57
- "__essentials__",
58
- "__threads__",
59
- "__recent__",
60
- "__buffer__",
61
- ] as const;
62
-
63
46
  // ---------------------------------------------------------------------------
64
47
  // memory_v2_migrate — wraps runMemoryV2Migration
65
48
  // ---------------------------------------------------------------------------
@@ -106,16 +89,22 @@ export async function memoryV2MigrateJob(
106
89
  }
107
90
 
108
91
  // ---------------------------------------------------------------------------
109
- // memory_v2_reembed — fan out embed jobs for every page + meta file
92
+ // memory_v2_reembed — fan out embed jobs for every concept page
110
93
  // ---------------------------------------------------------------------------
111
94
 
112
95
  /**
113
- * Job handler: enqueue an `embed_concept_page` job per concept-page slug, plus
114
- * one job per reserved meta-file slug ({@link META_FILE_SLUGS}).
96
+ * Job handler: enqueue an `embed_concept_page` job per concept-page slug.
97
+ *
98
+ * Returns the total number of jobs enqueued. Callers (and tests) use the
99
+ * return value to assert progress without inspecting the job table directly.
115
100
  *
116
- * Returns the total number of jobs enqueued `concept-page count + 4`.
117
- * Callers (and tests) use the return value to assert progress without
118
- * inspecting the job table directly.
101
+ * Note on meta files: `essentials.md` / `threads.md` / `recent.md` /
102
+ * `buffer.md` are direct-injected into the system prompt every turn via
103
+ * `_autoinject.md`. They are NOT enqueued for embedding here — their slugs
104
+ * (`__essentials__` etc.) contain underscores that the concept-page slug
105
+ * validator rejects (`[a-z0-9][a-z0-9-]*`), and they live at `memory/<name>.md`
106
+ * rather than `memory/concepts/<name>.md`, so path resolution would also miss.
107
+ * Embedding them would be redundant with the direct injection regardless.
119
108
  */
120
109
  export async function memoryV2ReembedJob(
121
110
  _job: MemoryJob,
@@ -127,16 +116,12 @@ export async function memoryV2ReembedJob(
127
116
  for (const slug of slugs) {
128
117
  enqueueEmbedConceptPageJob({ slug });
129
118
  }
130
- for (const slug of META_FILE_SLUGS) {
131
- enqueueEmbedConceptPageJob({ slug });
132
- }
133
119
 
134
- const total = slugs.length + META_FILE_SLUGS.length;
135
120
  log.info(
136
- { conceptPages: slugs.length, metaFiles: META_FILE_SLUGS.length, total },
121
+ { conceptPages: slugs.length, total: slugs.length },
137
122
  "Memory v2 reembed enqueued",
138
123
  );
139
- return total;
124
+ return slugs.length;
140
125
  }
141
126
 
142
127
  // ---------------------------------------------------------------------------
@@ -303,55 +288,3 @@ function lastExchangeTexts(conversationId: string): {
303
288
  }
304
289
  return { userText, assistantText };
305
290
  }
306
-
307
- /**
308
- * Coerce stored message content (JSON-serialized `ContentBlock[]` *or* plain
309
- * string in legacy rows) into a single text string. Image / tool blocks are
310
- * dropped — recompute only needs the spoken text.
311
- */
312
- function stringifyMessageContent(stored: string): string {
313
- let parsed: unknown;
314
- try {
315
- parsed = JSON.parse(stored);
316
- } catch {
317
- return stored.trim();
318
- }
319
- if (typeof parsed === "string") return parsed.trim();
320
- if (!Array.isArray(parsed)) return "";
321
- const parts: string[] = [];
322
- for (const block of parsed) {
323
- if (
324
- block &&
325
- typeof block === "object" &&
326
- (block as { type?: string }).type === "text" &&
327
- typeof (block as { text?: unknown }).text === "string"
328
- ) {
329
- parts.push((block as { text: string }).text);
330
- }
331
- }
332
- return parts.join("\n").trim();
333
- }
334
-
335
- /**
336
- * Read the prose meta files that compose the "NOW" context the activation
337
- * pipeline correlates against. Mirrors the autoload order in
338
- * `system-prompt.ts` so the same prose drives both injection and recompute.
339
- * Missing or unreadable files are treated as empty.
340
- */
341
- async function loadNowText(workspaceDir: string): Promise<string> {
342
- const filenames = ["essentials.md", "threads.md", "recent.md"];
343
- const reads = await Promise.all(
344
- filenames.map(async (filename) => {
345
- try {
346
- const text = await readFile(
347
- join(workspaceDir, "memory", filename),
348
- "utf-8",
349
- );
350
- return text.trim();
351
- } catch {
352
- return "";
353
- }
354
- }),
355
- );
356
- return reads.filter((part) => part.length > 0).join("\n\n");
357
- }
@@ -6,17 +6,17 @@
6
6
  * rewrites `memory/recent.md`, promotes new essentials/threads, and trims the
7
7
  * buffer down to entries that arrived after the run started.
8
8
  *
9
- * Unlike `sweep`, consolidation runs as the assistant: `wakeAgentForOpportunity()`
10
- * loads the standard system prompt (SOUL.md + IDENTITY.md + persona + memory/*
11
- * autoloads) and the standard tool surface (read_file, write_file, edit_file,
12
- * list_files, bash). The hint string carries the prompt body from §10 of the
13
- * design doc with the cutoff timestamp templated in. Care, judgment, and the
9
+ * Consolidation runs as the assistant: `runBackgroundJob()` bootstraps a
10
+ * background conversation and routes the cutoff-templated prompt through
11
+ * `processMessage`, so the standard system prompt (SOUL.md + IDENTITY.md +
12
+ * persona + memory/* autoloads) and tool surface (read_file, write_file,
13
+ * edit_file, list_files, bash) are loaded. Care, judgment, and the
14
14
  * assistant's voice are the point — there is no "consolidator persona" to
15
15
  * substitute in.
16
16
  *
17
17
  * Lifecycle:
18
- * 1. Bail if the `memory-v2-enabled` feature flag is off (the worker may
19
- * have claimed a stale row at flag-flip time).
18
+ * 1. Bail if `config.memory.v2.enabled` is false (the worker may have
19
+ * claimed a stale row from before v2 was disabled).
20
20
  * 2. Acquire a single-process lock at `memory/.v2-state/consolidation.lock`
21
21
  * so two overlapping schedule windows can't fight over the same files.
22
22
  * The lock contains the holder's PID + timestamp so a crashed run leaves
@@ -26,21 +26,29 @@
26
26
  * the next pass.
27
27
  * 4. Read `memory/buffer.md`. Bail if empty (no work to do, but the lock
28
28
  * and skip path still log so operators can confirm the schedule fired).
29
- * 5. Bootstrap a background conversation (mirrors `runUpdateBulletinJobIfNeeded`)
30
- * and call `wakeAgentForOpportunity()` with the templated hint. The wake
31
- * reuses the assistant's full system prompt + tools.
32
- * 6. On wake success, enqueue `memory_v2_reembed` to re-index any pages the
33
- * agent touched. Tracking touched pages via mtime would be more precise
34
- * but is fragile across filesystems; the embedder's content-hash cache
35
- * makes a conservative full-reembed effectively free. On wake failure
36
- * no follow-ups are enqueued the agent didn't run, so there's nothing
37
- * to re-embed.
38
- * 7. Release the lock.
29
+ * 5. Hand off to `runBackgroundJob()` with the templated prompt. The runner
30
+ * handles bootstrap + processMessage + timeout + error classification,
31
+ * and (because we set `suppressFailureNotifications: true`) does NOT
32
+ * emit an `activity.failed` notification on transient failures
33
+ * consolidation runs on tight intervals, so a network blip or model
34
+ * hiccup should not spam the home feed. Sentry-side reporting is
35
+ * unchanged. The prompt body is loaded via `resolveConsolidationPrompt`
36
+ * which bounds any operator-provided override to a regular file under
37
+ * 1 MiB before substitution.
38
+ * 6. On success, enqueue `memory_v2_reembed` (re-index any pages the agent
39
+ * touched). Tracking touched pages via mtime would be more precise but
40
+ * is fragile across filesystems; the embedder's content-hash cache makes
41
+ * a conservative full-reembed effectively free. On failure no follow-ups
42
+ * are enqueued — the agent's writes may be partial and re-embedding
43
+ * partial state would be misleading.
44
+ * 7. Release the lock. If a prior holder's PID is no longer running, the
45
+ * stale lock is taken over automatically (single-writer per workspace,
46
+ * so a holder whose process died is unambiguously stale).
39
47
  *
40
- * The handler never propagates a wake exception: it logs, cleans up the
41
- * orphan conversation, releases the lock, and returns `wake_failed` so the
42
- * next scheduled run can re-attempt. A thrown bootstrap error bubbles up and
43
- * the jobs-worker treats it as a retryable failure.
48
+ * The handler never propagates exceptions from the run path `runBackgroundJob`
49
+ * absorbs them and returns a structured result. A thrown error before the
50
+ * runner is invoked (e.g. mkdir failures) bubbles up and the jobs-worker
51
+ * treats it as a retryable failure.
44
52
  */
45
53
 
46
54
  import {
@@ -53,15 +61,12 @@ import {
53
61
  } from "node:fs";
54
62
  import { dirname, join } from "node:path";
55
63
 
56
- import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
57
64
  import type { AssistantConfig } from "../../config/types.js";
58
- import { INTERNAL_GUARDIAN_TRUST_CONTEXT } from "../../daemon/trust-context.js";
59
- import { wakeAgentForOpportunity } from "../../runtime/agent-wake.js";
65
+ import { runBackgroundJob } from "../../runtime/background-job-runner.js";
60
66
  import { getLogger } from "../../util/logger.js";
61
67
  import { getWorkspaceDir } from "../../util/platform.js";
62
68
  import { isProcessAlive } from "../../util/process-liveness.js";
63
- import { bootstrapConversation } from "../conversation-bootstrap.js";
64
- import { deleteConversation } from "../conversation-crud.js";
69
+ import { formatBufferTimestamp } from "../graph/tool-handlers.js";
65
70
  import {
66
71
  enqueueMemoryJob,
67
72
  type MemoryJob,
@@ -72,6 +77,17 @@ import { resolveConsolidationPrompt } from "./prompts/consolidation.js";
72
77
 
73
78
  const log = getLogger("memory-v2-consolidate");
74
79
 
80
+ /** Stable identifier surfaced in `runBackgroundJob` logs and notifications. */
81
+ const JOB_NAME = "memory.consolidate";
82
+
83
+ /**
84
+ * Hard timeout for the consolidation run. Consolidation reads the buffer,
85
+ * rewrites several files, and re-encodes essentials/threads — generous
86
+ * upper bound so a slow run isn't killed mid-edit, but bounded so a stuck
87
+ * provider can't pin the worker indefinitely.
88
+ */
89
+ const CONSOLIDATION_TIMEOUT_MS = 15 * 60 * 1000;
90
+
75
91
  /**
76
92
  * Follow-up jobs to fan out after a successful consolidation.
77
93
  *
@@ -85,14 +101,14 @@ const FOLLOW_UP_JOB_TYPES: readonly MemoryJobType[] = [
85
101
 
86
102
  /**
87
103
  * Job handler. See file header for the full lifecycle. Returns a discriminated
88
- * union so tests can assert on the path taken (flag-off / locked / empty /
89
- * invoked) without having to spy on the filesystem.
104
+ * union so tests can assert on the path taken (disabled / locked / empty /
105
+ * invoked / failed) without having to spy on the filesystem.
90
106
  */
91
107
  export type ConsolidationOutcome =
92
- | { kind: "flag_off" }
108
+ | { kind: "disabled" }
93
109
  | { kind: "locked"; holder: string }
94
110
  | { kind: "empty_buffer" }
95
- | { kind: "wake_failed"; reason?: string }
111
+ | { kind: "run_failed"; reason?: string }
96
112
  | {
97
113
  kind: "invoked";
98
114
  conversationId: string;
@@ -104,9 +120,9 @@ export async function memoryV2ConsolidateJob(
104
120
  _job: MemoryJob,
105
121
  config: AssistantConfig,
106
122
  ): Promise<ConsolidationOutcome> {
107
- if (!isAssistantFeatureFlagEnabled("memory-v2-enabled", config)) {
108
- log.debug("memory-v2-enabled flag off; consolidation skipped");
109
- return { kind: "flag_off" };
123
+ if (!config.memory.v2.enabled) {
124
+ log.debug("memory.v2.enabled is false; consolidation skipped");
125
+ return { kind: "disabled" };
110
126
  }
111
127
 
112
128
  const memoryDir = join(getWorkspaceDir(), "memory");
@@ -122,11 +138,13 @@ export async function memoryV2ConsolidateJob(
122
138
  }
123
139
 
124
140
  try {
125
- // Step 2: capture cutoff. ISO-8601 is the convention; it's a total order
126
- // string that compares correctly via lexicographic <, which is all the
127
- // prompt asks the agent to do. Captured here (not at enqueue time) so
128
- // late-claimed rows still get a fresh cutoff.
129
- const cutoff = new Date().toISOString();
141
+ // Step 2: capture cutoff. Formatted to match `buffer.md` entry timestamps
142
+ // (`Mon D, h:mm AM/PM`, see `formatBufferTimestamp`) so the agent's
143
+ // "timestamp cutoff" check compares like-with-like at minute precision.
144
+ // Same-minute entries land on the next pass — conservative but loss-free.
145
+ // Captured here (not at enqueue time) so late-claimed rows get a fresh
146
+ // cutoff.
147
+ const cutoff = formatBufferTimestamp(new Date());
130
148
 
131
149
  // Step 3: bail on empty buffer. Nothing for the agent to consolidate.
132
150
  // The lock is released in finally below.
@@ -136,57 +154,45 @@ export async function memoryV2ConsolidateJob(
136
154
  return { kind: "empty_buffer" };
137
155
  }
138
156
 
139
- // Step 4: bootstrap a background conversation and wake the assistant
140
- // with the cutoff-templated prompt. Mirrors the UPDATES.md pattern in
141
- // `runUpdateBulletinJobIfNeeded`the wake runs `mainAgent` against
142
- // the assistant's full system prompt, so consolidation thinks and
143
- // writes in the assistant's voice.
144
- const conversation = bootstrapConversation({
145
- conversationType: "background",
157
+ // Step 4: hand off to the centralized background-job runner. The runner
158
+ // bootstraps the conversation, drives `processMessage`, applies the
159
+ // timeout policy, classifies errors, and because we opt out via
160
+ // `suppressFailureNotifications` does NOT emit an `activity.failed`
161
+ // notification on transient failures. Consolidation runs on tight
162
+ // intervals; a network blip or model hiccup should not spam the feed.
163
+ // Sentry-side reporting is unchanged.
164
+ //
165
+ // The prompt body comes from `resolveConsolidationPrompt`, which honors
166
+ // the `memory.v2.consolidation_prompt_path` config override but bounds
167
+ // it to a regular file under 1 MiB before substitution so a stray path
168
+ // (or a `/dev/zero`-style pseudo-file) cannot exfiltrate megabytes of
169
+ // bytes through the wake hint.
170
+ const runResult = await runBackgroundJob({
171
+ jobName: JOB_NAME,
146
172
  source: MEMORY_V2_CONSOLIDATION_SOURCE,
173
+ prompt: resolveConsolidationPrompt(
174
+ config.memory.v2.consolidation_prompt_path,
175
+ cutoff,
176
+ ),
177
+ trustContext: { sourceChannel: "vellum", trustClass: "guardian" },
178
+ callSite: "mainAgent",
179
+ timeoutMs: CONSOLIDATION_TIMEOUT_MS,
147
180
  origin: "memory_consolidation",
148
- systemHint: "Running memory consolidation",
149
- groupId: "system:background",
181
+ suppressFailureNotifications: true,
150
182
  });
151
183
 
152
- let wakeInvoked = false;
153
- let failureReason: string | undefined;
154
- try {
155
- const result = await wakeAgentForOpportunity({
156
- conversationId: conversation.id,
157
- hint: resolveConsolidationPrompt(
158
- config.memory.v2.consolidation_prompt_path,
159
- cutoff,
160
- ),
161
- source: MEMORY_V2_CONSOLIDATION_SOURCE,
162
- trustContext: INTERNAL_GUARDIAN_TRUST_CONTEXT,
163
- });
164
- wakeInvoked = result.invoked;
165
- failureReason = result.reason;
166
- } catch (err) {
167
- failureReason = err instanceof Error ? err.message : String(err);
184
+ if (!runResult.ok) {
168
185
  log.error(
169
- { err, conversationId: conversation.id },
170
- "consolidation wake threw; cleaning up and re-enqueuing follow-ups skipped",
186
+ {
187
+ conversationId: runResult.conversationId,
188
+ errorKind: runResult.errorKind,
189
+ err: runResult.error?.message,
190
+ },
191
+ "consolidation run failed; follow-ups skipped",
171
192
  );
172
- }
173
-
174
- // If the wake never ran (resolver missing, conversation archived,
175
- // timeout, exception), clean up the orphan background conversation —
176
- // matches the cleanup logic in `runUpdateBulletinJobIfNeeded`. We
177
- // do NOT enqueue follow-ups in this branch because no pages changed.
178
- if (!wakeInvoked) {
179
- try {
180
- deleteConversation(conversation.id);
181
- } catch (err) {
182
- log.warn(
183
- { err, conversationId: conversation.id },
184
- "consolidation: failed to delete orphan background conversation; continuing",
185
- );
186
- }
187
- return failureReason !== undefined
188
- ? { kind: "wake_failed", reason: failureReason }
189
- : { kind: "wake_failed" };
193
+ return runResult.error?.message !== undefined
194
+ ? { kind: "run_failed", reason: runResult.error.message }
195
+ : { kind: "run_failed" };
190
196
  }
191
197
 
192
198
  // Step 5: enqueue follow-up jobs. Enqueueing now keeps the dispatch
@@ -208,7 +214,7 @@ export async function memoryV2ConsolidateJob(
208
214
 
209
215
  log.info(
210
216
  {
211
- conversationId: conversation.id,
217
+ conversationId: runResult.conversationId,
212
218
  cutoff,
213
219
  followUpJobIds,
214
220
  },
@@ -216,7 +222,7 @@ export async function memoryV2ConsolidateJob(
216
222
  );
217
223
  return {
218
224
  kind: "invoked",
219
- conversationId: conversation.id,
225
+ conversationId: runResult.conversationId,
220
226
  cutoff,
221
227
  followUpJobIds,
222
228
  };
@@ -336,7 +342,7 @@ function isHolderStale(holder: string): boolean {
336
342
 
337
343
  /**
338
344
  * Idempotent unlink of the lock file. Called from the `finally` block so a
339
- * crash in the wake path doesn't leave the lock stranded. ENOENT is swallowed
345
+ * crash in the run path doesn't leave the lock stranded. ENOENT is swallowed
340
346
  * because the lock may have been released by an operator or never created
341
347
  * (acquire failed before reaching the lock-write step).
342
348
  */