@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
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * Route handlers for memory item CRUD endpoints.
3
3
  *
4
+ * Queries memory_graph_nodes and maps results to the client's
5
+ * MemoryItemPayload shape for backwards compatibility.
6
+ *
4
7
  * GET /v1/memory-items — list memory items (with filtering, search, sort, pagination)
5
8
  * GET /v1/memory-items/:id — get a single memory item
6
9
  * POST /v1/memory-items — create a new memory item
@@ -8,8 +11,17 @@
8
11
  * DELETE /v1/memory-items/:id — delete a memory item and its embeddings
9
12
  */
10
13
 
11
- import { and, asc, count, desc, eq, inArray, like, ne, or } from "drizzle-orm";
12
- import { v4 as uuid } from "uuid";
14
+ import {
15
+ and,
16
+ asc,
17
+ count,
18
+ desc,
19
+ eq,
20
+ inArray,
21
+ like,
22
+ ne,
23
+ notInArray,
24
+ } from "drizzle-orm";
13
25
  import { z } from "zod";
14
26
 
15
27
  import { getConfig } from "../../config/loader.js";
@@ -19,15 +31,23 @@ import {
19
31
  generateSparseEmbedding,
20
32
  getMemoryBackendStatus,
21
33
  } from "../../memory/embedding-backend.js";
22
- import { computeMemoryFingerprint } from "../../memory/fingerprint.js";
34
+ import {
35
+ createNode,
36
+ deleteNode,
37
+ getNode,
38
+ updateNode,
39
+ } from "../../memory/graph/store.js";
40
+ import type {
41
+ Fidelity,
42
+ ImageRef,
43
+ MemoryNode,
44
+ MemoryType,
45
+ NewNode,
46
+ } from "../../memory/graph/types.js";
23
47
  import { enqueueMemoryJob } from "../../memory/jobs-store.js";
24
48
  import { withQdrantBreaker } from "../../memory/qdrant-circuit-breaker.js";
25
49
  import { getQdrantClient } from "../../memory/qdrant-client.js";
26
- import {
27
- conversations,
28
- memoryEmbeddings,
29
- memoryItems,
30
- } from "../../memory/schema.js";
50
+ import { conversations, memoryGraphNodes } from "../../memory/schema.js";
31
51
  import { getLogger } from "../../util/logger.js";
32
52
  import { httpError } from "../http-errors.js";
33
53
  import type { RouteContext, RouteDefinition } from "../http-router.js";
@@ -38,23 +58,20 @@ const log = getLogger("memory-item-routes");
38
58
  // Constants
39
59
  // ---------------------------------------------------------------------------
40
60
 
41
- const VALID_KINDS = [
42
- "identity",
43
- "preference",
44
- "project",
45
- "decision",
46
- "constraint",
47
- "event",
48
- "capability",
49
- "journal",
50
- ] as const;
51
-
52
- type MemoryItemKind = (typeof VALID_KINDS)[number];
61
+ const VALID_TYPES: MemoryType[] = [
62
+ "episodic",
63
+ "semantic",
64
+ "procedural",
65
+ "emotional",
66
+ "prospective",
67
+ "behavioral",
68
+ "narrative",
69
+ "shared",
70
+ ];
53
71
 
54
72
  const VALID_SORT_FIELDS = [
55
73
  "lastSeenAt",
56
74
  "importance",
57
- "accessCount",
58
75
  "kind",
59
76
  "firstSeenAt",
60
77
  ] as const;
