@remnic/core 9.62.1 → 9.63.0

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 (484) hide show
  1. package/dist/access-admin-ops-surface.d.ts +11 -11
  2. package/dist/access-admin-ops-surface.js +26 -26
  3. package/dist/access-audit.js +2 -2
  4. package/dist/access-authorization-probe.d.ts +11 -11
  5. package/dist/access-authorization-probe.js +27 -27
  6. package/dist/access-boundary.d.ts +11 -11
  7. package/dist/access-boundary.js +26 -26
  8. package/dist/access-cli.js +88 -86
  9. package/dist/access-cli.js.map +1 -1
  10. package/dist/access-coding-context-resolution.d.ts +1 -1
  11. package/dist/access-extraction-force-flush.d.ts +11 -11
  12. package/dist/access-extraction-force-flush.js +26 -26
  13. package/dist/access-health-types.d.ts +1 -1
  14. package/dist/access-http-lcm-compaction.d.ts +11 -11
  15. package/dist/access-http-lifecycle-flush.d.ts +11 -11
  16. package/dist/access-http-offline-stream.d.ts +11 -11
  17. package/dist/access-http-query.js +26 -26
  18. package/dist/access-http.d.ts +12 -12
  19. package/dist/access-http.js +36 -36
  20. package/dist/access-identity-continuity-surface.d.ts +9 -9
  21. package/dist/access-identity-continuity-surface.js +26 -26
  22. package/dist/access-lcm-surface.d.ts +11 -11
  23. package/dist/access-lcm-surface.js +26 -26
  24. package/dist/access-mcp.d.ts +11 -11
  25. package/dist/access-mcp.js +31 -31
  26. package/dist/access-memory-search-fanout.d.ts +2 -2
  27. package/dist/{access-namespace-preflight-EMvicnrb.d.ts → access-namespace-preflight-yO4LMGFH.d.ts} +1 -1
  28. package/dist/access-namespace-preflight.d.ts +3 -3
  29. package/dist/access-namespace-preflight.js +26 -26
  30. package/dist/access-observe-write-surface.d.ts +11 -11
  31. package/dist/access-observe-write-surface.js +26 -26
  32. package/dist/access-offline-manifest.d.ts +9 -9
  33. package/dist/access-offline-manifest.js +2 -2
  34. package/dist/access-operations-batch.js +27 -27
  35. package/dist/access-operations.d.ts +11 -11
  36. package/dist/access-operations.js +30 -30
  37. package/dist/access-recall-concurrency.d.ts +11 -11
  38. package/dist/access-recall-concurrency.js +26 -26
  39. package/dist/access-recall-response.d.ts +11 -11
  40. package/dist/access-recall-response.js +26 -26
  41. package/dist/access-recall-surface.d.ts +11 -11
  42. package/dist/access-recall-surface.js +26 -26
  43. package/dist/{access-service-BeDYQQ62.d.ts → access-service-M4LgO141.d.ts} +7 -7
  44. package/dist/access-service-helpers.d.ts +11 -11
  45. package/dist/access-service.d.ts +11 -11
  46. package/dist/access-service.js +26 -26
  47. package/dist/access-surface-catalog.d.ts +11 -11
  48. package/dist/access-surface-catalog.js +28 -28
  49. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  50. package/dist/action-confidence.d.ts +1 -1
  51. package/dist/active-memory-bridge.d.ts +1 -1
  52. package/dist/active-recall.d.ts +1 -1
  53. package/dist/active-recall.js +1 -1
  54. package/dist/ambient-provenance.d.ts +1 -1
  55. package/dist/artifact-search.d.ts +1 -1
  56. package/dist/{auto-sync-FMWQQB3J.js → auto-sync-Z52VWMNC.js} +3 -3
  57. package/dist/behavior-learner.d.ts +1 -1
  58. package/dist/behavior-learner.js +2 -2
  59. package/dist/behavior-signals.d.ts +1 -1
  60. package/dist/bootstrap.d.ts +9 -9
  61. package/dist/briefing-window.d.ts +2 -2
  62. package/dist/briefing.d.ts +2 -2
  63. package/dist/briefing.js +11 -10
  64. package/dist/buffer-surprise-report.d.ts +1 -1
  65. package/dist/buffer-turn-helpers.d.ts +1 -1
  66. package/dist/buffer.d.ts +2 -2
  67. package/dist/bulk-import/index.d.ts +3 -3
  68. package/dist/calibration.d.ts +1 -1
  69. package/dist/capabilities.d.ts +1 -1
  70. package/dist/{catalog-B2SxZ6LU.d.ts → catalog-CyYTf_ok.d.ts} +1 -1
  71. package/dist/causal-behavior.d.ts +1 -1
  72. package/dist/causal-behavior.js +3 -3
  73. package/dist/causal-chain.js +3 -3
  74. package/dist/causal-consolidation.d.ts +1 -1
  75. package/dist/causal-consolidation.js +14 -14
  76. package/dist/causal-retrieval.js +3 -3
  77. package/dist/causal-trajectory-graph.d.ts +1 -1
  78. package/dist/causal-trajectory.js +2 -2
  79. package/dist/{chunk-B2QHVLJO.js → chunk-256FBCVX.js} +22 -10
  80. package/dist/chunk-256FBCVX.js.map +1 -0
  81. package/dist/{chunk-QP2IZTUR.js → chunk-2TYIAKU5.js} +2 -2
  82. package/dist/{chunk-QNMNNFKD.js → chunk-347ZR6D4.js} +2 -2
  83. package/dist/{chunk-76YNCJ5H.js → chunk-3F3CVVDS.js} +2 -2
  84. package/dist/{chunk-KCFZOSR6.js → chunk-3MA7JVXN.js} +4 -4
  85. package/dist/{chunk-KHQ57QLJ.js → chunk-46WM6JX2.js} +7 -3
  86. package/dist/chunk-46WM6JX2.js.map +1 -0
  87. package/dist/chunk-47DU4SGJ.js +92 -0
  88. package/dist/chunk-47DU4SGJ.js.map +1 -0
  89. package/dist/{chunk-HKYNBEL4.js → chunk-4FFROSFG.js} +37 -14
  90. package/dist/{chunk-HKYNBEL4.js.map → chunk-4FFROSFG.js.map} +1 -1
  91. package/dist/{chunk-TLUSSS2F.js → chunk-4HO3542O.js} +2 -2
  92. package/dist/{chunk-4E67XCT2.js → chunk-4IZ2IT7D.js} +3 -3
  93. package/dist/{chunk-33JBK2XP.js → chunk-5F6HMNMZ.js} +2 -2
  94. package/dist/{chunk-5WQMORU5.js → chunk-5PFGMO33.js} +2 -2
  95. package/dist/{chunk-6HEM6HTQ.js → chunk-6GGTATZF.js} +2 -2
  96. package/dist/{chunk-UIRU3MIJ.js → chunk-7BJYTX6Q.js} +2 -2
  97. package/dist/{chunk-2GRLJMKJ.js → chunk-7DRSWPUV.js} +3 -3
  98. package/dist/{chunk-TVVEYCNW.js → chunk-7K5Q6COX.js} +4 -4
  99. package/dist/{chunk-HXXGZ4KV.js → chunk-ALNZEWGN.js} +2 -2
  100. package/dist/{chunk-5WVUO6QT.js → chunk-AR253JBM.js} +1 -1
  101. package/dist/chunk-AR253JBM.js.map +1 -0
  102. package/dist/{chunk-67MKNKJQ.js → chunk-AYIHDC5S.js} +2 -2
  103. package/dist/{chunk-IXJ5U6ZL.js → chunk-BBHFAVMP.js} +8 -8
  104. package/dist/{chunk-IIRK5V5Z.js → chunk-BHO6RHE5.js} +3 -3
  105. package/dist/{chunk-WANOCU3K.js → chunk-BP6WMYLP.js} +3 -3
  106. package/dist/{chunk-ZJKLGS76.js → chunk-CALURYWR.js} +283 -248
  107. package/dist/chunk-CALURYWR.js.map +1 -0
  108. package/dist/{chunk-JLMH5YMU.js → chunk-CH627RRV.js} +2 -2
  109. package/dist/{chunk-XIABRKF6.js → chunk-CLJ5QS6J.js} +239 -47
  110. package/dist/chunk-CLJ5QS6J.js.map +1 -0
  111. package/dist/{chunk-YLHM5BQQ.js → chunk-DCUMFQYM.js} +171 -8
  112. package/dist/chunk-DCUMFQYM.js.map +1 -0
  113. package/dist/{chunk-ZBJMUXZH.js → chunk-DJ7HMNSL.js} +15 -8
  114. package/dist/chunk-DJ7HMNSL.js.map +1 -0
  115. package/dist/{chunk-WTMG5GAK.js → chunk-DROAPP6N.js} +3 -3
  116. package/dist/{chunk-PBH2Z2NY.js → chunk-DTLF2SLZ.js} +2 -2
  117. package/dist/{chunk-7JAXC526.js → chunk-EFWHCTYJ.js} +2 -2
  118. package/dist/{chunk-3XG4QEA2.js → chunk-FF6E6HOT.js} +39 -39
  119. package/dist/{chunk-NP7FLVZW.js → chunk-G2FCSILA.js} +2 -2
  120. package/dist/{chunk-7PVTOZR4.js → chunk-H23GIXJC.js} +2 -2
  121. package/dist/{chunk-WT6UL3UA.js → chunk-H7PRHUBD.js} +2 -2
  122. package/dist/{chunk-ETCVSZLG.js → chunk-HSBQJRV2.js} +2 -2
  123. package/dist/{chunk-GZRDOVQN.js → chunk-HVKMJAEF.js} +2 -2
  124. package/dist/{chunk-CSOYVTRX.js → chunk-IIPJKCZB.js} +3 -3
  125. package/dist/{chunk-E57E5SCS.js → chunk-IRLH4NM2.js} +3 -3
  126. package/dist/{chunk-4G45LJJP.js → chunk-IZRNVNPV.js} +2 -2
  127. package/dist/{chunk-YSUSUZR4.js → chunk-JCJGYNIS.js} +3 -3
  128. package/dist/{chunk-EU74U4GT.js → chunk-JDI7G6EA.js} +2 -2
  129. package/dist/{chunk-QWPAQLYV.js → chunk-JFLKSD5V.js} +2 -2
  130. package/dist/{chunk-KQS72GCR.js → chunk-LJOIZPJH.js} +2 -2
  131. package/dist/{chunk-U27G4E5G.js → chunk-LLGDVG52.js} +3 -3
  132. package/dist/{chunk-7N7DB4L5.js → chunk-LTJTP5YQ.js} +10 -9
  133. package/dist/chunk-LTJTP5YQ.js.map +1 -0
  134. package/dist/{chunk-XL3TATMJ.js → chunk-OQIRBGUU.js} +21 -12
  135. package/dist/chunk-OQIRBGUU.js.map +1 -0
  136. package/dist/{chunk-JGW2EUCQ.js → chunk-PMRUMGK6.js} +2 -2
  137. package/dist/{chunk-3G6YU5YD.js → chunk-PSNN25DW.js} +2 -2
  138. package/dist/{chunk-LRGSLV7M.js → chunk-PYHOAXTI.js} +4 -4
  139. package/dist/{chunk-75U2FR7U.js → chunk-QCI73Z7C.js} +2 -2
  140. package/dist/{chunk-EHMMRZOZ.js → chunk-QICOU4RY.js} +2 -2
  141. package/dist/{chunk-K4WIUTNH.js → chunk-RFH7U5LT.js} +2 -2
  142. package/dist/{chunk-4SGDYYWV.js → chunk-RPKJHYVE.js} +2 -2
  143. package/dist/{chunk-BHO3IVAN.js → chunk-RYST72N5.js} +12 -1
  144. package/dist/chunk-RYST72N5.js.map +1 -0
  145. package/dist/chunk-T3GIETKV.js +152 -0
  146. package/dist/chunk-T3GIETKV.js.map +1 -0
  147. package/dist/{chunk-DYDACAK2.js → chunk-TGSMU3F2.js} +3 -3
  148. package/dist/{chunk-MJFDJTDC.js → chunk-TIRJV2LW.js} +2 -2
  149. package/dist/{chunk-QRA3XVJX.js → chunk-UDTME32W.js} +2 -2
  150. package/dist/{chunk-LAM6UDFV.js → chunk-WMOJIOIG.js} +2 -2
  151. package/dist/{chunk-LLLY5IBK.js → chunk-WR2YKUIW.js} +2 -2
  152. package/dist/{chunk-KYI3CM42.js → chunk-X6E7TT3A.js} +2 -2
  153. package/dist/{chunk-QN7XQEIT.js → chunk-YIIC5IDU.js} +2 -2
  154. package/dist/{chunk-JDJOAL4B.js → chunk-YSR3DXGC.js} +2 -2
  155. package/dist/{chunk-LBJBNWS2.js → chunk-YTHQHH5U.js} +2 -2
  156. package/dist/{chunk-JF6YSHJM.js → chunk-ZPGHA7EO.js} +12 -12
  157. package/dist/{chunk-VUDALPI5.js → chunk-ZQKXRKMR.js} +19 -5
  158. package/dist/chunk-ZQKXRKMR.js.map +1 -0
  159. package/dist/{chunk-YG56A6XY.js → chunk-ZS4JADYY.js} +3 -3
  160. package/dist/{cli-DB_uakTc.d.ts → cli-Bw9z-KqX.d.ts} +5 -5
  161. package/dist/cli.d.ts +13 -13
  162. package/dist/cli.js +60 -60
  163. package/dist/coding/pre-action-gate.d.ts +1 -1
  164. package/dist/coding/pre-action-gate.js +3 -3
  165. package/dist/compounding/engine.d.ts +2 -2
  166. package/dist/compounding/engine.js +11 -10
  167. package/dist/compounding/preference-consolidator.d.ts +1 -1
  168. package/dist/compression-optimizer.d.ts +1 -1
  169. package/dist/config.d.ts +1 -1
  170. package/dist/config.js +1 -1
  171. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  172. package/dist/connectors/codex-materialize-runner.js +11 -10
  173. package/dist/connectors/codex-materialize.d.ts +1 -1
  174. package/dist/connectors/index.d.ts +1 -1
  175. package/dist/connectors/index.js +11 -10
  176. package/dist/consolidation-provenance-check.d.ts +2 -2
  177. package/dist/consolidation-undo.d.ts +2 -2
  178. package/dist/contradiction/index.d.ts +2 -2
  179. package/dist/converge-config.d.ts +1 -1
  180. package/dist/convergence-refresh.d.ts +2 -2
  181. package/dist/convergence-refresh.js +13 -12
  182. package/dist/conversation-index/backend.d.ts +1 -1
  183. package/dist/conversation-index/chunker.d.ts +1 -1
  184. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  185. package/dist/conversation-index/indexer.d.ts +1 -1
  186. package/dist/conversation-index/search.d.ts +1 -1
  187. package/dist/corpus-watermark.d.ts +1 -1
  188. package/dist/corpus-watermark.js +13 -12
  189. package/dist/day-summary.d.ts +1 -1
  190. package/dist/delinearize.d.ts +1 -1
  191. package/dist/dependency-propagation-config.d.ts +1 -1
  192. package/dist/{dependency-propagation-delivery-DcOVpK3y.d.ts → dependency-propagation-delivery-BxhvAppj.d.ts} +1 -1
  193. package/dist/direct-answer-wiring.d.ts +1 -1
  194. package/dist/direct-answer-wiring.js +3 -3
  195. package/dist/direct-answer.d.ts +1 -1
  196. package/dist/direct-answer.js +2 -2
  197. package/dist/embedding-fallback.d.ts +1 -1
  198. package/dist/enrichment/index.d.ts +1 -1
  199. package/dist/entity-origin-fields.d.ts +1 -1
  200. package/dist/entity-retrieval.d.ts +2 -2
  201. package/dist/entity-retrieval.js +11 -10
  202. package/dist/entity-schema.d.ts +1 -1
  203. package/dist/episodic-context.d.ts +92 -0
  204. package/dist/episodic-context.js +16 -0
  205. package/dist/episodic-context.js.map +1 -0
  206. package/dist/explicit-capture.d.ts +9 -9
  207. package/dist/external-wiki-access.d.ts +11 -11
  208. package/dist/external-wiki-access.js +27 -27
  209. package/dist/external-wiki-collection-registration.d.ts +1 -1
  210. package/dist/external-wiki-collection.d.ts +1 -1
  211. package/dist/external-wiki-mcp-tools.d.ts +11 -11
  212. package/dist/extraction-error-classification.d.ts +1 -1
  213. package/dist/extraction-faithfulness.d.ts +1 -1
  214. package/dist/extraction-judge-telemetry.d.ts +1 -1
  215. package/dist/extraction-judge-training.d.ts +1 -1
  216. package/dist/extraction-judge.d.ts +1 -1
  217. package/dist/extraction-liveness.d.ts +1 -1
  218. package/dist/extraction-normalization.d.ts +1 -1
  219. package/dist/extraction-normalization.js +2 -2
  220. package/dist/extraction-prompt.d.ts +1 -1
  221. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  222. package/dist/extraction-source-grounding.d.ts +1 -1
  223. package/dist/extraction.d.ts +1 -1
  224. package/dist/extraction.js +14 -14
  225. package/dist/fallback-llm.d.ts +1 -1
  226. package/dist/{forget-5TWK7CZT.js → forget-SZ2BXDGF.js} +2 -2
  227. package/dist/graph-dashboard-diff.d.ts +1 -1
  228. package/dist/graph-dashboard-key.d.ts +1 -1
  229. package/dist/graph-dashboard-parser.d.ts +1 -1
  230. package/dist/graph-edge-reinforcement.d.ts +1 -1
  231. package/dist/graph-path-reconstruction.d.ts +1 -1
  232. package/dist/graph-path-scoring.d.ts +1 -1
  233. package/dist/graph-snapshot.d.ts +1 -1
  234. package/dist/graph.d.ts +1 -1
  235. package/dist/harmonic-construction.js +2 -2
  236. package/dist/harmonic-retrieval.js +2 -2
  237. package/dist/importance.d.ts +1 -1
  238. package/dist/importers/index.d.ts +1 -1
  239. package/dist/in-flight-reads.d.ts +1 -1
  240. package/dist/index.d.ts +21 -21
  241. package/dist/index.js +100 -98
  242. package/dist/intent.d.ts +1 -1
  243. package/dist/lcm/engine.d.ts +8 -2
  244. package/dist/lcm/engine.js +4 -4
  245. package/dist/lcm/index.d.ts +1 -1
  246. package/dist/lcm/index.js +9 -9
  247. package/dist/lcm/tools.d.ts +1 -1
  248. package/dist/lifecycle.d.ts +1 -1
  249. package/dist/live-connectors-runner.d.ts +1 -1
  250. package/dist/local-llm.d.ts +1 -1
  251. package/dist/local-model-endpoint.d.ts +1 -1
  252. package/dist/maintenance/memory-governance.d.ts +1 -1
  253. package/dist/maintenance/memory-governance.js +11 -10
  254. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  255. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +11 -10
  256. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  257. package/dist/maintenance/rebuild-memory-projection.js +12 -11
  258. package/dist/{maintenance-5c1olVtB.d.ts → maintenance-uJb74j64.d.ts} +3 -3
  259. package/dist/mcp-memory-inspector-app.d.ts +11 -11
  260. package/dist/memory-action-policy.d.ts +1 -1
  261. package/dist/memory-cache.d.ts +1 -1
  262. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  263. package/dist/memory-projection-store.d.ts +1 -1
  264. package/dist/memory-provenance.d.ts +1 -1
  265. package/dist/memory-snapshot.d.ts +1 -1
  266. package/dist/memory-worth-outcomes.d.ts +2 -2
  267. package/dist/models-json.d.ts +1 -1
  268. package/dist/namespaces/migrate.d.ts +3 -3
  269. package/dist/namespaces/migrate.js +12 -11
  270. package/dist/namespaces/principal.d.ts +1 -1
  271. package/dist/namespaces/search.d.ts +1 -1
  272. package/dist/namespaces/search.js +6 -5
  273. package/dist/namespaces/storage.d.ts +3 -3
  274. package/dist/namespaces/storage.js +11 -10
  275. package/dist/native-knowledge.d.ts +1 -1
  276. package/dist/offline-sync-impression-drain.d.ts +1 -1
  277. package/dist/operator-doctor-corpus.d.ts +1 -1
  278. package/dist/operator-doctor-corpus.js +14 -13
  279. package/dist/operator-doctor-replica.d.ts +1 -1
  280. package/dist/operator-toolkit.d.ts +3 -3
  281. package/dist/operator-toolkit.js +19 -18
  282. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  283. package/dist/orchestration/maintenance.d.ts +4 -4
  284. package/dist/orchestration/maintenance.js +16 -15
  285. package/dist/{orchestrator-HPuY6I4i.d.ts → orchestrator-CFi-5JSR.d.ts} +23 -8
  286. package/dist/orchestrator.d.ts +9 -9
  287. package/dist/orchestrator.js +88 -86
  288. package/dist/patterns-cli.d.ts +1 -1
  289. package/dist/{pipeline-CvVe1Q2_.d.ts → pipeline-BdF3ferY.d.ts} +1 -1
  290. package/dist/policy-runtime.d.ts +1 -1
  291. package/dist/policy-runtime.js +3 -3
  292. package/dist/proactive-contention.d.ts +1 -1
  293. package/dist/provenance.d.ts +1 -1
  294. package/dist/{public-http-D0JKFkyf.d.ts → public-http-DK-QwaBu.d.ts} +1 -1
  295. package/dist/{qmd-Bd0Tp76_.d.ts → qmd-D_62bYNl.d.ts} +1 -1
  296. package/dist/qmd-preflight.d.ts +2 -2
  297. package/dist/qmd-recall-cache.d.ts +1 -1
  298. package/dist/qmd.d.ts +2 -2
  299. package/dist/recall-concurrency-config.d.ts +1 -1
  300. package/dist/recall-disclosure-escalation.d.ts +1 -1
  301. package/dist/recall-explain-renderer.d.ts +1 -1
  302. package/dist/recall-explain-renderer.js +3 -3
  303. package/dist/recall-memory-map.d.ts +1 -1
  304. package/dist/recall-planner-llm.d.ts +1 -1
  305. package/dist/recall-query-policy.js +2 -2
  306. package/dist/recall-state.d.ts +1 -1
  307. package/dist/recall-tag-filter.d.ts +1 -1
  308. package/dist/recall-timings.d.ts +1 -1
  309. package/dist/recall-tokenization.d.ts +3 -1
  310. package/dist/recall-tokenization.js +5 -1
  311. package/dist/recall-xray-cli.d.ts +1 -1
  312. package/dist/recall-xray-cli.js +4 -4
  313. package/dist/recall-xray-renderer.d.ts +1 -1
  314. package/dist/recall-xray-renderer.js +3 -3
  315. package/dist/recall-xray.d.ts +1 -1
  316. package/dist/recall-xray.js +2 -2
  317. package/dist/reconcile/cursor.d.ts +1 -1
  318. package/dist/reconcile/manifest.d.ts +10 -1
  319. package/dist/reconcile/manifest.js +1 -1
  320. package/dist/reconcile/plan.d.ts +1 -1
  321. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  322. package/dist/replay/normalizers/claude.d.ts +1 -1
  323. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  324. package/dist/replay/normalizers/shared.d.ts +1 -1
  325. package/dist/replay/runner.d.ts +1 -1
  326. package/dist/replay/types.d.ts +1 -1
  327. package/dist/replica-divergence.d.ts +1 -1
  328. package/dist/replica-peers-config.d.ts +1 -1
  329. package/dist/resolve-auth-token.d.ts +1 -1
  330. package/dist/resume-bundles.js +4 -4
  331. package/dist/retrieval-agents.d.ts +2 -2
  332. package/dist/retrieval-tiers.d.ts +1 -1
  333. package/dist/routing/engine.d.ts +1 -1
  334. package/dist/routing/store.d.ts +1 -1
  335. package/dist/salvage-envelope.d.ts +1 -1
  336. package/dist/{scope-profiles-ClLtm9gK.d.ts → scope-profiles-CeMv7pP0.d.ts} +1 -1
  337. package/dist/search/embed-helper.d.ts +1 -1
  338. package/dist/search/factory.d.ts +1 -1
  339. package/dist/search/factory.js +5 -4
  340. package/dist/search/index.d.ts +1 -1
  341. package/dist/search/index.js +9 -8
  342. package/dist/search/lancedb-backend.d.ts +14 -1
  343. package/dist/search/lancedb-backend.js +1 -1
  344. package/dist/search/meilisearch-backend.d.ts +1 -1
  345. package/dist/search/noop-backend.d.ts +1 -1
  346. package/dist/search/orama-backend.d.ts +22 -1
  347. package/dist/search/orama-backend.js +2 -1
  348. package/dist/search/port.d.ts +1 -1
  349. package/dist/search/remote-backend.d.ts +1 -1
  350. package/dist/{semantic-consolidation-B1EkeEDj.d.ts → semantic-consolidation-B-85brYj.d.ts} +1 -1
  351. package/dist/semantic-consolidation.d.ts +2 -2
  352. package/dist/semantic-consolidation.js +12 -12
  353. package/dist/semantic-rule-promotion.js +11 -10
  354. package/dist/semantic-rule-verifier.d.ts +1 -1
  355. package/dist/semantic-rule-verifier.js +11 -11
  356. package/dist/{service-Cf3ANQj9.d.ts → service-CoO0HA2E.d.ts} +2 -2
  357. package/dist/session-observer-bands.d.ts +1 -1
  358. package/dist/session-observer-state.d.ts +1 -1
  359. package/dist/shared-context/manager.d.ts +1 -1
  360. package/dist/signal.d.ts +1 -1
  361. package/dist/source-agent-qualifier.d.ts +1 -1
  362. package/dist/source-agent-qualifier.js +11 -10
  363. package/dist/{storage-DS2O_6Qt.d.ts → storage-BVAVitkO.d.ts} +1 -1
  364. package/dist/storage.d.ts +2 -2
  365. package/dist/storage.js +10 -9
  366. package/dist/summarizer.d.ts +1 -1
  367. package/dist/summary-snapshot.d.ts +1 -1
  368. package/dist/support-passport/index.d.ts +14 -14
  369. package/dist/support-passport/index.js +29 -29
  370. package/dist/temporal-supersession.d.ts +2 -2
  371. package/dist/temporal-timeline-recall.d.ts +1 -1
  372. package/dist/temporal-validity.d.ts +1 -1
  373. package/dist/threading.d.ts +1 -1
  374. package/dist/tier-migration.d.ts +2 -2
  375. package/dist/tier-routing.d.ts +1 -1
  376. package/dist/topics.d.ts +1 -1
  377. package/dist/transcript.d.ts +1 -1
  378. package/dist/transfer/import-sqlite.js +2 -2
  379. package/dist/trust-score-stage.d.ts +1 -1
  380. package/dist/trust-score.d.ts +1 -1
  381. package/dist/trust-zones.js +2 -2
  382. package/dist/{types-BOANGhCJ.d.ts → types-DWHOxlZP.d.ts} +3 -0
  383. package/dist/types.d.ts +1 -1
  384. package/dist/types.js +1 -1
  385. package/dist/user-message-cleaning.d.ts +23 -0
  386. package/dist/user-message-cleaning.js +10 -0
  387. package/dist/user-message-cleaning.js.map +1 -0
  388. package/dist/utility-runtime.d.ts +1 -1
  389. package/dist/verified-recall.js +11 -11
  390. package/dist/work-product-ledger.js +2 -2
  391. package/dist/write-envelope.d.ts +1 -1
  392. package/package.json +12 -2
  393. package/src/access-service-offline-file-content.test.ts +1 -0
  394. package/src/config.ts +11 -0
  395. package/src/episodic-context-recall.integration.test.ts +169 -0
  396. package/src/episodic-context.test.ts +266 -0
  397. package/src/episodic-context.ts +274 -0
  398. package/src/lcm/engine.ts +18 -1
  399. package/src/lifecycle/tombstones.test.ts +134 -0
  400. package/src/lifecycle/tombstones.ts +29 -2
  401. package/src/orchestration/episodic-context-section.ts +255 -0
  402. package/src/orchestration/recall-internal-deps.ts +2 -0
  403. package/src/orchestration/recall-internal.ts +40 -25
  404. package/src/orchestration/recall-result-formatter.ts +37 -0
  405. package/src/recall-tokenization.ts +14 -8
  406. package/src/reconcile/manifest.test.ts +133 -4
  407. package/src/reconcile/manifest.ts +43 -7
  408. package/src/search/factory.ts +1 -0
  409. package/src/search/lancedb-backend.ts +24 -16
  410. package/src/search/orama-backend.test.ts +208 -1
  411. package/src/search/orama-backend.ts +133 -18
  412. package/src/search/orama-cjk-tokenizer.test.ts +108 -0
  413. package/src/search/orama-cjk-tokenizer.ts +143 -0
  414. package/src/storage/tombstone-migration-sources.test.ts +116 -0
  415. package/src/storage/tombstone-migration-sources.ts +90 -0
  416. package/src/storage.ts +13 -34
  417. package/src/types.ts +3 -3
  418. package/src/user-message-cleaning.ts +139 -0
  419. package/dist/chunk-5WVUO6QT.js.map +0 -1
  420. package/dist/chunk-7N7DB4L5.js.map +0 -1
  421. package/dist/chunk-B2QHVLJO.js.map +0 -1
  422. package/dist/chunk-BHO3IVAN.js.map +0 -1
  423. package/dist/chunk-KHQ57QLJ.js.map +0 -1
  424. package/dist/chunk-VUDALPI5.js.map +0 -1
  425. package/dist/chunk-XIABRKF6.js.map +0 -1
  426. package/dist/chunk-XL3TATMJ.js.map +0 -1
  427. package/dist/chunk-YLHM5BQQ.js.map +0 -1
  428. package/dist/chunk-ZBJMUXZH.js.map +0 -1
  429. package/dist/chunk-ZJKLGS76.js.map +0 -1
  430. /package/dist/{auto-sync-FMWQQB3J.js.map → auto-sync-Z52VWMNC.js.map} +0 -0
  431. /package/dist/{chunk-QP2IZTUR.js.map → chunk-2TYIAKU5.js.map} +0 -0
  432. /package/dist/{chunk-QNMNNFKD.js.map → chunk-347ZR6D4.js.map} +0 -0
  433. /package/dist/{chunk-76YNCJ5H.js.map → chunk-3F3CVVDS.js.map} +0 -0
  434. /package/dist/{chunk-KCFZOSR6.js.map → chunk-3MA7JVXN.js.map} +0 -0
  435. /package/dist/{chunk-TLUSSS2F.js.map → chunk-4HO3542O.js.map} +0 -0
  436. /package/dist/{chunk-4E67XCT2.js.map → chunk-4IZ2IT7D.js.map} +0 -0
  437. /package/dist/{chunk-33JBK2XP.js.map → chunk-5F6HMNMZ.js.map} +0 -0
  438. /package/dist/{chunk-5WQMORU5.js.map → chunk-5PFGMO33.js.map} +0 -0
  439. /package/dist/{chunk-6HEM6HTQ.js.map → chunk-6GGTATZF.js.map} +0 -0
  440. /package/dist/{chunk-UIRU3MIJ.js.map → chunk-7BJYTX6Q.js.map} +0 -0
  441. /package/dist/{chunk-2GRLJMKJ.js.map → chunk-7DRSWPUV.js.map} +0 -0
  442. /package/dist/{chunk-TVVEYCNW.js.map → chunk-7K5Q6COX.js.map} +0 -0
  443. /package/dist/{chunk-HXXGZ4KV.js.map → chunk-ALNZEWGN.js.map} +0 -0
  444. /package/dist/{chunk-67MKNKJQ.js.map → chunk-AYIHDC5S.js.map} +0 -0
  445. /package/dist/{chunk-IXJ5U6ZL.js.map → chunk-BBHFAVMP.js.map} +0 -0
  446. /package/dist/{chunk-IIRK5V5Z.js.map → chunk-BHO6RHE5.js.map} +0 -0
  447. /package/dist/{chunk-WANOCU3K.js.map → chunk-BP6WMYLP.js.map} +0 -0
  448. /package/dist/{chunk-JLMH5YMU.js.map → chunk-CH627RRV.js.map} +0 -0
  449. /package/dist/{chunk-WTMG5GAK.js.map → chunk-DROAPP6N.js.map} +0 -0
  450. /package/dist/{chunk-PBH2Z2NY.js.map → chunk-DTLF2SLZ.js.map} +0 -0
  451. /package/dist/{chunk-7JAXC526.js.map → chunk-EFWHCTYJ.js.map} +0 -0
  452. /package/dist/{chunk-3XG4QEA2.js.map → chunk-FF6E6HOT.js.map} +0 -0
  453. /package/dist/{chunk-NP7FLVZW.js.map → chunk-G2FCSILA.js.map} +0 -0
  454. /package/dist/{chunk-7PVTOZR4.js.map → chunk-H23GIXJC.js.map} +0 -0
  455. /package/dist/{chunk-WT6UL3UA.js.map → chunk-H7PRHUBD.js.map} +0 -0
  456. /package/dist/{chunk-ETCVSZLG.js.map → chunk-HSBQJRV2.js.map} +0 -0
  457. /package/dist/{chunk-GZRDOVQN.js.map → chunk-HVKMJAEF.js.map} +0 -0
  458. /package/dist/{chunk-CSOYVTRX.js.map → chunk-IIPJKCZB.js.map} +0 -0
  459. /package/dist/{chunk-E57E5SCS.js.map → chunk-IRLH4NM2.js.map} +0 -0
  460. /package/dist/{chunk-4G45LJJP.js.map → chunk-IZRNVNPV.js.map} +0 -0
  461. /package/dist/{chunk-YSUSUZR4.js.map → chunk-JCJGYNIS.js.map} +0 -0
  462. /package/dist/{chunk-EU74U4GT.js.map → chunk-JDI7G6EA.js.map} +0 -0
  463. /package/dist/{chunk-QWPAQLYV.js.map → chunk-JFLKSD5V.js.map} +0 -0
  464. /package/dist/{chunk-KQS72GCR.js.map → chunk-LJOIZPJH.js.map} +0 -0
  465. /package/dist/{chunk-U27G4E5G.js.map → chunk-LLGDVG52.js.map} +0 -0
  466. /package/dist/{chunk-JGW2EUCQ.js.map → chunk-PMRUMGK6.js.map} +0 -0
  467. /package/dist/{chunk-3G6YU5YD.js.map → chunk-PSNN25DW.js.map} +0 -0
  468. /package/dist/{chunk-LRGSLV7M.js.map → chunk-PYHOAXTI.js.map} +0 -0
  469. /package/dist/{chunk-75U2FR7U.js.map → chunk-QCI73Z7C.js.map} +0 -0
  470. /package/dist/{chunk-EHMMRZOZ.js.map → chunk-QICOU4RY.js.map} +0 -0
  471. /package/dist/{chunk-K4WIUTNH.js.map → chunk-RFH7U5LT.js.map} +0 -0
  472. /package/dist/{chunk-4SGDYYWV.js.map → chunk-RPKJHYVE.js.map} +0 -0
  473. /package/dist/{chunk-DYDACAK2.js.map → chunk-TGSMU3F2.js.map} +0 -0
  474. /package/dist/{chunk-MJFDJTDC.js.map → chunk-TIRJV2LW.js.map} +0 -0
  475. /package/dist/{chunk-QRA3XVJX.js.map → chunk-UDTME32W.js.map} +0 -0
  476. /package/dist/{chunk-LAM6UDFV.js.map → chunk-WMOJIOIG.js.map} +0 -0
  477. /package/dist/{chunk-LLLY5IBK.js.map → chunk-WR2YKUIW.js.map} +0 -0
  478. /package/dist/{chunk-KYI3CM42.js.map → chunk-X6E7TT3A.js.map} +0 -0
  479. /package/dist/{chunk-QN7XQEIT.js.map → chunk-YIIC5IDU.js.map} +0 -0
  480. /package/dist/{chunk-JDJOAL4B.js.map → chunk-YSR3DXGC.js.map} +0 -0
  481. /package/dist/{chunk-LBJBNWS2.js.map → chunk-YTHQHH5U.js.map} +0 -0
  482. /package/dist/{chunk-JF6YSHJM.js.map → chunk-ZPGHA7EO.js.map} +0 -0
  483. /package/dist/{chunk-YG56A6XY.js.map → chunk-ZS4JADYY.js.map} +0 -0
  484. /package/dist/{forget-5TWK7CZT.js.map → forget-SZ2BXDGF.js.map} +0 -0
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Host-agnostic user-message cleaning (issue #2331).
3
+ *
4
+ * Owns the generic part of the cleaner the OpenClaw wiring has always used
5
+ * (`src/user-message-cleaning.ts` in the root host bundle): stripping the
6
+ * structured host-injected memory wrappers and the leading memory-context
7
+ * preamble from a user message. The host wrapper keeps only the
8
+ * platform-header pattern (channel envelopes are an OpenClaw concept) and
9
+ * delegates here, so core consumers — the episodic-context recall section
10
+ * re-rendering archived user turns — share ONE implementation instead of a
11
+ * second cleaner drifting beside it.
12
+ */
13
+ declare function cleanUserMessageWithPattern(content: string, platformHeaderPattern: RegExp): string;
14
+ /**
15
+ * Clean an archived user turn for re-injection (issue #2331): strips the
16
+ * memory wrappers this system itself injects, so an archived echo of a
17
+ * previous recall output cannot re-enter the context through the
18
+ * episodic-context section. No platform envelope stripping — core has no
19
+ * host channel-envelope concept.
20
+ */
21
+ declare function cleanArchivedUserMessage(content: string): string;
22
+
23
+ export { cleanArchivedUserMessage, cleanUserMessageWithPattern };
@@ -0,0 +1,10 @@
1
+ import {
2
+ cleanArchivedUserMessage,
3
+ cleanUserMessageWithPattern
4
+ } from "./chunk-47DU4SGJ.js";
5
+ import "./chunk-PZ5AY32C.js";
6
+ export {
7
+ cleanArchivedUserMessage,
8
+ cleanUserMessageWithPattern
9
+ };
10
+ //# sourceMappingURL=user-message-cleaning.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,6 +1,6 @@
1
1
  import { TierRoutingPolicy } from './tier-routing.js';
2
2
  import './lifecycle.js';
3
- import './types-BOANGhCJ.js';
3
+ import './types-DWHOxlZP.js';
4
4
  import './message-parts/index.js';
5
5
  import './bounded-jsonl-state.js';
6
6
  import './operator-doctor-types.js';
@@ -1,20 +1,20 @@
1
1
  import {
2
2
  compareVerifiedEpisodeResults,
3
3
  searchVerifiedEpisodes
4
- } from "./chunk-IIRK5V5Z.js";
4
+ } from "./chunk-BHO6RHE5.js";
5
5
  import "./chunk-B7RWBZXW.js";
