@vellumai/assistant 0.3.4 → 0.3.6

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 (506) hide show
  1. package/Dockerfile +2 -0
  2. package/README.md +88 -2
  3. package/eslint.config.mjs +31 -0
  4. package/package.json +1 -1
  5. package/scripts/ipc/check-swift-decoder-drift.ts +4 -1
  6. package/scripts/ipc/generate-swift.ts +31 -2
  7. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +438 -1
  8. package/src/__tests__/approval-conversation-turn.test.ts +214 -0
  9. package/src/__tests__/approval-hardcoded-copy-guard.test.ts +41 -0
  10. package/src/__tests__/approval-message-composer.test.ts +253 -0
  11. package/src/__tests__/browser-manager.test.ts +1 -0
  12. package/src/__tests__/call-conversation-messages.test.ts +130 -0
  13. package/src/__tests__/call-domain.test.ts +12 -2
  14. package/src/__tests__/call-orchestrator.test.ts +799 -249
  15. package/src/__tests__/call-pointer-messages.test.ts +148 -0
  16. package/src/__tests__/call-recovery.test.ts +3 -0
  17. package/src/__tests__/call-routes-http.test.ts +32 -2
  18. package/src/__tests__/call-store.test.ts +3 -0
  19. package/src/__tests__/channel-approval-routes.test.ts +1277 -98
  20. package/src/__tests__/channel-approval.test.ts +37 -0
  21. package/src/__tests__/channel-approvals.test.ts +36 -50
  22. package/src/__tests__/channel-guardian.test.ts +630 -22
  23. package/src/__tests__/channel-readiness-service.test.ts +324 -0
  24. package/src/__tests__/checker.test.ts +14 -7
  25. package/src/__tests__/clarification-resolver.test.ts +44 -24
  26. package/src/__tests__/commit-message-enrichment-service.test.ts +9 -4
  27. package/src/__tests__/computer-use-session-working-dir.test.ts +8 -0
  28. package/src/__tests__/config-schema.test.ts +14 -8
  29. package/src/__tests__/context-window-manager.test.ts +30 -2
  30. package/src/__tests__/contradiction-checker.test.ts +20 -5
  31. package/src/__tests__/credential-security-invariants.test.ts +7 -2
  32. package/src/__tests__/daemon-lifecycle.test.ts +13 -12
  33. package/src/__tests__/db-migration-rollback.test.ts +752 -0
  34. package/src/__tests__/dictation-mode-detection.test.ts +63 -0
  35. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -0
  36. package/src/__tests__/entity-search.test.ts +615 -0
  37. package/src/__tests__/fuzzy-match-property.test.ts +5 -5
  38. package/src/__tests__/guardian-action-store.test.ts +123 -0
  39. package/src/__tests__/guardian-action-sweep.test.ts +277 -0
  40. package/src/__tests__/guardian-dispatch.test.ts +389 -0
  41. package/src/__tests__/guardian-question-copy.test.ts +47 -0
  42. package/src/__tests__/handlers-telegram-config.test.ts +4 -2
  43. package/src/__tests__/handlers-twilio-config.test.ts +533 -0
  44. package/src/__tests__/intent-routing.test.ts +2 -0
  45. package/src/__tests__/ipc-snapshot.test.ts +291 -1
  46. package/src/__tests__/memory-upsert-concurrency.test.ts +828 -0
  47. package/src/__tests__/messaging-send-tool.test.ts +65 -0
  48. package/src/__tests__/model-intents.test.ts +96 -0
  49. package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +42 -0
  50. package/src/__tests__/oauth2-gateway-transport.test.ts +130 -0
  51. package/src/__tests__/onboarding-starter-tasks.test.ts +2 -0
  52. package/src/__tests__/provider-commit-message-generator.test.ts +89 -13
  53. package/src/__tests__/provider-error-scenarios.test.ts +621 -0
  54. package/src/__tests__/provider-fail-open-selection.test.ts +119 -0
  55. package/src/__tests__/qdrant-manager.test.ts +27 -20
  56. package/src/__tests__/relay-server.test.ts +779 -40
  57. package/src/__tests__/run-orchestrator-assistant-events.test.ts +6 -0
  58. package/src/__tests__/run-orchestrator.test.ts +42 -4
  59. package/src/__tests__/runtime-runs-http.test.ts +17 -1
  60. package/src/__tests__/runtime-runs.test.ts +16 -0
  61. package/src/__tests__/schedule-store.test.ts +18 -4
  62. package/src/__tests__/scheduler-recurrence.test.ts +13 -4
  63. package/src/__tests__/session-abort-tool-results.test.ts +6 -0
  64. package/src/__tests__/session-agent-loop.test.ts +857 -0
  65. package/src/__tests__/session-conflict-gate.test.ts +6 -0
  66. package/src/__tests__/session-pre-run-repair.test.ts +6 -0
  67. package/src/__tests__/session-profile-injection.test.ts +6 -0
  68. package/src/__tests__/session-provider-retry-repair.test.ts +6 -0
  69. package/src/__tests__/session-queue.test.ts +6 -0
  70. package/src/__tests__/session-runtime-assembly.test.ts +321 -13
  71. package/src/__tests__/session-slash-known.test.ts +6 -0
  72. package/src/__tests__/session-slash-queue.test.ts +6 -0
  73. package/src/__tests__/session-slash-unknown.test.ts +6 -0
  74. package/src/__tests__/session-surfaces-task-progress.test.ts +2 -0
  75. package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -0
  76. package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -0
  77. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -0
  78. package/src/__tests__/session-workspace-injection.test.ts +6 -0
  79. package/src/__tests__/session-workspace-tool-tracking.test.ts +6 -0
  80. package/src/__tests__/skills.test.ts +2 -0
  81. package/src/__tests__/sms-messaging-provider.test.ts +126 -0
  82. package/src/__tests__/starter-task-flow.test.ts +2 -0
  83. package/src/__tests__/swarm-dag-pathological.test.ts +535 -0
  84. package/src/__tests__/system-prompt.test.ts +2 -0
  85. package/src/__tests__/task-management-tools.test.ts +2 -2
  86. package/src/__tests__/task-runner.test.ts +14 -4
  87. package/src/__tests__/terminal-tools.test.ts +25 -19
  88. package/src/__tests__/tool-execution-abort-cleanup.test.ts +545 -0
  89. package/src/__tests__/tool-executor-shell-integration.test.ts +11 -11
  90. package/src/__tests__/tool-executor.test.ts +23 -24
  91. package/src/__tests__/trust-store.test.ts +3 -3
  92. package/src/__tests__/twilio-rest.test.ts +29 -0
  93. package/src/__tests__/twilio-routes-elevenlabs.test.ts +3 -0
  94. package/src/__tests__/twilio-routes-twiml.test.ts +11 -0
  95. package/src/__tests__/twilio-routes.test.ts +167 -11
  96. package/src/__tests__/twitter-cli-error-shaping.test.ts +2 -2
  97. package/src/__tests__/user-reference.test.ts +2 -0
  98. package/src/__tests__/voice-quality.test.ts +222 -0
  99. package/src/__tests__/web-search.test.ts +46 -30
  100. package/src/__tests__/work-item-output.test.ts +110 -0
  101. package/src/agent/loop.ts +1 -1
  102. package/src/agent-heartbeat/agent-heartbeat-service.ts +2 -10
  103. package/src/amazon/client.ts +1418 -0
  104. package/src/amazon/request-extractor.ts +135 -0
  105. package/src/amazon/session.ts +109 -0
  106. package/src/autonomy/autonomy-store.ts +5 -5
  107. package/src/browser-extension-relay/client.ts +124 -0
  108. package/src/browser-extension-relay/protocol.ts +63 -0
  109. package/src/browser-extension-relay/server.ts +177 -0
  110. package/src/bundler/app-bundler.ts +3 -3
  111. package/src/bundler/bundle-signer.ts +1 -1
  112. package/src/bundler/signature-verifier.ts +1 -1
  113. package/src/calls/call-conversation-messages.ts +33 -0
  114. package/src/calls/call-domain.ts +114 -10
  115. package/src/calls/call-orchestrator.ts +268 -59
  116. package/src/calls/call-pointer-messages.ts +53 -0
  117. package/src/calls/call-recovery.ts +3 -8
  118. package/src/calls/call-store.ts +69 -87
  119. package/src/calls/elevenlabs-config.ts +3 -2
  120. package/src/calls/guardian-action-sweep.ts +105 -0
  121. package/src/calls/guardian-dispatch.ts +203 -0
  122. package/src/calls/guardian-question-copy.ts +133 -0
  123. package/src/calls/relay-server.ts +466 -8
  124. package/src/calls/speaker-identification.ts +1 -1
  125. package/src/calls/twilio-config.ts +22 -14
  126. package/src/calls/twilio-provider.ts +6 -4
  127. package/src/calls/twilio-rest.ts +308 -7
  128. package/src/calls/twilio-routes.ts +65 -12
  129. package/src/calls/types.ts +3 -1
  130. package/src/channels/types.ts +25 -0
  131. package/src/cli/amazon.ts +815 -0
  132. package/src/cli/config-commands.ts +2 -2
  133. package/src/cli/core-commands.ts +4 -3
  134. package/src/cli/influencer.ts +244 -0
  135. package/src/cli/map.ts +89 -6
  136. package/src/cli.ts +1 -1
  137. package/src/config/agent-schema.ts +171 -0
  138. package/src/config/bundled-skills/amazon/SKILL.md +127 -0
  139. package/src/config/bundled-skills/amazon/icon.svg +13 -0
  140. package/src/config/bundled-skills/api-mapping/SKILL.md +78 -0
  141. package/src/config/bundled-skills/browser/SKILL.md +1 -0
  142. package/src/config/bundled-skills/browser/TOOLS.json +17 -0
  143. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +25 -0
  144. package/src/config/bundled-skills/doordash/SKILL.md +51 -51
  145. package/src/config/bundled-skills/email-setup/SKILL.md +14 -5
  146. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +183 -0
  147. package/src/config/bundled-skills/influencer/SKILL.md +144 -0
  148. package/src/config/bundled-skills/knowledge-graph/SKILL.md +15 -0
  149. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +56 -0
  150. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +185 -0
  151. package/src/config/bundled-skills/macos-automation/icon.svg +12 -0
  152. package/src/config/bundled-skills/media-processing/SKILL.md +176 -0
  153. package/src/config/bundled-skills/media-processing/TOOLS.json +230 -0
  154. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +77 -0
  155. package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +69 -0
  156. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +303 -0
  157. package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +55 -0
  158. package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +86 -0
  159. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +339 -0
  160. package/src/config/bundled-skills/media-processing/services/preprocess.ts +551 -0
  161. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +259 -0
  162. package/src/config/bundled-skills/media-processing/services/reduce.ts +197 -0
  163. package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +136 -0
  164. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +59 -0
  165. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +195 -0
  166. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +197 -0
  167. package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +143 -0
  168. package/src/config/bundled-skills/media-processing/tools/media-status.ts +75 -0
  169. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +65 -0
  170. package/src/config/bundled-skills/messaging/SKILL.md +33 -8
  171. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -7
  172. package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +2 -1
  173. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +5 -1
  174. package/src/config/bundled-skills/phone-calls/SKILL.md +88 -23
  175. package/src/config/bundled-skills/twitter/SKILL.md +19 -3
  176. package/src/config/bundled-skills/twitter/icon.svg +14 -0
  177. package/src/config/bundled-tool-registry.ts +310 -0
  178. package/src/config/calls-schema.ts +181 -0
  179. package/src/config/core-schema.ts +309 -0
  180. package/src/config/defaults.ts +28 -3
  181. package/src/config/env-registry.ts +162 -0
  182. package/src/config/env.ts +175 -0
  183. package/src/config/loader.ts +6 -6
  184. package/src/config/memory-schema.ts +528 -0
  185. package/src/config/sandbox-schema.ts +55 -0
  186. package/src/config/schema.ts +158 -1133
  187. package/src/config/skill-state.ts +1 -1
  188. package/src/config/skills-schema.ts +32 -0
  189. package/src/config/skills.ts +35 -24
  190. package/src/config/system-prompt.ts +131 -56
  191. package/src/config/templates/IDENTITY.md +2 -2
  192. package/src/config/templates/SOUL.md +1 -1
  193. package/src/config/types.ts +1 -0
  194. package/src/config/user-reference.ts +4 -9
  195. package/src/config/vellum-skills/catalog.json +6 -7
  196. package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +5 -1
  197. package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +4 -3
  198. package/src/config/vellum-skills/sms-setup/SKILL.md +216 -0
  199. package/src/config/vellum-skills/twilio-setup/SKILL.md +40 -8
  200. package/src/context/window-manager.ts +27 -7
  201. package/src/daemon/approval-generators.ts +186 -0
  202. package/src/daemon/approved-devices-store.ts +140 -0
  203. package/src/daemon/assistant-attachments.ts +1 -1
  204. package/src/daemon/classifier.ts +35 -32
  205. package/src/daemon/config-watcher.ts +1 -1
  206. package/src/daemon/daemon-control.ts +217 -0
  207. package/src/daemon/handlers/apps.ts +2 -3
  208. package/src/daemon/handlers/config-channels.ts +158 -0
  209. package/src/daemon/handlers/config-inbox.ts +540 -0
  210. package/src/daemon/handlers/config-ingress.ts +231 -0
  211. package/src/daemon/handlers/config-integrations.ts +258 -0
  212. package/src/daemon/handlers/config-model.ts +143 -0
  213. package/src/daemon/handlers/config-parental.ts +163 -0
  214. package/src/daemon/handlers/config-scheduling.ts +172 -0
  215. package/src/daemon/handlers/config-slack.ts +92 -0
  216. package/src/daemon/handlers/config-telegram.ts +301 -0
  217. package/src/daemon/handlers/config-tools.ts +177 -0
  218. package/src/daemon/handlers/config-trust.ts +104 -0
  219. package/src/daemon/handlers/config-twilio.ts +1080 -0
  220. package/src/daemon/handlers/config.ts +53 -1689
  221. package/src/daemon/handlers/diagnostics.ts +1 -1
  222. package/src/daemon/handlers/dictation.ts +180 -0
  223. package/src/daemon/handlers/documents.ts +18 -32
  224. package/src/daemon/handlers/identity.ts +14 -23
  225. package/src/daemon/handlers/index.ts +11 -0
  226. package/src/daemon/handlers/misc.ts +3 -5
  227. package/src/daemon/handlers/pairing.ts +98 -0
  228. package/src/daemon/handlers/sessions.ts +56 -5
  229. package/src/daemon/handlers/shared.ts +6 -1
  230. package/src/daemon/handlers/skills.ts +1 -1
  231. package/src/daemon/handlers/twitter-auth.ts +2 -0
  232. package/src/daemon/handlers/work-items.ts +17 -9
  233. package/src/daemon/handlers/workspace-files.ts +4 -3
  234. package/src/daemon/install-cli-launchers.ts +113 -0
  235. package/src/daemon/ipc-contract/apps.ts +356 -0
  236. package/src/daemon/ipc-contract/browser.ts +74 -0
  237. package/src/daemon/ipc-contract/computer-use.ts +151 -0
  238. package/src/daemon/ipc-contract/diagnostics.ts +56 -0
  239. package/src/daemon/ipc-contract/documents.ts +74 -0
  240. package/src/daemon/ipc-contract/inbox.ts +209 -0
  241. package/src/daemon/ipc-contract/integrations.ts +284 -0
  242. package/src/daemon/ipc-contract/memory.ts +48 -0
  243. package/src/daemon/ipc-contract/messages.ts +211 -0
  244. package/src/daemon/ipc-contract/pairing.ts +45 -0
  245. package/src/daemon/ipc-contract/parental-control.ts +95 -0
  246. package/src/daemon/ipc-contract/schedules.ts +97 -0
  247. package/src/daemon/ipc-contract/sessions.ts +315 -0
  248. package/src/daemon/ipc-contract/shared.ts +42 -0
  249. package/src/daemon/ipc-contract/skills.ts +120 -0
  250. package/src/daemon/ipc-contract/subagents.ts +58 -0
  251. package/src/daemon/ipc-contract/surfaces.ts +250 -0
  252. package/src/daemon/ipc-contract/trust.ts +60 -0
  253. package/src/daemon/ipc-contract/work-items.ts +225 -0
  254. package/src/daemon/ipc-contract/workspace.ts +113 -0
  255. package/src/daemon/ipc-contract-inventory.json +70 -0
  256. package/src/daemon/ipc-contract-inventory.ts +55 -29
  257. package/src/daemon/ipc-contract.ts +229 -2426
  258. package/src/daemon/ipc-protocol.ts +1 -1
  259. package/src/daemon/ipc-validate.ts +7 -0
  260. package/src/daemon/lifecycle.ts +97 -377
  261. package/src/daemon/pairing-store.ts +177 -0
  262. package/src/daemon/providers-setup.ts +43 -0
  263. package/src/daemon/ride-shotgun-handler.ts +68 -3
  264. package/src/daemon/server.ts +66 -46
  265. package/src/daemon/session-agent-loop-handlers.ts +421 -0
  266. package/src/daemon/session-agent-loop.ts +117 -275
  267. package/src/daemon/session-dynamic-profile.ts +1 -1
  268. package/src/daemon/session-history.ts +1 -1
  269. package/src/daemon/session-media-retry.ts +1 -1
  270. package/src/daemon/session-messaging.ts +37 -2
  271. package/src/daemon/session-notifiers.ts +5 -25
  272. package/src/daemon/session-process.ts +99 -59
  273. package/src/daemon/session-queue-manager.ts +96 -4
  274. package/src/daemon/session-runtime-assembly.ts +199 -10
  275. package/src/daemon/session-surfaces.ts +19 -4
  276. package/src/daemon/session-tool-setup.ts +30 -30
  277. package/src/daemon/session-workspace.ts +1 -1
  278. package/src/daemon/session.ts +35 -2
  279. package/src/daemon/shutdown-handlers.ts +122 -0
  280. package/src/daemon/trace-emitter.ts +1 -1
  281. package/src/daemon/watch-handler.ts +36 -33
  282. package/src/doordash/cart-queries.ts +787 -0
  283. package/src/doordash/client.ts +144 -127
  284. package/src/doordash/order-queries.ts +85 -0
  285. package/src/doordash/queries.ts +10 -1308
  286. package/src/doordash/search-queries.ts +203 -0
  287. package/src/doordash/session.ts +3 -2
  288. package/src/doordash/store-queries.ts +246 -0
  289. package/src/doordash/types.ts +367 -0
  290. package/src/email/providers/agentmail.ts +2 -1
  291. package/src/email/providers/index.ts +3 -2
  292. package/src/email/service.ts +3 -2
  293. package/src/errors.ts +43 -0
  294. package/src/home-base/prebuilt/seed.ts +1 -1
  295. package/src/hooks/cli.ts +6 -5
  296. package/src/hooks/config.ts +6 -8
  297. package/src/hooks/discovery.ts +6 -5
  298. package/src/hooks/manager.ts +4 -3
  299. package/src/hooks/runner.ts +2 -2
  300. package/src/hooks/templates.ts +5 -5
  301. package/src/inbound/public-ingress-urls.ts +6 -4
  302. package/src/index.ts +4 -2
  303. package/src/influencer/client.ts +1104 -0
  304. package/src/instrument.ts +4 -3
  305. package/src/logfire.ts +4 -3
  306. package/src/memory/admin.ts +25 -35
  307. package/src/memory/attachments-store.ts +4 -7
  308. package/src/memory/channel-delivery-store.ts +30 -1
  309. package/src/memory/channel-guardian-store.ts +202 -2
  310. package/src/memory/clarification-resolver.ts +37 -33
  311. package/src/memory/conflict-store.ts +67 -61
  312. package/src/memory/contradiction-checker.ts +141 -117
  313. package/src/memory/conversation-store.ts +335 -51
  314. package/src/memory/db-connection.ts +27 -4
  315. package/src/memory/db-init.ts +265 -4
  316. package/src/memory/db.ts +14 -1
  317. package/src/memory/embedding-backend.ts +27 -5
  318. package/src/memory/embedding-ollama.ts +2 -1
  319. package/src/memory/entity-extractor.ts +38 -35
  320. package/src/memory/guardian-action-store.ts +430 -0
  321. package/src/memory/inbox-escalation-projection.ts +59 -0
  322. package/src/memory/inbox-thread-store.ts +218 -0
  323. package/src/memory/ingress-invite-store.ts +338 -0
  324. package/src/memory/ingress-member-store.ts +350 -0
  325. package/src/memory/items-extractor.ts +91 -97
  326. package/src/memory/job-handlers/index-maintenance.ts +3 -3
  327. package/src/memory/job-handlers/media-processing.ts +69 -0
  328. package/src/memory/job-handlers/summarization.ts +32 -26
  329. package/src/memory/job-utils.ts +3 -10
  330. package/src/memory/jobs-store.ts +8 -10
  331. package/src/memory/jobs-worker.ts +55 -36
  332. package/src/memory/media-store.ts +759 -0
  333. package/src/memory/migrations/001-job-deferrals.ts +45 -0
  334. package/src/memory/migrations/002-tool-invocations-fk.ts +43 -0
  335. package/src/memory/migrations/003-memory-fts-backfill.ts +24 -0
  336. package/src/memory/migrations/004-entity-relation-dedup.ts +87 -0
  337. package/src/memory/migrations/005-fingerprint-scope-unique.ts +80 -0
  338. package/src/memory/migrations/006-scope-salted-fingerprints.ts +62 -0
  339. package/src/memory/migrations/007-assistant-id-to-self.ts +254 -0
  340. package/src/memory/migrations/008-remove-assistant-id-columns.ts +208 -0
  341. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +83 -0
  342. package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +56 -0
  343. package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +63 -0
  344. package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +19 -0
  345. package/src/memory/migrations/013-guardian-action-tables.ts +68 -0
  346. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +76 -0
  347. package/src/memory/migrations/015-drop-active-search-index.ts +27 -0
  348. package/src/memory/migrations/016-memory-segments-indexes.ts +11 -0
  349. package/src/memory/migrations/017-memory-items-indexes.ts +10 -0
  350. package/src/memory/migrations/018-remaining-table-indexes.ts +13 -0
  351. package/src/memory/migrations/index.ts +24 -0
  352. package/src/memory/migrations/registry.ts +79 -0
  353. package/src/memory/migrations/validate-migration-state.ts +69 -0
  354. package/src/memory/qdrant-manager.ts +49 -8
  355. package/src/memory/query-builder.ts +1 -1
  356. package/src/memory/raw-query.ts +119 -0
  357. package/src/memory/recall-cache.ts +4 -1
  358. package/src/memory/retriever.ts +165 -47
  359. package/src/memory/schema-migration.ts +25 -984
  360. package/src/memory/schema.ts +228 -7
  361. package/src/memory/search/entity.ts +205 -31
  362. package/src/memory/search/lexical.ts +81 -52
  363. package/src/memory/search/ranking.ts +27 -23
  364. package/src/memory/search/semantic.ts +157 -19
  365. package/src/memory/search/types.ts +24 -0
  366. package/src/memory/shared-app-links-store.ts +4 -5
  367. package/src/memory/validation.ts +19 -0
  368. package/src/messaging/draft-store.ts +5 -6
  369. package/src/messaging/provider-types.ts +2 -0
  370. package/src/messaging/providers/sms/adapter.ts +201 -0
  371. package/src/messaging/providers/sms/client.ts +93 -0
  372. package/src/messaging/providers/sms/types.ts +7 -0
  373. package/src/messaging/providers/telegram-bot/adapter.ts +2 -5
  374. package/src/messaging/providers/whatsapp/adapter.ts +136 -0
  375. package/src/messaging/providers/whatsapp/client.ts +67 -0
  376. package/src/messaging/style-analyzer.ts +5 -4
  377. package/src/messaging/thread-summarizer.ts +61 -69
  378. package/src/messaging/triage-engine.ts +62 -71
  379. package/src/migrations/config-merge.ts +53 -0
  380. package/src/migrations/data-layout.ts +68 -0
  381. package/src/migrations/data-merge.ts +33 -0
  382. package/src/migrations/hooks-merge.ts +90 -0
  383. package/src/migrations/index.ts +6 -0
  384. package/src/migrations/log.ts +23 -0
  385. package/src/migrations/skills-merge.ts +33 -0
  386. package/src/migrations/workspace-layout.ts +79 -0
  387. package/src/permissions/checker.ts +133 -11
  388. package/src/permissions/prompter.ts +14 -0
  389. package/src/permissions/shell-identity.ts +31 -1
  390. package/src/permissions/trust-store.ts +21 -1
  391. package/src/providers/anthropic/client.ts +4 -4
  392. package/src/providers/failover.ts +2 -2
  393. package/src/providers/model-intents.ts +70 -0
  394. package/src/providers/ollama/client.ts +2 -1
  395. package/src/providers/provider-send-message.ts +176 -0
  396. package/src/providers/registry.ts +71 -30
  397. package/src/providers/retry.ts +35 -1
  398. package/src/providers/types.ts +12 -1
  399. package/src/runtime/approval-conversation-turn.ts +97 -0
  400. package/src/runtime/approval-message-composer.ts +253 -0
  401. package/src/runtime/channel-approval-parser.ts +36 -2
  402. package/src/runtime/channel-approvals.ts +11 -24
  403. package/src/runtime/channel-guardian-service.ts +88 -21
  404. package/src/runtime/channel-readiness-service.ts +418 -0
  405. package/src/runtime/channel-readiness-types.ts +35 -0
  406. package/src/runtime/channel-retry-sweep.ts +184 -0
  407. package/src/runtime/guardian-context-resolver.ts +108 -0
  408. package/src/runtime/http-server.ts +275 -717
  409. package/src/runtime/http-types.ts +59 -3
  410. package/src/runtime/middleware/auth.ts +116 -0
  411. package/src/runtime/middleware/error-handler.ts +33 -0
  412. package/src/runtime/middleware/twilio-validation.ts +127 -0
  413. package/src/runtime/routes/app-routes.ts +1 -1
  414. package/src/runtime/routes/call-routes.ts +51 -7
  415. package/src/runtime/routes/channel-delivery-routes.ts +170 -0
  416. package/src/runtime/routes/channel-guardian-routes.ts +1191 -0
  417. package/src/runtime/routes/channel-inbound-routes.ts +1152 -0
  418. package/src/runtime/routes/channel-route-shared.ts +144 -0
  419. package/src/runtime/routes/channel-routes.ts +32 -1588
  420. package/src/runtime/routes/conversation-routes.ts +50 -7
  421. package/src/runtime/routes/events-routes.ts +2 -2
  422. package/src/runtime/routes/identity-routes.ts +126 -0
  423. package/src/runtime/routes/pairing-routes.ts +143 -0
  424. package/src/runtime/routes/run-routes.ts +15 -1
  425. package/src/runtime/run-orchestrator.ts +86 -35
  426. package/src/schedule/schedule-store.ts +36 -32
  427. package/src/schedule/scheduler.ts +3 -3
  428. package/src/security/encrypted-store.ts +5 -7
  429. package/src/security/oauth2.ts +45 -15
  430. package/src/security/parental-control-store.ts +183 -0
  431. package/src/security/secret-allowlist.ts +4 -3
  432. package/src/security/secret-scanner.ts +5 -5
  433. package/src/security/secure-keys.ts +1 -1
  434. package/src/security/token-manager.ts +3 -2
  435. package/src/services/vercel-deploy.ts +6 -2
  436. package/src/skills/tool-manifest.ts +3 -3
  437. package/src/skills/vellum-catalog-remote.ts +75 -16
  438. package/src/slack/slack-webhook.ts +2 -1
  439. package/src/swarm/orchestrator.ts +92 -1
  440. package/src/swarm/router-planner.ts +6 -9
  441. package/src/swarm/worker-prompts.ts +9 -12
  442. package/src/tasks/task-compiler.ts +19 -28
  443. package/src/tasks/task-runner.ts +1 -1
  444. package/src/tools/assets/materialize.ts +2 -2
  445. package/src/tools/assets/search.ts +15 -14
  446. package/src/tools/browser/__tests__/auth-detector.test.ts +1 -0
  447. package/src/tools/browser/auto-navigate.ts +1 -0
  448. package/src/tools/browser/browser-execution.ts +10 -1
  449. package/src/tools/browser/browser-manager.ts +119 -4
  450. package/src/tools/browser/network-recorder.ts +5 -0
  451. package/src/tools/calls/call-start.ts +1 -0
  452. package/src/tools/credentials/broker.ts +11 -2
  453. package/src/tools/credentials/metadata-store.ts +18 -14
  454. package/src/tools/credentials/post-connect-hooks.ts +61 -0
  455. package/src/tools/credentials/vault.ts +49 -23
  456. package/src/tools/execution-target.ts +11 -1
  457. package/src/tools/executor.ts +68 -9
  458. package/src/tools/host-terminal/cli-discover.ts +1 -1
  459. package/src/tools/network/script-proxy/http-forwarder.ts +1 -1
  460. package/src/tools/network/script-proxy/mitm-handler.ts +1 -1
  461. package/src/tools/network/script-proxy/server.ts +1 -1
  462. package/src/tools/network/script-proxy/session-manager.ts +6 -5
  463. package/src/tools/network/web-fetch.ts +18 -2
  464. package/src/tools/network/web-search.ts +8 -4
  465. package/src/tools/reminder/reminder-store.ts +14 -15
  466. package/src/tools/schedule/create.ts +1 -0
  467. package/src/tools/schedule/list.ts +2 -1
  468. package/src/tools/shared/filesystem/file-ops-service.ts +5 -7
  469. package/src/tools/skills/skill-script-runner.ts +24 -9
  470. package/src/tools/skills/skill-tool-factory.ts +1 -0
  471. package/src/tools/tasks/work-item-enqueue.ts +2 -2
  472. package/src/tools/terminal/evaluate-typescript.ts +21 -12
  473. package/src/tools/terminal/parser.ts +50 -0
  474. package/src/tools/types.ts +2 -0
  475. package/src/tools/watcher/delete.ts +6 -0
  476. package/src/tools/weather/service.ts +1 -1
  477. package/src/twitter/client.ts +190 -24
  478. package/src/twitter/router.ts +1 -1
  479. package/src/twitter/session.ts +4 -3
  480. package/src/util/clipboard.ts +1 -1
  481. package/src/util/errors.ts +65 -8
  482. package/src/util/fs.ts +40 -0
  483. package/src/util/json.ts +10 -0
  484. package/src/util/log-redact.ts +189 -0
  485. package/src/util/logger.ts +19 -17
  486. package/src/util/object.ts +3 -0
  487. package/src/util/platform.ts +105 -363
  488. package/src/util/pricing.ts +1 -1
  489. package/src/util/promise-guard.ts +1 -1
  490. package/src/util/retry.ts +19 -0
  491. package/src/util/row-mapper.ts +79 -0
  492. package/src/util/silently.ts +21 -0
  493. package/src/watcher/engine.ts +5 -1
  494. package/src/watcher/provider-types.ts +20 -0
  495. package/src/watcher/providers/github.ts +156 -0
  496. package/src/watcher/providers/gmail.ts +1 -0
  497. package/src/watcher/providers/google-calendar.ts +1 -0
  498. package/src/watcher/providers/linear.ts +460 -0
  499. package/src/watcher/providers/slack.ts +1 -0
  500. package/src/work-items/work-item-runner.ts +1 -1
  501. package/src/workspace/git-service.ts +1 -1
  502. package/src/workspace/provider-commit-message-generator.ts +51 -22
  503. package/src/__tests__/call-bridge.test.ts +0 -517
  504. package/src/__tests__/session-process-bridge.test.ts +0 -244
  505. package/src/calls/call-bridge.ts +0 -168
  506. package/src/config/vellum-skills/google-oauth-setup/SKILL.md +0 -199
