@remnic/core 9.57.6 → 9.58.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 (471) hide show
  1. package/dist/access-admin-ops-surface.d.ts +12 -11
  2. package/dist/access-admin-ops-surface.js +25 -24
  3. package/dist/access-authorization-probe.d.ts +12 -11
  4. package/dist/access-authorization-probe.js +26 -25
  5. package/dist/access-boundary.d.ts +12 -11
  6. package/dist/access-boundary.js +25 -24
  7. package/dist/access-cli.js +77 -76
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-coding-context-resolution.d.ts +1 -1
  10. package/dist/access-extraction-force-flush.d.ts +12 -11
  11. package/dist/access-extraction-force-flush.js +25 -24
  12. package/dist/access-health-types.d.ts +1 -1
  13. package/dist/access-http-lcm-compaction.d.ts +12 -11
  14. package/dist/access-http-lifecycle-flush.d.ts +12 -11
  15. package/dist/access-http-offline-stream.d.ts +12 -11
  16. package/dist/access-http-query.js +25 -24
  17. package/dist/access-http.d.ts +13 -12
  18. package/dist/access-http.js +36 -35
  19. package/dist/access-identity-continuity-surface.d.ts +10 -9
  20. package/dist/access-identity-continuity-surface.js +25 -24
  21. package/dist/access-lcm-surface.d.ts +12 -11
  22. package/dist/access-lcm-surface.js +25 -24
  23. package/dist/access-mcp.d.ts +12 -11
  24. package/dist/access-mcp.js +32 -31
  25. package/dist/access-memory-search-fanout.d.ts +2 -2
  26. package/dist/{access-namespace-preflight-Bpt-SYP0.d.ts → access-namespace-preflight-TBXz-8s_.d.ts} +1 -1
  27. package/dist/access-namespace-preflight.d.ts +3 -3
  28. package/dist/access-namespace-preflight.js +25 -24
  29. package/dist/access-observe-write-surface.d.ts +12 -11
  30. package/dist/access-observe-write-surface.js +25 -24
  31. package/dist/access-offline-manifest.d.ts +10 -9
  32. package/dist/access-operations-batch.js +27 -26
  33. package/dist/access-operations.d.ts +12 -11
  34. package/dist/access-operations.js +31 -30
  35. package/dist/access-recall-concurrency.d.ts +12 -11
  36. package/dist/access-recall-concurrency.js +25 -24
  37. package/dist/access-recall-response.d.ts +12 -11
  38. package/dist/access-recall-response.js +25 -24
  39. package/dist/access-recall-surface.d.ts +12 -11
  40. package/dist/access-recall-surface.js +25 -24
  41. package/dist/access-schema.js +3 -3
  42. package/dist/{access-service-4DO8XMq6.d.ts → access-service-BQkRul4d.d.ts} +7 -7
  43. package/dist/access-service-helpers.d.ts +12 -11
  44. package/dist/access-service.d.ts +12 -11
  45. package/dist/access-service.js +25 -24
  46. package/dist/access-surface-catalog.d.ts +12 -11
  47. package/dist/access-surface-catalog.js +27 -26
  48. package/dist/access-surface-catalog.js.map +1 -1
  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/behavior-learner.d.ts +1 -1
  57. package/dist/behavior-signals.d.ts +1 -1
  58. package/dist/bootstrap.d.ts +10 -9
  59. package/dist/briefing-window.d.ts +2 -2
  60. package/dist/briefing.d.ts +2 -2
  61. package/dist/briefing.js +10 -10
  62. package/dist/buffer-surprise-report.d.ts +1 -1
  63. package/dist/buffer-surprise.js +4 -3
  64. package/dist/buffer-turn-helpers.d.ts +1 -1
  65. package/dist/buffer.d.ts +2 -2
  66. package/dist/bulk-import/index.d.ts +3 -3
  67. package/dist/calibration.d.ts +1 -1
  68. package/dist/capabilities.d.ts +1 -1
  69. package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-GWVG7LGC.js} +2 -2
  70. package/dist/{catalog-BasnO3Bw.d.ts → catalog-z1UerMbh.d.ts} +1 -1
  71. package/dist/causal-behavior.d.ts +2 -1
  72. package/dist/causal-consolidation.d.ts +1 -1
  73. package/dist/causal-consolidation.js +14 -13
  74. package/dist/causal-consolidation.js.map +1 -1
  75. package/dist/causal-trajectory-graph.d.ts +1 -1
  76. package/dist/{chunk-P6WBAR27.js → chunk-2GBFKHBZ.js} +9 -9
  77. package/dist/chunk-2GBFKHBZ.js.map +1 -0
  78. package/dist/{chunk-YTZA7U6Q.js → chunk-2VHCLHZ5.js} +3 -3
  79. package/dist/{chunk-NEJQ65NV.js → chunk-4CLE2LXB.js} +2 -2
  80. package/dist/{chunk-3VFVQDZO.js → chunk-4IIKJOYM.js} +1 -1
  81. package/dist/{chunk-3VFVQDZO.js.map → chunk-4IIKJOYM.js.map} +1 -1
  82. package/dist/{chunk-JLNBQWZ2.js → chunk-5JMAGU26.js} +7 -6
  83. package/dist/{chunk-JLNBQWZ2.js.map → chunk-5JMAGU26.js.map} +1 -1
  84. package/dist/{chunk-VDX2J7OX.js → chunk-5W7CTZ2E.js} +4 -4
  85. package/dist/{chunk-CZUHNJHX.js → chunk-6C7Q6NG3.js} +13 -13
  86. package/dist/{chunk-LMXUWAXW.js → chunk-6TBIWIAG.js} +9 -8
  87. package/dist/chunk-6TBIWIAG.js.map +1 -0
  88. package/dist/{chunk-4O6R3GPK.js → chunk-6W2ISYUV.js} +4 -4
  89. package/dist/{chunk-3AJOJOFP.js → chunk-77DAFTUU.js} +3 -3
  90. package/dist/{chunk-IKT6ZVO7.js → chunk-7DHFB5SG.js} +3 -3
  91. package/dist/{chunk-SFR7J2G6.js → chunk-7G34CBKS.js} +2 -2
  92. package/dist/{chunk-IT57AOMC.js → chunk-AH2NX6S7.js} +3 -3
  93. package/dist/{chunk-HYQJQGD3.js → chunk-AM4T6CHX.js} +49 -35
  94. package/dist/chunk-AM4T6CHX.js.map +1 -0
  95. package/dist/{chunk-Z54EM5YZ.js → chunk-B2QHVLJO.js} +60 -30
  96. package/dist/chunk-B2QHVLJO.js.map +1 -0
  97. package/dist/{chunk-FI3PIOOI.js → chunk-B4CSPFYN.js} +8 -8
  98. package/dist/{chunk-7PJARJS4.js → chunk-BPM6UHUL.js} +2 -2
  99. package/dist/{chunk-PPUTUOC3.js → chunk-BTHDQOF4.js} +5 -5
  100. package/dist/{chunk-DUHMYBVE.js → chunk-CZGOLAEW.js} +41 -41
  101. package/dist/{chunk-5PGYCWA7.js → chunk-DE6YCZEE.js} +2 -2
  102. package/dist/{chunk-JOA4Q765.js → chunk-EUYWQ7TS.js} +2 -2
  103. package/dist/{chunk-O5AFC5KM.js → chunk-EWL5DICB.js} +2 -2
  104. package/dist/{chunk-4YZCIK5E.js → chunk-EZXGJJXM.js} +2 -2
  105. package/dist/{chunk-GXIY65UH.js → chunk-FI5EAP4N.js} +2 -2
  106. package/dist/{chunk-YOKSRIFI.js → chunk-FUWS2MNJ.js} +4 -4
  107. package/dist/{chunk-6RK2X7BR.js → chunk-G3JFFUKR.js} +2 -2
  108. package/dist/{chunk-VANZKHTN.js → chunk-G5OB4XZX.js} +4 -4
  109. package/dist/{chunk-TEHPIMXD.js → chunk-HK6KYIF6.js} +2 -2
  110. package/dist/{chunk-XBGLEOID.js → chunk-I4BLRM7X.js} +9 -9
  111. package/dist/{chunk-5ZIWRMZM.js → chunk-IVKIODHO.js} +7 -6
  112. package/dist/chunk-IVKIODHO.js.map +1 -0
  113. package/dist/{chunk-6SX4MY5Q.js → chunk-J65AKOD6.js} +2 -2
  114. package/dist/{chunk-BPWZDHFM.js → chunk-J6QIAYNR.js} +2 -2
  115. package/dist/{chunk-XL3TATMJ.js → chunk-JHMAYABJ.js} +4 -4
  116. package/dist/{chunk-F7M36OG2.js → chunk-JNWISMYG.js} +10 -10
  117. package/dist/{chunk-VYIXCMUP.js → chunk-KBIIE57I.js} +3 -3
  118. package/dist/{chunk-QKPDN325.js → chunk-KF75ANST.js} +6 -3
  119. package/dist/chunk-KF75ANST.js.map +1 -0
  120. package/dist/{chunk-24PNX2GF.js → chunk-KXYMU4IN.js} +3 -3
  121. package/dist/{chunk-FKTD7IVS.js → chunk-L3JVAM5Q.js} +2 -2
  122. package/dist/{chunk-5QHDXMXP.js → chunk-LLZKOSGM.js} +1 -1
  123. package/dist/{chunk-5QHDXMXP.js.map → chunk-LLZKOSGM.js.map} +1 -1
  124. package/dist/{chunk-LIF6DO6U.js → chunk-MG7GI4TT.js} +2 -2
  125. package/dist/{chunk-RUZM6Z52.js → chunk-MMZK2DWN.js} +1 -1
  126. package/dist/{chunk-NTJ6TY44.js → chunk-ODAE36PG.js} +3 -3
  127. package/dist/{chunk-QFN4U7AG.js → chunk-ODZKV2F7.js} +3 -3
  128. package/dist/{chunk-QFN4U7AG.js.map → chunk-ODZKV2F7.js.map} +1 -1
  129. package/dist/{chunk-YLHM5BQQ.js → chunk-OLX2HJFW.js} +4 -4
  130. package/dist/{chunk-DNC4A7RS.js → chunk-OU7RWWW6.js} +2 -2
  131. package/dist/{chunk-L3LRWDJW.js → chunk-OV36CROW.js} +3 -3
  132. package/dist/{chunk-BXLOS5AJ.js → chunk-OWHERGF2.js} +2 -2
  133. package/dist/{chunk-CSV34HIW.js → chunk-P5OYNV7B.js} +2 -2
  134. package/dist/{chunk-SNW3YRO6.js → chunk-P6GOYLHN.js} +2 -2
  135. package/dist/{chunk-REVMY7RA.js → chunk-PFPNUFKZ.js} +109 -59
  136. package/dist/chunk-PFPNUFKZ.js.map +1 -0
  137. package/dist/{chunk-USGKHF36.js → chunk-QUJC22CT.js} +2 -2
  138. package/dist/{chunk-BVRREV3N.js → chunk-R7IV3EUJ.js} +2 -2
  139. package/dist/{chunk-KSXJOC4F.js → chunk-RDFF2NAU.js} +18 -8
  140. package/dist/chunk-RDFF2NAU.js.map +1 -0
  141. package/dist/{chunk-D4LVHPOA.js → chunk-RXN7Z2V5.js} +3 -3
  142. package/dist/{chunk-7VSHDLJQ.js → chunk-T2VJ2EO5.js} +6 -6
  143. package/dist/chunk-TOTT6S2V.js +20 -0
  144. package/dist/chunk-TOTT6S2V.js.map +1 -0
  145. package/dist/{chunk-U7BMN33M.js → chunk-UBSM6TZP.js} +2 -2
  146. package/dist/{chunk-DQEMWVMT.js → chunk-UVYI6VIX.js} +1 -1
  147. package/dist/{chunk-U7XLOSG2.js → chunk-VIM6QH4D.js} +2 -2
  148. package/dist/{chunk-LJJWFV2Q.js → chunk-VJXSAJFW.js} +2 -2
  149. package/dist/{chunk-HZC3OECF.js → chunk-VOKK4WCG.js} +2 -2
  150. package/dist/{chunk-LTAVSOZW.js → chunk-WVP2I6C5.js} +5 -4
  151. package/dist/chunk-WVP2I6C5.js.map +1 -0
  152. package/dist/{chunk-LRDP2AC2.js → chunk-YBCZTBN2.js} +2 -2
  153. package/dist/{chunk-USAUBGBC.js → chunk-YKZFX2HQ.js} +2 -2
  154. package/dist/{chunk-I2GIYTRU.js → chunk-ZOGOOSB3.js} +2 -2
  155. package/dist/{chunk-PBGWYM3H.js → chunk-ZPUIRTIZ.js} +27 -15
  156. package/dist/chunk-ZPUIRTIZ.js.map +1 -0
  157. package/dist/chunking.js +2 -1
  158. package/dist/{cli-CQdYilcx.d.ts → cli-DsyVvOFP.d.ts} +5 -5
  159. package/dist/cli.d.ts +14 -13
  160. package/dist/cli.js +57 -56
  161. package/dist/coding/pre-action-gate.d.ts +1 -1
  162. package/dist/compounding/engine.d.ts +2 -2
  163. package/dist/compounding/engine.js +10 -10
  164. package/dist/compounding/preference-consolidator.d.ts +2 -1
  165. package/dist/compression-optimizer.d.ts +1 -1
  166. package/dist/config.d.ts +1 -1
  167. package/dist/config.js +1 -1
  168. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  169. package/dist/connectors/codex-materialize-runner.js +12 -11
  170. package/dist/connectors/codex-materialize.d.ts +7 -12
  171. package/dist/connectors/codex-materialize.js +2 -1
  172. package/dist/connectors/index.d.ts +1 -1
  173. package/dist/connectors/index.js +12 -11
  174. package/dist/consolidation-provenance-check.d.ts +2 -2
  175. package/dist/consolidation-undo.d.ts +2 -2
  176. package/dist/contradiction/index.d.ts +2 -2
  177. package/dist/contradiction/index.js +4 -4
  178. package/dist/converge-config.d.ts +1 -1
  179. package/dist/convergence-refresh.d.ts +2 -2
  180. package/dist/convergence-refresh.js +12 -12
  181. package/dist/conversation-index/backend.d.ts +1 -1
  182. package/dist/conversation-index/chunker.d.ts +1 -1
  183. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  184. package/dist/conversation-index/indexer.d.ts +1 -1
  185. package/dist/conversation-index/search.d.ts +1 -1
  186. package/dist/corpus-watermark.d.ts +1 -1
  187. package/dist/corpus-watermark.js +12 -12
  188. package/dist/day-summary.d.ts +1 -1
  189. package/dist/day-summary.js +3 -2
  190. package/dist/delinearize.d.ts +1 -1
  191. package/dist/dependency-propagation-config.d.ts +1 -1
  192. package/dist/{dependency-propagation-delivery-C_K_AHcv.d.ts → dependency-propagation-delivery-DdwSc1qh.d.ts} +1 -1
  193. package/dist/direct-answer-wiring.d.ts +1 -1
  194. package/dist/direct-answer.d.ts +1 -1
  195. package/dist/embedding-fallback.d.ts +1 -1
  196. package/dist/enrichment/index.d.ts +1 -1
  197. package/dist/entity-retrieval.d.ts +2 -2
  198. package/dist/entity-retrieval.js +10 -10
  199. package/dist/entity-schema.d.ts +1 -1
  200. package/dist/explicit-capture.d.ts +10 -9
  201. package/dist/external-wiki-access.d.ts +12 -11
  202. package/dist/external-wiki-access.js +26 -25
  203. package/dist/external-wiki-collection-registration.d.ts +1 -1
  204. package/dist/external-wiki-collection.d.ts +1 -1
  205. package/dist/external-wiki-mcp-tools.d.ts +12 -11
  206. package/dist/extraction-error-classification.d.ts +1 -1
  207. package/dist/extraction-faithfulness.d.ts +1 -1
  208. package/dist/extraction-judge-telemetry.d.ts +1 -1
  209. package/dist/extraction-judge-training.d.ts +1 -1
  210. package/dist/extraction-judge.d.ts +1 -1
  211. package/dist/extraction-liveness.d.ts +1 -1
  212. package/dist/extraction-normalization.d.ts +1 -1
  213. package/dist/extraction-prompt.d.ts +1 -1
  214. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  215. package/dist/extraction-source-grounding.d.ts +1 -1
  216. package/dist/extraction.d.ts +1 -1
  217. package/dist/extraction.js +16 -15
  218. package/dist/fallback-llm.d.ts +1 -1
  219. package/dist/graph-dashboard-diff.d.ts +1 -1
  220. package/dist/graph-dashboard-key.d.ts +1 -1
  221. package/dist/graph-dashboard-parser.d.ts +1 -1
  222. package/dist/graph-edge-reinforcement.d.ts +1 -1
  223. package/dist/graph-path-reconstruction.d.ts +1 -1
  224. package/dist/graph-path-scoring.d.ts +1 -1
  225. package/dist/graph-snapshot.d.ts +1 -1
  226. package/dist/graph.d.ts +1 -1
  227. package/dist/harmonic-retrieval.js +1 -1
  228. package/dist/importance.d.ts +1 -1
  229. package/dist/importers/index.d.ts +1 -1
  230. package/dist/in-flight-reads.d.ts +1 -1
  231. package/dist/index.d.ts +22 -21
  232. package/dist/index.js +81 -80
  233. package/dist/intent.d.ts +1 -1
  234. package/dist/lcm/archive.d.ts +3 -2
  235. package/dist/lcm/archive.js +2 -1
  236. package/dist/lcm/engine.d.ts +2 -1
  237. package/dist/lcm/engine.js +5 -4
  238. package/dist/lcm/index.d.ts +2 -1
  239. package/dist/lcm/index.js +7 -6
  240. package/dist/lcm/recall.d.ts +1 -0
  241. package/dist/lcm/summarizer.d.ts +1 -0
  242. package/dist/lcm/summarizer.js +3 -2
  243. package/dist/lcm/tools.d.ts +2 -1
  244. package/dist/lifecycle.d.ts +1 -1
  245. package/dist/live-connectors-runner.d.ts +1 -1
  246. package/dist/local-llm.d.ts +2 -3
  247. package/dist/local-llm.js +2 -1
  248. package/dist/local-model-endpoint.d.ts +1 -1
  249. package/dist/maintenance/memory-governance.d.ts +1 -1
  250. package/dist/maintenance/memory-governance.js +10 -10
  251. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  252. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -10
  253. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  254. package/dist/maintenance/rebuild-memory-projection.js +11 -11
  255. package/dist/{maintenance-DdP931i9.d.ts → maintenance-DvkiF7fm.d.ts} +3 -3
  256. package/dist/mcp-memory-inspector-app.d.ts +12 -11
  257. package/dist/memory-action-policy.d.ts +1 -1
  258. package/dist/memory-cache.d.ts +1 -1
  259. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  260. package/dist/memory-projection-store.d.ts +1 -1
  261. package/dist/memory-provenance.d.ts +1 -1
  262. package/dist/memory-snapshot.d.ts +1 -1
  263. package/dist/memory-worth-outcomes.d.ts +2 -2
  264. package/dist/models-json.d.ts +1 -1
  265. package/dist/namespaces/migrate.d.ts +3 -3
  266. package/dist/namespaces/migrate.js +11 -11
  267. package/dist/namespaces/principal.d.ts +1 -1
  268. package/dist/namespaces/search.d.ts +1 -1
  269. package/dist/namespaces/search.js +7 -7
  270. package/dist/namespaces/storage.d.ts +3 -3
  271. package/dist/namespaces/storage.js +10 -10
  272. package/dist/native-knowledge.d.ts +1 -1
  273. package/dist/offline-sync-impression-drain.d.ts +1 -1
  274. package/dist/operator-doctor-corpus.d.ts +1 -1
  275. package/dist/operator-doctor-corpus.js +13 -13
  276. package/dist/operator-doctor-replica.d.ts +1 -1
  277. package/dist/operator-toolkit.d.ts +3 -3
  278. package/dist/operator-toolkit.js +18 -18
  279. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  280. package/dist/orchestration/maintenance.d.ts +4 -4
  281. package/dist/orchestration/maintenance.js +15 -15
  282. package/dist/{orchestrator-DxUWX7gs.d.ts → orchestrator-CXPIzs3D.d.ts} +9 -9
  283. package/dist/orchestrator.d.ts +10 -9
  284. package/dist/orchestrator.js +77 -76
  285. package/dist/patterns-cli.d.ts +1 -1
  286. package/dist/{pipeline-BKUMU1vU.d.ts → pipeline-BuYWU9rt.d.ts} +1 -1
  287. package/dist/policy-runtime.d.ts +1 -1
  288. package/dist/proactive-contention.d.ts +1 -1
  289. package/dist/provenance.d.ts +1 -1
  290. package/dist/{public-http-Dw0bJhcC.d.ts → public-http-m9x1Qyzn.d.ts} +1 -1
  291. package/dist/{qmd-DJP-GLFe.d.ts → qmd-DYnrPw-m.d.ts} +1 -1
  292. package/dist/qmd-preflight.d.ts +2 -2
  293. package/dist/qmd-recall-cache.d.ts +1 -1
  294. package/dist/qmd.d.ts +2 -2
  295. package/dist/recall-concurrency-config.d.ts +1 -1
  296. package/dist/recall-disclosure-escalation.d.ts +1 -1
  297. package/dist/recall-explain-renderer.d.ts +1 -1
  298. package/dist/recall-explain-renderer.js +4 -3
  299. package/dist/recall-memory-map.d.ts +1 -1
  300. package/dist/recall-planner-llm.d.ts +1 -1
  301. package/dist/recall-state.d.ts +1 -1
  302. package/dist/recall-tag-filter.d.ts +1 -1
  303. package/dist/recall-timings.d.ts +1 -1
  304. package/dist/recall-xray-cli.d.ts +1 -1
  305. package/dist/recall-xray-cli.js +5 -4
  306. package/dist/recall-xray-renderer.d.ts +1 -1
  307. package/dist/recall-xray-renderer.js +4 -3
  308. package/dist/recall-xray.d.ts +2 -7
  309. package/dist/recall-xray.js +3 -2
  310. package/dist/reconcile/cursor.d.ts +1 -1
  311. package/dist/reconcile/manifest.d.ts +1 -1
  312. package/dist/reconcile/plan.d.ts +1 -1
  313. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  314. package/dist/replay/normalizers/claude.d.ts +1 -1
  315. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  316. package/dist/replay/normalizers/shared.d.ts +1 -1
  317. package/dist/replay/runner.d.ts +1 -1
  318. package/dist/replay/types.d.ts +1 -1
  319. package/dist/replica-divergence.d.ts +1 -1
  320. package/dist/replica-peers-config.d.ts +1 -1
  321. package/dist/resolve-auth-token.d.ts +1 -1
  322. package/dist/resume-bundles.js +4 -3
  323. package/dist/retrieval-agents.d.ts +2 -2
  324. package/dist/retrieval-tiers.d.ts +1 -1
  325. package/dist/routing/engine.d.ts +1 -1
  326. package/dist/routing/store.d.ts +1 -1
  327. package/dist/salvage-envelope.d.ts +1 -1
  328. package/dist/{scope-profiles-CaKcnB-6.d.ts → scope-profiles-C1QG4Cmv.d.ts} +1 -1
  329. package/dist/search/embed-helper.d.ts +1 -1
  330. package/dist/search/factory.d.ts +1 -1
  331. package/dist/search/factory.js +6 -6
  332. package/dist/search/index.d.ts +1 -1
  333. package/dist/search/index.js +11 -11
  334. package/dist/search/lancedb-backend.d.ts +1 -1
  335. package/dist/search/lancedb-backend.js +2 -2
  336. package/dist/search/meilisearch-backend.d.ts +1 -1
  337. package/dist/search/meilisearch-backend.js +2 -2
  338. package/dist/search/noop-backend.d.ts +1 -1
  339. package/dist/search/orama-backend.d.ts +1 -1
  340. package/dist/search/orama-backend.js +2 -2
  341. package/dist/search/port.d.ts +1 -1
  342. package/dist/search/remote-backend.d.ts +1 -1
  343. package/dist/semantic-chunking.js +3 -2
  344. package/dist/{semantic-consolidation-P0eMWqh-.d.ts → semantic-consolidation-DMeX8XS0.d.ts} +1 -1
  345. package/dist/semantic-consolidation.d.ts +2 -2
  346. package/dist/semantic-consolidation.js +14 -13
  347. package/dist/semantic-rule-promotion.js +10 -10
  348. package/dist/semantic-rule-verifier.d.ts +1 -1
  349. package/dist/semantic-rule-verifier.js +10 -10
  350. package/dist/{service-D5GQLxq_.d.ts → service-CT3ENiTO.d.ts} +2 -2
  351. package/dist/session-observer-bands.d.ts +1 -1
  352. package/dist/session-observer-state.d.ts +1 -1
  353. package/dist/session-observer-state.js +1 -1
  354. package/dist/shared-context/manager.d.ts +1 -1
  355. package/dist/signal.d.ts +1 -1
  356. package/dist/source-agent-qualifier.d.ts +1 -1
  357. package/dist/source-agent-qualifier.js +12 -11
  358. package/dist/{storage-DIyil2ll.d.ts → storage-B0L76y7N.d.ts} +1 -1
  359. package/dist/storage.d.ts +2 -2
  360. package/dist/storage.js +9 -9
  361. package/dist/summarizer.d.ts +1 -1
  362. package/dist/summarizer.js +3 -2
  363. package/dist/summary-snapshot.d.ts +1 -1
  364. package/dist/support-passport/index.d.ts +15 -14
  365. package/dist/support-passport/index.js +28 -27
  366. package/dist/temporal-supersession.d.ts +2 -2
  367. package/dist/temporal-timeline-recall.d.ts +1 -1
  368. package/dist/temporal-validity.d.ts +1 -1
  369. package/dist/threading.d.ts +1 -1
  370. package/dist/tier-migration.d.ts +2 -2
  371. package/dist/tier-routing.d.ts +1 -1
  372. package/dist/token-estimate.d.ts +10 -0
  373. package/dist/token-estimate.js +8 -0
  374. package/dist/token-estimate.js.map +1 -0
  375. package/dist/topics.d.ts +1 -1
  376. package/dist/transcript.d.ts +1 -6
  377. package/dist/transcript.js +2 -1
  378. package/dist/transfer/backup.js +2 -2
  379. package/dist/transfer/capsule-export.js +2 -2
  380. package/dist/transfer/capsule-import.js +2 -2
  381. package/dist/trust-score-stage.d.ts +1 -1
  382. package/dist/trust-score.d.ts +1 -1
  383. package/dist/{types-CbXieHKr.d.ts → types-D7pB0QwO.d.ts} +1 -1
  384. package/dist/types.d.ts +1 -1
  385. package/dist/types.js +1 -1
  386. package/dist/utility-runtime.d.ts +1 -1
  387. package/dist/verified-recall.js +10 -10
  388. package/dist/write-envelope.d.ts +1 -1
  389. package/package.json +12 -2
  390. package/src/chunking.ts +6 -12
  391. package/src/config.ts +2 -0
  392. package/src/connectors/codex-materialize.ts +21 -26
  393. package/src/lcm/archive.ts +4 -5
  394. package/src/lcm/engine.ts +55 -34
  395. package/src/lcm/summarizer.ts +27 -16
  396. package/src/lcm-engine.test.ts +82 -2
  397. package/src/local-llm.ts +4 -6
  398. package/src/memory-extension-host/render-extensions-block.ts +3 -9
  399. package/src/orchestration/recall-section-coordinator.ts +93 -27
  400. package/src/recall-token-budget.test.ts +51 -0
  401. package/src/recall-xray.ts +4 -11
  402. package/src/semantic-chunking.ts +5 -12
  403. package/src/session-observer-state.ts +3 -3
  404. package/src/testing/subjects/recall-budget.test.ts +21 -5
  405. package/src/token-estimate.test.ts +38 -0
  406. package/src/token-estimate.ts +22 -0
  407. package/src/transcript.test.ts +38 -3
  408. package/src/transcript.ts +58 -59
  409. package/src/types.ts +1 -1
  410. package/dist/chunk-5ZIWRMZM.js.map +0 -1
  411. package/dist/chunk-HYQJQGD3.js.map +0 -1
  412. package/dist/chunk-KSXJOC4F.js.map +0 -1
  413. package/dist/chunk-LMXUWAXW.js.map +0 -1
  414. package/dist/chunk-LTAVSOZW.js.map +0 -1
  415. package/dist/chunk-P6WBAR27.js.map +0 -1
  416. package/dist/chunk-PBGWYM3H.js.map +0 -1
  417. package/dist/chunk-QKPDN325.js.map +0 -1
  418. package/dist/chunk-REVMY7RA.js.map +0 -1
  419. package/dist/chunk-Z54EM5YZ.js.map +0 -1
  420. /package/dist/{capsule-crypto-YO5QJ6L3.js.map → capsule-crypto-GWVG7LGC.js.map} +0 -0
  421. /package/dist/{chunk-YTZA7U6Q.js.map → chunk-2VHCLHZ5.js.map} +0 -0
  422. /package/dist/{chunk-NEJQ65NV.js.map → chunk-4CLE2LXB.js.map} +0 -0
  423. /package/dist/{chunk-VDX2J7OX.js.map → chunk-5W7CTZ2E.js.map} +0 -0
  424. /package/dist/{chunk-CZUHNJHX.js.map → chunk-6C7Q6NG3.js.map} +0 -0
  425. /package/dist/{chunk-4O6R3GPK.js.map → chunk-6W2ISYUV.js.map} +0 -0
  426. /package/dist/{chunk-3AJOJOFP.js.map → chunk-77DAFTUU.js.map} +0 -0
  427. /package/dist/{chunk-IKT6ZVO7.js.map → chunk-7DHFB5SG.js.map} +0 -0
  428. /package/dist/{chunk-SFR7J2G6.js.map → chunk-7G34CBKS.js.map} +0 -0
  429. /package/dist/{chunk-IT57AOMC.js.map → chunk-AH2NX6S7.js.map} +0 -0
  430. /package/dist/{chunk-FI3PIOOI.js.map → chunk-B4CSPFYN.js.map} +0 -0
  431. /package/dist/{chunk-7PJARJS4.js.map → chunk-BPM6UHUL.js.map} +0 -0
  432. /package/dist/{chunk-PPUTUOC3.js.map → chunk-BTHDQOF4.js.map} +0 -0
  433. /package/dist/{chunk-DUHMYBVE.js.map → chunk-CZGOLAEW.js.map} +0 -0
  434. /package/dist/{chunk-5PGYCWA7.js.map → chunk-DE6YCZEE.js.map} +0 -0
  435. /package/dist/{chunk-JOA4Q765.js.map → chunk-EUYWQ7TS.js.map} +0 -0
  436. /package/dist/{chunk-O5AFC5KM.js.map → chunk-EWL5DICB.js.map} +0 -0
  437. /package/dist/{chunk-4YZCIK5E.js.map → chunk-EZXGJJXM.js.map} +0 -0
  438. /package/dist/{chunk-GXIY65UH.js.map → chunk-FI5EAP4N.js.map} +0 -0
  439. /package/dist/{chunk-YOKSRIFI.js.map → chunk-FUWS2MNJ.js.map} +0 -0
  440. /package/dist/{chunk-6RK2X7BR.js.map → chunk-G3JFFUKR.js.map} +0 -0
  441. /package/dist/{chunk-VANZKHTN.js.map → chunk-G5OB4XZX.js.map} +0 -0
  442. /package/dist/{chunk-TEHPIMXD.js.map → chunk-HK6KYIF6.js.map} +0 -0
  443. /package/dist/{chunk-XBGLEOID.js.map → chunk-I4BLRM7X.js.map} +0 -0
  444. /package/dist/{chunk-6SX4MY5Q.js.map → chunk-J65AKOD6.js.map} +0 -0
  445. /package/dist/{chunk-BPWZDHFM.js.map → chunk-J6QIAYNR.js.map} +0 -0
  446. /package/dist/{chunk-XL3TATMJ.js.map → chunk-JHMAYABJ.js.map} +0 -0
  447. /package/dist/{chunk-F7M36OG2.js.map → chunk-JNWISMYG.js.map} +0 -0
  448. /package/dist/{chunk-VYIXCMUP.js.map → chunk-KBIIE57I.js.map} +0 -0
  449. /package/dist/{chunk-24PNX2GF.js.map → chunk-KXYMU4IN.js.map} +0 -0
  450. /package/dist/{chunk-FKTD7IVS.js.map → chunk-L3JVAM5Q.js.map} +0 -0
  451. /package/dist/{chunk-LIF6DO6U.js.map → chunk-MG7GI4TT.js.map} +0 -0
  452. /package/dist/{chunk-RUZM6Z52.js.map → chunk-MMZK2DWN.js.map} +0 -0
  453. /package/dist/{chunk-NTJ6TY44.js.map → chunk-ODAE36PG.js.map} +0 -0
  454. /package/dist/{chunk-YLHM5BQQ.js.map → chunk-OLX2HJFW.js.map} +0 -0
  455. /package/dist/{chunk-DNC4A7RS.js.map → chunk-OU7RWWW6.js.map} +0 -0
  456. /package/dist/{chunk-L3LRWDJW.js.map → chunk-OV36CROW.js.map} +0 -0
  457. /package/dist/{chunk-BXLOS5AJ.js.map → chunk-OWHERGF2.js.map} +0 -0
  458. /package/dist/{chunk-CSV34HIW.js.map → chunk-P5OYNV7B.js.map} +0 -0
  459. /package/dist/{chunk-SNW3YRO6.js.map → chunk-P6GOYLHN.js.map} +0 -0
  460. /package/dist/{chunk-USGKHF36.js.map → chunk-QUJC22CT.js.map} +0 -0
  461. /package/dist/{chunk-BVRREV3N.js.map → chunk-R7IV3EUJ.js.map} +0 -0
  462. /package/dist/{chunk-D4LVHPOA.js.map → chunk-RXN7Z2V5.js.map} +0 -0
  463. /package/dist/{chunk-7VSHDLJQ.js.map → chunk-T2VJ2EO5.js.map} +0 -0
  464. /package/dist/{chunk-U7BMN33M.js.map → chunk-UBSM6TZP.js.map} +0 -0
  465. /package/dist/{chunk-DQEMWVMT.js.map → chunk-UVYI6VIX.js.map} +0 -0
  466. /package/dist/{chunk-U7XLOSG2.js.map → chunk-VIM6QH4D.js.map} +0 -0
  467. /package/dist/{chunk-LJJWFV2Q.js.map → chunk-VJXSAJFW.js.map} +0 -0
  468. /package/dist/{chunk-HZC3OECF.js.map → chunk-VOKK4WCG.js.map} +0 -0
  469. /package/dist/{chunk-LRDP2AC2.js.map → chunk-YBCZTBN2.js.map} +0 -0
  470. /package/dist/{chunk-USAUBGBC.js.map → chunk-YKZFX2HQ.js.map} +0 -0
  471. /package/dist/{chunk-I2GIYTRU.js.map → chunk-ZOGOOSB3.js.map} +0 -0