6
- import "./chunk-ZJKLGS76.js";
6
+ import "./chunk-CALURYWR.js";
7
7
  import "./chunk-UHVXE24Y.js";
8
- import "./chunk-KHQ57QLJ.js";
8
+ import "./chunk-46WM6JX2.js";
9
9
  import "./chunk-SXIMQLGV.js";
10
- import "./chunk-QWPAQLYV.js";
11
- import "./chunk-7N7DB4L5.js";
10
+ import "./chunk-JFLKSD5V.js";
11
+ import "./chunk-LTJTP5YQ.js";
12
+ import "./chunk-CYEPCZN5.js";
13
+ import "./chunk-DCUMFQYM.js";
12
14
  import "./chunk-VYISFWVX.js";
13
15
  import "./chunk-6KTXE6A3.js";
14
- import "./chunk-XL3TATMJ.js";
16
+ import "./chunk-OQIRBGUU.js";
15
17
  import "./chunk-VANZKHTN.js";
16
- import "./chunk-CYEPCZN5.js";
17
- import "./chunk-YLHM5BQQ.js";
18
18
  import "./chunk-W7IGLX4G.js";
19
19
  import "./chunk-GUMZC2BO.js";
20
20
  import "./chunk-227UFSEQ.js";
@@ -22,12 +22,12 @@ import "./chunk-ET356KSB.js";
22
22
  import "./chunk-72A4L5JJ.js";