@@ -0,0 +1,208 @@
1
+ import { getSqliteFrom, type DrizzleDb } from '../db-connection.js';
2
+
3
+ /**
4
+ * One-shot migration: rebuild tables that previously stored assistant_id to remove
5
+ * that column now that all rows are keyed to the implicit single-tenant identity ("self").
6
+ *
7
+ * Must run AFTER migrateAssistantIdToSelf (which normalises all values to "self")
8
+ * so there are no constraint violations when recreating the tables without the
9
+ * assistant_id dimension.
10
+ *
11
+ * Each table section is guarded by a DDL check so this is safe on fresh installs
12
+ * where the column was never created in the first place.
13
+ *
14
+ * Tables rebuilt:
15
+ * - conversation_keys UNIQUE (conversation_key)
16
+ * - attachments no structural unique; content-dedup index updated
17
+ * - channel_inbound_events UNIQUE (source_channel, external_chat_id, external_message_id)
18
+ * - message_runs no unique constraint on assistant_id
19
+ * - llm_usage_events nullable column with no constraint
20
+ */
21
+ export function migrateRemoveAssistantIdColumns(database: DrizzleDb): void {
22
+ const raw = getSqliteFrom(database);
23
+ const checkpointKey = 'migration_remove_assistant_id_columns_v1';
24
+ const checkpoint = raw.query(
25
+ `SELECT 1 FROM memory_checkpoints WHERE key = ?`,
26
+ ).get(checkpointKey);
27
+ if (checkpoint) return;
28
+
29
+ raw.exec('PRAGMA foreign_keys = OFF');
30
+ try {
31
+ raw.exec('BEGIN');
32
+
33
+ // --- conversation_keys ---
34
+ const ckDdl = raw.query(
35
+ `SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'conversation_keys'`,
36
+ ).get() as { sql: string } | null;
37
+ if (ckDdl?.sql.includes('assistant_id')) {
38
+ raw.exec(/*sql*/ `
39
+ CREATE TABLE conversation_keys_new (
40
+ id TEXT PRIMARY KEY,
41
+ conversation_key TEXT NOT NULL UNIQUE,
42
+ conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
43
+ created_at INTEGER NOT NULL
44
+ )
45
+ `);
46
+ raw.exec(/*sql*/ `
47
+ INSERT INTO conversation_keys_new (id, conversation_key, conversation_id, created_at)
48
+ SELECT id, conversation_key, conversation_id, created_at FROM conversation_keys
49
+ `);
50
+ raw.exec(/*sql*/ `DROP TABLE conversation_keys`);
51
+ raw.exec(/*sql*/ `ALTER TABLE conversation_keys_new RENAME TO conversation_keys`);
52
+ }
53
+
54
+ // --- attachments ---
55
+ const attDdl = raw.query(
56
+ `SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'attachments'`,
57
+ ).get() as { sql: string } | null;
58
+ if (attDdl?.sql.includes('assistant_id')) {
59
+ raw.exec(/*sql*/ `
60
+ CREATE TABLE attachments_new (
61
+ id TEXT PRIMARY KEY,
62
+ original_filename TEXT NOT NULL,
63
+ mime_type TEXT NOT NULL,
64
+ size_bytes INTEGER NOT NULL,
65
+ kind TEXT NOT NULL,
66
+ data_base64 TEXT NOT NULL,
67
+ content_hash TEXT,
68
+ thumbnail_base64 TEXT,
69
+ created_at INTEGER NOT NULL
70
+ )
71
+ `);
72
+ raw.exec(/*sql*/ `
73
+ INSERT INTO attachments_new (id, original_filename, mime_type, size_bytes, kind, data_base64, content_hash, thumbnail_base64, created_at)
74
+ SELECT id, original_filename, mime_type, size_bytes, kind, data_base64, content_hash, thumbnail_base64, created_at FROM attachments
75
+ `);
76
+ raw.exec(/*sql*/ `DROP TABLE attachments`);
77
+ raw.exec(/*sql*/ `ALTER TABLE attachments_new RENAME TO attachments`);
78
+ }
79
+
80
+ // --- channel_inbound_events ---
81
+ const cieDdl = raw.query(
82
+ `SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'channel_inbound_events'`,
83
+ ).get() as { sql: string } | null;
84
+ if (cieDdl?.sql.includes('assistant_id')) {
85
+ raw.exec(/*sql*/ `
86
+ CREATE TABLE channel_inbound_events_new (
87
+ id TEXT PRIMARY KEY,
88
+ source_channel TEXT NOT NULL,
89
+ external_chat_id TEXT NOT NULL,
90
+ external_message_id TEXT NOT NULL,
91
+ source_message_id TEXT,
92
+ conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
93
+ message_id TEXT REFERENCES messages(id) ON DELETE CASCADE,
94
+ delivery_status TEXT NOT NULL DEFAULT 'pending',
95
+ processing_status TEXT NOT NULL DEFAULT 'pending',
96
+ processing_attempts INTEGER NOT NULL DEFAULT 0,
97
+ last_processing_error TEXT,
98
+ retry_after INTEGER,
99
+ raw_payload TEXT,
100
+ created_at INTEGER NOT NULL,
101
+ updated_at INTEGER NOT NULL,
102
+ UNIQUE (source_channel, external_chat_id, external_message_id)
103
+ )
104
+ `);
105
+ raw.exec(/*sql*/ `
106
+ INSERT INTO channel_inbound_events_new (
107
+ id, source_channel, external_chat_id, external_message_id, source_message_id,
108
+ conversation_id, message_id, delivery_status, processing_status,
109
+ processing_attempts, last_processing_error, retry_after, raw_payload,
110
+ created_at, updated_at
111
+ )
112
+ SELECT
113
+ id, source_channel, external_chat_id, external_message_id, source_message_id,
114
+ conversation_id, message_id, delivery_status, processing_status,
115
+ processing_attempts, last_processing_error, retry_after, raw_payload,
116
+ created_at, updated_at
117
+ FROM channel_inbound_events
118
+ `);
119
+ raw.exec(/*sql*/ `DROP TABLE channel_inbound_events`);
120
+ raw.exec(/*sql*/ `ALTER TABLE channel_inbound_events_new RENAME TO channel_inbound_events`);
121
+ }
122
+
123
+ // --- message_runs ---
124
+ const mrDdl = raw.query(
125
+ `SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'message_runs'`,
126
+ ).get() as { sql: string } | null;
127
+ if (mrDdl?.sql.includes('assistant_id')) {
128
+ raw.exec(/*sql*/ `
129
+ CREATE TABLE message_runs_new (
130
+ id TEXT PRIMARY KEY,
131
+ conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
132
+ message_id TEXT REFERENCES messages(id) ON DELETE CASCADE,
133
+ status TEXT NOT NULL DEFAULT 'running',
134
+ pending_confirmation TEXT,
135
+ input_tokens INTEGER NOT NULL DEFAULT 0,
136
+ output_tokens INTEGER NOT NULL DEFAULT 0,
137
+ estimated_cost REAL NOT NULL DEFAULT 0,
138
+ error TEXT,
139
+ created_at INTEGER NOT NULL,
140
+ updated_at INTEGER NOT NULL
141
+ )
142
+ `);
143
+ raw.exec(/*sql*/ `
144
+ INSERT INTO message_runs_new (
145
+ id, conversation_id, message_id, status, pending_confirmation,
146
+ input_tokens, output_tokens, estimated_cost, error, created_at, updated_at
147
+ )
148
+ SELECT
149
+ id, conversation_id, message_id, status, pending_confirmation,
150
+ input_tokens, output_tokens, estimated_cost, error, created_at, updated_at
151
+ FROM message_runs
152
+ `);
153
+ raw.exec(/*sql*/ `DROP TABLE message_runs`);
154
+ raw.exec(/*sql*/ `ALTER TABLE message_runs_new RENAME TO message_runs`);
155
+ }
156
+
157
+ // --- llm_usage_events ---
158
+ const lueDdl = raw.query(
159
+ `SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'llm_usage_events'`,
160
+ ).get() as { sql: string } | null;
161
+ if (lueDdl?.sql.includes('assistant_id')) {
162
+ raw.exec(/*sql*/ `
163
+ CREATE TABLE llm_usage_events_new (
164
+ id TEXT PRIMARY KEY,
165
+ created_at INTEGER NOT NULL,
166
+ conversation_id TEXT,
167
+ run_id TEXT,
168
+ request_id TEXT,
169
+ actor TEXT NOT NULL,
170
+ provider TEXT NOT NULL,
171
+ model TEXT NOT NULL,
172
+ input_tokens INTEGER NOT NULL,
173
+ output_tokens INTEGER NOT NULL,
174
+ cache_creation_input_tokens INTEGER,
175
+ cache_read_input_tokens INTEGER,
176
+ estimated_cost_usd REAL,
177
+ pricing_status TEXT NOT NULL,
178
+ metadata_json TEXT
179
+ )
180
+ `);
181
+ raw.exec(/*sql*/ `
182
+ INSERT INTO llm_usage_events_new (
183
+ id, created_at, conversation_id, run_id, request_id, actor, provider, model,
184
+ input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens,
185
+ estimated_cost_usd, pricing_status, metadata_json
186
+ )
187
+ SELECT
188
+ id, created_at, conversation_id, run_id, request_id, actor, provider, model,
189
+ input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens,
190
+ estimated_cost_usd, pricing_status, metadata_json
191
+ FROM llm_usage_events
192
+ `);
193
+ raw.exec(/*sql*/ `DROP TABLE llm_usage_events`);
194
+ raw.exec(/*sql*/ `ALTER TABLE llm_usage_events_new RENAME TO llm_usage_events`);
195
+ }
196
+
197
+ raw.query(
198
+ `INSERT OR IGNORE INTO memory_checkpoints (key, value, updated_at) VALUES (?, '1', ?)`,
199
+ ).run(checkpointKey, Date.now());
200
+
201
+ raw.exec('COMMIT');
202
+ } catch (e) {
203
+ try { raw.exec('ROLLBACK'); } catch { /* no active transaction */ }
204
+ throw e;
205
+ } finally {
206
+ raw.exec('PRAGMA foreign_keys = ON');
207
+ }
208
+ }
@@ -0,0 +1,83 @@
1
+ import { getSqliteFrom, type DrizzleDb } from '../db-connection.js';
2
+
3
+ /**
4
+ * One-shot migration: rebuild llm_usage_events to drop the assistant_id column.
5
+ *
6
+ * This is a SEPARATE migration from migrateRemoveAssistantIdColumns so that installs
7
+ * where the 4-table version of that migration already ran (checkpoint already set)
8
+ * still get the llm_usage_events column removed. Without a separate checkpoint key,
9
+ * those installs would skip the llm_usage_events rebuild entirely.
10
+ *
11
+ * Safe on fresh installs (DDL guard exits early) and idempotent via checkpoint.
12
+ */
13
+ export function migrateLlmUsageEventsDropAssistantId(database: DrizzleDb): void {
14
+ const raw = getSqliteFrom(database);
15
+ const checkpointKey = 'migration_remove_assistant_id_lue_v1';
16
+ const checkpoint = raw.query(
17
+ `SELECT 1 FROM memory_checkpoints WHERE key = ?`,
18
+ ).get(checkpointKey);
19
+ if (checkpoint) return;
20
+
21
+ // DDL guard: if the column was already removed (fresh install or migrateRemoveAssistantIdColumns
22
+ // ran with the llm_usage_events block), just record the checkpoint and exit.
23
+ const lueDdl = raw.query(
24
+ `SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'llm_usage_events'`,
25
+ ).get() as { sql: string } | null;
26
+
27
+ if (!lueDdl?.sql.includes('assistant_id')) {
28
+ raw.query(
29
+ `INSERT OR IGNORE INTO memory_checkpoints (key, value, updated_at) VALUES (?, '1', ?)`,
30
+ ).run(checkpointKey, Date.now());
31
+ return;
32
+ }
33
+
34
+ raw.exec('PRAGMA foreign_keys = OFF');
35
+ try {
36
+ raw.exec('BEGIN');
37
+
38
+ raw.exec(/*sql*/ `
39
+ CREATE TABLE llm_usage_events_new (
40
+ id TEXT PRIMARY KEY,
41
+ created_at INTEGER NOT NULL,
42
+ conversation_id TEXT,
43
+ run_id TEXT,
44
+ request_id TEXT,
45
+ actor TEXT NOT NULL,
46
+ provider TEXT NOT NULL,
47
+ model TEXT NOT NULL,
48
+ input_tokens INTEGER NOT NULL,
49
+ output_tokens INTEGER NOT NULL,
50
+ cache_creation_input_tokens INTEGER,
51
+ cache_read_input_tokens INTEGER,
52
+ estimated_cost_usd REAL,
53
+ pricing_status TEXT NOT NULL,
54
+ metadata_json TEXT
55
+ )
56
+ `);
57
+ raw.exec(/*sql*/ `
58
+ INSERT INTO llm_usage_events_new (
59
+ id, created_at, conversation_id, run_id, request_id, actor, provider, model,
60
+ input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens,
61
+ estimated_cost_usd, pricing_status, metadata_json
62
+ )
63
+ SELECT
64
+ id, created_at, conversation_id, run_id, request_id, actor, provider, model,
65
+ input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens,
66
+ estimated_cost_usd, pricing_status, metadata_json
67
+ FROM llm_usage_events
68
+ `);
69
+ raw.exec(/*sql*/ `DROP TABLE llm_usage_events`);
70
+ raw.exec(/*sql*/ `ALTER TABLE llm_usage_events_new RENAME TO llm_usage_events`);
71
+
72
+ raw.query(
73
+ `INSERT OR IGNORE INTO memory_checkpoints (key, value, updated_at) VALUES (?, '1', ?)`,
74
+ ).run(checkpointKey, Date.now());
75
+
76
+ raw.exec('COMMIT');
77
+ } catch (e) {
78
+ try { raw.exec('ROLLBACK'); } catch { /* no active transaction */ }
79
+ throw e;
80
+ } finally {
81
+ raw.exec('PRAGMA foreign_keys = ON');
82
+ }
83
+ }
@@ -0,0 +1,56 @@
1
+ import { getSqliteFrom, type DrizzleDb } from '../db-connection.js';
2
+
3
+ /**
4
+ * One-shot migration: deduplicate external_conversation_bindings rows that
5
+ * share the same (source_channel, external_chat_id), then create a unique
6
+ * index to enforce the invariant at DB level.
7
+ *
8
+ * For each duplicate group, the binding with the newest updatedAt (then
9
+ * createdAt) is kept; older duplicates are deleted.
10
+ */
11
+ export function migrateExtConvBindingsChannelChatUnique(database: DrizzleDb): void {
12
+ const raw = getSqliteFrom(database);
13
+
14
+ // If the unique index already exists, nothing to do.
15
+ const idxExists = raw.query(
16
+ `SELECT 1 FROM sqlite_master WHERE type = 'index' AND name = 'idx_ext_conv_bindings_channel_chat_unique'`,
17
+ ).get();
18
+ if (idxExists) return;
19
+
20
+ // Check if the table exists (first boot edge case).
21
+ const tableExists = raw.query(
22
+ `SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'external_conversation_bindings'`,
23
+ ).get();
24
+ if (!tableExists) return;
25
+
26
+ // Remove duplicates: keep the row with the newest updatedAt, then createdAt.
27
+ // Since conversation_id is the PK (rowid alias), we use it for ordering ties.
28
+ try {
29
+ raw.exec('BEGIN');
30
+
31
+ raw.exec(/*sql*/ `
32
+ DELETE FROM external_conversation_bindings
33
+ WHERE rowid NOT IN (
34
+ SELECT rowid FROM (
35
+ SELECT rowid,
36
+ ROW_NUMBER() OVER (
37
+ PARTITION BY source_channel, external_chat_id
38
+ ORDER BY updated_at DESC, created_at DESC, rowid DESC
39
+ ) AS rn
40
+ FROM external_conversation_bindings
41
+ )
42
+ WHERE rn = 1
43
+ )
44
+ `);
45
+
46
+ raw.exec(/*sql*/ `
47
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_ext_conv_bindings_channel_chat_unique
48
+ ON external_conversation_bindings(source_channel, external_chat_id)
49
+ `);
50
+
51
+ raw.exec('COMMIT');
52
+ } catch (e) {
53
+ try { raw.exec('ROLLBACK'); } catch { /* no active transaction */ }
54
+ throw e;
55
+ }
56
+ }
@@ -0,0 +1,63 @@
1
+ import { getSqliteFrom, type DrizzleDb } from '../db-connection.js';
2
+ import { getLogger } from '../../util/logger.js';
3
+
4
+ const log = getLogger('memory-db');
5
+
6
+ /**
7
+ * One-shot migration: remove duplicate (provider, provider_call_sid) rows from
8
+ * call_sessions so that the unique index can be created safely on upgraded databases
9
+ * that pre-date the constraint.
10
+ *
11
+ * For each set of duplicates, the most recently updated row is kept.
12
+ */
13
+ export function migrateCallSessionsProviderSidDedup(database: DrizzleDb): void {
14
+ const raw = getSqliteFrom(database);
15
+
16
+ // Quick check: if the unique index already exists, no dedup is needed.
17
+ const idxExists = raw.query(
18
+ `SELECT 1 FROM sqlite_master WHERE type = 'index' AND name = 'idx_call_sessions_provider_sid_unique'`,
19
+ ).get();
20
+ if (idxExists) return;
21
+
22
+ // Check if the table even exists yet (first boot).
23
+ const tableExists = raw.query(
24
+ `SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'call_sessions'`,
25
+ ).get();
26
+ if (!tableExists) return;
27
+
28
+ // Count duplicates before doing any work.
29
+ const dupCount = raw.query(/*sql*/ `
30
+ SELECT COUNT(*) AS c FROM (
31
+ SELECT provider, provider_call_sid
32
+ FROM call_sessions
33
+ WHERE provider_call_sid IS NOT NULL
34
+ GROUP BY provider, provider_call_sid
35
+ HAVING COUNT(*) > 1
36
+ )
37
+ `).get() as { c: number } | null;
38
+
39
+ if (!dupCount || dupCount.c === 0) return;
40
+
41
+ log.warn({ duplicateGroups: dupCount.c }, 'Deduplicating call_sessions with duplicate provider_call_sid before creating unique index');
42
+
43
+ try {
44
+ raw.exec('BEGIN');
45
+
46
+ // Keep the most recently updated row per (provider, provider_call_sid);
47
+ // delete the rest.
48
+ raw.exec(/*sql*/ `
49
+ DELETE FROM call_sessions
50
+ WHERE provider_call_sid IS NOT NULL
51
+ AND rowid NOT IN (
52
+ SELECT MAX(rowid) FROM call_sessions
53
+ WHERE provider_call_sid IS NOT NULL
54
+ GROUP BY provider, provider_call_sid
55
+ )
56
+ `);
57
+
58
+ raw.exec('COMMIT');
59
+ } catch (e) {
60
+ try { raw.exec('ROLLBACK'); } catch { /* no active transaction */ }
61
+ throw e;
62
+ }
63
+ }
@@ -0,0 +1,19 @@
1
+ import { getSqliteFrom, type DrizzleDb } from '../db-connection.js';
2
+
3
+ /**
4
+ * Add the `initiated_from_conversation_id` column to `call_sessions` so
5
+ * voice calls can track which conversation triggered them while pointing
6
+ * the session's `conversation_id` to a dedicated per-call voice conversation.
7
+ *
8
+ * Uses ALTER TABLE ... ADD COLUMN which is a no-op if the column already
9
+ * exists (caught via try/catch, matching the existing migration pattern in
10
+ * db-init.ts for similar additive columns).
11
+ */
12
+ export function migrateCallSessionsAddInitiatedFrom(database: DrizzleDb): void {
13
+ const raw = getSqliteFrom(database);
14
+ try {
15
+ raw.exec(/*sql*/ `ALTER TABLE call_sessions ADD COLUMN initiated_from_conversation_id TEXT`);
16
+ } catch {
17
+ // Column already exists — nothing to do.
18
+ }
19
+ }
@@ -0,0 +1,68 @@
1
+ import { getSqliteFrom, type DrizzleDb } from '../db-connection.js';
2
+
3
+ /**
4
+ * Create guardian_action_requests and guardian_action_deliveries tables
5
+ * for cross-channel voice guardian dispatch.
6
+ *
7
+ * Uses CREATE TABLE IF NOT EXISTS + CREATE INDEX IF NOT EXISTS for
8
+ * idempotency across restarts.
9
+ */
10
+ export function migrateGuardianActionTables(database: DrizzleDb): void {
11
+ const raw = getSqliteFrom(database);
12
+
13
+ try {
14
+ raw.exec('BEGIN');
15
+
16
+ raw.exec(/*sql*/ `
17
+ CREATE TABLE IF NOT EXISTS guardian_action_requests (
18
+ id TEXT PRIMARY KEY,
19
+ assistant_id TEXT NOT NULL DEFAULT 'self',
20
+ kind TEXT NOT NULL,
21
+ source_channel TEXT NOT NULL,
22
+ source_conversation_id TEXT NOT NULL,
23
+ call_session_id TEXT NOT NULL REFERENCES call_sessions(id) ON DELETE CASCADE,
24
+ pending_question_id TEXT NOT NULL REFERENCES call_pending_questions(id) ON DELETE CASCADE,
25
+ question_text TEXT NOT NULL,
26
+ request_code TEXT NOT NULL,
27
+ status TEXT NOT NULL DEFAULT 'pending',
28
+ answer_text TEXT,
29
+ answered_by_channel TEXT,
30
+ answered_by_external_user_id TEXT,
31
+ answered_at INTEGER,
32
+ expires_at INTEGER NOT NULL,
33
+ created_at INTEGER NOT NULL,
34
+ updated_at INTEGER NOT NULL
35
+ )
36
+ `);
37
+
38
+ raw.exec(/*sql*/ `
39
+ CREATE TABLE IF NOT EXISTS guardian_action_deliveries (
40
+ id TEXT PRIMARY KEY,
41
+ request_id TEXT NOT NULL REFERENCES guardian_action_requests(id) ON DELETE CASCADE,
42
+ destination_channel TEXT NOT NULL,
43
+ destination_conversation_id TEXT,
44
+ destination_chat_id TEXT,
45
+ destination_external_user_id TEXT,
46
+ status TEXT NOT NULL DEFAULT 'pending',
47
+ sent_at INTEGER,
48
+ responded_at INTEGER,
49
+ last_error TEXT,
50
+ created_at INTEGER NOT NULL,
51
+ updated_at INTEGER NOT NULL
52
+ )
53
+ `);
54
+
55
+ raw.exec(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_guardian_action_requests_status ON guardian_action_requests(status)`);
56
+ raw.exec(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_guardian_action_requests_call_session ON guardian_action_requests(call_session_id)`);
57
+ raw.exec(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_guardian_action_requests_pending_question ON guardian_action_requests(pending_question_id)`);
58
+ raw.exec(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_guardian_action_requests_request_code ON guardian_action_requests(request_code)`);
59
+ raw.exec(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_guardian_action_deliveries_request_id ON guardian_action_deliveries(request_id)`);
60
+ raw.exec(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_guardian_action_deliveries_status ON guardian_action_deliveries(status)`);
61
+ raw.exec(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_guardian_action_deliveries_destination ON guardian_action_deliveries(destination_channel, destination_chat_id)`);
62
+
63
+ raw.exec('COMMIT');
64
+ } catch (e) {
65
+ try { raw.exec('ROLLBACK'); } catch { /* no active transaction */ }
66
+ throw e;
67
+ }
68
+ }
@@ -0,0 +1,76 @@
1
+ import { getSqliteFrom, type DrizzleDb } from '../db-connection.js';
2
+
3
+ /**
4
+ * One-shot migration: seed assistant_inbox_thread_state from existing
5
+ * external_conversation_bindings so that pre-existing conversations
6
+ * appear in the inbox without waiting for new inbound activity.
7
+ *
8
+ * Uses INSERT OR IGNORE for idempotency (conversation_id is PK).
9
+ * Counters (unread_count, pending_escalation_count, has_pending_escalation)
10
+ * are initialised to zero since historical state is unknown.
11
+ */
12
+ export function migrateBackfillInboxThreadStateFromBindings(database: DrizzleDb): void {
13
+ const raw = getSqliteFrom(database);
14
+ const checkpointKey = 'backfill_inbox_thread_state_from_bindings';
15
+ const checkpoint = raw.query(
16
+ `SELECT 1 FROM memory_checkpoints WHERE key = ?`,
17
+ ).get(checkpointKey);
18
+ if (checkpoint) return;
19
+
20
+ // Guard: skip if either table does not exist yet (first boot edge case).
21
+ const srcExists = raw.query(
22
+ `SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'external_conversation_bindings'`,
23
+ ).get();
24
+ const dstExists = raw.query(
25
+ `SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'assistant_inbox_thread_state'`,
26
+ ).get();
27
+ if (!srcExists || !dstExists) {
28
+ raw.query(
29
+ `INSERT OR IGNORE INTO memory_checkpoints (key, value, updated_at) VALUES (?, '1', ?)`,
30
+ ).run(checkpointKey, Date.now());
31
+ return;
32
+ }
33
+
34
+ try {
35
+ raw.exec('BEGIN');
36
+
37
+ raw.exec(/*sql*/ `
38
+ INSERT OR IGNORE INTO assistant_inbox_thread_state (
39
+ conversation_id, assistant_id, source_channel, external_chat_id,
40
+ external_user_id, display_name, username,
41
+ last_inbound_at, last_outbound_at, last_message_at,
42
+ unread_count, pending_escalation_count, has_pending_escalation,
43
+ created_at, updated_at
44
+ )
45
+ SELECT
46
+ conversation_id,
47
+ 'self',
48
+ source_channel,
49
+ external_chat_id,
50
+ external_user_id,
51
+ display_name,
52
+ username,
53
+ last_inbound_at,
54
+ last_outbound_at,
55
+ CASE
56
+ WHEN last_inbound_at IS NULL AND last_outbound_at IS NULL THEN NULL
57
+ ELSE MAX(COALESCE(last_inbound_at, 0), COALESCE(last_outbound_at, 0))
58
+ END,
59
+ 0,
60
+ 0,
61
+ 0,
62
+ created_at,
63
+ updated_at
64
+ FROM external_conversation_bindings
65
+ `);
66
+
67
+ raw.query(
68
+ `INSERT OR IGNORE INTO memory_checkpoints (key, value, updated_at) VALUES (?, '1', ?)`,
69
+ ).run(checkpointKey, Date.now());
70
+
71
+ raw.exec('COMMIT');
72
+ } catch (e) {
73
+ try { raw.exec('ROLLBACK'); } catch { /* no active transaction */ }
74
+ throw e;
75
+ }
76
+ }
@@ -0,0 +1,27 @@
1
+ import { getSqliteFrom, type DrizzleDb } from '../db-connection.js';
2
+
3
+ /**
4
+ * One-time migration to drop the old idx_memory_items_active_search index so
5
+ * it can be recreated with updated covering columns by the idempotent
6
+ * CREATE INDEX IF NOT EXISTS in db-init.
7
+ */
8
+ export function migrateDropActiveSearchIndex(database: DrizzleDb): void {
9
+ const raw = getSqliteFrom(database);
10
+ const checkpointKey = 'drop_active_search_index_v1';
11
+ const checkpoint = raw.query(
12
+ `SELECT 1 FROM memory_checkpoints WHERE key = ?`,
13
+ ).get(checkpointKey);
14
+ if (checkpoint) return;
15
+
16
+ try {
17
+ raw.exec('BEGIN');
18
+ raw.exec(/*sql*/ `DROP INDEX IF EXISTS idx_memory_items_active_search`);
19
+ raw.query(
20
+ `INSERT OR IGNORE INTO memory_checkpoints (key, value, updated_at) VALUES (?, '1', ?)`,
21
+ ).run(checkpointKey, Date.now());
22
+ raw.exec('COMMIT');
23
+ } catch (e) {
24
+ try { raw.exec('ROLLBACK'); } catch { /* no active transaction */ }
25
+ throw e;
26
+ }
27
+ }
@@ -0,0 +1,11 @@
1
+ import type { DrizzleDb } from '../db-connection.js';
2
+
3
+ /**
4
+ * Idempotent migration to ensure memory_segments has indexes on scope_id and
5
+ * conversation_id for faster lookups. scope_id was already covered by
6
+ * db-init, but we include both here for completeness.
7
+ */
8
+ export function migrateMemorySegmentsIndexes(database: DrizzleDb): void {
9
+ database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_memory_segments_scope_id ON memory_segments(scope_id)`);
10
+ database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_memory_segments_conversation_id ON memory_segments(conversation_id)`);
11
+ }
@@ -0,0 +1,10 @@
1
+ import type { DrizzleDb } from '../db-connection.js';
2
+
3
+ /**
4
+ * Idempotent migration to add indexes on memory_items for scope_id and
5
+ * fingerprint — critical for duplicate detection and scope-filtered queries.
6
+ */
7
+ export function migrateMemoryItemsIndexes(database: DrizzleDb): void {
8
+ database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_memory_items_scope_id ON memory_items(scope_id)`);
9
+ database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_memory_items_fingerprint ON memory_items(fingerprint)`);
10
+ }
@@ -0,0 +1,13 @@
1
+ import type { DrizzleDb } from '../db-connection.js';
2
+
3
+ /**
4
+ * Idempotent migration to add indexes on foreign-key and scope columns that
5
+ * lacked them. messages.conversation_id is a FK used for ON DELETE CASCADE,
6
+ * so the index also speeds up cascading deletes.
7
+ */
8
+ export function migrateRemainingTableIndexes(database: DrizzleDb): void {
9
+ database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_memory_item_conflicts_scope_id ON memory_item_conflicts(scope_id)`);
10
+ database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_memory_summaries_scope_id ON memory_summaries(scope_id)`);
11
+ database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_messages_conversation_id ON messages(conversation_id)`);
12
+ database.run(/*sql*/ `CREATE INDEX IF NOT EXISTS idx_tool_invocations_conversation_id ON tool_invocations(conversation_id)`);
13
+ }
@@ -0,0 +1,24 @@
1
+ export {
2
+ type MigrationRegistryEntry,
3
+ MIGRATION_REGISTRY,
4
+ type MigrationValidationResult,
5
+ } from './registry.js';
6
+ export { validateMigrationState } from './validate-migration-state.js';
7
+ export { migrateJobDeferrals } from './001-job-deferrals.js';
8
+ export { migrateToolInvocationsFk } from './002-tool-invocations-fk.js';
9
+ export { migrateMemoryFtsBackfill } from './003-memory-fts-backfill.js';
10
+ export { migrateMemoryEntityRelationDedup } from './004-entity-relation-dedup.js';
11
+ export { migrateMemoryItemsFingerprintScopeUnique } from './005-fingerprint-scope-unique.js';
12
+ export { migrateMemoryItemsScopeSaltedFingerprints } from './006-scope-salted-fingerprints.js';
13
+ export { migrateAssistantIdToSelf } from './007-assistant-id-to-self.js';
14
+ export { migrateRemoveAssistantIdColumns } from './008-remove-assistant-id-columns.js';
15
+ export { migrateLlmUsageEventsDropAssistantId } from './009-llm-usage-events-drop-assistant-id.js';
16
+ export { migrateExtConvBindingsChannelChatUnique } from './010-ext-conv-bindings-channel-chat-unique.js';
17
+ export { migrateCallSessionsProviderSidDedup } from './011-call-sessions-provider-sid-dedup.js';
18
+ export { migrateCallSessionsAddInitiatedFrom } from './012-call-sessions-add-initiated-from.js';
19
+ export { migrateGuardianActionTables } from './013-guardian-action-tables.js';
20
+ export { migrateBackfillInboxThreadStateFromBindings } from './014-backfill-inbox-thread-state.js';
21
+ export { migrateDropActiveSearchIndex } from './015-drop-active-search-index.js';
22
+ export { migrateMemorySegmentsIndexes } from './016-memory-segments-indexes.js';
23
+ export { migrateMemoryItemsIndexes } from './017-memory-items-indexes.js';
24
+ export { migrateRemainingTableIndexes } from './018-remaining-table-indexes.js';