@vellumai/assistant 0.5.16 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (592) hide show
  1. package/AGENTS.md +4 -0
  2. package/ARCHITECTURE.md +69 -16
  3. package/Dockerfile +2 -5
  4. package/bun.lock +6 -2
  5. package/docker-entrypoint.sh +32 -1
  6. package/docs/architecture/integrations.md +1 -1
  7. package/docs/architecture/memory.md +21 -24
  8. package/knip.json +2 -1
  9. package/openapi.yaml +1198 -83
  10. package/package.json +5 -1
  11. package/src/__tests__/actor-token-service.test.ts +68 -0
  12. package/src/__tests__/agent-loop.test.ts +0 -32
  13. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  14. package/src/__tests__/anthropic-provider.test.ts +217 -98
  15. package/src/__tests__/app-compiler.test.ts +120 -0
  16. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  17. package/src/__tests__/app-executors.test.ts +47 -1
  18. package/src/__tests__/app-source-watcher.test.ts +159 -0
  19. package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -2
  20. package/src/__tests__/call-conversation-messages.test.ts +2 -6
  21. package/src/__tests__/call-domain.test.ts +2 -6
  22. package/src/__tests__/call-pointer-messages.test.ts +2 -14
  23. package/src/__tests__/call-recovery.test.ts +2 -6
  24. package/src/__tests__/call-routes-http.test.ts +2 -6
  25. package/src/__tests__/call-store.test.ts +2 -6
  26. package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -6
  27. package/src/__tests__/canonical-guardian-store.test.ts +2 -6
  28. package/src/__tests__/channel-delivery-store.test.ts +2 -6
  29. package/src/__tests__/channel-retry-sweep.test.ts +2 -6
  30. package/src/__tests__/checker.test.ts +63 -9
  31. package/src/__tests__/clawhub.test.ts +54 -24
  32. package/src/__tests__/cli-command-risk-guard.test.ts +14 -0
  33. package/src/__tests__/config-schema.test.ts +6 -1
  34. package/src/__tests__/config-set-platform-guard.test.ts +302 -0
  35. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -6
  36. package/src/__tests__/contacts-tools.test.ts +31 -0
  37. package/src/__tests__/context-overflow-reducer.test.ts +86 -0
  38. package/src/__tests__/context-token-estimator.test.ts +175 -10
  39. package/src/__tests__/conversation-agent-loop-overflow.test.ts +13 -6
  40. package/src/__tests__/conversation-agent-loop.test.ts +13 -51
  41. package/src/__tests__/conversation-attachments.test.ts +2 -6
  42. package/src/__tests__/conversation-attention-store.test.ts +2 -6
  43. package/src/__tests__/conversation-clear-safety.test.ts +2 -6
  44. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +4 -10
  45. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -6
  46. package/src/__tests__/conversation-disk-view.test.ts +2 -6
  47. package/src/__tests__/conversation-error.test.ts +33 -2
  48. package/src/__tests__/conversation-fork-crud.test.ts +2 -6
  49. package/src/__tests__/conversation-history-web-search.test.ts +6 -1
  50. package/src/__tests__/conversation-load-history-repair.test.ts +5 -1
  51. package/src/__tests__/conversation-media-retry.test.ts +91 -0
  52. package/src/__tests__/conversation-runtime-assembly.test.ts +653 -832
  53. package/src/__tests__/conversation-runtime-workspace.test.ts +1 -93
  54. package/src/__tests__/conversation-starter-routes.test.ts +20 -11
  55. package/src/__tests__/conversation-store.test.ts +2 -6
  56. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +17 -4
  57. package/src/__tests__/conversation-usage.test.ts +2 -6
  58. package/src/__tests__/conversation-wipe.test.ts +13 -414
  59. package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -12
  60. package/src/__tests__/conversation-workspace-injection.test.ts +25 -26
  61. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
  62. package/src/__tests__/copy-composer-tc-templates.test.ts +335 -0
  63. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
  64. package/src/__tests__/credential-execution-shell-lockdown.test.ts +2 -2
  65. package/src/__tests__/credential-security-e2e.test.ts +2 -0
  66. package/src/__tests__/date-context.test.ts +76 -210
  67. package/src/__tests__/db-schedule-syntax-migration.test.ts +16 -1
  68. package/src/__tests__/file-list-tool.test.ts +219 -0
  69. package/src/__tests__/first-greeting.test.ts +1 -1
  70. package/src/__tests__/followup-tools.test.ts +2 -6
  71. package/src/__tests__/graph-extraction-event-date.test.ts +186 -0
  72. package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -6
  73. package/src/__tests__/guardian-action-followup-executor.test.ts +2 -6
  74. package/src/__tests__/guardian-action-followup-store.test.ts +2 -6
  75. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +2 -6
  76. package/src/__tests__/guardian-action-late-reply.test.ts +2 -6
  77. package/src/__tests__/guardian-action-store.test.ts +2 -6
  78. package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -6
  79. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +8 -8
  80. package/src/__tests__/guardian-dispatch.test.ts +2 -6
  81. package/src/__tests__/guardian-grant-minting.test.ts +2 -14
  82. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -6
  83. package/src/__tests__/guardian-routing-invariants.test.ts +192 -6
  84. package/src/__tests__/guardian-routing-state.test.ts +2 -6
  85. package/src/__tests__/guardian-verification-voice-binding.test.ts +2 -6
  86. package/src/__tests__/heartbeat-service.test.ts +180 -3
  87. package/src/__tests__/identity-routes.test.ts +328 -0
  88. package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
  89. package/src/__tests__/injection-block.test.ts +178 -0
  90. package/src/__tests__/install-meta.test.ts +506 -0
  91. package/src/__tests__/install-skill-routing.test.ts +293 -0
  92. package/src/__tests__/invite-redemption-service.test.ts +2 -6
  93. package/src/__tests__/invite-routes-http.test.ts +2 -6
  94. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +17 -28
  95. package/src/__tests__/list-messages-attachments.test.ts +2 -6
  96. package/src/__tests__/list-messages-tool-merge.test.ts +300 -0
  97. package/src/__tests__/llm-context-normalization.test.ts +18 -18
  98. package/src/__tests__/llm-context-route-provider.test.ts +103 -6
  99. package/src/__tests__/llm-request-log-turn-query.test.ts +164 -6
  100. package/src/__tests__/llm-usage-store.test.ts +2 -6
  101. package/src/__tests__/log-export-workspace.test.ts +74 -111
  102. package/src/__tests__/managed-store.test.ts +38 -11
  103. package/src/__tests__/mcp-abort-signal.test.ts +5 -0
  104. package/src/__tests__/mcp-client-auth.test.ts +5 -0
  105. package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
  106. package/src/__tests__/memory-recall-log-store.test.ts +134 -6
  107. package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
  108. package/src/__tests__/migration-export-streaming.test.ts +304 -0
  109. package/src/__tests__/migration-import-commit-http.test.ts +11 -10
  110. package/src/__tests__/mock-fetch.ts +87 -0
  111. package/src/__tests__/non-member-access-request.test.ts +2 -6
  112. package/src/__tests__/notification-decision-recipient-context.test.ts +282 -0
  113. package/src/__tests__/notification-guardian-path.test.ts +2 -6
  114. package/src/__tests__/oauth-cli.test.ts +364 -2
  115. package/src/__tests__/oauth2-gateway-transport.test.ts +18 -3
  116. package/src/__tests__/onboarding-template-contract.test.ts +62 -14
  117. package/src/__tests__/outlook-attachments.test.ts +301 -0
  118. package/src/__tests__/outlook-automation-tools.test.ts +425 -0
  119. package/src/__tests__/outlook-categories.test.ts +212 -0
  120. package/src/__tests__/outlook-client-automation.test.ts +246 -0
  121. package/src/__tests__/outlook-compose-tools.test.ts +325 -0
  122. package/src/__tests__/outlook-declutter-tools.test.ts +585 -0
  123. package/src/__tests__/outlook-email-watcher.test.ts +322 -0
  124. package/src/__tests__/outlook-follow-up.test.ts +196 -0
  125. package/src/__tests__/outlook-messaging-provider.test.ts +498 -3
  126. package/src/__tests__/outlook-trash.test.ts +77 -0
  127. package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
  128. package/src/__tests__/parser.test.ts +32 -0
  129. package/src/__tests__/permission-checker-host-gate.test.ts +452 -0
  130. package/src/__tests__/permission-controls-v2-flag.test.ts +55 -0
  131. package/src/__tests__/permission-mode-sse.test.ts +418 -0
  132. package/src/__tests__/permission-mode-store.test.ts +277 -0
  133. package/src/__tests__/permission-mode.test.ts +101 -0
  134. package/src/__tests__/platform-bash-auto-approve.test.ts +359 -0
  135. package/src/__tests__/platform-callback-registration.test.ts +4 -4
  136. package/src/__tests__/playbook-execution.test.ts +76 -80
  137. package/src/__tests__/playbook-tools.test.ts +5 -7
  138. package/src/__tests__/profiler-routes.test.ts +502 -0
  139. package/src/__tests__/profiler-run-store.test.ts +441 -0
  140. package/src/__tests__/provider-error-scenarios.test.ts +21 -0
  141. package/src/__tests__/proxy-approval-callback.test.ts +4 -75
  142. package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
  143. package/src/__tests__/registry.test.ts +3 -3
  144. package/src/__tests__/require-fresh-approval.test.ts +64 -2
  145. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
  146. package/src/__tests__/runtime-events-sse.test.ts +2 -6
  147. package/src/__tests__/sandbox-host-parity.test.ts +5 -4
  148. package/src/__tests__/schedule-store.test.ts +2 -6
  149. package/src/__tests__/schedule-tools.test.ts +2 -6
  150. package/src/__tests__/scheduler-recurrence.test.ts +1 -5
  151. package/src/__tests__/scheduler-reuse-conversation.test.ts +368 -0
  152. package/src/__tests__/scoped-approval-grants.test.ts +2 -6
  153. package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
  154. package/src/__tests__/scrub-corrupted-image-attachments.test.ts +278 -0
  155. package/src/__tests__/search-skills-unified.test.ts +422 -0
  156. package/src/__tests__/secret-onetime-send.test.ts +2 -0
  157. package/src/__tests__/send-endpoint-busy.test.ts +44 -9
  158. package/src/__tests__/sequence-store.test.ts +2 -6
  159. package/src/__tests__/server-history-render.test.ts +2 -6
  160. package/src/__tests__/set-permission-mode.test.ts +274 -0
  161. package/src/__tests__/skill-feature-flags-integration.test.ts +38 -31
  162. package/src/__tests__/skill-feature-flags.test.ts +6 -6
  163. package/src/__tests__/skill-load-feature-flag.test.ts +23 -11
  164. package/src/__tests__/skill-memory.test.ts +2 -741
  165. package/src/__tests__/skills-uninstall.test.ts +2 -2
  166. package/src/__tests__/skills.test.ts +1 -1
  167. package/src/__tests__/slack-inbound-verification.test.ts +2 -6
  168. package/src/__tests__/strip-memory-injections.test.ts +187 -0
  169. package/src/__tests__/subagent-detail.test.ts +84 -0
  170. package/src/__tests__/subagent-disposal.test.ts +308 -0
  171. package/src/__tests__/subagent-manager-notify.test.ts +19 -10
  172. package/src/__tests__/subagent-notify-parent.test.ts +390 -0
  173. package/src/__tests__/subagent-role-registry.test.ts +108 -0
  174. package/src/__tests__/subagent-tool-filtering.test.ts +71 -0
  175. package/src/__tests__/subagent-tools.test.ts +464 -4
  176. package/src/__tests__/system-prompt-ask-mode.test.ts +139 -0
  177. package/src/__tests__/task-compiler.test.ts +2 -6
  178. package/src/__tests__/task-management-tools.test.ts +2 -6
  179. package/src/__tests__/task-memory-cleanup.test.ts +185 -241
  180. package/src/__tests__/task-runner.test.ts +2 -6
  181. package/src/__tests__/task-scheduler.test.ts +2 -6
  182. package/src/__tests__/terminal-tools.test.ts +17 -27
  183. package/src/__tests__/test-preload.ts +7 -0
  184. package/src/__tests__/tool-approval-handler.test.ts +2 -6
  185. package/src/__tests__/tool-executor.test.ts +4 -26
  186. package/src/__tests__/tool-grant-request-escalation.test.ts +2 -6
  187. package/src/__tests__/tool-side-effects-slack-dm.test.ts +277 -0
  188. package/src/__tests__/top-level-renderer.test.ts +10 -13
  189. package/src/__tests__/trust-store.test.ts +1 -1
  190. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +2 -6
  191. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +118 -8
  192. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -6
  193. package/src/__tests__/trusted-contact-verification.test.ts +2 -6
  194. package/src/__tests__/turn-boundary-resolution.test.ts +2 -6
  195. package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -6
  196. package/src/__tests__/usage-routes.test.ts +2 -6
  197. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  198. package/src/__tests__/voice-invite-redemption.test.ts +2 -6
  199. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -6
  200. package/src/__tests__/voice-session-bridge.test.ts +2 -6
  201. package/src/__tests__/volume-security-guard.test.ts +2 -0
  202. package/src/__tests__/workspace-lifecycle.test.ts +29 -1
  203. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -6
  204. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +2 -6
  205. package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
  206. package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +387 -0
  207. package/src/__tests__/workspace-policy.test.ts +1 -1
  208. package/src/agent/attachments.ts +7 -2
  209. package/src/agent/image-optimize.ts +165 -0
  210. package/src/agent/loop.ts +7 -15
  211. package/src/approvals/guardian-request-resolvers.ts +24 -0
  212. package/src/avatar/traits-png-sync.ts +3 -3
  213. package/src/bundler/app-compiler.ts +179 -2
  214. package/src/bundler/package-resolver.ts +3 -5
  215. package/src/cli/__tests__/notifications.test.ts +1 -2
  216. package/src/cli/__tests__/run-assistant-command.ts +29 -0
  217. package/src/cli/commands/__tests__/email-download.test.ts +245 -0
  218. package/src/cli/commands/__tests__/email-list.test.ts +192 -0
  219. package/src/cli/commands/__tests__/email-register.test.ts +186 -0
  220. package/src/cli/commands/__tests__/email-send.test.ts +291 -0
  221. package/src/cli/commands/__tests__/email-status.test.ts +181 -0
  222. package/src/cli/commands/__tests__/email-unregister.test.ts +139 -0
  223. package/src/cli/commands/__tests__/routes.test.ts +562 -0
  224. package/src/cli/commands/avatar.ts +3 -3
  225. package/src/cli/commands/config.ts +26 -13
  226. package/src/cli/commands/conversations.ts +1 -8
  227. package/src/cli/commands/doctor.ts +2 -2
  228. package/src/cli/commands/email.ts +584 -835
  229. package/src/cli/commands/memory.ts +37 -84
  230. package/src/cli/commands/notifications.ts +7 -2
  231. package/src/cli/commands/oauth/__tests__/connect.test.ts +2 -2
  232. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +2 -2
  233. package/src/cli/commands/oauth/__tests__/mode.test.ts +8 -1
  234. package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
  235. package/src/cli/commands/oauth/connect.ts +25 -11
  236. package/src/cli/commands/oauth/mode.ts +7 -0
  237. package/src/cli/commands/oauth/shared.ts +39 -3
  238. package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
  239. package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
  240. package/src/cli/commands/platform/__tests__/status.test.ts +5 -5
  241. package/src/cli/commands/platform/index.ts +16 -16
  242. package/src/cli/commands/routes.ts +396 -0
  243. package/src/cli/commands/skills.ts +218 -36
  244. package/src/cli/commands/trust.ts +2 -2
  245. package/src/cli/lib/daemon-credential-client.ts +2 -3
  246. package/src/cli/program.ts +2 -0
  247. package/src/cli.ts +1 -120
  248. package/src/config/bundled-skills/acp/TOOLS.json +1 -1
  249. package/src/config/bundled-skills/app-builder/SKILL.md +4 -1
  250. package/src/config/bundled-skills/contacts/SKILL.md +0 -1
  251. package/src/config/bundled-skills/contacts/TOOLS.json +0 -8
  252. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -4
  253. package/src/config/bundled-skills/gmail/SKILL.md +4 -12
  254. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
  255. package/src/config/bundled-skills/messaging/SKILL.md +17 -18
  256. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +40 -33
  257. package/src/config/bundled-skills/outlook/SKILL.md +189 -0
  258. package/src/config/bundled-skills/outlook/TOOLS.json +530 -0
  259. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +85 -0
  260. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +77 -0
  261. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +84 -0
  262. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +94 -0
  263. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +49 -0
  264. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +237 -0
  265. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +161 -0
  266. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +32 -0
  267. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +272 -0
  268. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +29 -0
  269. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +129 -0
  270. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +87 -0
  271. package/src/config/bundled-skills/outlook/tools/shared.ts +20 -0
  272. package/src/config/bundled-skills/outlook-calendar/SKILL.md +51 -0
  273. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +221 -0
  274. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +252 -0
  275. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +53 -0
  276. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +74 -0
  277. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +18 -0
  278. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +46 -0
  279. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +36 -0
  280. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +17 -0
  281. package/src/config/bundled-skills/outlook-calendar/types.ts +120 -0
  282. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +47 -40
  283. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +16 -29
  284. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +16 -18
  285. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +39 -47
  286. package/src/config/bundled-skills/schedule/SKILL.md +22 -2
  287. package/src/config/bundled-skills/schedule/TOOLS.json +8 -0
  288. package/src/config/bundled-skills/settings/tools/avatar-get.ts +3 -13
  289. package/src/config/bundled-skills/settings/tools/avatar-remove.ts +2 -4
  290. package/src/config/bundled-skills/settings/tools/avatar-update.ts +5 -2
  291. package/src/config/bundled-skills/slack/SKILL.md +3 -7
  292. package/src/config/bundled-skills/subagent/SKILL.md +43 -3
  293. package/src/config/bundled-skills/subagent/TOOLS.json +29 -4
  294. package/src/config/bundled-tool-registry.ts +56 -4
  295. package/src/config/env-registry.ts +78 -8
  296. package/src/config/feature-flag-registry.json +38 -125
  297. package/src/config/schema.ts +8 -0
  298. package/src/config/schemas/filing.ts +51 -0
  299. package/src/config/schemas/heartbeat.ts +15 -12
  300. package/src/config/schemas/memory-lifecycle.ts +12 -0
  301. package/src/config/schemas/platform.ts +8 -0
  302. package/src/config/schemas/security.ts +14 -0
  303. package/src/config/schemas/timeouts.ts +1 -1
  304. package/src/config/skills.ts +18 -7
  305. package/src/context/token-estimator.ts +25 -18
  306. package/src/context/window-manager.ts +6 -2
  307. package/src/credential-execution/process-manager.ts +3 -1
  308. package/src/daemon/app-source-watcher.ts +93 -0
  309. package/src/daemon/config-watcher.ts +79 -1
  310. package/src/daemon/context-overflow-reducer.ts +46 -2
  311. package/src/daemon/conversation-agent-loop-handlers.ts +143 -82
  312. package/src/daemon/conversation-agent-loop.ts +236 -108
  313. package/src/daemon/conversation-error.ts +31 -8
  314. package/src/daemon/conversation-history.ts +4 -19
  315. package/src/daemon/conversation-lifecycle.ts +36 -9
  316. package/src/daemon/conversation-media-retry.ts +85 -7
  317. package/src/daemon/conversation-notifiers.ts +4 -1
  318. package/src/daemon/conversation-process.ts +13 -7
  319. package/src/daemon/conversation-runtime-assembly.ts +305 -306
  320. package/src/daemon/conversation-tool-setup.ts +44 -14
  321. package/src/daemon/conversation-workspace.ts +1 -2
  322. package/src/daemon/conversation.ts +59 -2
  323. package/src/daemon/daemon-control.ts +8 -2
  324. package/src/daemon/date-context.ts +26 -53
  325. package/src/daemon/first-greeting.ts +1 -1
  326. package/src/daemon/handlers/conversations.ts +4 -7
  327. package/src/daemon/handlers/shared.test.ts +143 -0
  328. package/src/daemon/handlers/shared.ts +85 -17
  329. package/src/daemon/handlers/skills.ts +416 -209
  330. package/src/daemon/lifecycle.ts +212 -131
  331. package/src/daemon/main.ts +5 -1
  332. package/src/daemon/message-types/conversations.ts +29 -7
  333. package/src/daemon/message-types/messages.ts +12 -2
  334. package/src/daemon/message-types/schedules.ts +1 -0
  335. package/src/daemon/message-types/settings.ts +6 -0
  336. package/src/daemon/message-types/skills.ts +97 -36
  337. package/src/daemon/profiler-run-store.ts +557 -0
  338. package/src/daemon/providers-setup.ts +5 -0
  339. package/src/daemon/server.ts +100 -11
  340. package/src/daemon/shutdown-handlers.ts +5 -0
  341. package/src/daemon/tool-side-effects.ts +50 -8
  342. package/src/export/transcript-formatter.ts +148 -0
  343. package/src/filing/filing-service.ts +228 -0
  344. package/src/heartbeat/heartbeat-service.ts +97 -7
  345. package/src/hooks/cli.ts +2 -2
  346. package/src/hooks/runner.ts +15 -38
  347. package/src/inbound/platform-callback-registration.ts +14 -14
  348. package/src/mcp/client.ts +6 -0
  349. package/src/mcp/mcp-oauth-provider.ts +149 -27
  350. package/src/memory/admin.ts +42 -75
  351. package/src/memory/app-store.ts +69 -0
  352. package/src/memory/conversation-bootstrap.ts +3 -1
  353. package/src/memory/conversation-crud.ts +211 -288
  354. package/src/memory/conversation-group-migration.ts +157 -0
  355. package/src/memory/conversation-queries.ts +61 -13
  356. package/src/memory/conversation-title-service.ts +1 -0
  357. package/src/memory/db-init.ts +194 -361
  358. package/src/memory/embed.ts +73 -0
  359. package/src/memory/embedding-backend.ts +8 -14
  360. package/src/memory/embedding-runtime-manager.ts +12 -114
  361. package/src/memory/fingerprint.ts +2 -2
  362. package/src/memory/graph/bootstrap.ts +521 -0
  363. package/src/memory/graph/capability-seed.ts +449 -0
  364. package/src/memory/graph/consolidation.ts +725 -0
  365. package/src/memory/graph/conversation-graph-memory.ts +659 -0
  366. package/src/memory/graph/decay.test.ts +208 -0
  367. package/src/memory/graph/decay.ts +195 -0
  368. package/src/memory/graph/extraction-job.ts +74 -0
  369. package/src/memory/graph/extraction.test.ts +936 -0
  370. package/src/memory/graph/extraction.ts +1297 -0
  371. package/src/memory/graph/graph-memory-state-store.ts +37 -0
  372. package/src/memory/graph/graph-search.ts +280 -0
  373. package/src/memory/graph/image-ref-utils.ts +29 -0
  374. package/src/memory/graph/injection.test.ts +513 -0
  375. package/src/memory/graph/injection.ts +469 -0
  376. package/src/memory/graph/inspect.ts +543 -0
  377. package/src/memory/graph/narrative.ts +267 -0
  378. package/src/memory/graph/pattern-scan.ts +269 -0
  379. package/src/memory/graph/retriever.ts +1111 -0
  380. package/src/memory/graph/scoring.test.ts +548 -0
  381. package/src/memory/graph/scoring.ts +232 -0
  382. package/src/memory/graph/serendipity.ts +65 -0
  383. package/src/memory/graph/store.test.ts +1098 -0
  384. package/src/memory/graph/store.ts +838 -0
  385. package/src/memory/graph/tool-handlers.ts +301 -0
  386. package/src/memory/graph/tools.ts +97 -0
  387. package/src/memory/graph/triggers.test.ts +487 -0
  388. package/src/memory/graph/triggers.ts +223 -0
  389. package/src/memory/graph/types.ts +295 -0
  390. package/src/memory/group-crud.ts +191 -0
  391. package/src/memory/indexer.ts +37 -19
  392. package/src/memory/job-handlers/cleanup.ts +32 -42
  393. package/src/memory/job-handlers/conversation-starters.ts +91 -53
  394. package/src/memory/job-handlers/embedding.ts +5 -31
  395. package/src/memory/job-handlers/index-maintenance.ts +23 -11
  396. package/src/memory/job-handlers/summarization.ts +32 -17
  397. package/src/memory/job-utils.ts +1 -1
  398. package/src/memory/jobs-store.ts +21 -31
  399. package/src/memory/jobs-worker.ts +180 -129
  400. package/src/memory/llm-request-log-store.ts +96 -12
  401. package/src/memory/memory-recall-log-store.ts +49 -5
  402. package/src/memory/message-content.ts +1 -0
  403. package/src/memory/migrations/202-memory-graph-tables.ts +130 -0
  404. package/src/memory/migrations/203-drop-memory-items-tables.ts +55 -0
  405. package/src/memory/migrations/204-rename-memory-graph-type-values.ts +46 -0
  406. package/src/memory/migrations/205-memory-graph-image-refs.ts +11 -0
  407. package/src/memory/migrations/206-memory-graph-node-edits.ts +19 -0
  408. package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +131 -0
  409. package/src/memory/migrations/207-conversation-graph-memory-state.ts +20 -0
  410. package/src/memory/migrations/208-conversations-last-message-at.ts +35 -0
  411. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +85 -0
  412. package/src/memory/migrations/210-schedule-reuse-conversation.ts +13 -0
  413. package/src/memory/migrations/211-memory-recall-logs-query-context.ts +21 -0
  414. package/src/memory/migrations/212-llm-request-logs-created-at-index.ts +19 -0
  415. package/src/memory/migrations/index.ts +12 -0
  416. package/src/memory/migrations/registry.ts +16 -0
  417. package/src/memory/qdrant-client.ts +44 -17
  418. package/src/memory/schema/conversations.ts +14 -0
  419. package/src/memory/schema/index.ts +1 -0
  420. package/src/memory/schema/infrastructure.ts +8 -1
  421. package/src/memory/schema/memory-core.ts +0 -51
  422. package/src/memory/schema/memory-graph.ts +154 -0
  423. package/src/memory/search/semantic.ts +47 -91
  424. package/src/memory/task-memory-cleanup.ts +58 -61
  425. package/src/messaging/providers/outlook/adapter.ts +8 -1
  426. package/src/messaging/providers/outlook/client.ts +299 -0
  427. package/src/messaging/providers/outlook/types.ts +118 -0
  428. package/src/notifications/adapters/macos.ts +1 -0
  429. package/src/notifications/copy-composer.ts +95 -0
  430. package/src/notifications/decision-engine.ts +35 -0
  431. package/src/notifications/signal.ts +16 -0
  432. package/src/oauth/seed-providers.ts +2 -1
  433. package/src/permissions/checker.ts +36 -4
  434. package/src/permissions/defaults.ts +4 -4
  435. package/src/permissions/permission-mode-store.ts +180 -0
  436. package/src/permissions/permission-mode.ts +31 -0
  437. package/src/permissions/workspace-policy.ts +10 -1
  438. package/src/playbooks/playbook-compiler.ts +19 -18
  439. package/src/playbooks/types.ts +4 -3
  440. package/src/prompts/system-prompt.ts +62 -36
  441. package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +100 -0
  442. package/src/prompts/templates/BOOTSTRAP.md +70 -165
  443. package/src/prompts/templates/HEARTBEAT.md +3 -1
  444. package/src/prompts/templates/SOUL.md +25 -4
  445. package/src/prompts/templates/UPDATES.md +8 -0
  446. package/src/providers/anthropic/client.ts +136 -220
  447. package/src/providers/gemini/client.ts +1 -1
  448. package/src/providers/openai/client.ts +1 -1
  449. package/src/providers/registry.ts +1 -1
  450. package/src/providers/retry.ts +19 -3
  451. package/src/runtime/actor-trust-resolver.ts +5 -1
  452. package/src/runtime/auth/route-policy.ts +30 -0
  453. package/src/runtime/guardian-reply-router.ts +5 -1
  454. package/src/runtime/http-server.ts +55 -5
  455. package/src/runtime/http-types.ts +12 -1
  456. package/src/runtime/middleware/auth.ts +20 -0
  457. package/src/runtime/migrations/vbundle-builder.ts +389 -3
  458. package/src/runtime/migrations/vbundle-importer.ts +8 -6
  459. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +378 -0
  460. package/src/runtime/routes/app-management-routes.ts +1 -11
  461. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +26 -0
  462. package/src/runtime/routes/archive-utils.ts +29 -0
  463. package/src/runtime/routes/attachment-routes.test.ts +106 -0
  464. package/src/runtime/routes/attachment-routes.ts +106 -16
  465. package/src/runtime/routes/avatar-routes.ts +2 -9
  466. package/src/runtime/routes/brain-graph-routes.ts +21 -22
  467. package/src/runtime/routes/btw-routes.ts +22 -1
  468. package/src/runtime/routes/conversation-analysis-routes.ts +173 -0
  469. package/src/runtime/routes/conversation-management-routes.ts +3 -14
  470. package/src/runtime/routes/conversation-query-routes.ts +49 -3
  471. package/src/runtime/routes/conversation-routes.ts +264 -44
  472. package/src/runtime/routes/conversation-starter-routes.ts +2 -2
  473. package/src/runtime/routes/debug-routes.ts +1 -1
  474. package/src/runtime/routes/global-search-routes.ts +21 -19
  475. package/src/runtime/routes/group-routes.ts +207 -0
  476. package/src/runtime/routes/guardian-action-routes.ts +21 -10
  477. package/src/runtime/routes/guardian-bootstrap-routes.ts +23 -19
  478. package/src/runtime/routes/heartbeat-routes.ts +4 -10
  479. package/src/runtime/routes/identity-routes.ts +53 -18
  480. package/src/runtime/routes/inbound-message-handler.ts +19 -0
  481. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +292 -0
  482. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +207 -0
  483. package/src/runtime/routes/llm-context-normalization.ts +14 -10
  484. package/src/runtime/routes/log-export-routes.ts +23 -275
  485. package/src/runtime/routes/memory-item-routes.test.ts +170 -247
  486. package/src/runtime/routes/memory-item-routes.ts +341 -388
  487. package/src/runtime/routes/migration-routes.ts +18 -7
  488. package/src/runtime/routes/profiler-routes.ts +350 -0
  489. package/src/runtime/routes/schedule-routes.ts +28 -11
  490. package/src/runtime/routes/settings-routes.ts +95 -8
  491. package/src/runtime/routes/skills-routes.ts +103 -37
  492. package/src/runtime/routes/subagents-routes.ts +28 -7
  493. package/src/runtime/routes/user-route-dispatcher.ts +223 -0
  494. package/src/runtime/routes/user-routes.ts +41 -0
  495. package/src/runtime/routes/work-items-routes.test.ts +2 -6
  496. package/src/runtime/routes/workspace-routes.ts +0 -1
  497. package/src/schedule/schedule-store.ts +30 -0
  498. package/src/schedule/scheduler.ts +52 -18
  499. package/src/security/oauth2.ts +1 -1
  500. package/src/security/secure-keys.ts +4 -8
  501. package/src/shared/provider-env-vars.ts +19 -0
  502. package/src/skills/catalog-cache.ts +5 -0
  503. package/src/skills/catalog-install.ts +25 -16
  504. package/src/skills/clawhub.ts +134 -154
  505. package/src/skills/install-meta.ts +208 -0
  506. package/src/skills/managed-store.ts +29 -18
  507. package/src/skills/skill-memory.ts +12 -229
  508. package/src/skills/skillssh-registry.ts +19 -17
  509. package/src/subagent/index.ts +13 -3
  510. package/src/subagent/manager.ts +308 -29
  511. package/src/subagent/types.ts +68 -0
  512. package/src/tasks/task-runner.ts +7 -5
  513. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
  514. package/src/tools/apps/executors.ts +29 -4
  515. package/src/tools/browser/runtime-check.ts +3 -1
  516. package/src/tools/filesystem/list.ts +93 -0
  517. package/src/tools/memory/register.ts +63 -46
  518. package/src/tools/permission-checker.ts +85 -1
  519. package/src/tools/registry.ts +4 -0
  520. package/src/tools/schedule/create.ts +3 -0
  521. package/src/tools/schedule/list.ts +1 -0
  522. package/src/tools/schedule/update.ts +6 -0
  523. package/src/tools/shared/filesystem/errors.ts +5 -0
  524. package/src/tools/shared/filesystem/file-ops-service.ts +90 -2
  525. package/src/tools/shared/filesystem/image-read.ts +22 -85
  526. package/src/tools/shared/filesystem/types.ts +17 -0
  527. package/src/tools/shared/shell-output.ts +31 -2
  528. package/src/tools/subagent/abort.ts +12 -2
  529. package/src/tools/subagent/message.ts +9 -2
  530. package/src/tools/subagent/notify-parent.ts +79 -0
  531. package/src/tools/subagent/read.ts +29 -8
  532. package/src/tools/subagent/resolve.ts +21 -0
  533. package/src/tools/subagent/spawn.ts +2 -0
  534. package/src/tools/subagent/status.ts +11 -1
  535. package/src/tools/system/avatar-generator.ts +3 -3
  536. package/src/tools/system/register.ts +23 -0
  537. package/src/tools/system/set-permission-mode.ts +103 -0
  538. package/src/tools/terminal/parser.ts +30 -5
  539. package/src/tools/terminal/safe-env.ts +17 -1
  540. package/src/tools/tool-manifest.ts +9 -3
  541. package/src/tools/types.ts +2 -0
  542. package/src/util/browser.ts +25 -10
  543. package/src/util/bun-runtime.ts +172 -0
  544. package/src/util/logger.ts +1 -1
  545. package/src/util/platform.ts +50 -17
  546. package/src/watcher/providers/outlook-calendar.ts +343 -0
  547. package/src/watcher/providers/outlook.ts +198 -0
  548. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +2 -2
  549. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +2 -2
  550. package/src/workspace/migrations/025-remove-oauth-app-setup-skills.ts +76 -0
  551. package/src/workspace/migrations/026-backfill-install-meta.ts +325 -0
  552. package/src/workspace/migrations/027-remove-orphaned-optimized-images-cache.ts +42 -0
  553. package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +270 -0
  554. package/src/workspace/migrations/029-seed-pkb.ts +84 -0
  555. package/src/workspace/migrations/registry.ts +10 -0
  556. package/src/workspace/top-level-renderer.ts +5 -9
  557. package/src/__tests__/cli-memory.test.ts +0 -372
  558. package/src/__tests__/clipboard.test.ts +0 -88
  559. package/src/__tests__/context-memory-e2e.test.ts +0 -415
  560. package/src/__tests__/journal-context.test.ts +0 -268
  561. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -297
  562. package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -459
  563. package/src/__tests__/memory-query-builder.test.ts +0 -59
  564. package/src/__tests__/memory-recall-quality.test.ts +0 -1046
  565. package/src/__tests__/memory-regressions.experimental.test.ts +0 -629
  566. package/src/__tests__/memory-regressions.test.ts +0 -3696
  567. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -295
  568. package/src/cli/cli-memory.ts +0 -176
  569. package/src/daemon/conversation-memory.ts +0 -207
  570. package/src/memory/conversation-starters-cadence.ts +0 -74
  571. package/src/memory/items-extractor.ts +0 -860
  572. package/src/memory/job-handlers/batch-extraction.ts +0 -753
  573. package/src/memory/job-handlers/extraction.ts +0 -40
  574. package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -355
  575. package/src/memory/job-handlers/journal-carry-forward.ts +0 -255
  576. package/src/memory/journal-memory.ts +0 -224
  577. package/src/memory/query-builder.ts +0 -47
  578. package/src/memory/query-expansion.ts +0 -83
  579. package/src/memory/retriever.test.ts +0 -1592
  580. package/src/memory/retriever.ts +0 -1331
  581. package/src/memory/search/formatting.test.ts +0 -140
  582. package/src/memory/search/formatting.ts +0 -262
  583. package/src/memory/search/mmr.ts +0 -139
  584. package/src/memory/search/ranking.ts +0 -15
  585. package/src/memory/search/staleness.ts +0 -40
  586. package/src/memory/search/tier-classifier.ts +0 -18
  587. package/src/memory/search/types.ts +0 -121
  588. package/src/prompts/journal-context.ts +0 -154
  589. package/src/tools/memory/definitions.ts +0 -69
  590. package/src/tools/memory/handlers.test.ts +0 -562
  591. package/src/tools/memory/handlers.ts +0 -434
  592. package/src/util/clipboard.ts +0 -34
