@vellumai/assistant 0.5.16 → 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 (407) hide show
  1. package/ARCHITECTURE.md +1 -1
  2. package/Dockerfile +0 -3
  3. package/knip.json +2 -1
  4. package/openapi.yaml +660 -80
  5. package/package.json +1 -1
  6. package/src/__tests__/actor-token-service.test.ts +68 -0
  7. package/src/__tests__/agent-loop.test.ts +0 -32
  8. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  9. package/src/__tests__/anthropic-provider.test.ts +57 -3
  10. package/src/__tests__/app-compiler.test.ts +120 -0
  11. package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -2
  12. package/src/__tests__/call-conversation-messages.test.ts +2 -6
  13. package/src/__tests__/call-domain.test.ts +2 -6
  14. package/src/__tests__/call-pointer-messages.test.ts +2 -14
  15. package/src/__tests__/call-recovery.test.ts +2 -6
  16. package/src/__tests__/call-routes-http.test.ts +2 -6
  17. package/src/__tests__/call-store.test.ts +2 -6
  18. package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -6
  19. package/src/__tests__/canonical-guardian-store.test.ts +2 -6
  20. package/src/__tests__/channel-delivery-store.test.ts +2 -6
  21. package/src/__tests__/channel-retry-sweep.test.ts +2 -6
  22. package/src/__tests__/checker.test.ts +25 -3
  23. package/src/__tests__/clawhub.test.ts +54 -24
  24. package/src/__tests__/cli-command-risk-guard.test.ts +14 -0
  25. package/src/__tests__/cli-memory.test.ts +74 -69
  26. package/src/__tests__/config-schema.test.ts +1 -1
  27. package/src/__tests__/config-set-platform-guard.test.ts +302 -0
  28. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -6
  29. package/src/__tests__/contacts-tools.test.ts +31 -0
  30. package/src/__tests__/context-overflow-reducer.test.ts +86 -0
  31. package/src/__tests__/context-token-estimator.test.ts +175 -10
  32. package/src/__tests__/conversation-agent-loop-overflow.test.ts +9 -0
  33. package/src/__tests__/conversation-agent-loop.test.ts +9 -0
  34. package/src/__tests__/conversation-attachments.test.ts +2 -6
  35. package/src/__tests__/conversation-attention-store.test.ts +2 -6
  36. package/src/__tests__/conversation-clear-safety.test.ts +2 -6
  37. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +4 -10
  38. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -6
  39. package/src/__tests__/conversation-disk-view.test.ts +2 -6
  40. package/src/__tests__/conversation-error.test.ts +33 -2
  41. package/src/__tests__/conversation-fork-crud.test.ts +2 -6
  42. package/src/__tests__/conversation-history-web-search.test.ts +5 -0
  43. package/src/__tests__/conversation-load-history-repair.test.ts +5 -1
  44. package/src/__tests__/conversation-media-retry.test.ts +91 -0
  45. package/src/__tests__/conversation-starter-routes.test.ts +20 -11
  46. package/src/__tests__/conversation-store.test.ts +2 -6
  47. package/src/__tests__/conversation-usage.test.ts +2 -6
  48. package/src/__tests__/conversation-wipe.test.ts +11 -408
  49. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
  50. package/src/__tests__/credential-execution-shell-lockdown.test.ts +2 -2
  51. package/src/__tests__/credential-security-e2e.test.ts +2 -0
  52. package/src/__tests__/followup-tools.test.ts +2 -6
  53. package/src/__tests__/graph-extraction-event-date.test.ts +186 -0
  54. package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -6
  55. package/src/__tests__/guardian-action-followup-executor.test.ts +2 -6
  56. package/src/__tests__/guardian-action-followup-store.test.ts +2 -6
  57. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +2 -6
  58. package/src/__tests__/guardian-action-late-reply.test.ts +2 -6
  59. package/src/__tests__/guardian-action-store.test.ts +2 -6
  60. package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -6
  61. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +8 -8
  62. package/src/__tests__/guardian-dispatch.test.ts +2 -6
  63. package/src/__tests__/guardian-grant-minting.test.ts +2 -14
  64. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -6
  65. package/src/__tests__/guardian-routing-invariants.test.ts +192 -6
  66. package/src/__tests__/guardian-routing-state.test.ts +2 -6
  67. package/src/__tests__/guardian-verification-voice-binding.test.ts +2 -6
  68. package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
  69. package/src/__tests__/injection-block.test.ts +154 -0
  70. package/src/__tests__/install-meta.test.ts +506 -0
  71. package/src/__tests__/install-skill-routing.test.ts +292 -0
  72. package/src/__tests__/invite-redemption-service.test.ts +2 -6
  73. package/src/__tests__/invite-routes-http.test.ts +2 -6
  74. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -14
  75. package/src/__tests__/list-messages-attachments.test.ts +2 -6
  76. package/src/__tests__/llm-context-route-provider.test.ts +2 -6
  77. package/src/__tests__/llm-request-log-turn-query.test.ts +2 -6
  78. package/src/__tests__/llm-usage-store.test.ts +2 -6
  79. package/src/__tests__/log-export-workspace.test.ts +2 -6
  80. package/src/__tests__/managed-store.test.ts +38 -11
  81. package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
  82. package/src/__tests__/memory-recall-log-store.test.ts +2 -6
  83. package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
  84. package/src/__tests__/non-member-access-request.test.ts +2 -6
  85. package/src/__tests__/notification-guardian-path.test.ts +2 -6
  86. package/src/__tests__/oauth-cli.test.ts +364 -2
  87. package/src/__tests__/oauth2-gateway-transport.test.ts +18 -3
  88. package/src/__tests__/outlook-attachments.test.ts +301 -0
  89. package/src/__tests__/outlook-automation-tools.test.ts +425 -0
  90. package/src/__tests__/outlook-categories.test.ts +212 -0
  91. package/src/__tests__/outlook-client-automation.test.ts +246 -0
  92. package/src/__tests__/outlook-compose-tools.test.ts +325 -0
  93. package/src/__tests__/outlook-declutter-tools.test.ts +585 -0
  94. package/src/__tests__/outlook-email-watcher.test.ts +322 -0
  95. package/src/__tests__/outlook-follow-up.test.ts +196 -0
  96. package/src/__tests__/outlook-messaging-provider.test.ts +498 -3
  97. package/src/__tests__/outlook-trash.test.ts +77 -0
  98. package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
  99. package/src/__tests__/platform-callback-registration.test.ts +4 -4
  100. package/src/__tests__/playbook-execution.test.ts +76 -80
  101. package/src/__tests__/playbook-tools.test.ts +5 -7
  102. package/src/__tests__/provider-error-scenarios.test.ts +21 -0
  103. package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
  104. package/src/__tests__/registry.test.ts +2 -2
  105. package/src/__tests__/require-fresh-approval.test.ts +64 -2
  106. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
  107. package/src/__tests__/runtime-events-sse.test.ts +2 -6
  108. package/src/__tests__/schedule-store.test.ts +2 -6
  109. package/src/__tests__/schedule-tools.test.ts +2 -6
  110. package/src/__tests__/scheduler-recurrence.test.ts +1 -5
  111. package/src/__tests__/scoped-approval-grants.test.ts +2 -6
  112. package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
  113. package/src/__tests__/search-skills-unified.test.ts +421 -0
  114. package/src/__tests__/secret-onetime-send.test.ts +2 -0
  115. package/src/__tests__/send-endpoint-busy.test.ts +2 -6
  116. package/src/__tests__/sequence-store.test.ts +2 -6
  117. package/src/__tests__/server-history-render.test.ts +2 -6
  118. package/src/__tests__/skill-feature-flags-integration.test.ts +38 -31
  119. package/src/__tests__/skill-feature-flags.test.ts +6 -6
  120. package/src/__tests__/skill-load-feature-flag.test.ts +11 -11
  121. package/src/__tests__/skill-memory.test.ts +140 -98
  122. package/src/__tests__/skills-uninstall.test.ts +2 -2
  123. package/src/__tests__/skills.test.ts +1 -1
  124. package/src/__tests__/slack-inbound-verification.test.ts +2 -6
  125. package/src/__tests__/task-compiler.test.ts +2 -6
  126. package/src/__tests__/task-management-tools.test.ts +2 -6
  127. package/src/__tests__/task-memory-cleanup.test.ts +173 -229
  128. package/src/__tests__/task-runner.test.ts +2 -6
  129. package/src/__tests__/task-scheduler.test.ts +2 -6
  130. package/src/__tests__/test-preload.ts +3 -0
  131. package/src/__tests__/tool-approval-handler.test.ts +2 -6
  132. package/src/__tests__/tool-grant-request-escalation.test.ts +2 -6
  133. package/src/__tests__/tool-side-effects-slack-dm.test.ts +276 -0
  134. package/src/__tests__/trust-store.test.ts +1 -1
  135. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +2 -6
  136. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -6
  137. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -6
  138. package/src/__tests__/trusted-contact-verification.test.ts +2 -6
  139. package/src/__tests__/turn-boundary-resolution.test.ts +2 -6
  140. package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -6
  141. package/src/__tests__/usage-routes.test.ts +2 -6
  142. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  143. package/src/__tests__/voice-invite-redemption.test.ts +2 -6
  144. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -6
  145. package/src/__tests__/voice-session-bridge.test.ts +2 -6
  146. package/src/__tests__/volume-security-guard.test.ts +2 -0
  147. package/src/__tests__/workspace-lifecycle.test.ts +29 -1
  148. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -6
  149. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +2 -6
  150. package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
  151. package/src/__tests__/workspace-policy.test.ts +1 -1
  152. package/src/agent/attachments.ts +7 -2
  153. package/src/agent/image-optimize.ts +165 -0
  154. package/src/agent/loop.ts +1 -15
  155. package/src/bundler/app-compiler.ts +179 -2
  156. package/src/bundler/package-resolver.ts +3 -5
  157. package/src/cli/__tests__/notifications.test.ts +1 -2
  158. package/src/cli/cli-memory.ts +67 -64
  159. package/src/cli/commands/avatar.ts +3 -3
  160. package/src/cli/commands/config.ts +26 -13
  161. package/src/cli/commands/doctor.ts +2 -2
  162. package/src/cli/commands/memory.ts +41 -55
  163. package/src/cli/commands/oauth/__tests__/connect.test.ts +2 -2
  164. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +2 -2
  165. package/src/cli/commands/oauth/__tests__/mode.test.ts +8 -1
  166. package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
  167. package/src/cli/commands/oauth/connect.ts +11 -6
  168. package/src/cli/commands/oauth/mode.ts +7 -0
  169. package/src/cli/commands/oauth/shared.ts +39 -3
  170. package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
  171. package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
  172. package/src/cli/commands/platform/__tests__/status.test.ts +5 -5
  173. package/src/cli/commands/platform/index.ts +16 -16
  174. package/src/cli/commands/skills.ts +88 -16
  175. package/src/cli/commands/trust.ts +2 -2
  176. package/src/cli/lib/daemon-credential-client.ts +2 -3
  177. package/src/config/bundled-skills/acp/TOOLS.json +1 -1
  178. package/src/config/bundled-skills/contacts/SKILL.md +0 -1
  179. package/src/config/bundled-skills/contacts/TOOLS.json +0 -8
  180. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -4
  181. package/src/config/bundled-skills/gmail/SKILL.md +2 -10
  182. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
  183. package/src/config/bundled-skills/messaging/SKILL.md +10 -18
  184. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +40 -33
  185. package/src/config/bundled-skills/outlook/SKILL.md +189 -0
  186. package/src/config/bundled-skills/outlook/TOOLS.json +530 -0
  187. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +85 -0
  188. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +77 -0
  189. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +84 -0
  190. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +94 -0
  191. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +49 -0
  192. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +237 -0
  193. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +161 -0
  194. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +32 -0
  195. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +272 -0
  196. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +29 -0
  197. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +129 -0
  198. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +87 -0
  199. package/src/config/bundled-skills/outlook/tools/shared.ts +20 -0
  200. package/src/config/bundled-skills/outlook-calendar/SKILL.md +51 -0
  201. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +221 -0
  202. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +252 -0
  203. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +53 -0
  204. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +74 -0
  205. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +18 -0
  206. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +46 -0
  207. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +36 -0
  208. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +17 -0
  209. package/src/config/bundled-skills/outlook-calendar/types.ts +120 -0
  210. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +47 -40
  211. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +16 -29
  212. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +16 -18
  213. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +39 -47
  214. package/src/config/bundled-skills/slack/SKILL.md +1 -7
  215. package/src/config/bundled-tool-registry.ts +56 -4
  216. package/src/config/env-registry.ts +15 -8
  217. package/src/config/feature-flag-registry.json +21 -124
  218. package/src/config/schemas/platform.ts +8 -0
  219. package/src/config/schemas/timeouts.ts +1 -1
  220. package/src/config/skills.ts +18 -7
  221. package/src/context/token-estimator.ts +25 -18
  222. package/src/context/window-manager.ts +6 -2
  223. package/src/credential-execution/process-manager.ts +3 -1
  224. package/src/daemon/context-overflow-reducer.ts +46 -2
  225. package/src/daemon/conversation-agent-loop-handlers.ts +123 -82
  226. package/src/daemon/conversation-agent-loop.ts +96 -61
  227. package/src/daemon/conversation-error.ts +31 -8
  228. package/src/daemon/conversation-lifecycle.ts +33 -0
  229. package/src/daemon/conversation-media-retry.ts +85 -7
  230. package/src/daemon/conversation-notifiers.ts +4 -1
  231. package/src/daemon/conversation-runtime-assembly.ts +5 -0
  232. package/src/daemon/conversation.ts +41 -2
  233. package/src/daemon/daemon-control.ts +8 -2
  234. package/src/daemon/handlers/shared.ts +22 -12
  235. package/src/daemon/handlers/skills.ts +416 -202
  236. package/src/daemon/lifecycle.ts +40 -1
  237. package/src/daemon/main.ts +5 -1
  238. package/src/daemon/message-types/conversations.ts +4 -1
  239. package/src/daemon/message-types/messages.ts +3 -1
  240. package/src/daemon/message-types/skills.ts +97 -36
  241. package/src/daemon/providers-setup.ts +5 -0
  242. package/src/daemon/server.ts +11 -2
  243. package/src/daemon/tool-side-effects.ts +27 -5
  244. package/src/heartbeat/heartbeat-service.ts +1 -0
  245. package/src/hooks/cli.ts +2 -2
  246. package/src/hooks/runner.ts +15 -38
  247. package/src/inbound/platform-callback-registration.ts +14 -14
  248. package/src/memory/admin.ts +11 -45
  249. package/src/memory/conversation-bootstrap.ts +2 -0
  250. package/src/memory/conversation-crud.ts +242 -348
  251. package/src/memory/conversation-group-migration.ts +157 -0
  252. package/src/memory/conversation-queries.ts +4 -2
  253. package/src/memory/db-init.ts +30 -3
  254. package/src/memory/embed.ts +73 -0
  255. package/src/memory/embedding-backend.ts +8 -14
  256. package/src/memory/embedding-runtime-manager.ts +12 -114
  257. package/src/memory/fingerprint.ts +2 -2
  258. package/src/memory/graph/bootstrap.ts +512 -0
  259. package/src/memory/graph/capability-seed.ts +297 -0
  260. package/src/memory/graph/consolidation.ts +691 -0
  261. package/src/memory/graph/conversation-graph-memory.ts +630 -0
  262. package/src/memory/graph/decay.test.ts +208 -0
  263. package/src/memory/graph/decay.ts +195 -0
  264. package/src/memory/graph/extraction-job.ts +69 -0
  265. package/src/memory/graph/extraction.test.ts +936 -0
  266. package/src/memory/graph/extraction.ts +1254 -0
  267. package/src/memory/graph/graph-search.ts +266 -0
  268. package/src/memory/graph/image-ref-utils.ts +29 -0
  269. package/src/memory/graph/injection.test.ts +513 -0
  270. package/src/memory/graph/injection.ts +439 -0
  271. package/src/memory/graph/inspect.ts +534 -0
  272. package/src/memory/graph/narrative.ts +267 -0
  273. package/src/memory/graph/pattern-scan.ts +269 -0
  274. package/src/memory/graph/retriever.ts +1008 -0
  275. package/src/memory/graph/scoring.test.ts +548 -0
  276. package/src/memory/graph/scoring.ts +232 -0
  277. package/src/memory/graph/serendipity.ts +65 -0
  278. package/src/memory/graph/store.test.ts +1050 -0
  279. package/src/memory/graph/store.ts +699 -0
  280. package/src/memory/graph/tool-handlers.ts +426 -0
  281. package/src/memory/graph/tools.ts +141 -0
  282. package/src/memory/graph/triggers.test.ts +487 -0
  283. package/src/memory/graph/triggers.ts +223 -0
  284. package/src/memory/graph/types.ts +271 -0
  285. package/src/memory/group-crud.ts +191 -0
  286. package/src/memory/indexer.ts +37 -19
  287. package/src/memory/job-handlers/cleanup.ts +0 -53
  288. package/src/memory/job-handlers/conversation-starters.ts +91 -53
  289. package/src/memory/job-handlers/embedding.ts +5 -31
  290. package/src/memory/job-handlers/index-maintenance.ts +23 -11
  291. package/src/memory/job-handlers/summarization.ts +32 -17
  292. package/src/memory/job-utils.ts +1 -1
  293. package/src/memory/jobs-store.ts +50 -70
  294. package/src/memory/jobs-worker.ts +147 -112
  295. package/src/memory/message-content.ts +1 -0
  296. package/src/memory/migrations/202-memory-graph-tables.ts +130 -0
  297. package/src/memory/migrations/203-drop-memory-items-tables.ts +23 -0
  298. package/src/memory/migrations/204-rename-memory-graph-type-values.ts +46 -0
  299. package/src/memory/migrations/205-memory-graph-image-refs.ts +11 -0
  300. package/src/memory/migrations/index.ts +4 -0
  301. package/src/memory/migrations/registry.ts +8 -0
  302. package/src/memory/qdrant-client.ts +44 -17
  303. package/src/memory/schema/index.ts +1 -0
  304. package/src/memory/schema/memory-graph.ts +139 -0
  305. package/src/memory/search/semantic.ts +47 -91
  306. package/src/memory/task-memory-cleanup.ts +28 -50
  307. package/src/messaging/providers/outlook/adapter.ts +8 -1
  308. package/src/messaging/providers/outlook/client.ts +299 -0
  309. package/src/messaging/providers/outlook/types.ts +118 -0
  310. package/src/notifications/adapters/macos.ts +1 -0
  311. package/src/notifications/copy-composer.ts +9 -0
  312. package/src/notifications/signal.ts +16 -0
  313. package/src/oauth/seed-providers.ts +2 -1
  314. package/src/permissions/checker.ts +24 -3
  315. package/src/permissions/defaults.ts +4 -4
  316. package/src/permissions/workspace-policy.ts +1 -1
  317. package/src/playbooks/playbook-compiler.ts +19 -18
  318. package/src/playbooks/types.ts +4 -3
  319. package/src/prompts/system-prompt.ts +3 -29
  320. package/src/providers/anthropic/client.ts +47 -19
  321. package/src/providers/gemini/client.ts +1 -1
  322. package/src/providers/openai/client.ts +1 -1
  323. package/src/providers/registry.ts +1 -1
  324. package/src/providers/retry.ts +19 -3
  325. package/src/runtime/actor-trust-resolver.ts +5 -1
  326. package/src/runtime/auth/route-policy.ts +7 -0
  327. package/src/runtime/guardian-reply-router.ts +5 -1
  328. package/src/runtime/http-server.ts +23 -3
  329. package/src/runtime/middleware/auth.ts +20 -0
  330. package/src/runtime/routes/attachment-routes.test.ts +106 -0
  331. package/src/runtime/routes/attachment-routes.ts +106 -16
  332. package/src/runtime/routes/brain-graph-routes.ts +21 -22
  333. package/src/runtime/routes/btw-routes.ts +8 -0
  334. package/src/runtime/routes/conversation-management-routes.ts +2 -0
  335. package/src/runtime/routes/conversation-starter-routes.ts +2 -2
  336. package/src/runtime/routes/debug-routes.ts +1 -1
  337. package/src/runtime/routes/global-search-routes.ts +21 -19
  338. package/src/runtime/routes/group-routes.ts +207 -0
  339. package/src/runtime/routes/guardian-action-routes.ts +21 -10
  340. package/src/runtime/routes/guardian-bootstrap-routes.ts +23 -19
  341. package/src/runtime/routes/inbound-message-handler.ts +19 -0
  342. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +292 -0
  343. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +207 -0
  344. package/src/runtime/routes/memory-item-routes.test.ts +2 -14
  345. package/src/runtime/routes/memory-item-routes.ts +341 -388
  346. package/src/runtime/routes/schedule-routes.ts +2 -0
  347. package/src/runtime/routes/skills-routes.ts +103 -37
  348. package/src/runtime/routes/work-items-routes.test.ts +2 -6
  349. package/src/schedule/scheduler.ts +8 -1
  350. package/src/security/oauth2.ts +1 -1
  351. package/src/security/secure-keys.ts +4 -8
  352. package/src/shared/provider-env-vars.ts +19 -0
  353. package/src/skills/catalog-cache.ts +5 -0
  354. package/src/skills/catalog-install.ts +15 -14
  355. package/src/skills/clawhub.ts +134 -154
  356. package/src/skills/install-meta.ts +208 -0
  357. package/src/skills/managed-store.ts +27 -16
  358. package/src/skills/skill-memory.ts +152 -77
  359. package/src/skills/skillssh-registry.ts +19 -17
  360. package/src/tasks/task-runner.ts +3 -1
  361. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
  362. package/src/tools/browser/runtime-check.ts +3 -1
  363. package/src/tools/memory/register.ts +63 -46
  364. package/src/tools/permission-checker.ts +7 -1
  365. package/src/tools/shared/filesystem/image-read.ts +22 -85
  366. package/src/tools/terminal/safe-env.ts +1 -0
  367. package/src/tools/tool-manifest.ts +3 -3
  368. package/src/util/browser.ts +25 -10
  369. package/src/util/bun-runtime.ts +172 -0
  370. package/src/watcher/providers/outlook-calendar.ts +343 -0
  371. package/src/watcher/providers/outlook.ts +198 -0
  372. package/src/workspace/migrations/025-remove-oauth-app-setup-skills.ts +76 -0
  373. package/src/workspace/migrations/026-backfill-install-meta.ts +325 -0
  374. package/src/workspace/migrations/027-remove-orphaned-optimized-images-cache.ts +42 -0
  375. package/src/workspace/migrations/registry.ts +6 -0
  376. package/src/__tests__/context-memory-e2e.test.ts +0 -415
  377. package/src/__tests__/journal-context.test.ts +0 -268
  378. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -297
  379. package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -459
  380. package/src/__tests__/memory-query-builder.test.ts +0 -59
  381. package/src/__tests__/memory-recall-quality.test.ts +0 -1046
  382. package/src/__tests__/memory-regressions.experimental.test.ts +0 -629
  383. package/src/__tests__/memory-regressions.test.ts +0 -3696
  384. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -295
  385. package/src/daemon/conversation-memory.ts +0 -207
  386. package/src/memory/conversation-starters-cadence.ts +0 -74
  387. package/src/memory/items-extractor.ts +0 -860
  388. package/src/memory/job-handlers/batch-extraction.ts +0 -753
  389. package/src/memory/job-handlers/extraction.ts +0 -40
  390. package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -355
  391. package/src/memory/job-handlers/journal-carry-forward.ts +0 -255
  392. package/src/memory/journal-memory.ts +0 -224
  393. package/src/memory/query-builder.ts +0 -47
  394. package/src/memory/query-expansion.ts +0 -83
  395. package/src/memory/retriever.test.ts +0 -1592
  396. package/src/memory/retriever.ts +0 -1331
  397. package/src/memory/search/formatting.test.ts +0 -140
  398. package/src/memory/search/formatting.ts +0 -262
  399. package/src/memory/search/mmr.ts +0 -139
  400. package/src/memory/search/ranking.ts +0 -15
  401. package/src/memory/search/staleness.ts +0 -40
  402. package/src/memory/search/tier-classifier.ts +0 -18
  403. package/src/memory/search/types.ts +0 -121
  404. package/src/prompts/journal-context.ts +0 -154
  405. package/src/tools/memory/definitions.ts +0 -69
  406. package/src/tools/memory/handlers.test.ts +0 -562
  407. package/src/tools/memory/handlers.ts +0 -434
