@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,699 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Memory Graph — Data access layer
3
+ // ---------------------------------------------------------------------------
4
+
5
+ import { and, eq, inArray, sql } from "drizzle-orm";
6
+ import { v4 as uuid } from "uuid";
7
+
8
+ import { getDb } from "../db.js";
9
+ import {
10
+ memoryGraphEdges,
11
+ memoryGraphNodes,
12
+ memoryGraphTriggers,
13
+ } from "../schema.js";
14
+ import type {
15
+ ApplyDiffResult,
16
+ EmotionalCharge,
17
+ Fidelity,
18
+ ImageRef,
19
+ MemoryDiff,
20
+ MemoryEdge,
21
+ MemoryNode,
22
+ MemoryTrigger,
23
+ MemoryType,
24
+ NewEdge,
25
+ NewNode,
26
+ NewTrigger,
27
+ SourceType,
28
+ } from "./types.js";
29
+
30
+ // ---------------------------------------------------------------------------
31
+ // Row ↔ Domain conversion helpers
32
+ // ---------------------------------------------------------------------------
33
+
34
+ function rowToNode(row: typeof memoryGraphNodes.$inferSelect): MemoryNode {
35
+ return {
36
+ id: row.id,
37
+ content: row.content,
38
+ type: row.type as MemoryType,
39
+ created: row.created,
40
+ lastAccessed: row.lastAccessed,
41
+ lastConsolidated: row.lastConsolidated,
42
+ eventDate: row.eventDate ?? null,
43
+ emotionalCharge: JSON.parse(row.emotionalCharge) as EmotionalCharge,
44
+ fidelity: row.fidelity as Fidelity,
45
+ confidence: row.confidence,
46
+ significance: row.significance,
47
+ stability: row.stability,
48
+ reinforcementCount: row.reinforcementCount,
49
+ lastReinforced: row.lastReinforced,
50
+ sourceConversations: JSON.parse(row.sourceConversations) as string[],
51
+ sourceType: row.sourceType as SourceType,
52
+ narrativeRole: row.narrativeRole,
53
+ partOfStory: row.partOfStory,
54
+ imageRefs: row.imageRefs ? (JSON.parse(row.imageRefs) as ImageRef[]) : null,
55
+ scopeId: row.scopeId,
56
+ };
57
+ }
58
+
59
+ function nodeToInsertValues(node: NewNode, id: string) {
60
+ return {
61
+ id,
62
+ content: node.content,
63
+ type: node.type,
64
+ created: node.created,
65
+ lastAccessed: node.lastAccessed,
66
+ lastConsolidated: node.lastConsolidated,
67
+ eventDate: node.eventDate ?? null,
68
+ emotionalCharge: JSON.stringify(node.emotionalCharge),
69
+ fidelity: node.fidelity,
70
+ confidence: node.confidence,
71
+ significance: node.significance,
72
+ stability: node.stability,
73
+ reinforcementCount: node.reinforcementCount,
74
+ lastReinforced: node.lastReinforced,
75
+ sourceConversations: JSON.stringify(node.sourceConversations),
76
+ sourceType: node.sourceType,
77
+ narrativeRole: node.narrativeRole,
78
+ partOfStory: node.partOfStory,
79
+ imageRefs: node.imageRefs ? JSON.stringify(node.imageRefs) : null,
80
+ scopeId: node.scopeId,
81
+ };
82
+ }
83
+
84
+ function rowToEdge(row: typeof memoryGraphEdges.$inferSelect): MemoryEdge {
85
+ return {
86
+ id: row.id,
87
+ sourceNodeId: row.sourceNodeId,
88
+ targetNodeId: row.targetNodeId,
89
+ relationship: row.relationship as MemoryEdge["relationship"],
90
+ weight: row.weight,
91
+ created: row.created,
92
+ };
93
+ }
94
+
95
+ function rowToTrigger(
96
+ row: typeof memoryGraphTriggers.$inferSelect,
97
+ ): MemoryTrigger {
98
+ return {
99
+ id: row.id,
100
+ nodeId: row.nodeId,
101
+ type: row.type as MemoryTrigger["type"],
102
+ schedule: row.schedule,
103
+ condition: row.condition,
104
+ conditionEmbedding: row.conditionEmbedding
105
+ ? new Float32Array(row.conditionEmbedding as ArrayBuffer)
106
+ : null,
107
+ threshold: row.threshold,
108
+ eventDate: row.eventDate,
109
+ rampDays: row.rampDays,
110
+ followUpDays: row.followUpDays,
111
+ recurring: row.recurring,
112
+ consumed: row.consumed,
113
+ cooldownMs: row.cooldownMs,
114
+ lastFired: row.lastFired,
115
+ };
116
+ }
117
+
118
+ // ---------------------------------------------------------------------------
119
+ // Node CRUD
120
+ // ---------------------------------------------------------------------------
121
+
122
+ export function createNode(node: NewNode): MemoryNode {
123
+ const db = getDb();
124
+ const id = uuid();
125
+ db.insert(memoryGraphNodes).values(nodeToInsertValues(node, id)).run();
126
+ return { ...node, id };
127
+ }
128
+
129
+ export function getNode(id: string): MemoryNode | null {
130
+ const db = getDb();
131
+ const row = db
132
+ .select()
133
+ .from(memoryGraphNodes)
134
+ .where(eq(memoryGraphNodes.id, id))
135
+ .get();
136
+ return row ? rowToNode(row) : null;
137
+ }
138
+
139
+ export function getNodesByIds(ids: string[]): MemoryNode[] {
140
+ if (ids.length === 0) return [];
141
+ const db = getDb();
142
+ const rows = db
143
+ .select()
144
+ .from(memoryGraphNodes)
145
+ .where(inArray(memoryGraphNodes.id, ids))
146
+ .all();
147
+ return rows.map(rowToNode);
148
+ }
149
+
150
+ export function updateNode(
151
+ id: string,
152
+ changes: Partial<Omit<MemoryNode, "id">>,
153
+ ): void {
154
+ const db = getDb();
155
+ const updates: Record<string, unknown> = {};
156
+
157
+ if (changes.content !== undefined) updates.content = changes.content;
158
+ if (changes.type !== undefined) updates.type = changes.type;
159
+ if (changes.created !== undefined) updates.created = changes.created;
160
+ if (changes.lastAccessed !== undefined)
161
+ updates.lastAccessed = changes.lastAccessed;
162
+ if (changes.lastConsolidated !== undefined)
163
+ updates.lastConsolidated = changes.lastConsolidated;
164
+ if (changes.emotionalCharge !== undefined)
165
+ updates.emotionalCharge = JSON.stringify(changes.emotionalCharge);
166
+ if (changes.fidelity !== undefined) updates.fidelity = changes.fidelity;
167
+ if (changes.confidence !== undefined) updates.confidence = changes.confidence;
168
+ if (changes.significance !== undefined)
169
+ updates.significance = changes.significance;
170
+ if (changes.stability !== undefined) updates.stability = changes.stability;
171
+ if (changes.reinforcementCount !== undefined)
172
+ updates.reinforcementCount = changes.reinforcementCount;
173
+ if (changes.lastReinforced !== undefined)
174
+ updates.lastReinforced = changes.lastReinforced;
175
+ if (changes.sourceConversations !== undefined)
176
+ updates.sourceConversations = JSON.stringify(changes.sourceConversations);
177
+ if (changes.sourceType !== undefined) updates.sourceType = changes.sourceType;
178
+ if (changes.narrativeRole !== undefined)
179
+ updates.narrativeRole = changes.narrativeRole;
180
+ if (changes.partOfStory !== undefined)
181
+ updates.partOfStory = changes.partOfStory;
182
+ if (changes.imageRefs !== undefined)
183
+ updates.imageRefs = changes.imageRefs ? JSON.stringify(changes.imageRefs) : null;
184
+ if (changes.scopeId !== undefined) updates.scopeId = changes.scopeId;
185
+ if (changes.eventDate !== undefined) updates.eventDate = changes.eventDate;
186
+
187
+ if (Object.keys(updates).length === 0) return;
188
+
189
+ db.update(memoryGraphNodes)
190
+ .set(updates)
191
+ .where(eq(memoryGraphNodes.id, id))
192
+ .run();
193
+
194
+ // Sync event triggers when eventDate changes
195
+ if (changes.eventDate !== undefined) {
196
+ const triggers = getTriggersForNode(id);
197
+ const eventTriggers = triggers.filter((t) => t.type === "event");
198
+ for (const trigger of eventTriggers) {
199
+ if (changes.eventDate === null) {
200
+ // Clearing eventDate — delete orphaned event trigger
201
+ deleteTrigger(trigger.id);
202
+ } else {
203
+ // Updating eventDate — sync trigger's eventDate
204
+ updateTrigger(trigger.id, { eventDate: changes.eventDate });
205
+ }
206
+ }
207
+ }
208
+ }
209
+
210
+ export function deleteNode(id: string): void {
211
+ const db = getDb();
212
+ db.delete(memoryGraphNodes).where(eq(memoryGraphNodes.id, id)).run();
213
+ }
214
+
215
+ // ---------------------------------------------------------------------------
216
+ // Node queries
217
+ // ---------------------------------------------------------------------------
218
+
219
+ export interface NodeQueryFilters {
220
+ scopeId?: string;
221
+ types?: MemoryType[];
222
+ fidelityNot?: Fidelity[];
223
+ minSignificance?: number;
224
+ createdAfter?: number;
225
+ createdBefore?: number;
226
+ hasEventDate?: boolean;
227
+ eventDateAfter?: number;
228
+ eventDateBefore?: number;
229
+ limit?: number;
230
+ }
231
+
232
+ export function queryNodes(filters: NodeQueryFilters): MemoryNode[] {
233
+ const db = getDb();
234
+ const conditions = [];
235
+
236
+ if (filters.scopeId) {
237
+ conditions.push(eq(memoryGraphNodes.scopeId, filters.scopeId));
238
+ }
239
+ if (filters.types && filters.types.length > 0) {
240
+ conditions.push(inArray(memoryGraphNodes.type, filters.types));
241
+ }
242
+ if (filters.fidelityNot && filters.fidelityNot.length > 0) {
243
+ conditions.push(
244
+ sql`${memoryGraphNodes.fidelity} NOT IN (${sql.join(
245
+ filters.fidelityNot.map((f) => sql`${f}`),
246
+ sql`, `,
247
+ )})`,
248
+ );
249
+ }
250
+ if (filters.minSignificance !== undefined) {
251
+ conditions.push(
252
+ sql`${memoryGraphNodes.significance} >= ${filters.minSignificance}`,
253
+ );
254
+ }
255
+ if (filters.createdAfter !== undefined) {
256
+ conditions.push(
257
+ sql`${memoryGraphNodes.created} >= ${filters.createdAfter}`,
258
+ );
259
+ }
260
+ if (filters.createdBefore !== undefined) {
261
+ conditions.push(
262
+ sql`${memoryGraphNodes.created} <= ${filters.createdBefore}`,
263
+ );
264
+ }
265
+ if (filters.hasEventDate) {
266
+ conditions.push(sql`${memoryGraphNodes.eventDate} IS NOT NULL`);
267
+ }
268
+ if (filters.eventDateAfter !== undefined) {
269
+ conditions.push(
270
+ sql`${memoryGraphNodes.eventDate} >= ${filters.eventDateAfter}`,
271
+ );
272
+ }
273
+ if (filters.eventDateBefore !== undefined) {
274
+ conditions.push(
275
+ sql`${memoryGraphNodes.eventDate} <= ${filters.eventDateBefore}`,
276
+ );
277
+ }
278
+
279
+ let query = db
280
+ .select()
281
+ .from(memoryGraphNodes)
282
+ .where(conditions.length > 0 ? and(...conditions) : undefined)
283
+ .orderBy(sql`${memoryGraphNodes.significance} DESC`);
284
+
285
+ if (filters.limit) {
286
+ query = query.limit(filters.limit) as typeof query;
287
+ }
288
+
289
+ return query.all().map(rowToNode);
290
+ }
291
+
292
+ /** Count all non-gone nodes in a scope. */
293
+ export function countNodes(scopeId: string): number {
294
+ const db = getDb();
295
+ const result = db
296
+ .select({ count: sql<number>`count(*)` })
297
+ .from(memoryGraphNodes)
298
+ .where(
299
+ and(
300
+ eq(memoryGraphNodes.scopeId, scopeId),
301
+ sql`${memoryGraphNodes.fidelity} != 'gone'`,
302
+ ),
303
+ )
304
+ .get();
305
+ return result?.count ?? 0;
306
+ }
307
+
308
+ // ---------------------------------------------------------------------------
309
+ // Edge CRUD
310
+ // ---------------------------------------------------------------------------
311
+
312
+ export function createEdge(edge: NewEdge): MemoryEdge {
313
+ const db = getDb();
314
+ const id = uuid();
315
+ db.insert(memoryGraphEdges)
316
+ .values({
317
+ id,
318
+ sourceNodeId: edge.sourceNodeId,
319
+ targetNodeId: edge.targetNodeId,
320
+ relationship: edge.relationship,
321
+ weight: edge.weight,
322
+ created: edge.created,
323
+ })
324
+ .run();
325
+ return { ...edge, id };
326
+ }
327
+
328
+ export function deleteEdge(id: string): void {
329
+ const db = getDb();
330
+ db.delete(memoryGraphEdges).where(eq(memoryGraphEdges.id, id)).run();
331
+ }
332
+
333
+ export function getEdgesForNode(
334
+ nodeId: string,
335
+ direction?: "incoming" | "outgoing",
336
+ ): MemoryEdge[] {
337
+ const db = getDb();
338
+ const condition =
339
+ direction === "outgoing"
340
+ ? eq(memoryGraphEdges.sourceNodeId, nodeId)
341
+ : direction === "incoming"
342
+ ? eq(memoryGraphEdges.targetNodeId, nodeId)
343
+ : sql`${memoryGraphEdges.sourceNodeId} = ${nodeId} OR ${memoryGraphEdges.targetNodeId} = ${nodeId}`;
344
+
345
+ return db
346
+ .select()
347
+ .from(memoryGraphEdges)
348
+ .where(condition)
349
+ .all()
350
+ .map(rowToEdge);
351
+ }
352
+
353
+ // ---------------------------------------------------------------------------
354
+ // Trigger CRUD
355
+ // ---------------------------------------------------------------------------
356
+
357
+ export function createTrigger(trigger: NewTrigger): MemoryTrigger {
358
+ const db = getDb();
359
+ const id = uuid();
360
+ db.insert(memoryGraphTriggers)
361
+ .values({
362
+ id,
363
+ nodeId: trigger.nodeId,
364
+ type: trigger.type,
365
+ schedule: trigger.schedule,
366
+ condition: trigger.condition,
367
+ conditionEmbedding: trigger.conditionEmbedding
368
+ ? Buffer.from(trigger.conditionEmbedding.buffer)
369
+ : null,
370
+ threshold: trigger.threshold,
371
+ eventDate: trigger.eventDate,
372
+ rampDays: trigger.rampDays,
373
+ followUpDays: trigger.followUpDays,
374
+ recurring: trigger.recurring,
375
+ consumed: trigger.consumed,
376
+ cooldownMs: trigger.cooldownMs,
377
+ lastFired: trigger.lastFired,
378
+ })
379
+ .run();
380
+ return { ...trigger, id };
381
+ }
382
+
383
+ export function deleteTrigger(id: string): void {
384
+ const db = getDb();
385
+ db.delete(memoryGraphTriggers)
386
+ .where(eq(memoryGraphTriggers.id, id))
387
+ .run();
388
+ }
389
+
390
+ export function updateTrigger(
391
+ id: string,
392
+ updates: Partial<MemoryTrigger>,
393
+ ): void {
394
+ const db = getDb();
395
+ const values: Record<string, unknown> = {};
396
+ if (updates.consumed !== undefined) values.consumed = updates.consumed;
397
+ if (updates.lastFired !== undefined) values.lastFired = updates.lastFired;
398
+ if (updates.conditionEmbedding !== undefined)
399
+ values.conditionEmbedding = updates.conditionEmbedding
400
+ ? Buffer.from(updates.conditionEmbedding.buffer)
401
+ : null;
402
+ if (updates.eventDate !== undefined) values.eventDate = updates.eventDate;
403
+ if (updates.rampDays !== undefined) values.rampDays = updates.rampDays;
404
+ if (updates.followUpDays !== undefined)
405
+ values.followUpDays = updates.followUpDays;
406
+
407
+ if (Object.keys(values).length === 0) return;
408
+ db.update(memoryGraphTriggers)
409
+ .set(values)
410
+ .where(eq(memoryGraphTriggers.id, id))
411
+ .run();
412
+ }
413
+
414
+ export function getTriggersForNode(nodeId: string): MemoryTrigger[] {
415
+ const db = getDb();
416
+ return db
417
+ .select()
418
+ .from(memoryGraphTriggers)
419
+ .where(eq(memoryGraphTriggers.nodeId, nodeId))
420
+ .all()
421
+ .map(rowToTrigger);
422
+ }
423
+
424
+ export function getActiveTriggersByType(
425
+ type: MemoryTrigger["type"],
426
+ scopeId?: string,
427
+ ): MemoryTrigger[] {
428
+ const db = getDb();
429
+ const conditions = [
430
+ eq(memoryGraphTriggers.type, type),
431
+ eq(memoryGraphTriggers.consumed, false),
432
+ ];
433
+
434
+ // Join to nodes table to filter by scope if needed
435
+ if (scopeId) {
436
+ const rows = db
437
+ .select({
438
+ trigger: memoryGraphTriggers,
439
+ })
440
+ .from(memoryGraphTriggers)
441
+ .innerJoin(
442
+ memoryGraphNodes,
443
+ eq(memoryGraphTriggers.nodeId, memoryGraphNodes.id),
444
+ )
445
+ .where(
446
+ and(
447
+ ...conditions,
448
+ eq(memoryGraphNodes.scopeId, scopeId),
449
+ sql`${memoryGraphNodes.fidelity} != 'gone'`,
450
+ ),
451
+ )
452
+ .all();
453
+ return rows.map((r) => rowToTrigger(r.trigger));
454
+ }
455
+
456
+ return db
457
+ .select()
458
+ .from(memoryGraphTriggers)
459
+ .where(and(...conditions))
460
+ .all()
461
+ .map(rowToTrigger);
462
+ }
463
+
464
+ // ---------------------------------------------------------------------------
465
+ // Reinforcement
466
+ // ---------------------------------------------------------------------------
467
+
468
+ const REINFORCEMENT_STABILITY_MULTIPLIER = 1.5;
469
+
470
+ /**
471
+ * Reinforce a memory node — confirms it's still accurate/relevant.
472
+ * Increments reinforcementCount, multiplies stability by 1.5,
473
+ * and optionally boosts significance back toward peak.
474
+ */
475
+ export function reinforceNode(id: string): void {
476
+ const db = getDb();
477
+ const now = Date.now();
478
+ db.update(memoryGraphNodes)
479
+ .set({
480
+ reinforcementCount: sql`${memoryGraphNodes.reinforcementCount} + 1`,
481
+ stability: sql`${memoryGraphNodes.stability} * ${REINFORCEMENT_STABILITY_MULTIPLIER}`,
482
+ lastReinforced: now,
483
+ significance: sql`MIN(1.0, ${memoryGraphNodes.significance} * 1.1)`,
484
+ })
485
+ .where(eq(memoryGraphNodes.id, id))
486
+ .run();
487
+ }
488
+
489
+ /**
490
+ * Supersede an old node with a new one. The new node inherits the old node's
491
+ * earned durability (stability, reinforcementCount, significance).
492
+ * A "supersedes" edge is created, and the old node is returned for content update.
493
+ */
494
+ export function supersedeNode(
495
+ oldNodeId: string,
496
+ newNode: NewNode,
497
+ ): { newNode: MemoryNode; oldNode: MemoryNode | null } {
498
+ const oldNode = getNode(oldNodeId);
499
+ if (!oldNode) {
500
+ return { newNode: createNode(newNode), oldNode: null };
501
+ }
502
+
503
+ // Inherit the old node's earned durability
504
+ const inherited: NewNode = {
505
+ ...newNode,
506
+ stability: Math.max(newNode.stability, oldNode.stability),
507
+ reinforcementCount: Math.max(
508
+ newNode.reinforcementCount,
509
+ oldNode.reinforcementCount,
510
+ ),
511
+ significance: Math.max(newNode.significance, oldNode.significance),
512
+ eventDate: newNode.eventDate ?? oldNode.eventDate,
513
+ imageRefs: newNode.imageRefs ?? oldNode.imageRefs,
514
+ };
515
+
516
+ const created = createNode(inherited);
517
+
518
+ // Create supersedes edge
519
+ createEdge({
520
+ sourceNodeId: created.id,
521
+ targetNodeId: oldNodeId,
522
+ relationship: "supersedes",
523
+ weight: 1.0,
524
+ created: Date.now(),
525
+ });
526
+
527
+ return { newNode: created, oldNode };
528
+ }
529
+
530
+ // ---------------------------------------------------------------------------
531
+ // Diff application (transactional)
532
+ // ---------------------------------------------------------------------------
533
+
534
+ /**
535
+ * Apply a MemoryDiff atomically. All operations run in a single transaction.
536
+ */
537
+ export function applyDiff(diff: MemoryDiff): ApplyDiffResult {
538
+ const db = getDb();
539
+ const result: ApplyDiffResult = {
540
+ nodesCreated: 0,
541
+ nodesUpdated: 0,
542
+ nodesDeleted: 0,
543
+ edgesCreated: 0,
544
+ edgesDeleted: 0,
545
+ triggersCreated: 0,
546
+ triggersDeleted: 0,
547
+ nodesReinforced: 0,
548
+ createdNodeIds: [],
549
+ };
550
+
551
+ db.transaction((tx) => {
552
+ // Delete nodes first (cascades edges + triggers)
553
+ for (const id of diff.deleteNodeIds) {
554
+ tx.delete(memoryGraphNodes).where(eq(memoryGraphNodes.id, id)).run();
555
+ result.nodesDeleted++;
556
+ }
557
+
558
+ // Create nodes
559
+ for (const node of diff.createNodes) {
560
+ const id = uuid();
561
+ tx.insert(memoryGraphNodes).values(nodeToInsertValues(node, id)).run();
562
+ result.nodesCreated++;
563
+ result.createdNodeIds.push(id);
564
+ }
565
+
566
+ // Update nodes
567
+ for (const update of diff.updateNodes) {
568
+ const updates: Record<string, unknown> = {};
569
+ const c = update.changes;
570
+ if (c.content !== undefined) updates.content = c.content;
571
+ if (c.type !== undefined) updates.type = c.type;
572
+ if (c.emotionalCharge !== undefined)
573
+ updates.emotionalCharge = JSON.stringify(c.emotionalCharge);
574
+ if (c.fidelity !== undefined) updates.fidelity = c.fidelity;
575
+ if (c.confidence !== undefined) updates.confidence = c.confidence;
576
+ if (c.significance !== undefined) updates.significance = c.significance;
577
+ if (c.stability !== undefined) updates.stability = c.stability;
578
+ if (c.narrativeRole !== undefined)
579
+ updates.narrativeRole = c.narrativeRole;
580
+ if (c.partOfStory !== undefined) updates.partOfStory = c.partOfStory;
581
+ if (c.imageRefs !== undefined)
582
+ updates.imageRefs = c.imageRefs ? JSON.stringify(c.imageRefs) : null;
583
+ if (c.sourceConversations !== undefined)
584
+ updates.sourceConversations = JSON.stringify(c.sourceConversations);
585
+ if (c.eventDate !== undefined) updates.eventDate = c.eventDate;
586
+
587
+ if (Object.keys(updates).length > 0) {
588
+ tx.update(memoryGraphNodes)
589
+ .set(updates)
590
+ .where(eq(memoryGraphNodes.id, update.id))
591
+ .run();
592
+ result.nodesUpdated++;
593
+ }
594
+
595
+ // Sync event triggers when eventDate changes
596
+ if (c.eventDate !== undefined) {
597
+ const triggers = tx
598
+ .select()
599
+ .from(memoryGraphTriggers)
600
+ .where(
601
+ and(
602
+ eq(memoryGraphTriggers.nodeId, update.id),
603
+ eq(memoryGraphTriggers.type, "event"),
604
+ ),
605
+ )
606
+ .all();
607
+
608
+ for (const trigger of triggers) {
609
+ if (c.eventDate == null) {
610
+ // eventDate cleared — delete orphaned event trigger
611
+ tx.delete(memoryGraphTriggers)
612
+ .where(eq(memoryGraphTriggers.id, trigger.id))
613
+ .run();
614
+ result.triggersDeleted++;
615
+ } else {
616
+ // eventDate changed — sync trigger
617
+ tx.update(memoryGraphTriggers)
618
+ .set({ eventDate: c.eventDate })
619
+ .where(eq(memoryGraphTriggers.id, trigger.id))
620
+ .run();
621
+ }
622
+ }
623
+ }
624
+ }
625
+
626
+ // Reinforce nodes
627
+ const now = Date.now();
628
+ for (const id of diff.reinforceNodeIds) {
629
+ tx.update(memoryGraphNodes)
630
+ .set({
631
+ reinforcementCount: sql`${memoryGraphNodes.reinforcementCount} + 1`,
632
+ stability: sql`${memoryGraphNodes.stability} * ${REINFORCEMENT_STABILITY_MULTIPLIER}`,
633
+ lastReinforced: now,
634
+ significance: sql`MIN(1.0, ${memoryGraphNodes.significance} * 1.1)`,
635
+ })
636
+ .where(eq(memoryGraphNodes.id, id))
637
+ .run();
638
+ result.nodesReinforced++;
639
+ }
640
+
641
+ // Delete edges
642
+ for (const id of diff.deleteEdgeIds) {
643
+ tx.delete(memoryGraphEdges).where(eq(memoryGraphEdges.id, id)).run();
644
+ result.edgesDeleted++;
645
+ }
646
+
647
+ // Create edges
648
+ for (const edge of diff.createEdges) {
649
+ const id = uuid();
650
+ tx.insert(memoryGraphEdges)
651
+ .values({
652
+ id,
653
+ sourceNodeId: edge.sourceNodeId,
654
+ targetNodeId: edge.targetNodeId,
655
+ relationship: edge.relationship,
656
+ weight: edge.weight,
657
+ created: edge.created,
658
+ })
659
+ .run();
660
+ result.edgesCreated++;
661
+ }
662
+
663
+ // Delete triggers
664
+ for (const id of diff.deleteTriggerIds) {
665
+ tx.delete(memoryGraphTriggers)
666
+ .where(eq(memoryGraphTriggers.id, id))
667
+ .run();
668
+ result.triggersDeleted++;
669
+ }
670
+
671
+ // Create triggers
672
+ for (const trigger of diff.createTriggers) {
673
+ const id = uuid();
674
+ tx.insert(memoryGraphTriggers)
675
+ .values({
676
+ id,
677
+ nodeId: trigger.nodeId,
678
+ type: trigger.type,
679
+ schedule: trigger.schedule,
680
+ condition: trigger.condition,
681
+ conditionEmbedding: trigger.conditionEmbedding
682
+ ? Buffer.from(trigger.conditionEmbedding.buffer)
683
+ : null,
684
+ threshold: trigger.threshold,
685
+ eventDate: trigger.eventDate,
686
+ rampDays: trigger.rampDays,
687
+ followUpDays: trigger.followUpDays,
688
+ recurring: trigger.recurring,
689
+ consumed: trigger.consumed,
690
+ cooldownMs: trigger.cooldownMs,
691
+ lastFired: trigger.lastFired,
692
+ })
693
+ .run();
694
+ result.triggersCreated++;
695
+ }
696
+ });
697
+
698
+ return result;
699
+ }