@remnic/core 9.3.733 → 9.3.735

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 (304) hide show
  1. package/dist/access-boundary.d.ts +13 -11
  2. package/dist/access-boundary.js +9 -9
  3. package/dist/access-cli.js +26 -24
  4. package/dist/access-cli.js.map +1 -1
  5. package/dist/access-http.d.ts +13 -11
  6. package/dist/access-http.js +14 -14
  7. package/dist/access-mcp.d.ts +13 -11
  8. package/dist/access-mcp.js +13 -13
  9. package/dist/access-operations-batch.js +11 -11
  10. package/dist/access-operations.d.ts +13 -11
  11. package/dist/access-operations.js +12 -12
  12. package/dist/access-schema.d.ts +4 -4
  13. package/dist/{access-service-Byoe3HsT.d.ts → access-service-CVx7mmvK.d.ts} +4 -4
  14. package/dist/access-service.d.ts +13 -11
  15. package/dist/access-service.js +8 -8
  16. package/dist/access-surface-catalog.d.ts +13 -11
  17. package/dist/action-confidence.d.ts +1 -1
  18. package/dist/active-memory-bridge.d.ts +1 -1
  19. package/dist/active-memory-bridge.js +3 -2
  20. package/dist/active-recall.d.ts +1 -1
  21. package/dist/behavior-learner.d.ts +1 -1
  22. package/dist/behavior-signals.d.ts +1 -1
  23. package/dist/bootstrap.d.ts +12 -10
  24. package/dist/briefing.d.ts +1 -1
  25. package/dist/buffer-surprise-report.d.ts +1 -1
  26. package/dist/buffer.d.ts +1 -1
  27. package/dist/calibration.d.ts +1 -1
  28. package/dist/capabilities.d.ts +196 -2
  29. package/dist/capabilities.js +21 -3
  30. package/dist/{catalog-DM1nk7cM.d.ts → catalog-BVhDEUhT.d.ts} +2 -2
  31. package/dist/causal-behavior.d.ts +1 -1
  32. package/dist/causal-consolidation.d.ts +1 -1
  33. package/dist/causal-trajectory-graph.d.ts +1 -1
  34. package/dist/{chunk-CX77GNMB.js → chunk-2T2N7ISV.js} +6 -3
  35. package/dist/chunk-2T2N7ISV.js.map +1 -0
  36. package/dist/{chunk-HHNSLPX7.js → chunk-5BOQNB2K.js} +10 -9
  37. package/dist/chunk-5BOQNB2K.js.map +1 -0
  38. package/dist/{chunk-QZHF4BWN.js → chunk-AAIHDIMD.js} +6 -6
  39. package/dist/{chunk-H3MB3F62.js → chunk-AB2E5DCN.js} +4 -3
  40. package/dist/chunk-AB2E5DCN.js.map +1 -0
  41. package/dist/{chunk-KSJCXXOU.js → chunk-AE7NTZ75.js} +6 -3
  42. package/dist/chunk-AE7NTZ75.js.map +1 -0
  43. package/dist/{chunk-OTQE66IX.js → chunk-AESC5OQJ.js} +6 -3
  44. package/dist/chunk-AESC5OQJ.js.map +1 -0
  45. package/dist/{chunk-FFUCCKPN.js → chunk-BXPG5AVX.js} +10 -7
  46. package/dist/chunk-BXPG5AVX.js.map +1 -0
  47. package/dist/{chunk-P3VJCTVE.js → chunk-CHJIWG2H.js} +4 -3
  48. package/dist/chunk-CHJIWG2H.js.map +1 -0
  49. package/dist/{chunk-FYWUNVFZ.js → chunk-E4LYJ7PY.js} +6 -6
  50. package/dist/{chunk-NIZQH6AU.js → chunk-FF36YNKY.js} +8 -7
  51. package/dist/chunk-FF36YNKY.js.map +1 -0
  52. package/dist/{chunk-OUITHS6V.js → chunk-FLCYY5JX.js} +801 -711
  53. package/dist/chunk-FLCYY5JX.js.map +1 -0
  54. package/dist/{chunk-PLBIPT6I.js → chunk-FLPKEMSO.js} +7 -4
  55. package/dist/chunk-FLPKEMSO.js.map +1 -0
  56. package/dist/{chunk-6TUWSUUD.js → chunk-G54IDCD3.js} +59 -53
  57. package/dist/chunk-G54IDCD3.js.map +1 -0
  58. package/dist/{chunk-J6BH2OBA.js → chunk-GB2FZOWB.js} +8 -5
  59. package/dist/chunk-GB2FZOWB.js.map +1 -0
  60. package/dist/{chunk-CGPHMNL4.js → chunk-GYICIICQ.js} +10 -6
  61. package/dist/chunk-GYICIICQ.js.map +1 -0
  62. package/dist/{chunk-DKT3X5C3.js → chunk-HFXZIF3V.js} +7 -4
  63. package/dist/chunk-HFXZIF3V.js.map +1 -0
  64. package/dist/{chunk-646B5ERJ.js → chunk-HLPYL6LC.js} +71 -65
  65. package/dist/chunk-HLPYL6LC.js.map +1 -0
  66. package/dist/{chunk-ZVHRSR2R.js → chunk-IPI45Q4S.js} +6 -3
  67. package/dist/chunk-IPI45Q4S.js.map +1 -0
  68. package/dist/{chunk-24D66MMN.js → chunk-IX4L7E5G.js} +7 -4
  69. package/dist/chunk-IX4L7E5G.js.map +1 -0
  70. package/dist/{chunk-SYX73XD7.js → chunk-IXGXALRV.js} +10 -7
  71. package/dist/chunk-IXGXALRV.js.map +1 -0
  72. package/dist/{chunk-ESF7TRYJ.js → chunk-JWDE7OVJ.js} +79 -2
  73. package/dist/chunk-JWDE7OVJ.js.map +1 -0
  74. package/dist/{chunk-GGL34GCW.js → chunk-K3Y2SJTN.js} +7 -4
  75. package/dist/chunk-K3Y2SJTN.js.map +1 -0
  76. package/dist/{chunk-PMAQRUN4.js → chunk-NDKW67ER.js} +5 -2
  77. package/dist/chunk-NDKW67ER.js.map +1 -0
  78. package/dist/{chunk-ZQUAVZNG.js → chunk-NNJKEAP2.js} +7 -4
  79. package/dist/chunk-NNJKEAP2.js.map +1 -0
  80. package/dist/{chunk-UZYLX7M6.js → chunk-OYHYBHHI.js} +9 -6
  81. package/dist/chunk-OYHYBHHI.js.map +1 -0
  82. package/dist/{chunk-NOU77OHX.js → chunk-P6VLG7KE.js} +2 -2
  83. package/dist/{chunk-O4ZIBPIW.js → chunk-QNTLWH3T.js} +3 -3
  84. package/dist/{chunk-LUCARK4W.js → chunk-UO6MPN77.js} +37 -35
  85. package/dist/chunk-UO6MPN77.js.map +1 -0
  86. package/dist/{chunk-HJWQJUKQ.js → chunk-VOEVVIP3.js} +3 -3
  87. package/dist/{chunk-KQYGNGON.js → chunk-ZBZ4XULO.js} +6 -3
  88. package/dist/chunk-ZBZ4XULO.js.map +1 -0
  89. package/dist/{cli-Dt-tuiYH.d.ts → cli-Cx5Mxwk7.d.ts} +3 -3
  90. package/dist/cli.d.ts +14 -12
  91. package/dist/cli.js +20 -20
  92. package/dist/compounding/engine.d.ts +3 -2
  93. package/dist/compounding/engine.js +2 -1
  94. package/dist/compounding/preference-consolidator.d.ts +1 -1
  95. package/dist/compression-optimizer.d.ts +1 -1
  96. package/dist/config.d.ts +1 -1
  97. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  98. package/dist/connectors/codex-materialize.d.ts +1 -1
  99. package/dist/connectors/index.d.ts +1 -1
  100. package/dist/consolidation-provenance-check.d.ts +1 -1
  101. package/dist/consolidation-undo.d.ts +1 -1
  102. package/dist/contradiction/index.d.ts +2 -2
  103. package/dist/contradiction/index.js +2 -1
  104. package/dist/{contradiction-scan-HWGEOUDS.js → contradiction-scan-2B4AE4TI.js} +3 -2
  105. package/dist/conversation-index/backend.d.ts +1 -1
  106. package/dist/conversation-index/chunker.d.ts +1 -1
  107. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  108. package/dist/conversation-index/indexer.d.ts +1 -1
  109. package/dist/conversation-index/search.d.ts +1 -1
  110. package/dist/day-summary.d.ts +1 -1
  111. package/dist/delinearize.d.ts +1 -1
  112. package/dist/direct-answer-wiring.d.ts +1 -1
  113. package/dist/direct-answer.d.ts +1 -1
  114. package/dist/embedding-fallback.d.ts +1 -1
  115. package/dist/embedding-fallback.js +2 -2
  116. package/dist/enrichment/index.d.ts +1 -1
  117. package/dist/entity-retrieval.d.ts +1 -1
  118. package/dist/entity-retrieval.js +2 -1
  119. package/dist/entity-schema.d.ts +1 -1
  120. package/dist/explicit-capture.d.ts +12 -10
  121. package/dist/explicit-capture.js +2 -1
  122. package/dist/extraction-faithfulness.d.ts +1 -1
  123. package/dist/extraction-judge-telemetry.d.ts +1 -1
  124. package/dist/extraction-judge-training.d.ts +1 -1
  125. package/dist/extraction-judge.d.ts +1 -1
  126. package/dist/extraction.d.ts +1 -1
  127. package/dist/extraction.js +3 -3
  128. package/dist/fallback-llm.d.ts +1 -1
  129. package/dist/{first-start-migration-OOR57AYR.js → first-start-migration-2RQYDIZ7.js} +10 -8
  130. package/dist/first-start-migration-2RQYDIZ7.js.map +1 -0
  131. package/dist/graph-dashboard-diff.d.ts +1 -1
  132. package/dist/graph-dashboard-key.d.ts +1 -1
  133. package/dist/graph-dashboard-parser.d.ts +1 -1
  134. package/dist/graph-edge-reinforcement.d.ts +1 -1
  135. package/dist/graph-snapshot.d.ts +1 -1
  136. package/dist/graph.d.ts +1 -1
  137. package/dist/identity-continuity.d.ts +1 -1
  138. package/dist/importance.d.ts +1 -1
  139. package/dist/index.d.ts +12 -12
  140. package/dist/index.js +44 -44
  141. package/dist/intent.d.ts +1 -1
  142. package/dist/lcm/engine.d.ts +1 -1
  143. package/dist/lcm/index.d.ts +1 -1
  144. package/dist/lcm/tools.d.ts +1 -1
  145. package/dist/lifecycle.d.ts +1 -1
  146. package/dist/live-connectors-runner.d.ts +1 -1
  147. package/dist/local-llm.d.ts +1 -1
  148. package/dist/local-llm.js +2 -1
  149. package/dist/local-model-endpoint.d.ts +1 -1
  150. package/dist/maintenance/memory-governance.d.ts +1 -1
  151. package/dist/mcp-memory-inspector-app.d.ts +13 -11
  152. package/dist/memory-action-policy.d.ts +1 -1
  153. package/dist/memory-cache.d.ts +1 -1
  154. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  155. package/dist/memory-projection-store.d.ts +1 -1
  156. package/dist/memory-provenance.d.ts +1 -1
  157. package/dist/memory-worth-outcomes.d.ts +1 -1
  158. package/dist/models-json.d.ts +1 -1
  159. package/dist/namespaces/migrate.d.ts +2 -2
  160. package/dist/namespaces/migrate.js +6 -6
  161. package/dist/namespaces/principal.d.ts +1 -1
  162. package/dist/namespaces/principal.js +2 -1
  163. package/dist/namespaces/search.d.ts +1 -1
  164. package/dist/namespaces/search.js +4 -4
  165. package/dist/namespaces/storage.d.ts +2 -2
  166. package/dist/namespaces/storage.js +2 -1
  167. package/dist/native-knowledge.d.ts +1 -1
  168. package/dist/operator-toolkit.d.ts +1 -1
  169. package/dist/operator-toolkit.js +11 -11
  170. package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
  171. package/dist/orchestration/compression-guideline-coordinator.js +2 -1
  172. package/dist/orchestration/maintenance.d.ts +2 -2
  173. package/dist/orchestration/maintenance.js +6 -5
  174. package/dist/{orchestrator-B4KjaOtY.d.ts → orchestrator-oF0cceBX.d.ts} +143 -18
  175. package/dist/orchestrator.d.ts +8 -6
  176. package/dist/orchestrator.js +21 -19
  177. package/dist/patterns-cli.d.ts +1 -1
  178. package/dist/policy-runtime.d.ts +1 -1
  179. package/dist/provenance.d.ts +1 -1
  180. package/dist/qmd-recall-cache.d.ts +1 -1
  181. package/dist/qmd.d.ts +1 -1
  182. package/dist/recall-disclosure-escalation.d.ts +1 -1
  183. package/dist/recall-explain-renderer.d.ts +1 -1
  184. package/dist/recall-planner-llm.d.ts +1 -1
  185. package/dist/recall-state.d.ts +1 -1
  186. package/dist/recall-tag-filter.d.ts +1 -1
  187. package/dist/recall-xray-cli.d.ts +1 -1
  188. package/dist/recall-xray-renderer.d.ts +1 -1
  189. package/dist/recall-xray.d.ts +1 -1
  190. package/dist/resolve-auth-token.d.ts +1 -1
  191. package/dist/retrieval-agents.d.ts +1 -1
  192. package/dist/retrieval-tiers.d.ts +1 -1
  193. package/dist/routing/engine.d.ts +1 -1
  194. package/dist/routing/store.d.ts +1 -1
  195. package/dist/schemas.d.ts +2 -2
  196. package/dist/search/embed-helper.d.ts +1 -1
  197. package/dist/search/embed-helper.js +2 -2
  198. package/dist/search/factory.d.ts +1 -1
  199. package/dist/search/factory.js +3 -3
  200. package/dist/search/index.d.ts +1 -1
  201. package/dist/search/index.js +3 -3
  202. package/dist/search/lancedb-backend.d.ts +1 -1
  203. package/dist/search/meilisearch-backend.d.ts +1 -1
  204. package/dist/search/noop-backend.d.ts +1 -1
  205. package/dist/search/orama-backend.d.ts +1 -1
  206. package/dist/search/port.d.ts +1 -1
  207. package/dist/search/remote-backend.d.ts +1 -1
  208. package/dist/{semantic-SLAa_prH.d.ts → semantic-DJR8_DMQ.d.ts} +1 -1
  209. package/dist/{semantic-consolidation-CstTvHPo.d.ts → semantic-consolidation-DKGbufYO.d.ts} +1 -1
  210. package/dist/semantic-consolidation.d.ts +2 -2
  211. package/dist/semantic-rule-verifier.d.ts +1 -1
  212. package/dist/session-observer-bands.d.ts +1 -1
  213. package/dist/session-observer-state.d.ts +1 -1
  214. package/dist/shared-context/manager.d.ts +3 -3
  215. package/dist/signal.d.ts +1 -1
  216. package/dist/storage.d.ts +1 -1
  217. package/dist/summarizer.d.ts +1 -1
  218. package/dist/summarizer.js +3 -2
  219. package/dist/summary-snapshot.d.ts +1 -1
  220. package/dist/temporal-supersession.d.ts +1 -1
  221. package/dist/temporal-validity.d.ts +1 -1
  222. package/dist/threading.d.ts +1 -1
  223. package/dist/tier-migration.d.ts +1 -1
  224. package/dist/tier-routing.d.ts +1 -1
  225. package/dist/{tier-stats-3LYQ3VV5.js → tier-stats-KPDIISG7.js} +8 -4
  226. package/dist/tier-stats-KPDIISG7.js.map +1 -0
  227. package/dist/topics.d.ts +1 -1
  228. package/dist/transcript.d.ts +1 -1
  229. package/dist/transfer/types.d.ts +30 -30
  230. package/dist/trust-score-stage.d.ts +1 -1
  231. package/dist/trust-score.d.ts +1 -1
  232. package/dist/{types-VkxElCHR.d.ts → types-C7UCxpuO.d.ts} +1 -1
  233. package/dist/types.d.ts +1 -1
  234. package/dist/utility-runtime.d.ts +1 -1
  235. package/package.json +2 -2
  236. package/src/access-service.ts +61 -56
  237. package/src/active-memory-bridge.ts +2 -1
  238. package/src/admin/admin-surfaces.ts +2 -1
  239. package/src/capabilities.test.ts +375 -0
  240. package/src/capabilities.ts +403 -0
  241. package/src/cli/creation-ledger-commands.ts +2 -2
  242. package/src/cli/research-status-commands.ts +13 -13
  243. package/src/cli.ts +29 -25
  244. package/src/compounding/engine.ts +4 -3
  245. package/src/contradiction/contradiction-scan.ts +4 -3
  246. package/src/embedding-fallback.ts +5 -2
  247. package/src/entity-retrieval.ts +3 -2
  248. package/src/explicit-capture.ts +2 -1
  249. package/src/extraction.ts +6 -3
  250. package/src/local-llm.ts +4 -3
  251. package/src/maintenance/first-start-migration.ts +8 -5
  252. package/src/maintenance/namespace-maintenance-fanout.ts +2 -1
  253. package/src/maintenance/namespace-planner.ts +4 -3
  254. package/src/maintenance/tier-stats.ts +4 -3
  255. package/src/namespaces/catalog.ts +2 -1
  256. package/src/namespaces/migrate.ts +2 -1
  257. package/src/namespaces/principal.ts +6 -5
  258. package/src/namespaces/scope-profiles.ts +2 -1
  259. package/src/namespaces/search.ts +2 -1
  260. package/src/namespaces/storage.ts +4 -3
  261. package/src/operator-toolkit.ts +27 -26
  262. package/src/orchestration/compression-guideline-coordinator.ts +7 -6
  263. package/src/orchestration/lifecycle-policy-coordinator.ts +504 -0
  264. package/src/orchestration/maintenance.ts +8 -4
  265. package/src/orchestration/semantic-consolidation-coordinator.ts +454 -0
  266. package/src/orchestration/tier-migration-coordinator.ts +5 -4
  267. package/src/orchestrator.ts +106 -800
  268. package/src/scopes/scope-plan.ts +3 -2
  269. package/src/search/embed-helper.ts +5 -2
  270. package/src/search/factory.ts +9 -6
  271. package/src/summarizer.ts +3 -2
  272. package/dist/chunk-24D66MMN.js.map +0 -1
  273. package/dist/chunk-646B5ERJ.js.map +0 -1
  274. package/dist/chunk-6TUWSUUD.js.map +0 -1
  275. package/dist/chunk-CGPHMNL4.js.map +0 -1
  276. package/dist/chunk-CX77GNMB.js.map +0 -1
  277. package/dist/chunk-DKT3X5C3.js.map +0 -1
  278. package/dist/chunk-ESF7TRYJ.js.map +0 -1
  279. package/dist/chunk-FFUCCKPN.js.map +0 -1
  280. package/dist/chunk-GGL34GCW.js.map +0 -1
  281. package/dist/chunk-H3MB3F62.js.map +0 -1
  282. package/dist/chunk-HHNSLPX7.js.map +0 -1
  283. package/dist/chunk-J6BH2OBA.js.map +0 -1
  284. package/dist/chunk-KQYGNGON.js.map +0 -1
  285. package/dist/chunk-KSJCXXOU.js.map +0 -1
  286. package/dist/chunk-LUCARK4W.js.map +0 -1
  287. package/dist/chunk-NIZQH6AU.js.map +0 -1
  288. package/dist/chunk-OTQE66IX.js.map +0 -1
  289. package/dist/chunk-OUITHS6V.js.map +0 -1
  290. package/dist/chunk-P3VJCTVE.js.map +0 -1
  291. package/dist/chunk-PLBIPT6I.js.map +0 -1
  292. package/dist/chunk-PMAQRUN4.js.map +0 -1
  293. package/dist/chunk-SYX73XD7.js.map +0 -1
  294. package/dist/chunk-UZYLX7M6.js.map +0 -1
  295. package/dist/chunk-ZQUAVZNG.js.map +0 -1
  296. package/dist/chunk-ZVHRSR2R.js.map +0 -1
  297. package/dist/first-start-migration-OOR57AYR.js.map +0 -1
  298. package/dist/tier-stats-3LYQ3VV5.js.map +0 -1
  299. /package/dist/{chunk-QZHF4BWN.js.map → chunk-AAIHDIMD.js.map} +0 -0
  300. /package/dist/{chunk-FYWUNVFZ.js.map → chunk-E4LYJ7PY.js.map} +0 -0
  301. /package/dist/{chunk-NOU77OHX.js.map → chunk-P6VLG7KE.js.map} +0 -0
  302. /package/dist/{chunk-O4ZIBPIW.js.map → chunk-QNTLWH3T.js.map} +0 -0
  303. /package/dist/{chunk-HJWQJUKQ.js.map → chunk-VOEVVIP3.js.map} +0 -0
  304. /package/dist/{contradiction-scan-HWGEOUDS.js.map → contradiction-scan-2B4AE4TI.js.map} +0 -0