@@ -5,7 +5,7 @@
5
5
  * suggestion chips shown on the empty conversation page.
6
6
  */
7
7
 
8
- import { and, desc, eq } from "drizzle-orm";
8
+ import { and, desc, eq, sql } from "drizzle-orm";
9
9
  import { v4 as uuid } from "uuid";
10
10
 
11
11
  import { loadSkillCatalog } from "../../config/skills.js";
@@ -26,7 +26,7 @@ import { rawAll, rawGet } from "../raw-query.js";
26
26
  import {
27
27
  conversationStarters,
28
28
  memoryCheckpoints,
29
- memoryItems,
29
+ memoryGraphNodes,
30
30
  } from "../schema.js";
31
31
 
32
32
  const log = getLogger("conversation-starters-gen");
@@ -42,32 +42,47 @@ const CK_LAST_GEN_AT = "conversation_starters:last_gen_at";
42
42
  // ── Rollup construction ───────────────────────────────────────────
43
43
 
44
44
  export function buildMemoryRollup(scopeId: string): string {
45
- const db = getDb();
46
- const items = db
47
- .select({
48
- kind: memoryItems.kind,
49
- subject: memoryItems.subject,
50
- statement: memoryItems.statement,
51
- importance: memoryItems.importance,
52
- })
53
- .from(memoryItems)
54
- .where(
55
- and(eq(memoryItems.status, "active"), eq(memoryItems.scopeId, scopeId)),
56
- )
57
- .orderBy(desc(memoryItems.importance))
58
- .limit(60)
59
- .all();
60
-
61
- if (items.length === 0) return "";
45
+ let rows: Array<{
46
+ type: string;
47
+ content: string;
48
+ significance: number | null;
49
+ }>;
50
+ try {
51
+ const db = getDb();
52
+ rows = db
53
+ .select({
54
+ type: memoryGraphNodes.type,
55
+ content: memoryGraphNodes.content,
56
+ significance: memoryGraphNodes.significance,
57
+ })
58
+ .from(memoryGraphNodes)
59
+ .where(
60
+ and(
61
+ sql`${memoryGraphNodes.fidelity} != 'gone'`,
62
+ eq(memoryGraphNodes.scopeId, scopeId),
63
+ )
64
+ )
65
+ .orderBy(desc(memoryGraphNodes.significance))
66
+ .limit(60)
67
+ .all();
68
+ } catch {
69
+ // Table may have been dropped (migration 203)
70
+ return "";
71
+ }
72
+
73
+ if (rows.length === 0) return "";
62
74
 
63
75
  const byKind = new Map<string, string[]>();
64
- for (const item of items) {
65
- let lines = byKind.get(item.kind);
76
+ for (const item of rows) {
77
+ const nl = item.content.indexOf("\n");
78
+ const subject = nl >= 0 ? item.content.slice(0, nl) : item.content;
79
+ const statement = nl >= 0 ? item.content.slice(nl + 1) : item.content;
80
+ let lines = byKind.get(item.type);
66
81
  if (!lines) {
67
82
  lines = [];
68
- byKind.set(item.kind, lines);
83
+ byKind.set(item.type, lines);
69
84
  }
70
- lines.push(`- ${item.subject}: ${item.statement}`);
85
+ lines.push(`- ${subject}: ${statement}`);
71
86
  }
72
87
 
73
88
  let rollup = "";
@@ -90,21 +105,25 @@ function buildNewItemsDiff(scopeId: string): string {
90
105
 
91
106
  const newItems = rawAll<{
92
107
  kind: string;
93
- subject: string;
94
- statement: string;
108
+ content: string;
95
109
  }>(
96
- `SELECT kind, subject, statement FROM memory_items
97
- WHERE status = 'active' AND scope_id = ? AND first_seen_at > ?
98
- ORDER BY first_seen_at DESC LIMIT 20`,
110
+ `SELECT type AS kind, content FROM memory_graph_nodes
111
+ WHERE fidelity != 'gone' AND scope_id = ? AND created > ?
112
+ ORDER BY created DESC LIMIT 20`,
99
113
  scopeId,
100
- lastGenAt,
114
+ lastGenAt
101
115
  );
102
116
 
103
117
  if (newItems.length === 0) return "";
104
118
 
105
119
  return (
106
120
  "## New since last generation\n" +
107
- newItems.map((i) => `- (${i.kind}) ${i.subject}: ${i.statement}`).join("\n")
121
+ newItems.map((i) => {
122
+ const nl = i.content.indexOf("\n");
123
+ const subject = nl >= 0 ? i.content.slice(0, nl) : i.content;
124
+ const statement = nl >= 0 ? i.content.slice(nl + 1) : i.content;
125
+ return `- (${i.kind}) ${subject}: ${statement}`;
126
+ }).join("\n")
108
127
  );
109
128
  }
110
129
 
@@ -143,8 +162,7 @@ export const CONVERSATION_STARTER_CATEGORIES = [
143
162
  "integration",
144
163
  ] as const;
145
164
 
146
- export type ConversationStarterCategory =
147
- (typeof CONVERSATION_STARTER_CATEGORIES)[number];
165
+ export type ConversationStarterCategory = typeof CONVERSATION_STARTER_CATEGORIES[number];
148
166
 
149
167
  interface GeneratedStarter {
150
168
  label: string;
@@ -168,7 +186,15 @@ async function generateStarters(scopeId: string): Promise<GeneratedStarter[]> {
168
186
  const skills = buildSkillsSummary();
169
187
 
170
188
  const now = new Date();
171
- const timeContext = `Current time: ${now.toLocaleString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "2-digit", hour12: true })}`;
189
+ const timeContext = `Current time: ${now.toLocaleString("en-US", {
190
+ weekday: "long",
191
+ year: "numeric",
192
+ month: "long",
193
+ day: "numeric",
194
+ hour: "numeric",
195
+ minute: "2-digit",
196
+ hour12: true,
197
+ })}`;
172
198
 
173
199
  // Truncate identity context to prevent oversized prompts when SOUL.md /
174
200
  // IDENTITY.md / USER.md are large.
@@ -185,7 +211,11 @@ ${timeContext}
185
211
 
186
212
  Your goal: suggest the 4 most useful things this person could ask you to do right now.
187
213
 
188
- ${identityContext ? `## Assistant identity & user profile\n\n${identityContext}\n\n` : ""}## What you know
214
+ ${
215
+ identityContext
216
+ ? `## Assistant identity & user profile\n\n${identityContext}\n\n`
217
+ : ""
218
+ }## What you know
189
219
 
190
220
  ${rollup}
191
221
  ${diff}
@@ -253,7 +283,7 @@ Bad → Good (assistant voice → user voice):
253
283
  const response = await provider.sendMessage(
254
284
  [
255
285
  userMessage(
256
- "Generate personalized conversation starters based on my context.",
286
+ "Generate personalized conversation starters based on my context."
257
287
  ),
258
288
  ],
259
289
  [
@@ -303,14 +333,14 @@ Bad → Good (assistant voice → user voice):
303
333
  },
304
334
  },
305
335
  signal,
306
- },
336
+ }
307
337
  );
308
338
  cleanup();
309
339
 
310
340
  const toolBlock = extractToolUse(response);
311
341
  if (!toolBlock) {
312
342
  log.warn(
313
- "No tool_use block in conversation starters generation response",
343
+ "No tool_use block in conversation starters generation response"
314
344
  );
315
345
  return [];
316
346
  }
@@ -327,7 +357,7 @@ Bad → Good (assistant voice → user voice):
327
357
  typeof s.label === "string" &&
328
358
  s.label.length > 0 &&
329
359
  typeof s.prompt === "string" &&
330
- s.prompt.length > 0,
360
+ s.prompt.length > 0
331
361
  )
