@vellumai/assistant 0.11.1 → 0.11.2-staging.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 (318) hide show
  1. package/Dockerfile +1 -3
  2. package/README.md +1 -1
  3. package/eslint.config.mjs +28 -8
  4. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  5. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/stripe-currency.test.ts +37 -0
  6. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
  7. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  8. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/stripe-currency.test.ts +37 -0
  9. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
  10. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  11. package/node_modules/@vellumai/service-contracts/src/__tests__/stripe-currency.test.ts +37 -0
  12. package/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
  13. package/node_modules/@vellumai/slack-text/src/index.test.ts +48 -0
  14. package/node_modules/@vellumai/slack-text/src/index.ts +25 -6
  15. package/openapi.yaml +292 -5
  16. package/package.json +1 -1
  17. package/src/__tests__/agent-loop-resume-interrupted.test.ts +223 -0
  18. package/src/__tests__/byok-default-profile-ensure.test.ts +43 -0
  19. package/src/__tests__/cli-logger-boundary-guard.test.ts +87 -0
  20. package/src/__tests__/compaction-events.test.ts +139 -2
  21. package/src/__tests__/config-loader-backfill.test.ts +35 -3
  22. package/src/__tests__/config-schema.test.ts +1 -0
  23. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +30 -0
  24. package/src/__tests__/conversation-agent-loop.test.ts +180 -7
  25. package/src/__tests__/conversation-error.test.ts +211 -4
  26. package/src/__tests__/conversation-options-turn-scoped-transport.test.ts +64 -0
  27. package/src/__tests__/conversation-queue.test.ts +126 -0
  28. package/src/__tests__/conversation-retry-route.test.ts +46 -7
  29. package/src/__tests__/conversation-slash.test.ts +4 -2
  30. package/src/__tests__/conversation-summarize-route.test.ts +7 -1
  31. package/src/__tests__/conversation-summarize-up-to.test.ts +71 -5
  32. package/src/__tests__/document-create-dedupe.test.ts +2 -1
  33. package/src/__tests__/document-find-replace.test.ts +2 -1
  34. package/src/__tests__/document-tool-security.test.ts +2 -1
  35. package/src/__tests__/document-update-default-surface.test.ts +2 -1
  36. package/src/__tests__/document-workspace-file.test.ts +467 -0
  37. package/src/__tests__/emit-signal-routing-intent.test.ts +290 -49
  38. package/src/__tests__/guardian-card-withdrawal.test.ts +91 -3
  39. package/src/__tests__/http-user-message-parity.test.ts +66 -0
  40. package/src/__tests__/list-messages-attachments.test.ts +87 -0
  41. package/src/__tests__/list-messages-provider-error.test.ts +143 -0
  42. package/src/__tests__/list-messages-system-card.test.ts +100 -0
  43. package/src/__tests__/llm-resolver.test.ts +19 -9
  44. package/src/__tests__/managed-profile-guard.test.ts +23 -0
  45. package/src/__tests__/notification-platform-adapter.test.ts +130 -2
  46. package/src/__tests__/notification-telegram-adapter.test.ts +6 -0
  47. package/src/__tests__/notification-vellum-adapter.test.ts +45 -0
  48. package/src/__tests__/plugin-api-model-profiles.test.ts +10 -1
  49. package/src/__tests__/plugin-import-boundary-guard.test.ts +3 -0
  50. package/src/__tests__/provider-error-scenarios.test.ts +140 -0
  51. package/src/__tests__/provider-send-message-override-profile.test.ts +95 -0
  52. package/src/__tests__/run-conversation-turn-persistence.test.ts +66 -3
  53. package/src/__tests__/scripted-turn-metadata-persistence.test.ts +209 -0
  54. package/src/__tests__/skills.test.ts +27 -0
  55. package/src/__tests__/slack-channels-routes.test.ts +0 -2
  56. package/src/__tests__/slack-share-routes.test.ts +0 -3
  57. package/src/__tests__/slack-users-routes.test.ts +0 -2
  58. package/src/__tests__/subagent-tools.test.ts +11 -0
  59. package/src/__tests__/tool-preview-lifecycle.test.ts +58 -0
  60. package/src/__tests__/tool-result-spool.test.ts +5 -4
  61. package/src/__tests__/turn-boundary-resolution.test.ts +53 -0
  62. package/src/__tests__/turn-events-store.test.ts +26 -0
  63. package/src/__tests__/ui-visual-surface.test.ts +695 -0
  64. package/src/__tests__/unified-turn-context-visible-app.test.ts +99 -0
  65. package/src/__tests__/visible-app-context.test.ts +189 -0
  66. package/src/__tests__/workspace-git-service.test.ts +173 -33
  67. package/src/__tests__/workspace-migration-137-repair-retired-fireworks-minimax-model-id.test.ts +157 -0
  68. package/src/__tests__/workspace-migration-138-backfill-home-feed-titles.test.ts +373 -0
  69. package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +137 -0
  70. package/src/agent/loop.ts +36 -7
  71. package/src/api/events/context-window-usage.ts +31 -0
  72. package/src/api/events/notification-intent.ts +8 -0
  73. package/src/api/events/ui-surface-pending.ts +35 -0
  74. package/src/api/index.ts +14 -0
  75. package/src/api/responses/conversation-message.ts +25 -4
  76. package/src/api/surfaces.ts +90 -1
  77. package/src/approvals/guardian-card-withdrawal.ts +66 -31
  78. package/src/approvals/guardian-decision-primitive.ts +4 -0
  79. package/src/calls/__tests__/call-setup-router.test.ts +156 -26
  80. package/src/calls/__tests__/voice-session-bridge.test.ts +201 -12
  81. package/src/calls/call-setup-router.ts +80 -36
  82. package/src/calls/voice-session-bridge.ts +173 -26
  83. package/src/cli/commands/inference.help.ts +3 -3
  84. package/src/cli/commands/notifications.help.ts +3 -2
  85. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +42 -128
  86. package/src/cli/commands/platform/__tests__/credits.test.ts +9 -78
  87. package/src/cli/commands/platform/__tests__/helpers.ts +90 -0
  88. package/src/cli/commands/platform/__tests__/invoices.test.ts +238 -0
  89. package/src/cli/commands/platform/__tests__/plans.test.ts +9 -88
  90. package/src/cli/commands/platform/__tests__/status.test.ts +12 -87
  91. package/src/cli/commands/platform/__tests__/subscription.test.ts +9 -86
  92. package/src/cli/commands/platform/index.help.ts +92 -0
  93. package/src/cli/commands/platform/index.ts +7 -0
  94. package/src/cli/commands/platform/invoices.ts +132 -0
  95. package/src/cli/commands/usage.help.ts +1 -1
  96. package/src/cli/lib/list-installed-plugins.ts +2 -1
  97. package/src/config/__tests__/default-profile-catalog.test.ts +7 -10
  98. package/src/config/__tests__/deployment-context-defaults.test.ts +27 -5
  99. package/src/config/assistant-feature-flags.ts +7 -2
  100. package/src/config/bundled-skills/app-builder/SKILL.md +3 -2
  101. package/src/config/bundled-skills/subagent/SKILL.md +3 -1
  102. package/src/config/bundled-skills/subagent/TOOLS.json +3 -3
  103. package/src/config/bundled-skills/visualize/SKILL.md +163 -0
  104. package/src/config/call-site-defaults.ts +3 -2
  105. package/src/config/default-profile-catalog.ts +75 -70
  106. package/src/config/default-profile-names.ts +13 -28
  107. package/src/config/env-registry.ts +1 -0
  108. package/src/config/feature-flag-registry.json +16 -0
  109. package/src/config/llm-resolver.ts +21 -5
  110. package/src/config/loader.ts +18 -11
  111. package/src/config/schemas/llm.ts +1 -9
  112. package/src/config/schemas/memory-retrospective.ts +9 -0
  113. package/src/config/schemas/monitoring.ts +28 -2
  114. package/src/config/schemas/workspace-git.ts +15 -0
  115. package/src/config/seed-inference-profiles.ts +19 -5
  116. package/src/context/post-turn-tool-result-truncation.ts +2 -2
  117. package/src/conversations/__tests__/message-consolidation.test.ts +54 -0
  118. package/src/conversations/message-consolidation.ts +17 -15
  119. package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +182 -0
  120. package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +181 -0
  121. package/src/daemon/conversation-agent-loop-handlers.ts +90 -7
  122. package/src/daemon/conversation-agent-loop.ts +107 -22
  123. package/src/daemon/conversation-error.ts +169 -48
  124. package/src/daemon/conversation-messaging.ts +87 -4
  125. package/src/daemon/conversation-process.ts +57 -45
  126. package/src/daemon/conversation-runtime-assembly.ts +57 -0
  127. package/src/daemon/conversation-store.ts +36 -1
  128. package/src/daemon/conversation-surfaces.ts +68 -6
  129. package/src/daemon/conversation-turn-finalize.ts +76 -18
  130. package/src/daemon/conversation.ts +122 -27
  131. package/src/daemon/lifecycle.ts +9 -0
  132. package/src/daemon/message-types/conversations.ts +8 -0
  133. package/src/daemon/message-types/surfaces.ts +3 -0
  134. package/src/documents/document-store.ts +247 -10
  135. package/src/home/__tests__/feed-types.test.ts +43 -8
  136. package/src/home/__tests__/feed-writer.test.ts +59 -0
  137. package/src/home/feed-types.ts +34 -7
  138. package/src/home/feed-writer.ts +15 -6
  139. package/src/live-voice/__tests__/activity-label.test.ts +95 -0
  140. package/src/live-voice/__tests__/live-activity-reporter.test.ts +86 -5
  141. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +310 -25
  142. package/src/live-voice/__tests__/live-voice-events.test.ts +4 -4
  143. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +8 -4
  144. package/src/live-voice/__tests__/live-voice-vad.test.ts +9 -1
  145. package/src/live-voice/activity-label.ts +169 -0
  146. package/src/live-voice/live-activity-reporter.ts +35 -6
  147. package/src/live-voice/live-voice-session.ts +282 -41
  148. package/src/live-voice/protocol.ts +35 -0
  149. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +84 -2
  150. package/src/messaging/providers/slack/adapter.ts +86 -19
  151. package/src/messaging/providers/slack/api.test.ts +85 -1
  152. package/src/messaging/providers/slack/api.ts +121 -288
  153. package/src/messaging/providers/slack/client.ts +20 -251
  154. package/src/messaging/providers/slack/send.test.ts +4 -9
  155. package/src/messaging/providers/slack/send.ts +1 -1
  156. package/src/messaging/providers/slack/types.ts +5 -0
  157. package/src/messaging/providers/slack/web-api-transport.test.ts +181 -0
  158. package/src/messaging/providers/slack/web-api-transport.ts +367 -0
  159. package/src/messaging/providers/slack/withdraw.ts +6 -14
  160. package/src/messaging/providers/telegram-bot/send.test.ts +31 -1
  161. package/src/messaging/providers/telegram-bot/send.ts +23 -2
  162. package/src/messaging/providers/telegram-bot/withdraw.test.ts +152 -0
  163. package/src/messaging/providers/telegram-bot/withdraw.ts +166 -0
  164. package/src/monitoring/__tests__/db-integrity-sample.test.ts +18 -4
  165. package/src/monitoring/__tests__/file-descriptors.test.ts +144 -0
  166. package/src/monitoring/file-descriptors.ts +262 -0
  167. package/src/monitoring/process-memory.ts +4 -11
  168. package/src/monitoring/resource-sampler.ts +5 -0
  169. package/src/monitoring/worker.ts +12 -0
  170. package/src/notifications/__tests__/assistant-reply-producer.test.ts +740 -0
  171. package/src/notifications/__tests__/broadcaster.test.ts +347 -7
  172. package/src/notifications/__tests__/copy-composer.test.ts +53 -3
  173. package/src/notifications/__tests__/decision-engine.test.ts +349 -29
  174. package/src/notifications/__tests__/deterministic-checks.test.ts +21 -0
  175. package/src/notifications/__tests__/edit-notification.test.ts +330 -0
  176. package/src/notifications/__tests__/guardian-delivery-recorder.test.ts +71 -0
  177. package/src/notifications/__tests__/home-feed-side-effect.test.ts +170 -12
  178. package/src/notifications/adapters/macos.ts +3 -0
  179. package/src/notifications/adapters/platform.ts +90 -14
  180. package/src/notifications/adapters/telegram.ts +6 -4
  181. package/src/notifications/assistant-reply-producer.ts +219 -0
  182. package/src/notifications/broadcaster.ts +523 -317
  183. package/src/notifications/copy-composer.ts +27 -6
  184. package/src/notifications/decision-engine.ts +154 -77
  185. package/src/notifications/deterministic-checks.ts +6 -7
  186. package/src/notifications/edit-notification.ts +8 -4
  187. package/src/notifications/emit-signal.ts +49 -16
  188. package/src/notifications/guardian-delivery-recorder.ts +8 -2
  189. package/src/notifications/home-feed-side-effect.ts +43 -6
  190. package/src/notifications/notification-utils.ts +39 -4
  191. package/src/notifications/signal.ts +10 -0
  192. package/src/notifications/types.ts +17 -0
  193. package/src/persistence/bookmark-crud.ts +18 -9
  194. package/src/persistence/conversation-attention-store.ts +26 -0
  195. package/src/persistence/conversation-crud.ts +79 -32
  196. package/src/persistence/conversation-queries.ts +30 -15
  197. package/src/persistence/conversation-title-service.ts +5 -170
  198. package/src/persistence/conversation-types.ts +192 -1
  199. package/src/persistence/db-init.ts +14 -1
  200. package/src/persistence/db-maintenance.ts +5 -4
  201. package/src/persistence/embeddings/__tests__/plugin-index-qdrant-init.test.ts +219 -0
  202. package/src/persistence/embeddings/__tests__/plugin-index.test.ts +22 -0
  203. package/src/persistence/embeddings/__tests__/worker-script-version.test.ts +76 -0
  204. package/src/persistence/embeddings/embedding-local.ts +2 -1
  205. package/src/persistence/embeddings/embedding-runtime-manager.ts +29 -5
  206. package/src/persistence/embeddings/plugin-index.ts +84 -12
  207. package/src/persistence/migrations/360-add-document-workspace-path.test.ts +110 -0
  208. package/src/persistence/migrations/360-add-document-workspace-path.ts +39 -0
  209. package/src/persistence/planner-statistics.ts +14 -0
  210. package/src/persistence/schema/documents.ts +26 -11
  211. package/src/persistence/steps.ts +2 -0
  212. package/src/platform/client.test.ts +172 -2
  213. package/src/platform/client.ts +178 -55
  214. package/src/plugin-api/conversation-turn.ts +13 -0
  215. package/src/plugin-api/model-profiles.test.ts +6 -2
  216. package/src/plugins/defaults/memory/__tests__/bookmark-crud.test.ts +34 -0
  217. package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +22 -0
  218. package/src/plugins/defaults/memory/__tests__/jobs-store-enqueue-gate.test.ts +11 -0
  219. package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +199 -0
  220. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +98 -1
  221. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +105 -1
  222. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +24 -2
  223. package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +524 -0
  224. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +1 -1
  225. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +9 -4
  226. package/src/plugins/defaults/memory/host-utils.ts +5 -0
  227. package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +105 -1
  228. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +64 -5
  229. package/src/plugins/defaults/memory/memory-retrospective-job.ts +36 -1
  230. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +12 -3
  231. package/src/plugins/defaults/memory/src/__tests__/memory-v2-simulate-route.test.ts +1 -0
  232. package/src/plugins/defaults/memory/substrate/__tests__/skill-store.test.ts +195 -1
  233. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +1 -1
  234. package/src/plugins/defaults/memory/substrate/skill-store.ts +167 -29
  235. package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +131 -0
  236. package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +1 -0
  237. package/src/plugins/defaults/memory/v2/activation-log-store.ts +4 -0
  238. package/src/plugins/defaults/memory/v2/injection.ts +48 -3
  239. package/src/plugins/defaults/memory/v2/rerank-local.ts +6 -2
  240. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +1 -1
  241. package/src/plugins/defaults/platform-hosted/routes/reengage.ts +1 -1
  242. package/src/plugins/defaults/turn-context/injectors.ts +1 -0
  243. package/src/plugins/defaults/turn-context/unified-turn-context.ts +26 -0
  244. package/src/plugins/types.ts +17 -0
  245. package/src/prompts/templates/system-sections.ts +2 -2
  246. package/src/providers/__tests__/dispatch-connection-routing.test.ts +43 -2
  247. package/src/providers/__tests__/vellum-mismatch-routing.test.ts +8 -0
  248. package/src/providers/call-site-routing.ts +77 -14
  249. package/src/providers/connection-resolution.ts +42 -2
  250. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +127 -1
  251. package/src/providers/inference/adapter-factory.ts +70 -12
  252. package/src/providers/model-catalog.ts +0 -11
  253. package/src/providers/model-intents.ts +11 -0
  254. package/src/providers/registry.ts +8 -0
  255. package/src/providers/retry.ts +85 -17
  256. package/src/providers/types.ts +8 -1
  257. package/src/runtime/__tests__/agent-wake.test.ts +181 -0
  258. package/src/runtime/agent-wake.ts +132 -9
  259. package/src/runtime/channel-approval-types.ts +25 -0
  260. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +2 -2
  261. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +11 -0
  262. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +121 -9
  263. package/src/runtime/routes/__tests__/platform-invoice-routes.test.ts +392 -0
  264. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +7 -0
  265. package/src/runtime/routes/__tests__/workspace-commit-routes.test.ts +63 -0
  266. package/src/runtime/routes/consolidation-routes.ts +1 -1
  267. package/src/runtime/routes/conversation-management-routes.ts +18 -6
  268. package/src/runtime/routes/conversation-query-routes.ts +14 -23
  269. package/src/runtime/routes/conversation-routes.ts +113 -8
  270. package/src/runtime/routes/credential-routes.ts +1 -5
  271. package/src/runtime/routes/documents-routes.ts +207 -12
  272. package/src/runtime/routes/identity-routes.ts +3 -93
  273. package/src/runtime/routes/inbound-stages/admission-policy.test.ts +31 -1
  274. package/src/runtime/routes/inbound-stages/admission-policy.ts +18 -0
  275. package/src/runtime/routes/inference-provider-connection-routes.ts +52 -3
  276. package/src/runtime/routes/notification-routes.ts +4 -1
  277. package/src/runtime/routes/platform-routes.ts +238 -3
  278. package/src/runtime/routes/playground/guard.ts +1 -2
  279. package/src/runtime/routes/slack-channel-routes.ts +2 -4
  280. package/src/runtime/routes/workspace-commit-routes.ts +49 -2
  281. package/src/runtime/routes/workspace-routes.ts +11 -12
  282. package/src/runtime/routes/workspace-utils.ts +49 -2
  283. package/src/runtime/services/conversation-serializer.ts +2 -4
  284. package/src/subagent/__tests__/consult-context-gating.test.ts +98 -0
  285. package/src/subagent/__tests__/consult-context-skills.test.ts +82 -0
  286. package/src/subagent/__tests__/consult-context.test.ts +84 -0
  287. package/src/subagent/__tests__/consult-prompt.test.ts +36 -0
  288. package/src/subagent/consult-context.ts +410 -0
  289. package/src/subagent/consult-prompt.ts +38 -5
  290. package/src/subagent/manager.ts +9 -4
  291. package/src/subagent/types.ts +8 -0
  292. package/src/telemetry/telemetry-event-sources.ts +7 -0
  293. package/src/telemetry/telemetry-wire-source.json +1 -1
  294. package/src/telemetry/telemetry-wire.generated.ts +1 -0
  295. package/src/telemetry/turn-events-store.ts +30 -1
  296. package/src/telemetry/types.ts +24 -0
  297. package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
  298. package/src/tools/browser/pinned-tabs.ts +3 -1
  299. package/src/tools/subagent/spawn.ts +23 -1
  300. package/src/tools/terminal/safe-env.ts +1 -0
  301. package/src/tools/ui-surface/definitions.ts +39 -1
  302. package/src/tools/ui-surface/surface-shape-docs.ts +38 -4
  303. package/src/tools/ui-surface/visual-validation.ts +787 -0
  304. package/src/tools/workflows/run-workflow.test.ts +1 -0
  305. package/src/util/__tests__/short-title.test.ts +229 -0
  306. package/src/util/__tests__/worker-compute.test.ts +65 -0
  307. package/src/util/cgroup-cpu.ts +93 -0
  308. package/src/util/errors.ts +27 -0
  309. package/src/util/process-tree.ts +19 -0
  310. package/src/util/short-title.ts +189 -0
  311. package/src/util/worker-compute.ts +83 -0
  312. package/src/workspace/byok-default-profile-ensure.ts +25 -15
  313. package/src/workspace/git-service.ts +79 -30
  314. package/src/workspace/migrations/137-repair-retired-fireworks-minimax-model-id.ts +131 -0
  315. package/src/workspace/migrations/138-backfill-home-feed-titles.ts +179 -0
  316. package/src/workspace/migrations/139-clear-renamed-cost-profile-label.ts +92 -0
  317. package/src/workspace/migrations/registry.ts +6 -0
  318. package/src/plugins/defaults/memory/substrate/constants.ts +0 -8
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Workspace migration `138-backfill-home-feed-titles`.
3
+ *
4
+ * Gives every item in `<workspace>/data/home-feed.json` a non-empty
5
+ * `title`. The feed writer sets one on every item it appends; stored
6
+ * items that lack the field get a headline derived from their own
7
+ * `summary`, so the field is uniformly present across the file.
8
+ *
9
+ * Behaviour:
10
+ * - Missing file, unparseable JSON, or a non-object root: no-op.
11
+ * - Item that already has a non-empty `title`: untouched.
12
+ * - Item without one: title derived from `summary` (markdown and
13
+ * newlines flattened, first sentence, capped at 60 characters with
14
+ * an ellipsis).
15
+ * - `version`, `updatedAt`, and every other item field are preserved.
16
+ *
17
+ * Idempotent: a second run finds every item titled, so it writes
18
+ * nothing. The runner's checkpoint also skips re-runs, but this in-file
19
+ * guard keeps the migration safe even if the checkpoint is wiped.
20
+ */
21
+
22
+ import { existsSync, readFileSync, renameSync, writeFileSync } from "node:fs";
23
+ import { join } from "node:path";
24
+
25
+ import { getLogger } from "../../util/logger.js";
26
+ import type { WorkspaceMigration } from "./types.js";
27
+
28
+ const log = getLogger("workspace-migration-138-backfill-home-feed-titles");
29
+
30
+ const HOME_FEED_RELATIVE_PATH = join("data", "home-feed.json");
31
+
32
+ /**
33
+ * Matches `NOTIFICATION_TITLE_MAX_LENGTH` in
34
+ * `notifications/notification-utils.ts`, the cap on the headline the feed
35
+ * writer derives from a summary, so a backfilled item and a freshly
36
+ * written one with the same summary carry the same title.
37
+ */
38
+ const MAX_TITLE_LENGTH = 60;
39
+
40
+ /**
41
+ * The persisted item fields this migration touches. Inlined rather than
42
+ * imported from `home/feed-types.ts` so the migration stays
43
+ * self-contained per the migrations AGENTS.md.
44
+ */
45
+ interface PersistedFeedItem {
46
+ /** Missing, empty, or non-string on the items repaired here. */
47
+ title?: unknown;
48
+ /** Source text for the derived title. */
49
+ summary?: unknown;
50
+ /** Every other persisted field is carried through untouched. */
51
+ [key: string]: unknown;
52
+ }
53
+
54
+ export const backfillHomeFeedTitlesMigration: WorkspaceMigration = {
55
+ id: "138-backfill-home-feed-titles",
56
+ description:
57
+ "Backfill a summary-derived title on home-feed items that lack one",
58
+
59
+ run(workspaceDir: string): void {
60
+ const path = join(workspaceDir, HOME_FEED_RELATIVE_PATH);
61
+ if (!existsSync(path)) {
62
+ return;
63
+ }
64
+
65
+ // Read outside the parse catch: a transient filesystem error (EIO,
66
+ // EACCES) must reach the runner so the migration retries, while
67
+ // malformed JSON is a permanent state this migration cannot repair.
68
+ const rawText = readFileSync(path, "utf-8");
69
+
70
+ let feed: Record<string, unknown>;
71
+ try {
72
+ const parsed = JSON.parse(rawText);
73
+ if (!isPlainObject(parsed)) {
74
+ return;
75
+ }
76
+ feed = parsed;
77
+ } catch (err) {
78
+ log.warn(
79
+ { err, path },
80
+ "Failed to parse home-feed.json; skipping title backfill",
81
+ );
82
+ return;
83
+ }
84
+
85
+ const rawItems = Array.isArray(feed.items) ? feed.items : [];
86
+ let backfilled = 0;
87
+ for (const entry of rawItems) {
88
+ if (!isPlainObject(entry)) {
89
+ continue;
90
+ }
91
+ const item: PersistedFeedItem = entry;
92
+ if (typeof item.title === "string" && item.title.trim().length > 0) {
93
+ continue;
94
+ }
95
+ if (typeof item.summary !== "string") {
96
+ continue;
97
+ }
98
+ const derived = deriveTitle(item.summary);
99
+ if (derived.length === 0) {
100
+ continue;
101
+ }
102
+ item.title = derived;
103
+ backfilled++;
104
+ }
105
+
106
+ if (backfilled === 0) {
107
+ return;
108
+ }
109
+
110
+ // Write-then-rename so an interrupted write cannot leave
111
+ // home-feed.json truncated: the reader treats an unparseable file as
112
+ // an empty feed, so a torn in-place write would discard the user's
113
+ // notification history outright.
114
+ const tmpPath = `${path}.migration-138.tmp`;
115
+ writeFileSync(tmpPath, JSON.stringify(feed, null, 2), "utf-8");
116
+ renameSync(tmpPath, path);
117
+
118
+ log.info({ path, backfilled }, "Backfilled titles on home-feed items");
119
+ },
120
+
121
+ // Deriving a title from the summary is idempotent, so a transient
122
+ // failure (full disk, I/O error) is safe to retry on later startups.
123
+ retryFailedCheckpoint: true,
124
+
125
+ down(_workspaceDir: string): void {
126
+ // Forward-only: a derived title is indistinguishable from an
127
+ // authored one, so there is nothing safe to strip back out.
128
+ },
129
+ };
130
+
131
+ // ---------------------------------------------------------------------------
132
+ // Helpers: self-contained per the workspace migrations AGENTS.md
133
+ // ---------------------------------------------------------------------------
134
+
135
+ /**
136
+ * Derive a short headline from a summary: the markdown is flattened to a
137
+ * single line of plain text, the first sentence is taken when the text
138
+ * has a terminator, and the result is capped at `MAX_TITLE_LENGTH`
139
+ * characters with an ellipsis. Returns "" when nothing usable survives.
140
+ *
141
+ * Inlined rather than imported from the notification pipeline so the
142
+ * migration stays self-contained per the migrations AGENTS.md.
143
+ */
144
+ function deriveTitle(summary: string): string {
145
+ const text = flattenToPlainText(summary);
146
+ const firstSentenceEnd = text.search(/[.!?](\s|$)/);
147
+ const candidate =
148
+ firstSentenceEnd > 0 ? text.slice(0, firstSentenceEnd + 1) : text;
149
+ return candidate.length > MAX_TITLE_LENGTH
150
+ ? candidate.slice(0, MAX_TITLE_LENGTH).trim() + "…"
151
+ : candidate.trim();
152
+ }
153
+
154
+ /**
155
+ * Reduce markdown-rich summary text to a single line of plain prose:
156
+ * block structure (code fences, headings, blockquotes, list markers) is
157
+ * dropped, inline formatting is unwrapped, and every run of whitespace,
158
+ * newlines included, collapses to one space.
159
+ */
160
+ function flattenToPlainText(text: string): string {
161
+ return text
162
+ .replace(/^\s{0,3}(?:```|~~~).*$/gm, "")
163
+ .replace(/^\s{0,3}#{1,6}\s+/gm, "")
164
+ .replace(/^\s{0,3}>\s?/gm, "")
165
+ .replace(/^\s{0,3}(?:[-*+]|\d+[.)])\s+/gm, "")
166
+ .replace(/\*\*(.+?)\*\*/g, "$1")
167
+ .replace(/__(.+?)__/g, "$1")
168
+ .replace(/\*(.+?)\*/g, "$1")
169
+ .replace(/(?<!\w)_(.+?)_(?!\w)/g, "$1")
170
+ .replace(/~~(.+?)~~/g, "$1")
171
+ .replace(/`(.+?)`/g, "$1")
172
+ .replace(/\[(.+?)\]\(.*?\)/g, "$1")
173
+ .replace(/\s+/g, " ")
174
+ .trim();
175
+ }
176
+
177
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
178
+ return typeof value === "object" && value !== null && !Array.isArray(value);
179
+ }
@@ -0,0 +1,92 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import type { WorkspaceMigration } from "./types.js";
5
+
6
+ /**
7
+ * Clear the machinery-written `"Speed"` label off the `cost-optimized`
8
+ * profile so the code catalog's new label ("Cost") reaches existing installs.
9
+ *
10
+ * `label` is workspace-owned overlay state: a managed-source entry's label
11
+ * wins over the code default (`WORKSPACE_OWNED_DEFAULT_FIELDS` in
12
+ * `config/default-profile-catalog.ts`). Migration 082 and the pre-catalog
13
+ * seeder both wrote `"Speed"` onto `cost-optimized`, and migration 126
14
+ * carried it onto the thin stub, so without this the picker would show two
15
+ * profiles named "Speed": `cost-optimized`'s stale overlay and
16
+ * `latency-optimized`, the user-facing Speed profile.
17
+ *
18
+ * Deleting the key (rather than writing "Cost") returns the label to code
19
+ * ownership, so later renames ship with a release instead of a migration.
20
+ *
21
+ * Only the exact string `"Speed"` is cleared. A user rename to anything else
22
+ * survives, as does an explicit `null` (label deliberately cleared). A rename
23
+ * that happened to be "Speed" is indistinguishable from the seeded value and
24
+ * is cleared too.
25
+ *
26
+ * Deliberately does NOT touch the `"Speed (Managed)"` label on BYOK hatch
27
+ * stubs: `ensureByokDefaultProfiles` matches that exact string to recognize a
28
+ * hatch stub and delete it (which is what re-enables the profile). Clearing
29
+ * it here would strand those installs with `cost-optimized` disabled. Once
30
+ * that pass removes the stub, the code label applies.
31
+ */
32
+ export const clearRenamedCostProfileLabelMigration: WorkspaceMigration = {
33
+ id: "139-clear-renamed-cost-profile-label",
34
+ description:
35
+ 'Clear the seeded "Speed" label on cost-optimized so the code catalog label applies',
36
+ run(workspaceDir: string): void {
37
+ const configPath = join(workspaceDir, "config.json");
38
+ if (!existsSync(configPath)) {
39
+ return;
40
+ }
41
+
42
+ // Read outside the parse catch: a transient filesystem error must reach
43
+ // the runner so the migration retries, while malformed JSON is a
44
+ // permanent state this migration cannot repair.
45
+ const rawText = readFileSync(configPath, "utf-8");
46
+
47
+ let config: Record<string, unknown>;
48
+ try {
49
+ const parsed = JSON.parse(rawText);
50
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
51
+ return;
52
+ }
53
+ config = parsed as Record<string, unknown>;
54
+ } catch {
55
+ return;
56
+ }
57
+
58
+ const llm = readObject(config.llm);
59
+ if (llm === null) {
60
+ return;
61
+ }
62
+ const profiles = readObject(llm.profiles);
63
+ if (profiles === null) {
64
+ return;
65
+ }
66
+ const entry = readObject(profiles["cost-optimized"]);
67
+ if (entry === null) {
68
+ return;
69
+ }
70
+ // Only a managed-source entry carries a machinery-written label. Anything
71
+ // else, a source-less legacy entry included, shadows the default outright
72
+ // (see `getEffectiveProfile`), so its label is the user's.
73
+ if (entry.source !== "managed") {
74
+ return;
75
+ }
76
+ if (entry.label !== "Speed") {
77
+ return;
78
+ }
79
+
80
+ delete entry.label;
81
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
82
+ },
83
+ down(_workspaceDir: string): void {
84
+ // Forward-only: the label is code-owned once cleared.
85
+ },
86
+ };
87
+
88
+ function readObject(value: unknown): Record<string, unknown> | null {
89
+ return value !== null && typeof value === "object" && !Array.isArray(value)
90
+ ? (value as Record<string, unknown>)
91
+ : null;
92
+ }
@@ -134,6 +134,9 @@ import { collapseProviderConnectionsMigration } from "./133-collapse-provider-co
134
134
  import { imageGenerationModeToProviderMigration } from "./134-image-generation-mode-to-provider.js";
135
135
  import { copySubstrateTunablesMigration } from "./135-copy-substrate-tunables.js";
136
136
  import { repairStaleFireworksKimiModelIdMigration } from "./136-repair-stale-fireworks-kimi-model-id.js";
137
+ import { repairRetiredFireworksMinimaxModelIdMigration } from "./137-repair-retired-fireworks-minimax-model-id.js";
138
+ import { backfillHomeFeedTitlesMigration } from "./138-backfill-home-feed-titles.js";
139
+ import { clearRenamedCostProfileLabelMigration } from "./139-clear-renamed-cost-profile-label.js";
137
140
  import { migrateToWorkspaceVolumeMigration } from "./migrate-to-workspace-volume.js";
138
141
  import type { WorkspaceMigration } from "./types.js";
139
142
 
@@ -283,4 +286,7 @@ export const WORKSPACE_MIGRATIONS: WorkspaceMigration[] = [
283
286
  imageGenerationModeToProviderMigration,
284
287
  copySubstrateTunablesMigration,
285
288
  repairStaleFireworksKimiModelIdMigration,
289
+ repairRetiredFireworksMinimaxModelIdMigration,
290
+ backfillHomeFeedTitlesMigration,
291
+ clearRenamedCostProfileLabelMigration,
286
292
  ];
@@ -1,8 +0,0 @@
1
- /**
2
- * Canonical `conversations.source` string for background memory v2
3
- * consolidation runs. Lives in a tiny constants module so the route layer can
4
- * recognize consolidation conversations without importing the consolidation
5
- * job (which pulls in agent-wake + bootstrap dependencies).
6
- */
7
- // FROZEN: persisted `conversations.source` value — never rename it.
8
- export const MEMORY_V2_CONSOLIDATION_SOURCE = "memory_v2_consolidation";