@@ -17,8 +17,9 @@
17
17
  * TierMigrationCoordinator accessor pattern.
18
18
  */
19
19
 
20
- import type { PluginConfig, RecallSectionConfig } from "../types.js";
21
20
  import type { LastRecallBudgetSummary } from "../recall-state.js";
21
+ import { estimateTokenCount } from "../token-estimate.js";
22
+ import type { PluginConfig, RecallSectionConfig } from "../types.js";
22
23
 
23
24
  export interface RecallSectionAppendOptions {
24
25
  atomic?: boolean;
@@ -179,18 +180,54 @@ export class RecallSectionCoordinator {
179
180
  const end = boundary > 0 ? boundary : contentLimit;
180
181
  return `${content.slice(0, end).trimEnd()}${suffix}`;
181
182
  }
182
-
183
183
  truncateRecallSectionToBudget(
184
184
  content: string,
185
185
  maxChars: number,
186
+ maxTokens?: number,
186
187
  ): string {
187
- if (maxChars <= 0) return "";
188
- if (content.length <= maxChars) return content;
188
+ if (maxChars <= 0 || maxTokens === 0) return "";
189
189
  const suffix = "\n\n...(memory context trimmed)";
190
- if (maxChars <= suffix.length) {
191
- return content.slice(0, maxChars);
190
+ const charBounded =
191
+ content.length <= maxChars
192
+ ? content
193
+ : maxChars <= suffix.length
194
+ ? content.slice(0, maxChars)
195
+ : `${content.slice(0, maxChars - suffix.length)}${suffix}`;
196
+ if (maxTokens === undefined || estimateTokenCount(charBounded) <= maxTokens) {
197
+ return charBounded;
192
198
  }
193
- return `${content.slice(0, maxChars - suffix.length)}${suffix}`;
199
+ const markerFits =
200
+ maxChars > suffix.length && estimateTokenCount(suffix) <= maxTokens;
201
+ const tokenSource = content.length > maxChars ? content.slice(0, maxChars) : content;
202
+ const codePoints = [...tokenSource];
203
+ let low = 0;
204
+ let high = codePoints.length;
205
+ while (low < high) {
206
+ const mid = Math.ceil((low + high) / 2);
207
+ const prefix = codePoints.slice(0, mid).join("");
208
+ const candidate = markerFits ? `${prefix}${suffix}` : prefix;
209
+ if (candidate.length <= maxChars && estimateTokenCount(candidate) <= maxTokens) {
210
+ low = mid;
211
+ } else {
212
+ high = mid - 1;
213
+ }
214
+ }
215
+ if (markerFits && low === 0) {
216
+ low = 0;
217
+ high = codePoints.length;
218
+ while (low < high) {
219
+ const mid = Math.ceil((low + high) / 2);
220
+ const prefix = codePoints.slice(0, mid).join("");
221
+ if (prefix.length <= maxChars && estimateTokenCount(prefix) <= maxTokens) {
222
+ low = mid;
223
+ } else {
224
+ high = mid - 1;
225
+ }
226
+ }
227
+ return codePoints.slice(0, low).join("");
228
+ }
229
+ const prefix = codePoints.slice(0, low).join("");
230
+ return markerFits ? `${prefix}${suffix}` : prefix;
194
231
  }
195
232
 
196
233
 
@@ -280,6 +317,7 @@ export class RecallSectionCoordinator {
280
317
  }
281
318
 
282
319
  const budget = this.getRecallBudgetChars(budgetOverride);
320
+ const tokenBudget = Math.max(0, Math.floor(this.getConfig().maxMemoryTokens));
283
321
  const candidateMemoryChunks =
284
322
  orderedSections
285
323
  .find((section) => section.id === "memories")
@@ -312,10 +350,19 @@ export class RecallSectionCoordinator {
312
350
  const memoryIndex = allocationOrder.indexOf("memories");
313
351
  const memoryBudget = this.getRecallSectionMaxChars("memories") ?? budget;
314
352
  const memoryAllocationBudget = Math.min(budget, memoryBudget);
315
- let firstAtomicMemoryReserveChars = 0;
353
+ let firstAtomicMemoryReserve:
354
+ | { chars: number; tokens: number }
355
+ | undefined;
316
356
  for (const chunk of memorySection?.chunks ?? []) {
317
- if (chunk.atomic && chunk.content.length <= memoryAllocationBudget) {
318
- firstAtomicMemoryReserveChars = chunk.content.length;
357
+ if (!chunk.atomic || chunk.content.length > memoryAllocationBudget) {
358
+ continue;
359
+ }
360
+ const tokens = estimateTokenCount(chunk.content);
361
+ if (tokens <= tokenBudget) {
362
+ firstAtomicMemoryReserve = {
363
+ chars: chunk.content.length,
364
+ tokens,
365
+ };
319
366
  break;
320
367
  }
321
368
  }
@@ -323,6 +370,7 @@ export class RecallSectionCoordinator {
323
370
  const includedMemoryPaths: string[] = [];
324
371
  const includedMemoryNamespaces: Array<string | undefined> = [];
325
372
  let usedChars = 0;
373
+ let usedTokens = 0;
326
374
  let truncated = false;
327
375
  const selected = new Map<string, string>();
328
376
 
@@ -331,19 +379,30 @@ export class RecallSectionCoordinator {
331
379
  if (!section || selected.has(id)) continue;
332
380
  const separatorChars = selected.size > 0 ? separator.length : 0;
333
381
  const available = budget - usedChars - separatorChars;
382
+ const separatorTokens = selected.size > 0 ? estimateTokenCount(separator) : 0;
383
+ const availableTokens = tokenBudget - usedTokens - separatorTokens;
334
384
  const sectionMaxChars = this.getRecallSectionMaxChars(id);
335
- const reservesFirstMemory =
336
- memoryIndex > allocationOrder.indexOf(id) &&
337
- firstAtomicMemoryReserveChars > 0;
338
- const memoryReserve = reservesFirstMemory
339
- ? firstAtomicMemoryReserveChars + separator.length
385
+ const reservedMemory =
386
+ memoryIndex > allocationOrder.indexOf(id)
387
+ ? firstAtomicMemoryReserve
388
+ : undefined;
389
+ const memoryReserveSeparatorChars = separator.length;
390
+ const memoryReserveSeparatorTokens = estimateTokenCount(separator);
391
+ const memoryReserve = reservedMemory
392
+ ? reservedMemory.chars + memoryReserveSeparatorChars
340
393
  : 0;
341
394
  const availableAfterMemoryReserve = available - memoryReserve;
342
395
  const allocatedSectionAvailable =
343
396
  typeof sectionMaxChars === "number"
344
397
  ? Math.min(availableAfterMemoryReserve, sectionMaxChars)
345
398
  : availableAfterMemoryReserve;
346
- if (allocatedSectionAvailable <= 0) {
399
+ const availableAfterMemoryReserveTokens = reservedMemory
400
+ ? availableTokens -
401
+ reservedMemory.tokens -
402
+ memoryReserveSeparatorTokens
403
+ : availableTokens;
404
+ const allocatedTokenAvailable = availableAfterMemoryReserveTokens;
405
+ if (allocatedSectionAvailable <= 0 || allocatedTokenAvailable <= 0) {
347
406
  truncated = true;
348
407
  continue;
349
408
  }
@@ -372,13 +431,11 @@ export class RecallSectionCoordinator {
372
431
  Math.min(profileLimit, allocatedSectionAvailable),
373
432
  )
374
433
  : content;
375
- finalContent =
376
- id === "profile"
377
- ? boundedContent
378
- : this.truncateRecallSectionToBudget(
379
- boundedContent,
380
- allocatedSectionAvailable,
381
- );
434
+ finalContent = this.truncateRecallSectionToBudget(
435
+ boundedContent,
436
+ allocatedSectionAvailable,
437
+ allocatedTokenAvailable,
438
+ );
382
439
  if (!finalContent) {
383
440
  truncated = true;
384
441
  continue;
@@ -400,7 +457,10 @@ export class RecallSectionCoordinator {
400
457
  const candidate = rendered
401
458
  ? `${rendered}\n\n${chunk.content}`
402
459
  : chunk.content;
403
- if (candidate.length <= allocatedSectionAvailable) {
460
+ if (
461
+ candidate.length <= allocatedSectionAvailable &&
462
+ estimateTokenCount(candidate) <= allocatedTokenAvailable
463
+ ) {
404
464
  rendered = candidate;
405
465
  includedLeadingContent = true;
406
466
  } else {
@@ -412,12 +472,16 @@ export class RecallSectionCoordinator {
412
472
  const candidate = rendered
413
473
  ? `${rendered}\n\n${chunk.content}`
414
474
  : chunk.content;
415
- if (candidate.length > allocatedSectionAvailable) {
475
+ if (
476
+ candidate.length > allocatedSectionAvailable ||
477
+ estimateTokenCount(candidate) > allocatedTokenAvailable
478
+ ) {
416
479
  if (
417
480
  chunk.atomic &&
418
481
  includedAtomicCount === 0 &&
419
482
  includedLeadingContent &&
420
- chunk.content.length <= allocatedSectionAvailable
483
+ chunk.content.length <= allocatedSectionAvailable &&
484
+ estimateTokenCount(chunk.content) <= allocatedTokenAvailable
421
485
  ) {
422
486
  rendered = chunk.content;
423
487
  includedLeadingContent = false;
@@ -435,7 +499,8 @@ export class RecallSectionCoordinator {
435
499
  !chunk.atomic &&
436
500
  includedAtomicCount === 0 &&
437
501
  includedLeadingContent &&
438
- chunk.content.length <= allocatedSectionAvailable
502
+ chunk.content.length <= allocatedSectionAvailable &&
503
+ estimateTokenCount(chunk.content) <= allocatedTokenAvailable
439
504
  ) {
440
505
  rendered = chunk.content;
441
506
  includedLeadingContent = false;
@@ -479,6 +544,7 @@ export class RecallSectionCoordinator {
479
544
  }
480
545
  selected.set(id, finalContent);
481
546
  usedChars += separatorChars + finalContent.length;
547
+ usedTokens += separatorTokens + estimateTokenCount(finalContent);
482
548
  }
483
549
 
484
550
  const sections: string[] = [];
@@ -0,0 +1,51 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ import { parseConfig } from "./config.js";
5
+ import { RecallSectionCoordinator } from "./orchestration/recall-section-coordinator.js";
6
+ import { estimateTokenCount } from "./token-estimate.js";
7
+
8
+ test("recall derived budget keeps Japanese injection within maxMemoryTokens", () => {
9
+ const config = parseConfig({
10
+ maxMemoryTokens: 12,
11
+ recallPipeline: [{ id: "memories", enabled: true }],
12
+ });
13
+ const coordinator = new RecallSectionCoordinator({ getConfig: () => config });
14
+ const buckets = new Map<string, string[]>();
15
+
16
+ coordinator.appendRecallSection(buckets, "memories", "日本語の記憶。".repeat(20));
17
+ const assembled = coordinator.assembleRecallSections(buckets);
18
+ const injected = assembled.sections.join("\n\n---\n\n");
19
+
20
+ assert.equal(config.recallBudgetChars, config.maxMemoryTokens * 4);
21
+ assert.ok(estimateTokenCount(injected) <= config.maxMemoryTokens);
22
+ });
23
+ test("recall reserves one memory chunk that fits both character and token budgets", () => {
24
+ const config = parseConfig({
25
+ maxMemoryTokens: 50,
26
+ recallBudgetChars: 150,
27
+ recallPipeline: [
28
+ { id: "profile", enabled: true },
29
+ { id: "memories", enabled: true },
30
+ ],
31
+ });
32
+ const coordinator = new RecallSectionCoordinator({ getConfig: () => config });
33
+ const buckets = new Map<string, string[]>();
34
+
35
+ coordinator.appendRecallSection(buckets, "profile", "x".repeat(90));
36
+ coordinator.appendRecallSection(buckets, "memories", "日".repeat(51), {
37
+ atomic: true,
38
+ memoryId: "wide",
39
+ memoryPath: "memories/wide.md",
40
+ });
41
+ coordinator.appendRecallSection(buckets, "memories", "a".repeat(100), {
42
+ atomic: true,
43
+ memoryId: "latin",
44
+ memoryPath: "memories/latin.md",
45
+ });
46
+
47
+ const assembled = coordinator.assembleRecallSections(buckets);
48
+
49
+ assert.deepEqual(assembled.includedMemoryIds, ["latin"]);
50
+ assert.ok(estimateTokenCount(assembled.sections.join("\n\n---\n\n")) <= 50);
51
+ });
@@ -19,24 +19,17 @@
19
19
 
20
20
  import { randomUUID } from "node:crypto";
21
21
 
22
- import {
23
- normalizeRetrievedMemoryProvenance,
24
- type RetrievedMemoryProvenance,
25
- } from "./memory-provenance.js";
22
+ import { normalizeRetrievedMemoryProvenance, type RetrievedMemoryProvenance } from "./memory-provenance.js";
23
+ import { estimateTokenCount } from "./token-estimate.js";
26
24
  import type { RecallDisclosure, RecallTierExplain } from "./types.js";
27
25
  import { isRecallDisclosure } from "./types.js";
28
26
 
29
27
  /**
30
- * Estimate token cost of a payload at the rough ~4 chars/token English
31
- * heuristic. Non-negative integer; returns 0 for empty / null input.
32
- * Used by recall surfaces to attach `estimatedTokens` to X-ray results
33
- * (issue #677 PR 3/4). Identical to the private heuristic in
34
- * `chunking.ts`; kept self-contained here so X-ray callers don't pull
35
- * in chunking internals.
28
+ * Estimate token cost of a payload for X-ray disclosure accounting.
36
29
  */
37
30
  export function estimateRecallTokens(text: string | null | undefined): number {
38
31
  if (typeof text !== "string" || text.length === 0) return 0;
39
- return Math.ceil(text.length / 4);
32
+ return estimateTokenCount(text);
40
33
  }
41
34
 
42
35
  /**
@@ -13,6 +13,7 @@ import {
13
13
  type Chunk,
14
14
  type ChunkResult,
15
15
  } from "./chunking.js";
16
+ import { estimateTokenCount } from "./token-estimate.js";
16
17
 
17
18
  // ---------------------------------------------------------------------------
18
19
  // Configuration
@@ -184,14 +185,6 @@ export function findLocalMinima(
184
185
 
185
186
  // ---------------------------------------------------------------------------
186
187
 
187
- // ---------------------------------------------------------------------------
188
- // Token estimation
189
- // ---------------------------------------------------------------------------
190
-
191
- /** Rough token estimate: ~4 chars per token for English. */
192
- function estimateTokens(text: string): number {
193
- return Math.ceil(text.length / 4);
194
- }
195
188
 
196
189
  // ---------------------------------------------------------------------------
197
190
  // Core semantic chunking
@@ -278,7 +271,7 @@ function mergeShortSegments(
278
271
 
279
272
  for (let i = 0; i < segments.length; i++) {
280
273
  buffer = [...buffer, ...segments[i]];
281
- const tokenCount = estimateTokens(joinSentences(buffer));
274
+ const tokenCount = estimateTokenCount(joinSentences(buffer));
282
275
 
283
276
  if (tokenCount >= minTokens || i === segments.length - 1) {
284
277
  merged.push(buffer);
@@ -358,7 +351,7 @@ export async function semanticChunkContent(
358
351
  const sentences = splitSentences(content);
359
352
 
360
353
  if (sentences.length <= 1) {
361
- const tokenCount = estimateTokens(content);
354
+ const tokenCount = estimateTokenCount(content);
362
355
  return {
363
356
  chunked: false,
364
357
  chunks: [
@@ -375,7 +368,7 @@ export async function semanticChunkContent(
375
368
  }
376
369
 
377
370
  // If total tokens is short enough, return as single chunk
378
- const totalTokens = estimateTokens(content);
371
+ const totalTokens = estimateTokenCount(content);
379
372
  if (totalTokens <= cfg.minTokens) {
380
373
  return {
381
374
  chunked: false,
@@ -474,7 +467,7 @@ export async function semanticChunkContent(
474
467
  for (let segIdx = 0; segIdx < segments.length; segIdx++) {
475
468
  const segment = segments[segIdx];
476
469
  const segText = joinSentences(segment);
477
- const segTokens = estimateTokens(segText);
470
+ const segTokens = estimateTokenCount(segText);
478
471
 
479
472
  if (segTokens > cfg.maxTokens) {
480
473
  // Recursive split for oversized segment
@@ -14,7 +14,7 @@ interface SessionObserverCursor {
14
14
  }
15
15
 
16
16
  interface SessionObserverPersistedState {
17
- version: 1;
17
+ version: 2;
18
18
  sessions: Record<string, SessionObserverCursor>;
19
19
  }
20
20
 
@@ -134,7 +134,7 @@ export class SessionObserverState {
134
134
  try {
135
135
  const raw = await readFile(this.statePath, "utf-8");
136
136
  const parsed = JSON.parse(raw) as SessionObserverPersistedState;
137
- if (parsed?.version !== 1 || !parsed.sessions || typeof parsed.sessions !== "object") {
137
+ if (parsed?.version !== 2 || !parsed.sessions || typeof parsed.sessions !== "object") {
138
138
  return null;
139
139
  }
140
140
  return parsed;
@@ -246,7 +246,7 @@ export class SessionObserverState {
246
246
  for (const [key, value] of sessionsMap.entries()) {
247
247
  sessions[key] = value;
248
248
  }
249
- const payload: SessionObserverPersistedState = { version: 1, sessions };
249
+ const payload: SessionObserverPersistedState = { version: 2, sessions };
250
250
  await mkdir(path.dirname(this.statePath), { recursive: true });
251
251
  await writeFile(this.statePath, JSON.stringify(payload, null, 2), "utf-8");
252
252
  }
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * The nine rows are realized honestly against the coordinator's REAL behavior —
11
11
  * no mocks. Config is built through the production `parseConfig` path so the
12
- * budget derivation (recallBudgetChars = maxMemoryTokens * 4), section
12
+ * budget derivation (recallBudgetChars = maxMemoryTokens), section
13
13
  * enablement filtering, per-section maxChars caps, and cap-after-filter
14
14
  * ordering are all exercised as they ship. Each row asserts one recall-budget
15
15
  * contract invariant:
@@ -28,6 +28,7 @@ import assert from "node:assert/strict";
28
28
 
29
29
  import { parseConfig } from "../../config.js";
30
30
  import { RecallSectionCoordinator } from "../../orchestration/recall-section-coordinator.js";
31
+ import { estimateTokenCount } from "../../token-estimate.js";
31
32
  import { createRecallSectionMetricRecorder, formatRecallSectionMetric } from "../../recall-qos.js";
32
33
  import { reorderRecallResultsWithMmr } from "../../recall-mmr.js";
33
34
  import { applyRuntimeRetrievalPolicy, expandQuery } from "../../retrieval.js";
@@ -297,10 +298,10 @@ const subject: LifecycleSubject<RecallBudgetState> = {
297
298
  return;
298
299
  }
299
300
  case "sparse-metadata-with-binding": {
300
- // Budget is derived from maxMemoryTokens (recallBudgetChars = tokens*4).
301
+ // Budget keeps Latin-script headroom and token-aware assembly caps wide scripts.
301
302
  assert.equal(config.recallBudgetChars, config.maxMemoryTokens * 4, "budget derives from maxMemoryTokens");
302
- assert.equal(budget, config.maxMemoryTokens * 4, "coordinator honors the token-derived budget");
303
- assert.ok(assembled.finalChars <= budget, "section sum stays within the token-derived budget");
303
+ assert.ok(budget <= config.maxMemoryTokens * 4, "coordinator honors the character budget");
304
+ assert.ok(assembled.finalChars <= budget, "section sum stays within the character budget");
304
305
  assert.ok(assembled.truncated, "oversized content forces truncation");
305
306
  return;
306
307
  }
@@ -372,7 +373,22 @@ const subject: LifecycleSubject<RecallBudgetState> = {
372
373
  // truncateRecallSectionToBudget respects a hard per-section budget too.
373
374
  const truncated = coordinator.truncateRecallSectionToBudget(body("m", 200), 50);
374
375
  assert.equal(truncated.length, 50, "budget-aware truncation lands exactly on the per-section limit");
375
- // A budget-skipped section reports as a debug-level "skip" metric — the
376
+ const tokenTrimmed = coordinator.truncateRecallSectionToBudget("x".repeat(200), 200, 20);
377
+ assert.match(tokenTrimmed, /\.\.\.\(memory context trimmed\)$/);
378
+ assert.ok(estimateTokenCount(tokenTrimmed) <= 20, "token-aware truncation keeps its marker inside the cap");
379
+ const markerBudget = estimateTokenCount("\n\n...(memory context trimmed)");
380
+ const markerOnlyBudget = coordinator.truncateRecallSectionToBudget("日本語".repeat(100), 200, markerBudget);
381
+ assert.ok(markerOnlyBudget.length > 0, "a marker-only budget keeps useful content");
382
+ assert.doesNotMatch(markerOnlyBudget, /\.\.\.\(memory context trimmed\)$/);
383
+ assert.ok(estimateTokenCount(markerOnlyBudget) <= markerBudget);
384
+ const wideScriptTrimmed = coordinator.truncateRecallSectionToBudget("日".repeat(100), 30, markerBudget);
385
+ assert.equal([...wideScriptTrimmed].length, 8, "wide-script fallback uses the available character room");
386
+ assert.ok(estimateTokenCount(wideScriptTrimmed) <= markerBudget);
387
+ assert.doesNotMatch(wideScriptTrimmed, /\.\.\.\(memory context trimmed\)$/);
388
+ const emojiTrimmed = coordinator.truncateRecallSectionToBudget("😀".repeat(30), 60, 29);
389
+ assert.ok(emojiTrimmed.length <= 60, "astral text stays within the UTF-16 character cap");
390
+ assert.ok(estimateTokenCount(emojiTrimmed) <= 29, "astral text stays within the token cap");
391
+ assert.match(emojiTrimmed, /\.\.\.\(memory context trimmed\)$/);
376
392
  // QoS accounting that flags a section dropped for the budget deadline.
377
393
  const skipMetric = formatRecallSectionMetric({
378
394
  section: "memories",
@@ -0,0 +1,38 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ import { estimateTokenCount } from "./token-estimate.js";
5
+
6
+ test("estimates English text at about four code points per token", () => {
7
+ assert.equal(estimateTokenCount("abcdefghijklmnop"), 4);
8
+ });
9
+
10
+ test("estimates Japanese text at about one token per code point", () => {
11
+ assert.equal(estimateTokenCount("日本語の文章です"), 8);
12
+ });
13
+
14
+ test("combines script-aware counts for mixed text", () => {
15
+ assert.equal(estimateTokenCount("abcd世界"), 3);
16
+ });
17
+
18
+ test("normalizes composed characters before counting code points", () => {
19
+ assert.equal(estimateTokenCount("e\u0301e\u0301e\u0301e\u0301"), 1);
20
+ });
21
+
22
+ test("counts Thai combining marks in wide-script text", () => {
23
+ assert.equal(estimateTokenCount("ที่"), 3);
24
+ });
25
+
26
+ test("counts token-dense Indic code points and emoji", () => {
27
+ assert.equal(estimateTokenCount("नमस्ते"), 6);
28
+ assert.equal(estimateTokenCount("😀😀😀😀"), 4);
29
+ });
30
+
31
+ test("counts unlisted letters and regional indicators conservatively", () => {
32
+ assert.equal(estimateTokenCount("ქართული"), 7);
33
+ assert.equal(estimateTokenCount("🇺🇸🇬🇧"), 4);
34
+ });
35
+
36
+ test("counts non-ASCII punctuation with token-dense text", () => {
37
+ assert.equal(estimateTokenCount("日。日。日。日。"), 8);
38
+ });
@@ -0,0 +1,22 @@
1
+ const NARROW_LETTER = /[\p{Script=Latin}\p{Script=Greek}\p{Script=Cyrillic}]/u;
2
+
3
+ /**
4
+ * Estimate model tokens without a tokenizer.
5
+ *
6
+ * Wide-script code points approximate one token each. Latin, Greek, Cyrillic,
7
+ * punctuation, and symbols use the established four-code-point heuristic.
8
+ * Unknown letters count conservatively as wide-script code points.
9
+ */
10
+ export function estimateTokenCount(text: string): number {
11
+ let wideTokens = 0;
12
+ let narrowCodePoints = 0;
13
+ for (const char of text.normalize("NFC")) {
14
+ const codePoint = char.codePointAt(0) ?? 0;
15
+ if (codePoint <= 0x7f || NARROW_LETTER.test(char)) {
16
+ narrowCodePoints++;
17
+ } else {
18
+ wideTokens++;
19
+ }
20
+ }
21
+ return wideTokens + Math.ceil(narrowCodePoints / 4);
22
+ }
@@ -1,8 +1,9 @@
1
- import test from "node:test";
2
1
  import assert from "node:assert/strict";
2
+ import { mkdtemp } from "node:fs/promises";
3
3
  import os from "node:os";
4
4
  import path from "node:path";
5
- import { mkdtemp } from "node:fs/promises";
5
+ import test from "node:test";
6
+ import { estimateTokenCount } from "./token-estimate.js";
6
7
  import { TranscriptManager } from "./transcript.js";
7
8
  import type { PluginConfig, TranscriptEntry } from "./types.js";
8
9
 
@@ -24,6 +25,40 @@ function entryAt(timestamp: string, sessionKey: string, turnId: string): Transcr
24
25
  return { timestamp, role: "user", content: `turn ${turnId}`, sessionKey, turnId };
25
26
  }
26
27
 
28
+ test("formatForRecall counts transcript separators inside its token budget", () => {
29
+ const manager = new TranscriptManager(makeConfig("/tmp/remnic-transcript-format-test"));
30
+ const entries = ["one", "two", "three"].map((turnId) =>
31
+ entryAt("2026-06-29T12:00:00.000Z", "agent:test-agent:main", turnId)
32
+ );
33
+
34
+ const formatted = manager.formatForRecall(entries, 23);
35
+
36
+ assert.ok(estimateTokenCount(formatted) <= 23);
37
+ });
38
+ test("formatForRecall returns no content for zero or undersized budgets", () => {
39
+ const manager = new TranscriptManager(makeConfig("/tmp/remnic-transcript-small-budget"));
40
+ const entries = [
41
+ {
42
+ ...entryAt("2026-06-29T12:00:00.000Z", "agent:test-agent:main", "oversized"),
43
+ content: "日本語".repeat(100),
44
+ },
45
+ ];
46
+
47
+ assert.equal(manager.formatForRecall(entries, 0), "");
48
+ assert.equal(manager.formatForRecall(entries, 10), "");
49
+ });
50
+ test("formatForRecall does not fall back to stale older entries", () => {
51
+ const manager = new TranscriptManager(makeConfig("/tmp/remnic-transcript-newest-budget"));
52
+ const entries = [
53
+ entryAt("2026-06-29T12:00:00.000Z", "agent:test-agent:main", "older"),
54
+ {
55
+ ...entryAt("2026-06-29T12:00:00.000Z", "agent:test-agent:main", "newest"),
56
+ content: "日本語".repeat(100),
57
+ },
58
+ ];
59
+
60
+ assert.equal(manager.formatForRecall(entries, 23), "");
61
+ });
27
62
  /**
28
63
  * Freeze `new Date()` / `Date.now()` to a fixed instant for the duration of `fn`.
29
64
  *
@@ -50,7 +85,7 @@ async function withFrozenNow<T>(now: Date, fn: () => Promise<T>): Promise<T> {
50
85
  args[3] as number,
51
86
  args[4] as number,
52
87
  args[5] as number,
53
- args[6] as number,
88
+ args[6] as number
54
89
  );
55
90
  }
56
91
  }