@remnic/core 9.3.738 → 9.3.740

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 (200) hide show
  1. package/dist/access-boundary.d.ts +6 -6
  2. package/dist/access-boundary.js +13 -13
  3. package/dist/access-cli.js +35 -35
  4. package/dist/access-http.d.ts +6 -6
  5. package/dist/access-http.js +18 -18
  6. package/dist/access-mcp.d.ts +6 -6
  7. package/dist/access-mcp.js +17 -17
  8. package/dist/access-operations-batch.js +15 -15
  9. package/dist/access-operations.d.ts +6 -6
  10. package/dist/access-operations.js +16 -16
  11. package/dist/{access-service-DwQ6BIQw.d.ts → access-service-Cbk-Kv_A.d.ts} +1 -1
  12. package/dist/access-service.d.ts +6 -6
  13. package/dist/access-service.js +12 -12
  14. package/dist/access-surface-catalog.d.ts +6 -6
  15. package/dist/active-memory-bridge.js +3 -3
  16. package/dist/bootstrap.d.ts +5 -5
  17. package/dist/briefing.js +2 -2
  18. package/dist/buffer.js +2 -2
  19. package/dist/capabilities.d.ts +97 -1
  20. package/dist/capabilities.js +7 -1
  21. package/dist/causal-consolidation.js +4 -3
  22. package/dist/causal-consolidation.js.map +1 -1
  23. package/dist/{chunk-IFCM6OLK.js → chunk-3TUDKDTQ.js} +7 -7
  24. package/dist/{chunk-A7INTIC5.js → chunk-4J53ZVPQ.js} +3 -3
  25. package/dist/{chunk-XYUFGHUW.js → chunk-56F6EAQ6.js} +2 -2
  26. package/dist/{chunk-F6OEXJQQ.js → chunk-6XG3NQRC.js} +2 -2
  27. package/dist/{chunk-24ZLC5QN.js → chunk-7N7S2RKF.js} +2 -2
  28. package/dist/{chunk-Y5OOHER4.js → chunk-7Y5KKMIP.js} +12 -11
  29. package/dist/chunk-7Y5KKMIP.js.map +1 -0
  30. package/dist/{chunk-VRBBZH4U.js → chunk-AX4TRSRE.js} +3 -3
  31. package/dist/{chunk-66RZ4EIT.js → chunk-BE6NEQLF.js} +3 -3
  32. package/dist/{chunk-YF2MMBKA.js → chunk-BJPL5WAL.js} +3 -3
  33. package/dist/{chunk-EO5QWINU.js → chunk-C3Z5YJSM.js} +5 -2
  34. package/dist/chunk-C3Z5YJSM.js.map +1 -0
  35. package/dist/{chunk-GEXI357K.js → chunk-C7C5WIIF.js} +2 -2
  36. package/dist/{chunk-L3TYGUTH.js → chunk-CMPXLMC3.js} +3 -3
  37. package/dist/{chunk-W2FBVBQ4.js → chunk-DBVBV2RF.js} +4 -4
  38. package/dist/{chunk-JQSP7YBJ.js → chunk-ELL5VYXC.js} +5 -4
  39. package/dist/chunk-ELL5VYXC.js.map +1 -0
  40. package/dist/{chunk-IQOEW5YV.js → chunk-FCQ7ZYCQ.js} +2 -2
  41. package/dist/{chunk-IIBFCZA7.js → chunk-FWXLKH2H.js} +3 -3
  42. package/dist/{chunk-RJBW4EOU.js → chunk-G7Q4D2G3.js} +74 -2
  43. package/dist/{chunk-RJBW4EOU.js.map → chunk-G7Q4D2G3.js.map} +1 -1
  44. package/dist/{chunk-WVAEIKUY.js → chunk-GPX5E36D.js} +5 -4
  45. package/dist/chunk-GPX5E36D.js.map +1 -0
  46. package/dist/{chunk-23PLOBWT.js → chunk-H3WSZWHK.js} +22 -20
  47. package/dist/chunk-H3WSZWHK.js.map +1 -0
  48. package/dist/{chunk-Q6BAA57B.js → chunk-JFCS6PQU.js} +2 -2
  49. package/dist/chunk-JFCS6PQU.js.map +1 -0
  50. package/dist/{chunk-CKHPUOAP.js → chunk-K2N6WIZM.js} +3 -3
  51. package/dist/{chunk-BHJAMSVC.js → chunk-LD6A7XG5.js} +7 -7
  52. package/dist/{chunk-AKKFHN3I.js → chunk-M4WI23X3.js} +2 -2
  53. package/dist/{chunk-N2O23WYA.js → chunk-M5KLYHHI.js} +2 -2
  54. package/dist/{chunk-TNLXCSXV.js → chunk-O4IWVWSW.js} +5 -4
  55. package/dist/chunk-O4IWVWSW.js.map +1 -0
  56. package/dist/{chunk-OQQRWPFZ.js → chunk-OS5RKJOH.js} +2 -2
  57. package/dist/{chunk-MAU7DFCJ.js → chunk-OT5K26NG.js} +5 -4
  58. package/dist/chunk-OT5K26NG.js.map +1 -0
  59. package/dist/{chunk-DS3FZ7GS.js → chunk-OUSOMUFV.js} +2 -2
  60. package/dist/{chunk-7B7IPPN5.js → chunk-OVYBENIJ.js} +3 -3
  61. package/dist/{chunk-5RZOFIDL.js → chunk-PI4JHLDD.js} +6 -3
  62. package/dist/chunk-PI4JHLDD.js.map +1 -0
  63. package/dist/{chunk-EU543UDC.js → chunk-QCO2QFLZ.js} +7 -7
  64. package/dist/chunk-QCO2QFLZ.js.map +1 -0
  65. package/dist/{chunk-YXOXAQ5Y.js → chunk-TQQN64J2.js} +5 -4
  66. package/dist/chunk-TQQN64J2.js.map +1 -0
  67. package/dist/{chunk-WDJCZQB4.js → chunk-UGFPGWJB.js} +2 -2
  68. package/dist/{chunk-75PDC7VT.js → chunk-UOVDO6TC.js} +6 -5
  69. package/dist/chunk-UOVDO6TC.js.map +1 -0
  70. package/dist/{chunk-BVG2IZOB.js → chunk-USHVHI6J.js} +7 -6
  71. package/dist/chunk-USHVHI6J.js.map +1 -0
  72. package/dist/{chunk-56LP72AD.js → chunk-UYYSOMS2.js} +4 -4
  73. package/dist/{chunk-EKQ3LWBM.js → chunk-VC7QELR6.js} +659 -584
  74. package/dist/chunk-VC7QELR6.js.map +1 -0
  75. package/dist/{chunk-XIQAOGAA.js → chunk-WGDE2TJP.js} +7 -6
  76. package/dist/chunk-WGDE2TJP.js.map +1 -0
  77. package/dist/{chunk-UFS7OXGL.js → chunk-WHEF76BQ.js} +5 -2
  78. package/dist/chunk-WHEF76BQ.js.map +1 -0
  79. package/dist/{chunk-QTJOORGN.js → chunk-WIMKOTNY.js} +2 -2
  80. package/dist/{chunk-GXTYEG7Q.js → chunk-WO22UEM3.js} +2 -2
  81. package/dist/{chunk-BHQQVUEQ.js → chunk-X5PMDVY4.js} +6 -5
  82. package/dist/{chunk-BHQQVUEQ.js.map → chunk-X5PMDVY4.js.map} +1 -1
  83. package/dist/{chunk-C53JDEH3.js → chunk-Y62QPRKV.js} +2 -2
  84. package/dist/{chunk-WFNH4UDF.js → chunk-Y6PNYJVO.js} +3 -3
  85. package/dist/{chunk-6YKIYQU7.js → chunk-YNHRWFAP.js} +5 -2
  86. package/dist/{chunk-6YKIYQU7.js.map → chunk-YNHRWFAP.js.map} +1 -1
  87. package/dist/{cli-BlEIWDQw.d.ts → cli-BQW2xKdb.d.ts} +2 -2
  88. package/dist/cli.d.ts +7 -7
  89. package/dist/cli.js +29 -29
  90. package/dist/compounding/engine.js +4 -4
  91. package/dist/connectors/codex-materialize-runner.js +2 -2
  92. package/dist/connectors/index.js +4 -3
  93. package/dist/contradiction/index.js +2 -2
  94. package/dist/{contradiction-scan-CWO3LIWV.js → contradiction-scan-UERKJESC.js} +3 -3
  95. package/dist/day-summary.js +2 -1
  96. package/dist/embedding-fallback.js +2 -2
  97. package/dist/entity-retrieval.js +3 -3
  98. package/dist/explicit-capture.d.ts +5 -5
  99. package/dist/explicit-capture.js +2 -2
  100. package/dist/extraction.js +4 -4
  101. package/dist/{first-start-migration-5DXD3TF2.js → first-start-migration-GQ3UQNIL.js} +2 -2
  102. package/dist/index.d.ts +8 -8
  103. package/dist/index.js +45 -45
  104. package/dist/local-llm.js +2 -2
  105. package/dist/maintenance/memory-governance.js +2 -2
  106. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +2 -2
  107. package/dist/maintenance/rebuild-memory-projection.js +3 -3
  108. package/dist/mcp-memory-inspector-app.d.ts +6 -6
  109. package/dist/namespaces/migrate.js +7 -7
  110. package/dist/namespaces/principal.js +2 -2
  111. package/dist/namespaces/search.js +4 -4
  112. package/dist/namespaces/storage.js +3 -3
  113. package/dist/operator-toolkit.js +13 -13
  114. package/dist/orchestration/compression-guideline-coordinator.js +2 -2
  115. package/dist/orchestration/maintenance.js +7 -7
  116. package/dist/{orchestrator-CJZ21ZiB.d.ts → orchestrator-BOAFN_Yr.d.ts} +186 -56
  117. package/dist/orchestrator.d.ts +4 -4
  118. package/dist/orchestrator.js +29 -29
  119. package/dist/search/embed-helper.js +2 -2
  120. package/dist/search/factory.js +3 -3
  121. package/dist/search/index.js +3 -3
  122. package/dist/semantic-consolidation.js +4 -3
  123. package/dist/semantic-rule-promotion.js +2 -2
  124. package/dist/semantic-rule-verifier.js +2 -2
  125. package/dist/shared-context/manager.js +2 -1
  126. package/dist/storage.d.ts +1 -1
  127. package/dist/storage.js +1 -1
  128. package/dist/summarizer.js +3 -3
  129. package/dist/{tier-stats-QID73BBB.js → tier-stats-CSKL7BDG.js} +2 -2
  130. package/dist/verified-recall.js +2 -2
  131. package/package.json +2 -2
  132. package/src/access-service.ts +2 -1
  133. package/src/capabilities.test.ts +166 -0
  134. package/src/capabilities.ts +267 -0
  135. package/src/cli/research-status-commands.ts +2 -1
  136. package/src/cli.ts +3 -2
  137. package/src/compounding/engine.ts +2 -1
  138. package/src/connectors/codex-marketplace.ts +2 -1
  139. package/src/day-summary.ts +2 -1
  140. package/src/embedding-fallback.ts +2 -1
  141. package/src/extraction.ts +3 -2
  142. package/src/local-llm.ts +2 -1
  143. package/src/maintenance/namespace-maintenance-fanout.ts +2 -1
  144. package/src/maintenance/namespace-planner.ts +2 -1
  145. package/src/operator-toolkit.ts +1 -0
  146. package/src/orchestration/conversation-index-coordinator.ts +344 -0
  147. package/src/orchestration/recall-rerank-coordinator.ts +425 -0
  148. package/src/orchestration/semantic-consolidation-coordinator.ts +3 -2
  149. package/src/orchestrator.ts +89 -598
  150. package/src/search/embed-helper.ts +2 -1
  151. package/src/search/factory.ts +2 -1
  152. package/src/semantic-consolidation.ts +2 -1
  153. package/src/shared-context/manager.ts +3 -2
  154. package/src/storage.ts +1 -1
  155. package/src/summarizer.ts +3 -2
  156. package/dist/chunk-23PLOBWT.js.map +0 -1
  157. package/dist/chunk-5RZOFIDL.js.map +0 -1
  158. package/dist/chunk-75PDC7VT.js.map +0 -1
  159. package/dist/chunk-BVG2IZOB.js.map +0 -1
  160. package/dist/chunk-EKQ3LWBM.js.map +0 -1
  161. package/dist/chunk-EO5QWINU.js.map +0 -1
  162. package/dist/chunk-EU543UDC.js.map +0 -1
  163. package/dist/chunk-JQSP7YBJ.js.map +0 -1
  164. package/dist/chunk-MAU7DFCJ.js.map +0 -1
  165. package/dist/chunk-Q6BAA57B.js.map +0 -1
  166. package/dist/chunk-TNLXCSXV.js.map +0 -1
  167. package/dist/chunk-UFS7OXGL.js.map +0 -1
  168. package/dist/chunk-WVAEIKUY.js.map +0 -1
  169. package/dist/chunk-XIQAOGAA.js.map +0 -1
  170. package/dist/chunk-Y5OOHER4.js.map +0 -1
  171. package/dist/chunk-YXOXAQ5Y.js.map +0 -1
  172. /package/dist/{chunk-IFCM6OLK.js.map → chunk-3TUDKDTQ.js.map} +0 -0
  173. /package/dist/{chunk-A7INTIC5.js.map → chunk-4J53ZVPQ.js.map} +0 -0
  174. /package/dist/{chunk-XYUFGHUW.js.map → chunk-56F6EAQ6.js.map} +0 -0
  175. /package/dist/{chunk-F6OEXJQQ.js.map → chunk-6XG3NQRC.js.map} +0 -0
  176. /package/dist/{chunk-24ZLC5QN.js.map → chunk-7N7S2RKF.js.map} +0 -0
  177. /package/dist/{chunk-VRBBZH4U.js.map → chunk-AX4TRSRE.js.map} +0 -0
  178. /package/dist/{chunk-66RZ4EIT.js.map → chunk-BE6NEQLF.js.map} +0 -0
  179. /package/dist/{chunk-YF2MMBKA.js.map → chunk-BJPL5WAL.js.map} +0 -0
  180. /package/dist/{chunk-GEXI357K.js.map → chunk-C7C5WIIF.js.map} +0 -0
  181. /package/dist/{chunk-L3TYGUTH.js.map → chunk-CMPXLMC3.js.map} +0 -0
  182. /package/dist/{chunk-W2FBVBQ4.js.map → chunk-DBVBV2RF.js.map} +0 -0
  183. /package/dist/{chunk-IQOEW5YV.js.map → chunk-FCQ7ZYCQ.js.map} +0 -0
  184. /package/dist/{chunk-IIBFCZA7.js.map → chunk-FWXLKH2H.js.map} +0 -0
  185. /package/dist/{chunk-CKHPUOAP.js.map → chunk-K2N6WIZM.js.map} +0 -0
  186. /package/dist/{chunk-BHJAMSVC.js.map → chunk-LD6A7XG5.js.map} +0 -0
  187. /package/dist/{chunk-AKKFHN3I.js.map → chunk-M4WI23X3.js.map} +0 -0
  188. /package/dist/{chunk-N2O23WYA.js.map → chunk-M5KLYHHI.js.map} +0 -0
  189. /package/dist/{chunk-OQQRWPFZ.js.map → chunk-OS5RKJOH.js.map} +0 -0
  190. /package/dist/{chunk-DS3FZ7GS.js.map → chunk-OUSOMUFV.js.map} +0 -0
  191. /package/dist/{chunk-7B7IPPN5.js.map → chunk-OVYBENIJ.js.map} +0 -0
  192. /package/dist/{chunk-WDJCZQB4.js.map → chunk-UGFPGWJB.js.map} +0 -0
  193. /package/dist/{chunk-56LP72AD.js.map → chunk-UYYSOMS2.js.map} +0 -0
  194. /package/dist/{chunk-QTJOORGN.js.map → chunk-WIMKOTNY.js.map} +0 -0
  195. /package/dist/{chunk-GXTYEG7Q.js.map → chunk-WO22UEM3.js.map} +0 -0
  196. /package/dist/{chunk-C53JDEH3.js.map → chunk-Y62QPRKV.js.map} +0 -0
  197. /package/dist/{chunk-WFNH4UDF.js.map → chunk-Y6PNYJVO.js.map} +0 -0
  198. /package/dist/{contradiction-scan-CWO3LIWV.js.map → contradiction-scan-UERKJESC.js.map} +0 -0
  199. /package/dist/{first-start-migration-5DXD3TF2.js.map → first-start-migration-GQ3UQNIL.js.map} +0 -0
  200. /package/dist/{tier-stats-QID73BBB.js.map → tier-stats-CSKL7BDG.js.map} +0 -0
@@ -7,10 +7,10 @@ import {
7
7
  } from "./chunk-OZECYVGI.js";
8
8
  import {
9
9
  CompressionGuidelineCoordinator
10
- } from "./chunk-QTJOORGN.js";
10
+ } from "./chunk-WIMKOTNY.js";
11
11
  import {
12
12
  MaintenanceScheduler
13
- } from "./chunk-YF2MMBKA.js";
13
+ } from "./chunk-BJPL5WAL.js";
14
14
  import {
15
15
  runPeerProfileReasoner
16
16
  } from "./chunk-I74SUMNI.js";