@@ -20,7 +20,7 @@ export interface QdrantClientConfig {
20
20
  }
21
21
 
22
22
  export interface QdrantPointPayload {
23
- target_type: "segment" | "item" | "summary" | "media";
23
+ target_type: "segment" | "item" | "summary" | "media" | "graph_node";
24
24
  target_id: string;
25
25
  text: string;
26
26
  kind?: string;
@@ -47,14 +47,14 @@ let _instance: VellumQdrantClient | null = null;
47
47
  export function getQdrantClient(): VellumQdrantClient {
48
48
  if (!_instance) {
49
49
  throw new Error(
50
- "Qdrant client not initialized. Call initQdrantClient() first.",
50
+ "Qdrant client not initialized. Call initQdrantClient() first."
51
51
  );
52
52
  }
53
53
  return _instance;
54
54
  }
55
55
 
56
56
  export function initQdrantClient(
57
- config: QdrantClientConfig,
57
+ config: QdrantClientConfig
58
58
  ): VellumQdrantClient {
59
59
  _instance = new VellumQdrantClient(config);
60
60
  return _instance;
@@ -125,7 +125,7 @@ export class VellumQdrantClient {
125
125
  currentSize,
126
126
  expectedSize: this.vectorSize,
127
127
  },
128
- "Qdrant collection uses unnamed vectors (legacy) — deleting and recreating with named vectors. Embeddings will be re-indexed.",
128
+ "Qdrant collection uses unnamed vectors (legacy) — deleting and recreating with named vectors. Embeddings will be re-indexed."
129
129
  );
130
130
  await this.client.deleteCollection(this.collection);
131
131
  migrated = true;
@@ -138,7 +138,7 @@ export class VellumQdrantClient {
138
138
  expectedSize: this.vectorSize,
139
139
  modelMismatch,
140
140
  },
141
- "Qdrant collection incompatible (dimension or model change) — deleting and recreating. Embeddings will be regenerated on demand.",
141
+ "Qdrant collection incompatible (dimension or model change) — deleting and recreating. Embeddings will be regenerated on demand."
142
142
  );