332
362
  .slice(0, 4)
333
363
  .map((s) => ({
@@ -336,7 +366,7 @@ Bad → Good (assistant voice → user voice):
336
366
  category:
337
367
  typeof s.category === "string" &&
338
368
  (CONVERSATION_STARTER_CATEGORIES as readonly string[]).includes(
339
- s.category,
369
+ s.category
340
370
  )
341
371
  ? s.category
342
372
  : "productivity",
@@ -350,7 +380,7 @@ Bad → Good (assistant voice → user voice):
350
380
  // ── Job handler ───────────────────────────────────────────────────
351
381
 
352
382
  export async function generateConversationStartersJob(
353
- job: MemoryJob,
383
+ job: MemoryJob
354
384
  ): Promise<void> {
355
385
  const scopeId = asString(job.payload.scopeId) ?? "default";
356
386
 
@@ -373,16 +403,24 @@ export async function generateConversationStartersJob(
373
403
  ? parseInt(batchCheckpoint.value, 10) + 1
374
404
  : 1;
375
405
 
376
- // Collect the memory kinds that informed this batch
377
- const kindRows = db
378
- .select({ kind: memoryItems.kind })
379
- .from(memoryItems)
380
- .where(
381
- and(eq(memoryItems.status, "active"), eq(memoryItems.scopeId, scopeId)),
382
- )
383
- .groupBy(memoryItems.kind)
384
- .all();
385
- const sourceKinds = kindRows.map((r) => r.kind).join(",");
406
+ // Collect the memory types that informed this batch
407
+ let sourceKinds = "";
408
+ try {
409
+ const kindRows = db
410
+ .select({ kind: memoryGraphNodes.type })
411
+ .from(memoryGraphNodes)
412
+ .where(
413
+ and(
414
+ sql`${memoryGraphNodes.fidelity} != 'gone'`,
415
+ eq(memoryGraphNodes.scopeId, scopeId),
416
+ )
417
+ )
418
+ .groupBy(memoryGraphNodes.type)
419
+ .all();
420
+ sourceKinds = kindRows.map((r) => r.kind).join(",");
421
+ } catch {
422
+ // Table may have been dropped (migration 203)
423
+ }
386
424
 
387
425
  // Remove previous starters for this scope before inserting the new batch
388
426
  db.delete(conversationStarters)
@@ -408,8 +446,8 @@ export async function generateConversationStartersJob(
408
446
 
409
447
  // Count active items for checkpoint
410
448
  const countRow = rawGet<{ c: number }>(
411
- `SELECT COUNT(*) AS c FROM memory_items WHERE status = 'active' AND scope_id = ?`,
412
- scopeId,
449
+ `SELECT COUNT(*) AS c FROM memory_graph_nodes WHERE fidelity != 'gone' AND scope_id = ?`,
450
+ scopeId
413
451
  );
414
452
  const totalActive = countRow?.c ?? 0;
415
453
 
@@ -430,6 +468,6 @@ export async function generateConversationStartersJob(
430
468
 
431
469
  log.info(
432
470
  { scopeId, batch: nextBatch, count: starters.length },
433
- "Generated conversation starters",
471
+ "Generated conversation starters"
434
472
  );
435
473
  }
@@ -11,7 +11,6 @@ import type { MemoryJob } from "../jobs-store.js";
11
11
  import { extractMediaBlocks } from "../message-content.js";
12
12
  import {
13
13
  mediaAssets,
14
- memoryItems,
15
14
  memorySegments,
16
15
  memorySummaries,
17
16
  messages,
@@ -19,7 +18,7 @@ import {
19
18
 
20
19
  export async function embedSegmentJob(
21
20
  job: MemoryJob,
22
- config: AssistantConfig,
21
+ config: AssistantConfig
23
22
  ): Promise<void> {
24
23
  const segmentId = asString(job.payload.segmentId);
25
24
  if (!segmentId) return;
@@ -38,34 +37,9 @@ export async function embedSegmentJob(
38
37
  });
39
38
  }
40
39
 
41
- export async function embedItemJob(
42
- job: MemoryJob,
43
- config: AssistantConfig,
44
- ): Promise<void> {
45
- const itemId = asString(job.payload.itemId);
46
- if (!itemId) return;
47
- const db = getDb();
48
- const item = db
49
- .select()
50
- .from(memoryItems)
51
- .where(eq(memoryItems.id, itemId))
52
- .get();
53
- if (!item || item.status !== "active") return;
54
- const text = `<kind>${item.kind}</kind> ${item.subject}: ${item.statement}`;
55
- await embedAndUpsert(config, "item", item.id, text, {
56
- kind: item.kind,
57
- subject: item.subject,
58
- status: item.status,
59
- confidence: item.confidence,
60
- created_at: item.firstSeenAt,
61
- last_seen_at: item.lastSeenAt,
62
- memory_scope_id: item.scopeId,
63
- });
64
- }
65
-
66
40
  export async function embedSummaryJob(
67
41
  job: MemoryJob,
68
- config: AssistantConfig,
42
+ config: AssistantConfig
69
43
  ): Promise<void> {
70
44
  const summaryId = asString(job.payload.summaryId);
71
45
  if (!summaryId) return;
@@ -86,13 +60,13 @@ export async function embedSummaryJob(
86
60
  created_at: summary.startAt,
87
61
  last_seen_at: summary.endAt,
88
62
  memory_scope_id: summary.scopeId,
89
- },
63
+ }
90
64
  );
91
65
  }
92
66
 
93
67
  export async function embedMediaJob(
94
68
  job: MemoryJob,
95
- config: AssistantConfig,
69
+ config: AssistantConfig
96
70
  ): Promise<void> {
97
71
  const assetId = asString(job.payload.assetId);
98
72
  if (!assetId) return;
@@ -125,7 +99,7 @@ export async function embedMediaJob(
125
99
 
126
100
  export async function embedAttachmentJob(
127
101
  job: MemoryJob,
128
- config: AssistantConfig,
102
+ config: AssistantConfig
129
103
  ): Promise<void> {
130
104
  const messageId = asString(job.payload.messageId);
131
105
  const blockIndex = job.payload.blockIndex as number;
@@ -1,4 +1,4 @@
1
- import { eq, like } from "drizzle-orm";
1
+ import { eq, isNotNull, like, ne } from "drizzle-orm";
2
2
 
3
3
  import { getConfig } from "../../config/loader.js";
4
4
  import { getLogger } from "../../util/logger.js";
@@ -12,7 +12,8 @@ import { getQdrantClient } from "../qdrant-client.js";
12
12
  import {
13
13
  mediaAssets,
14
14
  memoryEmbeddings,
15
- memoryItems,
15
+ memoryGraphNodes,
16
+ memoryGraphTriggers,
16
17
  memorySegments,
17
18
  memorySummaries,
18
19
  messages,
@@ -24,15 +25,6 @@ export async function rebuildIndexJob(): Promise<void> {
24
25
  const db = getDb();
25
26
  db.delete(memoryEmbeddings).run();
26
27
 
27
- const items = db
28
- .select({ id: memoryItems.id })
29
- .from(memoryItems)
30
- .where(eq(memoryItems.status, "active"))
31
- .all();
32
- for (const item of items) {
33
- enqueueMemoryJob("embed_item", { itemId: item.id });
34
- }
35
-
36
28
  const summaries = db
37
29
  .select({ id: memorySummaries.id })
38
30
  .from(memorySummaries)
@@ -77,6 +69,26 @@ export async function rebuildIndexJob(): Promise<void> {
77
69
  }
78
70
  }
79
71
  }
72
+
73
+ // Re-embed graph nodes stored in the memory graph.
74
+ const graphNodes = db
75
+ .select({ id: memoryGraphNodes.id })
76
+ .from(memoryGraphNodes)
77
+ .where(ne(memoryGraphNodes.fidelity, "gone"))
78
+ .all();
79
+ for (const node of graphNodes) {
80
+ enqueueMemoryJob("embed_graph_node", { nodeId: node.id });
81
+ }
82
+
83
+ // Re-embed semantic triggers that have condition text.
84
+ const triggers = db
85
+ .select({ id: memoryGraphTriggers.id })
86
+ .from(memoryGraphTriggers)
87
+ .where(isNotNull(memoryGraphTriggers.condition))
88
+ .all();
89
+ for (const trigger of triggers) {
90
+ enqueueMemoryJob("graph_trigger_embed", { triggerId: trigger.id });
91
+ }
80
92
  }
81
93
 
82
94
  export async function deleteQdrantVectorsJob(job: MemoryJob): Promise<void> {
@@ -1,4 +1,4 @@
1
- import { and, desc, eq, sql } from "drizzle-orm";
1
+ import { and, asc, eq, gt, sql } from "drizzle-orm";
2
2
  import { v4 as uuid } from "uuid";
3
3
 
4
4
  import type { AssistantConfig } from "../../config/types.js";
@@ -19,7 +19,7 @@ import { memorySegments, memorySummaries } from "../schema.js";
19
19
  const log = getLogger("memory-jobs-worker");
20
20
 
21
21
  const SUMMARY_LLM_TIMEOUT_MS = 20_000;
22
- const SUMMARY_MAX_TOKENS = 500;
22
+ const SUMMARY_MAX_TOKENS = 1000;
23
23
 
24
24
  const CONVERSATION_SUMMARY_SYSTEM_PROMPT = [
25
25
  "You compress conversation transcripts into compact summaries for semantic search and memory retrieval.",
@@ -37,7 +37,7 @@ const CONVERSATION_SUMMARY_SYSTEM_PROMPT = [
37
37
  "## Open Items",
38
38
  "Unresolved questions, pending tasks, or follow-ups (omit section if none).",
39
39
  "",
40
- "Target 200-400 tokens. Be dense.",
40
+ "Target 400-800 tokens. Be thorough — capture nuance, tone, and relationship dynamics, not just facts.",
41
41
  ].join("\n");
42
42
 
43
43
  export async function buildConversationSummaryJob(
@@ -47,14 +47,6 @@ export async function buildConversationSummaryJob(
47
47
  const conversationId = asString(job.payload.conversationId);
48
48
  if (!conversationId) return;
49
49
  const db = getDb();
50
- const rows = db
51
- .select()
52
- .from(memorySegments)
53
- .where(eq(memorySegments.conversationId, conversationId))
54
- .orderBy(desc(memorySegments.createdAt))
55
- .limit(40)
56
- .all();
57
- if (rows.length === 0) return;
58
50
 
59
51
  const existing = db
60
52
  .select()
@@ -67,9 +59,27 @@ export async function buildConversationSummaryJob(
67
59
  )
68
60
  .get();
69
61
 
70
- // Build segment text for LLM input (chronological order)
62
+ // Fetch only segments newer than what the existing summary already covers.
63
+ // For first-time summaries, fetch all segments.
64
+ const lastCoveredAt = existing
65
+ ? Math.max(existing.startAt, existing.endAt)
66
+ : 0;
67
+
68
+ const conditions = [eq(memorySegments.conversationId, conversationId)];
69
+ if (lastCoveredAt > 0) {
70
+ conditions.push(gt(memorySegments.createdAt, lastCoveredAt));
71
+ }
72
+
73
+ const rows = db
74
+ .select()
75
+ .from(memorySegments)
76
+ .where(and(...conditions))
77
+ .orderBy(asc(memorySegments.createdAt))
78
+ .all();
79
+ if (rows.length === 0) return;
80
+
81
+ // Build segment text for LLM input (already in chronological order)
71
82
  const segmentTexts = rows
72
- .reverse()
73
83
  .map((row) => `[${row.role}] ${truncate(row.text, 600)}`)
74
84
  .join("\n\n");
75
85
 
@@ -88,6 +98,11 @@ export async function buildConversationSummaryJob(
88
98
  const now = Date.now();
89
99
  const summaryId = existing?.id ?? uuid();
90
100
  const nextVersion = (existing?.version ?? 0) + 1;
101
+ const earliestCovered = existing
102
+ ? Math.min(existing.startAt, existing.endAt, rows[0].createdAt)
103
+ : rows[0].createdAt;
104
+ const latestCovered = rows[rows.length - 1].createdAt;
105
+
91
106
  db.insert(memorySummaries)
92
107
  .values({
93
108
  id: summaryId,
@@ -97,8 +112,8 @@ export async function buildConversationSummaryJob(
97
112
  summary: summaryText,
98
113
  tokenEstimate: estimateTextTokens(summaryText),
99
114
  version: nextVersion,
100
- startAt: rows[rows.length - 1].createdAt,
101
- endAt: rows[0].createdAt,
115
+ startAt: earliestCovered,
116
+ endAt: latestCovered,
102
117
  createdAt: now,
103
118
  updatedAt: now,
104
119
  })
@@ -109,8 +124,8 @@ export async function buildConversationSummaryJob(
109
124
  tokenEstimate: estimateTextTokens(summaryText),
110
125
  version: sql`${memorySummaries.version} + 1`,
111
126
  scopeId,
112
- startAt: rows[rows.length - 1].createdAt,
113
- endAt: rows[0].createdAt,
127
+ startAt: earliestCovered,
128
+ endAt: latestCovered,
114
129
  updatedAt: now,
115
130
  },
116
131
  })
@@ -147,7 +147,7 @@ export function truncate(text: string, max: number): string {
147
147
 
148
148
  export async function embedAndUpsert(
149
149
  config: AssistantConfig,
150
- targetType: "segment" | "item" | "summary" | "media",
150
+ targetType: "segment" | "item" | "summary" | "media" | "graph_node",
151
151
  targetId: string,
152
152
  input: EmbeddingInput,
153
153
  extraPayload?: Record<string, unknown>,