@@ -29,10 +29,10 @@ import {
29
29
  import {
30
30
  CompoundingEngine,
31
31
  defaultTierMigrationCycleBudget
32
- } from "./chunk-75PDC7VT.js";
32
+ } from "./chunk-UOVDO6TC.js";
33
33
  import {
34
34
  SharedContextManager
35
- } from "./chunk-UFS7OXGL.js";
35
+ } from "./chunk-WHEF76BQ.js";
36
36
  import {
37
37
  applyTrustScoreStage,
38
38
  buildTrustSignalsForRerank,
@@ -63,7 +63,7 @@ import {
63
63
  } from "./chunk-UHGBNIOS.js";
64
64
  import {
65
65
  HourlySummarizer
66
- } from "./chunk-BVG2IZOB.js";
66
+ } from "./chunk-USHVHI6J.js";
67
67
  import {
68
68
  buildTargetedFactRecallSection,
69
69
  shouldRecallTargetedFactEvidence
@@ -160,7 +160,7 @@ import {
160
160
  } from "./chunk-LTHVM4XN.js";
161
161
  import {
162
162
  ExtractionEngine
163
- } from "./chunk-XIQAOGAA.js";
163
+ } from "./chunk-WGDE2TJP.js";
164
164
  import {
165
165
  parseMemoryActionEligibilityContext
166
166
  } from "./chunk-5GSUBCZM.js";
@@ -169,7 +169,7 @@ import {
169
169
  } from "./chunk-PWFWCGOO.js";
170
170
  import {
171
171
  LocalLlmClient
172
- } from "./chunk-YXOXAQ5Y.js";
172
+ } from "./chunk-TQQN64J2.js";
173
173
  import {
174
174
  buildFocusedListRecallSection,
175
175
  shouldRecallFocusedListEvidence
@@ -187,18 +187,18 @@ import {
187
187
  } from "./chunk-4463LUIE.js";
188
188
  import {
189
189
  formatDaySummaryMemories
190
- } from "./chunk-EO5QWINU.js";
190
+ } from "./chunk-C3Z5YJSM.js";
191
191
  import {
192
192
  tryDirectAnswer
193
193
  } from "./chunk-Q6IP2ARR.js";
194
194
  import {
195
195
  EmbeddingFallback
196
- } from "./chunk-WVAEIKUY.js";
196
+ } from "./chunk-GPX5E36D.js";
197
197
  import {
198
198
  buildEntityRecallSection,
199
199
  entityRecentTranscriptLookbackHours,
200
200
  readRecentEntityTranscriptEntries
201
- } from "./chunk-CKHPUOAP.js";
201
+ } from "./chunk-K2N6WIZM.js";
202
202
  import {
203
203
  RoutingRulesStore
204
204
  } from "./chunk-WIWPSQYU.js";
@@ -208,14 +208,14 @@ import {
208
208
  import {
209
209
  compareVerifiedEpisodeResults,
210
210
  searchVerifiedEpisodes
211
- } from "./chunk-WDJCZQB4.js";
211
+ } from "./chunk-UGFPGWJB.js";
212
212
  import {
213
213
  ThreadingManager
214
214
  } from "./chunk-QRDOSYOR.js";
215
215
  import {
216
216
  compareVerifiedSemanticRuleResults,
217
217
  searchVerifiedSemanticRules
218
- } from "./chunk-IQOEW5YV.js";
218
+ } from "./chunk-FCQ7ZYCQ.js";
219
219
  import {
220
220
  searchWorkProductLedgerEntries
221
221
  } from "./chunk-ZRWB5D4H.js";
@@ -228,14 +228,14 @@ import {
228
228
  import {
229
229
  runNamespaceMaintenanceFanout,
230
230
  summarizeNamespaceMaintenanceHealth
231
- } from "./chunk-TNLXCSXV.js";
231
+ } from "./chunk-O4IWVWSW.js";
232
232
  import {
233
233
  NamespaceCatalog,
234
234
  planNamespaceMaintenance
235
- } from "./chunk-BHQQVUEQ.js";
235
+ } from "./chunk-X5PMDVY4.js";
236
236
  import {
237
237
  NamespaceStorageRouter
238
- } from "./chunk-VRBBZH4U.js";
238
+ } from "./chunk-AX4TRSRE.js";
239
239
  import {
240
240
  searchHarmonicRetrieval
241
241
  } from "./chunk-AV5ZEH4M.js";
@@ -270,7 +270,7 @@ import {
270
270
  materializeAfterSemanticConsolidation,
271
271
  parseConsolidationResponse,
272
272
  parseOperatorAwareConsolidationResponse
273
- } from "./chunk-5RZOFIDL.js";
273
+ } from "./chunk-PI4JHLDD.js";
274
274
  import {
275
275
  buildRecallQueryPolicy
276
276
  } from "./chunk-LBJBNWS2.js";
@@ -292,7 +292,7 @@ import {
292
292
  } from "./chunk-UQ7RN5HK.js";
293
293
  import {
294
294
  SmartBuffer
295
- } from "./chunk-OQQRWPFZ.js";
295
+ } from "./chunk-OS5RKJOH.js";
296
296
  import {
297
297
  isDisagreementPrompt
298
298
  } from "./chunk-H3FZVNRN.js";
@@ -311,7 +311,7 @@ import {
311
311
  clusterByKey,
312
312
  createCorrectionService,
313
313
  detectPassiveCorrections
314
- } from "./chunk-WFNH4UDF.js";
314
+ } from "./chunk-Y6PNYJVO.js";
315
315
  import {
316
316
  listTrustZoneRecords,
317
317
  searchTrustZoneRecords
@@ -333,14 +333,14 @@ import {
333
333
  resolveNamespaceFromStorageDir,
334
334
  resolveScopePlan,
335
335
  resolveScopeProfilePlan
336
- } from "./chunk-7B7IPPN5.js";
336
+ } from "./chunk-OVYBENIJ.js";
337
337
  import {
338
338
  NamespaceSearchRouter
339
- } from "./chunk-66RZ4EIT.js";
339
+ } from "./chunk-BE6NEQLF.js";
340
340
  import {
341
341
  createConversationIndexRuntime,
342
342
  createSearchBackend
343
- } from "./chunk-JQSP7YBJ.js";
343
+ } from "./chunk-ELL5VYXC.js";
344
344
  import {
345
345
  NoopSearchBackend
346
346
  } from "./chunk-CYEPCZN5.js";
@@ -363,7 +363,7 @@ import {
363
363
  } from "./chunk-QDW3E4RD.js";
364
364
  import {
365
365
  shouldSkipImplicitExtraction
366
- } from "./chunk-C53JDEH3.js";
366
+ } from "./chunk-Y62QPRKV.js";
367
367
  import {
368
368
  searchCausalTrajectories
369
369
  } from "./chunk-SQNED75R.js";
@@ -376,7 +376,7 @@ import {
376
376
  } from "./chunk-TBBDFYXW.js";
377
377
  import {
378
378
  buildChainFollowupGenerator
379
- } from "./chunk-F6OEXJQQ.js";
379
+ } from "./chunk-6XG3NQRC.js";
380
380
  import {
381
381
  ContentHashIndex,
382
382
  StorageManager,
@@ -384,7 +384,7 @@ import {
384
384
  fingerprintEntityStructuredFacts,
385
385
  normalizeAttributePairs,
386
386
  parseEntityFile
387
- } from "./chunk-Q6BAA57B.js";
387
+ } from "./chunk-JFCS6PQU.js";
388
388
  import {
389
389
  buildRetiredFactTombstoneInputs
390
390
  } from "./chunk-L2B3EE7B.js";