143
143
  await this.client.deleteCollection(this.collection);
144
144
  migrated = true;
@@ -152,7 +152,7 @@ export class VellumQdrantClient {
152
152
  } catch (err) {
153
153
  log.warn(
154
154
  { err },
155
- "Failed to verify collection compatibility, assuming compatible",
155
+ "Failed to verify collection compatibility, assuming compatible"
156
156
  );
157
157
  if (await this.ensurePayloadIndexesSafe()) {
158
158
  this.collectionReady = true;
@@ -166,7 +166,7 @@ export class VellumQdrantClient {
166
166
 
167
167
  log.info(
168
168
  { collection: this.collection, vectorSize: this.vectorSize },
169
- "Creating Qdrant collection with named vectors (dense + sparse)",
169
+ "Creating Qdrant collection with named vectors (dense + sparse)"
170
170
  );
171
171
 
172
172
  try {
@@ -222,7 +222,7 @@ export class VellumQdrantClient {
222
222
  this.collectionReady = true;
223
223
  log.info(
224
224
  { collection: this.collection },
225
- "Qdrant collection created with payload indexes",
225
+ "Qdrant collection created with payload indexes"
226
226
  );
227
227
  }
228
228
 
@@ -230,11 +230,11 @@ export class VellumQdrantClient {
230
230
  }
231
231
 
232
232
  async upsert(
233
- targetType: "segment" | "item" | "summary" | "media",
233
+ targetType: QdrantPointPayload["target_type"],
234
234
  targetId: string,
235
235
  vector: number[],
236
236
  payload: Omit<QdrantPointPayload, "target_type" | "target_id">,
237
- sparseVector?: QdrantSparseVector,
237
+ sparseVector?: QdrantSparseVector
238
238
  ): Promise<string> {
239
239
  await this.ensureCollection();
240
240
 
@@ -289,7 +289,7 @@ export class VellumQdrantClient {
289
289
  async search(
290
290
  vector: number[],
291
291
  limit: number,
292
- filter?: Record<string, unknown>,
292
+ filter?: Record<string, unknown>
293
293
  ): Promise<QdrantSearchResult[]> {
294
294
  await this.ensureCollection();
295
295
 
@@ -317,7 +317,7 @@ export class VellumQdrantClient {
317
317
  return results.map((result) => ({
318
318
  id: typeof result.id === "string" ? result.id : String(result.id),
319
319
  score: result.score,
320
- payload: result.payload as unknown as QdrantPointPayload,
320
+ payload: (result.payload as unknown) as QdrantPointPayload,
321
321
  }));
322
322
  }
323
323
 
@@ -326,7 +326,7 @@ export class VellumQdrantClient {
326
326
  limit: number,
327
327
  targetTypes: Array<"segment" | "item" | "summary" | "media">,
328
328
  excludeMessageIds?: string[],
329
- scopeIds?: string[],
329
+ scopeIds?: string[]
330
330
  ): Promise<QdrantSearchResult[]> {
331
331
  const mustConditions: Array<Record<string, unknown>> = [
332
332
  {
@@ -403,7 +403,7 @@ export class VellumQdrantClient {
403
403
  const queryParams = {
404
404
  prefetch: [
405
405
  {
406
- query: denseVector as unknown as number[],
406
+ query: (denseVector as unknown) as number[],
407
407
  using: "dense",
408
408
  limit: effectivePrefetchLimit,
409
409
  },
@@ -438,7 +438,7 @@ export class VellumQdrantClient {
438
438
  return (results.points ?? []).map((point) => ({
439
439
  id: typeof point.id === "string" ? point.id : String(point.id),
440
440
  score: point.score ?? 0,
441
- payload: point.payload as unknown as QdrantPointPayload,
441
+ payload: (point.payload as unknown) as QdrantPointPayload,
442
442
  }));
443
443
  }
444
444
 
@@ -469,6 +469,33 @@ export class VellumQdrantClient {
469
469
  }
470
470
  }
471
471
 
472
+ /**
473
+ * Delete all vectors matching a given target_type (bulk cleanup).
474
+ */
475
+ async deleteByTargetType(targetType: string): Promise<void> {
476
+ await this.ensureCollection();
477
+
478
+ const doDelete = () =>
479
+ this.client.delete(this.collection, {
480
+ wait: true,
481
+ filter: {
482
+ must: [{ key: "target_type", match: { value: targetType } }],
483
+ },
484
+ });
485
+
486
+ try {
487
+ await doDelete();
488
+ } catch (err) {
489
+ if (this.isCollectionMissing(err)) {
490
+ this.collectionReady = false;
491
+ await this.ensureCollection();
492
+ await doDelete();
493
+ } else {
494
+ throw err;
495
+ }
496
+ }
497
+ }
498
+
472
499
  async count(): Promise<number> {
473
500
  await this.ensureCollection();
474
501
 
@@ -498,7 +525,7 @@ export class VellumQdrantClient {
498
525
  } catch (err) {
499
526
  log.warn(
500
527
  { err, collection: this.collection },
501
- "Failed to delete Qdrant collection",
528
+ "Failed to delete Qdrant collection"
502
529
  );
503
530
  return false;
504
531
  }
@@ -615,7 +642,7 @@ export class VellumQdrantClient {
615
642
 
616
643
  private async findByTarget(
617
644
  targetType: string,
618
- targetId: string,
645
+ targetId: string
619
646
  ): Promise<string | null> {
620
647
  try {
621
648
  const results = await this.client.scroll(this.collection, {
@@ -30,9 +30,11 @@ export const conversations = sqliteTable(
30
30
  forkParentMessageId: text("fork_parent_message_id"),
31
31
  isAutoTitle: integer("is_auto_title").notNull().default(1),
32
32
  scheduleJobId: text("schedule_job_id"),
33
+ lastMessageAt: integer("last_message_at"),
33
34
  },
34
35
  (table) => [
35
36
  index("idx_conversations_updated_at").on(table.updatedAt),
37
+ index("idx_conversations_last_message_at").on(table.lastMessageAt),
36
38
  index("idx_conversations_conversation_type").on(table.conversationType),
37
39
  index("idx_conversations_fork_parent_conversation_id").on(
38
40
  table.forkParentConversationId,
@@ -109,6 +111,18 @@ export const messageAttachments = sqliteTable("message_attachments", {
109
111
  createdAt: integer("created_at").notNull(),
110
112
  });
111
113
 
114
+ export const conversationGraphMemoryState = sqliteTable(
115
+ "conversation_graph_memory_state",
116
+ {
117
+ conversationId: text("conversation_id")
118
+ .primaryKey()
119
+ .references(() => conversations.id, { onDelete: "cascade" }),
120
+ stateJson: text("state_json").notNull(),
121
+ createdAt: integer("created_at").notNull(),
122
+ updatedAt: integer("updated_at").notNull(),
123
+ },
124
+ );
125
+
112
126
  export const channelInboundEvents = sqliteTable("channel_inbound_events", {
113
127
  id: text("id").primaryKey(),
114
128
  sourceChannel: text("source_channel").notNull(),
@@ -4,6 +4,7 @@ export * from "./conversations.js";
4
4
  export * from "./guardian.js";
5
5
  export * from "./infrastructure.js";
6
6
  export * from "./memory-core.js";
7
+ export * from "./memory-graph.js";
7
8
  export * from "./notifications.js";
8
9
  export * from "./oauth.js";
9
10
  export * from "./tasks.js";
@@ -25,6 +25,9 @@ export const cronJobs = sqliteTable("cron_jobs", {
25
25
  routingHintsJson: text("routing_hints_json").notNull().default("{}"),
26
26
  status: text("status").notNull().default("active"), // 'active' | 'firing' | 'fired' | 'cancelled'
27
27
  quiet: integer("quiet", { mode: "boolean" }).notNull().default(false), // suppress completion notifications
28
+ reuseConversation: integer("reuse_conversation", { mode: "boolean" })
29
+ .notNull()
30
+ .default(false), // reuse the same conversation across runs
28
31
  createdAt: integer("created_at").notNull(),
29
32
  updatedAt: integer("updated_at").notNull(),
30
33
  });
@@ -118,7 +121,10 @@ export const llmRequestLogs = sqliteTable(
118
121
  responsePayload: text("response_payload").notNull(),
119
122
  createdAt: integer("created_at").notNull(),
120
123
  },
121
- (table) => [index("idx_llm_request_logs_message_id").on(table.messageId)],
124
+ (table) => [
125
+ index("idx_llm_request_logs_message_id").on(table.messageId),
126
+ index("idx_llm_request_logs_created_at").on(table.createdAt),
127
+ ],
122
128
  );
123
129
 
124
130
  export const memoryRecallLogs = sqliteTable(
@@ -144,6 +150,7 @@ export const memoryRecallLogs = sqliteTable(
144
150
  topCandidatesJson: text("top_candidates_json").notNull(),
145
151
  injectedText: text("injected_text"),
146
152
  reason: text("reason"),
153
+ queryContext: text("query_context"),
147
154
  createdAt: integer("created_at").notNull(),
148
155
  },
149
156
  (table) => [
@@ -2,7 +2,6 @@ import {
2
2
  blob,
3
3
  index,
4
4
  integer,
5
- real,
6
5
  sqliteTable,
7
6
  text,
8
7
  uniqueIndex,
@@ -32,56 +31,6 @@ export const memorySegments = sqliteTable(
32
31
  (table) => [index("idx_memory_segments_scope_id").on(table.scopeId)],
33
32
  );
34
33
 
35
- export const memoryItems = sqliteTable(
36
- "memory_items",
37
- {
38
- id: text("id").primaryKey(),
39
- kind: text("kind").notNull(),
40
- subject: text("subject").notNull(),
41
- statement: text("statement").notNull(),
42
- status: text("status").notNull(),
43
- confidence: real("confidence").notNull(),
44
- importance: real("importance"),
45
- accessCount: integer("access_count").notNull().default(0),
46
- fingerprint: text("fingerprint").notNull(),
47
- verificationState: text("verification_state")
48
- .notNull()
49
- .default("assistant_inferred"),
50
- scopeId: text("scope_id").notNull().default("default"),
51
- firstSeenAt: integer("first_seen_at").notNull(),
52
- lastSeenAt: integer("last_seen_at").notNull(),
53
- lastUsedAt: integer("last_used_at"),
54
- validFrom: integer("valid_from"),
55
- invalidAt: integer("invalid_at"),
56
- supersedes: text("supersedes"),
57
- supersededBy: text("superseded_by"),
58
- overrideConfidence: text("override_confidence").default("inferred"),
59
- sourceType: text("source_type").notNull().default("extraction"),
60
- sourceMessageRole: text("source_message_role"),
61
- },
62
- (table) => [
63
- index("idx_memory_items_scope_id").on(table.scopeId),
64
- index("idx_memory_items_fingerprint").on(table.fingerprint),
65
- ],
66
- );
67
-
68
- export const memoryItemSources = sqliteTable(
69
- "memory_item_sources",
70
- {
71
- memoryItemId: text("memory_item_id")
72
- .notNull()
73
- .references(() => memoryItems.id, { onDelete: "cascade" }),
74
- messageId: text("message_id")
75
- .notNull()
76
- .references(() => messages.id, { onDelete: "cascade" }),
77
- evidence: text("evidence"),
78
- createdAt: integer("created_at").notNull(),
79
- },
80
- (table) => [
81
- index("idx_memory_item_sources_memory_item_id").on(table.memoryItemId),
82
- ],
83
- );
84
-
85
34
  export const memorySummaries = sqliteTable(
86
35
  "memory_summaries",
87
36
  {
@@ -0,0 +1,154 @@
1
+ import {
2
+ blob,
3
+ index,
4
+ integer,
5
+ real,
6
+ sqliteTable,
7
+ text,
8
+ } from "drizzle-orm/sqlite-core";
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // Memory Graph — Drizzle ORM schema
12
+ // ---------------------------------------------------------------------------
13
+
14
+ export const memoryGraphNodes = sqliteTable(
15
+ "memory_graph_nodes",
16
+ {
17
+ id: text("id").primaryKey(),
18
+
19
+ /** First-person prose — how the assistant naturally remembers this. */
20
+ content: text("content").notNull(),
21
+ /** Memory type: episodic, semantic, procedural, emotional, prospective, behavioral, narrative, shared. */
22
+ type: text("type").notNull(),
23
+
24
+ // -- Temporal --
25
+ /** Epoch ms. Hour/dayOfWeek/month derived at query time via Date. */
26
+ created: integer("created").notNull(),
27
+ /** Epoch ms. Decay-rate modifier only — NOT a retrieval signal. */
28
+ lastAccessed: integer("last_accessed").notNull(),
29
+ /** Epoch ms of last consolidation pass. */
30
+ lastConsolidated: integer("last_consolidated").notNull(),
31
+ /** Epoch ms of the event this memory describes (null for non-event memories). */
32
+ eventDate: integer("event_date"),
33
+
34
+ // -- Energy --
35
+ /** JSON-serialized EmotionalCharge object. Read/written atomically. */
36
+ emotionalCharge: text("emotional_charge").notNull(),
37
+ /** vivid | clear | faded | gist | gone */
38
+ fidelity: text("fidelity").notNull().default("vivid"),
39
+ /** 0–1. How sure the assistant is this is accurate. */
40
+ confidence: real("confidence").notNull(),
41
+ /** 0–1. How important. Subject to Ebbinghaus decay. */
42
+ significance: real("significance").notNull(),
43
+
44
+ // -- Reinforcement --
45
+ /** Resistance to decay. Grows ×1.5 per reinforcement. */
46
+ stability: real("stability").notNull().default(14),
47
+ /** How many times confirmed/reinforced. */
48
+ reinforcementCount: integer("reinforcement_count").notNull().default(0),
49
+ /** Epoch ms. */
50
+ lastReinforced: integer("last_reinforced").notNull(),
51
+
52
+ // -- Provenance --
53
+ /** JSON array of conversation IDs. */
54
+ sourceConversations: text("source_conversations").notNull().default("[]"),
55
+ /** direct | inferred | observed | told-by-other */
56
+ sourceType: text("source_type").notNull().default("inferred"),
57
+
58
+ // -- Narrative --
59
+ narrativeRole: text("narrative_role"),
60
+ partOfStory: text("part_of_story"),
61
+
62
+ /** Memory scope for multi-scope isolation. */
63
+ scopeId: text("scope_id").notNull().default("default"),
64
+
65
+ /** JSON array of ImageRef objects — images attached to this memory. */
66
+ imageRefs: text("image_refs"),
67
+ },
68
+ (table) => [
69
+ index("idx_graph_nodes_scope_id").on(table.scopeId),
70
+ index("idx_graph_nodes_type").on(table.type),
71
+ index("idx_graph_nodes_fidelity").on(table.fidelity),
72
+ index("idx_graph_nodes_created").on(table.created),
73
+ index("idx_graph_nodes_significance").on(table.significance),
74
+ index("idx_graph_nodes_event_date").on(table.eventDate),
75
+ ],
76
+ );
77
+
78
+ export const memoryGraphEdges = sqliteTable(
79
+ "memory_graph_edges",
80
+ {
81
+ id: text("id").primaryKey(),
82
+ sourceNodeId: text("source_node_id")
83
+ .notNull()
84
+ .references(() => memoryGraphNodes.id, { onDelete: "cascade" }),
85
+ targetNodeId: text("target_node_id")
86
+ .notNull()
87
+ .references(() => memoryGraphNodes.id, { onDelete: "cascade" }),
88
+ /** caused-by | reminds-of | contradicts | depends-on | part-of | supersedes | resolved-by */
89
+ relationship: text("relationship").notNull(),
90
+ /** Connection strength 0–1. */
91
+ weight: real("weight").notNull().default(1.0),
92
+ /** Epoch ms. */
93
+ created: integer("created").notNull(),
94
+ },
95
+ (table) => [
96
+ index("idx_graph_edges_source").on(table.sourceNodeId),
97
+ index("idx_graph_edges_target").on(table.targetNodeId),
98
+ ],
99
+ );
100
+
101
+ export const memoryGraphTriggers = sqliteTable(
102
+ "memory_graph_triggers",
103
+ {
104
+ id: text("id").primaryKey(),
105
+ nodeId: text("node_id")
106
+ .notNull()
107
+ .references(() => memoryGraphNodes.id, { onDelete: "cascade" }),
108
+ /** temporal | semantic | event */
109
+ type: text("type").notNull(),
110
+
111
+ // -- Temporal --
112
+ schedule: text("schedule"),
113
+
114
+ // -- Semantic --
115
+ condition: text("condition"),
116
+ /** Pre-computed embedding stored as binary blob. */
117
+ conditionEmbedding: blob("condition_embedding"),
118
+ /** Cosine similarity threshold (0–1). */
119
+ threshold: real("threshold"),
120
+
121
+ // -- Event --
122
+ /** Epoch ms of the event date. */
123
+ eventDate: integer("event_date"),
124
+ rampDays: integer("ramp_days"),
125
+ followUpDays: integer("follow_up_days"),
126
+
127
+ // -- State --
128
+ recurring: integer("recurring", { mode: "boolean" })
129
+ .notNull()
130
+ .default(false),
131
+ consumed: integer("consumed", { mode: "boolean" }).notNull().default(false),
132
+ cooldownMs: integer("cooldown_ms"),
133
+ lastFired: integer("last_fired"),
134
+ },
135
+ (table) => [
136
+ index("idx_graph_triggers_node_id").on(table.nodeId),
137
+ index("idx_graph_triggers_type").on(table.type),
138
+ ],
139
+ );
140
+
141
+ export const memoryGraphNodeEdits = sqliteTable(
142
+ "memory_graph_node_edits",
143
+ {
144
+ id: text("id").primaryKey(),
145
+ nodeId: text("node_id")
146
+ .notNull()
147
+ .references(() => memoryGraphNodes.id, { onDelete: "cascade" }),
148
+ previousContent: text("previous_content").notNull(),
149
+ newContent: text("new_content").notNull(),
150
+ source: text("source").notNull(),
151
+ conversationId: text("conversation_id"),
152
+ created: integer("created").notNull(),
153
+ },
154
+ );
@@ -8,15 +8,42 @@ import type {
8
8
  QdrantSparseVector,
9
9
  } from "../qdrant-client.js";
10
10
  import { getQdrantClient } from "../qdrant-client.js";
11
- import {
12
- conversations,
13
- memoryItems,
14
- memoryItemSources,
15
- memorySegments,
16
- memorySummaries,
17
- } from "../schema.js";
18
- import { computeRecencyScore } from "./ranking.js";
19
- import type { Candidate } from "./types.js";
11
+ import { conversations, memorySegments, memorySummaries } from "../schema.js";
12
+ // ── Types (inlined from deleted types.ts) ──────────────────────────
13
+
14
+ type CandidateType = "segment" | "item" | "summary" | "media";
15
+
16
+ export interface Candidate {
17
+ key: string;
18
+ type: CandidateType;
19
+ id: string;
20
+ source: "semantic";
21
+ text: string;
22
+ kind: string;
23
+ modality?: "text" | "image" | "audio" | "video";
24
+ conversationId?: string;
25
+ messageId?: string;
26
+ confidence: number;
27
+ importance: number;
28
+ createdAt: number;
29
+ semantic: number;
30
+ recency: number;
31
+ finalScore: number;
32
+ }
33
+
34
+ // ── Recency scoring (inlined from deleted ranking.ts) ──────────────
35
+
36
+ /**
37
+ * Logarithmic recency decay (ACT-R inspired).
38
+ *
39
+ * 1 day -> 0.50, 7 days -> 0.25, 30 days -> 0.17
40
+ * 90 days -> 0.15, 1 year -> 0.12, 2 years -> 0.10
41
+ */
42
+ function computeRecencyScore(createdAt: number): number {
43
+ const ageMs = Math.max(0, Date.now() - createdAt);
44
+ const ageDays = ageMs / (24 * 60 * 60 * 1000);
45
+ return 1 / (1 + Math.log2(1 + ageDays));
46
+ }
20
47
 
21
48
  const _log = getLogger("semantic-search");
22
49
 
@@ -27,7 +54,7 @@ export async function semanticSearch(
27
54
  limit: number,
28
55
  excludedMessageIds: string[] = [],
29
56
  scopeIds?: string[],
30
- sparseVector?: QdrantSparseVector,
57
+ sparseVector?: QdrantSparseVector
31
58
  ): Promise<Candidate[]> {
32
59
  if (limit <= 0) return [];
33
60
 
@@ -52,31 +79,28 @@ export async function semanticSearch(
52
79
  filter,
53
80
  limit: fetchLimit,
54
81
  prefetchLimit: fetchLimit,
55
- }),
82
+ })
56
83
  );
57
84
  } else {
58
85
  results = await withQdrantBreaker(() =>
59
86
  qdrant.searchWithFilter(
60
87
  queryVector,
61
88
  fetchLimit,
62
- ["item", "summary", "segment", "media"],
89
+ ["summary", "segment", "media"],
63
90
  excludedMessageIds,
64
- scopeIds,
65
- ),
91
+ scopeIds
92
+ )
66
93
  );
67
94
  }
68
95
 
69
96
  const db = getDb();
70
97
 
71
98
  // Batch-fetch all backing records upfront to avoid N+1 queries per result
72
- const itemTargetIds: string[] = [];
73
99
  const summaryTargetIds: string[] = [];
74
100
  const segmentTargetIds: string[] = [];
75
101
  const mediaConversationIds: string[] = [];
76
102
  for (const r of results) {
77
- if (r.payload.target_type === "item")
78
- itemTargetIds.push(r.payload.target_id);
79
- else if (r.payload.target_type === "summary")
103
+ if (r.payload.target_type === "summary")
80
104
  summaryTargetIds.push(r.payload.target_id);
81
105
  else if (r.payload.target_type === "segment")
82
106
  segmentTargetIds.push(r.payload.target_id);
@@ -84,33 +108,6 @@ export async function semanticSearch(
84
108
  mediaConversationIds.push(r.payload.conversation_id);
85
109
  }
86
110
 
87
- const itemsMap = new Map<string, typeof memoryItems.$inferSelect>();
88
- if (itemTargetIds.length > 0) {
89
- const allItems = db
90
- .select()
91
- .from(memoryItems)
92
- .where(inArray(memoryItems.id, itemTargetIds))
93
- .all();
94
- for (const item of allItems) itemsMap.set(item.id, item);
95
- }
96
-
97
- const sourcesMap = new Map<string, string[]>();
98
- if (itemTargetIds.length > 0) {
99
- const allSources = db
100
- .select({
101
- memoryItemId: memoryItemSources.memoryItemId,
102
- messageId: memoryItemSources.messageId,
103
- })
104
- .from(memoryItemSources)
105
- .where(inArray(memoryItemSources.memoryItemId, itemTargetIds))
106
- .all();
107
- for (const s of allSources) {
108
- const existing = sourcesMap.get(s.memoryItemId);
109
- if (existing) existing.push(s.messageId);
110
- else sourcesMap.set(s.memoryItemId, [s.messageId]);
111
- }
112
- }
113
-
114
111
  const summariesMap = new Map<string, typeof memorySummaries.$inferSelect>();
115
112
  if (scopeIds && summaryTargetIds.length > 0) {
116
113
  const allSummaries = db
@@ -148,8 +145,6 @@ export async function semanticSearch(
148
145
  for (const row of rows) mediaScopeMap.set(row.id, row.memoryScopeId);
149
146
  }
150
147
 
151
- const excludedSet =
152
- excludedMessageIds.length > 0 ? new Set(excludedMessageIds) : null;
153
148
 
154
149
  const candidates: Candidate[] = [];
155
150
  for (const result of results) {
@@ -159,29 +154,8 @@ export async function semanticSearch(
159
154
  const createdAt = payload.created_at ?? Date.now();
160
155
 
161
156
  if (payload.target_type === "item") {
162
- const item = itemsMap.get(payload.target_id);
163
- if (!item || item.status !== "active" || item.invalidAt != null) continue;
164
- if (scopeIds && !scopeIds.includes(item.scopeId)) continue;
165
- const sources = sourcesMap.get(payload.target_id);
166
- if (!sources || sources.length === 0) continue;
167
- if (excludedSet) {
168
- const hasNonExcluded = sources.some((msgId) => !excludedSet.has(msgId));
169
- if (!hasNonExcluded) continue;
170
- }
171
- candidates.push({
172
- key: `item:${payload.target_id}`,
173
- type: "item",
174
- id: payload.target_id,
175
- source: "semantic",
176
- text: `${item.subject}: ${item.statement}`,
177
- kind: item.kind,
178
- confidence: item.confidence,
179
- importance: item.importance ?? 0.5,
180
- createdAt: item.lastSeenAt,
181
- semantic,
182
- recency: computeRecencyScore(item.lastSeenAt),
183
- finalScore: 0,
184
- });
157
+ // Legacy item vectors — skip (table dropped, Qdrant cleanup pending)
158
+ continue;
185
159
  } else if (payload.target_type === "summary") {
186
160
  if (scopeIds) {
187
161
  const summary = summariesMap.get(payload.target_id);
@@ -284,33 +258,15 @@ export async function semanticSearch(
284
258
  */
285
259
  function buildHybridFilter(
286
260
  excludeMessageIds: string[],
287
- scopeIds?: string[],
261
+ scopeIds?: string[]
288
262
  ): Record<string, unknown> {
289
263
  const mustConditions: Array<Record<string, unknown>> = [
290
264
  {
291
265
  key: "target_type",
292
- match: { any: ["item", "summary", "segment", "media"] },
266
+ match: { any: ["summary", "segment", "media"] },
293
267
  },
294
268
  ];
295
269
 
296
- if (excludeMessageIds.length > 0) {
297
- // Only require status=active for items; segments and summaries don't have a status field
298
- mustConditions.push({
299
- should: [
300
- {
301
- must: [
302
- { key: "target_type", match: { value: "item" } },
303
- { key: "status", match: { value: "active" } },
304
- ],
305
- },
306
- {
307
- key: "target_type",
308
- match: { any: ["segment", "summary", "media"] },
309
- },
310
- ],
311
- });
312
- }
313
-
314
270
  // Scope filtering: accept points whose memory_scope_id matches one of the
315
271
  // allowed scopes, OR points that lack the field entirely (legacy data).
316
272
  // Post-query DB filtering remains as defense-in-depth for legacy points.
@@ -346,6 +302,6 @@ export function mapCosineToUnit(value: number): number {
346
302
  export function isQdrantConnectionError(err: unknown): boolean {
347
303
  if (!(err instanceof Error)) return false;
348
304
  return /ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENETUNREACH|fetch failed/i.test(
349
- err.message,
305
+ err.message
350
306
  );
351
307
  }