23
23
  import "./chunk-A7Q43EUZ.js";
24
24
  import "./chunk-S2V7RUCL.js";
25
- import "./chunk-5WVUO6QT.js";
25
+ import "./chunk-AR253JBM.js";
26
26
  import "./chunk-S2HLHAZ4.js";
27
27
  import "./chunk-SCU65EZI.js";
28
28
  import "./chunk-PO7NXBG2.js";
29
- import "./chunk-DM2T26WE.js";
30
29
  import "./chunk-LDXUBPMO.js";
30
+ import "./chunk-DM2T26WE.js";
31
31
  import "./chunk-UG6VXIOK.js";
32
32
  import "./chunk-AAD2ZS6P.js";
33
33
  import "./chunk-H6ZXNH5I.js";
@@ -63,7 +63,7 @@ import "./chunk-PJKTFXE2.js";
63
63
  import "./chunk-W5BIQOAJ.js";
64
64
  import "./chunk-Z7L72ZHL.js";
65
65
  import "./chunk-4O4TKIXQ.js";
66
- import "./chunk-ZBJMUXZH.js";
66
+ import "./chunk-DJ7HMNSL.js";
67
67
  import "./chunk-BJMBJZ2Y.js";
68
68
  import "./chunk-UKJAGEXH.js";