@@ -62,31 +79,82 @@ const VALID_SORT_FIELDS = [
62
79
  type SortField = (typeof VALID_SORT_FIELDS)[number];
63
80
 
64
81
  const SORT_COLUMN_MAP = {
65
- lastSeenAt: memoryItems.lastSeenAt,
66
- importance: memoryItems.importance,
67
- accessCount: memoryItems.accessCount,
68
- kind: memoryItems.kind,
69
- firstSeenAt: memoryItems.firstSeenAt,
82
+ lastSeenAt: memoryGraphNodes.lastAccessed,
83
+ importance: memoryGraphNodes.significance,
84
+ kind: memoryGraphNodes.type,
85
+ firstSeenAt: memoryGraphNodes.created,
70
86
  } as const;
71
87
 
72
88
  // ---------------------------------------------------------------------------
73
89
  // Helpers
74
90
  // ---------------------------------------------------------------------------
75
91
 
76
- function isValidKind(value: string): value is MemoryItemKind {
77
- return (VALID_KINDS as readonly string[]).includes(value);
92
+ function isValidType(value: string): value is MemoryType {
93
+ return (VALID_TYPES as string[]).includes(value);
78
94
  }
79
95
 
80
96
  function isValidSortField(value: string): value is SortField {
81
97
  return (VALID_SORT_FIELDS as readonly string[]).includes(value);
82
98
  }
83
99
 
100
+ /**
101
+ * Split graph node content into subject (first line) and statement (rest).
102
+ * Playbooks store JSON in statement; other nodes use plain prose.
103
+ */
104
+ function splitContent(content: string): { subject: string; statement: string } {
105
+ const newlineIdx = content.indexOf("\n");
106
+ if (newlineIdx === -1) {
107
+ return { subject: content, statement: content };
108
+ }
109
+ return {
110
+ subject: content.slice(0, newlineIdx).trim(),
111
+ statement: content.slice(newlineIdx + 1).trim(),
112
+ };
113
+ }
114
+
115
+ /**
116
+ * Map a graph node to the client's MemoryItemPayload shape.
117
+ */
118
+ function nodeToPayload(
119
+ node: MemoryNode,
120
+ scopeLabel: string | null = null,
121
+ ): Record<string, unknown> {
122
+ const { subject, statement } = splitContent(node.content);
123
+ return {
124
+ id: node.id,
125
+ kind: node.type,
126
+ subject,
127
+ statement,
128
+ status: node.fidelity === "gone" ? "superseded" : "active",
129
+ confidence: node.confidence,
130
+ importance: node.significance,
131
+ eventDate: node.eventDate,
132
+ firstSeenAt: node.created,
133
+ lastSeenAt: node.lastAccessed,
134
+
135
+ // Graph-specific fields
136
+ fidelity: node.fidelity,
137
+ sourceType: node.sourceType,
138
+ narrativeRole: node.narrativeRole,
139
+ partOfStory: node.partOfStory,
140
+ reinforcementCount: node.reinforcementCount,
141
+ stability: node.stability,
142
+ emotionalCharge: node.emotionalCharge,
143
+
144
+ scopeId: node.scopeId,
145
+ scopeLabel,
146
+
147
+ // Legacy fields — not applicable to graph nodes
148
+ accessCount: null,
149
+ verificationState: null,
150
+ lastUsedAt: null,
151
+ supersedes: null,
152
+ supersededBy: null,
153
+ };
154
+ }
155
+
84
156
  /**
85
157
  * Resolve a `scopeLabel` for a memory item based on its `scopeId`.
86
- *
87
- * - `"default"` → `null`
88
- * - `"private:<conversationId>"` → `"Private · <title>"` when the conversation
89
- * has a title, or `"Private"` when it doesn't (or the conversation was deleted).
90
158
  */
91
159
  function resolveScopeLabel(
92
160
  scopeId: string,
@@ -103,7 +171,6 @@ function resolveScopeLabel(
103
171
 
104
172
  /**
105
173
  * Batch-fetch conversation titles for a set of private-scoped memory items.
106
- * Returns a Map from conversation ID → title (or null).
107
174
  */
108
175
  function buildConversationTitleMap(
109
176
  db: ReturnType<typeof getDb>,
@@ -129,20 +196,25 @@ function buildConversationTitleMap(
129
196
  return map;
130
197
  }
131
198
 
199
+ // ---------------------------------------------------------------------------
200
+ // Semantic search constants
201
+ // ---------------------------------------------------------------------------
202
+
203
+ const SEMANTIC_SEARCH_FETCH_CEILING = 10_000;
204
+
132
205
  // ---------------------------------------------------------------------------
133
206
  // Semantic search helper
134
207
  // ---------------------------------------------------------------------------
135
208
 
136
209
  /**
137
- * Attempt hybrid semantic search for memory items via Qdrant.
138
- * Returns ordered item IDs + total count on success, or `null` when
210
+ * Hybrid semantic search for graph nodes via Qdrant.
211
+ * Returns ordered node IDs + total count on success, or `null` when
139
212
  * the embedding backend / Qdrant is unavailable (caller falls back to SQL).
140
213
  */
141
- async function searchItemsSemantic(
214
+ async function searchNodesSemantic(
142
215
  query: string,
143
216
  fetchLimit: number,
144
217
  kindFilter: string | null,
145
- statusFilter: string,
146
218
  ): Promise<{ ids: string[]; total: number } | null> {
147
219
  try {
148
220
  const config = getConfig();
@@ -156,13 +228,10 @@ async function searchItemsSemantic(
156
228
  const sparse = generateSparseEmbedding(query);
157
229
  const sparseVector = { indices: sparse.indices, values: sparse.values };
158
230
 
159
- // Build Qdrant filter — items only, exclude sentinel
231
+ // Filter to graph_node target_type, exclude gone nodes
160
232
  const mustConditions: Array<Record<string, unknown>> = [
161
- { key: "target_type", match: { value: "item" } },
233
+ { key: "target_type", match: { value: "graph_node" } },
162
234
  ];
163
- if (statusFilter && statusFilter !== "all") {
164
- mustConditions.push({ key: "status", match: { value: statusFilter } });
165
- }
166
235
  if (kindFilter) {
167
236
  mustConditions.push({ key: "kind", match: { value: kindFilter } });
168
237
  }
@@ -184,11 +253,6 @@ async function searchItemsSemantic(
184
253
  );
185
254
 
186
255
  const ids = results.map((r) => r.payload.target_id);
187
-
188
- // Use the vector search result count as the pagination total.
189
- // A DB-wide COUNT would include items with no embedding yet (lagging) and
190
- // items irrelevant to the search query, inflating the total and causing
191
- // clients to paginate into empty pages.
192
256
  return { ids, total: ids.length };
193
257
  } catch (err) {
194
258
  log.warn({ err }, "Semantic memory search failed, falling back to SQL");
@@ -209,10 +273,10 @@ export async function handleListMemoryItems(url: URL): Promise<Response> {
209
273
  const limitParam = Number(url.searchParams.get("limit") ?? 100);
210
274
  const offsetParam = Number(url.searchParams.get("offset") ?? 0);
211
275
 
212
- if (kindParam && !isValidKind(kindParam)) {
276
+ if (kindParam && !isValidType(kindParam)) {
213
277
  return httpError(
214
278
  "BAD_REQUEST",
215
- `Invalid kind "${kindParam}". Must be one of: ${VALID_KINDS.join(", ")}`,
279
+ `Invalid kind "${kindParam}". Must be one of: ${VALID_TYPES.join(", ")}`,
216
280
  400,
217
281
  );
218
282
  }
@@ -235,41 +299,84 @@ export async function handleListMemoryItems(url: URL): Promise<Response> {
235
299
 
236
300
  const db = getDb();
237
301
 
302
+ // Build fidelity filter based on status param
303
+ const fidelityFilter =
304
+ statusParam === "all"
305
+ ? undefined
306
+ : statusParam === "inactive"
307
+ ? eq(memoryGraphNodes.fidelity, "gone")
308
+ : notInArray(memoryGraphNodes.fidelity, ["gone"]);
309
+
238
310
  // ── Semantic search path ────────────────────────────────────────────
239
- // When a search query is present, try Qdrant hybrid search first.
240
- // Falls back to SQL LIKE when embeddings / Qdrant are unavailable.
241
311
  if (searchParam) {
242
- const semanticResult = await searchItemsSemantic(
312
+ const semanticResult = await searchNodesSemantic(
243
313
  searchParam,
244
- limitParam + offsetParam,
245
- kindParam,
246
- statusParam,
314
+ SEMANTIC_SEARCH_FETCH_CEILING,
315
+ null,
247
316
  );
248
317
 
249
318
  if (semanticResult && semanticResult.ids.length > 0) {
250
- // Slice for pagination
251
- const pageIds = semanticResult.ids.slice(
252
- offsetParam,
253
- offsetParam + limitParam,
254
- );
255
-
256
- if (pageIds.length === 0) {
257
- return Response.json({ items: [], total: semanticResult.total });
319
+ // Compute kindCounts from all semantic matches
320
+ const kindCountConditions = [
321
+ inArray(memoryGraphNodes.id, semanticResult.ids),
322
+ ];
323
+ if (fidelityFilter) kindCountConditions.push(fidelityFilter);
324
+
325
+ const kindCountRows = db
326
+ .select({ kind: memoryGraphNodes.type, count: count() })
327
+ .from(memoryGraphNodes)
328
+ .where(and(...kindCountConditions))
329
+ .groupBy(memoryGraphNodes.type)
330
+ .all();
331
+ const semanticKindCounts: Record<string, number> = {};
332
+ for (const row of kindCountRows) {
333
+ semanticKindCounts[row.kind] = row.count;
258
334
  }
259
335
 
260
- // Re-apply the same DB-side filters used in the SQL path as defense-
261
- // in-depth against stale Qdrant payloads leaking deleted/mismatched rows.
262
- const hydrationConditions = [inArray(memoryItems.id, pageIds)];
263
- if (statusParam && statusParam !== "all") {
264
- hydrationConditions.push(eq(memoryItems.status, statusParam));
336
+ // Apply kind + fidelity filter while preserving semantic relevance ordering
337
+ let filteredIds = semanticResult.ids;
338
+ {
339
+ const filterConditions = [
340
+ inArray(memoryGraphNodes.id, semanticResult.ids),
341
+ ];
342
+ if (kindParam) {
343
+ filterConditions.push(eq(memoryGraphNodes.type, kindParam));
344
+ }
345
+ if (fidelityFilter) filterConditions.push(fidelityFilter);
346
+
347
+ if (filterConditions.length > 1) {
348
+ const validIdSet = new Set(
349
+ db
350
+ .select({ id: memoryGraphNodes.id })
351
+ .from(memoryGraphNodes)
352
+ .where(and(...filterConditions))
353
+ .all()
354
+ .map((r) => r.id),
355
+ );
356
+ filteredIds = semanticResult.ids.filter((id) => validIdSet.has(id));
357
+ }
265
358
  }
266
- if (kindParam) {
267
- hydrationConditions.push(eq(memoryItems.kind, kindParam));
359
+
360
+ const total = filteredIds.length;
361
+ const pageIds = filteredIds.slice(offsetParam, offsetParam + limitParam);
362
+
363
+ if (pageIds.length === 0) {
364
+ return Response.json({
365
+ items: [],
366
+ total,
367
+ kindCounts: semanticKindCounts,
368
+ });
268
369
  }
269
370
 
371
+ // Hydrate nodes from DB
372
+ const hydrationConditions = [inArray(memoryGraphNodes.id, pageIds)];
373
+ if (fidelityFilter) hydrationConditions.push(fidelityFilter);
374
+ if (kindParam)
375
+ hydrationConditions.push(eq(memoryGraphNodes.type, kindParam));
376
+
270
377
  const rows = db
271
378
  .select()
272
- .from(memoryItems)
379
+ .from(memoryGraphNodes)
273
380
  .where(and(...hydrationConditions))
274
381
  .all();
275
382
 
@@ -279,36 +386,46 @@ export async function handleListMemoryItems(url: URL): Promise<Response> {
279
386
 
280
387
  const titleMap = buildConversationTitleMap(
281
388
  db,
282
- rows.map((i) => i.scopeId),
389
+ rows.map((r) => r.scopeId),
283
390
  );
284
- const enrichedItems = rows.map((item) => ({
285
- ...item,
286
- scopeLabel: resolveScopeLabel(item.scopeId, titleMap),
287
- }));
288
-
289
- return Response.json({
290
- items: enrichedItems,
291
- total: semanticResult.total,
391
+ const items = rows.map((row) => {
392
+ const node = rowToNode(row);
393
+ return nodeToPayload(node, resolveScopeLabel(node.scopeId, titleMap));
292
394
  });
395
+
396
+ return Response.json({ items, total, kindCounts: semanticKindCounts });
293
397
  }
294
- // semanticResult was null (Qdrant unavailable) or empty — fall through to SQL
398
+ // Fall through to SQL path
295
399
  }
296
400
 
297
- // ── SQL path (default or fallback) ──────────────────────────────────
298
- const conditions = [];
299
- if (statusParam && statusParam !== "all") {
300
- conditions.push(eq(memoryItems.status, statusParam));
401
+ // ── Kind counts for SQL path ───────────────────────────────────────
402
+ const kindCountConditions = [];
403
+ if (fidelityFilter) kindCountConditions.push(fidelityFilter);
404
+ if (searchParam) {
405
+ kindCountConditions.push(
406
+ like(memoryGraphNodes.content, `%${searchParam}%`),
407
+ );
301
408
  }
302
- if (kindParam) {
303
- conditions.push(eq(memoryItems.kind, kindParam));
409
+ const kindCountWhere =
410
+ kindCountConditions.length > 0 ? and(...kindCountConditions) : undefined;
411
+
412
+ const sqlKindCountRows = db
413
+ .select({ kind: memoryGraphNodes.type, count: count() })
414
+ .from(memoryGraphNodes)
415
+ .where(kindCountWhere)
416
+ .groupBy(memoryGraphNodes.type)
417
+ .all();
418
+ const kindCounts: Record<string, number> = {};
419
+ for (const row of sqlKindCountRows) {
420
+ kindCounts[row.kind] = row.count;
304
421
  }
422
+
423
+ // ── SQL path (default or fallback) ──────────────────────────────────
424
+ const conditions = [];
425
+ if (fidelityFilter) conditions.push(fidelityFilter);
426
+ if (kindParam) conditions.push(eq(memoryGraphNodes.type, kindParam));
305
427
  if (searchParam) {
306
- conditions.push(
307
- or(
308
- like(memoryItems.subject, `%${searchParam}%`),
309
- like(memoryItems.statement, `%${searchParam}%`),
310
- )!,
311
- );
428
+ conditions.push(like(memoryGraphNodes.content, `%${searchParam}%`));
312
429
  }
313
430
 
314
431
  const whereClause = conditions.length > 0 ? and(...conditions) : undefined;
@@ -316,7 +433,7 @@ export async function handleListMemoryItems(url: URL): Promise<Response> {
316
433
  // Count query
317
434
  const countResult = db
318
435
  .select({ count: count() })
319
- .from(memoryItems)
436
+ .from(memoryGraphNodes)
320
437
  .where(whereClause)
321
438
  .get();
322
439
  const total = countResult?.count ?? 0;
@@ -325,26 +442,25 @@ export async function handleListMemoryItems(url: URL): Promise<Response> {
325
442
  const sortColumn = SORT_COLUMN_MAP[sortParam];
326
443
  const orderFn = orderParam === "asc" ? asc : desc;
327
444
 
328
- const items = db
445
+ const rows = db
329
446
  .select()
330
- .from(memoryItems)
447
+ .from(memoryGraphNodes)
331
448
  .where(whereClause)
332
449
  .orderBy(orderFn(sortColumn))
333
450
  .limit(limitParam)
334
451
  .offset(offsetParam)
335
452
  .all();
336
453
 
337
- // Resolve scope labels for private-scoped items
338
454
  const titleMap = buildConversationTitleMap(
339
455
  db,
340
- items.map((i) => i.scopeId),
456
+ rows.map((r) => r.scopeId),
341
457
  );
342
- const enrichedItems = items.map((item) => ({
343
- ...item,
344
- scopeLabel: resolveScopeLabel(item.scopeId, titleMap),
345
- }));
458
+ const items = rows.map((row) => {
459
+ const node = rowToNode(row);
460
+ return nodeToPayload(node, resolveScopeLabel(node.scopeId, titleMap));
461
+ });
346
462
 
347
- return Response.json({ items: enrichedItems, total });
463
+ return Response.json({ items, total, kindCounts });
348
464
  }
349
465
 
350
466
  // ---------------------------------------------------------------------------
@@ -353,51 +469,17 @@ export async function handleListMemoryItems(url: URL): Promise<Response> {
353
469
 
354
470
  export function handleGetMemoryItem(ctx: RouteContext): Response {
355
471
  const { id } = ctx.params;
356
- const db = getDb();
357
-
358
- const item = db
359
- .select()
360
- .from(memoryItems)
361
- .where(eq(memoryItems.id, id))
362
- .get();
363
472
 
364
- if (!item) {
473
+ const node = getNode(id);
474
+ if (!node) {
365
475
  return httpError("NOT_FOUND", "Memory item not found", 404);
366
476
  }
367
477
 
368
- let supersedesSubject: string | undefined;
369
- let supersededBySubject: string | undefined;
370
-
371
- if (item.supersedes) {
372
- const superseded = db
373
- .select({ subject: memoryItems.subject })
374
- .from(memoryItems)
375
- .where(eq(memoryItems.id, item.supersedes))
376
- .get();
377
- supersedesSubject = superseded?.subject;
378
- }
379
-
380
- if (item.supersededBy) {
381
- const superseding = db
382
- .select({ subject: memoryItems.subject })
383
- .from(memoryItems)
384
- .where(eq(memoryItems.id, item.supersededBy))
385
- .get();
386
- supersededBySubject = superseding?.subject;
387
- }
388
-
389
- // Resolve scope label
390
- const titleMap = buildConversationTitleMap(db, [item.scopeId]);
391
- const scopeLabel = resolveScopeLabel(item.scopeId, titleMap);
478
+ const db = getDb();
479
+ const titleMap = buildConversationTitleMap(db, [node.scopeId]);
480
+ const scopeLabel = resolveScopeLabel(node.scopeId, titleMap);
392
481
 
393
- return Response.json({
394
- item: {
395
- ...item,
396
- scopeLabel,
397
- ...(supersedesSubject !== undefined ? { supersedesSubject } : {}),
398
- ...(supersededBySubject !== undefined ? { supersededBySubject } : {}),
399
- },
400
- });
482
+ return Response.json({ item: nodeToPayload(node, scopeLabel) });
401
483
  }
402
484
 
403
485
  // ---------------------------------------------------------------------------
@@ -416,25 +498,14 @@ export async function handleCreateMemoryItem(
416
498
 
417
499
  const { kind, subject, statement, importance } = body;
418
500
 
419
- // Validate kind
420
- if (typeof kind !== "string" || !isValidKind(kind)) {
421
- return httpError(
422
- "BAD_REQUEST",
423
- `kind is required and must be one of: ${VALID_KINDS.join(", ")}`,
424
- 400,
425
- );
426
- }
427
-
428
- // Validate subject
429
- if (typeof subject !== "string" || subject.trim().length === 0) {
501
+ if (typeof kind !== "string" || !isValidType(kind)) {
430
502
  return httpError(
431
503
  "BAD_REQUEST",
432
- "subject is required and must be a non-empty string",
504
+ `kind is required and must be one of: ${VALID_TYPES.join(", ")}`,
433
505
  400,
434
506
  );
435
507
  }
436
508
 
437
- // Validate statement
438
509
  if (typeof statement !== "string" || statement.trim().length === 0) {
439
510
  return httpError(
440
511
  "BAD_REQUEST",
@@ -443,27 +514,21 @@ export async function handleCreateMemoryItem(
443
514
  );
444
515
  }
445
516
 
446
- const trimmedSubject = subject.trim();
517
+ const trimmedSubject = typeof subject === "string" ? subject.trim() : "";
447
518
  const trimmedStatement = statement.trim();
519
+ const content = trimmedSubject
520
+ ? `${trimmedSubject}\n${trimmedStatement}`
521
+ : trimmedStatement;
448
522
 
449
- const scopeId = "default";
450
- const fingerprint = computeMemoryFingerprint(
451
- scopeId,
452
- kind,
453
- trimmedSubject,
454
- trimmedStatement,
455
- );
456
-
523
+ // Check for duplicate content
457
524
  const db = getDb();
458
-
459
- // Check for existing item with same fingerprint + scopeId
460
525
  const existing = db
461
- .select()
462
- .from(memoryItems)
526
+ .select({ id: memoryGraphNodes.id })
527
+ .from(memoryGraphNodes)
463
528
  .where(
464
529
  and(
465
- eq(memoryItems.fingerprint, fingerprint),
466
- eq(memoryItems.scopeId, scopeId),
530
+ eq(memoryGraphNodes.content, content),
531
+ ne(memoryGraphNodes.fidelity, "gone"),
467
532
  ),
468
533
  )
469
534
  .get();
@@ -476,44 +541,43 @@ export async function handleCreateMemoryItem(
476
541
  );
477
542
  }
478
543
 
479
- const id = uuid();
480
544
  const now = Date.now();
545
+ const newNode: NewNode = {
546
+ content,
547
+ type: kind as MemoryType,
548
+ created: now,
549
+ lastAccessed: now,
550
+ lastConsolidated: now,
551
+ eventDate: null,
552
+ emotionalCharge: {
553
+ valence: 0,
554
+ intensity: 0.1,
555
+ decayCurve: "linear",
556
+ decayRate: 0.05,
557
+ originalIntensity: 0.1,
558
+ },
559
+ fidelity: "vivid",
560
+ confidence: 0.95,
561
+ significance: importance ?? 0.8,
562
+ stability: 14,
563
+ reinforcementCount: 0,
564
+ lastReinforced: now,
565
+ sourceConversations: [],
566
+ sourceType: "direct",
567
+ narrativeRole: null,
568
+ partOfStory: null,
569
+ imageRefs: null,
570
+ scopeId: "default",
571
+ };
481
572
 
482
- db.insert(memoryItems)
483
- .values({
484
- id,
485
- kind,
486
- subject: trimmedSubject,
487
- statement: trimmedStatement,
488
- status: "active",
489
- confidence: 0.95,
490
- importance: importance ?? 0.8,
491
- fingerprint,
492
- sourceType: "tool",
493
- verificationState: "user_confirmed",
494
- scopeId,
495
- firstSeenAt: now,
496
- lastSeenAt: now,
497
- lastUsedAt: null,
498
- overrideConfidence: "explicit",
499
- })
500
- .run();
501
-
502
- enqueueMemoryJob("embed_item", { itemId: id });
503
-
504
- // Fetch the inserted row to return it
505
- const insertedRow = db
506
- .select()
507
- .from(memoryItems)
508
- .where(eq(memoryItems.id, id))
509
- .get();
573
+ const created = createNode(newNode);
574
+ enqueueMemoryJob("embed_graph_node", { nodeId: created.id });
510
575
 
511
- // Enrich with scopeLabel for API consistency
512
- const titleMap = buildConversationTitleMap(db, [scopeId]);
513
- const scopeLabel = resolveScopeLabel(scopeId, titleMap);
576
+ const titleMap = buildConversationTitleMap(db, [created.scopeId]);
577
+ const scopeLabel = resolveScopeLabel(created.scopeId, titleMap);
514
578
 
515
579
  return Response.json(
516
- { item: { ...insertedRow, scopeLabel } },
580
+ { item: nodeToPayload(created, scopeLabel) },
517
581
  { status: 201 },
518
582
  );
519
583
  }
@@ -526,114 +590,82 @@ export async function handleUpdateMemoryItem(
526
590
  ctx: RouteContext,
527
591
  ): Promise<Response> {
528
592
  const { id } = ctx.params;
593
+
594
+ const existing = getNode(id);
595
+ if (!existing) {
596
+ return httpError("NOT_FOUND", "Memory item not found", 404);
597
+ }
598
+
529
599
  const body = (await ctx.req.json()) as {
530
600
  subject?: string;
531
601
  statement?: string;
532
602
  kind?: string;
533
603
  status?: string;
534
604
  importance?: number;
535
- sourceType?: string;
536
- verificationState?: string;
537
605
  };
538
606
 
539
- const db = getDb();
540
-
541
- const existing = db
542
- .select()
543
- .from(memoryItems)
544
- .where(eq(memoryItems.id, id))
545
- .get();
546
-
547
- if (!existing) {
548
- return httpError("NOT_FOUND", "Memory item not found", 404);
549
- }
550
-
551
- // Build the update set with only provided fields
552
- const set: Record<string, unknown> = {
553
- lastSeenAt: Date.now(),
607
+ const changes: Partial<Omit<MemoryNode, "id">> = {
608
+ lastAccessed: Date.now(),
554
609
  };
555
610
 
556
- if (body.subject !== undefined) {
557
- if (typeof body.subject !== "string") {
558
- return httpError("BAD_REQUEST", "subject must be a string", 400);
559
- }
560
- set.subject = body.subject.trim();
561
- }
562
- if (body.statement !== undefined) {
563
- if (typeof body.statement !== "string") {
564
- return httpError("BAD_REQUEST", "statement must be a string", 400);
611
+ // Rebuild content if subject or statement changed
612
+ const { subject: existingSubject, statement: existingStatement } =
613
+ splitContent(existing.content);
614
+ const newSubject =
615
+ body.subject !== undefined ? body.subject.trim() : existingSubject;
616
+ const newStatement =
617
+ body.statement !== undefined ? body.statement.trim() : existingStatement;
618
+
619
+ let contentChanged = false;
620
+ if (body.subject !== undefined || body.statement !== undefined) {
621
+ const newContent = newSubject
622
+ ? `${newSubject}\n${newStatement}`
623
+ : newStatement;
624
+ if (newContent !== existing.content) {
625
+ changes.content = newContent;
626
+ contentChanged = true;
565
627
  }
566
- set.statement = body.statement.trim();
567
628
  }
629
+
568
630
  if (body.kind !== undefined) {
569
- if (!isValidKind(body.kind)) {
631
+ if (!isValidType(body.kind)) {
570
632
  return httpError(
571
633
  "BAD_REQUEST",
572
- `Invalid kind "${body.kind}". Must be one of: ${VALID_KINDS.join(", ")}`,
634
+ `Invalid kind "${body.kind}". Must be one of: ${VALID_TYPES.join(", ")}`,
573
635
  400,
574
636
  );
575
637
  }
576
- set.kind = body.kind;
577
- }
578
- if (body.status !== undefined) {
579
- set.status = body.status;
580
- }
581
- if (body.importance !== undefined) {
582
- set.importance = body.importance;
583
- }
584
- if (body.sourceType !== undefined) {
585
- set.sourceType = body.sourceType;
638
+ changes.type = body.kind as MemoryType;
586
639
  }
587
640
 
588
- // Accept verificationState from clients that haven't migrated to sourceType yet.
589
- // Map verificationState sourceType for forward compat, and write both fields.
590
- if (body.verificationState !== undefined) {
591
- set.verificationState = body.verificationState;
592
- // Map verificationState to sourceType if sourceType wasn't explicitly provided
593
- if (body.sourceType === undefined) {
594
- set.sourceType =
595
- body.verificationState === "user_confirmed" ? "tool" : "extraction";
641
+ if (body.status !== undefined) {
642
+ // Map client status to fidelity
643
+ if (body.status === "superseded" || body.status === "inactive") {
644
+ changes.fidelity = "gone";
645
+ } else if (body.status === "active") {
646
+ changes.fidelity = "vivid";
596
647
  }
597
648
  }
598
- // If sourceType was set (either directly or via mapping), also write verificationState
599
- if (body.sourceType !== undefined && body.verificationState === undefined) {
600
- set.verificationState =
601
- body.sourceType === "tool"
602
- ? "user_confirmed"
603
- : existing.verificationState === "user_reported"
604
- ? "user_reported"
605
- : "assistant_inferred";
606
- }
607
649
 
608
- // If subject, statement, or kind changed, recompute fingerprint
609
- const contentChanged =
610
- body.subject !== undefined ||
611
- body.statement !== undefined ||
612
- body.kind !== undefined;
613
-
614
- if (contentChanged) {
615
- const newSubject = (set.subject as string | undefined) ?? existing.subject;
616
- const newStatement =
617
- (set.statement as string | undefined) ?? existing.statement;
618
- const newKind = (set.kind as string | undefined) ?? existing.kind;
619
- const scopeId = existing.scopeId;
620
-
621
- const fingerprint = computeMemoryFingerprint(
622
- scopeId,
623
- newKind,
624
- newSubject,
625
- newStatement,
626
- );
650
+ if (body.importance !== undefined) {
651
+ changes.significance = body.importance;
652
+ }
627
653
 
628
- // Check for collision (exclude self)
654
+ // Check for content collision when content changed OR when reactivating a
655
+ // gone item (which could duplicate an existing active item's content).
656
+ const reactivating =
657
+ changes.fidelity === "vivid" && existing.fidelity === "gone";
658
+ if (contentChanged || reactivating) {
659
+ const contentToCheck = changes.content ?? existing.content;
660
+ const db = getDb();
629
661
  const collision = db
630
- .select({ id: memoryItems.id })
631
- .from(memoryItems)
662
+ .select({ id: memoryGraphNodes.id })
663
+ .from(memoryGraphNodes)
632
664
  .where(
633
665
  and(
634
- eq(memoryItems.fingerprint, fingerprint),
635
- eq(memoryItems.scopeId, scopeId),
636
- ne(memoryItems.id, id),
666
+ eq(memoryGraphNodes.content, contentToCheck),
667
+ ne(memoryGraphNodes.id, id),
668
+ ne(memoryGraphNodes.fidelity, "gone"),
637
669
  ),
638
670
  )
639
671
  .get();
@@ -645,36 +677,25 @@ export async function handleUpdateMemoryItem(
645
677
  409,
646
678
  );
647
679
  }
648
-
649
- set.fingerprint = fingerprint;
650
680
  }
651
681
 
652
- db.update(memoryItems).set(set).where(eq(memoryItems.id, id)).run();
682
+ updateNode(id, changes);
653
683
 
654
- // If statement changed, enqueue embed job
655
- if (body.statement !== undefined) {
656
- enqueueMemoryJob("embed_item", { itemId: id });
684
+ if (contentChanged) {
685
+ enqueueMemoryJob("embed_graph_node", { nodeId: id });
657
686
  }
658
687
 
659
- // Fetch and return the updated row
660
- const updatedRow = db
661
- .select()
662
- .from(memoryItems)
663
- .where(eq(memoryItems.id, id))
664
- .get();
688
+ // Fetch updated node
689
+ const updated = getNode(id);
690
+ if (!updated) {
691
+ return httpError("NOT_FOUND", "Memory item not found after update", 404);
692
+ }
665
693
 
666
- // Enrich with scopeLabel for API consistency
667
- const patchTitleMap = buildConversationTitleMap(db, [
668
- updatedRow?.scopeId ?? existing.scopeId,
669
- ]);
670
- const patchScopeLabel = resolveScopeLabel(
671
- updatedRow?.scopeId ?? existing.scopeId,
672
- patchTitleMap,
673
- );
694
+ const db = getDb();
695
+ const titleMap = buildConversationTitleMap(db, [updated.scopeId]);
696
+ const scopeLabel = resolveScopeLabel(updated.scopeId, titleMap);
674
697
 
675
- return Response.json({
676
- item: { ...updatedRow, scopeLabel: patchScopeLabel },
677
- });
698
+ return Response.json({ item: nodeToPayload(updated, scopeLabel) });
678
699
  }
679
700
 
680
701
  // ---------------------------------------------------------------------------
@@ -685,34 +706,57 @@ export async function handleDeleteMemoryItem(
685
706
  ctx: RouteContext,
686
707
  ): Promise<Response> {
687
708
  const { id } = ctx.params;
688
- const db = getDb();
689
-
690
- const existing = db
691
- .select()
692
- .from(memoryItems)
693
- .where(eq(memoryItems.id, id))
694
- .get();
695
709
 
710
+ const existing = getNode(id);
696
711
  if (!existing) {
697
712
  return httpError("NOT_FOUND", "Memory item not found", 404);
698
713
  }
699
714
 
700
- // Delete embeddings for this item
701
- db.delete(memoryEmbeddings)
702
- .where(
703
- and(
704
- eq(memoryEmbeddings.targetType, "item"),
705
- eq(memoryEmbeddings.targetId, id),
706
- ),
707
- )
708
- .run();
715
+ // Hard-delete the node (cascades to edges and triggers via FK)
716
+ deleteNode(id);
709
717
 
710
- // Delete the item (cascades memoryItemSources)
711
- db.delete(memoryItems).where(eq(memoryItems.id, id)).run();
718
+ // Clean up Qdrant vectors asynchronously
719
+ enqueueMemoryJob("delete_qdrant_vectors", {
720
+ targetType: "graph_node",
721
+ targetId: id,
722
+ });
712
723
 
713
724
  return new Response(null, { status: 204 });
714
725
  }
715
726
 
727
+ // ---------------------------------------------------------------------------
728
+ // Row → MemoryNode helper (inline version of store's rowToNode)
729
+ // ---------------------------------------------------------------------------
730
+
731
+ function rowToNode(row: typeof memoryGraphNodes.$inferSelect): MemoryNode {
732
+ return {
733
+ id: row.id,
734
+ content: row.content,
735
+ type: row.type as MemoryType,
736
+ created: row.created,
737
+ lastAccessed: row.lastAccessed,
738
+ lastConsolidated: row.lastConsolidated,
739
+ eventDate: row.eventDate ?? null,
740
+ emotionalCharge: JSON.parse(row.emotionalCharge),
741
+ fidelity: row.fidelity as Fidelity,
742
+ confidence: row.confidence,
743
+ significance: row.significance,
744
+ stability: row.stability,
745
+ reinforcementCount: row.reinforcementCount,
746
+ lastReinforced: row.lastReinforced,
747
+ sourceConversations: JSON.parse(row.sourceConversations) as string[],
748
+ sourceType: row.sourceType as
749
+ | "direct"
750
+ | "inferred"
751
+ | "observed"
752
+ | "told-by-other",
753
+ narrativeRole: row.narrativeRole,
754
+ partOfStory: row.partOfStory,
755
+ imageRefs: row.imageRefs ? (JSON.parse(row.imageRefs) as ImageRef[]) : null,
756
+ scopeId: row.scopeId,
757
+ };
758
+ }
759
+
716
760
  // ---------------------------------------------------------------------------
717
761
  // Route definitions
718
762
  // ---------------------------------------------------------------------------
@@ -774,14 +818,13 @@ export function memoryItemRouteDefinitions(): RouteDefinition[] {
774
818
  method: "GET",
775
819
  policyKey: "memory-items",
776
820
  summary: "Get a memory item",
777
- description:
778
- "Return a single memory item by ID with supersession metadata.",
821
+ description: "Return a single memory item by ID with graph metadata.",
779
822
  tags: ["memory"],
780
823
  responseBody: z.object({
781
824
  item: z
782
825
  .object({})
783
826
  .passthrough()
784
- .describe("Memory item with scopeLabel and supersession info"),
827
+ .describe("Memory item with scopeLabel and graph metadata"),
785
828
  }),
786
829
  handler: (ctx) => handleGetMemoryItem(ctx),
787
830
  },
@@ -789,13 +832,16 @@ export function memoryItemRouteDefinitions(): RouteDefinition[] {
789
832
  endpoint: "memory-items",
790
833
  method: "POST",
791
834
  summary: "Create a memory item",
792
- description: "Create a new memory item and enqueue embedding.",
835
+ description: "Create a new memory graph node and enqueue embedding.",
793
836
  tags: ["memory"],
794
837
  requestBody: z.object({
795
838
  kind: z
796
839
  .string()
797
- .describe("Memory kind (identity, preference, project, etc.)"),
798
- subject: z.string().describe("Subject line"),
840
+ .describe("Memory type (episodic, semantic, procedural, etc.)"),
841
+ subject: z
842
+ .string()
843
+ .describe("Subject line (first line of content)")
844
+ .optional(),
799
845
  statement: z.string().describe("Statement content"),
800
846
  importance: z
801
847
  .number()
@@ -812,16 +858,14 @@ export function memoryItemRouteDefinitions(): RouteDefinition[] {
812
858
  method: "PATCH",
813
859
  policyKey: "memory-items",
814
860
  summary: "Update a memory item",
815
- description: "Partially update fields on an existing memory item.",
861
+ description: "Partially update fields on an existing memory graph node.",
816
862
  tags: ["memory"],
817
863
  requestBody: z.object({
818
- subject: z.string(),
819
- statement: z.string(),
820
- kind: z.string(),
821
- status: z.string(),
822
- importance: z.number(),
823
- sourceType: z.string(),
824
- verificationState: z.string(),
864
+ subject: z.string().optional(),
865
+ statement: z.string().optional(),
866
+ kind: z.string().optional(),
867
+ status: z.string().optional(),
868
+ importance: z.number().optional(),
825
869
  }),
826
870
  responseBody: z.object({
827
871
  item: z.object({}).passthrough().describe("Updated memory item"),
@@ -833,7 +877,7 @@ export function memoryItemRouteDefinitions(): RouteDefinition[] {
833
877
  method: "DELETE",
834
878
  policyKey: "memory-items",
835
879
  summary: "Delete a memory item",
836
- description: "Delete a memory item and its embeddings.",
880
+ description: "Delete a memory graph node and its embeddings.",
837
881
  tags: ["memory"],
838
882
  responseBody: z.object({
839
883
  ok: z.boolean(),