@vellumai/assistant 0.4.49 → 0.4.51

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 (353) hide show
  1. package/ARCHITECTURE.md +24 -33
  2. package/README.md +3 -3
  3. package/docs/architecture/integrations.md +2 -2
  4. package/docs/architecture/keychain-broker.md +6 -6
  5. package/docs/architecture/memory.md +180 -119
  6. package/knip.json +32 -0
  7. package/package.json +3 -2
  8. package/src/__tests__/agent-loop.test.ts +3 -1
  9. package/src/__tests__/anthropic-provider.test.ts +114 -23
  10. package/src/__tests__/approval-cascade.test.ts +1 -15
  11. package/src/__tests__/approval-routes-http.test.ts +2 -0
  12. package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
  13. package/src/__tests__/btw-routes.test.ts +61 -5
  14. package/src/__tests__/canonical-guardian-store.test.ts +95 -0
  15. package/src/__tests__/checker.test.ts +13 -0
  16. package/src/__tests__/config-schema.test.ts +1 -68
  17. package/src/__tests__/config-watcher.test.ts +8 -0
  18. package/src/__tests__/context-memory-e2e.test.ts +11 -100
  19. package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
  20. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  21. package/src/__tests__/credential-security-e2e.test.ts +1 -0
  22. package/src/__tests__/credential-security-invariants.test.ts +8 -7
  23. package/src/__tests__/credential-vault-unit.test.ts +23 -18
  24. package/src/__tests__/credential-vault.test.ts +30 -18
  25. package/src/__tests__/credentials-cli.test.ts +257 -82
  26. package/src/__tests__/cu-unified-flow.test.ts +532 -0
  27. package/src/__tests__/date-context.test.ts +93 -77
  28. package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
  29. package/src/__tests__/guardian-routing-invariants.test.ts +93 -0
  30. package/src/__tests__/history-repair.test.ts +245 -0
  31. package/src/__tests__/host-cu-proxy.test.ts +165 -3
  32. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  33. package/src/__tests__/inbound-invite-redemption.test.ts +36 -7
  34. package/src/__tests__/integration-status.test.ts +31 -30
  35. package/src/__tests__/invite-redemption-service.test.ts +166 -13
  36. package/src/__tests__/invite-routes-http.test.ts +166 -5
  37. package/src/__tests__/keychain-broker-client.test.ts +4 -4
  38. package/src/__tests__/list-messages-attachments.test.ts +193 -0
  39. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
  40. package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
  41. package/src/__tests__/memory-recall-quality.test.ts +244 -407
  42. package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
  43. package/src/__tests__/memory-regressions.test.ts +477 -2841
  44. package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
  45. package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
  46. package/src/__tests__/mime-builder.test.ts +28 -0
  47. package/src/__tests__/native-web-search.test.ts +1 -0
  48. package/src/__tests__/oauth-cli.test.ts +824 -31
  49. package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
  50. package/src/__tests__/oauth-store.test.ts +363 -17
  51. package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
  52. package/src/__tests__/registry.test.ts +0 -1
  53. package/src/__tests__/relay-server.test.ts +55 -1
  54. package/src/__tests__/schedule-tools.test.ts +32 -0
  55. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  56. package/src/__tests__/secret-onetime-send.test.ts +1 -0
  57. package/src/__tests__/secret-routes-managed-proxy.test.ts +183 -0
  58. package/src/__tests__/secure-keys.test.ts +78 -18
  59. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  60. package/src/__tests__/server-history-render.test.ts +2 -2
  61. package/src/__tests__/session-abort-tool-results.test.ts +1 -14
  62. package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
  63. package/src/__tests__/session-agent-loop.test.ts +19 -15
  64. package/src/__tests__/session-confirmation-signals.test.ts +1 -15
  65. package/src/__tests__/session-error.test.ts +124 -2
  66. package/src/__tests__/session-history-web-search.test.ts +918 -0
  67. package/src/__tests__/session-pre-run-repair.test.ts +1 -14
  68. package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
  69. package/src/__tests__/session-queue.test.ts +37 -27
  70. package/src/__tests__/session-runtime-assembly.test.ts +54 -0
  71. package/src/__tests__/session-slash-known.test.ts +1 -15
  72. package/src/__tests__/session-slash-queue.test.ts +1 -15
  73. package/src/__tests__/session-slash-unknown.test.ts +1 -15
  74. package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
  75. package/src/__tests__/session-workspace-injection.test.ts +3 -37
  76. package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
  77. package/src/__tests__/skills-install-extract.test.ts +93 -0
  78. package/src/__tests__/skills.test.ts +2 -2
  79. package/src/__tests__/skillssh-registry.test.ts +451 -0
  80. package/src/__tests__/slack-channel-config.test.ts +10 -8
  81. package/src/__tests__/trust-store.test.ts +15 -0
  82. package/src/__tests__/twilio-config.test.ts +11 -10
  83. package/src/__tests__/twilio-provider.test.ts +9 -4
  84. package/src/__tests__/voice-invite-redemption.test.ts +85 -5
  85. package/src/agent/ax-tree-compaction.test.ts +51 -0
  86. package/src/agent/loop.ts +39 -12
  87. package/src/approvals/AGENTS.md +1 -1
  88. package/src/approvals/guardian-request-resolvers.ts +14 -2
  89. package/src/bundler/compiler-tools.ts +66 -2
  90. package/src/calls/call-domain.ts +134 -3
  91. package/src/calls/call-store.ts +6 -0
  92. package/src/calls/relay-server.ts +44 -6
  93. package/src/calls/relay-setup-router.ts +17 -1
  94. package/src/calls/twilio-config.ts +5 -4
  95. package/src/calls/twilio-provider.ts +14 -9
  96. package/src/calls/twilio-rest.ts +10 -7
  97. package/src/calls/types.ts +3 -1
  98. package/src/cli/commands/config.ts +14 -9
  99. package/src/cli/commands/contacts.ts +3 -0
  100. package/src/cli/commands/credentials.ts +170 -174
  101. package/src/cli/commands/doctor.ts +11 -8
  102. package/src/cli/commands/keys.ts +9 -9
  103. package/src/cli/commands/mcp.ts +46 -59
  104. package/src/cli/commands/memory.ts +16 -165
  105. package/src/cli/commands/oauth/apps.ts +68 -10
  106. package/src/cli/commands/oauth/connections.ts +475 -105
  107. package/src/cli/commands/oauth/index.ts +3 -3
  108. package/src/cli/commands/oauth/providers.ts +18 -4
  109. package/src/cli/commands/sessions.ts +5 -2
  110. package/src/cli/commands/skills.ts +173 -1
  111. package/src/cli/http-client.ts +0 -20
  112. package/src/cli/main-screen.tsx +2 -2
  113. package/src/cli/program.ts +5 -6
  114. package/src/cli.ts +20 -22
  115. package/src/config/__tests__/feature-flag-registry-bundled.test.ts +39 -0
  116. package/src/config/bundled-skills/computer-use/TOOLS.json +1 -1
  117. package/src/config/bundled-skills/computer-use/tools/computer-use-observe.ts +12 -0
  118. package/src/config/bundled-skills/contacts/SKILL.md +35 -11
  119. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
  120. package/src/config/bundled-skills/gmail/SKILL.md +1 -1
  121. package/src/config/bundled-skills/gmail/TOOLS.json +52 -0
  122. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +13 -3
  123. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +9 -2
  124. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +5 -1
  125. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +5 -1
  126. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +5 -1
  127. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +5 -1
  128. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +9 -2
  129. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +5 -1
  130. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +5 -1
  131. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +5 -1
  132. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +5 -1
  133. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +5 -1
  134. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +5 -1
  135. package/src/config/bundled-skills/google-calendar/TOOLS.json +20 -0
  136. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +2 -1
  137. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +2 -1
  138. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +2 -1
  139. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +2 -1
  140. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +2 -1
  141. package/src/config/bundled-skills/google-calendar/tools/shared.ts +8 -2
  142. package/src/config/bundled-skills/messaging/SKILL.md +1 -1
  143. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -2
  144. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
  145. package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +2 -2
  146. package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +2 -2
  147. package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +2 -2
  148. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +2 -2
  149. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +2 -2
  150. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +2 -2
  151. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +2 -2
  152. package/src/config/bundled-skills/messaging/tools/shared.ts +7 -5
  153. package/src/config/bundled-skills/slack/tools/shared.ts +1 -1
  154. package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +1 -1
  155. package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +1 -1
  156. package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +1 -1
  157. package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +1 -1
  158. package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +1 -1
  159. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +1 -1
  160. package/src/config/bundled-tool-registry.ts +2 -5
  161. package/src/config/loader.ts +6 -42
  162. package/src/config/schema.ts +1 -12
  163. package/src/config/schemas/memory-lifecycle.ts +0 -9
  164. package/src/config/schemas/memory-processing.ts +0 -180
  165. package/src/config/schemas/memory-retrieval.ts +32 -104
  166. package/src/config/schemas/memory.ts +0 -10
  167. package/src/config/types.ts +0 -4
  168. package/src/contacts/contact-store.ts +39 -2
  169. package/src/contacts/contacts-write.ts +9 -0
  170. package/src/context/window-manager.ts +4 -1
  171. package/src/daemon/config-watcher.ts +55 -2
  172. package/src/daemon/daemon-control.ts +1 -1
  173. package/src/daemon/date-context.ts +114 -31
  174. package/src/daemon/handlers/config-ingress.ts +2 -2
  175. package/src/daemon/handlers/config-slack-channel.ts +59 -39
  176. package/src/daemon/handlers/config-telegram.ts +23 -14
  177. package/src/daemon/handlers/session-history.ts +1 -358
  178. package/src/daemon/handlers/sessions.ts +18 -13
  179. package/src/daemon/handlers/shared.ts +3 -17
  180. package/src/daemon/handlers/skills.ts +20 -1
  181. package/src/daemon/history-repair.ts +72 -8
  182. package/src/daemon/host-cu-proxy.ts +55 -26
  183. package/src/daemon/lifecycle.ts +39 -4
  184. package/src/daemon/mcp-reload-service.ts +2 -2
  185. package/src/daemon/message-types/computer-use.ts +1 -12
  186. package/src/daemon/message-types/memory.ts +4 -16
  187. package/src/daemon/message-types/messages.ts +1 -0
  188. package/src/daemon/message-types/sessions.ts +4 -42
  189. package/src/daemon/server.ts +6 -1
  190. package/src/daemon/session-agent-loop-handlers.ts +38 -0
  191. package/src/daemon/session-agent-loop.ts +334 -48
  192. package/src/daemon/session-error.ts +89 -6
  193. package/src/daemon/session-history.ts +17 -7
  194. package/src/daemon/session-media-retry.ts +6 -2
  195. package/src/daemon/session-memory.ts +69 -149
  196. package/src/daemon/session-process.ts +10 -1
  197. package/src/daemon/session-runtime-assembly.ts +49 -19
  198. package/src/daemon/session-slash.ts +3 -5
  199. package/src/daemon/session-surfaces.ts +4 -1
  200. package/src/daemon/session-tool-setup.ts +7 -1
  201. package/src/daemon/session.ts +12 -2
  202. package/src/email/providers/index.ts +2 -2
  203. package/src/instrument.ts +61 -1
  204. package/src/media/avatar-router.ts +1 -1
  205. package/src/memory/admin.ts +2 -191
  206. package/src/memory/canonical-guardian-store.ts +38 -2
  207. package/src/memory/conversation-crud.ts +0 -33
  208. package/src/memory/conversation-queries.ts +25 -83
  209. package/src/memory/db-init.ts +32 -0
  210. package/src/memory/embedding-backend.ts +84 -8
  211. package/src/memory/embedding-types.ts +9 -1
  212. package/src/memory/indexer.ts +7 -46
  213. package/src/memory/invite-store.ts +19 -0
  214. package/src/memory/items-extractor.ts +274 -76
  215. package/src/memory/job-handlers/backfill.ts +2 -127
  216. package/src/memory/job-handlers/cleanup.ts +2 -16
  217. package/src/memory/job-handlers/extraction.ts +2 -138
  218. package/src/memory/job-handlers/index-maintenance.ts +1 -6
  219. package/src/memory/job-handlers/summarization.ts +3 -148
  220. package/src/memory/job-utils.ts +21 -59
  221. package/src/memory/jobs-store.ts +1 -159
  222. package/src/memory/jobs-worker.ts +9 -52
  223. package/src/memory/migrations/104-core-indexes.ts +3 -3
  224. package/src/memory/migrations/149-oauth-tables.ts +2 -0
  225. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
  226. package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
  227. package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
  228. package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
  229. package/src/memory/migrations/154-drop-fts.ts +20 -0
  230. package/src/memory/migrations/155-drop-conflicts.ts +7 -0
  231. package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
  232. package/src/memory/migrations/157-invite-contact-id.ts +104 -0
  233. package/src/memory/migrations/index.ts +8 -0
  234. package/src/memory/migrations/registry.ts +6 -0
  235. package/src/memory/qdrant-client.ts +148 -51
  236. package/src/memory/raw-query.ts +1 -1
  237. package/src/memory/retriever.test.ts +294 -273
  238. package/src/memory/retriever.ts +421 -645
  239. package/src/memory/schema/calls.ts +2 -0
  240. package/src/memory/schema/contacts.ts +1 -0
  241. package/src/memory/schema/memory-core.ts +3 -48
  242. package/src/memory/schema/oauth.ts +2 -0
  243. package/src/memory/search/formatting.ts +263 -176
  244. package/src/memory/search/lexical.ts +1 -254
  245. package/src/memory/search/ranking.ts +0 -455
  246. package/src/memory/search/semantic.ts +100 -14
  247. package/src/memory/search/staleness.ts +47 -0
  248. package/src/memory/search/tier-classifier.ts +21 -0
  249. package/src/memory/search/types.ts +15 -77
  250. package/src/memory/task-memory-cleanup.ts +4 -6
  251. package/src/messaging/provider.ts +1 -1
  252. package/src/messaging/providers/gmail/adapter.ts +1 -1
  253. package/src/messaging/providers/gmail/mime-builder.ts +17 -7
  254. package/src/messaging/providers/telegram-bot/adapter.ts +17 -8
  255. package/src/messaging/providers/whatsapp/adapter.ts +13 -9
  256. package/src/messaging/registry.ts +9 -5
  257. package/src/oauth/byo-connection.test.ts +40 -25
  258. package/src/oauth/connect-orchestrator.ts +4 -10
  259. package/src/oauth/connection-resolver.ts +20 -6
  260. package/src/oauth/manual-token-connection.ts +5 -5
  261. package/src/oauth/oauth-store.ts +183 -31
  262. package/src/oauth/platform-connection.test.ts +1 -1
  263. package/src/oauth/provider-behaviors.ts +503 -4
  264. package/src/oauth/seed-providers.ts +214 -8
  265. package/src/oauth/token-persistence.ts +31 -16
  266. package/src/permissions/defaults.ts +1 -0
  267. package/src/permissions/trust-store.ts +23 -1
  268. package/src/playbooks/playbook-compiler.ts +1 -1
  269. package/src/prompts/system-prompt.ts +18 -2
  270. package/src/providers/anthropic/client.ts +56 -126
  271. package/src/providers/types.ts +7 -1
  272. package/src/runtime/AGENTS.md +9 -0
  273. package/src/runtime/auth/route-policy.ts +6 -3
  274. package/src/runtime/channel-readiness-service.ts +48 -40
  275. package/src/runtime/guardian-reply-router.ts +24 -22
  276. package/src/runtime/http-server.ts +2 -2
  277. package/src/runtime/http-types.ts +2 -0
  278. package/src/runtime/invite-redemption-service.ts +72 -12
  279. package/src/runtime/invite-service.ts +43 -0
  280. package/src/runtime/middleware/twilio-validation.ts +1 -1
  281. package/src/runtime/pending-interactions.ts +2 -2
  282. package/src/runtime/routes/brain-graph-routes.ts +10 -90
  283. package/src/runtime/routes/btw-routes.ts +10 -5
  284. package/src/runtime/routes/conversation-routes.ts +56 -11
  285. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
  286. package/src/runtime/routes/integrations/slack/channel.ts +2 -2
  287. package/src/runtime/routes/integrations/telegram.ts +2 -2
  288. package/src/runtime/routes/integrations/twilio.ts +17 -17
  289. package/src/runtime/routes/invite-routes.ts +29 -4
  290. package/src/runtime/routes/memory-item-routes.test.ts +754 -0
  291. package/src/runtime/routes/memory-item-routes.ts +503 -0
  292. package/src/runtime/routes/secret-routes.ts +17 -0
  293. package/src/runtime/routes/session-management-routes.ts +3 -3
  294. package/src/runtime/routes/settings-routes.ts +3 -3
  295. package/src/runtime/routes/trust-rules-routes.ts +14 -0
  296. package/src/runtime/routes/workspace-routes.ts +9 -4
  297. package/src/runtime/routes/workspace-utils.ts +8 -2
  298. package/src/schedule/integration-status.ts +26 -19
  299. package/src/security/keychain-broker-client.ts +17 -4
  300. package/src/security/oauth2.ts +6 -7
  301. package/src/security/secure-keys.ts +44 -19
  302. package/src/security/token-manager.ts +46 -39
  303. package/src/services/vercel-deploy.ts +0 -24
  304. package/src/signals/confirm.ts +78 -0
  305. package/src/signals/mcp-reload.ts +18 -0
  306. package/src/skills/catalog-install.ts +74 -18
  307. package/src/skills/skillssh-registry.ts +503 -0
  308. package/src/tools/assets/search.ts +5 -1
  309. package/src/tools/computer-use/definitions.ts +0 -10
  310. package/src/tools/computer-use/registry.ts +1 -1
  311. package/src/tools/credentials/vault.ts +22 -7
  312. package/src/tools/memory/definitions.ts +4 -13
  313. package/src/tools/memory/handlers.test.ts +83 -103
  314. package/src/tools/memory/handlers.ts +50 -85
  315. package/src/tools/network/script-proxy/session-manager.ts +8 -8
  316. package/src/tools/schedule/create.ts +10 -3
  317. package/src/tools/schedule/update.ts +8 -1
  318. package/src/tools/skills/load.ts +25 -2
  319. package/src/watcher/provider-types.ts +1 -1
  320. package/src/watcher/providers/github.ts +1 -1
  321. package/src/watcher/providers/gmail.ts +3 -3
  322. package/src/watcher/providers/google-calendar.ts +3 -3
  323. package/src/watcher/providers/linear.ts +1 -1
  324. package/src/__tests__/clarification-resolver.test.ts +0 -193
  325. package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
  326. package/src/__tests__/conflict-policy.test.ts +0 -269
  327. package/src/__tests__/conflict-store.test.ts +0 -372
  328. package/src/__tests__/contradiction-checker.test.ts +0 -361
  329. package/src/__tests__/entity-extractor.test.ts +0 -211
  330. package/src/__tests__/entity-search.test.ts +0 -1117
  331. package/src/__tests__/profile-compiler.test.ts +0 -392
  332. package/src/__tests__/session-conflict-gate.test.ts +0 -1228
  333. package/src/__tests__/session-profile-injection.test.ts +0 -557
  334. package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
  335. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
  336. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
  337. package/src/daemon/session-conflict-gate.ts +0 -167
  338. package/src/daemon/session-dynamic-profile.ts +0 -77
  339. package/src/memory/clarification-resolver.ts +0 -417
  340. package/src/memory/conflict-intent.ts +0 -205
  341. package/src/memory/conflict-policy.ts +0 -127
  342. package/src/memory/conflict-store.ts +0 -410
  343. package/src/memory/contradiction-checker.ts +0 -508
  344. package/src/memory/entity-extractor.ts +0 -535
  345. package/src/memory/format-recall.ts +0 -47
  346. package/src/memory/fts-reconciler.ts +0 -165
  347. package/src/memory/job-handlers/conflict.ts +0 -200
  348. package/src/memory/profile-compiler.ts +0 -195
  349. package/src/memory/recall-cache.ts +0 -117
  350. package/src/memory/search/entity.ts +0 -535
  351. package/src/memory/search/query-expansion.test.ts +0 -70
  352. package/src/memory/search/query-expansion.ts +0 -118
  353. package/src/runtime/routes/mcp-routes.ts +0 -20