69
69
  import "./chunk-FP2373TW.js";
@@ -4,8 +4,8 @@ import {
4
4
  resolveWorkProductLedgerDir,
5
5
  searchWorkProductLedgerEntries,
6
6
  validateWorkProductLedgerEntry
7
- } from "./chunk-WT6UL3UA.js";
8
- import "./chunk-ZBJMUXZH.js";
7
+ } from "./chunk-H7PRHUBD.js";
8
+ import "./chunk-DJ7HMNSL.js";
9
9
  import "./chunk-A2IYSXDQ.js";
10
10
  import "./chunk-P77QX3ID.js";
11
11
  import "./chunk-PZ5AY32C.js";
@@ -1,4 +1,4 @@
1
- import { w as MemoryCategory } from './types-BOANGhCJ.js';
1
+ import { w as MemoryCategory } from './types-DWHOxlZP.js';
2
2
  import './message-parts/index.js';
3
3
  import './bounded-jsonl-state.js';
4
4
  import './operator-doctor-types.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "9.62.1",
3
+ "version": "9.63.0",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -2930,6 +2930,16 @@
2930
2930
  "remnic-source": "./src/types.ts",
2931
2931
  "import": "./dist/types.js"
2932
2932
  },
2933
+ "./user-message-cleaning": {
2934
+ "types": "./dist/user-message-cleaning.d.ts",
2935
+ "remnic-source": "./src/user-message-cleaning.ts",
2936
+ "import": "./dist/user-message-cleaning.js"
2937
+ },
2938
+ "./user-message-cleaning.js": {
2939
+ "types": "./dist/user-message-cleaning.d.ts",
2940
+ "remnic-source": "./src/user-message-cleaning.ts",
2941
+ "import": "./dist/user-message-cleaning.js"
2942
+ },
2933
2943
  "./user-model": {
2934
2944
  "types": "./dist/user-model.d.ts",
2935
2945
  "remnic-source": "./src/user-model.ts",
@@ -3146,7 +3156,7 @@
3146
3156
  "core"
3147
3157
  ],
