@vellumai/assistant 0.5.1 → 0.5.2

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 (338) hide show
  1. package/ARCHITECTURE.md +54 -54
  2. package/docs/architecture/integrations.md +62 -67
  3. package/docs/credential-execution-service.md +3 -3
  4. package/package.json +1 -1
  5. package/src/__tests__/agent-loop.test.ts +111 -0
  6. package/src/__tests__/always-loaded-tools-guard.test.ts +3 -4
  7. package/src/__tests__/app-builder-tool-scripts.test.ts +13 -151
  8. package/src/__tests__/app-dir-path-guard.test.ts +78 -0
  9. package/src/__tests__/app-executors.test.ts +1 -291
  10. package/src/__tests__/app-git-history.test.ts +4 -4
  11. package/src/__tests__/app-routes-csp.test.ts +1 -0
  12. package/src/__tests__/app-store-dir-names.test.ts +426 -0
  13. package/src/__tests__/attachments-store.test.ts +169 -21
  14. package/src/__tests__/attachments.test.ts +115 -1
  15. package/src/__tests__/btw-routes.test.ts +1 -0
  16. package/src/__tests__/canonical-guardian-store.test.ts +38 -0
  17. package/src/__tests__/channel-reply-delivery.test.ts +55 -0
  18. package/src/__tests__/checker.test.ts +54 -0
  19. package/src/__tests__/claude-code-skill-regression.test.ts +2 -0
  20. package/src/__tests__/claude-code-tool-profiles.test.ts +2 -0
  21. package/src/__tests__/compaction.benchmark.test.ts +2 -1
  22. package/src/__tests__/config-schema-cmd.test.ts +68 -21
  23. package/src/__tests__/config-schema.test.ts +1 -1
  24. package/src/__tests__/conversation-agent-loop-overflow.test.ts +149 -5
  25. package/src/__tests__/conversation-agent-loop.test.ts +290 -2
  26. package/src/__tests__/conversation-attachments.test.ts +17 -19
  27. package/src/__tests__/conversation-disk-view-integration.test.ts +277 -0
  28. package/src/__tests__/conversation-disk-view.test.ts +810 -0
  29. package/src/__tests__/conversation-error.test.ts +1 -1
  30. package/src/__tests__/conversation-fork-crud.test.ts +551 -0
  31. package/src/__tests__/conversation-fork-route.test.ts +386 -0
  32. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  33. package/src/__tests__/conversation-key-store-disk-view.test.ts +130 -0
  34. package/src/__tests__/conversation-media-retry.test.ts +8 -2
  35. package/src/__tests__/conversation-queue.test.ts +36 -1
  36. package/src/__tests__/conversation-routes-disk-view.test.ts +439 -0
  37. package/src/__tests__/conversation-routes-guardian-reply.test.ts +2 -2
  38. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -7
  39. package/src/__tests__/conversation-runtime-assembly.test.ts +17 -2
  40. package/src/__tests__/conversation-skill-tools.test.ts +4 -9
  41. package/src/__tests__/conversation-slash-commands.test.ts +149 -0
  42. package/src/__tests__/conversation-store.test.ts +24 -21
  43. package/src/__tests__/conversation-surfaces-state-update.test.ts +246 -0
  44. package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -0
  45. package/src/__tests__/conversation-title-service.test.ts +137 -0
  46. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +25 -315
  47. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +1 -0
  48. package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +1 -0
  49. package/src/__tests__/conversation-workspace-cache-state.test.ts +44 -2
  50. package/src/__tests__/conversation-workspace-injection.test.ts +11 -0
  51. package/src/__tests__/credential-security-invariants.test.ts +3 -0
  52. package/src/__tests__/credential-vault-unit.test.ts +5 -10
  53. package/src/__tests__/cu-unified-flow.test.ts +1 -0
  54. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +241 -0
  55. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +214 -0
  56. package/src/__tests__/diagnostics-export.test.ts +70 -1
  57. package/src/__tests__/first-greeting.test.ts +80 -0
  58. package/src/__tests__/gateway-only-guard.test.ts +1 -0
  59. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +3 -7
  60. package/src/__tests__/history-repair.test.ts +32 -10
  61. package/src/__tests__/http-conversation-lineage.test.ts +251 -0
  62. package/src/__tests__/image-source-path-reinject.test.ts +136 -0
  63. package/src/__tests__/llm-context-normalization.test.ts +1116 -0
  64. package/src/__tests__/llm-context-route-provider.test.ts +217 -0
  65. package/src/__tests__/llm-request-log-turn-query.test.ts +270 -0
  66. package/src/__tests__/media-generate-image.test.ts +47 -94
  67. package/src/__tests__/memory-lifecycle-e2e.test.ts +3 -1
  68. package/src/__tests__/memory-recall-quality.test.ts +5 -5
  69. package/src/__tests__/migration-cross-version-compatibility.test.ts +4 -1
  70. package/src/__tests__/migration-export-http.test.ts +3 -1
  71. package/src/__tests__/migration-import-commit-http.test.ts +18 -4
  72. package/src/__tests__/migration-import-preflight-http.test.ts +1 -3
  73. package/src/__tests__/mime-builder.test.ts +3 -2
  74. package/src/__tests__/non-member-access-request.test.ts +12 -1
  75. package/src/__tests__/notification-decision-identity.test.ts +52 -0
  76. package/src/__tests__/oauth-apps-routes.test.ts +103 -0
  77. package/src/__tests__/oauth-store.test.ts +115 -0
  78. package/src/__tests__/provider-error-scenarios.test.ts +1 -3
  79. package/src/__tests__/provider-failover-actual-provider.test.ts +66 -0
  80. package/src/__tests__/recording-handler.test.ts +17 -0
  81. package/src/__tests__/registry.test.ts +3 -8
  82. package/src/__tests__/relay-server.test.ts +1 -1
  83. package/src/__tests__/runtime-attachment-metadata.test.ts +7 -3
  84. package/src/__tests__/schema-transforms.test.ts +165 -5
  85. package/src/__tests__/server-history-render.test.ts +2 -2
  86. package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
  87. package/src/__tests__/slack-inbound-verification.test.ts +2 -2
  88. package/src/__tests__/starter-task-flow.test.ts +1 -0
  89. package/src/__tests__/suggestion-routes.test.ts +443 -0
  90. package/src/__tests__/swarm-conversation-integration.test.ts +1 -0
  91. package/src/__tests__/swarm-recursion.test.ts +1 -0
  92. package/src/__tests__/swarm-tool.test.ts +1 -0
  93. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -0
  94. package/src/__tests__/tool-preview-lifecycle.test.ts +32 -5
  95. package/src/__tests__/top-level-renderer.test.ts +22 -0
  96. package/src/__tests__/turn-boundary-resolution.test.ts +243 -0
  97. package/src/__tests__/web-fetch.test.ts +6 -2
  98. package/src/__tests__/workspace-migration-006-services-config.test.ts +335 -0
  99. package/src/__tests__/workspace-migration-007-web-search-provider-rename.test.ts +312 -0
  100. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +278 -0
  101. package/src/__tests__/workspace-migration-010-app-dir-rename.test.ts +275 -0
  102. package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +77 -0
  103. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +401 -0
  104. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +328 -0
  105. package/src/__tests__/workspace-migration-seed-device-id.test.ts +6 -10
  106. package/src/agent/attachments.ts +27 -1
  107. package/src/agent/loop.ts +29 -1
  108. package/src/avatar/traits-png-sync.ts +80 -25
  109. package/src/bundler/app-bundler.ts +4 -4
  110. package/src/calls/call-domain.ts +1 -0
  111. package/src/calls/voice-session-bridge.ts +1 -0
  112. package/src/cli/commands/auth.ts +92 -0
  113. package/src/cli/commands/avatar.ts +7 -6
  114. package/src/cli/commands/config.ts +2 -0
  115. package/src/cli/commands/oauth/providers.ts +29 -0
  116. package/src/cli/program.ts +12 -0
  117. package/src/cli.ts +15 -48
  118. package/src/config/bundled-skills/app-builder/SKILL.md +103 -28
  119. package/src/config/bundled-skills/app-builder/TOOLS.json +5 -199
  120. package/src/config/bundled-skills/app-builder/tools/{app-query.ts → app-refresh.ts} +2 -2
  121. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +2 -3
  122. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +6 -9
  123. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +4 -6
  124. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +2 -3
  125. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +2 -3
  126. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +2 -3
  127. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +2 -3
  128. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +4 -6
  129. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +2 -3
  130. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +2 -3
  131. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -3
  132. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +2 -3
  133. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -3
  134. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +2 -3
  135. package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
  136. package/src/config/bundled-skills/image-studio/SKILL.md +2 -2
  137. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -2
  138. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +45 -72
  139. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +2 -2
  140. package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
  141. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -3
  142. package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
  143. package/src/config/bundled-skills/slack/tools/shared.ts +19 -4
  144. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +2 -3
  145. package/src/config/bundled-skills/transcribe/SKILL.md +1 -1
  146. package/src/config/bundled-skills/transcribe/TOOLS.json +2 -6
  147. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +19 -83
  148. package/src/config/bundled-tool-registry.ts +2 -14
  149. package/src/config/feature-flag-registry.json +8 -0
  150. package/src/config/loader.ts +64 -0
  151. package/src/config/raw-config-utils.ts +30 -0
  152. package/src/config/schema-utils.ts +28 -7
  153. package/src/config/schema.ts +8 -0
  154. package/src/config/schemas/elevenlabs.ts +18 -0
  155. package/src/config/schemas/memory-lifecycle.ts +4 -2
  156. package/src/config/schemas/memory-storage.ts +1 -1
  157. package/src/config/schemas/services.ts +8 -6
  158. package/src/contacts/contact-store.ts +13 -6
  159. package/src/contacts/contacts-write.ts +0 -1
  160. package/src/context/window-manager.ts +13 -2
  161. package/src/daemon/conversation-agent-loop-handlers.ts +48 -7
  162. package/src/daemon/conversation-agent-loop.ts +56 -19
  163. package/src/daemon/conversation-attachments.ts +18 -36
  164. package/src/daemon/conversation-error.ts +2 -1
  165. package/src/daemon/conversation-history.ts +18 -4
  166. package/src/daemon/conversation-lifecycle.ts +39 -15
  167. package/src/daemon/conversation-messaging.ts +70 -26
  168. package/src/daemon/conversation-process.ts +58 -34
  169. package/src/daemon/conversation-runtime-assembly.ts +21 -38
  170. package/src/daemon/conversation-slash.ts +121 -256
  171. package/src/daemon/conversation-surfaces.ts +143 -20
  172. package/src/daemon/conversation-tool-setup.ts +0 -6
  173. package/src/daemon/conversation-workspace.ts +21 -1
  174. package/src/daemon/conversation.ts +51 -29
  175. package/src/daemon/first-greeting.ts +35 -0
  176. package/src/daemon/handlers/config-embeddings.ts +148 -0
  177. package/src/daemon/handlers/config-model.ts +71 -26
  178. package/src/daemon/handlers/conversations.ts +0 -23
  179. package/src/daemon/handlers/recording.ts +26 -21
  180. package/src/daemon/host-cu-proxy.ts +2 -2
  181. package/src/daemon/lifecycle.ts +106 -64
  182. package/src/daemon/message-protocol.ts +3 -0
  183. package/src/daemon/message-types/conversations.ts +19 -0
  184. package/src/daemon/message-types/messages.ts +1 -0
  185. package/src/daemon/message-types/shared.ts +2 -0
  186. package/src/daemon/message-types/surfaces.ts +2 -0
  187. package/src/daemon/message-types/upgrades.ts +23 -0
  188. package/src/daemon/server.ts +83 -12
  189. package/src/daemon/shutdown-handlers.ts +8 -5
  190. package/src/daemon/startup-error.ts +9 -0
  191. package/src/daemon/tool-side-effects.ts +11 -28
  192. package/src/events/tool-permission-telemetry-listener.ts +1 -3
  193. package/src/instrument.ts +0 -4
  194. package/src/media/app-icon-generator.ts +2 -2
  195. package/src/memory/app-git-service.ts +28 -16
  196. package/src/memory/app-store.ts +230 -41
  197. package/src/memory/attachments-store.ts +558 -130
  198. package/src/memory/conversation-attention-store.ts +70 -0
  199. package/src/memory/conversation-crud.ts +442 -3
  200. package/src/memory/conversation-directories.ts +125 -0
  201. package/src/memory/conversation-disk-view.ts +390 -0
  202. package/src/memory/conversation-key-store.ts +17 -5
  203. package/src/memory/conversation-queries.ts +5 -1
  204. package/src/memory/conversation-title-service.ts +21 -49
  205. package/src/memory/db-init.ts +28 -0
  206. package/src/memory/embedding-backend.ts +42 -53
  207. package/src/memory/embedding-gemini.test.ts +4 -4
  208. package/src/memory/embedding-local.ts +1 -3
  209. package/src/memory/embedding-ollama.ts +1 -3
  210. package/src/memory/embedding-openai.ts +1 -3
  211. package/src/memory/indexer.ts +9 -7
  212. package/src/memory/items-extractor.ts +42 -13
  213. package/src/memory/job-handlers/conversation-starters.ts +6 -1
  214. package/src/memory/job-handlers/embedding.test.ts +1 -4
  215. package/src/memory/llm-request-log-store.ts +100 -1
  216. package/src/memory/migrations/102-alter-table-columns.ts +5 -0
  217. package/src/memory/migrations/146-schedule-oneshot-routing.ts +3 -3
  218. package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +66 -70
  219. package/src/memory/migrations/148-drop-reminders-table.ts +5 -9
  220. package/src/memory/migrations/160-drop-loopback-port-column.ts +1 -3
  221. package/src/memory/migrations/174-rename-thread-starters-table.ts +0 -7
  222. package/src/memory/migrations/178-oauth-providers-managed-service-config-key.ts +15 -0
  223. package/src/memory/migrations/179-llm-request-log-message-id.ts +16 -0
  224. package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +66 -0
  225. package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +46 -0
  226. package/src/memory/migrations/182-oauth-providers-display-metadata.ts +20 -0
  227. package/src/memory/migrations/183-add-conversation-fork-lineage.ts +22 -0
  228. package/src/memory/migrations/184-llm-request-log-provider.ts +12 -0
  229. package/src/memory/migrations/index.ts +7 -0
  230. package/src/memory/migrations/registry.ts +13 -0
  231. package/src/memory/retriever.test.ts +601 -2
  232. package/src/memory/retriever.ts +85 -9
  233. package/src/memory/schema/conversations.ts +6 -0
  234. package/src/memory/schema/infrastructure.ts +13 -7
  235. package/src/memory/schema/oauth.ts +6 -0
  236. package/src/messaging/providers/gmail/mime-builder.ts +3 -1
  237. package/src/notifications/copy-composer.ts +26 -0
  238. package/src/notifications/decision-engine.ts +14 -1
  239. package/src/notifications/emit-signal.ts +1 -1
  240. package/src/notifications/signal.ts +36 -0
  241. package/src/oauth/byo-connection.test.ts +1 -45
  242. package/src/oauth/byo-connection.ts +2 -8
  243. package/src/oauth/connect-orchestrator.ts +15 -11
  244. package/src/oauth/connection-resolver.test.ts +191 -0
  245. package/src/oauth/connection-resolver.ts +66 -38
  246. package/src/oauth/connection.ts +0 -1
  247. package/src/oauth/oauth-store.ts +97 -47
  248. package/src/oauth/platform-connection.test.ts +0 -1
  249. package/src/oauth/platform-connection.ts +11 -3
  250. package/src/oauth/seed-providers.ts +78 -3
  251. package/src/oauth/token-persistence.ts +16 -10
  252. package/src/permissions/checker.ts +71 -8
  253. package/src/prompts/templates/BOOTSTRAP.md +2 -0
  254. package/src/providers/anthropic/client.ts +8 -1
  255. package/src/providers/failover.ts +4 -1
  256. package/src/providers/gemini/client.ts +50 -0
  257. package/src/providers/model-catalog.ts +92 -0
  258. package/src/providers/model-intents.ts +29 -20
  259. package/src/providers/openai/client.ts +49 -0
  260. package/src/providers/types.ts +2 -0
  261. package/src/runtime/access-request-helper.ts +16 -7
  262. package/src/runtime/auth/credential-service.ts +3 -1
  263. package/src/runtime/auth/route-policy.ts +14 -1
  264. package/src/runtime/btw-sidechain.ts +101 -0
  265. package/src/runtime/channel-reply-delivery.ts +17 -1
  266. package/src/runtime/http-router.ts +3 -1
  267. package/src/runtime/http-server.ts +196 -141
  268. package/src/runtime/http-types.ts +1 -0
  269. package/src/runtime/migrations/vbundle-builder.ts +5 -1
  270. package/src/runtime/routes/access-request-decision.ts +41 -0
  271. package/src/runtime/routes/app-management-routes.ts +6 -3
  272. package/src/runtime/routes/app-routes.ts +7 -3
  273. package/src/runtime/routes/approval-routes.ts +1 -0
  274. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +34 -2
  275. package/src/runtime/routes/attachment-routes.ts +45 -15
  276. package/src/runtime/routes/btw-routes.ts +21 -61
  277. package/src/runtime/routes/conversation-management-routes.ts +68 -0
  278. package/src/runtime/routes/conversation-query-routes.ts +180 -10
  279. package/src/runtime/routes/conversation-routes.ts +222 -28
  280. package/src/runtime/routes/conversation-starter-routes.ts +9 -11
  281. package/src/runtime/routes/diagnostics-routes.ts +1 -0
  282. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -2
  283. package/src/runtime/routes/llm-context-normalization.ts +1199 -0
  284. package/src/runtime/routes/log-export-routes.ts +3 -0
  285. package/src/runtime/routes/memory-item-routes.test.ts +34 -0
  286. package/src/runtime/routes/memory-item-routes.ts +4 -0
  287. package/src/runtime/routes/migration-routes.ts +4 -1
  288. package/src/runtime/routes/oauth-apps.ts +291 -0
  289. package/src/runtime/routes/secret-routes.ts +28 -1
  290. package/src/runtime/routes/settings-routes.ts +14 -0
  291. package/src/runtime/routes/trace-event-routes.ts +4 -1
  292. package/src/schedule/schedule-store.ts +9 -21
  293. package/src/security/secure-keys.ts +21 -0
  294. package/src/signals/bash.ts +1 -1
  295. package/src/swarm/backend-claude-code.ts +3 -6
  296. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
  297. package/src/telemetry/usage-telemetry-reporter.ts +3 -1
  298. package/src/tools/AGENTS.md +6 -10
  299. package/src/tools/apps/executors.ts +17 -232
  300. package/src/tools/claude-code/claude-code.ts +2 -3
  301. package/src/tools/credentials/vault.ts +7 -12
  302. package/src/tools/host-filesystem/read.ts +13 -10
  303. package/src/tools/network/__tests__/web-search.test.ts +4 -2
  304. package/src/tools/schedule/list.ts +2 -7
  305. package/src/tools/schema-transforms.ts +5 -0
  306. package/src/tools/shared/filesystem/format-diff.ts +2 -7
  307. package/src/tools/skills/execute.ts +1 -1
  308. package/src/tools/tool-manifest.ts +0 -6
  309. package/src/tools/ui-surface/definitions.ts +2 -2
  310. package/src/util/device-id.ts +28 -5
  311. package/src/util/platform.ts +6 -0
  312. package/src/util/pricing.ts +1 -0
  313. package/src/util/retry.ts +1 -3
  314. package/src/workspace/migrations/002-backfill-installation-id.ts +23 -12
  315. package/src/workspace/migrations/003-seed-device-id.ts +3 -4
  316. package/src/workspace/migrations/006-services-config.ts +5 -0
  317. package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +12 -0
  318. package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +10 -0
  319. package/src/workspace/migrations/010-app-dir-rename.ts +223 -0
  320. package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +64 -0
  321. package/src/workspace/migrations/013-repair-conversation-disk-view.ts +11 -0
  322. package/src/workspace/migrations/rebuild-conversation-disk-view.ts +186 -0
  323. package/src/workspace/migrations/registry.ts +10 -0
  324. package/src/workspace/top-level-renderer.ts +12 -0
  325. package/src/__tests__/asset-materialize-tool.test.ts +0 -523
  326. package/src/__tests__/asset-search-tool.test.ts +0 -536
  327. package/src/__tests__/fixtures/media-reuse-fixtures.ts +0 -56
  328. package/src/__tests__/media-reuse-story.e2e.test.ts +0 -762
  329. package/src/__tests__/media-visibility-policy.test.ts +0 -190
  330. package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +0 -14
  331. package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +0 -13
  332. package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +0 -21
  333. package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +0 -14
  334. package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -13
  335. package/src/config/bundled-skills/app-builder/tools/app-update.ts +0 -23
  336. package/src/daemon/media-visibility-policy.ts +0 -59
  337. package/src/tools/assets/materialize.ts +0 -248
  338. package/src/tools/assets/search.ts +0 -400