@@ -0,0 +1,454 @@
1
+ /**
2
+ * Semantic-consolidation coordinator — extracted from the orchestrator
3
+ * (issue #1526, seam 5).
4
+ *
5
+ * Owns the semantic-consolidation lifecycle: discovering clusters of
6
+ * similar memories, synthesizing a canonical memory per cluster via the
7
+ * LLM (operator-aware or legacy), archiving the superseded sources, and
8
+ * firing post-consolidation hooks (Codex materialize, peer-profile
9
+ * reasoner).
10
+ *
11
+ * The orchestrator constructs one instance and delegates the internal
12
+ * entrypoint (`runSemanticConsolidation`) to it. The public wrappers
13
+ * (`runSemanticConsolidationNow`, `runSemanticConsolidationFanout`)
14
+ * remain on the orchestrator as thin pass-throughs. Storage is the
15
+ * orchestrator's stable `this.storage` (or a per-namespace override
16
+ * passed via options); the fast-tier LLM, content-hash removal, and
17
+ * index save arrive as callbacks so the orchestrator keeps ownership of
18
+ * gateway routing and cross-subsystem persistence.
19
+ *
20
+ * Behavior-preserving move from orchestrator.ts. No logic changes — the
21
+ * orchestrator keeps a thin delegating method so existing call sites
22
+ * and tests that exercise the public API continue to work.
23
+ */
24
+
25
+ import {
26
+ findSimilarClusters,
27
+ buildConsolidationPrompt,
28
+ parseConsolidationResponse,
29
+ buildOperatorAwareConsolidationPrompt,
30
+ parseOperatorAwareConsolidationResponse,
31
+ chooseConsolidationOperator,
32
+ buildExtensionsBlockForConsolidation,
33
+ materializeAfterSemanticConsolidation,
34
+ } from "../semantic-consolidation.js";
35
+ import type {
36
+ SemanticConsolidationLlmOperator,
37
+ SemanticConsolidationResult,
38
+ } from "../semantic-consolidation.js";
39
+ import {
40
+ FallbackLlmClient,
41
+ fallbackLlmRuntimeContextFromConfig,
42
+ gatewayTaskChainOptions,
43
+ } from "../fallback-llm.js";
44
+ import { resolveIndexingCapabilities } from "../capabilities.js";
45
+ import { deindexMemory } from "../temporal-index.js";
46
+ import { runPeerProfileReasoner } from "../peers/index.js";
47
+ import type { StorageManager } from "../index.js";
48
+ import type { LocalLlmClient } from "../local-llm.js";
49
+ import type { EmbeddingFallback } from "../embedding-fallback.js";
50
+ import type { PluginConfig, MemoryFile, AgentPersonaModelConfig } from "../types.js";
51
+ import { log } from "../logger.js";
52
+
53
+ /** Dependencies injected by the orchestrator. All stable references or
54
+ * live accessors. */
55
+ export interface SemanticConsolidationCoordinatorDeps {
56
+ config: PluginConfig;
57
+ /** Live accessor: the orchestrator's storage manager (stable post-ctor). */
58
+ getStorage: () => StorageManager;
59
+ /** Live accessor for the fast-tier local LLM client (falls back to main
60
+ * local LLM when localLlmFastEnabled is false — orchestrator ctor handles
61
+ * this). Injected as an accessor so tests that overwrite orchestrator.fastLlm
62
+ * after construction still take effect. */
63
+ getFastLlm: () => LocalLlmClient;
64
+ /** The embedding-fallback manager used for index cleanup on archival. */
65
+ embeddingFallback: EmbeddingFallback;
66
+ /** Remove a memory's content-hash entry from the storage-scoped index.
67
+ * Delegated to the orchestrator which owns the per-storage index map. */
68
+ removeContentHashForMemory: (
69
+ targetStorage: StorageManager,
70
+ memory: MemoryFile,
71
+ context: string,
72
+ ) => Promise<void>;
73
+ /** Persist all dirty content-hash indexes to disk. */
74
+ saveContentHashIndexes: () => Promise<void>;
75
+ }
76
+
77
+ /**
78
+ * Coordinates semantic consolidation. Holds no mutable state of its own —
79
+ * all persistence flows through the injected storage managers and
80
+ * callbacks.
81
+ */
82
+ export class SemanticConsolidationCoordinator {
83
+ constructor(private readonly deps: SemanticConsolidationCoordinatorDeps) {}
84
+
85
+ private get config(): PluginConfig {
86
+ return this.deps.config;
87
+ }
88
+
89
+ async runSemanticConsolidation(options?: {
90
+ dryRun?: boolean;
91
+ thresholdOverride?: number;
92
+ force?: boolean;
93
+ storage?: StorageManager;
94
+ }): Promise<SemanticConsolidationResult> {
95
+ const targetStorage = options?.storage ?? this.deps.getStorage();
96
+ const result: SemanticConsolidationResult = {
97
+ clustersFound: 0,
98
+ memoriesConsolidated: 0,
99
+ memoriesArchived: 0,
100
+ errors: 0,
101
+ clusters: [],
102
+ };
103
+
104
+ if (!this.config.semanticConsolidationEnabled && !options?.force) {
105
+ log.debug("[semantic-consolidation] disabled in config");
106
+ return result;
107
+ }
108
+
109
+ log.info("[semantic-consolidation] starting run");
110
+
111
+ const allMemories = await targetStorage.readAllMemories();
112
+ if (allMemories.length < 10) {
113
+ log.debug("[semantic-consolidation] too few memories, skipping");
114
+ return result;
115
+ }
116
+
117
+ const threshold =
118
+ options?.thresholdOverride ?? this.config.semanticConsolidationThreshold;
119
+ const clusters = findSimilarClusters(allMemories, {
120
+ threshold,
121
+ minClusterSize: this.config.semanticConsolidationMinClusterSize,
122
+ excludeCategories: this.config.semanticConsolidationExcludeCategories,
123
+ maxPerRun: this.config.semanticConsolidationMaxPerRun,
124
+ });
125
+
126
+ result.clustersFound = clusters.length;
127
+ result.clusters = clusters;
128
+
129
+ if (clusters.length === 0) {
130
+ log.info("[semantic-consolidation] no clusters found");
131
+ return result;
132
+ }
133
+
134
+ log.info(`[semantic-consolidation] found ${clusters.length} cluster(s)`);
135
+
136
+ if (options?.dryRun) {
137
+ log.info(
138
+ "[semantic-consolidation] dry run — skipping LLM synthesis and archival",
139
+ );
140
+ return result;
141
+ }
142
+
143
+ // Use FallbackLlmClient for LLM calls (same pattern as causal-consolidation.ts)
144
+ // Honor semanticConsolidationModel: "auto" = primary, "fast" = local fast, or specific model
145
+ const useGateway = this.config.modelSource === "gateway";
146
+ const modelSetting = this.config.semanticConsolidationModel;
147
+ if (modelSetting === "fast" && this.deps.getFastLlm() && !useGateway) {
148
+ log.info("[semantic-consolidation] using fast local LLM for synthesis");
149
+ }
150
+ // Gateway routing: an explicit "fast" setting keeps the fast persona chain
151
+ // (the operator's deliberate fast-tier choice). Otherwise route through the
152
+ // shared task-chain resolution so taskModelChain applies to semantic
153
+ // consolidation like every other background task (gotcha #22). Issue #1365.
154
+ const gatewayChainOptions: { modelChain?: AgentPersonaModelConfig; agentId?: string } =
155
+ !useGateway
156
+ ? {}
157
+ : modelSetting === "fast"
158
+ ? (this.config.fastGatewayAgentId
159
+ ? { agentId: this.config.fastGatewayAgentId }
160
+ : this.config.gatewayAgentId
161
+ ? { agentId: this.config.gatewayAgentId }
162
+ : {})
163
+ : gatewayTaskChainOptions(this.config);
164
+ const llm = new FallbackLlmClient(
165
+ this.config.gatewayConfig,
166
+ fallbackLlmRuntimeContextFromConfig(this.config),
167
+ );
168
+ if (!llm.isAvailable(gatewayChainOptions) && !(modelSetting === "fast" && this.deps.getFastLlm() && !useGateway)) {
169
+ log.warn(
170
+ "[semantic-consolidation] no LLM available — skipping synthesis",
171
+ );
172
+ return result;
173
+ }
174
+
175
+ // Discover memory extensions once for all clusters (#382)
176
+ let extensionsBlock = "";
177
+ try {
178
+ extensionsBlock = await buildExtensionsBlockForConsolidation(this.config);
179
+ } catch (err) {
180
+ log.warn(`[semantic-consolidation] extension discovery failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
181
+ }
182
+
183
+ for (const cluster of clusters) {
184
+ let canonicalWriteCompleted = false;
185
+ try {
186
+ // Operator-aware prompt (issue #561 PR 3): ask the LLM to pick the
187
+ // SPLIT/MERGE/UPDATE operator alongside the canonical output. Falls
188
+ // back to the legacy plain-blob prompt when operator-aware
189
+ // consolidation is explicitly disabled via config, so rollbacks stay
190
+ // clean.
191
+ // Use the `=== true` idiom for default-false flags (PR #632
192
+ // review, cursor Low): sibling disabled-by-default flags like
193
+ // `semanticConsolidationEnabled` follow the same convention,
194
+ // while `!== false` is reserved for default-on flags.
195
+ const operatorAwareEnabled =
196
+ this.config.operatorAwareConsolidationEnabled === true;
197
+ let prompt = operatorAwareEnabled
198
+ ? buildOperatorAwareConsolidationPrompt(cluster)
199
+ : buildConsolidationPrompt(cluster);
200
+ if (extensionsBlock.length > 0) {
201
+ prompt += "\n\n" + extensionsBlock;
202
+ }
203
+ const messages = [
204
+ {
205
+ role: "system" as const,
206
+ content: operatorAwareEnabled
207
+ ? 'You are a memory consolidation system. Return ONLY a JSON object with two keys, "operator" and "output". The "operator" value MUST be one of the exact strings "merge", "update", or "split" — never a pipe-separated placeholder, never prose. The "output" value is the canonical memory text.'
208
+ : "You are a memory consolidation system. Output only the consolidated memory text.",
209
+ },
210
+ { role: "user" as const, content: prompt },
211
+ ];
212
+ const llmOpts = { temperature: 0.2, maxTokens: 2000 };
213
+
214
+ // Route to the configured model
215
+ let response: { content: string } | null = null;
216
+ if (useGateway) {
217
+ // Gateway model source — use the appropriate agent chain
218
+ response = await llm.chatCompletion(messages, { ...llmOpts, ...gatewayChainOptions });
219
+ } else if (modelSetting === "fast" && this.deps.getFastLlm()) {
220
+ const fastResult = await this.deps.getFastLlm().chatCompletion(messages, {
221
+ operation: "semantic-consolidation",
222
+ maxTokens: llmOpts.maxTokens,
223
+ temperature: llmOpts.temperature,
224
+ priority: "background",
225
+ forceDisableThinking: true,
226
+ });
227
+ response = fastResult ? { content: fastResult.content } : null;
228
+ } else {
229
+ response = await llm.chatCompletion(messages, llmOpts);
230
+ }
231
+
232
+ if (!response?.content) {
233
+ log.warn(
234
+ `[semantic-consolidation] empty LLM response for cluster in "${cluster.category}"`,
235
+ );
236
+ result.errors++;
237
+ continue;
238
+ }
239
+
240
+ // Operator-aware parse (issue #561 PR 3). In legacy mode we fall
241
+ // back to the plain-text parser and derive the operator from the
242
+ // cluster-shape heuristic so `derived_via` still lands.
243
+ // Restricted to `SemanticConsolidationLlmOperator`
244
+ // (split/merge/update) — `pattern-reinforcement` joined the
245
+ // wider `ConsolidationOperator` type in #687 PR 2/4 but is
246
+ // reserved for the maintenance job and must never be assignable
247
+ // here (Cursor Bugbot review, PR #730).
248
+ let canonicalContent: string;
249
+ let operator: SemanticConsolidationLlmOperator;
250
+ if (operatorAwareEnabled) {
251
+ const parsed = parseOperatorAwareConsolidationResponse(
252
+ response.content,
253
+ cluster,
254
+ );
255
+ canonicalContent = parsed.output;
256
+ operator = parsed.operator;
257
+ } else {
258
+ canonicalContent = parseConsolidationResponse(response.content);
259
+ operator = chooseConsolidationOperator(cluster);
260
+ }
261
+ cluster.canonicalContent = canonicalContent;
262
+
263
+ // Pick the most recent memory's metadata as the basis for lineage
264
+ const sorted = [...cluster.memories].sort(
265
+ (a, b) =>
266
+ new Date(b.frontmatter.created).getTime() -
267
+ new Date(a.frontmatter.created).getTime(),
268
+ );
269
+ const newest = sorted[0];
270
+ const lineageIds = cluster.memories.map((m) => m.frontmatter.id);
271
+
272
+ // Consolidation provenance (issue #561 PR 2+3): snapshot each
273
+ // source memory BEFORE archiving it, collecting
274
+ // "<relpath>:<versionId>" pointers for the new canonical memory's
275
+ // `derived_from` frontmatter field. Snapshots are best-effort — if
276
+ // page-versioning is disabled (default in `config.ts`) or a single
277
+ // source fails to snapshot we simply omit that entry rather than
278
+ // abort the consolidation. The `derived_via` operator is chosen
279
+ // above (PR 3) from the LLM response or the cluster-shape
280
+ // heuristic fallback and emitted unconditionally so consolidation
281
+ // outputs stay identifiable even when no snapshots are captured
282
+ // (PR #624 review feedback).
283
+ const derivedFromEntries: string[] = [];
284
+ for (const m of cluster.memories) {
285
+ if (!m.path) continue;
286
+ const entry = await targetStorage.snapshotForProvenance(m.path);
287
+ if (entry) derivedFromEntries.push(entry);
288
+ }
289
+
290
+ // Write the canonical memory
291
+ const { id: canonicalId, tombstoneBlocked: canonicalBlocked } = await targetStorage.writeMemory(
292
+ newest.frontmatter.category,
293
+ canonicalContent,
294
+ {
295
+ actor: "semantic-consolidation",
296
+ confidence: newest.frontmatter.confidence,
297
+ tags: [
298
+ ...new Set(
299
+ cluster.memories.flatMap((m) => m.frontmatter.tags ?? []),
300
+ ),
301
+ ],
302
+ source: "semantic-consolidation",
303
+ lineage: lineageIds,
304
+ derivedFrom: derivedFromEntries.length > 0 ? derivedFromEntries : undefined,
305
+ derivedVia: operator,
306
+ },
307
+ );
308
+ if (canonicalBlocked) {
309
+ // #1645: canonical matched a tombstone (pending_review). Don't archive
310
+ // the sources — consolidation must never delete the only active copy.
311
+ log.info(`[semantic-consolidation] cluster in "${cluster.category}" tombstone-blocked — keeping ${cluster.memories.length} source(s) active (pending_review ${canonicalId})`);
312
+ continue;
313
+ }
314
+ canonicalWriteCompleted = true;
315
+
316
+ result.memoriesConsolidated++;
317
+
318
+ // Archive originals
319
+ for (const m of cluster.memories) {
320
+ const archiveResult = await targetStorage.archiveMemory(m, {
321
+ actor: "semantic-consolidation",
322
+ reasonCode: "semantic-consolidation",
323
+ relatedMemoryIds: [canonicalId],
324
+ });
325
+ if (archiveResult) {
326
+ // Remove from the same storage-scoped content-hash index that
327
+ // originally deduped this memory.
328
+ await this.deps.removeContentHashForMemory(
329
+ targetStorage,
330
+ m,
331
+ "semantic-consolidation",
332
+ );
333
+ // Best-effort index cleanup: a failure here (e.g. on-disk index save
334
+ // under disk-full) must NOT abort the archival loop and thereby skip
335
+ // the catalog write touch below for an already-durable canonical write
336
+ // (kilo NV0mh).
337
+ try {
338
+ await this.deps.embeddingFallback.removeFromIndex(m.frontmatter.id);
339
+ if (
340
+ resolveIndexingCapabilities(this.config).queryAwareIndexing &&
341
+ m.path &&
342
+ m.frontmatter?.created
343
+ ) {
344
+ deindexMemory(
345
+ targetStorage.dir,
346
+ m.path,
347
+ m.frontmatter.created,
348
+ m.frontmatter.tags ?? [],
349
+ );
350
+ }
351
+ } catch (cleanupErr) {
352
+ log.warn(
353
+ `[semantic-consolidation] index cleanup failed (non-fatal): ${cleanupErr}`,
354
+ );
355
+ }
356
+ result.memoriesArchived++;
357
+ }
358
+ }
359
+
360
+ log.info(
361
+ `[semantic-consolidation] consolidated ${cluster.memories.length} memories → ${canonicalId}`,
362
+ );
363
+ } catch (err) {
364
+ log.warn(
365
+ `[semantic-consolidation] cluster processing failed: ${err instanceof Error ? err.message : String(err)}`,
366
+ );
367
+ result.errors++;
368
+ } finally {
369
+ if (canonicalWriteCompleted) {
370
+ // Catalog write touch (issue #1499 sweep): record after the canonical
371
+ // write and, on the happy path, after archival of superseded cluster
372
+ // memories, so `lastWriteAt` reflects every durable mutation in this
373
+ // consolidation (cursor NUtCK). The `finally` also covers partial
374
+ // failures where the canonical memory was written but a later archive
375
+ // step throws and the cluster catch continues (codex NY-dK).
376
+ // Best-effort; namespace decoded from the storage dir since this path
377
+ // #1522: catalog touch handled at the storage chokepoint.
378
+ }
379
+ }
380
+ }
381
+
382
+ // Save hash indexes if we modified them.
383
+ if (result.memoriesArchived > 0) {
384
+ await this.deps.saveContentHashIndexes().catch((err) =>
385
+ log.warn(
386
+ `[semantic-consolidation] content-hash index save failed: ${err}`,
387
+ ),
388
+ );
389
+ }
390
+
391
+ log.info(
392
+ `[semantic-consolidation] complete: clusters=${result.clustersFound}, consolidated=${result.memoriesConsolidated}, archived=${result.memoriesArchived}, errors=${result.errors}`,
393
+ );
394
+
395
+ // #378: fire the Codex materialize post-hook so `codexMaterializeOnConsolidation`
396
+ // actually has a runtime effect. The helper silently no-ops when the
397
+ // feature flag or the per-trigger toggle is off, when the sentinel is
398
+ // missing, or when nothing has changed since the previous run, so it's
399
+ // safe to always call here. Wrapped in a try/catch because a failed
400
+ // materialize must never abort the consolidation result — consolidation
401
+ // is the load-bearing operation; materialization is an optional mirror.
402
+ try {
403
+ await materializeAfterSemanticConsolidation({
404
+ config: this.config,
405
+ memoryDir: targetStorage.dir,
406
+ });
407
+ } catch (err) {
408
+ log.warn(
409
+ `[semantic-consolidation] Codex materialize post-hook failed (non-fatal): ${
410
+ err instanceof Error ? err.message : String(err)
411
+ }`,
412
+ );
413
+ }
414
+
415
+ // Issue #679 PR 2/5 — async peer profile reasoner runs as part of
416
+ // the REM phase, immediately after semantic consolidation. Gated
417
+ // on `peerProfileReasonerEnabled` (default false, opt-in). Wrapped
418
+ // in a try/catch because reasoner I/O (LLM call, peer-profile
419
+ // writes) must never abort the consolidation result. The reasoner
420
+ // itself also defends against partial failure — see profile-reasoner.ts.
421
+ if (this.config.peerProfileReasonerEnabled) {
422
+ try {
423
+ const peerLlm = new FallbackLlmClient(
424
+ this.config.gatewayConfig,
425
+ fallbackLlmRuntimeContextFromConfig(this.config),
426
+ );
427
+ const peerResult = await runPeerProfileReasoner({
428
+ memoryDir: targetStorage.dir,
429
+ enabled: true,
430
+ llm: peerLlm,
431
+ model: this.config.peerProfileReasonerModel,
432
+ minInteractions: this.config.peerProfileReasonerMinInteractions,
433
+ maxFieldsPerRun: this.config.peerProfileReasonerMaxFieldsPerRun,
434
+ log: {
435
+ debug: (msg) => log.debug(msg),
436
+ info: (msg) => log.info(msg),
437
+ warn: (msg) => log.warn(msg),
438
+ },
439
+ });
440
+ log.info(
441
+ `[peer-profile-reasoner] complete: peers=${peerResult.peersConsidered}, processed=${peerResult.peersProcessed}, fields=${peerResult.fieldsApplied}`,
442
+ );
443
+ } catch (err) {
444
+ log.warn(
445
+ `[peer-profile-reasoner] post-consolidation hook failed (non-fatal): ${
446
+ err instanceof Error ? err.message : String(err)
447
+ }`,
448
+ );
449
+ }
450
+ }
451
+
452
+ return result;
453
+ }
454
+ }
@@ -42,6 +42,7 @@ import {
42
42
  } from "../utility-runtime.js";
43
43
  import type { PluginConfig, MemoryFile } from "../types.js";
44
44
  import { log } from "../logger.js";
45
+ import { resolveQmdCapabilities } from "../capabilities.js";
45
46
 
46
47
  /** Dependencies injected by the orchestrator. All stable references or live
47
48
  * accessors (the orchestrator reassigns `qmd` to NoopSearchBackend and
@@ -97,7 +98,7 @@ export class TierMigrationCoordinator {
97
98
  const { config, tierMigrationStatus } = this.deps;
98
99
  const dryRun = options?.dryRun === true;
99
100
  const persistSkipped = options?.force === true || trigger === "manual";
100
- if (!config.qmdTierMigrationEnabled && options?.force !== true) {
101
+ if (!resolveQmdCapabilities(config).qmdTierMigration && options?.force !== true) {
101
102
  const skipped: TierMigrationCycleSummary = {
102
103
  trigger,
103
104
  scanned: 0,
@@ -113,7 +114,7 @@ export class TierMigrationCoordinator {
113
114
  }
114
115
  if (
115
116
  trigger === "maintenance" &&
116
- !config.qmdTierAutoBackfillEnabled &&
117
+ !resolveQmdCapabilities(config).qmdTierAutoBackfill &&
117
118
  options?.force !== true
118
119
  ) {
119
120
  const skipped: TierMigrationCycleSummary = {
@@ -173,7 +174,7 @@ export class TierMigrationCoordinator {
173
174
 
174
175
  const policy = applyUtilityPromotionRuntimePolicy(
175
176
  {
176
- enabled: config.qmdTierMigrationEnabled,
177
+ enabled: resolveQmdCapabilities(config).qmdTierMigration,
177
178
  demotionMinAgeDays: config.qmdTierDemotionMinAgeDays,
178
179
  demotionValueThreshold: config.qmdTierDemotionValueThreshold,
179
180
  promotionValueThreshold: config.qmdTierPromotionValueThreshold,
@@ -218,7 +219,7 @@ export class TierMigrationCoordinator {
218
219
  hotCollection: config.qmdCollection,
219
220
  coldCollection:
220
221
  config.qmdColdCollection ?? `${config.qmdCollection}-cold`,
221
- autoEmbed: config.qmdAutoEmbedEnabled,
222
+ autoEmbed: resolveQmdCapabilities(config).qmdAutoEmbed,
222
223
  });
223
224
 
224
225
  let migrated = 0;