@@ -465,7 +465,7 @@ import {
465
465
  defaultNamespaceForPrincipal,
466
466
  recallNamespacesForPrincipal,
467
467
  resolvePrincipal
468
- } from "./chunk-DS3FZ7GS.js";
468
+ } from "./chunk-OUSOMUFV.js";
469
469
  import {
470
470
  isSafeRouteNamespace,
471
471
  selectRouteRule
@@ -474,6 +474,7 @@ import {
474
474
  resolveCapabilities,
475
475
  resolveCompressionCapabilities,
476
476
  resolveConsolidationCapabilities,
477
+ resolveConversationContextCapabilities,
477
478
  resolveCreationMemoryCapabilities,
478
479
  resolveEvalCapabilities,
479
480
  resolveGraphConstructionCapabilities,
@@ -483,12 +484,14 @@ import {
483
484
  resolveMemoryLifecycleCapabilities,
484
485
  resolveNamespaceCapabilities,
485
486
  resolveObjectiveStateCapabilities,
487
+ resolvePipelineProcessingCapabilities,
486
488
  resolvePresentationCapabilities,
487
489
  resolveQmdCapabilities,
488
490
  resolveRecallAuxiliaryCapabilities,
491
+ resolveRecallEnhancementCapabilities,
489
492
  resolveSecurityCapabilities,
490
493
  resolveUtilityLearningCapabilities
491
- } from "./chunk-RJBW4EOU.js";
494
+ } from "./chunk-G7Q4D2G3.js";
492
495
  import {
493
496
  sanitizeMemoryContent
494
497
  } from "./chunk-5GKPFL3S.js";
@@ -509,14 +512,14 @@ import {
509
512
  } from "./chunk-PVGDJXVK.js";
510
513
 
511
514
  // src/orchestrator.ts
512
- import path4 from "path";
515
+ import path5 from "path";
513
516
  import os2 from "os";
514
517
  import { createHash as createHash2, randomBytes } from "crypto";
515
518
  import { existsSync, readFileSync } from "fs";
516
519
  import {
517
520
  lstat,
518
521
  mkdir as mkdir3,
519
- readdir,
522
+ readdir as readdir2,
520
523
  readFile as readFile2,
521
524
  realpath,
522
525
  stat,
@@ -960,7 +963,7 @@ var SemanticConsolidationCoordinator = class {
960
963
  for (const cluster of clusters) {
961
964
  let canonicalWriteCompleted = false;
962
965
  try {
963
- const operatorAwareEnabled = this.config.operatorAwareConsolidationEnabled === true;
966
+ const operatorAwareEnabled = resolveConversationContextCapabilities(this.config).operatorAwareConsolidation === true;
964
967
  let prompt = operatorAwareEnabled ? buildOperatorAwareConsolidationPrompt(cluster) : buildConsolidationPrompt(cluster);
965
968
  if (extensionsBlock.length > 0) {
966
969
  prompt += "\n\n" + extensionsBlock;
@@ -1106,7 +1109,7 @@ var SemanticConsolidationCoordinator = class {
1106
1109
  `[semantic-consolidation] Codex materialize post-hook failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`
1107
1110
  );
1108
1111
  }
1109
- if (this.config.peerProfileReasonerEnabled) {
1112
+ if (resolveConversationContextCapabilities(this.config).peerProfileReasoner) {
1110
1113
  try {
1111
1114
  const peerLlm = new FallbackLlmClient(
1112
1115
  this.config.gatewayConfig,
@@ -1942,6 +1945,452 @@ ${lines.join("\n\n")}`;
1942
1945
  }
1943
1946
  };
1944
1947
 
1948
+ // src/orchestration/conversation-index-coordinator.ts
1949
+ import { readdir } from "fs/promises";
1950
+ import path3 from "path";
1951
+ var ConversationIndexCoordinator = class {
1952
+ config;
1953
+ getTranscript;
1954
+ getBackend;
1955
+ indexDir;
1956
+ lastUpdateAtMs = /* @__PURE__ */ new Map();
1957
+ constructor(options) {
1958
+ this.config = options.config;
1959
+ this.getTranscript = options.getTranscript;
1960
+ this.getBackend = options.getBackend;
1961
+ this.indexDir = options.indexDir;
1962
+ }
1963
+ /** Semantic recall over past-conversation chunks (fail-open: empty on miss). */
1964
+ async search(retrievalQuery, topK) {
1965
+ const backend = this.getBackend();
1966
+ if (backend) {
1967
+ return backend.search(retrievalQuery, topK);
1968
+ }
1969
+ return [];
1970
+ }
1971
+ /** Render conversation-recall search hits as a budgeted markdown section. */
1972
+ formatRecallSection(results, maxChars) {
1973
+ if (!Array.isArray(results) || results.length === 0) return null;
1974
+ const lines = ["## Semantic Recall (Past Conversations)", ""];
1975
+ let used = 0;
1976
+ for (const r of results) {
1977
+ if (!r?.snippet) continue;
1978
+ const chunk = `### ${r.path}
1979
+ Score: ${r.score.toFixed(3)}
1980
+
1981
+ ${r.snippet.trim()}
1982
+ `;
1983
+ if (used + chunk.length > maxChars) break;
1984
+ lines.push(chunk);
1985
+ used += chunk.length;
1986
+ }
1987
+ return used > 0 ? lines.join("\n") : null;
1988
+ }
1989
+ /** Recursively count `.md` chunk documents under a directory. */
1990
+ async countChunkDocs(dir) {
1991
+ try {
1992
+ const entries = await readdir(dir, { withFileTypes: true });
1993
+ let total = 0;
1994
+ for (const entry of entries) {
1995
+ const fullPath = path3.join(dir, entry.name);
1996
+ if (entry.isDirectory()) {
1997
+ total += await this.countChunkDocs(fullPath);
1998
+ continue;
1999
+ }
2000
+ if (entry.isFile() && entry.name.endsWith(".md")) {
2001
+ total += 1;
2002
+ }
2003
+ }
2004
+ return total;
2005
+ } catch {
2006
+ return 0;
2007
+ }
2008
+ }
2009
+ /** Read recent transcript entries and chunk them for indexing. */
2010
+ async buildChunks(sessionKey, hours = 24) {
2011
+ const entries = await this.getTranscript().readRecent(hours, sessionKey);
2012
+ const effectiveSessionKey = sessionKey ?? "all-sessions";
2013
+ return chunkTranscriptEntries(effectiveSessionKey, entries, {
2014
+ maxChars: this.config.conversationRecallMaxChars * 2,
2015
+ maxTurns: Math.max(10, this.config.hourlySummariesMaxTurnsPerRun)
2016
+ });
2017
+ }
2018
+ async getHealth() {
2019
+ const chunkDocCount = await this.countChunkDocs(this.indexDir);
2020
+ const lastUpdateAtMs = Math.max(0, ...this.lastUpdateAtMs.values());
2021
+ const lastUpdateAt = lastUpdateAtMs > 0 ? new Date(lastUpdateAtMs).toISOString() : null;
2022
+ if (!resolveIndexingCapabilities(this.config).conversationIndex) {
2023
+ return {
2024
+ enabled: false,
2025
+ backend: this.config.conversationIndexBackend,
2026
+ status: "disabled",
2027
+ chunkDocCount,
2028
+ lastUpdateAt
2029
+ };
2030
+ }
2031
+ const backend = this.getBackend();
2032
+ const backendHealth = backend ? await backend.health() : {
2033
+ backend: this.config.conversationIndexBackend,
2034
+ status: "degraded"
2035
+ };
2036
+ return {
2037
+ enabled: true,
2038
+ chunkDocCount,
2039
+ lastUpdateAt,
2040
+ ...backendHealth
2041
+ };
2042
+ }
2043
+ async inspect() {
2044
+ const chunkDocCount = await this.countChunkDocs(this.indexDir);
2045
+ const lastUpdateAtMs = Math.max(0, ...this.lastUpdateAtMs.values());
2046
+ const lastUpdateAt = lastUpdateAtMs > 0 ? new Date(lastUpdateAtMs).toISOString() : null;
2047
+ if (!resolveIndexingCapabilities(this.config).conversationIndex) {
2048
+ return {
2049
+ enabled: false,
2050
+ backend: this.config.conversationIndexBackend,
2051
+ status: "disabled",
2052
+ available: false,
2053
+ indexPath: this.indexDir,
2054
+ supportsIncrementalUpdate: true,
2055
+ message: "Conversation index disabled by config",
2056
+ metadata: {
2057
+ chunkCount: chunkDocCount
2058
+ },
2059
+ chunkDocCount,
2060
+ lastUpdateAt
2061
+ };
2062
+ }
2063
+ const backend = this.getBackend();
2064
+ const inspection = backend ? await backend.inspect() : {
2065
+ backend: this.config.conversationIndexBackend,
2066
+ status: "degraded",
2067
+ available: false,
2068
+ indexPath: this.indexDir,
2069
+ supportsIncrementalUpdate: true,
2070
+ message: "Conversation index backend unavailable",
2071
+ metadata: {
2072
+ chunkCount: chunkDocCount
2073
+ }
2074
+ };
2075
+ return {
2076
+ enabled: true,
2077
+ chunkDocCount,
2078
+ lastUpdateAt,
2079
+ ...inspection
2080
+ };
2081
+ }
2082
+ async update(sessionKey, hours = 24, opts) {
2083
+ if (!resolveIndexingCapabilities(this.config).conversationIndex) {
2084
+ return { chunks: 0, skipped: true, reason: "disabled", embedded: false };
2085
+ }
2086
+ const enforceMinInterval = opts?.enforceMinInterval !== false;
2087
+ if (enforceMinInterval) {
2088
+ const minIntervalMs = Math.max(
2089
+ 0,
2090
+ this.config.conversationIndexMinUpdateIntervalMs
2091
+ );
2092
+ const now = Date.now();
2093
+ const last = this.lastUpdateAtMs.get(sessionKey) ?? 0;
2094
+ const elapsed = now - last;
2095
+ if (minIntervalMs > 0 && elapsed < minIntervalMs) {
2096
+ return {
2097
+ chunks: 0,
2098
+ skipped: true,
2099
+ reason: "min_interval",
2100
+ retryAfterMs: minIntervalMs - elapsed,
2101
+ embedded: false
2102
+ };
2103
+ }
2104
+ }
2105
+ const chunks = await this.buildChunks(sessionKey, hours);
2106
+ await writeConversationChunks(this.indexDir, chunks);
2107
+ const retentionCutoffMs = Number.isFinite(this.config.conversationIndexRetentionDays) && this.config.conversationIndexRetentionDays > 0 ? Date.now() - this.config.conversationIndexRetentionDays * 24 * 60 * 60 * 1e3 : void 0;
2108
+ await cleanupConversationChunks(
2109
+ this.indexDir,
2110
+ this.config.conversationIndexRetentionDays
2111
+ );
2112
+ const shouldEmbed = opts?.embed ?? this.config.conversationIndexEmbedOnUpdate;
2113
+ let embedded = false;
2114
+ const backend = this.getBackend();
2115
+ if (backend) {
2116
+ const result = await backend.update(chunks, {
2117
+ embed: shouldEmbed,
2118
+ ...retentionCutoffMs !== void 0 ? { retentionCutoffMs } : {}
2119
+ });
2120
+ embedded = result.embedded;
2121
+ }
2122
+ this.lastUpdateAtMs.set(sessionKey, Date.now());
2123
+ return { chunks: chunks.length, skipped: false, embedded };
2124
+ }
2125
+ async rebuild(sessionKey, hours = 24, opts) {
2126
+ if (!resolveIndexingCapabilities(this.config).conversationIndex) {
2127
+ return {
2128
+ chunks: 0,
2129
+ skipped: true,
2130
+ reason: "disabled",
2131
+ embedded: false,
2132
+ rebuilt: false
2133
+ };
2134
+ }
2135
+ const chunks = await this.buildChunks(sessionKey, hours);
2136
+ await writeConversationChunks(this.indexDir, chunks);
2137
+ await cleanupConversationChunks(
2138
+ this.indexDir,
2139
+ this.config.conversationIndexRetentionDays
2140
+ );
2141
+ const shouldEmbed = opts?.embed ?? this.config.conversationIndexEmbedOnUpdate;
2142
+ let embedded = false;
2143
+ let rebuilt = false;
2144
+ const backend = this.getBackend();
2145
+ if (backend) {
2146
+ const result = await backend.rebuild(chunks, {
2147
+ embed: shouldEmbed
2148
+ });
2149
+ embedded = result.embedded;
2150
+ rebuilt = result.rebuilt;
2151
+ }
2152
+ const stamp = Date.now();
2153
+ if (sessionKey) {
2154
+ this.lastUpdateAtMs.set(sessionKey, stamp);
2155
+ } else {
2156
+ this.lastUpdateAtMs.set("__rebuild__", stamp);
2157
+ }
2158
+ return { chunks: chunks.length, skipped: false, embedded, rebuilt };
2159
+ }
2160
+ };
2161
+
2162
+ // src/orchestration/recall-rerank-coordinator.ts
2163
+ var RecallRerankCoordinator = class _RecallRerankCoordinator {
2164
+ getConfig;
2165
+ getStorage;
2166
+ readQmdResultMemory;
2167
+ memoryWorthCounterCache = /* @__PURE__ */ new Map();
2168
+ static MEMORY_WORTH_CACHE_TTL_MS = 3e4;
2169
+ trustSignalCache = /* @__PURE__ */ new Map();
2170
+ static TRUST_SIGNAL_CACHE_TTL_MS = 3e4;
2171
+ constructor(options) {
2172
+ this.getConfig = options.getConfig;
2173
+ this.getStorage = options.getStorage;
2174
+ this.readQmdResultMemory = options.readQmdResultMemory;
2175
+ }
2176
+ async applyMemoryWorthRerank(results, namespaces) {
2177
+ const counters = /* @__PURE__ */ new Map();
2178
+ const seenNamespaces = /* @__PURE__ */ new Set();
2179
+ const nowMs = Date.now();
2180
+ for (const [key, entry] of this.memoryWorthCounterCache) {
2181
+ if (nowMs - entry.at >= _RecallRerankCoordinator.MEMORY_WORTH_CACHE_TTL_MS) {
2182
+ this.memoryWorthCounterCache.delete(key);
2183
+ }
2184
+ }
2185
+ for (const ns of namespaces) {
2186
+ if (seenNamespaces.has(ns)) continue;
2187
+ seenNamespaces.add(ns);
2188
+ try {
2189
+ const cached = this.memoryWorthCounterCache.get(ns);
2190
+ let nsMap;
2191
+ if (cached && nowMs - cached.at < _RecallRerankCoordinator.MEMORY_WORTH_CACHE_TTL_MS) {
2192
+ nsMap = cached.counters;
2193
+ } else {
2194
+ const storage = await this.getStorage(ns);
2195
+ const memories = await storage.readAllMemories();
2196
+ nsMap = buildMemoryWorthCounterMap(memories);
2197
+ this.memoryWorthCounterCache.set(ns, { at: nowMs, counters: nsMap });
2198
+ }
2199
+ for (const [path6, c] of nsMap) counters.set(path6, c);
2200
+ } catch (err) {
2201
+ log.debug("memory-worth: failed to read namespace, skipping", {
2202
+ namespace: ns,
2203
+ error: err.message
2204
+ });
2205
+ }
2206
+ }
2207
+ const missing = results.filter((r) => !counters.has(r.path));
2208
+ if (missing.length > 0) {
2209
+ let reader = null;
2210
+ for (const ns of namespaces) {
2211
+ try {
2212
+ reader = await this.getStorage(ns);
2213
+ break;
2214
+ } catch {
2215
+ }
2216
+ }
2217
+ if (reader) {
2218
+ for (const r of missing) {
2219
+ try {
2220
+ const memory = await this.readQmdResultMemory(r.path, reader, namespaces);
2221
+ if (!memory) continue;
2222
+ const fm = memory.frontmatter;
2223
+ if (fm.mw_success === void 0 && fm.mw_fail === void 0) continue;
2224
+ counters.set(r.path, {
2225
+ mw_success: fm.mw_success,
2226
+ mw_fail: fm.mw_fail,
2227
+ lastAccessed: fm.lastAccessed
2228
+ });
2229
+ } catch (err) {
2230
+ log.debug("memory-worth: direct path lookup failed", {
2231
+ path: r.path,
2232
+ error: err.message
2233
+ });
2234
+ }
2235
+ }
2236
+ }
2237
+ }
2238
+ if (counters.size === 0) return results;
2239
+ const rankedInputs = results.map((r, i) => ({
2240
+ path: r.path,
2241
+ // Large positive rank score so multiplier math stays well-scaled and
2242
+ // we never hit zero; descending so earlier items rank higher.
2243
+ score: results.length - i
2244
+ }));
2245
+ const config = this.getConfig();
2246
+ const filtered = applyMemoryWorthFilter(rankedInputs, {
2247
+ counters,
2248
+ now: /* @__PURE__ */ new Date(),
2249
+ halfLifeMs: config.recallMemoryWorthHalfLifeMs > 0 ? config.recallMemoryWorthHalfLifeMs : void 0
2250
+ });
2251
+ const byPath = new Map(results.map((r) => [r.path, r]));
2252
+ const reordered = [];
2253
+ for (const item of filtered) {
2254
+ const original = byPath.get(item.path);
2255
+ if (original) reordered.push(original);
2256
+ }
2257
+ return reordered;
2258
+ }
2259
+ /**
2260
+ * Issue #1577 — unified TrustScore recall stage. Thin wiring over the pure
2261
+ * {@link applyTrustScoreStage} scorer + the {@link buildTrustSignalsForRerank}
2262
+ * signal builder. The stage subsumes the Memory Worth multiplier — the
2263
+ * orchestrator runs exactly one of the two (mutual exclusion, rule 39; the
2264
+ * double-multiplier test in trust-score-stage.test.ts pins it structurally).
2265
+ *
2266
+ * Returns the admitted results AND the per-path trust map (including
2267
+ * quarantined items) so the caller can: (a) render epistemic hedges, (b)
2268
+ * surface quarantined items in X-ray with a reason (rule 34), and (c) filter
2269
+ * quarantined paths from fallback recall branches. The trust map is a
2270
+ * per-recall local — never instance state — so concurrent recalls cannot
2271
+ * race on it (review: shared-trust-map concurrency).
2272
+ */
2273
+ async applyTrustScoreRerank(results, namespaces) {
2274
+ if (results.length === 0) return { results, trustByPath: null };
2275
+ const config = this.getConfig();
2276
+ const now = /* @__PURE__ */ new Date();
2277
+ const halfLifeDays = config.recallMemoryWorthHalfLifeMs > 0 ? config.recallMemoryWorthHalfLifeMs / (24 * 60 * 60 * 1e3) : void 0;
2278
+ let fallbackReader = null;
2279
+ const signals = await buildTrustSignalsForRerank(
2280
+ results.map((r) => r.path),
2281
+ namespaces,
2282
+ {
2283
+ readNamespaceMemories: async (ns) => (await this.getStorage(ns)).readAllMemories(),
2284
+ readMemoryFrontmatter: async (path6) => {
2285
+ if (!fallbackReader) {
2286
+ for (const ns of namespaces) {
2287
+ try {
2288
+ fallbackReader = await this.getStorage(ns);
2289
+ break;
2290
+ } catch {
2291
+ }
2292
+ }
2293
+ }
2294
+ if (!fallbackReader) return null;
2295
+ const memory = await this.readQmdResultMemory(path6, fallbackReader, namespaces);
2296
+ return memory ? memory.frontmatter : null;
2297
+ }
2298
+ },
2299
+ { cache: this.trustSignalCache, ttlMs: _RecallRerankCoordinator.TRUST_SIGNAL_CACHE_TTL_MS },
2300
+ now,
2301
+ {
2302
+ recencyHalfLifeDays: halfLifeDays,
2303
+ logDebug: (message, context) => log.debug(message, context)
2304
+ }
2305
+ );
2306
+ if (signals.size === 0) {
2307
+ return { results, trustByPath: null };
2308
+ }
2309
+ const rankedInputs = results.map((r, i) => ({ path: r.path, score: results.length - i }));
2310
+ const stage = applyTrustScoreStage(rankedInputs, {
2311
+ signals,
2312
+ weights: config.trustScoreWeights,
2313
+ minMultiplier: config.trustScoreMinMultiplier,
2314
+ maxMultiplier: config.trustScoreMaxMultiplier,
2315
+ quarantine: config.trustScoreQuarantine
2316
+ });
2317
+ const trustByPath = new Map(stage.all.map((item) => [item.path, item]));
2318
+ const byPath = new Map(results.map((r) => [r.path, r]));
2319
+ const admitted = stage.admitted.map((item) => byPath.get(item.path)).filter((r) => r !== void 0);
2320
+ return { results: admitted, trustByPath };
2321
+ }
2322
+ /**
2323
+ * Issue #1577 — apply the TrustScore stage (or, when trust is off, the Memory
2324
+ * Worth multiplier fallback) to ONE recall branch's results, returning the
2325
+ * scored results + the per-path trust map. Thin wiring over
2326
+ * {@link applyTrustScoreRerank} so every recall path — hot QMD, embedding
2327
+ * fallback, recent scan — applies the SAME multiplier gate (rule 41: a
2328
+ * feature gate must apply across ALL parallel recall paths). TrustScore
2329
+ * subsumes Memory Worth; exactly one runs (rule 39). Fail-open on lookup
2330
+ * errors so a storage hiccup never breaks a fallback path.
2331
+ */
2332
+ async applyTrustScoreToBranch(results, namespaces, caps, label) {
2333
+ if (caps.recallTrustScore && results.length > 0) {
2334
+ try {
2335
+ return await this.applyTrustScoreRerank(results, namespaces);
2336
+ } catch (err) {
2337
+ log.debug(`trust-score stage (${label}) failed open`, {
2338
+ error: err.message
2339
+ });
2340
+ }
2341
+ } else if (caps.recallMemoryWorthFilter && results.length > 0) {
2342
+ try {
2343
+ const filtered = await this.applyMemoryWorthRerank(results, namespaces);
2344
+ return { results: filtered, trustByPath: null };
2345
+ } catch (err) {
2346
+ log.debug(`memory-worth filter (${label}) failed open`, {
2347
+ error: err.message
2348
+ });
2349
+ }
2350
+ }
2351
+ return { results, trustByPath: null };
2352
+ }
2353
+ diversifyAndLimitRecallResults(sectionId, results, limit, retrievalQuery, caps = resolveCapabilities(this.getConfig())) {
2354
+ const safeLimit = typeof limit === "number" && Number.isFinite(limit) ? Math.max(0, Math.floor(limit)) : 0;
2355
+ if (!Array.isArray(results) || results.length === 0) return [];
2356
+ if (safeLimit === 0) return [];
2357
+ const boosted = caps.recallReasoningTraceBoost && typeof retrievalQuery === "string" ? applyReasoningTraceBoost(results, {
2358
+ enabled: true,
2359
+ query: retrievalQuery
2360
+ }) : results;
2361
+ const diversified = this.applyMmrToQmdResults(sectionId, boosted, caps);
2362
+ return diversified.slice(0, safeLimit);
2363
+ }
2364
+ /**
2365
+ * Apply Maximal Marginal Relevance to a section's ordered candidate list.
2366
+ *
2367
+ * Operates per-section so one redundant cluster cannot dominate a section,
2368
+ * and so one section's MMR pass cannot starve other sections. Returns the
2369
+ * input unchanged when disabled, when there are fewer than 2 candidates, or
2370
+ * when no budget information is available.
2371
+ */
2372
+ applyMmrToQmdResults(sectionId, results, caps = resolveCapabilities(this.getConfig())) {
2373
+ if (!caps.recallMmr) return results;
2374
+ if (!Array.isArray(results) || results.length < 2) return results;
2375
+ const config = this.getConfig();
2376
+ const configuredTopN = config.recallMmrTopN;
2377
+ const topN = typeof configuredTopN === "number" && Number.isFinite(configuredTopN) ? Math.max(0, Math.floor(configuredTopN)) : 40;
2378
+ if (topN === 0) return results;
2379
+ const lambda = config.recallMmrLambda ?? 0.7;
2380
+ const { reordered, diversity } = reorderRecallResultsWithMmr(results, {
2381
+ lambda,
2382
+ topN
2383
+ });
2384
+ try {
2385
+ log.info(
2386
+ `recall_mmr: section=${sectionId} kept=${diversity.kept}/${diversity.considered} headReorderCount=${diversity.headReorderCount} avgSimBefore=${diversity.avgPairwiseSimBefore.toFixed(3)} avgSimAfter=${diversity.avgPairwiseSimAfter.toFixed(3)} lambda=${lambda.toFixed(2)}`
2387
+ );
2388
+ } catch {
2389
+ }
2390
+ return reordered;
2391
+ }
2392
+ };
2393
+
1945
2394
  // src/maintenance/pattern-reinforcement.ts
1946
2395
  function patternReinforcementKey(content) {
1947
2396
  return content.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 200);
@@ -2275,7 +2724,7 @@ function generateResolverDocument(taxonomy) {
2275
2724
 
2276
2725
  // src/taxonomy/taxonomy-loader.ts
2277
2726
  import { readFile, mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
2278
- import path3 from "path";
2727
+ import path4 from "path";
2279
2728
  var TAXONOMY_DIR = ".taxonomy";
2280
2729
  var TAXONOMY_FILE = "taxonomy.json";
2281
2730
  var MAX_SLUG_LENGTH = 32;
@@ -2373,7 +2822,7 @@ function validateTaxonomy(taxonomy) {
2373
2822
  }
2374
2823
  }
2375
2824
  async function loadTaxonomy(memoryDir) {
2376
- const taxonomyPath = path3.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
2825
+ const taxonomyPath = path4.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
2377
2826
  let raw;
2378
2827
  try {
2379
2828
  raw = await readFile(taxonomyPath, "utf-8");
@@ -2423,16 +2872,16 @@ async function loadTaxonomy(memoryDir) {
2423
2872
  }
2424
2873
  async function saveTaxonomy(memoryDir, taxonomy) {
2425
2874
  validateTaxonomy(taxonomy);
2426
- const dir = path3.join(memoryDir, TAXONOMY_DIR);
2875
+ const dir = path4.join(memoryDir, TAXONOMY_DIR);
2427
2876
  await mkdir2(dir, { recursive: true });
2428
- const filePath = path3.join(dir, TAXONOMY_FILE);
2877
+ const filePath = path4.join(dir, TAXONOMY_FILE);
2429
2878
  await writeFile2(filePath, JSON.stringify(taxonomy, null, 2) + "\n", "utf-8");
2430
2879
  }
2431
2880
  function getTaxonomyDir(memoryDir) {
2432
- return path3.join(memoryDir, TAXONOMY_DIR);
2881
+ return path4.join(memoryDir, TAXONOMY_DIR);
2433
2882
  }
2434
2883
  function getTaxonomyFilePath(memoryDir) {
2435
- return path3.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
2884
+ return path4.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
2436
2885
  }
2437
2886
 
2438
2887
  // src/wearables/registry.ts
@@ -3333,7 +3782,7 @@ async function raceRecallAbort(promise, signal, message = "recall aborted") {
3333
3782
  }
3334
3783
  }
3335
3784
  function qmdCollectionPathParts(resultPath) {
3336
- if (!resultPath || path4.isAbsolute(resultPath)) return null;
3785
+ if (!resultPath || path5.isAbsolute(resultPath)) return null;
3337
3786
  const normalized = resultPath.replace(/\\/g, "/").replace(/^\/+/, "");
3338
3787
  const slashIndex = normalized.indexOf("/");
3339
3788
  if (slashIndex <= 0 || slashIndex >= normalized.length - 1) return null;
@@ -3346,9 +3795,9 @@ function qmdCollectionPathParts(resultPath) {
3346
3795
  }
3347
3796
  function qmdResultPathCandidates(storageDir, resultPath) {
3348
3797
  const candidates = /* @__PURE__ */ new Set();
3349
- const storageRoot = path4.resolve(storageDir);
3798
+ const storageRoot = path5.resolve(storageDir);
3350
3799
  const addCandidate = (candidate) => {
3351
- const resolved = path4.resolve(candidate);
3800
+ const resolved = path5.resolve(candidate);
3352
3801
  if (isPathInsideStorageRoot(storageRoot, resolved)) {
3353
3802
  candidates.add(resolved);
3354
3803
  }
@@ -3356,12 +3805,12 @@ function qmdResultPathCandidates(storageDir, resultPath) {
3356
3805
  const addRelativeCandidates = (relativePath) => {
3357
3806
  const normalized = relativePath.replace(/\\/g, "/").replace(/^\/+/, "");
3358
3807
  if (!normalized) return;
3359
- addCandidate(path4.join(storageRoot, normalized));
3808
+ addCandidate(path5.join(storageRoot, normalized));
3360
3809
  if (/^\d{4}-\d{2}-\d{2}\//.test(normalized)) {
3361
- addCandidate(path4.join(storageRoot, "facts", normalized));
3810
+ addCandidate(path5.join(storageRoot, "facts", normalized));
3362
3811
  }
3363
3812
  };
3364
- if (path4.isAbsolute(resultPath)) {
3813
+ if (path5.isAbsolute(resultPath)) {
3365
3814
  addCandidate(resultPath);
3366
3815
  } else {
3367
3816
  addRelativeCandidates(resultPath);
@@ -3478,7 +3927,7 @@ async function qmdStartupCollectionCheckWithTimeout(promise, controller, label)
3478
3927
  return await Promise.race([checkedPromise, timeoutPromise]);
3479
3928
  }
3480
3929
  function defaultWorkspaceDir() {
3481
- return path4.join(os2.homedir(), ".openclaw", "workspace");
3930
+ return path5.join(os2.homedir(), ".openclaw", "workspace");
3482
3931
  }
3483
3932
  function sanitizeSessionKeyForFilename(sessionKey) {
3484
3933
  const readable = sessionKey.replace(/[^a-zA-Z0-9._-]/g, "_");
@@ -3755,11 +4204,11 @@ function mergeGraphExpandedResults(primary, expanded) {
3755
4204
  return Array.from(mergedByPath.values());
3756
4205
  }
3757
4206
  function graphPathRelativeToStorage(storageDir, candidatePath) {
3758
- const absolutePath = path4.isAbsolute(candidatePath) ? candidatePath : path4.resolve(storageDir, candidatePath);
3759
- const rel = path4.relative(storageDir, absolutePath);
4207
+ const absolutePath = path5.isAbsolute(candidatePath) ? candidatePath : path5.resolve(storageDir, candidatePath);
4208
+ const rel = path5.relative(storageDir, absolutePath);
3760
4209
  if (!rel || rel === ".") return null;
3761
4210
  if (rel.startsWith("..")) return null;
3762
- return rel.split(path4.sep).join("/");
4211
+ return rel.split(path5.sep).join("/");
3763
4212
  }
3764
4213
  function normalizeGraphActivationScore(score) {
3765
4214
  const bounded = Number.isFinite(score) && score > 0 ? score : 0;
@@ -3904,7 +4353,7 @@ function buildMemoryPathById(allMemsForGraph, storageDir) {
3904
4353
  for (const mem of allMemsForGraph ?? []) {
3905
4354
  const id = mem.frontmatter.id;
3906
4355
  if (!id) continue;
3907
- pathById.set(id, path4.relative(storageDir, mem.path));
4356
+ pathById.set(id, path5.relative(storageDir, mem.path));
3908
4357
  }
3909
4358
  return pathById;
3910
4359
  }
@@ -3912,7 +4361,7 @@ function appendMemoryToGraphContext(options) {
3912
4361
  if (!Array.isArray(options.allMemsForGraph)) return;
3913
4362
  const nowIso = (/* @__PURE__ */ new Date()).toISOString();
3914
4363
  options.allMemsForGraph.push({
3915
- path: path4.join(options.storageDir, options.memoryRelPath),
4364
+ path: path5.join(options.storageDir, options.memoryRelPath),
3916
4365
  content: options.content,
3917
4366
  frontmatter: {
3918
4367
  id: options.memoryId,
@@ -3932,16 +4381,16 @@ function resolvePersistedMemoryRelativePath(options) {
3932
4381
  const persisted = options.pathById.get(options.memoryId);
3933
4382
  if (persisted) return persisted;
3934
4383
  if (options.category === "correction") {
3935
- return path4.join("corrections", `${options.memoryId}.md`);
4384
+ return path5.join("corrections", `${options.memoryId}.md`);
3936
4385
  }
3937
4386
  const subtree = categoryDirName(options.category);
3938
4387
  const idParts = options.memoryId.split("-");
3939
4388
  const maybeTimestamp = Number(idParts[1]);
3940
4389
  if (Number.isFinite(maybeTimestamp) && maybeTimestamp > 0) {
3941
4390
  const day = new Date(maybeTimestamp).toISOString().slice(0, 10);
3942
- return path4.join(subtree, day, `${options.memoryId}.md`);
4391
+ return path5.join(subtree, day, `${options.memoryId}.md`);
3943
4392
  }
3944
- return path4.join(subtree, `${options.memoryId}.md`);
4393
+ return path5.join(subtree, `${options.memoryId}.md`);
3945
4394
  }
3946
4395
  var Orchestrator = class _Orchestrator {
3947
4396
  storage;
@@ -4048,25 +4497,6 @@ var Orchestrator = class _Orchestrator {
4048
4497
  /** Lossless Context Management engine — proactive session archive + DAG summarization. */
4049
4498
  lcmEngine = null;
4050
4499
  rerankCache = new RerankCache();
4051
- /**
4052
- * Short-TTL cache for Memory Worth counter lookups so interactive recall
4053
- * doesn't trigger a full `readAllMemories` scan per query. Keyed by
4054
- * namespace; the filter unions across namespaces at query time. The TTL
4055
- * is intentionally short (seconds, not minutes) because counters are
4056
- * mutated by `recordMemoryOutcome` asynchronously and we'd rather serve
4057
- * a 30-second-stale worth score than a stable-but-wrong one.
4058
- */
4059
- memoryWorthCounterCache = /* @__PURE__ */ new Map();
4060
- static MEMORY_WORTH_CACHE_TTL_MS = 3e4;
4061
- /**
4062
- * Issue #1577 — per-namespace TrustScore signal map cache. Same TTL/shape
4063
- * discipline as {@link memoryWorthCounterCache}: seconds-scale, evicted on
4064
- * every call, keyed by namespace. Holds the frontmatter-derived signals
4065
- * (worth, provenance, faithfulness, corroboration, recency) so the trust
4066
- * stage doesn't trigger a fresh `readAllMemories` scan per query.
4067
- */
4068
- trustSignalCache = /* @__PURE__ */ new Map();
4069
- static TRUST_SIGNAL_CACHE_TTL_MS = 3e4;
4070
4500
  /**
4071
4501
  * Per-session workspace selections keyed by sessionKey.
4072
4502
  * Set by the before_agent_start hook so recall() uses the correct
@@ -4116,13 +4546,18 @@ var Orchestrator = class _Orchestrator {
4116
4546
  * to RecallResultFormatter.
4117
4547
  */
4118
4548
  recallResultFormatter;
4549
+ /**
4550
+ * Issue #1526: conversation-index subsystem moved to
4551
+ * ConversationIndexCoordinator.
4552
+ */
4553
+ conversationIndexCoordinator;
4554
+ recallRerankCoordinator;
4119
4555
  heartbeatObserverChains = /* @__PURE__ */ new Map();
4120
4556
  recentExtractionFingerprints = /* @__PURE__ */ new Map();
4121
4557
  consolidationObservers = /* @__PURE__ */ new Set();
4122
4558
  wearablesServiceInstance = null;
4123
4559
  wearablesAutoSyncHandle = null;
4124
4560
  lastQmdReprobeAtMs = 0;
4125
- conversationIndexLastUpdateAtMs = /* @__PURE__ */ new Map();
4126
4561
  lastFileHygieneRunAtMs = 0;
4127
4562
  // Pattern-reinforcement cadence gate (issue #687 PR 2/4). Tracks the
4128
4563
  // last successful run so `runPatternReinforcement` can short-circuit
@@ -4409,7 +4844,7 @@ var Orchestrator = class _Orchestrator {
4409
4844
  const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
4410
4845
  if (ns !== defaultNs && !isSafeRouteNamespace(ns)) return;
4411
4846
  if (!this.storageDirMatchesNamespaceHint(ns, storageDir)) return;
4412
- const resolvedStorageDir = path4.resolve(storageDir);
4847
+ const resolvedStorageDir = path5.resolve(storageDir);
4413
4848
  let hints = this.namespaceStorageDirHints.get(resolvedStorageDir);
4414
4849
  if (!hints) {
4415
4850
  hints = /* @__PURE__ */ new Set();
@@ -4420,21 +4855,21 @@ var Orchestrator = class _Orchestrator {
4420
4855
  storageDirMatchesNamespaceHint(namespace, storageDir) {
4421
4856
  const ns = normalizeNamespaceIdentity(namespace);
4422
4857
  if (!ns) return false;
4423
- const resolvedStorageDir = path4.resolve(storageDir);
4424
- const resolvedMemoryDir = path4.resolve(this.config.memoryDir);
4858
+ const resolvedStorageDir = path5.resolve(storageDir);
4859
+ const resolvedMemoryDir = path5.resolve(this.config.memoryDir);
4425
4860
  const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
4426
4861
  if (resolvedStorageDir === resolvedMemoryDir) return ns === defaultNs;
4427
- const resolvedNamespacesDir = path4.join(resolvedMemoryDir, "namespaces");
4862
+ const resolvedNamespacesDir = path5.join(resolvedMemoryDir, "namespaces");
4428
4863
  if (!isPathInsideStorageRoot(resolvedNamespacesDir, resolvedStorageDir)) return false;
4429
- const rawRoot = path4.resolve(resolvedNamespacesDir, ns);
4430
- const tokenRoot = path4.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
4864
+ const rawRoot = path5.resolve(resolvedNamespacesDir, ns);
4865
+ const tokenRoot = path5.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
4431
4866
  return resolvedStorageDir === rawRoot || resolvedStorageDir === tokenRoot;
4432
4867
  }
4433
4868
  namespaceStorageDirHintOwnershipRank(record, resolvedStorageDir, configured) {
4434
- if (resolvedStorageDir === path4.resolve(this.config.memoryDir)) {
4869
+ if (resolvedStorageDir === path5.resolve(this.config.memoryDir)) {
4435
4870
  return record.namespace === normalizeNamespaceIdentity(this.config.defaultNamespace) ? 0 : 3;
4436
4871
  }
4437
- const leaf = path4.basename(resolvedStorageDir);
4872
+ const leaf = path5.basename(resolvedStorageDir);
4438
4873
  const tokenOwnsRoot = namespaceIdentityToken(record.namespace) === leaf;
4439
4874
  if (tokenOwnsRoot && configured.has(record.namespace)) return 0;
4440
4875
  if (record.namespace === leaf) return 1;
@@ -4462,7 +4897,7 @@ var Orchestrator = class _Orchestrator {
4462
4897
  loadNamespaceStorageDirHintsFromCatalog() {
4463
4898
  if (this.namespaceStorageDirHintsLoaded || !this.namespaceCatalog.enabled) return;
4464
4899
  this.namespaceStorageDirHintsLoaded = true;
4465
- const catalogPath = path4.join(this.config.memoryDir, "state", "namespaces.jsonl");
4900
+ const catalogPath = path5.join(this.config.memoryDir, "state", "namespaces.jsonl");
4466
4901
  if (!existsSync(catalogPath)) return;
4467
4902
  let body;
4468
4903
  try {
@@ -4499,7 +4934,7 @@ var Orchestrator = class _Orchestrator {
4499
4934
  if (!this.storageDirMatchesNamespaceHint(record.namespace, record.storageDir)) {
4500
4935
  continue;
4501
4936
  }
4502
- const resolvedStorageDir = path4.resolve(record.storageDir);
4937
+ const resolvedStorageDir = path5.resolve(record.storageDir);
4503
4938
  const current = preferredByStorageDir.get(resolvedStorageDir);
4504
4939
  preferredByStorageDir.set(
4505
4940
  resolvedStorageDir,
@@ -4762,8 +5197,8 @@ var Orchestrator = class _Orchestrator {
4762
5197
  constructor(config) {
4763
5198
  this.config = config;
4764
5199
  this.profiler = new ProfilingCollector({
4765
- enabled: config.profilingEnabled,
4766
- storageDir: config.profilingStorageDir || path4.join(config.memoryDir, "profiling"),
5200
+ enabled: resolvePipelineProcessingCapabilities(this.config).profiling,
5201
+ storageDir: config.profilingStorageDir || path5.join(config.memoryDir, "profiling"),
4767
5202
  maxTraces: config.profilingMaxTraces
4768
5203
  });
4769
5204
  this.namespaceCatalog = new NamespaceCatalog(config);
@@ -4829,15 +5264,26 @@ var Orchestrator = class _Orchestrator {
4829
5264
  this.conversationQmd = conversationIndexRuntime.qmd;
4830
5265
  this.conversationFaiss = conversationIndexRuntime.faiss;
4831
5266
  this.conversationIndexBackend = conversationIndexRuntime.backend;
4832
- this.sharedContext = config.sharedContextEnabled ? new SharedContextManager(config) : void 0;
5267
+ this.sharedContext = resolveConversationContextCapabilities(this.config).sharedContext ? new SharedContextManager(config) : void 0;
4833
5268
  this.compounding = resolveConsolidationCapabilities(config).compounding ? new CompoundingEngine(config, this.storage) : void 0;
4834
5269
  this.buffer = new SmartBuffer(config, this.storage);
4835
5270
  this.transcript = new TranscriptManager(config);
4836
- this.conversationIndexDir = path4.join(
5271
+ this.conversationIndexDir = path5.join(
4837
5272
  config.memoryDir,
4838
5273
  "conversation-index",
4839
5274
  "chunks"
4840
5275
  );
5276
+ this.conversationIndexCoordinator = new ConversationIndexCoordinator({
5277
+ config,
5278
+ getTranscript: () => this.transcript,
5279
+ getBackend: () => this.conversationIndexBackend,
5280
+ indexDir: this.conversationIndexDir
5281
+ });
5282
+ this.recallRerankCoordinator = new RecallRerankCoordinator({
5283
+ getConfig: () => this.config,
5284
+ getStorage: (namespace) => this.getStorage(namespace),
5285
+ readQmdResultMemory: (resultPath, fallbackStorage, recallNamespaces) => this.readQmdResultMemory(resultPath, fallbackStorage, recallNamespaces)
5286
+ });
4841
5287
  this.modelRegistry = new ModelRegistry(config.memoryDir);
4842
5288
  this.relevance = new RelevanceStore(config.memoryDir);
4843
5289
  this.negatives = new NegativeExampleStore(config.memoryDir);
@@ -4881,7 +5327,7 @@ var Orchestrator = class _Orchestrator {
4881
5327
  this.judgeDeferCounts = createDeferCountMap();
4882
5328
  this.localLlm = new LocalLlmClient(config, this.modelRegistry);
4883
5329
  this.localLlm.disableThinking = config.localLlmDisableThinking;
4884
- this.fastLlm = config.localLlmFastEnabled ? (() => {
5330
+ this.fastLlm = resolvePipelineProcessingCapabilities(this.config).localLlmFast ? (() => {
4885
5331
  const client = new LocalLlmClient(
4886
5332
  {
4887
5333
  ...config,
@@ -4928,7 +5374,7 @@ var Orchestrator = class _Orchestrator {
4928
5374
  saveContentHashIndexes: () => this.saveContentHashIndexes()
4929
5375
  });
4930
5376
  this.threading = new ThreadingManager(
4931
- path4.join(config.memoryDir, "threads"),
5377
+ path5.join(config.memoryDir, "threads"),
4932
5378
  config.threadingGapMinutes
4933
5379
  );
4934
5380
  const lifecycleCaps = resolveMemoryLifecycleCapabilities(config);
@@ -4937,7 +5383,7 @@ var Orchestrator = class _Orchestrator {
4937
5383
  tmtHourlyMinMemories: config.tmtHourlyMinMemories,
4938
5384
  tmtSummaryMaxTokens: config.tmtSummaryMaxTokens
4939
5385
  });
4940
- if (config.lcmEnabled) {
5386
+ if (resolvePipelineProcessingCapabilities(this.config).lcm) {
4941
5387
  const summarizeFn = async (text, targetTokens, aggressive) => {
4942
5388
  const instructionText = aggressive ? `Compress the following into bullet points. One bullet per distinct fact or decision. Maximum ${targetTokens} tokens total. No prose.` : `Compress the following conversation segment into a dense summary. Preserve: decisions made, code artifacts mentioned, errors encountered, open questions, and any commitments or next-steps. Omit: pleasantries, restatements, and anything the agent would not need to recall later. Output a single paragraph, maximum ${targetTokens} tokens.`;
4943
5389
  try {
@@ -4976,7 +5422,7 @@ var Orchestrator = class _Orchestrator {
4976
5422
  dir,
4977
5423
  new BoxBuilder(dir, {
4978
5424
  memoryBoxesEnabled: resolvePresentationCapabilities(this.config).memoryBoxes,
4979
- traceWeaverEnabled: this.config.traceWeaverEnabled,
5425
+ traceWeaverEnabled: resolvePipelineProcessingCapabilities(this.config).traceWeaver,
4980
5426
  boxTopicShiftThreshold: this.config.boxTopicShiftThreshold,
4981
5427
  boxTimeGapMs: this.config.boxTimeGapMs,
4982
5428
  boxMaxMemories: this.config.boxMaxMemories,
@@ -5042,7 +5488,7 @@ var Orchestrator = class _Orchestrator {
5042
5488
  return this.routingRulesStore;
5043
5489
  }
5044
5490
  async loadRoutingRules() {
5045
- if (!this.config.routingRulesEnabled) return [];
5491
+ if (!resolvePipelineProcessingCapabilities(this.config).routingRules) return [];
5046
5492
  try {
5047
5493
  return await this.getRoutingRulesStore().read(this.routeEngineOptions());
5048
5494
  } catch (err) {
@@ -5248,10 +5694,10 @@ var Orchestrator = class _Orchestrator {
5248
5694
  if (resolveRecallAuxiliaryCapabilities(this.config).compactionReset) {
5249
5695
  try {
5250
5696
  const wsDir = this.config.workspaceDir || defaultWorkspaceDir();
5251
- const files = await readdir(wsDir).catch(() => []);
5697
+ const files = await readdir2(wsDir).catch(() => []);
5252
5698
  for (const f of files) {
5253
5699
  if (!f.startsWith(".compaction-reset-signal-")) continue;
5254
- const fp = path4.join(wsDir, f);
5700
+ const fp = path5.join(wsDir, f);
5255
5701
  const s = await stat(fp).catch(() => null);
5256
5702
  if (s && Date.now() - s.mtimeMs >= COMPACTION_SIGNAL_MAX_AGE_MS) {
5257
5703
  await unlink(fp).catch(() => {
@@ -5446,7 +5892,7 @@ var Orchestrator = class _Orchestrator {
5446
5892
  if (signal.aborted) return;
5447
5893
  if (lifecycleCaps.lifecyclePolicy && resolveQmdCapabilities(this.config).qmdTierMigration) {
5448
5894
  try {
5449
- const { runFirstStartMigration } = await import("./first-start-migration-5DXD3TF2.js");
5895
+ const { runFirstStartMigration } = await import("./first-start-migration-GQ3UQNIL.js");
5450
5896
  const result = await runFirstStartMigration({
5451
5897
  storage: this.storage,
5452
5898
  config: this.config,
@@ -5760,15 +6206,15 @@ ${doc.content}` : doc.content,
5760
6206
  this.lastFileHygieneRunAtMs = now;
5761
6207
  if (hygiene.rotateEnabled) {
5762
6208
  for (const rel of hygiene.rotatePaths) {
5763
- const abs = path4.isAbsolute(rel) ? rel : path4.join(this.config.workspaceDir, rel);
6209
+ const abs = path5.isAbsolute(rel) ? rel : path5.join(this.config.workspaceDir, rel);
5764
6210
  try {
5765
6211
  const raw = await readFile2(abs, "utf-8");
5766
6212
  if (raw.length > hygiene.rotateMaxBytes) {
5767
- const archiveDir = path4.join(
6213
+ const archiveDir = path5.join(
5768
6214
  this.config.workspaceDir,
5769
6215
  hygiene.archiveDir
5770
6216
  );
5771
- const base = path4.basename(abs);
6217
+ const base = path5.basename(abs);
5772
6218
  const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
5773
6219
  const { newContent } = await rotateMarkdownFileToArchive({
5774
6220
  filePath: abs,
@@ -5793,8 +6239,8 @@ ${doc.content}` : doc.content,
5793
6239
  log.warn(w.message);
5794
6240
  }
5795
6241
  if (hygiene.warningsLogEnabled && warnings.length > 0) {
5796
- const fp = path4.join(this.config.memoryDir, hygiene.warningsLogPath);
5797
- await mkdir3(path4.dirname(fp), { recursive: true });
6242
+ const fp = path5.join(this.config.memoryDir, hygiene.warningsLogPath);
6243
+ await mkdir3(path5.dirname(fp), { recursive: true });
5798
6244
  const stamp = (/* @__PURE__ */ new Date()).toISOString();
5799
6245
  const block = `
5800
6246
 
@@ -5933,16 +6379,16 @@ ${doc.content}` : doc.content,
5933
6379
  for (const categoryDir of RECALL_FALLBACK_DIRS) {
5934
6380
  if (memoryRootReal === null) break;
5935
6381
  for (const date of datesToScan) {
5936
- const dateDir = path4.join(storage.dir, categoryDir, date);
6382
+ const dateDir = path5.join(storage.dir, categoryDir, date);
5937
6383
  try {
5938
6384
  const dirStat = await lstat(dateDir);
5939
6385
  if (dirStat.isSymbolicLink() || !dirStat.isDirectory()) continue;
5940
6386
  assertPathInsideRoot(memoryRootReal, await realpath(dateDir), dateDir);
5941
- const entries = await readdir(dateDir, { withFileTypes: true });
6387
+ const entries = await readdir2(dateDir, { withFileTypes: true });
5942
6388
  for (const entry of entries) {
5943
6389
  if (entry.isSymbolicLink()) continue;
5944
6390
  if (!entry.name.endsWith(".md")) continue;
5945
- const fullPath = path4.join(dateDir, entry.name);
6391
+ const fullPath = path5.join(dateDir, entry.name);
5946
6392
  try {
5947
6393
  assertPathInsideRoot(memoryRootReal, await realpath(fullPath), fullPath);
5948
6394
  const raw = await readFile2(fullPath, "utf-8");
@@ -5964,7 +6410,7 @@ ${doc.content}` : doc.content,
5964
6410
  facts.push({
5965
6411
  path: fullPath,
5966
6412
  frontmatter: {
5967
- id: fm.id || path4.basename(entry.name, ".md"),
6413
+ id: fm.id || path5.basename(entry.name, ".md"),
5968
6414
  category: fm.category || "fact",
5969
6415
  created,
5970
6416
  updated: fm.updated || created,
@@ -5987,13 +6433,13 @@ ${doc.content}` : doc.content,
5987
6433
  return a.frontmatter.created < b.frontmatter.created ? -1 : 1;
5988
6434
  });
5989
6435
  const hourlySummaries = [];
5990
- const hourlyBaseDir = path4.join(storage.dir, "summaries", "hourly");
6436
+ const hourlyBaseDir = path5.join(storage.dir, "summaries", "hourly");
5991
6437
  try {
5992
- const sessionKeys = await readdir(hourlyBaseDir, { withFileTypes: true });
6438
+ const sessionKeys = await readdir2(hourlyBaseDir, { withFileTypes: true });
5993
6439
  for (const sk of sessionKeys) {
5994
6440
  if (!sk.isDirectory()) continue;
5995
6441
  for (const date of datesToScan) {
5996
- const summaryFile = path4.join(hourlyBaseDir, sk.name, `${date}.md`);
6442
+ const summaryFile = path5.join(hourlyBaseDir, sk.name, `${date}.md`);
5997
6443
  try {
5998
6444
  const raw = await readFile2(summaryFile, "utf-8");
5999
6445
  const filtered = filterHourlySummaryMarkdownForLocalDay(
@@ -6097,7 +6543,7 @@ ${doc.content}` : doc.content,
6097
6543
  }
6098
6544
  async getLastGraphRecallSnapshot(namespace) {
6099
6545
  const storage = await this.getStorage(namespace);
6100
- const snapshotPath = path4.join(
6546
+ const snapshotPath = path5.join(
6101
6547
  storage.dir,
6102
6548
  "state",
6103
6549
  "last_graph_recall.json"
@@ -6136,7 +6582,7 @@ ${doc.content}` : doc.content,
6136
6582
  }
6137
6583
  async getLastIntentSnapshot(namespace) {
6138
6584
  const storage = await this.getStorage(namespace);
6139
- const snapshotPath = path4.join(storage.dir, "state", "last_intent.json");
6585
+ const snapshotPath = path5.join(storage.dir, "state", "last_intent.json");
6140
6586
  try {
6141
6587
  const raw = await readFile2(snapshotPath, "utf-8");
6142
6588
  const parsed = JSON.parse(raw);
@@ -6169,7 +6615,7 @@ ${doc.content}` : doc.content,
6169
6615
  }
6170
6616
  async getLastQmdRecallSnapshot(namespace) {
6171
6617
  const storage = await this.getStorage(namespace);
6172
- const snapshotPath = path4.join(
6618
+ const snapshotPath = path5.join(
6173
6619
  storage.dir,
6174
6620
  "state",
6175
6621
  "last_qmd_recall.json"
@@ -6294,206 +6740,31 @@ ${doc.content}` : doc.content,
6294
6740
  })
6295
6741
  ].join("\n");
6296
6742
  }
6297
- async searchConversationRecallResults(retrievalQuery, topK) {
6298
- if (this.conversationIndexBackend) {
6299
- return this.conversationIndexBackend.search(retrievalQuery, topK);
6300
- }
6301
- return [];
6302
- }
6303
- formatConversationRecallSection(results, maxChars) {
6304
- if (!Array.isArray(results) || results.length === 0) return null;
6305
- const lines = ["## Semantic Recall (Past Conversations)", ""];
6306
- let used = 0;
6307
- for (const r of results) {
6308
- if (!r?.snippet) continue;
6309
- const chunk = `### ${r.path}
6310
- Score: ${r.score.toFixed(3)}
6311
-
6312
- ${r.snippet.trim()}
6313
- `;
6314
- if (used + chunk.length > maxChars) break;
6315
- lines.push(chunk);
6316
- used += chunk.length;
6317
- }
6318
- return used > 0 ? lines.join("\n") : null;
6319
- }
6320
- async countConversationChunkDocs(dir) {
6321
- try {
6322
- const entries = await readdir(dir, { withFileTypes: true });
6323
- let total = 0;
6324
- for (const entry of entries) {
6325
- const fullPath = path4.join(dir, entry.name);
6326
- if (entry.isDirectory()) {
6327
- total += await this.countConversationChunkDocs(fullPath);
6328
- continue;
6329
- }
6330
- if (entry.isFile() && entry.name.endsWith(".md")) {
6331
- total += 1;
6332
- }
6333
- }
6334
- return total;
6335
- } catch {
6336
- return 0;
6337
- }
6338
- }
6339
- async buildConversationIndexChunks(sessionKey, hours = 24) {
6340
- const entries = await this.transcript.readRecent(hours, sessionKey);
6341
- const effectiveSessionKey = sessionKey ?? "all-sessions";
6342
- return chunkTranscriptEntries(effectiveSessionKey, entries, {
6343
- maxChars: this.config.conversationRecallMaxChars * 2,
6344
- maxTurns: Math.max(10, this.config.hourlySummariesMaxTurnsPerRun)
6345
- });
6346
- }
6347
- async getConversationIndexHealth() {
6348
- const chunkDocCount = await this.countConversationChunkDocs(
6349
- this.conversationIndexDir
6350
- );
6351
- const lastUpdateAtMs = Math.max(
6352
- 0,
6353
- ...this.conversationIndexLastUpdateAtMs.values()
6354
- );
6355
- const lastUpdateAt = lastUpdateAtMs > 0 ? new Date(lastUpdateAtMs).toISOString() : null;
6356
- if (!resolveIndexingCapabilities(this.config).conversationIndex) {
6357
- return {
6358
- enabled: false,
6359
- backend: this.config.conversationIndexBackend,
6360
- status: "disabled",
6361
- chunkDocCount,
6362
- lastUpdateAt
6363
- };
6364
- }
6365
- const backendHealth = this.conversationIndexBackend ? await this.conversationIndexBackend.health() : {
6366
- backend: this.config.conversationIndexBackend,
6367
- status: "degraded"
6368
- };
6369
- return {
6370
- enabled: true,
6371
- chunkDocCount,
6372
- lastUpdateAt,
6373
- ...backendHealth
6374
- };
6375
- }
6376
- async inspectConversationIndex() {
6377
- const chunkDocCount = await this.countConversationChunkDocs(
6378
- this.conversationIndexDir
6379
- );
6380
- const lastUpdateAtMs = Math.max(
6381
- 0,
6382
- ...this.conversationIndexLastUpdateAtMs.values()
6383
- );
6384
- const lastUpdateAt = lastUpdateAtMs > 0 ? new Date(lastUpdateAtMs).toISOString() : null;
6385
- if (!resolveIndexingCapabilities(this.config).conversationIndex) {
6386
- return {
6387
- enabled: false,
6388
- backend: this.config.conversationIndexBackend,
6389
- status: "disabled",
6390
- available: false,
6391
- indexPath: this.conversationIndexDir,
6392
- supportsIncrementalUpdate: true,
6393
- message: "Conversation index disabled by config",
6394
- metadata: {
6395
- chunkCount: chunkDocCount
6396
- },
6397
- chunkDocCount,
6398
- lastUpdateAt
6399
- };
6400
- }
6401
- const inspection = this.conversationIndexBackend ? await this.conversationIndexBackend.inspect() : {
6402
- backend: this.config.conversationIndexBackend,
6403
- status: "degraded",
6404
- available: false,
6405
- indexPath: this.conversationIndexDir,
6406
- supportsIncrementalUpdate: true,
6407
- message: "Conversation index backend unavailable",
6408
- metadata: {
6409
- chunkCount: chunkDocCount
6410
- }
6411
- };
6412
- return {
6413
- enabled: true,
6414
- chunkDocCount,
6415
- lastUpdateAt,
6416
- ...inspection
6417
- };
6743
+ async searchConversationRecallResults(retrievalQuery, topK) {
6744
+ return this.conversationIndexCoordinator.search(retrievalQuery, topK);
6745
+ }
6746
+ formatConversationRecallSection(results, maxChars) {
6747
+ return this.conversationIndexCoordinator.formatRecallSection(
6748
+ results,
6749
+ maxChars
6750
+ );
6751
+ }
6752
+ // Issue #1526: countConversationChunkDocs / buildConversationIndexChunks moved
6753
+ // to ConversationIndexCoordinator (internal helpers, no orchestrator callers).
6754
+ async getConversationIndexHealth() {
6755
+ return this.conversationIndexCoordinator.getHealth();
6756
+ }
6757
+ async inspectConversationIndex() {
6758
+ return this.conversationIndexCoordinator.inspect();
6418
6759
  }
6419
6760
  async getRecoverySummary(sessionKey) {
6420
6761
  return this.transcript.getRecoverySummary(sessionKey);
6421
6762
  }
6422
6763
  async updateConversationIndex(sessionKey, hours = 24, opts) {
6423
- if (!resolveIndexingCapabilities(this.config).conversationIndex) {
6424
- return { chunks: 0, skipped: true, reason: "disabled", embedded: false };
6425
- }
6426
- const enforceMinInterval = opts?.enforceMinInterval !== false;
6427
- if (enforceMinInterval) {
6428
- const minIntervalMs = Math.max(
6429
- 0,
6430
- this.config.conversationIndexMinUpdateIntervalMs
6431
- );
6432
- const now = Date.now();
6433
- const last = this.conversationIndexLastUpdateAtMs.get(sessionKey) ?? 0;
6434
- const elapsed = now - last;
6435
- if (minIntervalMs > 0 && elapsed < minIntervalMs) {
6436
- return {
6437
- chunks: 0,
6438
- skipped: true,
6439
- reason: "min_interval",
6440
- retryAfterMs: minIntervalMs - elapsed,
6441
- embedded: false
6442
- };
6443
- }
6444
- }
6445
- const chunks = await this.buildConversationIndexChunks(sessionKey, hours);
6446
- await writeConversationChunks(this.conversationIndexDir, chunks);
6447
- const retentionCutoffMs = Number.isFinite(this.config.conversationIndexRetentionDays) && this.config.conversationIndexRetentionDays > 0 ? Date.now() - this.config.conversationIndexRetentionDays * 24 * 60 * 60 * 1e3 : void 0;
6448
- await cleanupConversationChunks(
6449
- this.conversationIndexDir,
6450
- this.config.conversationIndexRetentionDays
6451
- );
6452
- const shouldEmbed = opts?.embed ?? this.config.conversationIndexEmbedOnUpdate;
6453
- let embedded = false;
6454
- if (this.conversationIndexBackend) {
6455
- const result = await this.conversationIndexBackend.update(chunks, {
6456
- embed: shouldEmbed,
6457
- ...retentionCutoffMs !== void 0 ? { retentionCutoffMs } : {}
6458
- });
6459
- embedded = result.embedded;
6460
- }
6461
- this.conversationIndexLastUpdateAtMs.set(sessionKey, Date.now());
6462
- return { chunks: chunks.length, skipped: false, embedded };
6764
+ return this.conversationIndexCoordinator.update(sessionKey, hours, opts);
6463
6765
  }
6464
6766
  async rebuildConversationIndex(sessionKey, hours = 24, opts) {
6465
- if (!resolveIndexingCapabilities(this.config).conversationIndex) {
6466
- return {
6467
- chunks: 0,
6468
- skipped: true,
6469
- reason: "disabled",
6470
- embedded: false,
6471
- rebuilt: false
6472
- };
6473
- }
6474
- const chunks = await this.buildConversationIndexChunks(sessionKey, hours);
6475
- await writeConversationChunks(this.conversationIndexDir, chunks);
6476
- await cleanupConversationChunks(
6477
- this.conversationIndexDir,
6478
- this.config.conversationIndexRetentionDays
6479
- );
6480
- const shouldEmbed = opts?.embed ?? this.config.conversationIndexEmbedOnUpdate;
6481
- let embedded = false;
6482
- let rebuilt = false;
6483
- if (this.conversationIndexBackend) {
6484
- const result = await this.conversationIndexBackend.rebuild(chunks, {
6485
- embed: shouldEmbed
6486
- });
6487
- embedded = result.embedded;
6488
- rebuilt = result.rebuilt;
6489
- }
6490
- const stamp = Date.now();
6491
- if (sessionKey) {
6492
- this.conversationIndexLastUpdateAtMs.set(sessionKey, stamp);
6493
- } else {
6494
- this.conversationIndexLastUpdateAtMs.set("__rebuild__", stamp);
6495
- }
6496
- return { chunks: chunks.length, skipped: false, embedded, rebuilt };
6767
+ return this.conversationIndexCoordinator.rebuild(sessionKey, hours, opts);
6497
6768
  }
6498
6769
  /**
6499
6770
  * Validate local LLM model availability and context window compatibility.
@@ -7228,7 +7499,7 @@ ${r.snippet.trim()}
7228
7499
  resolvedPath = resolvedCold.result.path;
7229
7500
  resolvedResult = resolvedCold.result;
7230
7501
  }
7231
- if (!path4.isAbsolute(resolvedPath)) {
7502
+ if (!path5.isAbsolute(resolvedPath)) {
7232
7503
  resolvedAmbiguousSeeds.set(result.path, null);
7233
7504
  return null;
7234
7505
  }
@@ -7253,7 +7524,7 @@ ${r.snippet.trim()}
7253
7524
  }
7254
7525
  continue;
7255
7526
  }
7256
- if (path4.isAbsolute(result.path)) {
7527
+ if (path5.isAbsolute(result.path)) {
7257
7528
  const resolved = await resolveAmbiguousSeedOwner(result, null);
7258
7529
  if (resolved) {
7259
7530
  addResultForNamespace(resolved.namespace, resolved.result);
@@ -7296,7 +7567,7 @@ ${r.snippet.trim()}
7296
7567
  0
7297
7568
  );
7298
7569
  seedPaths.push(
7299
- ...seedRelativePaths.map((rel) => path4.join(storage.dir, rel))
7570
+ ...seedRelativePaths.map((rel) => path5.join(storage.dir, rel))
7300
7571
  );
7301
7572
  const seedSet = new Set(seedRelativePaths);
7302
7573
  const expanded = await this.graphIndexFor(storage).spreadingActivation(
@@ -7312,7 +7583,7 @@ ${r.snippet.trim()}
7312
7583
  for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
7313
7584
  if (deadlineExpired()) break;
7314
7585
  if (seedSet.has(candidate.path)) continue;
7315
- const memoryPath = path4.resolve(storage.dir, candidate.path);
7586
+ const memoryPath = path5.resolve(storage.dir, candidate.path);
7316
7587
  const memory = await storage.readMemoryByPath(memoryPath);
7317
7588
  if (deadlineExpired()) break;
7318
7589
  if (!memory) continue;
@@ -7337,7 +7608,7 @@ ${r.snippet.trim()}
7337
7608
  path: memory.path,
7338
7609
  score,
7339
7610
  namespace,
7340
- seed: path4.resolve(storage.dir, candidate.seed),
7611
+ seed: path5.resolve(storage.dir, candidate.seed),
7341
7612
  hopDepth: candidate.hopDepth,
7342
7613
  decayedWeight: candidate.decayedWeight,
7343
7614
  graphType: candidate.graphType,
@@ -7358,12 +7629,12 @@ ${r.snippet.trim()}
7358
7629
  }
7359
7630
  async recordLastGraphRecallSnapshot(options) {
7360
7631
  try {
7361
- const snapshotPath = path4.join(
7632
+ const snapshotPath = path5.join(
7362
7633
  options.storage.dir,
7363
7634
  "state",
7364
7635
  "last_graph_recall.json"
7365
7636
  );
7366
- await mkdir3(path4.dirname(snapshotPath), { recursive: true });
7637
+ await mkdir3(path5.dirname(snapshotPath), { recursive: true });
7367
7638
  const now = (/* @__PURE__ */ new Date()).toISOString();
7368
7639
  const totalSeedCount = options.seedPaths.length;
7369
7640
  const totalExpandedCount = options.expandedPaths.length;
@@ -7397,12 +7668,12 @@ ${r.snippet.trim()}
7397
7668
  }
7398
7669
  async recordLastIntentSnapshot(options) {
7399
7670
  try {
7400
- const snapshotPath = path4.join(
7671
+ const snapshotPath = path5.join(
7401
7672
  options.storage.dir,
7402
7673
  "state",
7403
7674
  "last_intent.json"
7404
7675
  );
7405
- await mkdir3(path4.dirname(snapshotPath), { recursive: true });
7676
+ await mkdir3(path5.dirname(snapshotPath), { recursive: true });
7406
7677
  await writeFile3(
7407
7678
  snapshotPath,
7408
7679
  JSON.stringify(options.snapshot, null, 2),
@@ -7414,12 +7685,12 @@ ${r.snippet.trim()}
7414
7685
  }
7415
7686
  async recordLastQmdRecallSnapshot(options) {
7416
7687
  try {
7417
- const snapshotPath = path4.join(
7688
+ const snapshotPath = path5.join(
7418
7689
  options.storage.dir,
7419
7690
  "state",
7420
7691
  "last_qmd_recall.json"
7421
7692
  );
7422
- await mkdir3(path4.dirname(snapshotPath), { recursive: true });
7693
+ await mkdir3(path5.dirname(snapshotPath), { recursive: true });
7423
7694
  await writeFile3(
7424
7695
  snapshotPath,
7425
7696
  JSON.stringify(options.snapshot, null, 2),
@@ -7434,8 +7705,8 @@ ${r.snippet.trim()}
7434
7705
  const stateDir = await this.resolveStateDirForNamespace(
7435
7706
  options.namespace
7436
7707
  );
7437
- const snapshotPath = path4.join(stateDir, "last_intent.json");
7438
- await mkdir3(path4.dirname(snapshotPath), { recursive: true });
7708
+ const snapshotPath = path5.join(stateDir, "last_intent.json");
7709
+ await mkdir3(path5.dirname(snapshotPath), { recursive: true });
7439
7710
  await writeFile3(
7440
7711
  snapshotPath,
7441
7712
  JSON.stringify(options.snapshot, null, 2),
@@ -7447,12 +7718,12 @@ ${r.snippet.trim()}
7447
7718
  }
7448
7719
  async resolveStateDirForNamespace(namespace) {
7449
7720
  if (!resolveNamespaceCapabilities(this.config).namespaces) {
7450
- return path4.join(this.config.memoryDir, "state");
7721
+ return path5.join(this.config.memoryDir, "state");
7451
7722
  }
7452
7723
  if (namespace !== this.config.defaultNamespace) {
7453
- return path4.join(this.config.memoryDir, "namespaces", namespace, "state");
7724
+ return path5.join(this.config.memoryDir, "namespaces", namespace, "state");
7454
7725
  }
7455
- const candidate = path4.join(
7726
+ const candidate = path5.join(
7456
7727
  this.config.memoryDir,
7457
7728
  "namespaces",
7458
7729
  this.config.defaultNamespace
@@ -7460,11 +7731,11 @@ ${r.snippet.trim()}
7460
7731
  try {
7461
7732
  const candidateStat = await stat(candidate);
7462
7733
  if (candidateStat.isDirectory()) {
7463
- return path4.join(candidate, "state");
7734
+ return path5.join(candidate, "state");
7464
7735
  }
7465
7736
  } catch {
7466
7737
  }
7467
- return path4.join(this.config.memoryDir, "state");
7738
+ return path5.join(this.config.memoryDir, "state");
7468
7739
  }
7469
7740
  buildGraphRecallRankedResults(results, sourceLabelResolver, limit = 64) {
7470
7741
  return results.slice(0, limit).map((result) => ({
@@ -7765,7 +8036,7 @@ ${r.snippet.trim()}
7765
8036
  caps,
7766
8037
  signal: options.abortSignal
7767
8038
  });
7768
- if (this.config.recallPlannerTelemetryEnabled && recallDecision.plannerSource && recallDecision.plannerSource !== "heuristic") {
8039
+ if (resolveRecallEnhancementCapabilities(this.config).recallPlannerTelemetry && recallDecision.plannerSource && recallDecision.plannerSource !== "heuristic") {
7769
8040
  log.debug(
7770
8041
  `[recall-planner] mode=${recallDecision.shadowLlmMode ?? recallDecision.effectiveMode} source=${recallDecision.plannerSource} planned=${recallDecision.plannedMode} heuristic=${recallDecision.plannerHeuristicMode ?? recallDecision.plannedMode} model=${recallDecision.plannerModelUsed ?? "n/a"} latencyMs=${recallDecision.plannerLatencyMs ?? 0} fallback=${recallDecision.plannerFallbackUsed ?? false}` + (recallDecision.shadowLlmMode ? " (shadow)" : "")
7771
8042
  );
@@ -7866,7 +8137,7 @@ ${r.snippet.trim()}
7866
8137
  const graphExpandedResultPaths = /* @__PURE__ */ new Set();
7867
8138
  const graphSourceLabelsForPath = (resultPath) => {
7868
8139
  const labels = [];
7869
- const normalizedPath = resultPath.split(path4.sep).join("/");
8140
+ const normalizedPath = resultPath.split(path5.sep).join("/");
7870
8141
  const isEntityPath = normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/");
7871
8142
  if (graphBaselinePaths.has(resultPath)) labels.push("baseline");
7872
8143
  if (graphExpandedResultPaths.has(resultPath))
@@ -8016,7 +8287,7 @@ ${r.snippet.trim()}
8016
8287
  profileStorageNamespaces.map((namespace) => this.storageRouter.storageFor(namespace))
8017
8288
  );
8018
8289
  const emptyProfileStorage = new Proxy(
8019
- { dir: path4.join(this.config.memoryDir, ".empty-scope-profile") },
8290
+ { dir: path5.join(this.config.memoryDir, ".empty-scope-profile") },
8020
8291
  {
8021
8292
  get(target, prop) {
8022
8293
  if (prop in target) return target[prop];
@@ -8156,7 +8427,7 @@ ${r.snippet.trim()}
8156
8427
  const sharedContextPromise = (async () => {
8157
8428
  if (!this.isRecallSectionEnabled(
8158
8429
  "shared-context",
8159
- this.config.sharedContextEnabled === true
8430
+ resolveConversationContextCapabilities(this.config).sharedContext === true
8160
8431
  ))
8161
8432
  return null;
8162
8433
  if (!this.sharedContext) return null;
@@ -8234,7 +8505,7 @@ ${trimmedBody}`;
8234
8505
  })();
8235
8506
  let peerProfileXrayAnnotation = void 0;
8236
8507
  const peerProfileRecallPromise = (async () => {
8237
- if (!this.config.peerProfileRecallEnabled) return null;
8508
+ if (!resolveRecallEnhancementCapabilities(this.config).peerProfileRecall) return null;
8238
8509
  if (this.config.peerProfileRecallMaxFields <= 0) return null;
8239
8510
  const peerId = this.getPeerIdForSession(sessionKey);
8240
8511
  if (!peerId) return null;
@@ -8559,9 +8830,9 @@ ${rows.join("\n")}
8559
8830
  })();
8560
8831
  const causalTrajectoryPromise = (async () => {
8561
8832
  const t0 = Date.now();
8562
- if (!this.config.causalTrajectoryMemoryEnabled || !this.config.causalTrajectoryRecallEnabled || !this.isRecallSectionEnabled(
8833
+ if (!resolveRecallEnhancementCapabilities(this.config).causalTrajectoryMemory || !resolveRecallEnhancementCapabilities(this.config).causalTrajectoryRecall || !this.isRecallSectionEnabled(
8563
8834
  "causal-trajectories",
8564
- this.config.causalTrajectoryRecallEnabled === true
8835
+ resolveRecallEnhancementCapabilities(this.config).causalTrajectoryRecall === true
8565
8836
  )) {
8566
8837
  recordRecallSectionMetric({
8567
8838
  section: "causalTrajectories",
@@ -8606,9 +8877,9 @@ ${rows.join("\n")}
8606
8877
  })();
8607
8878
  const cmcRetrievalPromise = (async () => {
8608
8879
  const t0 = Date.now();
8609
- if (!this.config.cmcRetrievalEnabled || !this.isRecallSectionEnabled(
8880
+ if (!resolveRecallEnhancementCapabilities(this.config).cmcRetrieval || !this.isRecallSectionEnabled(
8610
8881
  "cmc-causal-chains",
8611
- this.config.cmcRetrievalEnabled === true
8882
+ resolveRecallEnhancementCapabilities(this.config).cmcRetrieval === true
8612
8883
  )) {
8613
8884
  recordRecallSectionMetric({
8614
8885
  section: "cmcCausalChains",
@@ -9436,7 +9707,7 @@ ${rows.join("\n")}
9436
9707
  }
9437
9708
  let section = null;
9438
9709
  let checkpointInjected = false;
9439
- if (this.config.checkpointEnabled) {
9710
+ if (resolvePipelineProcessingCapabilities(this.config).checkpoint) {
9440
9711
  const checkpoint = await this.transcript.loadCheckpoint(sessionKey);
9441
9712
  log.debug(
9442
9713
  `recall: checkpoint loaded, turns=${checkpoint?.turns?.length ?? 0}`
@@ -9492,11 +9763,11 @@ ${formatted}`;
9492
9763
  if (!resolveRecallAuxiliaryCapabilities(this.config).compactionReset) return null;
9493
9764
  const workspaceDir = compactionWorkspaceDir || this.config.workspaceDir || defaultWorkspaceDir();
9494
9765
  const safeSessionKey = sanitizeSessionKeyForFilename(effectiveSessionKey);
9495
- const signalPath = path4.join(
9766
+ const signalPath = path5.join(
9496
9767
  workspaceDir,
9497
9768
  `.compaction-reset-signal-${safeSessionKey}`
9498
9769
  );
9499
- const bootPath = path4.join(workspaceDir, "BOOT.md");
9770
+ const bootPath = path5.join(workspaceDir, "BOOT.md");
9500
9771
  try {
9501
9772
  const signalStat = await stat(signalPath).catch(() => null);
9502
9773
  if (!signalStat) return null;
@@ -9544,7 +9815,7 @@ ${formatted}`;
9544
9815
  })();
9545
9816
  const summariesPromise = (async () => {
9546
9817
  const t0 = Date.now();
9547
- if (!this.config.hourlySummariesEnabled || !sessionKey || !this.isRecallSectionEnabled("summaries", true)) {
9818
+ if (!resolvePipelineProcessingCapabilities(this.config).hourlySummaries || !sessionKey || !this.isRecallSectionEnabled("summaries", true)) {
9548
9819
  recordRecallSectionMetric({
9549
9820
  section: "summaries",
9550
9821
  priority: "core",
@@ -9729,7 +10000,7 @@ ${formatted}`;
9729
10000
  const compoundingPromise = observeEnrichmentPromise(
9730
10001
  (async () => {
9731
10002
  const t0 = Date.now();
9732
- if (!this.compounding || !this.config.compoundingInjectEnabled || !this.isRecallSectionEnabled("compounding", true)) {
10003
+ if (!this.compounding || !resolveRecallEnhancementCapabilities(this.config).compoundingInject || !this.isRecallSectionEnabled("compounding", true)) {
9733
10004
  recordRecallSectionMetric({
9734
10005
  section: "compounding",
9735
10006
  priority: "enrichment",
@@ -9970,7 +10241,7 @@ ${formatted}`;
9970
10241
  if (sharedCtx)
9971
10242
  this.appendRecallSection(sectionBuckets, "shared-context", sharedCtx);
9972
10243
  const explicitCueMaxChars = this.getRecallSectionMaxChars("explicit-cue") ?? this.config.explicitCueRecallMaxChars;
9973
- if (this.config.explicitCueRecallEnabled && this.isRecallSectionEnabled("explicit-cue") && explicitCueMaxChars !== 0 && this.lcmEngine?.enabled && recallMode !== "no_recall") {
10244
+ if (resolveRecallEnhancementCapabilities(this.config).explicitCueRecall && this.isRecallSectionEnabled("explicit-cue") && explicitCueMaxChars !== 0 && this.lcmEngine?.enabled && recallMode !== "no_recall") {
9974
10245
  try {
9975
10246
  const explicitCueSection = await buildExplicitCueRecallSection({
9976
10247
  engine: this.lcmEngine,
@@ -9999,7 +10270,7 @@ ${formatted}`;
9999
10270
  const targetedFactMaxChars = this.getRecallSectionMaxChars("targeted-facts") ?? this.config.targetedFactRecallMaxChars;
10000
10271
  if (this.isSpecializedRecallSectionEnabled(
10001
10272
  "targeted-facts",
10002
- this.config.targetedFactRecallEnabled
10273
+ resolveRecallEnhancementCapabilities(this.config).targetedFactRecall
10003
10274
  ) && targetedFactMaxChars !== 0 && this.lcmEngine?.enabled && recallMode !== "no_recall" && shouldRecallTargetedFactEvidence(retrievalQuery)) {
10004
10275
  try {
10005
10276
  const targetedFactSection = await buildTargetedFactRecallSection({
@@ -10029,7 +10300,7 @@ ${formatted}`;
10029
10300
  const focusedListMaxChars = this.getRecallSectionMaxChars("focused-list") ?? this.config.focusedListRecallMaxChars;
10030
10301
  if (this.isSpecializedRecallSectionEnabled(
10031
10302
  "focused-list",
10032
- this.config.focusedListRecallEnabled
10303
+ resolveRecallEnhancementCapabilities(this.config).focusedListRecall
10033
10304
  ) && focusedListMaxChars !== 0 && this.lcmEngine?.enabled && recallMode !== "no_recall" && shouldRecallFocusedListEvidence(retrievalQuery)) {
10034
10305
  try {
10035
10306
  const focusedListSection = await buildFocusedListRecallSection({
@@ -10063,7 +10334,7 @@ ${formatted}`;
10063
10334
  const responseGuidanceForcedByPipeline = responseGuidanceEntry?.forceGeneric === true && !responseGuidanceMatchesQuery;
10064
10335
  if (this.isSpecializedRecallSectionEnabled(
10065
10336
  "response-guidance",
10066
- this.config.responseGuidanceRecallEnabled
10337
+ resolveRecallEnhancementCapabilities(this.config).responseGuidanceRecall
10067
10338
  ) && responseGuidanceMaxChars !== 0 && this.lcmEngine?.enabled && recallMode !== "no_recall" && (responseGuidanceMatchesQuery || responseGuidanceForcedByPipeline)) {
10068
10339
  try {
10069
10340
  const responseGuidanceSection = await buildResponseGuidanceRecallSection({
@@ -10095,7 +10366,7 @@ ${formatted}`;
10095
10366
  const eventOrderMaxChars = this.getRecallSectionMaxChars("event-order") ?? this.config.eventOrderRecallMaxChars;
10096
10367
  if (this.isSpecializedRecallSectionEnabled(
10097
10368
  "event-order",
10098
- this.config.eventOrderRecallEnabled
10369
+ resolveRecallEnhancementCapabilities(this.config).eventOrderRecall
10099
10370
  ) && eventOrderMaxChars !== 0 && this.lcmEngine?.enabled && recallMode !== "no_recall" && shouldRecallEventOrderEvidence(retrievalQuery)) {
10100
10371
  try {
10101
10372
  const eventOrderSection = await firstNonEmptyLcmRead(
@@ -10388,7 +10659,7 @@ ${tmtNode.summary}`
10388
10659
  );
10389
10660
  const isFullModeGraphAssist = graphCaps.multiGraphMemory && caps.graphAssistInFullMode && recallMode === "full" && memoryResults.length >= Math.max(1, this.config.graphAssistMinSeedResults ?? 3);
10390
10661
  const shouldRunGraphExpansion = recallMode === "graph_mode" || isFullModeGraphAssist;
10391
- const graphShadowEvalEnabled = isFullModeGraphAssist && this.config.graphAssistShadowEvalEnabled === true;
10662
+ const graphShadowEvalEnabled = isFullModeGraphAssist && resolveRecallEnhancementCapabilities(this.config).graphAssistShadowEval === true;
10392
10663
  if (shouldRunGraphExpansion) {
10393
10664
  shouldPersistGraphSnapshot = true;
10394
10665
  graphDecisionShadowMode = graphShadowEvalEnabled;
@@ -10583,7 +10854,7 @@ ${tmtNode.summary}`
10583
10854
  retrievalQuery,
10584
10855
  caps
10585
10856
  );
10586
- if (this.config.memoryReconstructionEnabled && memoryResults.length > 0) {
10857
+ if (resolveRecallEnhancementCapabilities(this.config).memoryReconstruction && memoryResults.length > 0) {
10587
10858
  try {
10588
10859
  const snippets = memoryResults.map((r) => r.snippet);
10589
10860
  const coveredRefs = memoryResults.map((r) => r.path).filter((p) => p.startsWith("entities/")).map((p) => p.replace(/^entities\//, "").replace(/\.md$/, ""));
@@ -11888,7 +12159,7 @@ _Context: ${topQuestion.context}_`
11888
12159
  return ingestResult;
11889
12160
  }
11890
12161
  async observeSessionHeartbeat(sessionKey, options = {}) {
11891
- if (this.config.sessionObserverEnabled !== true) return;
12162
+ if (resolvePipelineProcessingCapabilities(this.config).sessionObserver !== true) return;
11892
12163
  if (!sessionKey || sessionKey.length === 0) return;
11893
12164
  const bufferKey = typeof options.bufferKey === "string" && options.bufferKey.length > 0 ? options.bufferKey : sessionKey;
11894
12165
  const previous = this.heartbeatObserverChains.get(sessionKey) ?? Promise.resolve();
@@ -12580,7 +12851,7 @@ ${normalized}`).digest("hex");
12580
12851
  this.maintenanceScheduler.requestQmdMaintenanceForTool(reason);
12581
12852
  }
12582
12853
  async persistExtraction(result, storage, threadIdForExtraction, sourceContext, baseNamespace, scopeProfileWritePlan, sourceText, graphCaps = resolveGraphConstructionCapabilities(this.config), lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config)) {
12583
- const citationEnabled = this.config.inlineSourceAttributionEnabled === true;
12854
+ const citationEnabled = resolvePipelineProcessingCapabilities(this.config).inlineSourceAttribution === true;
12584
12855
  const citationTemplate = this.config.inlineSourceAttributionFormat;
12585
12856
  const citationContextBase = citationEnabled ? {
12586
12857
  agent: sourceContext?.principal,
@@ -12677,7 +12948,7 @@ ${normalized}`).digest("hex");
12677
12948
  const actualTier = confidenceTier(confidence);
12678
12949
  const actualRank = confidenceTierOrder.indexOf(actualTier);
12679
12950
  if (actualRank === -1) return false;
12680
- if (!this.config.autoPromoteToSharedEnabled) return false;
12951
+ if (!resolveRecallEnhancementCapabilities(this.config).autoPromoteToShared) return false;
12681
12952
  if (!this.config.autoPromoteToSharedCategories.includes(category))
12682
12953
  return false;
12683
12954
  const minimumRank = confidenceTierOrder.indexOf(
@@ -13428,7 +13699,7 @@ ${normalized}`).digest("hex");
13428
13699
  const requireSpansPendingStatus = this.config.provenance?.requireSpans === true && fact.requireSpansPending === true ? "pending_review" : void 0;
13429
13700
  const faithfulnessEnforceStatus = faithfulnessGateStatus ?? requireSpansPendingStatus;
13430
13701
  let pendingSemanticSkip = null;
13431
- if (this.config.semanticDedupEnabled) {
13702
+ if (resolvePipelineProcessingCapabilities(this.config).semanticDedup) {
13432
13703
  let semanticDecision;
13433
13704
  if (batchBackendUnavailable) {
13434
13705
  semanticDecision = { action: "keep", reason: "backend_unavailable" };
@@ -13461,7 +13732,7 @@ ${normalized}`).digest("hex");
13461
13732
  pendingSemanticSkip = semanticDecision;
13462
13733
  }
13463
13734
  }
13464
- const inferredIntent = this.config.intentRoutingEnabled ? inferIntentFromText(
13735
+ const inferredIntent = resolveConversationContextCapabilities(this.config).intentRouting ? inferIntentFromText(
13465
13736
  `${writeCategory} ${fact.tags.join(" ")} ${fact.content}`
13466
13737
  ) : null;
13467
13738
  const extractionWriteSource = fact.source === "proactive" ? "extraction-proactive" : "extraction";
@@ -13469,7 +13740,7 @@ ${normalized}`).digest("hex");
13469
13740
  let links = [];
13470
13741
  let contradictionDetected = false;
13471
13742
  let contradiction;
13472
- if (this.config.contradictionDetectionEnabled && this.qmd.isAvailable() && faithfulnessEnforceStatus !== "pending_review") {
13743
+ if (resolveRecallEnhancementCapabilities(this.config).contradictionDetection && this.qmd.isAvailable() && faithfulnessEnforceStatus !== "pending_review") {
13473
13744
  const targetNamespace = this.storageDirNamespace(targetStorage.dir);
13474
13745
  contradiction = await this.checkForContradiction(
13475
13746
  fact.content,
@@ -13499,9 +13770,9 @@ ${normalized}`).digest("hex");
13499
13770
  dedupedCount++;
13500
13771
  continue;
13501
13772
  }
13502
- if (this.config.chunkingEnabled && writeCategory !== "procedure") {
13773
+ if (resolvePipelineProcessingCapabilities(this.config).chunking && writeCategory !== "procedure") {
13503
13774
  let chunkResult;
13504
- if (this.config.semanticChunkingEnabled) {
13775
+ if (resolvePipelineProcessingCapabilities(this.config).semanticChunking) {
13505
13776
  try {
13506
13777
  const embedFn = this.embeddingFallback.embedTexts.bind(this.embeddingFallback);
13507
13778
  const semanticResult = await semanticChunkContent(
@@ -13752,7 +14023,7 @@ ${normalized}`).digest("hex");
13752
14023
  continue;
13753
14024
  }
13754
14025
  }
13755
- if (this.config.memoryLinkingEnabled && this.qmd.isAvailable()) {
14026
+ if (resolveRecallEnhancementCapabilities(this.config).memoryLinking && this.qmd.isAvailable()) {
13756
14027
  const targetNamespace = this.storageDirNamespace(targetStorage.dir);
13757
14028
  const suggestedLinks = await this.suggestLinksForMemory(
13758
14029
  fact.content,
@@ -13964,7 +14235,7 @@ ${normalized}`).digest("hex");
13964
14235
  log.warn(`persistExtraction: entity write failed: ${err}`);
13965
14236
  }
13966
14237
  }
13967
- if (this.config.entityRelationshipsEnabled && Array.isArray(result.relationships)) {
14238
+ if (resolveRecallEnhancementCapabilities(this.config).entityRelationships && Array.isArray(result.relationships)) {
13968
14239
  for (const rel of result.relationships.slice(0, 5)) {
13969
14240
  if (!rel.source || !rel.target || !rel.label) continue;
13970
14241
  try {
@@ -13983,7 +14254,7 @@ ${normalized}`).digest("hex");
13983
14254
  }
13984
14255
  }
13985
14256
  }
13986
- if (this.config.entityActivityLogEnabled) {
14257
+ if (resolveRecallEnhancementCapabilities(this.config).entityActivityLog) {
13987
14258
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
13988
14259
  for (const entity of entities) {
13989
14260
  const name = entity?.name;
@@ -14012,7 +14283,7 @@ ${normalized}`).digest("hex");
14012
14283
  recordDurableNonFactWrite();
14013
14284
  }
14014
14285
  }
14015
- if (this.config.identityEnabled && result.identityReflection) {
14286
+ if (resolveRecallEnhancementCapabilities(this.config).identity && result.identityReflection) {
14016
14287
  try {
14017
14288
  await storage.appendIdentityReflection(result.identityReflection);
14018
14289
  recordDurableNonFactWrite();
@@ -14098,7 +14369,7 @@ ${normalized}`).digest("hex");
14098
14369
  const allMems = allMemsForGraph ?? [];
14099
14370
  for (const m of allMems) {
14100
14371
  if (m.frontmatter.entityRef === entityRef) {
14101
- const rel = path4.relative(storage.dir, m.path);
14372
+ const rel = path5.relative(storage.dir, m.path);
14102
14373
  if (rel !== memoryRelPath) entitySiblings.push(rel);
14103
14374
  }
14104
14375
  }
@@ -14395,7 +14666,7 @@ ${normalized}`).digest("hex");
14395
14666
  const tierMigration = await this.runTierMigrationCycle(this.storage, "maintenance");
14396
14667
  if (tierMigration.migrated > 0) memoryItemMutated = true;
14397
14668
  allMemories = await this.storage.readAllMemories();
14398
- if (this.config.factArchivalEnabled) {
14669
+ if (resolveRecallEnhancementCapabilities(this.config).factArchival) {
14399
14670
  const archived = await this.runFactArchival(allMemories);
14400
14671
  if (archived > 0) {
14401
14672
  memoryItemMutated = true;
@@ -14422,7 +14693,7 @@ ${normalized}`).digest("hex");
14422
14693
  }
14423
14694
  if (resolveConsolidationCapabilities(this.config).semanticConsolidation) {
14424
14695
  try {
14425
- const stateFilePath = path4.join(
14696
+ const stateFilePath = path5.join(
14426
14697
  this.config.memoryDir,
14427
14698
  "state",
14428
14699
  "semantic-consolidation-last-run.json"
@@ -14470,7 +14741,7 @@ ${normalized}`).digest("hex");
14470
14741
  );
14471
14742
  }
14472
14743
  if (semResult.errors === 0 || semResult.memoriesArchived > 0) {
14473
- const stateDir = path4.join(this.config.memoryDir, "state");
14744
+ const stateDir = path5.join(this.config.memoryDir, "state");
14474
14745
  await mkdir3(stateDir, { recursive: true });
14475
14746
  await writeFile3(
14476
14747
  stateFilePath,
@@ -14485,7 +14756,7 @@ ${normalized}`).digest("hex");
14485
14756
  );
14486
14757
  }
14487
14758
  }
14488
- if (this.config.identityEnabled) {
14759
+ if (resolveRecallEnhancementCapabilities(this.config).identity) {
14489
14760
  await this.autoConsolidateIdentity();
14490
14761
  }
14491
14762
  const profileSection = this.getRecallSectionEntry("profile");
@@ -14510,10 +14781,10 @@ ${normalized}`).digest("hex");
14510
14781
  }
14511
14782
  }
14512
14783
  }
14513
- if (this.config.summarizationEnabled) {
14784
+ if (resolvePipelineProcessingCapabilities(this.config).summarization) {
14514
14785
  await this.runSummarization(allMemories);
14515
14786
  }
14516
- if (this.config.topicExtractionEnabled) {
14787
+ if (resolvePipelineProcessingCapabilities(this.config).topicExtraction) {
14517
14788
  await this.runTopicExtraction(allMemories);
14518
14789
  }
14519
14790
  const meta = await this.storage.loadMeta();
@@ -14791,7 +15062,7 @@ ${reflectionsContent.trim()}
14791
15062
  const seenStorageDirs = /* @__PURE__ */ new Set();
14792
15063
  const addStorage = (storage) => {
14793
15064
  const storageDir = storageDirFor(storage);
14794
- const storageKey = storageDir ? path4.resolve(storageDir) : `storage-without-dir-${storages.length}`;
15065
+ const storageKey = storageDir ? path5.resolve(storageDir) : `storage-without-dir-${storages.length}`;
14795
15066
  if (seenStorageDirs.has(storageKey)) return;
14796
15067
  seenStorageDirs.add(storageKey);
14797
15068
  storages.push(storage);
@@ -14821,7 +15092,7 @@ ${reflectionsContent.trim()}
14821
15092
  continue;
14822
15093
  }
14823
15094
  try {
14824
- const coldRoot = path4.join(storageDir, "cold");
15095
+ const coldRoot = path5.join(storageDir, "cold");
14825
15096
  for (const candidate of qmdResultPathCandidates(
14826
15097
  coldRoot,
14827
15098
  parts.relativePath
@@ -14862,7 +15133,7 @@ ${reflectionsContent.trim()}
14862
15133
  return null;
14863
15134
  }
14864
15135
  }
14865
- if (path4.isAbsolute(resultPath)) {
15136
+ if (path5.isAbsolute(resultPath)) {
14866
15137
  if (!fallbackStorageDir) {
14867
15138
  return await fallbackStorage.readMemoryByPath(resultPath);
14868
15139
  }
@@ -14901,7 +15172,7 @@ ${reflectionsContent.trim()}
14901
15172
  );
14902
15173
  if (!memory) return null;
14903
15174
  let ownerNamespace = null;
14904
- if (path4.isAbsolute(memory.path)) {
15175
+ if (path5.isAbsolute(memory.path)) {
14905
15176
  const ownerStorage = await this.storageForAbsoluteQmdResultPath(
14906
15177
  memory.path,
14907
15178
  fallbackStorage,
@@ -14925,16 +15196,16 @@ ${reflectionsContent.trim()}
14925
15196
  };
14926
15197
  }
14927
15198
  async storageForAbsoluteQmdResultPath(resultPath, fallbackStorage, recallNamespaces = []) {
14928
- const resolvedPath = path4.resolve(resultPath);
14929
- const memoryRoot = path4.resolve(this.config.memoryDir);
14930
- const namespacesRoot = path4.join(memoryRoot, "namespaces");
15199
+ const resolvedPath = path5.resolve(resultPath);
15200
+ const memoryRoot = path5.resolve(this.config.memoryDir);
15201
+ const namespacesRoot = path5.join(memoryRoot, "namespaces");
14931
15202
  const fallbackStorageDir = typeof fallbackStorage.dir === "string" && fallbackStorage.dir ? fallbackStorage.dir : null;
14932
15203
  const matches = [];
14933
15204
  const seenDirs = /* @__PURE__ */ new Set();
14934
15205
  const maybeAddStorage = (storage, namespace) => {
14935
15206
  const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
14936
15207
  if (!storageDir) return;
14937
- const candidateRoot = path4.resolve(storageDir);
15208
+ const candidateRoot = path5.resolve(storageDir);
14938
15209
  if (seenDirs.has(candidateRoot)) return;
14939
15210
  if (!isPathInsideStorageRoot(candidateRoot, resolvedPath)) return;
14940
15211
  if (candidateRoot === memoryRoot && isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
@@ -14952,7 +15223,7 @@ ${reflectionsContent.trim()}
14952
15223
  candidateNamespaces.add(ns);
14953
15224
  }
14954
15225
  if (isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
14955
- const relativeToNamespaces = path4.relative(namespacesRoot, resolvedPath);
15226
+ const relativeToNamespaces = path5.relative(namespacesRoot, resolvedPath);
14956
15227
  const [namespaceSegment] = relativeToNamespaces.split(/[\\/]/);
14957
15228
  if (namespaceSegment) {
14958
15229
  candidateNamespaces.add(
@@ -14974,218 +15245,22 @@ ${reflectionsContent.trim()}
14974
15245
  matches.sort((a, b) => b.dir.length - a.dir.length);
14975
15246
  return matches[0] ?? null;
14976
15247
  }
15248
+ // Issue #1526: recall-rerank methods moved to RecallRerankCoordinator.
15249
+ // Thin delegation keeps the private API stable for callers + tests.
14977
15250
  async applyMemoryWorthRerank(results, namespaces) {
14978
- const counters = /* @__PURE__ */ new Map();
14979
- const seenNamespaces = /* @__PURE__ */ new Set();
14980
- const nowMs = Date.now();
14981
- for (const [key, entry] of this.memoryWorthCounterCache) {
14982
- if (nowMs - entry.at >= _Orchestrator.MEMORY_WORTH_CACHE_TTL_MS) {
14983
- this.memoryWorthCounterCache.delete(key);
14984
- }
14985
- }
14986
- for (const ns of namespaces) {
14987
- if (seenNamespaces.has(ns)) continue;
14988
- seenNamespaces.add(ns);
14989
- try {
14990
- const cached = this.memoryWorthCounterCache.get(ns);
14991
- let nsMap;
14992
- if (cached && nowMs - cached.at < _Orchestrator.MEMORY_WORTH_CACHE_TTL_MS) {
14993
- nsMap = cached.counters;
14994
- } else {
14995
- const storage = await this.getStorage(ns);
14996
- const memories = await storage.readAllMemories();
14997
- nsMap = buildMemoryWorthCounterMap(memories);
14998
- this.memoryWorthCounterCache.set(ns, { at: nowMs, counters: nsMap });
14999
- }
15000
- for (const [path5, c] of nsMap) counters.set(path5, c);
15001
- } catch (err) {
15002
- log.debug("memory-worth: failed to read namespace, skipping", {
15003
- namespace: ns,
15004
- error: err.message
15005
- });
15006
- }
15007
- }
15008
- const missing = results.filter((r) => !counters.has(r.path));
15009
- if (missing.length > 0) {
15010
- let reader = null;
15011
- for (const ns of namespaces) {
15012
- try {
15013
- reader = await this.getStorage(ns);
15014
- break;
15015
- } catch {
15016
- }
15017
- }
15018
- if (reader) {
15019
- for (const r of missing) {
15020
- try {
15021
- const memory = await this.readQmdResultMemory(r.path, reader, namespaces);
15022
- if (!memory) continue;
15023
- const fm = memory.frontmatter;
15024
- if (fm.mw_success === void 0 && fm.mw_fail === void 0) continue;
15025
- counters.set(r.path, {
15026
- mw_success: fm.mw_success,
15027
- mw_fail: fm.mw_fail,
15028
- lastAccessed: fm.lastAccessed
15029
- });
15030
- } catch (err) {
15031
- log.debug("memory-worth: direct path lookup failed", {
15032
- path: r.path,
15033
- error: err.message
15034
- });
15035
- }
15036
- }
15037
- }
15038
- }
15039
- if (counters.size === 0) return results;
15040
- const rankedInputs = results.map((r, i) => ({
15041
- path: r.path,
15042
- // Large positive rank score so multiplier math stays well-scaled and
15043
- // we never hit zero; descending so earlier items rank higher.
15044
- score: results.length - i
15045
- }));
15046
- const filtered = applyMemoryWorthFilter(rankedInputs, {
15047
- counters,
15048
- now: /* @__PURE__ */ new Date(),
15049
- halfLifeMs: this.config.recallMemoryWorthHalfLifeMs > 0 ? this.config.recallMemoryWorthHalfLifeMs : void 0
15050
- });
15051
- const byPath = new Map(results.map((r) => [r.path, r]));
15052
- const reordered = [];
15053
- for (const item of filtered) {
15054
- const original = byPath.get(item.path);
15055
- if (original) reordered.push(original);
15056
- }
15057
- return reordered;
15251
+ return this.recallRerankCoordinator.applyMemoryWorthRerank(results, namespaces);
15058
15252
  }
15059
- /**
15060
- * Issue #1577 — unified TrustScore recall stage. Thin wiring over the pure
15061
- * {@link applyTrustScoreStage} scorer + the {@link buildTrustSignalsForRerank}
15062
- * signal builder. The stage subsumes the Memory Worth multiplier — the
15063
- * orchestrator runs exactly one of the two (mutual exclusion, rule 39; the
15064
- * double-multiplier test in trust-score-stage.test.ts pins it structurally).
15065
- *
15066
- * Returns the admitted results AND the per-path trust map (including
15067
- * quarantined items) so the caller can: (a) render epistemic hedges, (b)
15068
- * surface quarantined items in X-ray with a reason (rule 34), and (c) filter
15069
- * quarantined paths from fallback recall branches. The trust map is a
15070
- * per-recall local — never instance state — so concurrent recalls cannot
15071
- * race on it (review: shared-trust-map concurrency).
15072
- */
15073
15253
  async applyTrustScoreRerank(results, namespaces) {
15074
- if (results.length === 0) return { results, trustByPath: null };
15075
- const now = /* @__PURE__ */ new Date();
15076
- const halfLifeDays = this.config.recallMemoryWorthHalfLifeMs > 0 ? this.config.recallMemoryWorthHalfLifeMs / (24 * 60 * 60 * 1e3) : void 0;
15077
- let fallbackReader = null;
15078
- const signals = await buildTrustSignalsForRerank(
15079
- results.map((r) => r.path),
15080
- namespaces,
15081
- {
15082
- readNamespaceMemories: async (ns) => (await this.getStorage(ns)).readAllMemories(),
15083
- readMemoryFrontmatter: async (path5) => {
15084
- if (!fallbackReader) {
15085
- for (const ns of namespaces) {
15086
- try {
15087
- fallbackReader = await this.getStorage(ns);
15088
- break;
15089
- } catch {
15090
- }
15091
- }
15092
- }
15093
- if (!fallbackReader) return null;
15094
- const memory = await this.readQmdResultMemory(path5, fallbackReader, namespaces);
15095
- return memory ? memory.frontmatter : null;
15096
- }
15097
- },
15098
- { cache: this.trustSignalCache, ttlMs: _Orchestrator.TRUST_SIGNAL_CACHE_TTL_MS },
15099
- now,
15100
- {
15101
- recencyHalfLifeDays: halfLifeDays,
15102
- logDebug: (message, context) => log.debug(message, context)
15103
- }
15104
- );
15105
- if (signals.size === 0) {
15106
- return { results, trustByPath: null };
15107
- }
15108
- const rankedInputs = results.map((r, i) => ({ path: r.path, score: results.length - i }));
15109
- const stage = applyTrustScoreStage(rankedInputs, {
15110
- signals,
15111
- weights: this.config.trustScoreWeights,
15112
- minMultiplier: this.config.trustScoreMinMultiplier,
15113
- maxMultiplier: this.config.trustScoreMaxMultiplier,
15114
- quarantine: this.config.trustScoreQuarantine
15115
- });
15116
- const trustByPath = new Map(stage.all.map((item) => [item.path, item]));
15117
- const byPath = new Map(results.map((r) => [r.path, r]));
15118
- const admitted = stage.admitted.map((item) => byPath.get(item.path)).filter((r) => r !== void 0);
15119
- return { results: admitted, trustByPath };
15254
+ return this.recallRerankCoordinator.applyTrustScoreRerank(results, namespaces);
15120
15255
  }
15121
- /**
15122
- * Issue #1577 — apply the TrustScore stage (or, when trust is off, the Memory
15123
- * Worth multiplier fallback) to ONE recall branch's results, returning the
15124
- * scored results + the per-path trust map. Thin wiring over
15125
- * {@link applyTrustScoreRerank} so every recall path — hot QMD, embedding
15126
- * fallback, recent scan — applies the SAME multiplier gate (rule 41: a
15127
- * feature gate must apply across ALL parallel recall paths). TrustScore
15128
- * subsumes Memory Worth; exactly one runs (rule 39). Fail-open on lookup
15129
- * errors so a storage hiccup never breaks a fallback path.
15130
- */
15131
15256
  async applyTrustScoreToBranch(results, namespaces, caps, label) {
15132
- if (caps.recallTrustScore && results.length > 0) {
15133
- try {
15134
- return await this.applyTrustScoreRerank(results, namespaces);
15135
- } catch (err) {
15136
- log.debug(`trust-score stage (${label}) failed open`, {
15137
- error: err.message
15138
- });
15139
- }
15140
- } else if (caps.recallMemoryWorthFilter && results.length > 0) {
15141
- try {
15142
- const filtered = await this.applyMemoryWorthRerank(results, namespaces);
15143
- return { results: filtered, trustByPath: null };
15144
- } catch (err) {
15145
- log.debug(`memory-worth filter (${label}) failed open`, {
15146
- error: err.message
15147
- });
15148
- }
15149
- }
15150
- return { results, trustByPath: null };
15257
+ return this.recallRerankCoordinator.applyTrustScoreToBranch(results, namespaces, caps, label);
15151
15258
  }
15152
15259
  diversifyAndLimitRecallResults(sectionId, results, limit, retrievalQuery, caps = resolveCapabilities(this.config)) {
15153
- const safeLimit = typeof limit === "number" && Number.isFinite(limit) ? Math.max(0, Math.floor(limit)) : 0;
15154
- if (!Array.isArray(results) || results.length === 0) return [];
15155
- if (safeLimit === 0) return [];
15156
- const boosted = caps.recallReasoningTraceBoost && typeof retrievalQuery === "string" ? applyReasoningTraceBoost(results, {
15157
- enabled: true,
15158
- query: retrievalQuery
15159
- }) : results;
15160
- const diversified = this.applyMmrToQmdResults(sectionId, boosted, caps);
15161
- return diversified.slice(0, safeLimit);
15260
+ return this.recallRerankCoordinator.diversifyAndLimitRecallResults(sectionId, results, limit, retrievalQuery, caps);
15162
15261
  }
15163
- /**
15164
- * Apply Maximal Marginal Relevance to a section's ordered candidate list.
15165
- *
15166
- * Operates per-section so one redundant cluster cannot dominate a section,
15167
- * and so one section's MMR pass cannot starve other sections. Returns the
15168
- * input unchanged when disabled, when there are fewer than 2 candidates, or
15169
- * when no budget information is available.
15170
- */
15171
15262
  applyMmrToQmdResults(sectionId, results, caps = resolveCapabilities(this.config)) {
15172
- if (!caps.recallMmr) return results;
15173
- if (!Array.isArray(results) || results.length < 2) return results;
15174
- const configuredTopN = this.config.recallMmrTopN;
15175
- const topN = typeof configuredTopN === "number" && Number.isFinite(configuredTopN) ? Math.max(0, Math.floor(configuredTopN)) : 40;
15176
- if (topN === 0) return results;
15177
- const lambda = this.config.recallMmrLambda ?? 0.7;
15178
- const { reordered, diversity } = reorderRecallResultsWithMmr(results, {
15179
- lambda,
15180
- topN
15181
- });
15182
- try {
15183
- log.info(
15184
- `recall_mmr: section=${sectionId} kept=${diversity.kept}/${diversity.considered} headReorderCount=${diversity.headReorderCount} avgSimBefore=${diversity.avgPairwiseSimBefore.toFixed(3)} avgSimAfter=${diversity.avgPairwiseSimAfter.toFixed(3)} lambda=${lambda.toFixed(2)}`
15185
- );
15186
- } catch {
15187
- }
15188
- return reordered;
15263
+ return this.recallRerankCoordinator.applyMmrToQmdResults(sectionId, results, caps);
15189
15264
  }
15190
15265
  buildLastRecallBudgetSummary(options) {
15191
15266
  return {
@@ -15261,12 +15336,12 @@ ${reflectionsContent.trim()}
15261
15336
  */
15262
15337
  semanticDedupScopeFor(targetStorage) {
15263
15338
  if (!resolveNamespaceCapabilities(this.config).namespaces) return {};
15264
- const memoryDir = path4.resolve(this.config.memoryDir);
15265
- const storageDir = path4.resolve(targetStorage.dir);
15339
+ const memoryDir = path5.resolve(this.config.memoryDir);
15340
+ const storageDir = path5.resolve(targetStorage.dir);
15266
15341
  if (storageDir === memoryDir) {
15267
15342
  return { pathExcludePrefixes: ["namespaces/"] };
15268
15343
  }
15269
- let rel = path4.relative(memoryDir, storageDir);
15344
+ let rel = path5.relative(memoryDir, storageDir);
15270
15345
  if (!rel || rel.startsWith("..")) {
15271
15346
  log.debug(
15272
15347
  `semantic dedup: target storage dir ${storageDir} is outside memoryDir ${memoryDir}; scoping lookup to absolute path prefix`
@@ -15285,7 +15360,7 @@ ${reflectionsContent.trim()}
15285
15360
  if (hits.length === 0) return [];
15286
15361
  const results = [];
15287
15362
  for (const hit of hits) {
15288
- const fullPath = path4.isAbsolute(hit.path) ? hit.path : path4.join(this.config.memoryDir, hit.path);
15363
+ const fullPath = path5.isAbsolute(hit.path) ? hit.path : path5.join(this.config.memoryDir, hit.path);
15289
15364
  const memory = await this.storage.readMemoryByPath(fullPath);
15290
15365
  if (!memory) continue;
15291
15366
  results.push({
@@ -15482,7 +15557,7 @@ ${reflectionsContent.trim()}
15482
15557
  const storage = await this.storageRouter.storageFor(namespace);
15483
15558
  const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
15484
15559
  if (!storageDir) continue;
15485
- const recallRoot = path4.resolve(storageDir);
15560
+ const recallRoot = path5.resolve(storageDir);
15486
15561
  if (seenRecallRoots.has(recallRoot)) continue;
15487
15562
  seenRecallRoots.add(recallRoot);
15488
15563
  recallRoots.push(recallRoot);
@@ -15506,8 +15581,8 @@ ${reflectionsContent.trim()}
15506
15581
  if (resolvedCold) scopedResults.push(resolvedCold.result);
15507
15582
  continue;
15508
15583
  }
15509
- if (path4.isAbsolute(result.path)) {
15510
- const resolvedPath = path4.resolve(result.path);
15584
+ if (path5.isAbsolute(result.path)) {
15585
+ const resolvedPath = path5.resolve(result.path);
15511
15586
  if (recallRoots.some(
15512
15587
  (recallRoot) => isPathInsideStorageRoot(recallRoot, resolvedPath)
15513
15588
  )) {
@@ -15663,7 +15738,7 @@ ${reflectionsContent.trim()}
15663
15738
  * Updates are batched in memory and flushed during consolidation.
15664
15739
  */
15665
15740
  trackMemoryAccess(memoryIds) {
15666
- if (!this.config.accessTrackingEnabled) return;
15741
+ if (!resolveRecallEnhancementCapabilities(this.config).accessTracking) return;
15667
15742
  const now = (/* @__PURE__ */ new Date()).toISOString();
15668
15743
  for (const id of memoryIds) {
15669
15744
  const existing = this.accessTrackingBuffer.get(id);
@@ -15963,7 +16038,7 @@ ${reflectionsContent.trim()}
15963
16038
  temporalFromDate !== null ? queryByDateRangeAsync(this.config.memoryDir, temporalFromDate) : Promise.resolve(null),
15964
16039
  promptTags.length > 0 ? queryByTagsAsync(this.config.memoryDir, promptTags) : Promise.resolve(null)
15965
16040
  ]);
15966
- const queryIntent = this.config.intentRoutingEnabled && prompt ? inferIntentFromText(prompt) : null;
16041
+ const queryIntent = resolveConversationContextCapabilities(this.config).intentRouting && prompt ? inferIntentFromText(prompt) : null;
15967
16042
  let temporalCandidates = null;
15968
16043
  let tagCandidates = null;
15969
16044
  if (resolveIndexingCapabilities(this.config).queryAwareIndexing && prompt) {
@@ -16013,7 +16088,7 @@ ${reflectionsContent.trim()}
16013
16088
  importanceBoost >= 0 ? "boost" : "suppress"
16014
16089
  );
16015
16090
  }
16016
- if (this.config.feedbackEnabled) {
16091
+ if (resolveRecallEnhancementCapabilities(this.config).feedback) {
16017
16092
  const match = memory.path.match(/([^/]+)\.md$/);
16018
16093
  const memoryId = match ? match[1] : null;
16019
16094
  if (memoryId) {
@@ -16025,7 +16100,7 @@ ${reflectionsContent.trim()}
16025
16100
  );
16026
16101
  }
16027
16102
  }
16028
- if (this.config.negativeExamplesEnabled) {
16103
+ if (resolvePipelineProcessingCapabilities(this.config).negativeExamples) {
16029
16104
  const match = memory.path.match(/([^/]+)\.md$/);
16030
16105
  const memoryId = match ? match[1] : null;
16031
16106
  if (memoryId) {
@@ -16080,7 +16155,7 @@ ${reflectionsContent.trim()}
16080
16155
  lifecycleDelta >= 0 ? "boost" : "suppress"
16081
16156
  );
16082
16157
  let reinforcementBoost = 0;
16083
- if (this.config.reinforcementRecallBoostEnabled && typeof memory.frontmatter.reinforcement_count === "number" && memory.frontmatter.reinforcement_count > 0) {
16158
+ if (resolveRecallEnhancementCapabilities(this.config).reinforcementRecallBoost && typeof memory.frontmatter.reinforcement_count === "number" && memory.frontmatter.reinforcement_count > 0) {
16084
16159
  reinforcementBoost = Math.min(
16085
16160
  memory.frontmatter.reinforcement_count * this.config.reinforcementRecallBoostWeight,
16086
16161
  this.config.reinforcementRecallBoostMax
@@ -16441,4 +16516,4 @@ export {
16441
16516
  resolvePersistedMemoryRelativePath,
16442
16517
  Orchestrator
16443
16518
  };
16444
- //# sourceMappingURL=chunk-EKQ3LWBM.js.map
16519
+ //# sourceMappingURL=chunk-VC7QELR6.js.map