@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
@@ -98,51 +98,125 @@ export async function embedConceptPageJob(
98
98
  );
99
99
  }
100
100
 
101
- const contentHash = embeddingInputContentHash({ type: "text", text });
102
101
  const expectedDim = config.memory.qdrant.vectorSize;
103
- let provider = status.provider;
104
- let model = status.model!;
102
+ // The status provider is the cache lookup key for any prior row; the
103
+ // *actual* provider/model come back on the embedded result. They usually
104
+ // match, but a backend swap mid-run would surface here — body and summary
105
+ // are then re-embedded together so both rows write under the same identity.
106
+ const cacheProvider = status.provider;
107
+ const cacheModel = status.model!;
108
+
109
+ const db = getDb();
105
110
 
106
111
  // Cache lookup: same (targetType, targetId, provider, model) row gets
107
112
  // reused across runs as long as `contentHash` matches. The dim mismatch
108
113
  // check guards against a config change (vectorSize bumped) since the last
109
- // write — in that case we treat the row as stale and re-embed.
110
- const db = getDb();
111
- let cachedRow = db
112
- .select({
113
- vectorBlob: memoryEmbeddings.vectorBlob,
114
- vectorJson: memoryEmbeddings.vectorJson,
115
- dimensions: memoryEmbeddings.dimensions,
116
- contentHash: memoryEmbeddings.contentHash,
117
- })
118
- .from(memoryEmbeddings)
119
- .where(
120
- and(
121
- eq(memoryEmbeddings.targetType, CONCEPT_PAGE_TARGET_TYPE),
122
- eq(memoryEmbeddings.targetId, slug),
123
- eq(memoryEmbeddings.provider, provider),
124
- eq(memoryEmbeddings.model, model),
125
- ),
126
- )
127
- .get();
128
- if (cachedRow && cachedRow.dimensions !== expectedDim) cachedRow = undefined;
129
- if (cachedRow && cachedRow.contentHash !== contentHash) cachedRow = undefined;
130
-
131
- let dense: number[];
132
- let cacheHit = false;
133
- if (cachedRow) {
134
- dense = cachedRow.vectorBlob
135
- ? blobToVector(cachedRow.vectorBlob as Buffer)
136
- : (JSON.parse(cachedRow.vectorJson!) as number[]);
137
- cacheHit = true;
138
- } else {
139
- const embedded = await embedWithBackend(config, [{ type: "text", text }]);
140
- const vector = embedded.vectors[0];
141
- if (!vector) return;
142
- dense = vector;
143
- provider = embedded.provider;
144
- model = embedded.model;
114
+ // write — in that case we treat the row as stale and re-embed. The body
115
+ // and (optional) summary share the same provider/model — but each gets
116
+ // its own cache row keyed by a distinct targetId so summary edits don't
117
+ // invalidate the body cache and vice versa.
118
+ const bodyContentHash = embeddingInputContentHash({ type: "text", text });
119
+ const bodyCache = readEmbeddingCache(
120
+ db,
121
+ slug,
122
+ cacheProvider,
123
+ cacheModel,
124
+ expectedDim,
125
+ );
126
+ const bodyCacheHit = bodyCache?.contentHash === bodyContentHash;
127
+
128
+ // Optional summary embedding — only when the page has a `summary` in its
129
+ // frontmatter. Pages without one fall back to body-only retrieval at
130
+ // query time (the activation pipeline reads the summary score as
131
+ // undefined and uses the body score directly).
132
+ const summaryText = page.frontmatter.summary?.trim() ?? "";
133
+ const hasSummary = summaryText.length > 0;
134
+ const summaryCacheId = `${slug}#summary`;
135
+ const summaryContentHash = hasSummary
136
+ ? embeddingInputContentHash({ type: "text", text: summaryText })
137
+ : undefined;
138
+ const summaryCache = hasSummary
139
+ ? readEmbeddingCache(
140
+ db,
141
+ summaryCacheId,
142
+ cacheProvider,
143
+ cacheModel,
144
+ expectedDim,
145
+ )
146
+ : null;
147
+ const summaryCacheHit =
148
+ hasSummary && summaryCache?.contentHash === summaryContentHash;
149
+
150
+ // Batch all cache misses into one `embedWithBackend` call. Each backend
151
+ // round-trip is the dominant cost — fresh body + fresh summary in a
152
+ // single batch saves a round-trip vs serial calls and gives both vectors
153
+ // the same provider/model regardless of any backend rotation mid-run.
154
+ type Slot = "body" | "summary";
155
+ const toEmbed: Array<{ type: "text"; text: string }> = [];
156
+ const slots: Slot[] = [];
157
+ if (!bodyCacheHit) {
158
+ toEmbed.push({ type: "text", text });
159
+ slots.push("body");
160
+ }
161
+ if (hasSummary && !summaryCacheHit) {
162
+ toEmbed.push({ type: "text", text: summaryText });
163
+ slots.push("summary");
164
+ }
165
+
166
+ let bodyDense: number[] | undefined = bodyCacheHit
167
+ ? bodyCache!.dense
168
+ : undefined;
169
+ let summaryDense: number[] | undefined = summaryCacheHit
170
+ ? summaryCache!.dense
171
+ : undefined;
172
+ let writeProvider = cacheProvider;
173
+ let writeModel = cacheModel;
174
+ let bodyFresh = false;
175
+ let summaryFresh = false;
176
+ if (toEmbed.length > 0) {
177
+ let embedded = await embedWithBackend(config, toEmbed);
178
+ let appliedSlots = slots;
179
+ // Backend rotation between `getMemoryBackendStatus()` and
180
+ // `embedWithBackend()` would tag the cached half with the old
181
+ // provider/model and the fresh half with the new — writing both into
182
+ // one Qdrant point mixes embedding spaces. Re-embed every slot fresh
183
+ // when we detect the rotation so the point's named vectors share one
184
+ // identity.
185
+ const rotated =
186
+ (bodyCacheHit || summaryCacheHit) &&
187
+ (embedded.provider !== cacheProvider || embedded.model !== cacheModel);
188
+ if (rotated) {
189
+ const allTexts: Array<{ type: "text"; text: string }> = [
190
+ { type: "text", text },
191
+ ];
192
+ const allSlots: Slot[] = ["body"];
193
+ if (hasSummary) {
194
+ allTexts.push({ type: "text", text: summaryText });
195
+ allSlots.push("summary");
196
+ }
197
+ embedded = await embedWithBackend(config, allTexts);
198
+ appliedSlots = allSlots;
199
+ bodyDense = undefined;
200
+ summaryDense = undefined;
201
+ }
202
+ writeProvider = embedded.provider;
203
+ writeModel = embedded.model;
204
+ for (let i = 0; i < appliedSlots.length; i++) {
205
+ const vector = embedded.vectors[i];
206
+ if (!vector) continue;
207
+ if (appliedSlots[i] === "body") {
208
+ bodyDense = vector;
209
+ bodyFresh = true;
210
+ } else {
211
+ summaryDense = vector;
212
+ summaryFresh = true;
213
+ }
214
+ }
145
215
  }
216
+ // Body embedding is the ground truth — without it the page can't surface.
217
+ // (Cache hit paths populate `bodyDense` above; a fresh embed that returned
218
+ // no vectors short-circuits here too.)
219
+ if (!bodyDense) return;
146
220
 
147
221
  // Sparse is cheap (in-process tokenization) and changes any time the body
148
222
  // changes, so we always recompute it rather than caching alongside dense.
@@ -151,57 +225,45 @@ export async function embedConceptPageJob(
151
225
  // corpus for the first time), fall back to the legacy TF-only encoding —
152
226
  // the next reembed pass overwrites the page once stats are available.
153
227
  const corpusStats = getConceptPageCorpusStats();
154
- const sparse = corpusStats
155
- ? generateBm25DocEmbedding(text, corpusStats, {
156
- k1: config.memory.v2.bm25_k1,
157
- b: config.memory.v2.bm25_b,
158
- })
159
- : generateSparseEmbedding(text);
228
+ const encodeSparse = (input: string) =>
229
+ corpusStats
230
+ ? generateBm25DocEmbedding(input, corpusStats, {
231
+ k1: config.memory.v2.bm25_k1,
232
+ b: config.memory.v2.bm25_b,
233
+ })
234
+ : generateSparseEmbedding(input);
235
+ const sparse = encodeSparse(text);
236
+ const summarySparse = hasSummary ? encodeSparse(summaryText) : undefined;
160
237
 
161
238
  const now = Date.now();
162
239
  // Persist freshly embedded vectors for cross-restart reuse. On cache hit
163
240
  // the existing row already has identical content + hash, so the write
164
- // would be a no-op — skip it. Best-effort: write failure is not fatal,
165
- // we still want the Qdrant upsert below to fire.
166
- if (!cacheHit) {
167
- try {
168
- const blobValue = vectorToBlob(dense);
169
- db.insert(memoryEmbeddings)
170
- .values({
171
- id: randomUUID(),
172
- targetType: CONCEPT_PAGE_TARGET_TYPE,
173
- targetId: slug,
174
- provider,
175
- model,
176
- dimensions: dense.length,
177
- vectorBlob: blobValue,
178
- vectorJson: null,
179
- contentHash,
180
- createdAt: now,
181
- updatedAt: now,
182
- })
183
- .onConflictDoUpdate({
184
- target: [
185
- memoryEmbeddings.targetType,
186
- memoryEmbeddings.targetId,
187
- memoryEmbeddings.provider,
188
- memoryEmbeddings.model,
189
- ],
190
- set: {
191
- vectorBlob: blobValue,
192
- vectorJson: null,
193
- dimensions: dense.length,
194
- contentHash,
195
- updatedAt: now,
196
- },
197
- })
198
- .run();
199
- } catch (err) {
200
- log.warn(
201
- { err, slug },
202
- "Failed to write concept-page embedding cache row",
203
- );
204
- }
241
+ // would be a no-op — skip it. Backend rotation flips a cache hit into a
242
+ // fresh embed (see `rotated` above); the `*Fresh` flags capture that so
243
+ // the new vector overwrites the now-stale cache row under the new
244
+ // provider/model identity. Best-effort: write failure is not fatal, we
245
+ // still want the Qdrant upsert below to fire.
246
+ if (bodyFresh) {
247
+ writeEmbeddingCache(db, {
248
+ slug,
249
+ cacheId: slug,
250
+ dense: bodyDense,
251
+ contentHash: bodyContentHash,
252
+ provider: writeProvider,
253
+ model: writeModel,
254
+ now,
255
+ });
256
+ }
257
+ if (hasSummary && summaryFresh && summaryDense && summaryContentHash) {
258
+ writeEmbeddingCache(db, {
259
+ slug,
260
+ cacheId: summaryCacheId,
261
+ dense: summaryDense,
262
+ contentHash: summaryContentHash,
263
+ provider: writeProvider,
264
+ model: writeModel,
265
+ now,
266
+ });
205
267
  }
206
268
 
207
269
  // Apply anisotropy correction at the boundary between the (raw) cached
@@ -210,19 +272,129 @@ export async function embedConceptPageJob(
210
272
  // the cache survives and the (cheap) correction math reruns over each
211
273
  // cached vector. Pass-through when no calibration is fit yet.
212
274
  const correctedDense = await applyCorrectionIfCalibrated(
213
- dense,
214
- provider,
215
- model,
275
+ bodyDense,
276
+ writeProvider,
277
+ writeModel,
216
278
  );
279
+ const correctedSummaryDense = summaryDense
280
+ ? await applyCorrectionIfCalibrated(summaryDense, writeProvider, writeModel)
281
+ : undefined;
217
282
 
218
283
  await upsertConceptPageEmbedding({
219
284
  slug,
220
285
  dense: correctedDense,
221
286
  sparse,
287
+ summary:
288
+ correctedSummaryDense && summarySparse
289
+ ? { dense: correctedSummaryDense, sparse: summarySparse }
290
+ : undefined,
222
291
  updatedAt: now,
223
292
  });
224
293
  }
225
294
 
295
+ /** SQLite cache row shape returned by `readEmbeddingCache`. */
296
+ interface EmbeddingCacheEntry {
297
+ dense: number[];
298
+ contentHash: string;
299
+ }
300
+
301
+ /**
302
+ * Look up a cached dense vector keyed on `(targetType, targetId, provider,
303
+ * model)`. Returns the row only when the persisted dimensions match the
304
+ * configured expectation — a stale row from a previous `vectorSize` is
305
+ * treated as a cache miss so the caller re-embeds.
306
+ */
307
+ function readEmbeddingCache(
308
+ db: ReturnType<typeof getDb>,
309
+ cacheId: string,
310
+ provider: string,
311
+ model: string,
312
+ expectedDim: number,
313
+ ): EmbeddingCacheEntry | null {
314
+ const row = db
315
+ .select({
316
+ vectorBlob: memoryEmbeddings.vectorBlob,
317
+ vectorJson: memoryEmbeddings.vectorJson,
318
+ dimensions: memoryEmbeddings.dimensions,
319
+ contentHash: memoryEmbeddings.contentHash,
320
+ })
321
+ .from(memoryEmbeddings)
322
+ .where(
323
+ and(
324
+ eq(memoryEmbeddings.targetType, CONCEPT_PAGE_TARGET_TYPE),
325
+ eq(memoryEmbeddings.targetId, cacheId),
326
+ eq(memoryEmbeddings.provider, provider),
327
+ eq(memoryEmbeddings.model, model),
328
+ ),
329
+ )
330
+ .get();
331
+ if (!row || row.dimensions !== expectedDim) return null;
332
+ // A row without a contentHash is a legacy/corrupt entry — treat as a miss
333
+ // and force a re-embed rather than misalign the cache key.
334
+ if (row.contentHash === null) return null;
335
+ const dense = row.vectorBlob
336
+ ? blobToVector(row.vectorBlob as Buffer)
337
+ : (JSON.parse(row.vectorJson!) as number[]);
338
+ return { dense, contentHash: row.contentHash };
339
+ }
340
+
341
+ /**
342
+ * Persist a freshly embedded dense vector in the SQLite cache. Best-effort:
343
+ * a write failure is logged and swallowed so the Qdrant upsert still runs.
344
+ */
345
+ function writeEmbeddingCache(
346
+ db: ReturnType<typeof getDb>,
347
+ params: {
348
+ slug: string;
349
+ cacheId: string;
350
+ dense: number[];
351
+ contentHash: string;
352
+ provider: string;
353
+ model: string;
354
+ now: number;
355
+ },
356
+ ): void {
357
+ const { slug, cacheId, dense, contentHash, provider, model, now } = params;
358
+ try {
359
+ const blobValue = vectorToBlob(dense);
360
+ db.insert(memoryEmbeddings)
361
+ .values({
362
+ id: randomUUID(),
363
+ targetType: CONCEPT_PAGE_TARGET_TYPE,
364
+ targetId: cacheId,
365
+ provider,
366
+ model,
367
+ dimensions: dense.length,
368
+ vectorBlob: blobValue,
369
+ vectorJson: null,
370
+ contentHash,
371
+ createdAt: now,
372
+ updatedAt: now,
373
+ })
374
+ .onConflictDoUpdate({
375
+ target: [
376
+ memoryEmbeddings.targetType,
377
+ memoryEmbeddings.targetId,
378
+ memoryEmbeddings.provider,
379
+ memoryEmbeddings.model,
380
+ ],
381
+ set: {
382
+ vectorBlob: blobValue,
383
+ vectorJson: null,
384
+ dimensions: dense.length,
385
+ contentHash,
386
+ updatedAt: now,
387
+ },
388
+ })
389
+ .run();
390
+ } catch (err) {
391
+ log.warn(
392
+ { err, slug, cacheId },
393
+ "Failed to write concept-page embedding cache row",
394
+ );
395
+ }
396
+ }
397
+
226
398
  /**
227
399
  * Enqueue an `embed_concept_page` job (async, fire-and-forget). Modeled on
228
400
  * `enqueuePkbIndexJob` — callers that want a slug re-embedded after a write
@@ -42,7 +42,8 @@ export type MemoryJobType =
42
42
  | "memory_v2_consolidate"
43
43
  | "memory_v2_migrate"
44
44
  | "memory_v2_reembed"
45
- | "memory_v2_activation_recompute";
45
+ | "memory_v2_activation_recompute"
46
+ | "memory_retrospective";
46
47
 
47
48
  export const EMBED_JOB_TYPES: MemoryJobType[] = [
48
49
  "embed_segment",
@@ -52,6 +53,7 @@ export const EMBED_JOB_TYPES: MemoryJobType[] = [
52
53
  "embed_graph_node",
53
54
  "embed_pkb_file",
54
55
  "graph_trigger_embed",
56
+ "embed_concept_page",
55
57
  ];
56
58
 
57
59
  export const SLOW_LLM_JOB_TYPES: MemoryJobType[] = [
@@ -65,6 +67,7 @@ export const SLOW_LLM_JOB_TYPES: MemoryJobType[] = [
65
67
  "memory_v2_sweep",
66
68
  "memory_v2_consolidate",
67
69
  "memory_v2_migrate",
70
+ "memory_retrospective",
68
71
  "backfill",
69
72
  "graph_bootstrap",
70
73
  ];
@@ -251,6 +254,53 @@ export function upsertAutoAnalysisJob(
251
254
  }
252
255
  }
253
256
 
257
+ /**
258
+ * Upsert a pending `memory_retrospective` job keyed by `conversationId`. All
259
+ * four retrospective triggers (interval, message_count, compaction,
260
+ * lifecycle) collapse into a single pending row per conversation — rapid
261
+ * triggers coalesce instead of double-firing. The `runAfter` parameter on a
262
+ * follow-up enqueue overwrites the existing row's `runAfter` so a sooner
263
+ * trigger can pull a later-scheduled job earlier; a later-scheduled trigger
264
+ * does NOT push a sooner-scheduled row further out (consumer takes the
265
+ * minimum). The trigger metadata is intentionally not retained — it is only
266
+ * useful for observability at enqueue time.
267
+ */
268
+ export function upsertMemoryRetrospectiveJob(
269
+ payload: { conversationId: string },
270
+ runAfter: number = Date.now(),
271
+ dbOverride?: Parameters<ReturnType<typeof getDb>["transaction"]>[0] extends (
272
+ tx: infer T,
273
+ ) => unknown
274
+ ? T
275
+ : never,
276
+ ): void {
277
+ const db = dbOverride ?? getDb();
278
+ const existing = db
279
+ .select()
280
+ .from(memoryJobs)
281
+ .where(
282
+ and(
283
+ eq(memoryJobs.type, "memory_retrospective"),
284
+ eq(memoryJobs.status, "pending"),
285
+ sql`json_extract(${memoryJobs.payload}, '$.conversationId') = ${payload.conversationId}`,
286
+ ),
287
+ )
288
+ .get();
289
+ if (existing) {
290
+ // Take the minimum of the existing and incoming runAfter so the earliest
291
+ // trigger always wins. A later trigger never pushes work further out.
292
+ const nextRunAfter = Math.min(existing.runAfter, runAfter);
293
+ if (nextRunAfter !== existing.runAfter) {
294
+ db.update(memoryJobs)
295
+ .set({ runAfter: nextRunAfter, updatedAt: Date.now() })
296
+ .where(eq(memoryJobs.id, existing.id))
297
+ .run();
298
+ }
299
+ return;
300
+ }
301
+ enqueueMemoryJob("memory_retrospective", payload, runAfter, dbOverride);
302
+ }
303
+
254
304
  /**
255
305
  * Check whether a pending or running job of the given type already exists.
256
306
  * Used to prevent duplicate enqueues for long-running maintenance jobs.
@@ -11,7 +11,6 @@ import {
11
11
  getLastScheduledCleanupEnqueueMs,
12
12
  markScheduledCleanupEnqueued,
13
13
  } from "./cleanup-schedule-state.js";
14
- import { isMemoryV2ReadActive } from "./context-search/sources/memory-v2.js";
15
14
  import { conversationAnalyzeJob } from "./conversation-analyze-job.js";
16
15
  import { maybeRunDbMaintenance } from "./db-maintenance.js";
17
16
  import { bootstrapFromHistory } from "./graph/bootstrap.js";
@@ -68,6 +67,8 @@ import {
68
67
  resetRunningJobsToPending,
69
68
  SLOW_LLM_JOB_TYPES,
70
69
  } from "./jobs-store.js";
70
+ import { memoryRetrospectiveJob } from "./memory-retrospective-job.js";
71
+ import { sweepOrphanMemoryRetrospectiveConversations } from "./memory-retrospective-startup-cleanup.js";
71
72
  import { QdrantCircuitOpenError } from "./qdrant-circuit-breaker.js";
72
73
  import {
73
74
  memoryV2ActivationRecomputeJob,
@@ -79,6 +80,26 @@ import { memoryV2SweepJob } from "./v2/sweep-job.js";
79
80
 
80
81
  const log = getLogger("memory-jobs-worker");
81
82
 
83
+ /**
84
+ * V1 job types that read or write the v1 Qdrant collection via
85
+ * `getQdrantClient()`. When `memory.v2.enabled` is true, the v1 client is
86
+ * intentionally left uninitialized in `lifecycle.ts`, so these handlers would
87
+ * throw `BackendUnavailableError` and accumulate as a deferred backlog. Stale
88
+ * rows from indexer.ts and other unguarded enqueue sites must short-circuit
89
+ * here for the same reason `graph_extract` does below.
90
+ */
91
+ const V1_QDRANT_JOB_TYPES = new Set<MemoryJobType>([
92
+ "embed_segment",
93
+ "embed_summary",
94
+ "embed_media",
95
+ "embed_attachment",
96
+ "embed_graph_node",
97
+ "embed_pkb_file",
98
+ "graph_trigger_embed",
99
+ "rebuild_index",
100
+ "delete_qdrant_vectors",
101
+ ]);
102
+
82
103
  /**
83
104
  * Job types whose handlers have been removed. Existing rows may still sit in
84
105
  * the database — the worker completes them silently instead of throwing.
@@ -112,6 +133,19 @@ export function startMemoryJobsWorker(): MemoryJobsWorker {
112
133
  log.info({ recovered }, "Recovered stale running memory jobs");
113
134
  }
114
135
 
136
+ // After running-job recovery (so legitimate in-flight retries aren't
137
+ // swept), clean up orphan memory-retrospective background conversations
138
+ // left behind by daemon crashes mid-job. Best-effort — never block worker
139
+ // startup on cleanup failures.
140
+ try {
141
+ sweepOrphanMemoryRetrospectiveConversations();
142
+ } catch (err) {
143
+ log.warn(
144
+ { err },
145
+ "Memory-retrospective startup cleanup failed; continuing worker startup",
146
+ );
147
+ }
148
+
115
149
  let stopped = false;
116
150
  let tickRunning = false;
117
151
  let timer: ReturnType<typeof setTimeout>;
@@ -125,16 +159,24 @@ export function startMemoryJobsWorker(): MemoryJobsWorker {
125
159
  enableScheduledCleanup: true,
126
160
  });
127
161
  if (processed > 0) {
128
- currentIntervalMs = POLL_INTERVAL_MIN_MS;
162
+ // Per-tick claim budget equals the lane caps, so when a tick
163
+ // processed work the next tick must run immediately to drain any
164
+ // remaining backlog. Holding the 1.5s floor between ticks would cap
165
+ // sustained throughput at lane-cap jobs per 1.5s and starve large
166
+ // backlogs of short jobs.
167
+ currentIntervalMs = 0;
129
168
  } else {
130
169
  currentIntervalMs = Math.min(
131
- currentIntervalMs * 2,
170
+ Math.max(currentIntervalMs * 2, POLL_INTERVAL_MIN_MS),
132
171
  POLL_INTERVAL_MAX_MS,
133
172
  );
134
173
  }
135
174
  } catch (err) {
136
175
  log.error({ err }, "Memory worker tick failed");
137
- currentIntervalMs = Math.min(currentIntervalMs * 2, POLL_INTERVAL_MAX_MS);
176
+ currentIntervalMs = Math.min(
177
+ Math.max(currentIntervalMs * 2, POLL_INTERVAL_MIN_MS),
178
+ POLL_INTERVAL_MAX_MS,
179
+ );
138
180
  } finally {
139
181
  tickRunning = false;
140
182
  }
@@ -463,6 +505,9 @@ async function processJob(
463
505
  job: MemoryJob,
464
506
  config: AssistantConfig,
465
507
  ): Promise<void> {
508
+ if (config.memory.v2.enabled && V1_QDRANT_JOB_TYPES.has(job.type)) {
509
+ return;
510
+ }
466
511
  switch (job.type) {
467
512
  case "embed_segment":
468
513
  await embedSegmentJob(job, config);
@@ -510,6 +555,11 @@ async function processJob(
510
555
  await embedGraphTriggerJob(job, config);
511
556
  return;
512
557
  case "graph_extract":
558
+ // Stale rows enqueued before v2 was enabled (or by any unguarded v1
559
+ // path) must not consume embedding/extraction budget when v2 is on.
560
+ if (config.memory.v2.enabled) {
561
+ return;
562
+ }
513
563
  await graphExtractJob(job, config);
514
564
  return;
515
565
  case "conversation_analyze":
@@ -551,6 +601,9 @@ async function processJob(
551
601
  case "memory_v2_activation_recompute":
552
602
  await memoryV2ActivationRecomputeJob(job, config);
553
603
  return;
604
+ case "memory_retrospective":
605
+ await memoryRetrospectiveJob(job, config);
606
+ return;
554
607
 
555
608
  default: {
556
609
  const rawType = (job as { type: string }).type;
@@ -623,8 +676,8 @@ export const GRAPH_MAINTENANCE_CHECKPOINTS = {
623
676
  * Enqueue periodic graph maintenance jobs.
624
677
  *
625
678
  * Mutually exclusive between v1 and v2:
626
- * - v2 active (both `memory-v2-enabled` flag and `memory.v2.enabled`
627
- * config on) → only `memory_v2_consolidate` is scheduled.
679
+ * - v2 active (`memory.v2.enabled` on) only `memory_v2_consolidate` is
680
+ * scheduled.
628
681
  * - v2 inactive → the four v1 entries (decay, consolidate, pattern_scan,
629
682
  * narrative) are scheduled instead.
630
683
  *
@@ -643,7 +696,7 @@ export function maybeEnqueueGraphMaintenanceJobs(
643
696
  config: AssistantConfig,
644
697
  nowMs = Date.now(),
645
698
  ): void {
646
- const v2Active = isMemoryV2ReadActive(config);
699
+ const v2Active = config.memory.v2.enabled;
647
700
 
648
701
  const schedule: Array<{
649
702
  key: string;