3148
3158
  "peerDependencies": {
3149
- "@remnic/coding-graph": "^9.62.1"
3159
+ "@remnic/coding-graph": "^9.63.0"
3150
3160
  },
3151
3161
  "peerDependenciesMeta": {
3152
3162
  "@remnic/coding-graph": {
@@ -213,6 +213,7 @@ test("offline manifest streams body-free active, archived, old, bad, and encrypt
213
213
  id: "active-memory",
214
214
  category: "fact",
215
215
  contentHash: activeContentHash,
216
+ identityResolutionVersion: 2,
216
217
  normalizerVersion: 4,
217
218
  status: "active",
218
219
  });
package/src/config.ts CHANGED
@@ -2472,6 +2472,7 @@ export function parseConfig(
2472
2472
  memoryPoisoningDefenseEnabled: cfg.memoryPoisoningDefenseEnabled === true,
2473
2473
  memoryRedTeamBenchEnabled: cfg.memoryRedTeamBenchEnabled === true,
2474
2474
  harmonicRetrievalEnabled: cfg.harmonicRetrievalEnabled === true,
2475
+ episodicContextEnabled: cfg.episodicContextEnabled === true,
2475
2476
  abstractionAnchorsEnabled: cfg.abstractionAnchorsEnabled === true,
2476
2477
  verifiedRecallEnabled: cfg.verifiedRecallEnabled === true,
2477
2478
  semanticRulePromotionEnabled: cfg.semanticRulePromotionEnabled === true,
@@ -3175,6 +3176,9 @@ export function parseConfig(
3175
3176
  oramaEnabled: cfg.oramaEnabled === true,
3176
3177
  oramaDbPath: typeof cfg.oramaDbPath === "string" ? cfg.oramaDbPath : path.join(memoryDir, "orama"),
3177
3178
  oramaEmbeddingDimension: typeof cfg.oramaEmbeddingDimension === "number" ? cfg.oramaEmbeddingDimension : 1536,
3179
+ // CJK/Thai lexical segmentation (issue #2187) — default on; string forms
3180
+ // from CLI `--config` are coerced like neighboring boolean flags.
3181
+ oramaCjkSegmentation: coerceBooleanLike(cfg.oramaCjkSegmentation) ?? true,
3178
3182
 
3179
3183
  // QMD daemon mode
3180
3184
  qmdDaemonEnabled: cfg.qmdDaemonEnabled !== false,
@@ -4428,6 +4432,13 @@ function buildDefaultRecallPipeline(cfg: Record<string, unknown>): RecallSection
4428
4432
  ? Math.max(0, Math.floor(cfg.qmdMaxResults))
4429
4433
  : 8,
4430
4434
  },
4435
+ {
4436
+ id: "episodic-context",
4437
+ enabled: cfg.episodicContextEnabled === true,
4438
+ maxResults: 2,
4439
+ maxTurns: 8,
4440
+ maxChars: 2400,
4441
+ },
4431
4442
  {
4432
4443
  id: "compression-guidelines",
4433
4444
  enabled: cfg.compressionGuidelineLearningEnabled === true,
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Integration tests for the episodic-context recall section (issue #2331).
3
+ *
4
+ * Seeds a real Orchestrator with an LCM archive and one fact whose
5
+ * `sources` provenance carries a resolvable turn fingerprint, then asserts:
6
+ * - flag off: no `## Source Episodes` section and ZERO archive reads
7
+ * - flag on: grouped episode injected, within the recall budget
8
+ * - facts without structured sources are skipped
9
+ * - foreign-session provenance (cross-namespace) is skipped
10
+ */
11
+ import assert from "node:assert/strict";
12
+ import { mkdtemp, rm } from "node:fs/promises";
13
+ import os from "node:os";
14
+ import path from "node:path";
15
+ import test from "node:test";
16
+
17
+ import { parseConfig } from "./config.js";
18
+ import { Orchestrator } from "./orchestrator.js";
19
+ import type { ProvenanceSource } from "./types.js";
20
+
21
+ const SEP = String.fromCharCode(1);
22
+
23
+ const SESSION_KEY = "session-atlas-7";
24
+
25
+ function fingerprint(turnIndex: number): string {
26
+ return `user${SEP}we settled the storage question${SEP}thread-1${SEP}${turnIndex}`;
27
+ }
28
+
29
+ function provenance(turnIndex: number): ProvenanceSource {
30
+ return {
31
+ sessionKey: SESSION_KEY,
32
+ turnId: fingerprint(turnIndex),
33
+ observedAt: "2026-08-16T00:00:00.000Z",
34
+ quote: "we settled the storage question",
35
+ };
36
+ }
37
+
38
+ async function seedArchive(orchestrator: Orchestrator): Promise<void> {
39
+ const engine = orchestrator.lcmEngine!;
40
+ await engine.observeMessages(SESSION_KEY, [
41
+ { role: "user", content: "turn zero greeting" },
42
+ { role: "user", content: "we settled the storage question: postgres for the atlas cluster" },
43
+ { role: "assistant", content: "understood, postgres it is" },
44
+ { role: "user", content: "also note the replica lives in frankfurt" },
45
+ { role: "assistant", content: "replica noted" },
46
+ ]);
47
+ await engine.waitForObserveQueueIdle();
48
+ }
49
+
50
+ /** Wrap the engine's read surfaces with call counters. */
51
+ function countArchiveReads(orchestrator: Orchestrator): { reads: () => number } {
52
+ const engine = orchestrator.lcmEngine as unknown as {
53
+ getTurnRange: (...args: unknown[]) => Promise<unknown[]>;
54
+ searchContextFull: (...args: unknown[]) => Promise<unknown[]>;
55
+ };
56
+ let reads = 0;
57
+ const originalGetTurnRange = engine.getTurnRange.bind(engine);
58
+ const originalSearch = engine.searchContextFull.bind(engine);
59
+ engine.getTurnRange = async (...args: unknown[]) => {
60
+ reads += 1;
61
+ return originalGetTurnRange(...args);
62
+ };
63
+ engine.searchContextFull = async (...args: unknown[]) => {
64
+ reads += 1;
65
+ return originalSearch(...args);
66
+ };
67
+ return { reads: () => reads };
68
+ }
69
+
70
+ async function buildOrchestrator(
71
+ memoryDir: string,
72
+ episodicContextEnabled: boolean,
73
+ ): Promise<Orchestrator> {
74
+ const config = parseConfig({
75
+ memoryDir,
76
+ qmdEnabled: false,
77
+ lcmEnabled: true,
78
+ episodicContextEnabled,
79
+ transcriptEnabled: false,
80
+ injectQuestions: false,
81
+ sharedContextEnabled: false,
82
+ });
83
+ return new Orchestrator(config);
84
+ }
85
+
86
+ test("episodic context: flag off = no section and zero archive reads", async () => {
87
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-episodic-off-"));
88
+ try {
89
+ const orchestrator = await buildOrchestrator(memoryDir, false);
90
+ await seedArchive(orchestrator);
91
+ const storage = await orchestrator.getStorage("default");
92
+ await storage.ensureDirectories();
93
+ await storage.writeMemory("fact", "The atlas cluster stores its graph in postgres.", {
94
+ source: "test",
95
+ sources: [provenance(1)],
96
+ });
97
+ const counter = countArchiveReads(orchestrator);
98
+ const context = await orchestrator.recall("where does the atlas cluster store data?", SESSION_KEY);
99
+ assert.ok(!context.includes("## Source Episodes"), "flag off must not inject the section");
100
+ assert.equal(counter.reads(), 0, "flag off must issue zero archive reads");
101
+ await orchestrator.destroy();
102
+ } finally {
103
+ await rm(memoryDir, { recursive: true, force: true });
104
+ }
105
+ });
106
+
107
+ test("episodic context: flag on injects grouped episodes within budget", async () => {
108
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-episodic-on-"));
109
+ try {
110
+ const orchestrator = await buildOrchestrator(memoryDir, true);
111
+ await seedArchive(orchestrator);
112
+ const storage = await orchestrator.getStorage("default");
113
+ await storage.ensureDirectories();
114
+ // Two facts whose windows overlap around turn 1: one merged episode.
115
+ await storage.writeMemory("fact", "The atlas cluster stores its graph in postgres.", {
116
+ source: "test",
117
+ sources: [provenance(1)],
118
+ });
119
+ await storage.writeMemory("fact", "The atlas replica lives in frankfurt.", {
120
+ source: "test",
121
+ sources: [provenance(3)],
122
+ });
123
+ // A fact with NO structured sources: silently skipped.
124
+ await storage.writeMemory("fact", "Legacy fact without provenance sources.", {
125
+ source: "test",
126
+ });
127
+ const context = await orchestrator.recall("where does the atlas cluster store data?", SESSION_KEY);
128
+ const sectionStart = context.indexOf("## Source Episodes");
129
+ assert.ok(sectionStart >= 0, `section must be injected, got: ${context.slice(0, 400)}`);
130
+ const section = context.slice(sectionStart);
131
+ assert.ok(section.includes("### Episode: session-"), "episode header uses shortened session key");
132
+ assert.ok(section.includes("supports ["), "episode cites supporting memory ids");
133
+ assert.ok(section.includes("postgres for the atlas cluster"), "raw source turn is injected");
134
+ assert.ok(section.includes("replica lives in frankfurt"), "merged window covers turn 3");
135
+ assert.ok(!section.includes("Legacy fact"), "fact without sources contributes nothing");
136
+ assert.ok(context.length <= orchestrator.config.recallBudgetChars + 2000, "context stays within budget envelope");
137
+ await orchestrator.destroy();
138
+ } finally {
139
+ await rm(memoryDir, { recursive: true, force: true });
140
+ }
141
+ });
142
+
143
+ test("episodic context: foreign-session provenance is skipped under namespace framing", async () => {
144
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-episodic-ns-"));
145
+ try {
146
+ const orchestrator = await buildOrchestrator(memoryDir, true);
147
+ await seedArchive(orchestrator);
148
+ // The fact's provenance points at a session whose rows live under a
149
+ // DIFFERENT namespace frame than this single-store recall resolves.
150
+ // Candidate keys never match, so no episode is injected.
151
+ const foreign: ProvenanceSource = {
152
+ sessionKey: "\u001fsome-other-tenant\u001fsession-atlas-7",
153
+ turnId: fingerprint(1),
154
+ observedAt: "2026-08-16T00:00:00.000Z",
155
+ quote: "we settled the storage question",
156
+ };
157
+ const storage = await orchestrator.getStorage("default");
158
+ await storage.ensureDirectories();
159
+ await storage.writeMemory("fact", "The atlas cluster stores its graph in postgres.", {
160
+ source: "test",
161
+ sources: [foreign],
162
+ });
163
+ const context = await orchestrator.recall("where does the atlas cluster store data?", SESSION_KEY);
164
+ assert.ok(!context.includes("## Source Episodes"), "foreign-session episode must be skipped");
165
+ await orchestrator.destroy();
166
+ } finally {
167
+ await rm(memoryDir, { recursive: true, force: true });
168
+ }
169
+ });
@@ -0,0 +1,266 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ import {
5
+ compareEpisodeWindows,
6
+ factsNeedingQuoteFallback,
7
+ planEpisodeWindows,
8
+ planEpisodeWindowsWithFallback,
9
+ resolveProvenanceTurnIndex,
10
+ type EpisodicFactInput,
11
+ } from "./episodic-context.js";
12
+ import { cleanArchivedUserMessage } from "./user-message-cleaning.js";
13
+ import { RecallResultFormatter } from "./orchestration/recall-result-formatter.js";
14
+ import { parseConfig } from "./config.js";
15
+ import type { ProvenanceSource } from "./types.js";
16
+
17
+ const SEP = String.fromCharCode(1);
18
+
19
+ function source(overrides: Partial<ProvenanceSource> = {}): ProvenanceSource {
20
+ return {
21
+ sessionKey: "session-a",
22
+ observedAt: "2026-08-16T00:00:00.000Z",
23
+ quote: "the atlas cluster stores edges",
24
+ ...overrides,
25
+ };
26
+ }
27
+
28
+ function fact(
29
+ memoryId: string,
30
+ rank: number,
31
+ sources: ProvenanceSource[] | undefined,
32
+ ): EpisodicFactInput {
33
+ return { memoryId, rank, sources };
34
+ }
35
+
36
+ test("resolveProvenanceTurnIndex parses the fingerprint's trailing turn index", () => {
37
+ const fingerprint = `user${SEP}hello world${SEP}thread-1${SEP}42`;
38
+ assert.equal(resolveProvenanceTurnIndex(fingerprint), 42);
39
+ assert.equal(resolveProvenanceTurnIndex("7"), 7);
40
+ assert.equal(resolveProvenanceTurnIndex("not-a-number"), null);
41
+ assert.equal(resolveProvenanceTurnIndex(`user${SEP}x${SEP}t${SEP}12x`), null);
42
+ assert.equal(resolveProvenanceTurnIndex(undefined), null);
43
+ assert.equal(resolveProvenanceTurnIndex("-3"), null);
44
+ });
45
+
46
+ test("planEpisodeWindows returns [] before any work when limits are zero", () => {
47
+ const facts = [
48
+ fact("m1", 0, [source({ turnId: "5" })]),
49
+ ];
50
+ assert.deepEqual(planEpisodeWindows({ recalledFacts: facts, maxEpisodes: 0, maxTurnsPerEpisode: 8 }), []);
51
+ assert.deepEqual(planEpisodeWindows({ recalledFacts: facts, maxEpisodes: 2, maxTurnsPerEpisode: 0 }), []);
52
+ });
53
+
54
+ test("planEpisodeWindows skips facts without structured sources and unparseable turnIds", () => {
55
+ const facts = [
56
+ fact("m1", 0, undefined),
57
+ fact("m2", 1, []),
58
+ fact("m3", 2, [source({ turnId: "abc" })]),
59
+ fact("m4", 3, [source({ turnId: "10" })]),
60
+ ];
61
+ const windows = planEpisodeWindows({ recalledFacts: facts, maxEpisodes: 2, maxTurnsPerEpisode: 8 });
62
+ assert.equal(windows.length, 1);
63
+ assert.deepEqual(windows[0], {
64
+ sessionKey: "session-a",
65
+ fromTurn: 9,
66
+ toTurn: 12,
67
+ factRank: 3,
68
+ memoryIds: ["m4"],
69
+ });
70
+ });
71
+
72
+ test("planEpisodeWindows merges overlapping and adjacent windows without double-counting turns", () => {
73
+ // turn 5 -> [4,7); turn 6 -> [5,8): overlap -> one merged window [4,8).
74
+ const facts = [
75
+ fact("m1", 0, [source({ turnId: "5" })]),
76
+ fact("m2", 1, [source({ turnId: "6" })]),
77
+ ];
78
+ const windows = planEpisodeWindows({ recalledFacts: facts, maxEpisodes: 2, maxTurnsPerEpisode: 8 });
79
+ assert.equal(windows.length, 1);
80
+ assert.equal(windows[0]!.fromTurn, 4);
81
+ assert.equal(windows[0]!.toTurn, 8);
82
+ assert.deepEqual(windows[0]!.memoryIds, ["m1", "m2"]);
83
+ assert.equal(windows[0]!.factRank, 0);
84
+
85
+ // Boundary adjacency: turn 5 -> [4,7) and turn 7 -> [6,9) share no source
86
+ // turn but read as one episode; they must still merge into [4,9).
87
+ const adjacent = [
88
+ fact("m1", 0, [source({ turnId: "5" })]),
89
+ fact("m2", 1, [source({ turnId: "7" })]),
90
+ ];
91
+ const mergedAdjacent = planEpisodeWindows({
92
+ recalledFacts: adjacent,
93
+ maxEpisodes: 2,
94
+ maxTurnsPerEpisode: 8,
95
+ });
96
+ assert.equal(mergedAdjacent.length, 1);
97
+ assert.equal(mergedAdjacent[0]!.toTurn - mergedAdjacent[0]!.fromTurn, 5);
98
+
99
+ // One gap: turn 5 -> [4,7) and turn 8 -> [7,10) are adjacent and merge;
100
+ // turn 9+ creates a second window only when disjoint.
101
+ const disjoint = [
102
+ fact("m1", 0, [source({ turnId: "2" })]),
103
+ fact("m2", 1, [source({ turnId: "50" })]),
104
+ ];
105
+ const two = planEpisodeWindows({ recalledFacts: disjoint, maxEpisodes: 2, maxTurnsPerEpisode: 8 });
106
+ assert.equal(two.length, 2);
107
+ });
108
+
109
+ test("planEpisodeWindows caps merged span and keeps the best-ranked fact's turn inside", () => {
110
+ // Overlapping sources at turns 2/4/6/8 merge into [1,10) — span 9 with a
111
+ // cap of 4. The trim must keep the rank-0 fact's turn 2 inside.
112
+ const facts = [
113
+ fact("m-best", 0, [source({ turnId: "2" })]),
114
+ fact("m-mid", 3, [source({ turnId: "4" })]),
115
+ fact("m-late", 5, [source({ turnId: "6" })]),
116
+ fact("m-last", 6, [source({ turnId: "8" })]),
117
+ ];
118
+ const windows = planEpisodeWindows({ recalledFacts: facts, maxEpisodes: 2, maxTurnsPerEpisode: 4 });
119
+ assert.equal(windows.length, 1);
120
+ const window = windows[0]!;
121
+ assert.equal(window.toTurn - window.fromTurn, 4);
122
+ assert.ok(
123
+ window.fromTurn <= 2 && 2 < window.toTurn,
124
+ `best turn 2 must be inside [${window.fromTurn},${window.toTurn})`,
125
+ );
126
+ assert.equal(window.factRank, 0);
127
+ });
128
+
129
+ test("planEpisodeWindows is deterministic under input shuffle", () => {
130
+ const facts: EpisodicFactInput[] = [
131
+ fact("m1", 2, [source({ sessionKey: "s-b", turnId: "30" })]),
132
+ fact("m2", 0, [source({ sessionKey: "s-b", turnId: "5" })]),
133
+ fact("m3", 0, [source({ sessionKey: "s-a", turnId: "5" })]),
134
+ fact("m4", 1, [source({ sessionKey: "s-a", turnId: "40" })]),
135
+ ];
136
+ const baseline = planEpisodeWindows({ recalledFacts: facts, maxEpisodes: 3, maxTurnsPerEpisode: 8 });
137
+ for (let shuffle = 0; shuffle < 8; shuffle += 1) {
138
+ const copy = [...facts];
139
+ for (let i = copy.length - 1; i > 0; i -= 1) {
140
+ const j = Math.floor(Math.random() * (i + 1));
141
+ [copy[i], copy[j]] = [copy[j]!, copy[i]!];
142
+ }
143
+ assert.deepEqual(
144
+ planEpisodeWindows({ recalledFacts: copy, maxEpisodes: 3, maxTurnsPerEpisode: 8 }),
145
+ baseline,
146
+ );
147
+ }
148
+ // Ordering contract: rank asc, then sessionKey asc, then fromTurn asc.
149
+ assert.deepEqual(
150
+ baseline.map((w) => w.sessionKey),
151
+ ["s-a", "s-b", "s-a"],
152
+ );
153
+ assert.ok(compareEpisodeWindows(baseline[0]!, baseline[1]!) < 0);
154
+ });
155
+
156
+ test("planEpisodeWindows honors maxEpisodes by best fact rank", () => {
157
+ const facts = [
158
+ fact("m-late", 9, [source({ sessionKey: "s-late", turnId: "5" })]),
159
+ fact("m-early", 0, [source({ sessionKey: "s-early", turnId: "5" })]),
160
+ ];
161
+ const windows = planEpisodeWindows({ recalledFacts: facts, maxEpisodes: 1, maxTurnsPerEpisode: 8 });
162
+ assert.equal(windows.length, 1);
163
+ assert.equal(windows[0]!.sessionKey, "s-early");
164
+ });
165
+
166
+ test("quote fallback: facts whose turnIds all fail resolve through the locator", async () => {
167
+ const facts = [
168
+ fact("m-fallback", 0, [source({ sessionKey: "session-a", turnId: "not-numeric" })]),
169
+ fact("m-direct", 1, [source({ sessionKey: "session-a", turnId: "20" })]),
170
+ ];
171
+ assert.deepEqual(
172
+ factsNeedingQuoteFallback(facts).map((f) => f.memoryId),
173
+ ["m-fallback"],
174
+ );
175
+ const located = await planEpisodeWindowsWithFallback({
176
+ recalledFacts: facts,
177
+ maxEpisodes: 2,
178
+ maxTurnsPerEpisode: 8,
179
+ locateQuote: async (quote, sessionKey) => {
180
+ assert.equal(quote, "the atlas cluster stores edges");
181
+ assert.equal(sessionKey, "session-a");
182
+ return 3;
183
+ },
184
+ });
185
+ // The located quote (turn 3) and the direct turn-20 source are disjoint
186
+ // sessions of turns: two windows, fallback first (better rank).
187
+ assert.equal(located.length, 2);
188
+ assert.deepEqual(located[0], {
189
+ sessionKey: "session-a",
190
+ fromTurn: 2,
191
+ toTurn: 5,
192
+ factRank: 0,
193
+ memoryIds: ["m-fallback"],
194
+ });
195
+ assert.deepEqual(located[1]!.memoryIds, ["m-direct"]);
196
+ });
197
+
198
+ test("quote fallback: a locator miss means no episode; locator errors are swallowed", async () => {
199
+ const facts = [fact("m1", 0, [source({ turnId: "???" })])];
200
+ const missed = await planEpisodeWindowsWithFallback({
201
+ recalledFacts: facts,
202
+ maxEpisodes: 2,
203
+ maxTurnsPerEpisode: 8,
204
+ locateQuote: async () => null,
205
+ });
206
+ assert.deepEqual(missed, []);
207
+ const threw = await planEpisodeWindowsWithFallback({
208
+ recalledFacts: facts,
209
+ maxEpisodes: 2,
210
+ maxTurnsPerEpisode: 8,
211
+ locateQuote: async () => {
212
+ throw new Error("archive unavailable");
213
+ },
214
+ });
215
+ assert.deepEqual(threw, []);
216
+ });
217
+
218
+ test("formatEpisodicContext renders episodes and returns null when empty", () => {
219
+ const formatter = new RecallResultFormatter(parseConfig({ memoryDir: "/tmp/remnic-episodic-test" }));
220
+ assert.equal(formatter.formatEpisodicContext([]), null);
221
+ const rendered = formatter.formatEpisodicContext([
222
+ {
223
+ sessionKey: "session-alpha-long",
224
+ fromTurn: 4,
225
+ toTurn: 7,
226
+ memoryIds: ["m1", "m2"],
227
+ turns: [
228
+ { role: "user", content: "we chose postgres" },
229
+ { role: "assistant", content: "noted" },
230
+ ],
231
+ },
232
+ ]);
233
+ assert.ok(rendered!.startsWith("## Source Episodes\n\n### Episode: session-… turns 4-6 (supports [m1, m2])"));
234
+ assert.ok(rendered!.includes("user: we chose postgres"));
235
+ });
236
+
237
+ test("cleanArchivedUserMessage strips an injected memory-context preamble (shipped cleaner contract)", () => {
238
+ // The shared cleaner (moved verbatim from the host wiring) strips a LEADING
239
+ // `## Memory Context` preamble up to the next `## ` header or end of string.
240
+ const leadingWithHeader =
241
+ "## Memory Context (Remnic)\n\n- old fact\n\n## Actual Question\nWhere do we stand?";
242
+ assert.equal(
243
+ cleanArchivedUserMessage(leadingWithHeader),
244
+ "## Actual Question\nWhere do we stand?",
245
+ );
246
+ const wrapped =
247
+ "<supermemory-context>injected</supermemory-context>Real question about the atlas cluster";
248
+ assert.equal(
249
+ cleanArchivedUserMessage(wrapped),
250
+ "Real question about the atlas cluster",
251
+ );
252
+ // A block that is not leading stays: a user writing this title mid-message
253
+ // keeps it (documented behavior — anchored strip, no free-form deletion).
254
+ const userAuthored =
255
+ "Reminder:\n## Memory Context (Remnic)\nthis is my own note";
256
+ assert.equal(cleanArchivedUserMessage(userAuthored), userAuthored);
257
+ });
258
+
259
+ test("cleanArchivedUserMessage preserves text before and between wrappers (round 4 regression)", () => {
260
+ const mixed =
261
+ "keep this <supermemory-context>first</supermemory-context> and this <supermemory-context k=\"v\">second</supermemory-context> end";
262
+ assert.equal(
263
+ cleanArchivedUserMessage(mixed),
264
+ "keep this and this end",
265
+ );
266
+ });