@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
@@ -8,6 +8,13 @@
8
8
  // musings from the retrospective agent's own writes).
9
9
  // - Source isn't a `scheduled` thread or a memory-consolidation background
10
10
  // (low yield — see `isLowYieldRetrospectiveSource`).
11
+ // - The unprocessed tail contains user activity, when
12
+ // `memory.retrospective.requireUserActivity` is on. Assistant-only
13
+ // stretches (proactive sends composed by turns running elsewhere) carry
14
+ // no user turn, so their window anchor is undecidable and their content
15
+ // is a recap of work captured at its source; the gate defers them until
16
+ // real user activity arrives. Living here, every trigger kind funnels
17
+ // through one check.
11
18
  //
12
19
  // All trigger types funnel through `upsertMemoryRetrospectiveJob` which
13
20
  // coalesces rapid enqueues into a single pending row per conversation.
@@ -23,10 +30,12 @@
23
30
  // hooks ran (crash / IPC drop) and the conversation then went idle. See
24
31
  // `memory-retrospective-sweep.ts`.
25
32
 
33
+ import { getConfig } from "../../../config/loader.js";
26
34
  import {
27
35
  getConversation,
28
36
  getConversationSource,
29
37
  } from "../../../persistence/conversation-crud.js";
38
+ import { MEMORY_V2_CONSOLIDATION_SOURCE } from "../../../persistence/conversation-types.js";
30
39
  import {
31
40
  isMemoryEnabled,
32
41
  upsertMemoryRetrospectiveJob,
@@ -34,8 +43,9 @@ import {
34
43
  import { type TrustClass } from "../../../runtime/actor-trust-resolver.js";
35
44
  import { resolveCapabilities } from "../../../runtime/capabilities.js";
36
45
  import { getLogger } from "./logging.js";
46
+ import { hasQualifyingUserMessageAfter } from "./memory-retrospective-accounting.js";
37
47
  import { isMemoryRetrospectiveSource } from "./memory-retrospective-constants.js";
38
- import { MEMORY_V2_CONSOLIDATION_SOURCE } from "./substrate/constants.js";
48
+ import { getRetrospectiveState } from "./memory-retrospective-state.js";
39
49
 
40
50
  const log = getLogger("memory-retrospective-enqueue");
41
51
 
@@ -47,14 +57,19 @@ export type MemoryRetrospectiveTrigger =
47
57
 
48
58
  const COMPACTION_DEBOUNCE_MS = 500;
49
59
 
60
+ /**
61
+ * Returns true when a job row was upserted, false when a gate skipped the
62
+ * enqueue (or the upsert failed). The sweep counts only true returns toward
63
+ * its per-pass cap.
64
+ */
50
65
  export function enqueueMemoryRetrospectiveIfEnabled(args: {
51
66
  conversationId: string;
52
67
  trigger: MemoryRetrospectiveTrigger;
53
- }): void {
68
+ }): boolean {
54
69
  const { conversationId, trigger } = args;
55
70
 
56
71
  if (!isMemoryEnabled()) {
57
- return;
72
+ return false;
58
73
  }
59
74
 
60
75
  if (isMemoryRetrospectiveConversation(conversationId)) {
@@ -62,7 +77,7 @@ export function enqueueMemoryRetrospectiveIfEnabled(args: {
62
77
  { conversationId, trigger },
63
78
  "Skipping memory-retrospective enqueue: source is a memory-retrospective conversation",
64
79
  );
65
- return;
80
+ return false;
66
81
  }
67
82
 
68
83
  if (isLowYieldRetrospectiveSource(conversationId)) {
@@ -70,7 +85,11 @@ export function enqueueMemoryRetrospectiveIfEnabled(args: {
70
85
  { conversationId, trigger },
71
86
  "Skipping memory-retrospective enqueue: scheduled or consolidation source",
72
87
  );
73
- return;
88
+ return false;
89
+ }
90
+
91
+ if (!passesUserActivityGate(conversationId, trigger)) {
92
+ return false;
74
93
  }
75
94
 
76
95
  const runAfter =
@@ -83,6 +102,46 @@ export function enqueueMemoryRetrospectiveIfEnabled(args: {
83
102
  { err, conversationId, trigger },
84
103
  "Failed to upsert memory-retrospective job",
85
104
  );
105
+ return false;
106
+ }
107
+ return true;
108
+ }
109
+
110
+ /**
111
+ * The `memory.retrospective.requireUserActivity` gate: pass when the config
112
+ * is off or the unprocessed tail (everything after the conversation's
113
+ * `lastProcessedMessageId`) contains at least one user message carrying
114
+ * non-tool_result content. A gate that cannot be evaluated (config or DB
115
+ * unavailable) passes — an unevaluable gate must not silence retrospectives.
116
+ */
117
+ function passesUserActivityGate(
118
+ conversationId: string,
119
+ trigger: MemoryRetrospectiveTrigger,
120
+ ): boolean {
121
+ try {
122
+ if (!getConfig().memory.retrospective.requireUserActivity) {
123
+ return true;
124
+ }
125
+ const state = getRetrospectiveState(conversationId);
126
+ if (
127
+ hasQualifyingUserMessageAfter(
128
+ conversationId,
129
+ state?.lastProcessedMessageId ?? null,
130
+ )
131
+ ) {
132
+ return true;
133
+ }
134
+ log.debug(
135
+ { conversationId, trigger },
136
+ "Skipping memory-retrospective enqueue: no user activity in the unprocessed tail",
137
+ );
138
+ return false;
139
+ } catch (err) {
140
+ log.warn(
141
+ { err, conversationId, trigger },
142
+ "User-activity gate check failed; enqueueing anyway",
143
+ );
144
+ return true;
86
145
  }
87
146
  }
88
147
 
@@ -80,7 +80,10 @@ import { wakeAgentForOpportunity } from "../../../runtime/agent-wake.js";
80
80
  import { recordWatchdogEvent } from "../../../telemetry/watchdog-events-store.js";
81
81
  import { findMostRecentRetrospectiveFor } from "./find-most-recent-retrospective-for.js";
82
82
  import { getLogger } from "./logging.js";
83
- import { getRetrospectiveMessagesAfter } from "./memory-retrospective-accounting.js";
83
+ import {
84
+ getRetrospectiveMessagesAfter,
85
+ messagesHaveUserActivity,
86
+ } from "./memory-retrospective-accounting.js";
84
87
  import {
85
88
  MEMORY_RETROSPECTIVE_FORK_SOURCE,
86
89
  MEMORY_RETROSPECTIVE_GROUP_ID,
@@ -125,6 +128,7 @@ const MEMORY_RETROSPECTIVE_RUN_CHECK_NAME = "memory_retrospective_run";
125
128
  export type MemoryRetrospectiveOutcome =
126
129
  | { kind: "disabled" }
127
130
  | { kind: "no_new_messages" }
131
+ | { kind: "no_user_activity" }
128
132
  | { kind: "source_dormant" }
129
133
  | { kind: "source_processing" }
130
134
  | { kind: "wake_failed"; reason?: string; conversationId?: string }
@@ -174,6 +178,7 @@ export async function memoryRetrospectiveJob(
174
178
  try {
175
179
  outcome = await runForkBasedRetrospective(sourceConversationId, config, {
176
180
  enforceSweepLookback: true,
181
+ enforceUserActivityGate: true,
177
182
  });
178
183
  } catch (err) {
179
184
  emitRunOutcome("error", err instanceof Error ? err.message : String(err));
@@ -209,6 +214,14 @@ export async function runForkBasedRetrospective(
209
214
  * window.
210
215
  */
211
216
  enforceSweepLookback?: boolean;
217
+ /**
218
+ * Apply the `memory.retrospective.requireUserActivity` gate to the loaded
219
+ * slice. The queue handler passes this so rows that predate the enqueue
220
+ * gate (or that lost their user activity to a cursor race) complete as
221
+ * no-ops; the CLI's manual command omits it — an operator's explicit
222
+ * request overrides the gate.
223
+ */
224
+ enforceUserActivityGate?: boolean;
212
225
  },
213
226
  ): Promise<MemoryRetrospectiveOutcome> {
214
227
  // Start stamp for the retrospective's end-to-end wall time, surfaced as
@@ -305,6 +318,23 @@ export async function runForkBasedRetrospective(
305
318
  return { kind: "no_new_messages" };
306
319
  }
307
320
 
321
+ // Execution-time twin of the enqueue funnel's user-activity gate. An
322
+ // assistant-only slice has no user turn to anchor the review window on and
323
+ // recaps work captured at its source, so it is deferred, not run: both
324
+ // state pointers stay untouched and the slice is reviewed by the first
325
+ // retrospective after real user activity arrives.
326
+ if (
327
+ opts?.enforceUserActivityGate === true &&
328
+ config.memory.retrospective.requireUserActivity &&
329
+ !messagesHaveUserActivity(newMessages)
330
+ ) {
331
+ log.info(
332
+ { sourceConversationId, newMessageCount: newMessages.length },
333
+ "memory-retrospective (fork): unprocessed tail has no user activity; skipping",
334
+ );
335
+ return { kind: "no_user_activity" };
336
+ }
337
+
308
338
  const cutoffMessage = newMessages[newMessages.length - 1];
309
339
  if (!cutoffMessage) {
310
340
  return { kind: "no_new_messages" };
@@ -497,6 +527,11 @@ export async function runForkBasedRetrospective(
497
527
  hintRole: "user",
498
528
  skipHintInjection: true,
499
529
  suppressAutoCompaction: true,
530
+ // Finalization consumes the window (cursor advance + prior-retro GC)
531
+ // on `invoked: true`, so an empty reply with no usable output must
532
+ // fail the wake and leave the window retryable instead of reading as
533
+ // a successful pass (LUM-3013).
534
+ requireUsableOutput: true,
500
535
  // The fork's title already reads "(Retrospective)", so an empty-body
501
536
  // "Conversation Woke" surface card on top of it would be noise. Suppress
502
537
  // it — clients should display the fork as a normal background conv.
@@ -42,7 +42,9 @@
42
42
  // - Enqueues route through `enqueueMemoryRetrospectiveIfEnabled`, whose
43
43
  // `upsertMemoryRetrospectiveJob` coalesces against any already-pending job,
44
44
  // so a conversation already queued by an event trigger is never
45
- // double-processed.
45
+ // double-processed. An enqueue the funnel's gates decline (recursion,
46
+ // low-yield, user-activity) returns false and does not consume the
47
+ // per-pass cap.
46
48
  // - Enqueues are capped at `SWEEP_MAX_ENQUEUES_PER_PASS` per pass. Inside
47
49
  // the lookback window, organic stalled work is a handful of conversations;
48
50
  // a pass wanting more signals an anomalous backlog. Each pass re-scans
@@ -65,6 +67,7 @@ import { and, asc, gt, ne, notInArray } from "drizzle-orm";
65
67
  import type { AssistantConfig } from "../../../config/types.js";
66
68
  import { AUTO_ANALYSIS_SOURCE } from "../../../persistence/auto-analysis-constants.js";
67
69
  import { getConversationRecentProvenanceTrustClass } from "../../../persistence/conversation-crud.js";
70
+ import { MEMORY_V2_CONSOLIDATION_SOURCE } from "../../../persistence/conversation-types.js";
68
71
  import { getDb } from "../../../persistence/db-connection.js";
69
72
  import type { MemoryJob } from "../../../persistence/jobs-store.js";
70
73
  import {
@@ -77,7 +80,6 @@ import { countRetrospectiveMessagesAfter } from "./memory-retrospective-accounti
77
80
  import { MEMORY_RETROSPECTIVE_SOURCES } from "./memory-retrospective-constants.js";
78
81
  import { enqueueMemoryRetrospectiveIfEnabled } from "./memory-retrospective-enqueue.js";
79
82
  import { getRetrospectiveState } from "./memory-retrospective-state.js";
80
- import { MEMORY_V2_CONSOLIDATION_SOURCE } from "./substrate/constants.js";
81
83
 
82
84
  const log = getLogger("memory-retrospective-sweep");
83
85
 
@@ -277,7 +279,14 @@ export async function runRetrospectiveSweep(
277
279
  continue;
278
280
  }
279
281
 
280
- enqueueMemoryRetrospectiveIfEnabled({ conversationId, trigger: "sweep" });
282
+ if (
283
+ !enqueueMemoryRetrospectiveIfEnabled({
284
+ conversationId,
285
+ trigger: "sweep",
286
+ })
287
+ ) {
288
+ continue;
289
+ }
281
290
  enqueued += 1;
282
291
  if (enqueued >= SWEEP_MAX_ENQUEUES_PER_PASS) {
283
292
  log.warn(
@@ -35,6 +35,7 @@ import type { ToolDefinition } from "../../llm-helpers.js";
35
35
  mock.module("../../substrate/skill-store.js", () => ({
36
36
  SKILL_SLUG_PREFIX: "skills/",
37
37
  listSkillEntries: () => [],
38
+ listAlwaysCandidateSkillSlugs: () => [],
38
39
  seedV2SkillEntries: async () => undefined,
39
40
  }));
40
41
 
@@ -15,6 +15,10 @@
15
15
  * slugs (`"skills/example-skill"`).
16
16
  * - It swallows errors from the embedding backend — the function resolves
17
17
  * and the cache is unchanged from prior state.
18
+ * - `listAlwaysCandidateSkillSlugs` serves pins (and their renderable cards)
19
+ * from the local catalog before any seed run completes, applies the same
20
+ * enablement/flag filtering the seeding path does, and yields to the seeded
21
+ * snapshot once one lands.
18
22
  *
19
23
  * Hermetic by design: the embedding backend, Qdrant module, and feature-flag
20
24
  * resolver are module-mocked so the suite never reaches a real backend. One
@@ -55,6 +59,7 @@ interface BackfillCall {
55
59
 
56
60
  interface TestState {
57
61
  catalog: SkillSummary[] | null;
62
+ catalogThrows: Error | null;
58
63
  resolved: ResolvedSkill[] | null;
59
64
  fullCatalog: CatalogSkill[];
60
65
  fullCatalogThrows: Error | null;
@@ -69,10 +74,12 @@ interface TestState {
69
74
  backfillReturn: number;
70
75
  backfillThrows: Error | null;
71
76
  callSequence: Array<"upsert" | "prune" | "backfill">;
77
+ catalogLoadCount: number;
72
78
  }
73
79
 
74
80
  const state: TestState = {
75
81
  catalog: [],
82
+ catalogThrows: null,
76
83
  resolved: [],
77
84
  fullCatalog: [],
78
85
  fullCatalogThrows: null,
@@ -87,10 +94,17 @@ const state: TestState = {
87
94
  backfillReturn: 0,
88
95
  backfillThrows: null,
89
96
  callSequence: [],
97
+ catalogLoadCount: 0,
90
98
  };
91
99
 
92
100
  mock.module("../../../../../config/skills.js", () => ({
93
- loadSkillCatalog: () => state.catalog ?? [],
101
+ loadSkillCatalog: () => {
102
+ state.catalogLoadCount += 1;
103
+ if (state.catalogThrows) {
104
+ throw state.catalogThrows;
105
+ }
106
+ return state.catalog ?? [];
107
+ },
94
108
  }));
95
109
 
96
110
  mock.module("../../../../../config/skill-state.js", () => ({
@@ -187,6 +201,7 @@ mock.module("../../../../../skills/catalog-cache.js", () => ({
187
201
  const {
188
202
  seedV2SkillEntries,
189
203
  getSkillCapability,
204
+ listAlwaysCandidateSkillSlugs,
190
205
  listSkillEntries,
191
206
  _resetSkillStoreForTests,
192
207
  } = await import("../skill-store.js");
@@ -210,6 +225,7 @@ function makeSummary(overrides: Partial<SkillSummary> = {}): SkillSummary {
210
225
 
211
226
  function resetState(): void {
212
227
  state.catalog = [];
228
+ state.catalogThrows = null;
213
229
  state.resolved = [];
214
230
  state.fullCatalog = [];
215
231
  state.fullCatalogThrows = null;
@@ -224,6 +240,7 @@ function resetState(): void {
224
240
  state.backfillReturn = 0;
225
241
  state.backfillThrows = null;
226
242
  state.callSequence.length = 0;
243
+ state.catalogLoadCount = 0;
227
244
  _resetSkillStoreForTests();
228
245
  }
229
246
 
@@ -286,6 +303,34 @@ describe("seedV2SkillEntries", () => {
286
303
  expect(state.upsertCalls[0].slug).toBe("skills/example-skill-a");
287
304
  });
288
305
 
306
+ test("reports enabled always-candidate skills and excludes disabled ones", async () => {
307
+ const pinned = makeSummary({
308
+ id: "example-skill-a",
309
+ alwaysCandidate: true,
310
+ });
311
+ const pinnedButDisabled = makeSummary({
312
+ id: "example-skill-b",
313
+ alwaysCandidate: true,
314
+ });
315
+ const ordinary = makeSummary({ id: "example-skill-c" });
316
+ state.catalog = [pinned, pinnedButDisabled, ordinary];
317
+ state.resolved = [
318
+ { summary: pinned, state: "enabled" },
319
+ { summary: pinnedButDisabled, state: "disabled" },
320
+ { summary: ordinary, state: "enabled" },
321
+ ];
322
+ state.embedReturn = [
323
+ [0.1, 0.2, 0.3],
324
+ [0.4, 0.5, 0.6],
325
+ ];
326
+
327
+ await seedV2SkillEntries();
328
+
329
+ expect(await listAlwaysCandidateSkillSlugs()).toEqual([
330
+ "skills/example-skill-a",
331
+ ]);
332
+ });
333
+
289
334
  test("does not re-seed an installed-but-disabled skill from the remote catalog", async () => {
290
335
  // Regression: if `seenIds` is built only from enabled skills, a locally
291
336
  // installed-but-disabled skill falls through to the catalog loop and gets
@@ -880,6 +925,155 @@ Write a local article draft.
880
925
  });
881
926
  });
882
927
 
928
+ describe("listAlwaysCandidateSkillSlugs — pre-seed catalog fallback", () => {
929
+ // Always-candidate membership is a static catalog fact. The boot seed is
930
+ // fire-and-forget and needs Qdrant plus a configured embedding backend, so on
931
+ // a freshly hatched assistant turn 1 lands before it finishes. Reading the
932
+ // catalog directly is what keeps the pin (and its card) alive on that turn.
933
+
934
+ test("reports always-candidate slugs before any seed run completes", async () => {
935
+ const pinned = makeSummary({
936
+ id: "example-skill-a",
937
+ displayName: "Skill A",
938
+ alwaysCandidate: true,
939
+ });
940
+ const ordinary = makeSummary({ id: "example-skill-b" });
941
+ state.catalog = [pinned, ordinary];
942
+ state.resolved = [
943
+ { summary: pinned, state: "enabled" },
944
+ { summary: ordinary, state: "enabled" },
945
+ ];
946
+
947
+ expect(await listAlwaysCandidateSkillSlugs()).toEqual([
948
+ "skills/example-skill-a",
949
+ ]);
950
+ // No seed ran, so nothing was embedded.
951
+ expect(state.upsertCalls).toHaveLength(0);
952
+ });
953
+
954
+ test("excludes disabled and flag-gated skills exactly as the seeding path does", async () => {
955
+ const pinned = makeSummary({
956
+ id: "example-skill-a",
957
+ alwaysCandidate: true,
958
+ });
959
+ const pinnedButDisabled = makeSummary({
960
+ id: "example-skill-b",
961
+ alwaysCandidate: true,
962
+ });
963
+ // Flag gating is resolved host-side: the gated skill is absent from
964
+ // `resolveSkillStates`, so it surfaces as `state: "unavailable"`.
965
+ const pinnedButGated = makeSummary({
966
+ id: "example-skill-c",
967
+ alwaysCandidate: true,
968
+ featureFlag: "off-flag",
969
+ });
970
+ state.catalog = [pinned, pinnedButDisabled, pinnedButGated];
971
+ state.resolved = [
972
+ { summary: pinned, state: "enabled" },
973
+ { summary: pinnedButDisabled, state: "disabled" },
974
+ ];
975
+
976
+ expect(await listAlwaysCandidateSkillSlugs()).toEqual([
977
+ "skills/example-skill-a",
978
+ ]);
979
+ expect(getSkillCapability("example-skill-b")).toBeNull();
980
+ expect(getSkillCapability("example-skill-c")).toBeNull();
981
+ });
982
+
983
+ test("renders the pinned skill's card content on the fallback path", async () => {
984
+ // The load-bearing half: `renderInjectionBlock` resolves each pinned slug
985
+ // through `getSkillCapability`, so a pin whose card does not resolve is
986
+ // silently dropped from the block.
987
+ const pinned = makeSummary({
988
+ id: "example-skill-a",
989
+ displayName: "Skill A",
990
+ description: "Draws inline visuals",
991
+ activationHints: ["user asks for a chart", "user asks for a diagram"],
992
+ avoidWhen: ["user wants a spreadsheet"],
993
+ alwaysCandidate: true,
994
+ });
995
+ state.catalog = [pinned];
996
+ state.resolved = [{ summary: pinned, state: "enabled" }];
997
+
998
+ const slugs = await listAlwaysCandidateSkillSlugs();
999
+ expect(slugs).toEqual(["skills/example-skill-a"]);
1000
+
1001
+ const entry = getSkillCapability(slugs[0]);
1002
+ expect(entry).not.toBeNull();
1003
+ expect(entry?.id).toBe("example-skill-a");
1004
+ expect(entry?.content).toContain('The "Skill A" skill');
1005
+ expect(entry?.content).toContain("Draws inline visuals");
1006
+ // The larger always-candidate budget switches the hints to a bulleted list,
1007
+ // proving the fallback renders through the same `buildSkillContent` budget
1008
+ // the seeding path uses.
1009
+ expect(entry?.content).toContain("Use when:\n- user asks for a chart");
1010
+ expect(entry?.content).toContain("Avoid when:\n- user wants a spreadsheet");
1011
+ // Bare-id lookup resolves the same entry.
1012
+ expect(getSkillCapability("example-skill-a")).toEqual(entry);
1013
+ });
1014
+
1015
+ test("scans the catalog once and reuses the fallback across turns", async () => {
1016
+ const pinned = makeSummary({
1017
+ id: "example-skill-a",
1018
+ alwaysCandidate: true,
1019
+ });
1020
+ state.catalog = [pinned];
1021
+ state.resolved = [{ summary: pinned, state: "enabled" }];
1022
+
1023
+ await listAlwaysCandidateSkillSlugs();
1024
+ const afterFirst = state.catalogLoadCount;
1025
+ expect(afterFirst).toBeGreaterThan(0);
1026
+
1027
+ await listAlwaysCandidateSkillSlugs();
1028
+ await listAlwaysCandidateSkillSlugs();
1029
+
1030
+ expect(state.catalogLoadCount).toBe(afterFirst);
1031
+ });
1032
+
1033
+ test("the seeded snapshot replaces the fallback once a seed completes", async () => {
1034
+ const pinned = makeSummary({
1035
+ id: "example-skill-a",
1036
+ displayName: "Skill A",
1037
+ alwaysCandidate: true,
1038
+ });
1039
+ state.catalog = [pinned];
1040
+ state.resolved = [{ summary: pinned, state: "enabled" }];
1041
+
1042
+ expect(await listAlwaysCandidateSkillSlugs()).toEqual([
1043
+ "skills/example-skill-a",
1044
+ ]);
1045
+
1046
+ // The user disables the skill, then a seed run lands: the seeded snapshot
1047
+ // is authoritative and the stale fallback must not resurrect the pin.
1048
+ state.resolved = [{ summary: pinned, state: "disabled" }];
1049
+ state.embedReturn = [];
1050
+ await seedV2SkillEntries();
1051
+
1052
+ expect(await listAlwaysCandidateSkillSlugs()).toEqual([]);
1053
+ expect(getSkillCapability("example-skill-a")).toBeNull();
1054
+ expect(listSkillEntries()).toEqual([]);
1055
+ });
1056
+
1057
+ test("a catalog read failure degrades to an empty pin set and is retried next turn", async () => {
1058
+ const pinned = makeSummary({
1059
+ id: "example-skill-a",
1060
+ alwaysCandidate: true,
1061
+ });
1062
+ state.catalog = [pinned];
1063
+ state.resolved = [{ summary: pinned, state: "enabled" }];
1064
+ state.catalogThrows = new Error("skills directory unreadable");
1065
+
1066
+ expect(await listAlwaysCandidateSkillSlugs()).toEqual([]);
1067
+
1068
+ // A failed build is not latched, so the next turn picks the catalog up.
1069
+ state.catalogThrows = null;
1070
+
1071
+ expect(await listAlwaysCandidateSkillSlugs()).toEqual([
1072
+ "skills/example-skill-a",
1073
+ ]);
1074
+ });
1075
+ });
1076
+
883
1077
  describe("getSkillCapability", () => {
884
1078
  test("returns null before any seed run", () => {
885
1079
  expect(getSkillCapability("example-skill-a")).toBeNull();
@@ -83,6 +83,7 @@ import {
83
83
  getMemoryCheckpoint,
84
84
  setMemoryCheckpoint,
85
85
  } from "../../../../persistence/checkpoints.js";
86
+ import { MEMORY_V2_CONSOLIDATION_SOURCE } from "../../../../persistence/conversation-types.js";
86
87
  import {
87
88
  enqueueMemoryJob,
88
89
  hasPendingJobOfType,
@@ -99,7 +100,6 @@ import {
99
100
  releaseLock,
100
101
  tryAcquireLock,
101
102
  } from "./consolidation-lock.js";
102
- import { MEMORY_V2_CONSOLIDATION_SOURCE } from "./constants.js";
103
103
  import { getPageIndex, type PageParseFailure } from "./page-index.js";
104
104
  import { resolveConsolidationPrompt } from "./prompts/consolidation.js";
105
105
  import { resolveSubstrateTuning } from "./tuning.js";