@vellumai/assistant 0.5.15 → 0.6.0

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 (503) hide show
  1. package/ARCHITECTURE.md +3 -3
  2. package/Dockerfile +0 -3
  3. package/docs/architecture/integrations.md +15 -14
  4. package/knip.json +4 -1
  5. package/openapi.yaml +670 -122
  6. package/package.json +1 -1
  7. package/src/__tests__/actor-token-service.test.ts +68 -0
  8. package/src/__tests__/agent-loop.test.ts +0 -32
  9. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  10. package/src/__tests__/anthropic-provider.test.ts +57 -3
  11. package/src/__tests__/app-compiler.test.ts +120 -0
  12. package/src/__tests__/assistant-feature-flags-integration.test.ts +5 -377
  13. package/src/__tests__/call-conversation-messages.test.ts +2 -6
  14. package/src/__tests__/call-domain.test.ts +2 -6
  15. package/src/__tests__/call-pointer-messages.test.ts +2 -14
  16. package/src/__tests__/call-recovery.test.ts +2 -6
  17. package/src/__tests__/call-routes-http.test.ts +2 -6
  18. package/src/__tests__/call-store.test.ts +2 -6
  19. package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -6
  20. package/src/__tests__/canonical-guardian-store.test.ts +2 -6
  21. package/src/__tests__/ces-rpc-credential-backend.test.ts +4 -1
  22. package/src/__tests__/channel-delivery-store.test.ts +2 -6
  23. package/src/__tests__/channel-retry-sweep.test.ts +2 -6
  24. package/src/__tests__/checker.test.ts +84 -3
  25. package/src/__tests__/clawhub.test.ts +54 -24
  26. package/src/__tests__/cli-command-risk-guard.test.ts +108 -6
  27. package/src/__tests__/cli-memory.test.ts +377 -0
  28. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +12 -2
  29. package/src/__tests__/config-schema.test.ts +1 -3
  30. package/src/__tests__/config-set-platform-guard.test.ts +302 -0
  31. package/src/__tests__/config-watcher-feature-flags.test.ts +211 -0
  32. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -6
  33. package/src/__tests__/contacts-tools.test.ts +31 -0
  34. package/src/__tests__/context-overflow-reducer.test.ts +86 -0
  35. package/src/__tests__/context-token-estimator.test.ts +175 -10
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +9 -0
  37. package/src/__tests__/conversation-agent-loop.test.ts +9 -0
  38. package/src/__tests__/conversation-attachments.test.ts +2 -6
  39. package/src/__tests__/conversation-attention-store.test.ts +2 -6
  40. package/src/__tests__/conversation-clear-safety.test.ts +2 -6
  41. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +4 -10
  42. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -6
  43. package/src/__tests__/conversation-disk-view.test.ts +2 -6
  44. package/src/__tests__/conversation-error.test.ts +33 -2
  45. package/src/__tests__/conversation-fork-crud.test.ts +2 -6
  46. package/src/__tests__/conversation-history-web-search.test.ts +5 -0
  47. package/src/__tests__/conversation-load-history-repair.test.ts +5 -1
  48. package/src/__tests__/conversation-media-retry.test.ts +91 -0
  49. package/src/__tests__/conversation-runtime-assembly.test.ts +7 -4
  50. package/src/__tests__/conversation-slash-commands.test.ts +2 -6
  51. package/src/__tests__/conversation-starter-routes.test.ts +20 -11
  52. package/src/__tests__/conversation-store.test.ts +2 -6
  53. package/src/__tests__/conversation-usage.test.ts +3 -6
  54. package/src/__tests__/conversation-wipe.test.ts +11 -408
  55. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
  56. package/src/__tests__/credential-execution-shell-lockdown.test.ts +2 -2
  57. package/src/__tests__/credential-security-e2e.test.ts +6 -1
  58. package/src/__tests__/docker-signing-key-bootstrap.test.ts +7 -73
  59. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -7
  60. package/src/__tests__/followup-tools.test.ts +2 -6
  61. package/src/__tests__/graph-extraction-event-date.test.ts +186 -0
  62. package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -6
  63. package/src/__tests__/guardian-action-followup-executor.test.ts +2 -6
  64. package/src/__tests__/guardian-action-followup-store.test.ts +2 -6
  65. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +2 -6
  66. package/src/__tests__/guardian-action-late-reply.test.ts +2 -6
  67. package/src/__tests__/guardian-action-store.test.ts +2 -6
  68. package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -6
  69. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +8 -8
  70. package/src/__tests__/guardian-dispatch.test.ts +2 -6
  71. package/src/__tests__/guardian-grant-minting.test.ts +2 -14
  72. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -6
  73. package/src/__tests__/guardian-routing-invariants.test.ts +343 -6
  74. package/src/__tests__/guardian-routing-state.test.ts +2 -6
  75. package/src/__tests__/guardian-verification-voice-binding.test.ts +2 -6
  76. package/src/__tests__/heartbeat-service.test.ts +1 -3
  77. package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
  78. package/src/__tests__/injection-block.test.ts +154 -0
  79. package/src/__tests__/install-meta.test.ts +506 -0
  80. package/src/__tests__/install-skill-routing.test.ts +292 -0
  81. package/src/__tests__/intent-routing.test.ts +6 -18
  82. package/src/__tests__/invite-redemption-service.test.ts +2 -6
  83. package/src/__tests__/invite-routes-http.test.ts +2 -6
  84. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -14
  85. package/src/__tests__/list-messages-attachments.test.ts +2 -6
  86. package/src/__tests__/llm-context-route-provider.test.ts +2 -6
  87. package/src/__tests__/llm-request-log-turn-query.test.ts +2 -6
  88. package/src/__tests__/llm-usage-store.test.ts +2 -6
  89. package/src/__tests__/log-export-workspace.test.ts +4 -34
  90. package/src/__tests__/managed-skill-lifecycle.test.ts +7 -37
  91. package/src/__tests__/managed-store.test.ts +40 -21
  92. package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
  93. package/src/__tests__/memory-recall-log-store.test.ts +2 -6
  94. package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
  95. package/src/__tests__/messaging-send-tool.test.ts +6 -6
  96. package/src/__tests__/migration-cross-version-compatibility.test.ts +1 -29
  97. package/src/__tests__/migration-export-http.test.ts +3 -34
  98. package/src/__tests__/migration-import-commit-http.test.ts +1 -29
  99. package/src/__tests__/migration-import-preflight-http.test.ts +3 -34
  100. package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +2 -1
  101. package/src/__tests__/non-member-access-request.test.ts +2 -6
  102. package/src/__tests__/notification-guardian-path.test.ts +2 -6
  103. package/src/__tests__/oauth-apps-routes.test.ts +120 -10
  104. package/src/__tests__/oauth-cli.test.ts +364 -2
  105. package/src/__tests__/oauth-connect-orchestrator.test.ts +709 -0
  106. package/src/__tests__/oauth-provider-serializer.test.ts +2 -1
  107. package/src/__tests__/oauth-provider-visibility.test.ts +149 -0
  108. package/src/__tests__/oauth-providers-routes.test.ts +5 -2
  109. package/src/__tests__/oauth-store.test.ts +0 -5
  110. package/src/__tests__/oauth2-gateway-transport.test.ts +18 -3
  111. package/src/__tests__/outlook-attachments.test.ts +301 -0
  112. package/src/__tests__/outlook-automation-tools.test.ts +425 -0
  113. package/src/__tests__/outlook-categories.test.ts +212 -0
  114. package/src/__tests__/outlook-client-automation.test.ts +246 -0
  115. package/src/__tests__/outlook-compose-tools.test.ts +325 -0
  116. package/src/__tests__/outlook-declutter-tools.test.ts +585 -0
  117. package/src/__tests__/outlook-email-watcher.test.ts +322 -0
  118. package/src/__tests__/outlook-follow-up.test.ts +196 -0
  119. package/src/__tests__/outlook-messaging-provider.test.ts +1071 -0
  120. package/src/__tests__/outlook-trash.test.ts +77 -0
  121. package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
  122. package/src/__tests__/path-policy.test.ts +2 -17
  123. package/src/__tests__/permission-types.test.ts +0 -1
  124. package/src/__tests__/platform-callback-registration.test.ts +7 -11
  125. package/src/__tests__/playbook-execution.test.ts +76 -80
  126. package/src/__tests__/playbook-tools.test.ts +5 -7
  127. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  128. package/src/__tests__/provider-error-scenarios.test.ts +21 -2
  129. package/src/__tests__/qdrant-manager.test.ts +68 -21
  130. package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
  131. package/src/__tests__/registry.test.ts +2 -2
  132. package/src/__tests__/require-fresh-approval.test.ts +64 -3
  133. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
  134. package/src/__tests__/runtime-events-sse.test.ts +2 -6
  135. package/src/__tests__/sandbox-diagnostics.test.ts +20 -29
  136. package/src/__tests__/scaffold-managed-skill-tool.test.ts +2 -10
  137. package/src/__tests__/schedule-store.test.ts +2 -6
  138. package/src/__tests__/schedule-tools.test.ts +2 -6
  139. package/src/__tests__/scheduler-recurrence.test.ts +1 -5
  140. package/src/__tests__/scoped-approval-grants.test.ts +2 -6
  141. package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
  142. package/src/__tests__/search-skills-unified.test.ts +421 -0
  143. package/src/__tests__/secret-allowlist.test.ts +20 -35
  144. package/src/__tests__/secret-onetime-send.test.ts +2 -0
  145. package/src/__tests__/send-endpoint-busy.test.ts +2 -6
  146. package/src/__tests__/sequence-store.test.ts +2 -6
  147. package/src/__tests__/server-history-render.test.ts +2 -6
  148. package/src/__tests__/shell-credential-ref.test.ts +0 -5
  149. package/src/__tests__/skill-feature-flags-integration.test.ts +38 -31
  150. package/src/__tests__/skill-feature-flags.test.ts +6 -6
  151. package/src/__tests__/skill-load-feature-flag.test.ts +13 -54
  152. package/src/__tests__/skill-load-inline-command.test.ts +3 -65
  153. package/src/__tests__/skill-load-inline-includes.test.ts +3 -65
  154. package/src/__tests__/skill-load-tool.test.ts +3 -67
  155. package/src/__tests__/skill-memory.test.ts +480 -195
  156. package/src/__tests__/skills-uninstall.test.ts +2 -2
  157. package/src/__tests__/skills.test.ts +23 -50
  158. package/src/__tests__/slack-channel-config.test.ts +2 -21
  159. package/src/__tests__/slack-inbound-verification.test.ts +2 -6
  160. package/src/__tests__/starter-bundle.test.ts +2 -8
  161. package/src/__tests__/stt-hints.test.ts +7 -2
  162. package/src/__tests__/system-prompt.test.ts +25 -45
  163. package/src/__tests__/task-compiler.test.ts +2 -27
  164. package/src/__tests__/task-management-tools.test.ts +2 -27
  165. package/src/__tests__/task-memory-cleanup.test.ts +173 -250
  166. package/src/__tests__/task-runner.test.ts +2 -27
  167. package/src/__tests__/task-scheduler.test.ts +2 -27
  168. package/src/__tests__/terminal-tools.test.ts +1 -17
  169. package/src/__tests__/test-preload.ts +3 -0
  170. package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +0 -79
  171. package/src/__tests__/tool-approval-handler.test.ts +4 -27
  172. package/src/__tests__/tool-execution-abort-cleanup.test.ts +2 -11
  173. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -25
  174. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  175. package/src/__tests__/tool-executor.test.ts +0 -1
  176. package/src/__tests__/tool-grant-request-escalation.test.ts +4 -27
  177. package/src/__tests__/tool-preview-lifecycle.test.ts +0 -20
  178. package/src/__tests__/tool-side-effects-slack-dm.test.ts +276 -0
  179. package/src/__tests__/trust-store.test.ts +10 -42
  180. package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -30
  181. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +3 -27
  182. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -28
  183. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -28
  184. package/src/__tests__/trusted-contact-verification.test.ts +2 -28
  185. package/src/__tests__/turn-boundary-resolution.test.ts +2 -34
  186. package/src/__tests__/twilio-provider.test.ts +0 -16
  187. package/src/__tests__/twilio-routes-twiml.test.ts +7 -12
  188. package/src/__tests__/twilio-routes.test.ts +0 -24
  189. package/src/__tests__/update-bulletin.test.ts +17 -89
  190. package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -26
  191. package/src/__tests__/usage-routes.test.ts +2 -27
  192. package/src/__tests__/user-reference.test.ts +1 -5
  193. package/src/__tests__/vbundle-pax-and-symlink.test.ts +4 -34
  194. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +2 -53
  195. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  196. package/src/__tests__/voice-invite-redemption.test.ts +2 -27
  197. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -30
  198. package/src/__tests__/voice-session-bridge.test.ts +2 -27
  199. package/src/__tests__/volume-security-guard.test.ts +2 -0
  200. package/src/__tests__/workspace-lifecycle.test.ts +29 -1
  201. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +4 -29
  202. package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +2 -2
  203. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +4 -29
  204. package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
  205. package/src/__tests__/workspace-migration-down-functions.test.ts +0 -6
  206. package/src/__tests__/workspace-policy.test.ts +1 -1
  207. package/src/acp/client-handler.ts +1 -2
  208. package/src/agent/attachments.ts +7 -2
  209. package/src/agent/image-optimize.ts +165 -0
  210. package/src/agent/loop.ts +1 -15
  211. package/src/bundler/app-compiler.ts +179 -2
  212. package/src/bundler/package-resolver.ts +3 -5
  213. package/src/cli/__tests__/notifications.test.ts +1 -24
  214. package/src/cli/cli-memory.ts +179 -0
  215. package/src/cli/commands/avatar.ts +3 -3
  216. package/src/cli/commands/config.ts +26 -13
  217. package/src/cli/commands/doctor.ts +2 -2
  218. package/src/cli/commands/memory.ts +41 -55
  219. package/src/cli/commands/oauth/__tests__/connect.test.ts +2 -2
  220. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +2 -2
  221. package/src/cli/commands/oauth/__tests__/mode.test.ts +8 -1
  222. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
  223. package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
  224. package/src/cli/commands/oauth/connect.ts +26 -6
  225. package/src/cli/commands/oauth/mode.ts +7 -0
  226. package/src/cli/commands/oauth/providers.ts +49 -42
  227. package/src/cli/commands/oauth/shared.ts +39 -3
  228. package/src/cli/commands/platform/__tests__/connect.test.ts +3 -49
  229. package/src/cli/commands/platform/__tests__/disconnect.test.ts +3 -49
  230. package/src/cli/commands/platform/__tests__/status.test.ts +5 -55
  231. package/src/cli/commands/platform/index.ts +16 -16
  232. package/src/cli/commands/skills.ts +88 -16
  233. package/src/cli/commands/trust.ts +2 -2
  234. package/src/cli/lib/daemon-credential-client.ts +2 -3
  235. package/src/config/bundled-skills/acp/TOOLS.json +1 -1
  236. package/src/config/bundled-skills/computer-use/TOOLS.json +7 -7
  237. package/src/config/bundled-skills/contacts/SKILL.md +0 -1
  238. package/src/config/bundled-skills/contacts/TOOLS.json +0 -8
  239. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -4
  240. package/src/config/bundled-skills/gmail/SKILL.md +2 -10
  241. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
  242. package/src/config/bundled-skills/messaging/SKILL.md +26 -19
  243. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +40 -33
  244. package/src/config/bundled-skills/outlook/SKILL.md +189 -0
  245. package/src/config/bundled-skills/outlook/TOOLS.json +530 -0
  246. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +85 -0
  247. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +77 -0
  248. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +84 -0
  249. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +94 -0
  250. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +49 -0
  251. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +237 -0
  252. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +161 -0
  253. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +32 -0
  254. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +272 -0
  255. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +29 -0
  256. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +129 -0
  257. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +87 -0
  258. package/src/config/bundled-skills/outlook/tools/shared.ts +20 -0
  259. package/src/config/bundled-skills/outlook-calendar/SKILL.md +51 -0
  260. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +221 -0
  261. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +252 -0
  262. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +53 -0
  263. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +74 -0
  264. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +18 -0
  265. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +46 -0
  266. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +36 -0
  267. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +17 -0
  268. package/src/config/bundled-skills/outlook-calendar/types.ts +120 -0
  269. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +47 -40
  270. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +16 -29
  271. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +16 -18
  272. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +39 -47
  273. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  274. package/src/config/bundled-skills/slack/SKILL.md +1 -7
  275. package/src/config/bundled-tool-registry.ts +56 -4
  276. package/src/config/env-registry.ts +15 -8
  277. package/src/config/feature-flag-registry.json +29 -116
  278. package/src/config/loader.ts +4 -0
  279. package/src/config/schemas/platform.ts +8 -0
  280. package/src/config/schemas/security.ts +0 -6
  281. package/src/config/schemas/services.ts +8 -0
  282. package/src/config/schemas/timeouts.ts +1 -1
  283. package/src/config/skills.ts +18 -7
  284. package/src/context/token-estimator.ts +25 -18
  285. package/src/context/window-manager.ts +32 -9
  286. package/src/credential-execution/approval-bridge.ts +0 -1
  287. package/src/credential-execution/process-manager.ts +3 -1
  288. package/src/daemon/config-watcher.ts +51 -0
  289. package/src/daemon/context-overflow-reducer.ts +46 -2
  290. package/src/daemon/conversation-agent-loop-handlers.ts +123 -82
  291. package/src/daemon/conversation-agent-loop.ts +99 -63
  292. package/src/daemon/conversation-error.ts +31 -8
  293. package/src/daemon/conversation-lifecycle.ts +33 -0
  294. package/src/daemon/conversation-media-retry.ts +85 -7
  295. package/src/daemon/conversation-notifiers.ts +4 -1
  296. package/src/daemon/conversation-process.ts +1 -0
  297. package/src/daemon/conversation-runtime-assembly.ts +5 -0
  298. package/src/daemon/conversation-usage.ts +1 -0
  299. package/src/daemon/conversation.ts +41 -2
  300. package/src/daemon/daemon-control.ts +8 -2
  301. package/src/daemon/handlers/shared.ts +22 -12
  302. package/src/daemon/handlers/skills.ts +423 -201
  303. package/src/daemon/lifecycle.ts +52 -4
  304. package/src/daemon/main.ts +5 -1
  305. package/src/daemon/message-types/conversations.ts +5 -1
  306. package/src/daemon/message-types/messages.ts +3 -1
  307. package/src/daemon/message-types/skills.ts +97 -36
  308. package/src/daemon/providers-setup.ts +7 -0
  309. package/src/daemon/server.ts +35 -22
  310. package/src/daemon/tool-side-effects.ts +27 -5
  311. package/src/events/domain-events.ts +1 -2
  312. package/src/heartbeat/heartbeat-service.ts +1 -0
  313. package/src/hooks/cli.ts +2 -2
  314. package/src/hooks/runner.ts +15 -38
  315. package/src/inbound/platform-callback-registration.ts +14 -14
  316. package/src/memory/admin.ts +11 -45
  317. package/src/memory/conversation-bootstrap.ts +2 -0
  318. package/src/memory/conversation-crud.ts +242 -348
  319. package/src/memory/conversation-group-migration.ts +157 -0
  320. package/src/memory/conversation-queries.ts +4 -2
  321. package/src/memory/db-init.ts +39 -3
  322. package/src/memory/embed.ts +73 -0
  323. package/src/memory/embedding-backend.ts +8 -14
  324. package/src/memory/embedding-runtime-manager.ts +12 -114
  325. package/src/memory/fingerprint.ts +2 -2
  326. package/src/memory/graph/bootstrap.ts +512 -0
  327. package/src/memory/graph/capability-seed.ts +297 -0
  328. package/src/memory/graph/consolidation.ts +691 -0
  329. package/src/memory/graph/conversation-graph-memory.ts +630 -0
  330. package/src/memory/graph/decay.test.ts +208 -0
  331. package/src/memory/graph/decay.ts +195 -0
  332. package/src/memory/graph/extraction-job.ts +69 -0
  333. package/src/memory/graph/extraction.test.ts +936 -0
  334. package/src/memory/graph/extraction.ts +1254 -0
  335. package/src/memory/graph/graph-search.ts +266 -0
  336. package/src/memory/graph/image-ref-utils.ts +29 -0
  337. package/src/memory/graph/injection.test.ts +513 -0
  338. package/src/memory/graph/injection.ts +439 -0
  339. package/src/memory/graph/inspect.ts +534 -0
  340. package/src/memory/graph/narrative.ts +267 -0
  341. package/src/memory/graph/pattern-scan.ts +269 -0
  342. package/src/memory/graph/retriever.ts +1008 -0
  343. package/src/memory/graph/scoring.test.ts +548 -0
  344. package/src/memory/graph/scoring.ts +232 -0
  345. package/src/memory/graph/serendipity.ts +65 -0
  346. package/src/memory/graph/store.test.ts +1050 -0
  347. package/src/memory/graph/store.ts +699 -0
  348. package/src/memory/graph/tool-handlers.ts +426 -0
  349. package/src/memory/graph/tools.ts +141 -0
  350. package/src/memory/graph/triggers.test.ts +487 -0
  351. package/src/memory/graph/triggers.ts +223 -0
  352. package/src/memory/graph/types.ts +271 -0
  353. package/src/memory/group-crud.ts +191 -0
  354. package/src/memory/indexer.ts +37 -19
  355. package/src/memory/job-handlers/cleanup.ts +0 -53
  356. package/src/memory/job-handlers/conversation-starters.ts +91 -53
  357. package/src/memory/job-handlers/embedding.test.ts +3 -27
  358. package/src/memory/job-handlers/embedding.ts +5 -31
  359. package/src/memory/job-handlers/index-maintenance.ts +23 -11
  360. package/src/memory/job-handlers/summarization.ts +32 -17
  361. package/src/memory/job-utils.ts +1 -1
  362. package/src/memory/jobs-store.ts +50 -70
  363. package/src/memory/jobs-worker.ts +147 -112
  364. package/src/memory/llm-usage-store.ts +35 -2
  365. package/src/memory/message-content.ts +1 -0
  366. package/src/memory/migrations/201-oauth-providers-feature-flag.ts +11 -0
  367. package/src/memory/migrations/202-drop-callback-transport-column.ts +13 -0
  368. package/src/memory/migrations/202-memory-graph-tables.ts +130 -0
  369. package/src/memory/migrations/203-drop-memory-items-tables.ts +23 -0
  370. package/src/memory/migrations/204-rename-memory-graph-type-values.ts +46 -0
  371. package/src/memory/migrations/205-memory-graph-image-refs.ts +11 -0
  372. package/src/memory/migrations/index.ts +6 -0
  373. package/src/memory/migrations/registry.ts +8 -0
  374. package/src/memory/qdrant-client.ts +44 -17
  375. package/src/memory/qdrant-manager.ts +26 -5
  376. package/src/memory/schema/index.ts +1 -0
  377. package/src/memory/schema/memory-graph.ts +139 -0
  378. package/src/memory/schema/oauth.ts +1 -1
  379. package/src/memory/search/semantic.ts +47 -91
  380. package/src/memory/slack-thread-store.ts +17 -0
  381. package/src/memory/task-memory-cleanup.ts +28 -50
  382. package/src/messaging/providers/outlook/adapter.ts +200 -0
  383. package/src/messaging/providers/outlook/client.ts +610 -0
  384. package/src/messaging/providers/outlook/types.ts +201 -0
  385. package/src/notifications/adapters/macos.ts +1 -0
  386. package/src/notifications/adapters/slack.ts +1 -1
  387. package/src/notifications/copy-composer.ts +9 -0
  388. package/src/notifications/signal.ts +16 -0
  389. package/src/oauth/__tests__/identity-verifier.test.ts +1 -1
  390. package/src/oauth/connect-orchestrator.ts +10 -3
  391. package/src/oauth/oauth-store.ts +10 -11
  392. package/src/oauth/provider-serializer.ts +3 -0
  393. package/src/oauth/provider-visibility.ts +16 -0
  394. package/src/oauth/seed-providers.ts +50 -17
  395. package/src/permissions/checker.ts +62 -9
  396. package/src/permissions/defaults.ts +4 -4
  397. package/src/permissions/types.ts +2 -4
  398. package/src/permissions/workspace-policy.ts +1 -1
  399. package/src/playbooks/playbook-compiler.ts +19 -18
  400. package/src/playbooks/types.ts +4 -3
  401. package/src/prompts/system-prompt.ts +6 -93
  402. package/src/prompts/templates/UPDATES.md +6 -0
  403. package/src/providers/anthropic/client.ts +47 -19
  404. package/src/providers/gemini/client.ts +1 -1
  405. package/src/providers/openai/client.ts +1 -1
  406. package/src/providers/registry.ts +1 -1
  407. package/src/providers/retry.ts +19 -3
  408. package/src/runtime/actor-trust-resolver.ts +5 -1
  409. package/src/runtime/auth/__tests__/credential-service.test.ts +1 -27
  410. package/src/runtime/auth/__tests__/token-service.test.ts +1 -25
  411. package/src/runtime/auth/route-policy.ts +7 -4
  412. package/src/runtime/guardian-reply-router.ts +10 -2
  413. package/src/runtime/http-server.ts +23 -3
  414. package/src/runtime/middleware/auth.ts +20 -0
  415. package/src/runtime/routes/attachment-routes.test.ts +106 -0
  416. package/src/runtime/routes/attachment-routes.ts +106 -16
  417. package/src/runtime/routes/brain-graph-routes.ts +21 -22
  418. package/src/runtime/routes/btw-routes.ts +8 -0
  419. package/src/runtime/routes/conversation-management-routes.ts +2 -0
  420. package/src/runtime/routes/conversation-query-routes.ts +2 -58
  421. package/src/runtime/routes/conversation-starter-routes.ts +2 -2
  422. package/src/runtime/routes/debug-routes.ts +1 -1
  423. package/src/runtime/routes/global-search-routes.ts +21 -19
  424. package/src/runtime/routes/group-routes.ts +207 -0
  425. package/src/runtime/routes/guardian-action-routes.ts +21 -10
  426. package/src/runtime/routes/guardian-bootstrap-routes.ts +23 -19
  427. package/src/runtime/routes/inbound-message-handler.ts +19 -0
  428. package/src/runtime/routes/inbound-stages/background-dispatch.ts +43 -2
  429. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +292 -0
  430. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +207 -0
  431. package/src/runtime/routes/memory-item-routes.test.ts +2 -31
  432. package/src/runtime/routes/memory-item-routes.ts +385 -341
  433. package/src/runtime/routes/oauth-apps.ts +18 -1
  434. package/src/runtime/routes/oauth-providers.ts +13 -1
  435. package/src/runtime/routes/schedule-routes.ts +2 -0
  436. package/src/runtime/routes/settings-routes.ts +1 -0
  437. package/src/runtime/routes/skills-routes.ts +103 -37
  438. package/src/runtime/routes/usage-routes.ts +19 -2
  439. package/src/runtime/routes/work-items-routes.test.ts +2 -27
  440. package/src/runtime/routes/workspace-routes.test.ts +3 -27
  441. package/src/schedule/scheduler.ts +8 -1
  442. package/src/security/oauth2.ts +1 -1
  443. package/src/security/secret-allowlist.ts +4 -4
  444. package/src/security/secure-keys.ts +4 -8
  445. package/src/shared/provider-env-vars.ts +19 -0
  446. package/src/skills/catalog-cache.ts +5 -0
  447. package/src/skills/catalog-install.ts +15 -14
  448. package/src/skills/clawhub.ts +134 -154
  449. package/src/skills/install-meta.ts +208 -0
  450. package/src/skills/managed-store.ts +27 -16
  451. package/src/skills/skill-memory.ts +210 -96
  452. package/src/skills/skillssh-registry.ts +19 -17
  453. package/src/tasks/task-runner.ts +3 -1
  454. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
  455. package/src/tools/browser/runtime-check.ts +3 -1
  456. package/src/tools/memory/register.ts +63 -46
  457. package/src/tools/permission-checker.ts +7 -19
  458. package/src/tools/shared/filesystem/image-read.ts +22 -85
  459. package/src/tools/skills/skill-script-runner.ts +1 -1
  460. package/src/tools/terminal/safe-env.ts +1 -0
  461. package/src/tools/tool-manifest.ts +3 -3
  462. package/src/util/browser.ts +25 -10
  463. package/src/util/bun-runtime.ts +172 -0
  464. package/src/util/device-id.ts +3 -65
  465. package/src/watcher/providers/outlook-calendar.ts +343 -0
  466. package/src/watcher/providers/outlook.ts +198 -0
  467. package/src/workspace/git-service.ts +27 -6
  468. package/src/workspace/migrations/025-remove-oauth-app-setup-skills.ts +76 -0
  469. package/src/workspace/migrations/026-backfill-install-meta.ts +325 -0
  470. package/src/workspace/migrations/027-remove-orphaned-optimized-images-cache.ts +42 -0
  471. package/src/workspace/migrations/registry.ts +6 -0
  472. package/src/__tests__/context-memory-e2e.test.ts +0 -415
  473. package/src/__tests__/journal-context.test.ts +0 -268
  474. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -297
  475. package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -459
  476. package/src/__tests__/memory-query-builder.test.ts +0 -59
  477. package/src/__tests__/memory-recall-quality.test.ts +0 -1046
  478. package/src/__tests__/memory-regressions.experimental.test.ts +0 -629
  479. package/src/__tests__/memory-regressions.test.ts +0 -3696
  480. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -295
  481. package/src/daemon/conversation-memory.ts +0 -207
  482. package/src/memory/conversation-starters-cadence.ts +0 -74
  483. package/src/memory/items-extractor.ts +0 -860
  484. package/src/memory/job-handlers/batch-extraction.ts +0 -741
  485. package/src/memory/job-handlers/extraction.ts +0 -40
  486. package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -383
  487. package/src/memory/job-handlers/journal-carry-forward.ts +0 -255
  488. package/src/memory/journal-memory.ts +0 -224
  489. package/src/memory/query-builder.ts +0 -47
  490. package/src/memory/query-expansion.ts +0 -83
  491. package/src/memory/retriever.test.ts +0 -1590
  492. package/src/memory/retriever.ts +0 -1323
  493. package/src/memory/search/formatting.test.ts +0 -140
  494. package/src/memory/search/formatting.ts +0 -262
  495. package/src/memory/search/mmr.ts +0 -136
  496. package/src/memory/search/ranking.ts +0 -15
  497. package/src/memory/search/staleness.ts +0 -40
  498. package/src/memory/search/tier-classifier.ts +0 -18
  499. package/src/memory/search/types.ts +0 -121
  500. package/src/prompts/journal-context.ts +0 -156
  501. package/src/tools/memory/definitions.ts +0 -69
  502. package/src/tools/memory/handlers.test.ts +0 -590
  503. package/src/tools/memory/handlers.ts +0 -434