@@ -30,40 +30,37 @@ import { withCrashRecovery } from "./validate-migration-state.js";
30
30
  * preserved for the subsequent cleanup PR.
31
31
  */
32
32
  export function migrateRemindersToSchedules(database: DrizzleDb): void {
33
- withCrashRecovery(
34
- database,
35
- "migration_reminders_to_schedules_v1",
36
- () => {
37
- const raw = getSqliteFrom(database);
33
+ withCrashRecovery(database, "migration_reminders_to_schedules_v1", () => {
34
+ const raw = getSqliteFrom(database);
38
35
 
39
- // Guard: if the reminders table doesn't exist, nothing to migrate.
40
- const hasReminders = raw
41
- .query(
42
- "SELECT name FROM sqlite_master WHERE type='table' AND name='reminders'",
43
- )
44
- .get();
45
- if (!hasReminders) return;
36
+ // Guard: if the reminders table doesn't exist, nothing to migrate.
37
+ const hasReminders = raw
38
+ .query(
39
+ "SELECT name FROM sqlite_master WHERE type='table' AND name='reminders'",
40
+ )
41
+ .get();
42
+ if (!hasReminders) return;
46
43
 
47
- // Read all reminders into memory. We use the reminder's original ID as
48
- // the cron_jobs primary key so that INSERT OR IGNORE deduplicates
49
- // correctly if the migration re-runs after a crash.
50
- const reminders = raw.query("SELECT * FROM reminders").all() as Array<{
51
- id: string;
52
- label: string;
53
- message: string;
54
- fire_at: number;
55
- mode: string;
56
- status: string;
57
- fired_at: number | null;
58
- routing_intent: string;
59
- routing_hints_json: string;
60
- created_at: number;
61
- updated_at: number;
62
- }>;
44
+ // Read all reminders into memory. We use the reminder's original ID as
45
+ // the cron_jobs primary key so that INSERT OR IGNORE deduplicates
46
+ // correctly if the migration re-runs after a crash.
47
+ const reminders = raw.query("SELECT * FROM reminders").all() as Array<{
48
+ id: string;
49
+ label: string;
50
+ message: string;
51
+ fire_at: number;
52
+ mode: string;
53
+ status: string;
54
+ fired_at: number | null;
55
+ routing_intent: string;
56
+ routing_hints_json: string;
57
+ created_at: number;
58
+ updated_at: number;
59
+ }>;
63
60
 
64
- if (reminders.length === 0) return;
61
+ if (reminders.length === 0) return;
65
62
 
66
- const insert = raw.query(/*sql*/ `
63
+ const insert = raw.query(/*sql*/ `
67
64
  INSERT OR IGNORE INTO cron_jobs (
68
65
  id, name, enabled, cron_expression, schedule_syntax, timezone,
69
66
  message, next_run_at, last_run_at, last_status, retry_count,
@@ -77,53 +74,52 @@ export function migrateRemindersToSchedules(database: DrizzleDb): void {
77
74
  )
78
75
  `);
79
76
 
80
- // Mark migrated pending reminders as fired so the legacy
81
- // claimDueReminders path doesn't fire them a second time.
82
- const markFired = raw.query(/*sql*/ `
77
+ // Mark migrated pending reminders as fired so the legacy
78
+ // claimDueReminders path doesn't fire them a second time.
79
+ const markFired = raw.query(/*sql*/ `
83
80
  UPDATE reminders SET status = 'fired', fired_at = ?
84
81
  WHERE id = ? AND status = 'pending'
85
82
  `);
86
83
 
87
- try {
88
- raw.exec("BEGIN");
84
+ try {
85
+ raw.exec("BEGIN");
89
86
 
90
- for (const r of reminders) {
91
- const statusMap: Record<string, string> = {
92
- pending: "active",
93
- firing: "firing",
94
- fired: "fired",
95
- cancelled: "cancelled",
96
- };
87
+ for (const r of reminders) {
88
+ const statusMap: Record<string, string> = {
89
+ pending: "active",
90
+ firing: "firing",
91
+ fired: "fired",
92
+ cancelled: "cancelled",
93
+ };
97
94
 
98
- insert.run(
99
- r.id,
100
- r.label,
101
- r.status === "pending" ? 1 : 0,
102
- // message, next_run_at, last_run_at, last_status
103
- r.message,
104
- r.fire_at,
105
- r.fired_at,
106
- r.status === "fired" ? "ok" : null,
107
- // mode, routing_intent, routing_hints_json, status
108
- r.mode,
109
- r.routing_intent,
110
- r.routing_hints_json,
111
- statusMap[r.status] ?? "active",
112
- // created_at, updated_at
113
- r.created_at,
114
- r.updated_at,
115
- );
95
+ insert.run(
96
+ r.id,
97
+ r.label,
98
+ r.status === "pending" ? 1 : 0,
99
+ // message, next_run_at, last_run_at, last_status
100
+ r.message,
101
+ r.fire_at,
102
+ r.fired_at,
103
+ r.status === "fired" ? "ok" : null,
104
+ // mode, routing_intent, routing_hints_json, status
105
+ r.mode,
106
+ r.routing_intent,
107
+ r.routing_hints_json,
108
+ statusMap[r.status] ?? "active",
109
+ // created_at, updated_at
110
+ r.created_at,
111
+ r.updated_at,
112
+ );
116
113
 
117
- if (r.status === "pending") {
118
- markFired.run(Date.now(), r.id);
119
- }
114
+ if (r.status === "pending") {
115
+ markFired.run(Date.now(), r.id);
120
116
  }
121
-
122
- raw.exec("COMMIT");
123
- } catch (err) {
124
- raw.exec("ROLLBACK");
125
- throw err;
126
117
  }
127
- },
128
- );
118
+
119
+ raw.exec("COMMIT");
120
+ } catch (err) {
121
+ raw.exec("ROLLBACK");
122
+ throw err;
123
+ }
124
+ });
129
125
  }
@@ -6,13 +6,9 @@ import { withCrashRecovery } from "./validate-migration-state.js";
6
6
  * migrated into cron_jobs as one-shot schedules (migration 147).
7
7
  */
8
8
  export function migrateDropRemindersTable(database: DrizzleDb): void {
9
- withCrashRecovery(
10
- database,
11
- "migration_drop_reminders_table_v1",
12
- () => {
13
- const raw = getSqliteFrom(database);
14
- raw.run("DROP INDEX IF EXISTS idx_reminders_status_fire_at");
15
- raw.run("DROP TABLE IF EXISTS reminders");
16
- },
17
- );
9
+ withCrashRecovery(database, "migration_drop_reminders_table_v1", () => {
10
+ const raw = getSqliteFrom(database);
11
+ raw.run("DROP INDEX IF EXISTS idx_reminders_status_fire_at");
12
+ raw.run("DROP TABLE IF EXISTS reminders");
13
+ });
18
14
  }
@@ -4,9 +4,7 @@ import { getSqliteFrom } from "../db-connection.js";
4
4
  export function migrateDropLoopbackPortColumn(database: DrizzleDb): void {
5
5
  const raw = getSqliteFrom(database);
6
6
  try {
7
- raw.exec(
8
- /*sql*/ `ALTER TABLE oauth_providers DROP COLUMN loopback_port`,
9
- );
7
+ raw.exec(/*sql*/ `ALTER TABLE oauth_providers DROP COLUMN loopback_port`);
10
8
  } catch {
11
9
  // Column already dropped or doesn't exist — nothing to do.
12
10
  }
@@ -40,13 +40,6 @@ export function migrateRenameThreadStartersTable(database: DrizzleDb): void {
40
40
  raw.exec(
41
41
  /*sql*/ `CREATE INDEX IF NOT EXISTS idx_conversation_starters_card_type ON conversation_starters(card_type, scope_id)`,
42
42
  );
43
-
44
- // Migrate checkpoint keys from old thread_starters: prefix to
45
- // conversation_starters: so existing checkpoint data is found by
46
- // the renamed code paths and unnecessary re-generation is avoided.
47
- raw.exec(
48
- /*sql*/ `UPDATE memory_checkpoints SET key = replace(key, 'thread_starters:', 'conversation_starters:') WHERE key LIKE 'thread_starters:%'`,
49
- );
50
43
  },
51
44
  );
52
45
  }
@@ -0,0 +1,15 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { getSqliteFrom } from "../db-connection.js";
3
+
4
+ export function migrateOAuthProvidersManagedServiceConfigKey(
5
+ database: DrizzleDb,
6
+ ): void {
7
+ const raw = getSqliteFrom(database);
8
+ try {
9
+ raw.exec(
10
+ /*sql*/ `ALTER TABLE oauth_providers ADD COLUMN managed_service_config_key TEXT`,
11
+ );
12
+ } catch {
13
+ // Column already exists — nothing to do.
14
+ }
15
+ }
@@ -0,0 +1,16 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { getSqliteFrom } from "../db-connection.js";
3
+
4
+ export function migrateLlmRequestLogMessageId(database: DrizzleDb): void {
5
+ const raw = getSqliteFrom(database);
6
+ try {
7
+ raw.exec(/*sql*/ `ALTER TABLE llm_request_logs ADD COLUMN message_id TEXT`);
8
+ } catch {
9
+ // Column already exists — nothing to do.
10
+ }
11
+
12
+ raw.exec(/*sql*/ `
13
+ CREATE INDEX IF NOT EXISTS idx_llm_request_logs_message_id
14
+ ON llm_request_logs(message_id)
15
+ `);
16
+ }
@@ -0,0 +1,66 @@
1
+ import { writeAttachmentToDisk } from "../attachments-store.js";
2
+ import type { DrizzleDb } from "../db-connection.js";
3
+ import { getSqliteFrom } from "../db-connection.js";
4
+ import { withCrashRecovery } from "./validate-migration-state.js";
5
+
6
+ /**
7
+ * Backfill existing inline (base64-in-DB) attachments to disk.
8
+ *
9
+ * Finds attachment rows that have non-empty data_base64 but no file_path,
10
+ * writes each one to disk, and updates the row to store the file path
11
+ * while clearing the inline data.
12
+ *
13
+ * Processes in batches of 50 to avoid holding large amounts of base64 data
14
+ * in memory at once.
15
+ */
16
+ export function migrateBackfillInlineAttachmentsToDisk(
17
+ database: DrizzleDb,
18
+ ): void {
19
+ withCrashRecovery(
20
+ database,
21
+ "migration_backfill_inline_attachments_v1",
22
+ () => {
23
+ const raw = getSqliteFrom(database);
24
+ const BATCH_SIZE = 50;
25
+ let totalMigrated = 0;
26
+
27
+ for (;;) {
28
+ const rows = raw
29
+ .query(
30
+ `SELECT id, original_filename, data_base64 FROM attachments
31
+ WHERE (file_path IS NULL OR file_path = '')
32
+ AND data_base64 != ''
33
+ AND length(data_base64) > 0
34
+ LIMIT ?`,
35
+ )
36
+ .all(BATCH_SIZE) as Array<{
37
+ id: string;
38
+ original_filename: string;
39
+ data_base64: string;
40
+ }>;
41
+
42
+ if (rows.length === 0) break;
43
+
44
+ for (const row of rows) {
45
+ const filePath = writeAttachmentToDisk(
46
+ row.data_base64,
47
+ row.original_filename,
48
+ );
49
+ raw
50
+ .query(
51
+ `UPDATE attachments SET file_path = ?, data_base64 = '' WHERE id = ?`,
52
+ )
53
+ .run(filePath, row.id);
54
+ }
55
+
56
+ totalMigrated += rows.length;
57
+ }
58
+
59
+ if (totalMigrated > 0) {
60
+ // Log is intentionally not imported to keep migration self-contained;
61
+ // the checkpoint value records completion.
62
+ console.log(`Migrated ${totalMigrated} inline attachments to disk`);
63
+ }
64
+ },
65
+ );
66
+ }
@@ -0,0 +1,46 @@
1
+ import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
2
+ import { withCrashRecovery } from "./validate-migration-state.js";
3
+
4
+ /**
5
+ * Rename checkpoint keys from the old `thread_starters:` prefix to
6
+ * `conversation_starters:` so that the renamed code paths in
7
+ * `conversation-starters-cadence.ts` and `conversation-starters.ts`
8
+ * find existing generation state and avoid unnecessary re-generation.
9
+ *
10
+ * This was originally appended to migration 174, but that migration
11
+ * had already shipped with its own checkpoint key
12
+ * (`migration_rename_thread_starters_table_v1`), so `withCrashRecovery`
13
+ * would skip the entire body for users who had already run it. Moving
14
+ * the checkpoint-key rewrite into its own migration with an independent
15
+ * checkpoint key ensures it runs for all users.
16
+ *
17
+ * The rename is collision-safe: if a database already has both old
18
+ * `thread_starters:*` keys and new `conversation_starters:*` keys
19
+ * (written by updated code after the table rename), we drop the stale
20
+ * old rows first to avoid UNIQUE constraint violations on the primary key.
21
+ */
22
+ export function migrateRenameThreadStartersCheckpoints(
23
+ database: DrizzleDb,
24
+ ): void {
25
+ withCrashRecovery(
26
+ database,
27
+ "migration_rename_thread_starters_checkpoints_v1",
28
+ () => {
29
+ const raw = getSqliteFrom(database);
30
+
31
+ // 1. Delete old thread_starters: keys where a corresponding
32
+ // conversation_starters: key already exists (the newer key
33
+ // written by updated code takes precedence).
34
+ raw.exec(/*sql*/ `DELETE FROM memory_checkpoints
35
+ WHERE key LIKE 'thread_starters:%'
36
+ AND replace(key, 'thread_starters:', 'conversation_starters:') IN (
37
+ SELECT key FROM memory_checkpoints WHERE key LIKE 'conversation_starters:%'
38
+ )`);
39
+
40
+ // 2. Rename remaining old keys that have no collision.
41
+ raw.exec(
42
+ /*sql*/ `UPDATE memory_checkpoints SET key = replace(key, 'thread_starters:', 'conversation_starters:') WHERE key LIKE 'thread_starters:%'`,
43
+ );
44
+ },
45
+ );
46
+ }
@@ -0,0 +1,20 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { getSqliteFrom } from "../db-connection.js";
3
+
4
+ export function migrateOAuthProvidersDisplayMetadata(database: DrizzleDb): void {
5
+ const raw = getSqliteFrom(database);
6
+ const columns = [
7
+ "display_name TEXT",
8
+ "description TEXT",
9
+ "dashboard_url TEXT",
10
+ "client_id_placeholder TEXT",
11
+ "requires_client_secret INTEGER NOT NULL DEFAULT 1",
12
+ ];
13
+ for (const col of columns) {
14
+ try {
15
+ raw.exec(`ALTER TABLE oauth_providers ADD COLUMN ${col}`);
16
+ } catch {
17
+ // Column already exists — nothing to do.
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,22 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { getSqliteFrom } from "../db-connection.js";
3
+
4
+ export function migrateConversationForkLineage(database: DrizzleDb): void {
5
+ const raw = getSqliteFrom(database);
6
+ const columns = [
7
+ "fork_parent_conversation_id TEXT",
8
+ "fork_parent_message_id TEXT",
9
+ ];
10
+
11
+ for (const column of columns) {
12
+ try {
13
+ raw.exec(`ALTER TABLE conversations ADD COLUMN ${column}`);
14
+ } catch {
15
+ // Column already exists — nothing to do.
16
+ }
17
+ }
18
+
19
+ raw.exec(
20
+ /*sql*/ `CREATE INDEX IF NOT EXISTS idx_conversations_fork_parent_conversation_id ON conversations(fork_parent_conversation_id)`,
21
+ );
22
+ }
@@ -0,0 +1,12 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { getSqliteFrom } from "../db-connection.js";
3
+
4
+ export function migrateLlmRequestLogProvider(database: DrizzleDb): void {
5
+ const raw = getSqliteFrom(database);
6
+
7
+ try {
8
+ raw.exec(/*sql*/ `ALTER TABLE llm_request_logs ADD COLUMN provider TEXT`);
9
+ } catch {
10
+ // Column already exists — nothing to do.
11
+ }
12
+ }
@@ -119,6 +119,13 @@ export { migrateRenameThreadStartersTable } from "./174-rename-thread-starters-t
119
119
  export { createLifecycleEventsTable } from "./175-create-lifecycle-events.js";
120
120
  export { migrateDropCapabilityCardState } from "./176-drop-capability-card-state.js";
121
121
  export { migrateCreateTraceEventsTable } from "./177-create-trace-events-table.js";
122
+ export { migrateOAuthProvidersManagedServiceConfigKey } from "./178-oauth-providers-managed-service-config-key.js";
123
+ export { migrateLlmRequestLogMessageId } from "./179-llm-request-log-message-id.js";
124
+ export { migrateBackfillInlineAttachmentsToDisk } from "./180-backfill-inline-attachments-to-disk.js";
125
+ export { migrateRenameThreadStartersCheckpoints } from "./181-rename-thread-starters-checkpoints.js";
126
+ export { migrateOAuthProvidersDisplayMetadata } from "./182-oauth-providers-display-metadata.js";
127
+ export { migrateConversationForkLineage } from "./183-add-conversation-fork-lineage.js";
128
+ export { migrateLlmRequestLogProvider } from "./184-llm-request-log-provider.js";
122
129
  export {
123
130
  MIGRATION_REGISTRY,
124
131
  type MigrationRegistryEntry,
@@ -228,6 +228,19 @@ export const MIGRATION_REGISTRY: MigrationRegistryEntry[] = [
228
228
  description:
229
229
  "Remove deleted capability-card rows, jobs, checkpoints, and category state",
230
230
  },
231
+ {
232
+ key: "migration_backfill_inline_attachments_v1",
233
+ version: 34,
234
+ description:
235
+ "Backfill existing inline base64 attachments to on-disk storage and clear dataBase64",
236
+ },
237
+ {
238
+ key: "migration_rename_thread_starters_checkpoints_v1",
239
+ version: 35,
240
+ dependsOn: ["migration_rename_thread_starters_table_v1"],
241
+ description:
242
+ "Rename checkpoint keys from thread_starters: to conversation_starters: prefix so renamed code paths find existing generation state",
243
+ },
231
244
  ];
232
245
 
233
246
  export interface MigrationValidationResult {