@@ -2,20 +2,11 @@ import { getConfig } from "../config/loader.js";
2
2
  import type { AssistantConfig } from "../config/types.js";
3
3
  import { getLogger } from "../util/logger.js";
4
4
  import { rawRun } from "./db.js";
5
- import { reconcileFtsIndexes } from "./fts-reconciler.js";
5
+ import { backfillJob } from "./job-handlers/backfill.js";
6
6
  import {
7
- backfillEntityRelationsJob,
8
- backfillJob,
9
- } from "./job-handlers/backfill.js";
10
- import {
11
- checkContradictionsJob,
12
7
  cleanupStaleSupersededItemsJob,
13
8
  pruneOldConversationsJob,
14
9
  } from "./job-handlers/cleanup.js";
15
- import {
16
- cleanupResolvedConflictsJob,
17
- resolvePendingConflictsForMessageJob,
18
- } from "./job-handlers/conflict.js";
19
10
  // ── Per-job-type handlers ──────────────────────────────────────────
20
11
  import {
21
12
  embedAttachmentJob,
@@ -24,19 +15,13 @@ import {
24
15
  embedSegmentJob,
25
16
  embedSummaryJob,
26
17
  } from "./job-handlers/embedding.js";
27
- import {
28
- extractEntitiesJob,
29
- extractItemsJob,
30
- } from "./job-handlers/extraction.js";
18
+ import { extractItemsJob } from "./job-handlers/extraction.js";
31
19
  import {
32
20
  deleteQdrantVectorsJob,
33
21
  rebuildIndexJob,
34
22
  } from "./job-handlers/index-maintenance.js";
35
23
  import { mediaProcessingJob } from "./job-handlers/media-processing.js";
36
- import {
37
- buildConversationSummaryJob,
38
- buildGlobalSummaryJob,
39
- } from "./job-handlers/summarization.js";
24
+ import { buildConversationSummaryJob } from "./job-handlers/summarization.js";
40
25
  import {
41
26
  BackendUnavailableError,
42
27
  classifyError,
@@ -47,20 +32,14 @@ import {
47
32
  claimMemoryJobs,
48
33
  completeMemoryJob,
49
34
  deferMemoryJob,
50
- enqueueCleanupResolvedConflictsJob,
51
35
  enqueueCleanupStaleSupersededItemsJob,
52
36
  enqueuePruneOldConversationsJob,
53
- enqueueReconcileFtsJob,
54
37
  failMemoryJob,
55
38
  failStalledJobs,
56
39
  type MemoryJob,
57
40
  resetRunningJobsToPending,
58
41
  } from "./jobs-store.js";
59
42
  import { QdrantCircuitOpenError } from "./qdrant-circuit-breaker.js";
60
- import { bumpMemoryVersion } from "./recall-cache.js";
61
-
62
- // Re-export public utilities consumed by tests and other modules
63
- export { currentWeekWindow } from "./job-utils.js";
64
43
 
65
44
  const log = getLogger("memory-jobs-worker");
66
45
 
@@ -157,7 +136,6 @@ export async function runMemoryJobsOnce(
157
136
  try {
158
137
  await processJob(job, config);
159
138
  completeMemoryJob(job.id);
160
- bumpMemoryVersion();
161
139
  groupProcessed += 1;
162
140
  } catch (err) {
163
141
  try {
@@ -292,13 +270,7 @@ async function processJob(
292
270
  await extractItemsJob(job);
293
271
  return;
294
272
  case "extract_entities":
295
- await extractEntitiesJob(job, config);
296
- return;
297
- case "resolve_pending_conflicts_for_message":
298
- await resolvePendingConflictsForMessageJob(job, config);
299
- return;
300
- case "cleanup_resolved_conflicts":
301
- cleanupResolvedConflictsJob(job, config);
273
+ // Entity extraction has been removed — silently drop legacy jobs
302
274
  return;
303
275
  case "cleanup_stale_superseded_items":
304
276
  cleanupStaleSupersededItemsJob(job, config);
@@ -306,30 +278,22 @@ async function processJob(
306
278
  case "prune_old_conversations":
307
279
  pruneOldConversationsJob(job, config);
308
280
  return;
309
- case "check_contradictions":
310
- await checkContradictionsJob(job);
311
- return;
312
281
  case "build_conversation_summary":
313
282
  await buildConversationSummaryJob(job, config);
314
283
  return;
315
- case "refresh_weekly_summary":
316
- await buildGlobalSummaryJob("weekly_global", config);
317
- return;
318
- case "refresh_monthly_summary":
319
- await buildGlobalSummaryJob("monthly_global", config);
320
- return;
321
284
  case "backfill":
322
285
  backfillJob(job, config);
323
286
  return;
324
287
  case "backfill_entity_relations":
325
- backfillEntityRelationsJob(job, config);
288
+ // Entity relation backfill has been removed — silently drop legacy jobs
289
+ return;
290
+ case "refresh_weekly_summary":
291
+ case "refresh_monthly_summary":
292
+ // Global summary rollups have been removed — silently drop legacy jobs
326
293
  return;
327
294
  case "rebuild_index":
328
295
  rebuildIndexJob();
329
296
  return;
330
- case "reconcile_fts":
331
- reconcileFtsIndexes();
332
- return;
333
297
  case "delete_qdrant_vectors":
334
298
  await deleteQdrantVectorsJob(job);
335
299
  return;
@@ -371,9 +335,6 @@ export function maybeEnqueueScheduledCleanupJobs(
371
335
  if (nowMs - lastScheduledCleanupEnqueueMs < cleanup.enqueueIntervalMs)
372
336
  return false;
373
337
 
374
- const resolvedConflictsJobId = enqueueCleanupResolvedConflictsJob(
375
- cleanup.resolvedConflictRetentionMs,
376
- );
377
338
  const staleSupersededItemsJobId = enqueueCleanupStaleSupersededItemsJob(
378
339
  cleanup.supersededItemRetentionMs,
379
340
  );
@@ -381,16 +342,12 @@ export function maybeEnqueueScheduledCleanupJobs(
381
342
  cleanup.conversationRetentionDays > 0
382
343
  ? enqueuePruneOldConversationsJob(cleanup.conversationRetentionDays)
383
344
  : null;
384
- const reconcileFtsJobId = enqueueReconcileFtsJob();
385
345
  lastScheduledCleanupEnqueueMs = nowMs;
386
346
  log.debug(
387
347
  {
388
- resolvedConflictsJobId,
389
348
  staleSupersededItemsJobId,
390
349
  pruneConversationsJobId,
391
- reconcileFtsJobId,
392
350
  enqueueIntervalMs: cleanup.enqueueIntervalMs,
393
- resolvedConflictRetentionMs: cleanup.resolvedConflictRetentionMs,
394
351
  supersededItemRetentionMs: cleanup.supersededItemRetentionMs,
395
352
  conversationRetentionDays: cleanup.conversationRetentionDays,
396
353
  },
@@ -69,9 +69,9 @@ export function createCoreIndexes(database: DrizzleDb): void {
69
69
  database.run(
70
70
  /*sql*/ `CREATE INDEX IF NOT EXISTS idx_memory_items_last_seen_at ON memory_items(last_seen_at)`,
71
71
  );
72
- // Partial covering index for directItemSearch: the LIKE '%term%' pattern can't
73
- // seek a B-tree, but this index lets SQLite scan only active non-invalidated rows
74
- // and evaluate LIKE + return columns without touching the main table.
72
+ // Partial covering index for active memory item queries: this index lets SQLite
73
+ // scan only active non-invalidated rows and return columns without touching
74
+ // the main table.
75
75
  migrateDropActiveSearchIndex(database);
76
76
  database.run(/*sql*/ `
77
77
  CREATE INDEX IF NOT EXISTS idx_memory_items_active_search
@@ -18,6 +18,7 @@ export function createOAuthTables(database: DrizzleDb): void {
18
18
  extra_params TEXT,
19
19
  callback_transport TEXT,
20
20
  loopback_port INTEGER,
21
+ ping_url TEXT,
21
22
  created_at INTEGER NOT NULL,
22
23
  updated_at INTEGER NOT NULL
23
24
  )
@@ -28,6 +29,7 @@ export function createOAuthTables(database: DrizzleDb): void {
28
29
  id TEXT PRIMARY KEY,
29
30
  provider_key TEXT NOT NULL REFERENCES oauth_providers(provider_key),
30
31
  client_id TEXT NOT NULL,
32
+ client_secret_credential_path TEXT NOT NULL,
31
33
  created_at INTEGER NOT NULL,
32
34
  updated_at INTEGER NOT NULL
33
35
  )
@@ -0,0 +1,98 @@
1
+ import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
2
+ import { withCrashRecovery } from "./validate-migration-state.js";
3
+
4
+ /**
5
+ * Add client_secret_credential_path column to oauth_apps.
6
+ *
7
+ * Makes explicit what was previously implicit: the credential path pattern
8
+ * `oauth_app/${id}/client_secret`. Steps:
9
+ *
10
+ * 1. ALTER TABLE to add the column (nullable initially).
11
+ * 2. Backfill existing rows with `oauth_app/${id}/client_secret`.
12
+ * 3. Rebuild the table to enforce NOT NULL (SQLite doesn't support ALTER COLUMN).
13
+ *
14
+ * Idempotent — skips if the column already exists with NOT NULL.
15
+ */
16
+ export function migrateOAuthAppsClientSecretPath(database: DrizzleDb): void {
17
+ withCrashRecovery(
18
+ database,
19
+ "migration_oauth_apps_client_secret_path_v1",
20
+ () => {
21
+ const raw = getSqliteFrom(database);
22
+
23
+ // Guard: table must exist
24
+ const tableExists = raw
25
+ .query(
26
+ `SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'oauth_apps'`,
27
+ )
28
+ .get();
29
+ if (!tableExists) return;
30
+
31
+ // Guard: check if column already exists with NOT NULL
32
+ const colInfo = raw
33
+ .query(
34
+ `SELECT "notnull" FROM pragma_table_info('oauth_apps') WHERE name = 'client_secret_credential_path'`,
35
+ )
36
+ .get() as { notnull: number } | null;
37
+ if (colInfo && colInfo.notnull === 1) return;
38
+
39
+ // Step 1: Add the column (nullable) — wrapped in try/catch for idempotency
40
+ if (!colInfo) {
41
+ try {
42
+ raw.exec(
43
+ /*sql*/ `ALTER TABLE oauth_apps ADD COLUMN client_secret_credential_path TEXT`,
44
+ );
45
+ } catch {
46
+ // Column may already exist from a previous partial run
47
+ }
48
+ }
49
+
50
+ // Step 2: Backfill existing rows
51
+ raw.exec(
52
+ /*sql*/ `UPDATE oauth_apps SET client_secret_credential_path = 'oauth_app/' || id || '/client_secret' WHERE client_secret_credential_path IS NULL`,
53
+ );
54
+
55
+ // Step 3: Rebuild the table to enforce NOT NULL
56
+ raw.exec("PRAGMA foreign_keys = OFF");
57
+ try {
58
+ raw.exec("BEGIN");
59
+
60
+ raw.exec(/*sql*/ `
61
+ CREATE TABLE oauth_apps_new (
62
+ id TEXT PRIMARY KEY,
63
+ provider_key TEXT NOT NULL REFERENCES oauth_providers(provider_key),
64
+ client_id TEXT NOT NULL,
65
+ client_secret_credential_path TEXT NOT NULL DEFAULT '',
66
+ created_at INTEGER NOT NULL,
67
+ updated_at INTEGER NOT NULL
68
+ )
69
+ `);
70
+
71
+ raw.exec(/*sql*/ `
72
+ INSERT INTO oauth_apps_new
73
+ SELECT id, provider_key, client_id, client_secret_credential_path, created_at, updated_at
74
+ FROM oauth_apps
75
+ `);
76
+
77
+ raw.exec(/*sql*/ `DROP TABLE oauth_apps`);
78
+ raw.exec(/*sql*/ `ALTER TABLE oauth_apps_new RENAME TO oauth_apps`);
79
+
80
+ // Recreate the unique index
81
+ raw.exec(
82
+ /*sql*/ `CREATE UNIQUE INDEX IF NOT EXISTS idx_oauth_apps_provider_client ON oauth_apps(provider_key, client_id)`,
83
+ );
84
+
85
+ raw.exec("COMMIT");
86
+ } catch (e) {
87
+ try {
88
+ raw.exec("ROLLBACK");
89
+ } catch {
90
+ /* no active transaction */
91
+ }
92
+ throw e;
93
+ } finally {
94
+ raw.exec("PRAGMA foreign_keys = ON");
95
+ }
96
+ },
97
+ );
98
+ }
@@ -0,0 +1,11 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { getSqliteFrom } from "../db-connection.js";
3
+
4
+ export function migrateOAuthProvidersPingUrl(database: DrizzleDb): void {
5
+ const raw = getSqliteFrom(database);
6
+ try {
7
+ raw.exec(/*sql*/ `ALTER TABLE oauth_providers ADD COLUMN ping_url TEXT`);
8
+ } catch {
9
+ // Column already exists — nothing to do.
10
+ }
11
+ }
@@ -0,0 +1,44 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { getSqliteFrom } from "../db-connection.js";
3
+
4
+ /**
5
+ * Add supersession tracking columns and override confidence to memory_items.
6
+ *
7
+ * - `supersedes` — references the ID of the item this one replaces
8
+ * - `superseded_by` — references the ID of the item that replaced this one
9
+ * - `override_confidence` — enum: "explicit", "tentative", "inferred" (default "inferred")
10
+ * - Index on (status, superseded_by) for filtering active non-superseded items
11
+ *
12
+ * All columns are added via ALTER TABLE with try/catch for idempotency.
13
+ */
14
+ export function migrateMemoryItemSupersession(database: DrizzleDb): void {
15
+ const raw = getSqliteFrom(database);
16
+
17
+ try {
18
+ raw.exec(
19
+ /*sql*/ `ALTER TABLE memory_items ADD COLUMN supersedes TEXT DEFAULT NULL`,
20
+ );
21
+ } catch {
22
+ // Column already exists
23
+ }
24
+
25
+ try {
26
+ raw.exec(
27
+ /*sql*/ `ALTER TABLE memory_items ADD COLUMN superseded_by TEXT DEFAULT NULL`,
28
+ );
29
+ } catch {
30
+ // Column already exists
31
+ }
32
+
33
+ try {
34
+ raw.exec(
35
+ /*sql*/ `ALTER TABLE memory_items ADD COLUMN override_confidence TEXT DEFAULT 'inferred'`,
36
+ );
37
+ } catch {
38
+ // Column already exists
39
+ }
40
+
41
+ raw.exec(
42
+ /*sql*/ `CREATE INDEX IF NOT EXISTS idx_memory_items_status_superseded_by ON memory_items(status, superseded_by)`,
43
+ );
44
+ }
@@ -0,0 +1,15 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { getSqliteFrom } from "../db-connection.js";
3
+
4
+ /**
5
+ * Drop entity-related tables that are no longer used.
6
+ *
7
+ * Entity search has been replaced by hybrid search on entity-rich text
8
+ * in item statements, so these tables are now dead weight.
9
+ */
10
+ export function migrateDropEntityTables(database: DrizzleDb): void {
11
+ const raw = getSqliteFrom(database);
12
+ raw.exec(/*sql*/ `DROP TABLE IF EXISTS memory_item_entities`);
13
+ raw.exec(/*sql*/ `DROP TABLE IF EXISTS memory_entity_relations`);
14
+ raw.exec(/*sql*/ `DROP TABLE IF EXISTS memory_entities`);
15
+ }
@@ -0,0 +1,20 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { getSqliteFrom } from "../db-connection.js";
3
+
4
+ /**
5
+ * Drop the memory_segment_fts virtual table and its associated triggers.
6
+ *
7
+ * The FTS-based lexical search pipeline has been replaced by Qdrant hybrid
8
+ * search. Keeping the FTS table around wastes disk space and adds write
9
+ * overhead on every segment insert/update/delete.
10
+ */
11
+ export function migrateDropMemorySegmentFts(database: DrizzleDb): void {
12
+ const raw = getSqliteFrom(database);
13
+
14
+ // Drop triggers first — they reference the FTS table.
15
+ raw.exec(/*sql*/ `DROP TRIGGER IF EXISTS memory_segments_ai`);
16
+ raw.exec(/*sql*/ `DROP TRIGGER IF EXISTS memory_segments_ad`);
17
+ raw.exec(/*sql*/ `DROP TRIGGER IF EXISTS memory_segments_au`);
18
+
19
+ raw.exec(/*sql*/ `DROP TABLE IF EXISTS memory_segment_fts`);
20
+ }
@@ -0,0 +1,7 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { getSqliteFrom } from "../db-connection.js";
3
+
4
+ export function migrateDropConflicts(database: DrizzleDb): void {
5
+ const raw = getSqliteFrom(database);
6
+ raw.exec(/*sql*/ `DROP TABLE IF EXISTS memory_item_conflicts`);
7
+ }
@@ -0,0 +1,24 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+
3
+ /**
4
+ * Add invite metadata columns to call_sessions so outbound invite calls
5
+ * can persist friend/guardian names for deterministic routing in the
6
+ * relay setup router (mirroring how verification_session_id works for
7
+ * guardian verification calls).
8
+ */
9
+ export function migrateCallSessionInviteMetadata(database: DrizzleDb): void {
10
+ try {
11
+ database.run(
12
+ /*sql*/ `ALTER TABLE call_sessions ADD COLUMN invite_friend_name TEXT`,
13
+ );
14
+ } catch {
15
+ /* already exists */
16
+ }
17
+ try {
18
+ database.run(
19
+ /*sql*/ `ALTER TABLE call_sessions ADD COLUMN invite_guardian_name TEXT`,
20
+ );
21
+ } catch {
22
+ /* already exists */
23
+ }
24
+ }
@@ -0,0 +1,104 @@
1
+ import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
2
+ import { withCrashRecovery } from "./validate-migration-state.js";
3
+
4
+ /**
5
+ * Add a required contact_id column to assistant_ingress_invites.
6
+ * Invites must be bound to the contact they were created for.
7
+ * Legacy rows without a contact_id are deleted since they cannot
8
+ * be redeemed correctly.
9
+ *
10
+ * Steps:
11
+ * 1. Add the column as nullable.
12
+ * 2. Delete legacy rows that have no contact binding (NULL).
13
+ * 3. Rebuild the table to enforce NOT NULL (SQLite cannot ALTER COLUMN).
14
+ */
15
+ export function migrateInviteContactId(database: DrizzleDb): void {
16
+ withCrashRecovery(database, "migration_invite_contact_id_v1", () => {
17
+ const raw = getSqliteFrom(database);
18
+
19
+ const cols = (
20
+ raw.query(`PRAGMA table_info(assistant_ingress_invites)`).all() as Array<{
21
+ name: string;
22
+ notnull: number;
23
+ }>
24
+ ).map((c) => ({ name: c.name, notnull: c.notnull }));
25
+
26
+ const col = cols.find((c) => c.name === "contact_id");
27
+
28
+ // Step 1: Add the column as nullable
29
+ if (!col) {
30
+ raw.exec(
31
+ /*sql*/ `ALTER TABLE assistant_ingress_invites ADD COLUMN contact_id TEXT`,
32
+ );
33
+ }
34
+
35
+ // Step 2: Delete legacy rows with no contact binding
36
+ raw.exec(
37
+ /*sql*/ `DELETE FROM assistant_ingress_invites WHERE contact_id IS NULL OR contact_id = ''`,
38
+ );
39
+
40
+ // Step 3: Rebuild the table with NOT NULL on contact_id
41
+ if (col && col.notnull === 1) return; // already NOT NULL
42
+
43
+ raw.exec("PRAGMA foreign_keys = OFF");
44
+ try {
45
+ raw.exec(/*sql*/ `
46
+ BEGIN;
47
+
48
+ CREATE TABLE assistant_ingress_invites_new (
49
+ id TEXT PRIMARY KEY,
50
+ source_channel TEXT NOT NULL,
51
+ token_hash TEXT NOT NULL,
52
+ created_by_session_id TEXT,
53
+ note TEXT,
54
+ max_uses INTEGER NOT NULL DEFAULT 1 CHECK (max_uses > 0),
55
+ use_count INTEGER NOT NULL DEFAULT 0 CHECK (use_count >= 0),
56
+ expires_at INTEGER NOT NULL,
57
+ status TEXT NOT NULL DEFAULT 'active',
58
+ redeemed_by_external_user_id TEXT,
59
+ redeemed_by_external_chat_id TEXT,
60
+ redeemed_at INTEGER,
61
+ expected_external_user_id TEXT,
62
+ voice_code_hash TEXT,
63
+ voice_code_digits INTEGER,
64
+ invite_code_hash TEXT,
65
+ friend_name TEXT,
66
+ guardian_name TEXT,
67
+ contact_id TEXT NOT NULL,
68
+ created_at INTEGER NOT NULL,
69
+ updated_at INTEGER NOT NULL
70
+ );
71
+
72
+ INSERT INTO assistant_ingress_invites_new
73
+ SELECT id, source_channel, token_hash, created_by_session_id, note,
74
+ max_uses, use_count, expires_at, status,
75
+ redeemed_by_external_user_id, redeemed_by_external_chat_id,
76
+ redeemed_at, expected_external_user_id, voice_code_hash,
77
+ voice_code_digits, invite_code_hash, friend_name, guardian_name,
78
+ contact_id, created_at, updated_at
79
+ FROM assistant_ingress_invites;
80
+
81
+ DROP TABLE assistant_ingress_invites;
82
+ ALTER TABLE assistant_ingress_invites_new RENAME TO assistant_ingress_invites;
83
+
84
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_ingress_invites_token_hash
85
+ ON assistant_ingress_invites(token_hash);
86
+ CREATE INDEX IF NOT EXISTS idx_ingress_invites_channel_status
87
+ ON assistant_ingress_invites(source_channel, status, expires_at);
88
+ CREATE INDEX IF NOT EXISTS idx_ingress_invites_channel_created
89
+ ON assistant_ingress_invites(source_channel, created_at);
90
+
91
+ COMMIT;
92
+ `);
93
+ } catch (e) {
94
+ try {
95
+ raw.exec("ROLLBACK");
96
+ } catch {
97
+ /* no active transaction */
98
+ }
99
+ throw e;
100
+ } finally {
101
+ raw.exec("PRAGMA foreign_keys = ON");
102
+ }
103
+ });
104
+ }
@@ -91,6 +91,14 @@ export { migrateScheduleOneShotRouting } from "./146-schedule-oneshot-routing.js
91
91
  export { migrateRemindersToSchedules } from "./147-migrate-reminders-to-schedules.js";
92
92
  export { migrateDropRemindersTable } from "./148-drop-reminders-table.js";
93
93
  export { createOAuthTables } from "./149-oauth-tables.js";
94
+ export { migrateOAuthAppsClientSecretPath } from "./150-oauth-apps-client-secret-path.js";
95
+ export { migrateOAuthProvidersPingUrl } from "./151-oauth-providers-ping-url.js";
96
+ export { migrateMemoryItemSupersession } from "./152-memory-item-supersession.js";
97
+ export { migrateDropEntityTables } from "./153-drop-entity-tables.js";
98
+ export { migrateDropMemorySegmentFts } from "./154-drop-fts.js";
99
+ export { migrateDropConflicts } from "./155-drop-conflicts.js";
100
+ export { migrateCallSessionInviteMetadata } from "./156-call-session-invite-metadata.js";
101
+ export { migrateInviteContactId } from "./157-invite-contact-id.js";
94
102
  export {
95
103
  MIGRATION_REGISTRY,
96
104
  type MigrationRegistryEntry,
@@ -190,6 +190,12 @@ export const MIGRATION_REGISTRY: MigrationRegistryEntry[] = [
190
190
  description:
191
191
  "Drop the legacy reminders table and its index after data migration to cron_jobs",
192
192
  },
193
+ {
194
+ key: "migration_oauth_apps_client_secret_path_v1",
195
+ version: 28,
196
+ description:
197
+ "Add client_secret_credential_path column to oauth_apps and backfill existing rows with convention-based paths",
198
+ },
193
199
  ];
194
200
 
195
201
  export interface MigrationValidationResult {