@@ -0,0 +1,512 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Memory Graph — Bootstrap from historical conversations
3
+ //
4
+ // Re-extracts all historical conversations into the graph from scratch.
5
+ // Processes conversations chronologically so reinforcements, edges, and
6
+ // patterns build up naturally — the graph represents what the system
7
+ // WOULD have produced if running from the start.
8
+ //
9
+ // Checkpointed and resumable. Progress tracked via memory_checkpoints.
10
+ // ---------------------------------------------------------------------------
11
+
12
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
13
+ import { join } from "node:path";
14
+
15
+ import { and, asc, ne, sql } from "drizzle-orm";
16
+
17
+ import { getConfig } from "../../config/loader.js";
18
+ import { getLogger } from "../../util/logger.js";
19
+ import { getWorkspaceDir } from "../../util/platform.js";
20
+ import { getMemoryCheckpoint, setMemoryCheckpoint } from "../checkpoints.js";
21
+ import { getDb, rawAll } from "../db.js";
22
+ import { enqueueMemoryJob, hasActiveJobOfType } from "../jobs-store.js";
23
+ import { initQdrantClient } from "../qdrant-client.js";
24
+ import { conversations, memoryGraphNodes, memorySegments } from "../schema.js";
25
+ import { runGraphExtraction } from "./extraction.js";
26
+ import { countNodes, createNode } from "./store.js";
27
+ import type { NewNode } from "./types.js";
28
+
29
+ const log = getLogger("graph-bootstrap");
30
+
31
+ const CHECKPOINT_KEY = "graph_bootstrap:last_conversation_id";
32
+
33
+ export interface BootstrapOptions {
34
+ scopeId?: string;
35
+ /** Skip conversations created before this epoch ms. */
36
+ after?: number;
37
+ /** Maximum conversations to process (for testing). */
38
+ limit?: number;
39
+ /** Log progress every N conversations. */
40
+ progressInterval?: number;
41
+ /** If true, just report what would be done without executing. */
42
+ dryRun?: boolean;
43
+ }
44
+
45
+ export interface BootstrapResult {
46
+ conversationsProcessed: number;
47
+ conversationsSkipped: number;
48
+ totalNodesCreated: number;
49
+ totalNodesUpdated: number;
50
+ totalNodesReinforced: number;
51
+ totalEdgesCreated: number;
52
+ totalTriggersCreated: number;
53
+ errors: Array<{ conversationId: string; error: string }>;
54
+ elapsedMs: number;
55
+ }
56
+
57
+ /**
58
+ * Re-extract all historical conversations into the memory graph.
59
+ *
60
+ * Processes conversations chronologically. Resumable via checkpoint —
61
+ * if interrupted, re-run and it picks up where it left off.
62
+ */
63
+ export async function bootstrapFromHistory(
64
+ options?: BootstrapOptions
65
+ ): Promise<BootstrapResult> {
66
+ const start = Date.now();
67
+ const scopeId = options?.scopeId ?? "default";
68
+ const progressInterval = options?.progressInterval ?? 25;
69
+ const config = getConfig();
70
+
71
+ // Initialize Qdrant client for inline embedding
72
+ try {
73
+ initQdrantClient({
74
+ url: config.memory.qdrant.url ?? "http://127.0.0.1:6333",
75
+ collection: config.memory.qdrant.collection,
76
+ vectorSize: config.memory.qdrant.vectorSize,
77
+ onDisk: config.memory.qdrant.onDisk ?? true,
78
+ quantization: config.memory.qdrant.quantization ?? "none",
79
+ });
80
+ } catch {
81
+ // May already be initialized
82
+ }
83
+
84
+ const result: BootstrapResult = {
85
+ conversationsProcessed: 0,
86
+ conversationsSkipped: 0,
87
+ totalNodesCreated: 0,
88
+ totalNodesUpdated: 0,
89
+ totalNodesReinforced: 0,
90
+ totalEdgesCreated: 0,
91
+ totalTriggersCreated: 0,
92
+ errors: [],
93
+ elapsedMs: 0,
94
+ };
95
+
96
+ // Load all conversations, ordered chronologically
97
+ const db = getDb();
98
+ const allConversations = db
99
+ .select({
100
+ id: conversations.id,
101
+ createdAt: conversations.createdAt,
102
+ })
103
+ .from(conversations)
104
+ .orderBy(asc(conversations.createdAt))
105
+ .all();
106
+
107
+ log.info(
108
+ { total: allConversations.length },
109
+ "Starting graph bootstrap from historical conversations"
110
+ );
111
+
112
+ // Resume from checkpoint
113
+ const lastProcessedId = getMemoryCheckpoint(CHECKPOINT_KEY);
114
+ let foundCheckpoint = !lastProcessedId; // If no checkpoint, start from beginning
115
+
116
+ for (const conv of allConversations) {
117
+ // Skip until we pass the checkpoint
118
+ if (!foundCheckpoint) {
119
+ if (conv.id === lastProcessedId) {
120
+ foundCheckpoint = true;
121
+ }
122
+ result.conversationsSkipped++;
123
+ continue;
124
+ }
125
+
126
+ // Apply filters
127
+ if (options?.after && conv.createdAt < options.after) {
128
+ result.conversationsSkipped++;
129
+ continue;
130
+ }
131
+
132
+ if (options?.limit && result.conversationsProcessed >= options.limit) {
133
+ break;
134
+ }
135
+
136
+ if (options?.dryRun) {
137
+ result.conversationsProcessed++;
138
+ continue;
139
+ }
140
+
141
+ // Process this conversation
142
+ try {
143
+ const extractionResult = await runGraphExtraction(
144
+ conv.id,
145
+ scopeId,
146
+ config,
147
+ {
148
+ skipQdrant: true, // Use DB query for candidates (no Qdrant dependency)
149
+ conversationTimestamp: conv.createdAt, // Use actual conversation time
150
+ embedInline: true, // Embed synchronously so nodes are searchable immediately
151
+ }
152
+ );
153
+
154
+ result.totalNodesCreated += extractionResult.nodesCreated;
155
+ result.totalNodesUpdated += extractionResult.nodesUpdated;
156
+ result.totalNodesReinforced += extractionResult.nodesReinforced;
157
+ result.totalEdgesCreated += extractionResult.edgesCreated;
158
+ result.totalTriggersCreated += extractionResult.triggersCreated;
159
+ result.conversationsProcessed++;
160
+
161
+ // Update checkpoint after each successful extraction
162
+ setMemoryCheckpoint(CHECKPOINT_KEY, conv.id);
163
+
164
+ // Progress logging
165
+ if (result.conversationsProcessed % progressInterval === 0) {
166
+ const nodeCount = countNodes(scopeId);
167
+ log.info(
168
+ {
169
+ processed: result.conversationsProcessed,
170
+ total: allConversations.length - result.conversationsSkipped,
171
+ nodes: nodeCount,
172
+ elapsed: `${((Date.now() - start) / 1000).toFixed(1)}s`,
173
+ },
174
+ "Bootstrap progress"
175
+ );
176
+ }
177
+ } catch (err) {
178
+ const errMsg = err instanceof Error ? err.message : String(err);
179
+ log.warn(
180
+ { conversationId: conv.id, err: errMsg },
181
+ "Failed to extract conversation, continuing"
182
+ );
183
+ result.errors.push({ conversationId: conv.id, error: errMsg });
184
+
185
+ // Still checkpoint — don't re-process failed conversations
186
+ setMemoryCheckpoint(CHECKPOINT_KEY, conv.id);
187
+ }
188
+ }
189
+
190
+ result.elapsedMs = Date.now() - start;
191
+
192
+ log.info(
193
+ {
194
+ conversationsProcessed: result.conversationsProcessed,
195
+ conversationsSkipped: result.conversationsSkipped,
196
+ totalNodesCreated: result.totalNodesCreated,
197
+ totalEdgesCreated: result.totalEdgesCreated,
198
+ totalTriggersCreated: result.totalTriggersCreated,
199
+ errors: result.errors.length,
200
+ elapsedMs: result.elapsedMs,
201
+ },
202
+ "Graph bootstrap complete"
203
+ );
204
+
205
+ return result;
206
+ }
207
+
208
+ /**
209
+ * Also extract from journal files on disk.
210
+ */
211
+ export async function bootstrapFromJournal(
212
+ scopeId: string = "default"
213
+ ): Promise<{ extracted: number; errors: number }> {
214
+ const config = getConfig();
215
+ const journalDir = join(getWorkspaceDir(), "journal");
216
+ let extracted = 0;
217
+ let errors = 0;
218
+
219
+ if (!existsSync(journalDir)) return { extracted, errors };
220
+
221
+ // Iterate user slug directories
222
+ for (const slug of readdirSync(journalDir)) {
223
+ const slugDir = join(journalDir, slug);
224
+ let files: string[];
225
+ try {
226
+ files = readdirSync(slugDir).filter(
227
+ (f) =>
228
+ f.endsWith(".md") &&
229
+ !f.startsWith(".") &&
230
+ f.toLowerCase() !== "readme.md"
231
+ );
232
+ } catch {
233
+ continue;
234
+ }
235
+
236
+ for (const file of files) {
237
+ try {
238
+ const content = readFileSync(join(slugDir, file), "utf-8");
239
+ if (content.trim().length < 50) continue;
240
+
241
+ const transcript = `[journal entry: ${file}]\n\n${content}`;
242
+ const journalTimestamp = parseJournalDate(file);
243
+ await runGraphExtraction(`journal:${slug}:${file}`, scopeId, config, {
244
+ transcript,
245
+ conversationTimestamp: journalTimestamp,
246
+ });
247
+ extracted++;
248
+ } catch (err) {
249
+ log.warn(
250
+ { file, slug, err: err instanceof Error ? err.message : String(err) },
251
+ "Failed to extract journal entry"
252
+ );
253
+ errors++;
254
+ }
255
+ }
256
+ }
257
+
258
+ return { extracted, errors };
259
+ }
260
+
261
+ /**
262
+ * Parse a date from a journal filename like "2026-03-30-0045.md" or "2026-03-28-early.md".
263
+ * Returns epoch ms, defaulting to noon on the parsed date.
264
+ * Falls back to Date.now() if unparseable.
265
+ */
266
+ function parseJournalDate(filename: string): number {
267
+ const match = filename.match(/^(\d{4})-(\d{2})-(\d{2})/);
268
+ if (!match) return Date.now();
269
+
270
+ const [, year, month, day] = match;
271
+ // Check for a time-like suffix (e.g. "0045" → 00:45)
272
+ const timeMatch = filename.match(/^\d{4}-\d{2}-\d{2}-(\d{4})\./);
273
+ let hours = 12;
274
+ let minutes = 0;
275
+ if (timeMatch) {
276
+ hours = parseInt(timeMatch[1].slice(0, 2), 10);
277
+ minutes = parseInt(timeMatch[1].slice(2), 10);
278
+ } else if (filename.includes("dawn")) {
279
+ hours = 6;
280
+ } else if (filename.includes("early")) {
281
+ hours = 5;
282
+ } else if (
283
+ filename.includes("night") ||
284
+ filename.includes("midnight") ||
285
+ filename.includes("late")
286
+ ) {
287
+ hours = 23;
288
+ }
289
+
290
+ return new Date(
291
+ `${year}-${month}-${day}T${String(hours).padStart(2, "0")}:${String(
292
+ minutes
293
+ ).padStart(2, "0")}:00`
294
+ ).getTime();
295
+ }
296
+
297
+ /**
298
+ * Reset the bootstrap checkpoint so it can be re-run from scratch.
299
+ */
300
+ export function resetBootstrapCheckpoint(): void {
301
+ setMemoryCheckpoint(CHECKPOINT_KEY, "");
302
+ }
303
+
304
+ /**
305
+ * Enqueue a graph_bootstrap job if the graph is empty (no non-procedural nodes)
306
+ * but historical data exists (segments or journal files). Called on daemon startup
307
+ * to auto-populate the graph for users upgrading from the old extraction system.
308
+ *
309
+ * Idempotent: does nothing if graph nodes already exist or a bootstrap job is
310
+ * already pending/running.
311
+ */
312
+ export function maybeEnqueueGraphBootstrap(): void {
313
+ const db = getDb();
314
+
315
+ // Check for non-procedural graph nodes (procedural = capability seeds, not real memories)
316
+ const nonProceduralCount =
317
+ db
318
+ .select({ count: sql<number>`count(*)` })
319
+ .from(memoryGraphNodes)
320
+ .where(
321
+ and(
322
+ ne(memoryGraphNodes.type, "procedural"),
323
+ sql`${memoryGraphNodes.fidelity} != 'gone'`
324
+ )
325
+ )
326
+ .get()?.count ?? 0;
327
+
328
+ if (nonProceduralCount > 0) return; // Graph already populated
329
+
330
+ // Check for historical data to bootstrap from
331
+ const segmentCount =
332
+ db
333
+ .select({ count: sql<number>`count(*)` })
334
+ .from(memorySegments)
335
+ .get()?.count ?? 0;
336
+
337
+ const hasJournalFiles = existsSync(join(getWorkspaceDir(), "journal"));
338
+
339
+ if (segmentCount === 0 && !hasJournalFiles) return; // Nothing to bootstrap from
340
+
341
+ // Don't enqueue if already in progress
342
+ if (hasActiveJobOfType("graph_bootstrap")) return;
343
+
344
+ log.info(
345
+ { segmentCount, hasJournalFiles },
346
+ "Graph empty with historical data — enqueueing bootstrap"
347
+ );
348
+ enqueueMemoryJob("graph_bootstrap", {});
349
+ }
350
+
351
+ // ---------------------------------------------------------------------------
352
+ // One-time migration: port tool-created memoryItems to graph nodes
353
+ // ---------------------------------------------------------------------------
354
+
355
+ const MIGRATE_ITEMS_CHECKPOINT = "graph_bootstrap:migrated_tool_items";
356
+
357
+ interface LegacyItem {
358
+ id: string;
359
+ kind: string;
360
+ subject: string;
361
+ statement: string;
362
+ confidence: number;
363
+ importance: number;
364
+ scope_id: string;
365
+ first_seen_at: number;
366
+ }
367
+
368
+ /** Source prefix mapping from old kind to new sourceConversations key. */
369
+ const KIND_TO_PREFIX: Record<string, string> = {
370
+ playbook: "playbook:",
371
+ style: "style:",
372
+ relationship: "relationship:",
373
+ };
374
+
375
+ /**
376
+ * Migrate tool-created memoryItems (playbooks, style patterns, relationship
377
+ * dynamics) into graph nodes. These were created directly by tool handlers
378
+ * and won't be picked up by the conversation-based graph bootstrap.
379
+ *
380
+ * Idempotent: uses a checkpoint to run only once. Skips items whose
381
+ * sourceKey already exists in the graph.
382
+ */
383
+ export function migrateToolCreatedItems(): void {
384
+ if (getMemoryCheckpoint(MIGRATE_ITEMS_CHECKPOINT)) return;
385
+
386
+ const kinds = Object.keys(KIND_TO_PREFIX);
387
+ const placeholders = kinds.map(() => "?").join(", ");
388
+
389
+ let rows: LegacyItem[];
390
+ try {
391
+ rows = rawAll<LegacyItem>(
392
+ `SELECT id, kind, subject, statement, confidence, importance, scope_id, first_seen_at
393
+ FROM memory_items
394
+ WHERE kind IN (${placeholders}) AND status = 'active'`,
395
+ ...kinds
396
+ );
397
+ } catch {
398
+ // Table may not exist (fresh install) — nothing to migrate
399
+ setMemoryCheckpoint(MIGRATE_ITEMS_CHECKPOINT, "done");
400
+ return;
401
+ }
402
+
403
+ if (rows.length === 0) {
404
+ setMemoryCheckpoint(MIGRATE_ITEMS_CHECKPOINT, "done");
405
+ return;
406
+ }
407
+
408
+ const db = getDb();
409
+ let migrated = 0;
410
+
411
+ for (const row of rows) {
412
+ const prefix = KIND_TO_PREFIX[row.kind];
413
+ if (!prefix) continue;
414
+
415
+ // Build content in the format the new tools expect
416
+ const content =
417
+ row.kind === "playbook"
418
+ ? `${row.subject}\n${row.statement}`
419
+ : `${row.subject}: ${row.statement}`;
420
+
421
+ // Check if already migrated (sourceKey exists in graph)
422
+ const sourceKey = `${prefix}${row.id}`;
423
+ const existing = db
424
+ .select({ id: memoryGraphNodes.id })
425
+ .from(memoryGraphNodes)
426
+ .where(
427
+ sql`${memoryGraphNodes.sourceConversations} LIKE ${
428
+ "%" + sourceKey + "%"
429
+ }`
430
+ )
431
+ .get();
432
+ if (existing) continue;
433
+
434
+ const now = Date.now();
435
+ const node: NewNode = {
436
+ content,
437
+ type: "semantic",
438
+ created: row.first_seen_at || now,
439
+ lastAccessed: now,
440
+ lastConsolidated: now,
441
+ eventDate: null,
442
+ emotionalCharge: {
443
+ valence: 0,
444
+ intensity: 0.1,
445
+ decayCurve: "linear",
446
+ decayRate: 0.05,
447
+ originalIntensity: 0.1,
448
+ },
449
+ fidelity: "vivid",
450
+ confidence: row.confidence,
451
+ significance: row.importance,
452
+ stability: 14,
453
+ reinforcementCount: 0,
454
+ lastReinforced: now,
455
+ sourceConversations: [sourceKey],
456
+ sourceType: "direct",
457
+ narrativeRole: null,
458
+ partOfStory: null,
459
+ imageRefs: null,
460
+ scopeId: row.scope_id || "default",
461
+ };
462
+
463
+ const created = createNode(node);
464
+ enqueueMemoryJob("embed_graph_node", { nodeId: created.id });
465
+ migrated++;
466
+ }
467
+
468
+ setMemoryCheckpoint(MIGRATE_ITEMS_CHECKPOINT, "done");
469
+
470
+ if (migrated > 0) {
471
+ log.info(
472
+ { migrated, total: rows.length },
473
+ "Migrated tool-created items to graph nodes"
474
+ );
475
+ }
476
+ }
477
+
478
+ // ---------------------------------------------------------------------------
479
+ // One-time cleanup: remove stale Qdrant vectors with target_type "item"
480
+ // ---------------------------------------------------------------------------
481
+
482
+ const CLEANUP_ITEM_VECTORS_CHECKPOINT = "graph_bootstrap:cleaned_item_vectors";
483
+
484
+ /**
485
+ * Delete Qdrant vectors with target_type "item" left over from the legacy
486
+ * memory_items system. The backing SQLite rows have been dropped (migration
487
+ * 203), so these vectors are orphaned and waste index space.
488
+ *
489
+ * Checkpoint-gated: runs exactly once per workspace.
490
+ */
491
+ export async function cleanupStaleItemVectors(): Promise<void> {
492
+ if (getMemoryCheckpoint(CLEANUP_ITEM_VECTORS_CHECKPOINT)) return;
493
+
494
+ let qdrant;
495
+ try {
496
+ qdrant = (await import("../qdrant-client.js")).getQdrantClient();
497
+ } catch {
498
+ // Qdrant not initialized yet — skip; will run on next startup.
499
+ return;
500
+ }
501
+
502
+ try {
503
+ await qdrant.deleteByTargetType("item");
504
+ setMemoryCheckpoint(CLEANUP_ITEM_VECTORS_CHECKPOINT, "done");
505
+ log.info("Cleaned up stale Qdrant vectors with target_type 'item'");
506
+ } catch (err) {
507
+ log.warn(
508
+ { err: err instanceof Error ? err.message : String(err) },
509
+ "Failed to clean up stale item vectors — will retry on next startup"
510
+ );
511
+ }
512
+ }