@remnic/core 10.0.5 → 10.0.7

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 (373) hide show
  1. package/dist/access-admin-ops-surface.js +57 -56
  2. package/dist/access-authorization-probe.js +58 -57
  3. package/dist/access-boundary.js +57 -56
  4. package/dist/access-cli.js +108 -107
  5. package/dist/access-cli.js.map +1 -1
  6. package/dist/access-extraction-force-flush.js +57 -56
  7. package/dist/access-http-briefing.js +58 -57
  8. package/dist/access-http-query.js +59 -58
  9. package/dist/access-http.js +77 -76
  10. package/dist/access-idempotency.d.ts.map +1 -1
  11. package/dist/access-idempotency.js +2 -1
  12. package/dist/access-identity-continuity-surface.js +57 -56
  13. package/dist/access-lcm-surface.js +57 -56
  14. package/dist/access-mcp.js +69 -68
  15. package/dist/access-namespace-preflight.js +57 -56
  16. package/dist/access-observe-write-category.js +12 -11
  17. package/dist/access-observe-write-surface.js +57 -56
  18. package/dist/access-offline-manifest.js +11 -10
  19. package/dist/access-operations-batch.js +61 -60
  20. package/dist/access-operations.js +68 -67
  21. package/dist/access-recall-concurrency.js +57 -56
  22. package/dist/access-recall-response.js +57 -56
  23. package/dist/access-recall-surface.js +57 -56
  24. package/dist/access-schema.js +7 -6
  25. package/dist/access-service.js +57 -56
  26. package/dist/access-surface-catalog.js +59 -58
  27. package/dist/access-surface-catalog.js.map +1 -1
  28. package/dist/active-recall.js +23 -22
  29. package/dist/active-recall.js.map +1 -1
  30. package/dist/{auto-sync-FN7E3OTO.js → auto-sync-WSJAOLOP.js} +8 -7
  31. package/dist/{auto-sync-FN7E3OTO.js.map → auto-sync-WSJAOLOP.js.map} +1 -1
  32. package/dist/briefing.js +16 -15
  33. package/dist/buffer.js +11 -10
  34. package/dist/calibration.d.ts +31 -3
  35. package/dist/calibration.d.ts.map +1 -1
  36. package/dist/calibration.js +67 -16
  37. package/dist/calibration.js.map +1 -1
  38. package/dist/{capsule-merge-42GJGDUC.js → capsule-merge-M4HETD27.js} +5 -4
  39. package/dist/{capsule-merge-42GJGDUC.js.map → capsule-merge-M4HETD27.js.map} +1 -1
  40. package/dist/causal-behavior.js +2 -2
  41. package/dist/causal-chain.js +2 -2
  42. package/dist/causal-consolidation.js +19 -18
  43. package/dist/causal-consolidation.js.map +1 -1
  44. package/dist/causal-retrieval.js +2 -2
  45. package/dist/causal-trajectory-graph.js +4 -3
  46. package/dist/causal-trajectory-graph.js.map +1 -1
  47. package/dist/causal-trajectory.js +1 -1
  48. package/dist/{chunk-OZABSIOV.js → chunk-2AFHZTPI.js} +2 -2
  49. package/dist/{chunk-UK5EH7AI.js → chunk-2CXQZXWM.js} +3 -3
  50. package/dist/{chunk-RIEGCK2W.js → chunk-2KRNPFPK.js} +2 -2
  51. package/dist/{chunk-N7QV3CMX.js → chunk-2NCBDGND.js} +2 -2
  52. package/dist/{chunk-FLV7M7CT.js → chunk-2PBZBNY7.js} +2 -2
  53. package/dist/{chunk-KSUOM3YU.js → chunk-2SKI5ZSH.js} +11 -11
  54. package/dist/{chunk-SUAX5JWY.js → chunk-3DSRYRGR.js} +2 -2
  55. package/dist/{chunk-JA72X46J.js → chunk-3GLQUOL2.js} +2 -2
  56. package/dist/{chunk-CLCMDKTB.js → chunk-3I3U6FFT.js} +2 -2
  57. package/dist/{chunk-BNMI3JBV.js → chunk-4EHA327M.js} +3 -3
  58. package/dist/{chunk-QWUJWBZ5.js → chunk-4G4B3Z2B.js} +2 -2
  59. package/dist/{chunk-R7QY5ZVB.js → chunk-4NDWE44P.js} +2 -2
  60. package/dist/{chunk-U6HWKOGD.js → chunk-5GN5LRQW.js} +2 -2
  61. package/dist/{chunk-VFUEZZBS.js → chunk-5JMI26Q7.js} +5 -4
  62. package/dist/chunk-5JMI26Q7.js.map +1 -0
  63. package/dist/{chunk-MQNOIH2C.js → chunk-5O4UJ6PM.js} +3 -3
  64. package/dist/{chunk-HRZZJ4XB.js → chunk-645A37SC.js} +2 -2
  65. package/dist/{chunk-JA54KIYD.js → chunk-65FYHYBE.js} +2 -2
  66. package/dist/{chunk-CHDGJJV6.js → chunk-6VAHJ2F6.js} +2 -2
  67. package/dist/chunk-7LEQREP2.js +9 -0
  68. package/dist/chunk-7LEQREP2.js.map +1 -0
  69. package/dist/{chunk-TZQOCQXB.js → chunk-AL6EHLB5.js} +2 -2
  70. package/dist/{chunk-NBQIFCJE.js → chunk-B2UK6O2O.js} +5 -11
  71. package/dist/chunk-B2UK6O2O.js.map +1 -0
  72. package/dist/{chunk-VZBW6CDG.js → chunk-BOOFTFFE.js} +1 -1
  73. package/dist/{chunk-YJEUHGZZ.js → chunk-BR75HFPC.js} +2 -2
  74. package/dist/{chunk-GF4H3B3R.js → chunk-BSWHZJSP.js} +3 -3
  75. package/dist/{chunk-2U3R3DDH.js → chunk-BTJ6CAIA.js} +2 -2
  76. package/dist/{chunk-SNXBXYUE.js → chunk-CG2E6WT5.js} +3 -3
  77. package/dist/{chunk-GE6HETIF.js → chunk-CRYAYFUE.js} +2 -2
  78. package/dist/{chunk-GEGUBU3D.js → chunk-D6C4JWSN.js} +3 -3
  79. package/dist/{chunk-WRICYGYG.js → chunk-DSVRW5BD.js} +15 -15
  80. package/dist/{chunk-7LYRFI5A.js → chunk-E3OSDZ6M.js} +2 -2
  81. package/dist/{chunk-2COXDQ6C.js → chunk-E6KXJSMA.js} +2 -2
  82. package/dist/{chunk-6KHF6PAB.js → chunk-EBQCVOGC.js} +3 -3
  83. package/dist/{chunk-FFAZ2XFU.js → chunk-EHRE7ZG3.js} +5 -6
  84. package/dist/chunk-EHRE7ZG3.js.map +1 -0
  85. package/dist/{chunk-SZXPKUMN.js → chunk-ETGXRGSR.js} +4 -4
  86. package/dist/{chunk-KQI2PKYP.js → chunk-F2QIPGTG.js} +2 -2
  87. package/dist/{chunk-XVC7JU2N.js → chunk-FQD2KPQH.js} +2 -2
  88. package/dist/{chunk-QMFKW4OU.js → chunk-FRRR4KOW.js} +3 -3
  89. package/dist/{chunk-FRH2UC7Q.js → chunk-GH5R5BIH.js} +2 -2
  90. package/dist/{chunk-JMF5Q4JY.js → chunk-GTSQJTNS.js} +7 -7
  91. package/dist/{chunk-I56MTWE7.js → chunk-HHE57I2Z.js} +2 -2
  92. package/dist/{chunk-MULNBSPP.js → chunk-HT2C4EXO.js} +2 -2
  93. package/dist/{chunk-EMVJU7WC.js → chunk-IE2J3V5N.js} +2 -2
  94. package/dist/{chunk-L34W4W4I.js → chunk-IJU2ZWPE.js} +2 -2
  95. package/dist/{chunk-U6OXJQEH.js → chunk-J5QL66XK.js} +2 -2
  96. package/dist/{chunk-AJ6ORARY.js → chunk-JALYQUYO.js} +2 -2
  97. package/dist/chunk-JALYQUYO.js.map +1 -0
  98. package/dist/{chunk-FC6RCOIU.js → chunk-JFGX2DKT.js} +2 -2
  99. package/dist/{chunk-ANZXWOYD.js → chunk-JH4XB3RX.js} +2 -2
  100. package/dist/{chunk-N4PYB235.js → chunk-KI6UOSNR.js} +2 -2
  101. package/dist/{chunk-4K2H4KTR.js → chunk-KMAHEIOH.js} +3 -3
  102. package/dist/{chunk-EQUD7FP4.js → chunk-KYY4EACB.js} +2 -2
  103. package/dist/{chunk-46WM6JX2.js → chunk-LZKOVXMX.js} +2 -2
  104. package/dist/{chunk-I25RQA65.js → chunk-M4MAVJJX.js} +2 -2
  105. package/dist/{chunk-V32NHP2R.js → chunk-M6PEFWJ4.js} +2 -2
  106. package/dist/{chunk-XPRAOTJY.js → chunk-MHGHEBTR.js} +2 -2
  107. package/dist/{chunk-VC4J4UTI.js → chunk-NJTW2MUV.js} +2 -2
  108. package/dist/{chunk-4CWUZBPF.js → chunk-OCIJYYCA.js} +7 -7
  109. package/dist/{chunk-5CQO6LVM.js → chunk-ODGXQUPR.js} +2 -2
  110. package/dist/{chunk-5AYUHSAU.js → chunk-OFCHT2TN.js} +2 -2
  111. package/dist/{chunk-5BY3IA2U.js → chunk-OH75RBYF.js} +5 -5
  112. package/dist/{chunk-37HCPM56.js → chunk-OX5LMCEQ.js} +10 -10
  113. package/dist/{chunk-SWRN6U7Q.js → chunk-PBYY4WYM.js} +2 -2
  114. package/dist/{chunk-QRZMJ2WN.js → chunk-PO6MNTWH.js} +2 -2
  115. package/dist/{chunk-2CP577K6.js → chunk-PPIASWWR.js} +2 -2
  116. package/dist/{chunk-OGVJXIHX.js → chunk-PXTZOU5F.js} +2 -2
  117. package/dist/{chunk-IJ4FEGZR.js → chunk-Q67D4JYB.js} +2 -2
  118. package/dist/{chunk-GVUW5XK5.js → chunk-QF7XX74D.js} +39 -39
  119. package/dist/chunk-QF7XX74D.js.map +1 -0
  120. package/dist/{chunk-I25RINZK.js → chunk-QHL33ZDS.js} +2 -2
  121. package/dist/{chunk-MFZACYZ6.js → chunk-QUNDYIYZ.js} +3 -3
  122. package/dist/{chunk-TGF43K66.js → chunk-QWDH4QNA.js} +4 -4
  123. package/dist/{chunk-W5XWHTDO.js → chunk-QZZPUREO.js} +3 -3
  124. package/dist/{chunk-M47Q6566.js → chunk-RVJPY6E4.js} +2 -2
  125. package/dist/{chunk-KE5PWLI6.js → chunk-T5XG6GQI.js} +3 -3
  126. package/dist/{chunk-EP5WXE2G.js → chunk-TCYLCPC6.js} +2 -2
  127. package/dist/{chunk-WWLAKRMX.js → chunk-TPNCVFVI.js} +2 -2
  128. package/dist/{chunk-WG4TMZJ2.js → chunk-TVRTJZQ5.js} +2 -2
  129. package/dist/{chunk-DST7HRSG.js → chunk-UL7WKKGZ.js} +2 -2
  130. package/dist/{chunk-5LNPW7NE.js → chunk-UTXWLTX5.js} +2 -2
  131. package/dist/{chunk-YJAOYEWI.js → chunk-V4ACBX3C.js} +2 -2
  132. package/dist/{chunk-DJMVSUPK.js → chunk-VBNIQ6H2.js} +4 -4
  133. package/dist/{chunk-PO7NXNGC.js → chunk-VFTK5WKI.js} +2 -2
  134. package/dist/{chunk-L2VS27PZ.js → chunk-VIPGYPEG.js} +4 -4
  135. package/dist/{chunk-ENNC3RZ6.js → chunk-VQBGV44L.js} +2 -2
  136. package/dist/{chunk-5BPXMAUP.js → chunk-VUQDJ3JB.js} +4 -4
  137. package/dist/{chunk-7CXL25AA.js → chunk-W4RLOZOG.js} +3 -3
  138. package/dist/{chunk-LHRQBMJN.js → chunk-WADSXS4K.js} +2 -2
  139. package/dist/{chunk-NHSVW7UT.js → chunk-WUUE2I2A.js} +6 -6
  140. package/dist/{chunk-IM2GO42H.js → chunk-WVHRNAXL.js} +4 -4
  141. package/dist/chunk-WVHRNAXL.js.map +1 -0
  142. package/dist/{chunk-TDMNADPI.js → chunk-XKEDESWC.js} +2 -2
  143. package/dist/{chunk-UXIZ5XN5.js → chunk-XLIK2VDE.js} +3 -3
  144. package/dist/{chunk-2UPTRDGM.js → chunk-Y6DZ33PA.js} +4 -4
  145. package/dist/{chunk-HPAOMYKM.js → chunk-Y6IHIORY.js} +50 -50
  146. package/dist/{chunk-63UNVGZW.js → chunk-YBSWXKCH.js} +4 -4
  147. package/dist/{chunk-IFCKHPY4.js → chunk-YDH2FSDI.js} +2 -2
  148. package/dist/{chunk-L3PWXD73.js → chunk-YMVLPVQP.js} +2 -2
  149. package/dist/{chunk-52CQKST6.js → chunk-YNSHGVXT.js} +26 -26
  150. package/dist/{chunk-L6GNS5GB.js → chunk-YS7SA4HD.js} +2 -2
  151. package/dist/{chunk-RSMIRLKM.js → chunk-YV54LYEB.js} +2 -2
  152. package/dist/{chunk-EIFYYHAF.js → chunk-YYO447A7.js} +4 -4
  153. package/dist/{chunk-S5TGRZWY.js → chunk-Z2ZUV6FE.js} +3 -3
  154. package/dist/{chunk-XQSJXNWC.js → chunk-Z4CETAL7.js} +2 -2
  155. package/dist/{chunk-AXC7UTLM.js → chunk-Z5IQTRDN.js} +2 -2
  156. package/dist/{chunk-SIYZDT2V.js → chunk-ZBDTSFRA.js} +2 -2
  157. package/dist/{chunk-75PT4N7Q.js → chunk-ZI7LMSNI.js} +2 -2
  158. package/dist/{chunk-EUT2WCWS.js → chunk-ZQ3WU6JO.js} +2 -2
  159. package/dist/{chunk-JYG2334B.js → chunk-ZSJGYC3C.js} +2 -2
  160. package/dist/cli.js +92 -91
  161. package/dist/coding/export-okf-codegraph.js +16 -15
  162. package/dist/coding/export-okf-codegraph.js.map +1 -1
  163. package/dist/coding/pre-action-gate.js +2 -2
  164. package/dist/compounding/engine.d.ts.map +1 -1
  165. package/dist/compounding/engine.js +17 -16
  166. package/dist/config.js +23 -22
  167. package/dist/connectors/codex-materialize-runner.js +16 -15
  168. package/dist/connectors/index.js +16 -15
  169. package/dist/consolidation-provenance-check.js +5 -4
  170. package/dist/consolidation-undo.js +4 -3
  171. package/dist/consolidation-undo.js.map +1 -1
  172. package/dist/contradiction/index.js +6 -5
  173. package/dist/convergence-refresh.js +18 -17
  174. package/dist/corpus-watermark.js +18 -17
  175. package/dist/deep-recall-http-glue.js +8 -7
  176. package/dist/embedding-fallback.js +4 -3
  177. package/dist/embedding-generation-lock.js +3 -2
  178. package/dist/entity-retrieval.js +16 -15
  179. package/dist/explicit-capture.js +8 -7
  180. package/dist/external-wiki-access.js +58 -57
  181. package/dist/extraction.js +25 -24
  182. package/dist/{forget-SZ2BXDGF.js → forget-OHAJ6PSU.js} +4 -3
  183. package/dist/{forget-SZ2BXDGF.js.map → forget-OHAJ6PSU.js.map} +1 -1
  184. package/dist/{graph-edge-decay-PVKDKLQK.js → graph-edge-decay-CZ3SYLM4.js} +7 -6
  185. package/dist/graph-jsonl.js +5 -4
  186. package/dist/graph-snapshot.js +5 -4
  187. package/dist/graph-write-lock.js +3 -2
  188. package/dist/graph.js +4 -3
  189. package/dist/harmonic-retrieval.js +16 -15
  190. package/dist/http-retry.d.ts.map +1 -1
  191. package/dist/http-retry.js +6 -8
  192. package/dist/http-retry.js.map +1 -1
  193. package/dist/index.js +108 -107
  194. package/dist/location/index.js +19 -18
  195. package/dist/maintenance/memory-governance.js +16 -15
  196. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +16 -15
  197. package/dist/maintenance/rebuild-memory-projection-runner.js +18 -17
  198. package/dist/maintenance/rebuild-memory-projection.js +17 -16
  199. package/dist/memory-browse-operations.js +58 -57
  200. package/dist/memory-browse.js +6 -5
  201. package/dist/memory-subject.js +4 -3
  202. package/dist/namespaces/migrate.js +17 -16
  203. package/dist/namespaces/search.js +5 -4
  204. package/dist/namespaces/storage.js +16 -15
  205. package/dist/offline-sync-changeset-generations.js +5 -4
  206. package/dist/offline-sync-embedding-generation.js +4 -3
  207. package/dist/offline-sync-impression-drain.js +4 -3
  208. package/dist/offline-sync-snapshot-stream.js +7 -6
  209. package/dist/offline-sync.js +6 -5
  210. package/dist/operator-doctor-corpus.js +19 -18
  211. package/dist/operator-toolkit.js +35 -34
  212. package/dist/orchestration/maintenance.js +26 -25
  213. package/dist/orchestrator.js +108 -107
  214. package/dist/page-versioning.js +4 -3
  215. package/dist/procedural/procedure-miner.d.ts.map +1 -1
  216. package/dist/qmd-daemon-session.d.ts.map +1 -1
  217. package/dist/qmd-daemon-session.js +2 -1
  218. package/dist/qmd.d.ts.map +1 -1
  219. package/dist/qmd.js +3 -2
  220. package/dist/recall-navigation-operations.js +58 -57
  221. package/dist/recall-navigation.js +57 -56
  222. package/dist/recall-state-view-admission.js +6 -5
  223. package/dist/recall-state.js +3 -2
  224. package/dist/recall-why-service.js +6 -5
  225. package/dist/reconcile/manifest.js +4 -3
  226. package/dist/{resolution-TV3F7ZTH.js → resolution-E4GLHLY6.js} +7 -6
  227. package/dist/resume-bundles.js +24 -23
  228. package/dist/salvage-envelope.js +6 -5
  229. package/dist/search/factory.js +4 -3
  230. package/dist/search/index.js +4 -3
  231. package/dist/semantic-consolidation.js +17 -16
  232. package/dist/semantic-rule-promotion.js +16 -15
  233. package/dist/semantic-rule-verifier.js +16 -15
  234. package/dist/source-agent-qualifier.js +20 -19
  235. package/dist/standup/build.js +16 -15
  236. package/dist/storage.js +15 -14
  237. package/dist/subject-config.js +5 -4
  238. package/dist/summarizer.js +4 -3
  239. package/dist/summary-snapshot.js +3 -2
  240. package/dist/support-passport/index.js +60 -59
  241. package/dist/testing/orchestrator-lite.d.ts +1 -2
  242. package/dist/testing/orchestrator-lite.d.ts.map +1 -1
  243. package/dist/transfer/capsule-import.js +5 -4
  244. package/dist/transfer/export-okf.js +16 -15
  245. package/dist/utils/serialize-mutations.d.ts.map +1 -1
  246. package/dist/utils/serialize-mutations.js +2 -1
  247. package/dist/utils/sleep.d.ts +3 -0
  248. package/dist/utils/sleep.d.ts.map +1 -0
  249. package/dist/verified-recall.js +16 -15
  250. package/dist/who-knows-cli.js +17 -16
  251. package/dist/who-knows.js +16 -15
  252. package/dist/write-envelope.js +5 -4
  253. package/package.json +2 -2
  254. package/src/access-idempotency.ts +1 -4
  255. package/src/calibration-local-llm.test.ts +361 -0
  256. package/src/calibration.ts +109 -26
  257. package/src/compounding/engine.ts +2 -8
  258. package/src/http-retry.ts +2 -6
  259. package/src/memory-projection-batch.test.ts +55 -0
  260. package/src/offline-sync-digest-cache.test.ts +45 -0
  261. package/src/procedural/procedure-miner.ts +1 -4
  262. package/src/qmd-daemon-session.ts +1 -4
  263. package/src/qmd.ts +0 -4
  264. package/src/testing/orchestrator-lite.ts +2 -7
  265. package/src/utils/serialize-mutations.ts +1 -13
  266. package/src/utils/sleep.test.ts +32 -0
  267. package/src/utils/sleep.ts +5 -0
  268. package/dist/chunk-AJ6ORARY.js.map +0 -1
  269. package/dist/chunk-FFAZ2XFU.js.map +0 -1
  270. package/dist/chunk-GVUW5XK5.js.map +0 -1
  271. package/dist/chunk-IM2GO42H.js.map +0 -1
  272. package/dist/chunk-NBQIFCJE.js.map +0 -1
  273. package/dist/chunk-VFUEZZBS.js.map +0 -1
  274. /package/dist/{chunk-OZABSIOV.js.map → chunk-2AFHZTPI.js.map} +0 -0
  275. /package/dist/{chunk-UK5EH7AI.js.map → chunk-2CXQZXWM.js.map} +0 -0
  276. /package/dist/{chunk-RIEGCK2W.js.map → chunk-2KRNPFPK.js.map} +0 -0
  277. /package/dist/{chunk-N7QV3CMX.js.map → chunk-2NCBDGND.js.map} +0 -0
  278. /package/dist/{chunk-FLV7M7CT.js.map → chunk-2PBZBNY7.js.map} +0 -0
  279. /package/dist/{chunk-KSUOM3YU.js.map → chunk-2SKI5ZSH.js.map} +0 -0
  280. /package/dist/{chunk-SUAX5JWY.js.map → chunk-3DSRYRGR.js.map} +0 -0
  281. /package/dist/{chunk-JA72X46J.js.map → chunk-3GLQUOL2.js.map} +0 -0
  282. /package/dist/{chunk-CLCMDKTB.js.map → chunk-3I3U6FFT.js.map} +0 -0
  283. /package/dist/{chunk-BNMI3JBV.js.map → chunk-4EHA327M.js.map} +0 -0
  284. /package/dist/{chunk-QWUJWBZ5.js.map → chunk-4G4B3Z2B.js.map} +0 -0
  285. /package/dist/{chunk-R7QY5ZVB.js.map → chunk-4NDWE44P.js.map} +0 -0
  286. /package/dist/{chunk-U6HWKOGD.js.map → chunk-5GN5LRQW.js.map} +0 -0
  287. /package/dist/{chunk-MQNOIH2C.js.map → chunk-5O4UJ6PM.js.map} +0 -0
  288. /package/dist/{chunk-HRZZJ4XB.js.map → chunk-645A37SC.js.map} +0 -0
  289. /package/dist/{chunk-JA54KIYD.js.map → chunk-65FYHYBE.js.map} +0 -0
  290. /package/dist/{chunk-CHDGJJV6.js.map → chunk-6VAHJ2F6.js.map} +0 -0
  291. /package/dist/{chunk-TZQOCQXB.js.map → chunk-AL6EHLB5.js.map} +0 -0
  292. /package/dist/{chunk-VZBW6CDG.js.map → chunk-BOOFTFFE.js.map} +0 -0
  293. /package/dist/{chunk-YJEUHGZZ.js.map → chunk-BR75HFPC.js.map} +0 -0
  294. /package/dist/{chunk-GF4H3B3R.js.map → chunk-BSWHZJSP.js.map} +0 -0
  295. /package/dist/{chunk-2U3R3DDH.js.map → chunk-BTJ6CAIA.js.map} +0 -0
  296. /package/dist/{chunk-SNXBXYUE.js.map → chunk-CG2E6WT5.js.map} +0 -0
  297. /package/dist/{chunk-GE6HETIF.js.map → chunk-CRYAYFUE.js.map} +0 -0
  298. /package/dist/{chunk-GEGUBU3D.js.map → chunk-D6C4JWSN.js.map} +0 -0
  299. /package/dist/{chunk-WRICYGYG.js.map → chunk-DSVRW5BD.js.map} +0 -0
  300. /package/dist/{chunk-7LYRFI5A.js.map → chunk-E3OSDZ6M.js.map} +0 -0
  301. /package/dist/{chunk-2COXDQ6C.js.map → chunk-E6KXJSMA.js.map} +0 -0
  302. /package/dist/{chunk-6KHF6PAB.js.map → chunk-EBQCVOGC.js.map} +0 -0
  303. /package/dist/{chunk-SZXPKUMN.js.map → chunk-ETGXRGSR.js.map} +0 -0
  304. /package/dist/{chunk-KQI2PKYP.js.map → chunk-F2QIPGTG.js.map} +0 -0
  305. /package/dist/{chunk-XVC7JU2N.js.map → chunk-FQD2KPQH.js.map} +0 -0
  306. /package/dist/{chunk-QMFKW4OU.js.map → chunk-FRRR4KOW.js.map} +0 -0
  307. /package/dist/{chunk-FRH2UC7Q.js.map → chunk-GH5R5BIH.js.map} +0 -0
  308. /package/dist/{chunk-JMF5Q4JY.js.map → chunk-GTSQJTNS.js.map} +0 -0
  309. /package/dist/{chunk-I56MTWE7.js.map → chunk-HHE57I2Z.js.map} +0 -0
  310. /package/dist/{chunk-MULNBSPP.js.map → chunk-HT2C4EXO.js.map} +0 -0
  311. /package/dist/{chunk-EMVJU7WC.js.map → chunk-IE2J3V5N.js.map} +0 -0
  312. /package/dist/{chunk-L34W4W4I.js.map → chunk-IJU2ZWPE.js.map} +0 -0
  313. /package/dist/{chunk-U6OXJQEH.js.map → chunk-J5QL66XK.js.map} +0 -0
  314. /package/dist/{chunk-FC6RCOIU.js.map → chunk-JFGX2DKT.js.map} +0 -0
  315. /package/dist/{chunk-ANZXWOYD.js.map → chunk-JH4XB3RX.js.map} +0 -0
  316. /package/dist/{chunk-N4PYB235.js.map → chunk-KI6UOSNR.js.map} +0 -0
  317. /package/dist/{chunk-4K2H4KTR.js.map → chunk-KMAHEIOH.js.map} +0 -0
  318. /package/dist/{chunk-EQUD7FP4.js.map → chunk-KYY4EACB.js.map} +0 -0
  319. /package/dist/{chunk-46WM6JX2.js.map → chunk-LZKOVXMX.js.map} +0 -0
  320. /package/dist/{chunk-I25RQA65.js.map → chunk-M4MAVJJX.js.map} +0 -0
  321. /package/dist/{chunk-V32NHP2R.js.map → chunk-M6PEFWJ4.js.map} +0 -0
  322. /package/dist/{chunk-XPRAOTJY.js.map → chunk-MHGHEBTR.js.map} +0 -0
  323. /package/dist/{chunk-VC4J4UTI.js.map → chunk-NJTW2MUV.js.map} +0 -0
  324. /package/dist/{chunk-4CWUZBPF.js.map → chunk-OCIJYYCA.js.map} +0 -0
  325. /package/dist/{chunk-5CQO6LVM.js.map → chunk-ODGXQUPR.js.map} +0 -0
  326. /package/dist/{chunk-5AYUHSAU.js.map → chunk-OFCHT2TN.js.map} +0 -0
  327. /package/dist/{chunk-5BY3IA2U.js.map → chunk-OH75RBYF.js.map} +0 -0
  328. /package/dist/{chunk-37HCPM56.js.map → chunk-OX5LMCEQ.js.map} +0 -0
  329. /package/dist/{chunk-SWRN6U7Q.js.map → chunk-PBYY4WYM.js.map} +0 -0
  330. /package/dist/{chunk-QRZMJ2WN.js.map → chunk-PO6MNTWH.js.map} +0 -0
  331. /package/dist/{chunk-2CP577K6.js.map → chunk-PPIASWWR.js.map} +0 -0
  332. /package/dist/{chunk-OGVJXIHX.js.map → chunk-PXTZOU5F.js.map} +0 -0
  333. /package/dist/{chunk-IJ4FEGZR.js.map → chunk-Q67D4JYB.js.map} +0 -0
  334. /package/dist/{chunk-I25RINZK.js.map → chunk-QHL33ZDS.js.map} +0 -0
  335. /package/dist/{chunk-MFZACYZ6.js.map → chunk-QUNDYIYZ.js.map} +0 -0
  336. /package/dist/{chunk-TGF43K66.js.map → chunk-QWDH4QNA.js.map} +0 -0
  337. /package/dist/{chunk-W5XWHTDO.js.map → chunk-QZZPUREO.js.map} +0 -0
  338. /package/dist/{chunk-M47Q6566.js.map → chunk-RVJPY6E4.js.map} +0 -0
  339. /package/dist/{chunk-KE5PWLI6.js.map → chunk-T5XG6GQI.js.map} +0 -0
  340. /package/dist/{chunk-EP5WXE2G.js.map → chunk-TCYLCPC6.js.map} +0 -0
  341. /package/dist/{chunk-WWLAKRMX.js.map → chunk-TPNCVFVI.js.map} +0 -0
  342. /package/dist/{chunk-WG4TMZJ2.js.map → chunk-TVRTJZQ5.js.map} +0 -0
  343. /package/dist/{chunk-DST7HRSG.js.map → chunk-UL7WKKGZ.js.map} +0 -0
  344. /package/dist/{chunk-5LNPW7NE.js.map → chunk-UTXWLTX5.js.map} +0 -0
  345. /package/dist/{chunk-YJAOYEWI.js.map → chunk-V4ACBX3C.js.map} +0 -0
  346. /package/dist/{chunk-DJMVSUPK.js.map → chunk-VBNIQ6H2.js.map} +0 -0
  347. /package/dist/{chunk-PO7NXNGC.js.map → chunk-VFTK5WKI.js.map} +0 -0
  348. /package/dist/{chunk-L2VS27PZ.js.map → chunk-VIPGYPEG.js.map} +0 -0
  349. /package/dist/{chunk-ENNC3RZ6.js.map → chunk-VQBGV44L.js.map} +0 -0
  350. /package/dist/{chunk-5BPXMAUP.js.map → chunk-VUQDJ3JB.js.map} +0 -0
  351. /package/dist/{chunk-7CXL25AA.js.map → chunk-W4RLOZOG.js.map} +0 -0
  352. /package/dist/{chunk-LHRQBMJN.js.map → chunk-WADSXS4K.js.map} +0 -0
  353. /package/dist/{chunk-NHSVW7UT.js.map → chunk-WUUE2I2A.js.map} +0 -0
  354. /package/dist/{chunk-TDMNADPI.js.map → chunk-XKEDESWC.js.map} +0 -0
  355. /package/dist/{chunk-UXIZ5XN5.js.map → chunk-XLIK2VDE.js.map} +0 -0
  356. /package/dist/{chunk-2UPTRDGM.js.map → chunk-Y6DZ33PA.js.map} +0 -0
  357. /package/dist/{chunk-HPAOMYKM.js.map → chunk-Y6IHIORY.js.map} +0 -0
  358. /package/dist/{chunk-63UNVGZW.js.map → chunk-YBSWXKCH.js.map} +0 -0
  359. /package/dist/{chunk-IFCKHPY4.js.map → chunk-YDH2FSDI.js.map} +0 -0
  360. /package/dist/{chunk-L3PWXD73.js.map → chunk-YMVLPVQP.js.map} +0 -0
  361. /package/dist/{chunk-52CQKST6.js.map → chunk-YNSHGVXT.js.map} +0 -0
  362. /package/dist/{chunk-L6GNS5GB.js.map → chunk-YS7SA4HD.js.map} +0 -0
  363. /package/dist/{chunk-RSMIRLKM.js.map → chunk-YV54LYEB.js.map} +0 -0
  364. /package/dist/{chunk-EIFYYHAF.js.map → chunk-YYO447A7.js.map} +0 -0
  365. /package/dist/{chunk-S5TGRZWY.js.map → chunk-Z2ZUV6FE.js.map} +0 -0
  366. /package/dist/{chunk-XQSJXNWC.js.map → chunk-Z4CETAL7.js.map} +0 -0
  367. /package/dist/{chunk-AXC7UTLM.js.map → chunk-Z5IQTRDN.js.map} +0 -0
  368. /package/dist/{chunk-SIYZDT2V.js.map → chunk-ZBDTSFRA.js.map} +0 -0
  369. /package/dist/{chunk-75PT4N7Q.js.map → chunk-ZI7LMSNI.js.map} +0 -0
  370. /package/dist/{chunk-EUT2WCWS.js.map → chunk-ZQ3WU6JO.js.map} +0 -0
  371. /package/dist/{chunk-JYG2334B.js.map → chunk-ZSJGYC3C.js.map} +0 -0
  372. /package/dist/{graph-edge-decay-PVKDKLQK.js.map → graph-edge-decay-CZ3SYLM4.js.map} +0 -0
  373. /package/dist/{resolution-TV3F7ZTH.js.map → resolution-E4GLHLY6.js.map} +0 -0
@@ -0,0 +1,361 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
3
+ import http from "node:http";
4
+ import type { AddressInfo } from "node:net";
5
+ import os from "node:os";
6
+ import path from "node:path";
7
+ import test from "node:test";
8
+
9
+ import { calibrationConsolidationInput, readCalibrationIndex, runCalibrationConsolidation } from "./calibration.js";
10
+ import { parseConfig } from "./config.js";
11
+ import { type LoggerBackend, initLogger, resetLogger } from "./logger.js";
12
+ import type { GatewayConfig } from "./types.js";
13
+
14
+ /**
15
+ * Gateway-less calibration (standalone daemon): no gateway model chain, so
16
+ * consolidation must call the configured local LLM and surface skips above
17
+ * debug. These tests drive the real LocalLlmClient against a loopback stub.
18
+ */
19
+
20
+ interface CapturedRequest {
21
+ method: string;
22
+ path: string;
23
+ body: string;
24
+ headers: http.IncomingHttpHeaders;
25
+ }
26
+
27
+ interface StubServer {
28
+ url: string;
29
+ requests: CapturedRequest[];
30
+ close(): Promise<void>;
31
+ }
32
+
33
+ function startServer(handle: (req: CapturedRequest, res: http.ServerResponse) => void): Promise<StubServer> {
34
+ const requests: CapturedRequest[] = [];
35
+ const server = http.createServer((req, res) => {
36
+ const chunks: Buffer[] = [];
37
+ req.on("data", (chunk: Buffer) => chunks.push(chunk));
38
+ req.on("end", () => {
39
+ const captured: CapturedRequest = {
40
+ method: req.method ?? "",
41
+ path: req.url ?? "",
42
+ body: Buffer.concat(chunks).toString("utf8"),
43
+ headers: req.headers,
44
+ };
45
+ requests.push(captured);
46
+ handle(captured, res);
47
+ });
48
+ });
49
+ return new Promise((resolve) => {
50
+ server.listen(0, "127.0.0.1", () => {
51
+ const { port } = server.address() as AddressInfo;
52
+ resolve({
53
+ url: `http://127.0.0.1:${port}/v1`,
54
+ requests,
55
+ close: () => new Promise((done) => server.close(() => done())),
56
+ });
57
+ });
58
+ });
59
+ }
60
+
61
+ function json(res: http.ServerResponse, body: unknown): void {
62
+ res.writeHead(200, { "content-type": "application/json" });
63
+ res.end(JSON.stringify(body));
64
+ }
65
+
66
+ function ruleJson(condition: string): string {
67
+ return JSON.stringify({
68
+ rules: [
69
+ {
70
+ ruleType: "scope_boundary",
71
+ condition,
72
+ modelTendency: "It expands the task",
73
+ userExpectation: "Stay inside the request",
74
+ calibration: "Ask before widening the task.",
75
+ confidence: 0.8,
76
+ evidenceIds: ["correction-1", "correction-2"],
77
+ },
78
+ ],
79
+ });
80
+ }
81
+
82
+ function chatCompletionBody(content: string): unknown {
83
+ return { choices: [{ message: { content } }] };
84
+ }
85
+
86
+ async function writeCorrections(memoryDir: string, count: number): Promise<void> {
87
+ const dir = path.join(memoryDir, "corrections");
88
+ await mkdir(dir, { recursive: true });
89
+ for (let i = 1; i <= count; i += 1) {
90
+ const body = [
91
+ "---",
92
+ `id: correction-${i}`,
93
+ "confidence: 0.9",
94
+ "---",
95
+ "",
96
+ `Correction ${i}: the model assumed a broader scope than the user stated for task ${i}.`,
97
+ "",
98
+ ].join("\n");
99
+ await writeFile(path.join(dir, `correction-${i}.md`), body, "utf8");
100
+ }
101
+ }
102
+
103
+ function captureLogs(debug = true): { lines: Array<{ level: string; msg: string }> } {
104
+ const lines: Array<{ level: string; msg: string }> = [];
105
+ const backend: LoggerBackend = {
106
+ info(msg) {
107
+ lines.push({ level: "info", msg: String(msg) });
108
+ },
109
+ warn(msg) {
110
+ lines.push({ level: "warn", msg: String(msg) });
111
+ },
112
+ error(msg) {
113
+ lines.push({ level: "error", msg: String(msg) });
114
+ },
115
+ debug(msg) {
116
+ lines.push({ level: "debug", msg: String(msg) });
117
+ },
118
+ };
119
+ initLogger(backend, debug);
120
+ return { lines };
121
+ }
122
+
123
+ function gatewayConfig(baseUrl: string): GatewayConfig {
124
+ return {
125
+ agents: { defaults: { model: { primary: "stub/calibration-gateway" } } },
126
+ models: {
127
+ providers: {
128
+ stub: {
129
+ baseUrl,
130
+ api: "openai-completions",
131
+ apiKey: "gateway-test-key",
132
+ models: [],
133
+ },
134
+ },
135
+ },
136
+ };
137
+ }
138
+
139
+ test.describe("gateway-less calibration", { concurrency: false }, () => {
140
+ test("plugin mode supplies localLlm settings and leaves the gateway chain unset", () => {
141
+ const config = parseConfig({
142
+ memoryDir: "/tmp/remnic-cal-plugin",
143
+ modelSource: "plugin",
144
+ localLlmEnabled: true,
145
+ localLlmModel: "daemon-calibration-model",
146
+ gatewayAgentId: "ignored-in-plugin-mode",
147
+ taskModelChain: { primary: "stub/ignored" },
148
+ });
149
+ const input = calibrationConsolidationInput(config);
150
+ assert.equal(input.pluginConfig, config);
151
+ assert.equal(input.pluginConfig.localLlmModel, "daemon-calibration-model");
152
+ assert.equal(input.pluginConfig.localLlmEnabled, true);
153
+ assert.equal(input.gatewayAgentId, undefined);
154
+ assert.equal(input.modelChain, undefined);
155
+ assert.equal(input.gatewayConfig, undefined);
156
+ });
157
+
158
+ test("gateway mode keeps the agent and task chain on the calibration input", () => {
159
+ const config = parseConfig({
160
+ memoryDir: "/tmp/remnic-cal-gateway-input",
161
+ modelSource: "gateway",
162
+ gatewayAgentId: "agent-a",
163
+ taskModelChain: { primary: "stub/calibration-gateway" },
164
+ });
165
+ const input = calibrationConsolidationInput(config);
166
+ assert.equal(input.gatewayAgentId, "agent-a");
167
+ assert.deepEqual(input.modelChain, { primary: "stub/calibration-gateway" });
168
+ assert.equal(input.pluginConfig, config);
169
+ });
170
+
171
+ test("uses the daemon localLlm* settings when no gateway model chain exists", async () => {
172
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-cal-local-"));
173
+ const logs = captureLogs();
174
+ const server = await startServer((req, res) => {
175
+ if (req.method === "GET" && req.path === "/") {
176
+ res.writeHead(200, { "content-type": "text/plain" });
177
+ res.end("Ollama is running");
178
+ return;
179
+ }
180
+ if (req.method === "POST" && req.path === "/v1/chat/completions") {
181
+ json(res, chatCompletionBody(ruleJson("When the daemon has no gateway chain")));
182
+ return;
183
+ }
184
+ res.writeHead(404);
185
+ res.end();
186
+ });
187
+ try {
188
+ await writeCorrections(memoryDir, 3);
189
+ const pluginConfig = parseConfig({
190
+ memoryDir,
191
+ modelSource: "plugin",
192
+ localLlmEnabled: true,
193
+ localLlmUrl: server.url,
194
+ localLlmModel: "daemon-calibration-model",
195
+ localLlmHeaders: { "X-Remnic-Local": "calibration" },
196
+ localLlmApiKey: "local-test-key",
197
+ localLlmAuthHeader: true,
198
+ });
199
+ const rules = await runCalibrationConsolidation({
200
+ memoryDir,
201
+ workspaceDir: memoryDir,
202
+ pluginConfig,
203
+ });
204
+
205
+ assert.equal(rules.length, 1);
206
+ assert.equal(rules[0]?.condition, "When the daemon has no gateway chain");
207
+ const stored = await readCalibrationIndex(memoryDir);
208
+ assert.equal(stored.rules.length, 1);
209
+ assert.equal(stored.totalCorrectionsAnalyzed, 3);
210
+
211
+ const completion = server.requests.find((req) => req.method === "POST" && req.path === "/v1/chat/completions");
212
+ assert.ok(completion, "local LLM chat completion was not called");
213
+ const body = JSON.parse(completion.body) as { model?: string };
214
+ assert.equal(body.model, "daemon-calibration-model");
215
+ assert.equal(completion.headers["x-remnic-local"], "calibration");
216
+ assert.equal(completion.headers.authorization, "Bearer local-test-key");
217
+ assert.ok(
218
+ logs.lines.some((line) => line.level === "info" && line.msg.includes("model=daemon-calibration-model"))
219
+ );
220
+ assert.equal(
221
+ logs.lines.some((line) => line.msg.includes("no LLM available")),
222
+ false
223
+ );
224
+ } finally {
225
+ resetLogger();
226
+ await server.close();
227
+ await rm(memoryDir, { recursive: true, force: true });
228
+ }
229
+ });
230
+
231
+ test("warns and skips when neither a gateway chain nor a local LLM is configured", async () => {
232
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-cal-skip-"));
233
+ const logs = captureLogs(true);
234
+ try {
235
+ await writeCorrections(memoryDir, 3);
236
+ const pluginConfig = parseConfig({
237
+ memoryDir,
238
+ modelSource: "plugin",
239
+ localLlmEnabled: false,
240
+ });
241
+ const rules = await runCalibrationConsolidation({
242
+ memoryDir,
243
+ workspaceDir: memoryDir,
244
+ pluginConfig,
245
+ });
246
+ assert.deepEqual(rules, []);
247
+ const stored = await readCalibrationIndex(memoryDir);
248
+ assert.equal(stored.rules.length, 0);
249
+ assert.ok(logs.lines.some((line) => line.level === "warn" && line.msg.includes("no LLM available")));
250
+ assert.equal(
251
+ logs.lines.some((line) => line.level === "debug" && line.msg.includes("no LLM available")),
252
+ false
253
+ );
254
+ } finally {
255
+ resetLogger();
256
+ await rm(memoryDir, { recursive: true, force: true });
257
+ }
258
+ });
259
+
260
+ test("logs a short correction set at info", async () => {
261
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-cal-few-"));
262
+ const logs = captureLogs(true);
263
+ const server = await startServer((req, res) => {
264
+ if (req.method === "GET" && req.path === "/") {
265
+ res.writeHead(200, { "content-type": "text/plain" });
266
+ res.end("Ollama is running");
267
+ return;
268
+ }
269
+ res.writeHead(500);
270
+ res.end();
271
+ });
272
+ try {
273
+ await writeCorrections(memoryDir, 1);
274
+ const pluginConfig = parseConfig({
275
+ memoryDir,
276
+ modelSource: "plugin",
277
+ localLlmEnabled: true,
278
+ localLlmUrl: server.url,
279
+ localLlmModel: "daemon-calibration-model",
280
+ });
281
+ const rules = await runCalibrationConsolidation({
282
+ memoryDir,
283
+ workspaceDir: memoryDir,
284
+ pluginConfig,
285
+ });
286
+ assert.deepEqual(rules, []);
287
+ assert.equal(
288
+ server.requests.some((req) => req.method === "POST"),
289
+ false,
290
+ "synthesis must not call the LLM before the correction minimum"
291
+ );
292
+ assert.ok(logs.lines.some((line) => line.level === "info" && line.msg.includes("need at least 3")));
293
+ assert.equal(
294
+ logs.lines.some((line) => line.level === "debug" && line.msg.includes("need at least 3")),
295
+ false
296
+ );
297
+ } finally {
298
+ resetLogger();
299
+ await server.close();
300
+ await rm(memoryDir, { recursive: true, force: true });
301
+ }
302
+ });
303
+
304
+ test("keeps the gateway chain when one is configured", async () => {
305
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-cal-gateway-"));
306
+ const logs = captureLogs();
307
+ const local = await startServer((req, res) => {
308
+ if (req.method === "GET" && req.path === "/") {
309
+ res.writeHead(200, { "content-type": "text/plain" });
310
+ res.end("Ollama is running");
311
+ return;
312
+ }
313
+ if (req.method === "POST") {
314
+ json(res, chatCompletionBody(ruleJson("When the local model was used by mistake")));
315
+ return;
316
+ }
317
+ res.writeHead(404);
318
+ res.end();
319
+ });
320
+ const gateway = await startServer((req, res) => {
321
+ if (req.method === "POST" && req.path === "/v1/chat/completions") {
322
+ json(res, chatCompletionBody(ruleJson("When the gateway chain is present")));
323
+ return;
324
+ }
325
+ res.writeHead(404);
326
+ res.end();
327
+ });
328
+ try {
329
+ await writeCorrections(memoryDir, 3);
330
+ const pluginConfig = parseConfig({
331
+ memoryDir,
332
+ modelSource: "plugin",
333
+ localLlmEnabled: true,
334
+ localLlmUrl: local.url,
335
+ localLlmModel: "daemon-calibration-model",
336
+ });
337
+ const rules = await runCalibrationConsolidation({
338
+ memoryDir,
339
+ workspaceDir: memoryDir,
340
+ gatewayConfig: gatewayConfig(gateway.url),
341
+ pluginConfig,
342
+ });
343
+ assert.equal(rules.length, 1);
344
+ assert.equal(rules[0]?.condition, "When the gateway chain is present");
345
+ assert.equal(local.requests.length, 0);
346
+ assert.equal(
347
+ gateway.requests.filter((req) => req.method === "POST" && req.path === "/v1/chat/completions").length,
348
+ 1
349
+ );
350
+ assert.equal(
351
+ logs.lines.some((line) => line.msg.includes("using configured local LLM")),
352
+ false
353
+ );
354
+ } finally {
355
+ resetLogger();
356
+ await local.close();
357
+ await gateway.close();
358
+ await rm(memoryDir, { recursive: true, force: true });
359
+ }
360
+ });
361
+ });
@@ -13,14 +13,15 @@
13
13
  */
14
14
 
15
15
  import { createHash } from "node:crypto";
16
- import path from "node:path";
17
16
  import { mkdir, readFile, writeFile } from "node:fs/promises";
17
+ import path from "node:path";
18
+ import { resolveLocalLlmCapabilities } from "./capabilities.js";
19
+ import { OUTPUT_LANGUAGE_POLICY } from "./extraction-prompt.js";
18
20
  import { FallbackLlmClient } from "./fallback-llm.js";
19
- import type { AgentPersonaModelConfig, GatewayConfig, MemoryFile } from "./types.js";
20
- import { listJsonFiles, readJsonFile } from "./json-store.js";
21
- import { isRecord } from "./store-contract.js";
21
+ import { listJsonFiles } from "./json-store.js";
22
+ import { LocalLlmClient } from "./local-llm.js";
22
23
  import { log } from "./logger.js";
23
- import { OUTPUT_LANGUAGE_POLICY } from "./extraction-prompt.js";
24
+ import type { AgentPersonaModelConfig, GatewayConfig, PluginConfig } from "./types.js";
24
25
 
25
26
  // ─── Types ───────────────────────────────────────────────────────────────────
26
27
 
@@ -223,12 +224,57 @@ Output valid JSON only:
223
224
  ]
224
225
  }`;
225
226
 
227
+ interface CalibrationChatClient {
228
+ chatCompletion(
229
+ messages: Array<{ role: "system" | "user" | "assistant"; content: string }>,
230
+ options?: {
231
+ temperature?: number;
232
+ maxTokens?: number;
233
+ agentId?: string;
234
+ modelChain?: AgentPersonaModelConfig;
235
+ }
236
+ ): Promise<{ content?: string | null } | null>;
237
+ }
238
+
239
+ interface CalibrationLlmOptions {
240
+ gatewayConfig?: GatewayConfig;
241
+ gatewayAgentId?: string;
242
+ modelChain?: AgentPersonaModelConfig;
243
+ workspaceDir?: string;
244
+ /** Plugin config. Supplies `localLlm*` settings when the gateway chain is empty. */
245
+ pluginConfig?: PluginConfig;
246
+ }
247
+
248
+ function resolveCalibrationChatClient(options: CalibrationLlmOptions): CalibrationChatClient | null {
249
+ const gateway = new FallbackLlmClient(options.gatewayConfig, {
250
+ workspaceDir: options.workspaceDir,
251
+ });
252
+ if (gateway.isAvailable({ agentId: options.gatewayAgentId, modelChain: options.modelChain })) {
253
+ return gateway;
254
+ }
255
+ const pluginConfig = options.pluginConfig;
256
+ if (pluginConfig && resolveLocalLlmCapabilities(pluginConfig).localLlm) {
257
+ log.info(`[calibration] using configured local LLM (model=${pluginConfig.localLlmModel})`);
258
+ const local = new LocalLlmClient(pluginConfig);
259
+ return {
260
+ chatCompletion(messages, chatOptions) {
261
+ return local.chatCompletion(messages, {
262
+ temperature: chatOptions?.temperature,
263
+ maxTokens: chatOptions?.maxTokens,
264
+ });
265
+ },
266
+ };
267
+ }
268
+ log.warn("[calibration] no LLM available — skipping consolidation");
269
+ return null;
270
+ }
271
+
226
272
  export async function synthesizeCalibrationRules(
227
273
  corrections: CorrectionMemory[],
228
- llm: FallbackLlmClient,
274
+ llm: CalibrationChatClient,
229
275
  existingRules: CalibrationRule[],
230
276
  agentId?: string,
231
- modelChain?: AgentPersonaModelConfig,
277
+ modelChain?: AgentPersonaModelConfig
232
278
  ): Promise<CalibrationRule[]> {
233
279
  if (corrections.length < 2) return [];
234
280
 
@@ -238,16 +284,20 @@ export async function synthesizeCalibrationRules(
238
284
  .map((c, i) => `[${c.id}] ${c.content}`)
239
285
  .join("\n\n");
240
286
 
241
- const existingRulesText = existingRules.length > 0
242
- ? `\n\nExisting calibration rules (avoid duplicating these):\n${existingRules.map((r) => `- ${r.condition}: ${r.calibration}`).join("\n")}`
243
- : "";
287
+ const existingRulesText =
288
+ existingRules.length > 0
289
+ ? `\n\nExisting calibration rules (avoid duplicating these):\n${existingRules.map((r) => `- ${r.condition}: ${r.calibration}`).join("\n")}`
290
+ : "";
244
291
 
245
292
  const response = await llm.chatCompletion(
246
293
  [
247
294
  { role: "system", content: CLUSTER_PROMPT },
248
- { role: "user", content: `Here are ${corrections.length} corrections from this user:\n\n${correctionText}${existingRulesText}` },
295
+ {
296
+ role: "user",
297
+ content: `Here are ${corrections.length} corrections from this user:\n\n${correctionText}${existingRulesText}`,
298
+ },
249
299
  ],
250
- { temperature: 0.3, maxTokens: 3000, agentId, modelChain },
300
+ { temperature: 0.3, maxTokens: 3000, agentId, modelChain }
251
301
  );
252
302
 
253
303
  if (!response?.content) return [];
@@ -283,7 +333,10 @@ export async function synthesizeCalibrationRules(
283
333
  }
284
334
  const evidenceCorrectionIds = parseEvidenceIds(raw.evidenceIds);
285
335
  return {
286
- id: `cal-${createHash("sha256").update(condition + calibration).digest("hex").slice(0, 12)}`,
336
+ id: `cal-${createHash("sha256")
337
+ .update(condition + calibration)
338
+ .digest("hex")
339
+ .slice(0, 12)}`,
287
340
  ruleType: ruleType as CalibrationRule["ruleType"],
288
341
  condition,
289
342
  modelTendency,
@@ -292,8 +345,8 @@ export async function synthesizeCalibrationRules(
292
345
  confidence,
293
346
  evidenceCount: evidenceCorrectionIds.length,
294
347
  evidenceCorrectionIds,
295
- createdAt: now,
296
- lastReinforcedAt: now,
348
+ createdAt: now,
349
+ lastReinforcedAt: now,
297
350
  };
298
351
  })
299
352
  .filter((rule): rule is CalibrationRule => !!rule);
@@ -341,6 +394,30 @@ export function buildCalibrationRecallSection(
341
394
 
342
395
  // ─── Public API ──────────────────────────────────────────────────────────────
343
396
 
397
+ /**
398
+ * Options weekly compounding passes into calibration. Gateway agent and task
399
+ * chain fields stay limited to `modelSource: "gateway"`. `pluginConfig` carries
400
+ * the `localLlm*` settings used when that chain is empty.
401
+ */
402
+ export function calibrationConsolidationInput(config: PluginConfig): {
403
+ memoryDir: string;
404
+ gatewayConfig?: GatewayConfig;
405
+ gatewayAgentId?: string;
406
+ modelChain?: AgentPersonaModelConfig;
407
+ workspaceDir?: string;
408
+ pluginConfig: PluginConfig;
409
+ } {
410
+ const gateway = config.modelSource === "gateway";
411
+ return {
412
+ memoryDir: config.memoryDir,
413
+ gatewayConfig: config.gatewayConfig,
414
+ gatewayAgentId: gateway ? (config.gatewayAgentId || undefined) : undefined,
415
+ modelChain: gateway ? config.taskModelChain : undefined,
416
+ workspaceDir: config.workspaceDir,
417
+ pluginConfig: config,
418
+ };
419
+ }
420
+
344
421
  /**
345
422
  * Run the full calibration pipeline:
346
423
  * 1. Read all corrections
@@ -354,27 +431,29 @@ export async function runCalibrationConsolidation(options: {
354
431
  gatewayAgentId?: string;
355
432
  modelChain?: AgentPersonaModelConfig;
356
433
  workspaceDir?: string;
434
+ pluginConfig?: PluginConfig;
357
435
  }): Promise<CalibrationRule[]> {
358
436
  try {
359
- const llm = new FallbackLlmClient(options.gatewayConfig, {
360
- workspaceDir: options.workspaceDir,
361
- });
362
- if (!llm.isAvailable({ agentId: options.gatewayAgentId, modelChain: options.modelChain })) {
363
- log.debug("[calibration] no LLM available — skipping consolidation");
364
- return [];
365
- }
437
+ const llm = resolveCalibrationChatClient(options);
438
+ if (!llm) return [];
366
439
 
367
440
  const corrections = await readCorrections(options.memoryDir);
368
441
  if (corrections.length < 3) {
369
- log.debug(`[calibration] only ${corrections.length} corrections — need at least 3`);
442
+ log.info(`[calibration] only ${corrections.length} corrections — need at least 3`);
370
443
  return [];
371
444
  }
372
445
 
373
446
  const existingIndex = await readCalibrationIndex(options.memoryDir);
374
447
 
375
- const newRules = await synthesizeCalibrationRules(corrections, llm, existingIndex.rules, options.gatewayAgentId, options.modelChain);
448
+ const newRules = await synthesizeCalibrationRules(
449
+ corrections,
450
+ llm,
451
+ existingIndex.rules,
452
+ options.gatewayAgentId,
453
+ options.modelChain
454
+ );
376
455
  if (newRules.length === 0) {
377
- log.debug("[calibration] no new calibration rules synthesized");
456
+ log.info("[calibration] no new calibration rules synthesized");
378
457
  return existingIndex.rules;
379
458
  }
380
459
 
@@ -402,7 +481,9 @@ export async function runCalibrationConsolidation(options: {
402
481
  log.debug(`[calibration] synthesized ${newRules.length} new rule(s), ${allRules.length} total`);
403
482
  return allRules;
404
483
  } catch (error) {
405
- log.warn(`[calibration] consolidation failed (non-fatal): ${error instanceof Error ? error.message : String(error)}`);
484
+ log.warn(
485
+ `[calibration] consolidation failed (non-fatal): ${error instanceof Error ? error.message : String(error)}`
486
+ );
406
487
  return [];
407
488
  }
408
489
  }
@@ -421,6 +502,7 @@ export async function runCalibrationIfEnabled(options: {
421
502
  gatewayAgentId?: string;
422
503
  modelChain?: AgentPersonaModelConfig;
423
504
  workspaceDir?: string;
505
+ pluginConfig?: PluginConfig;
424
506
  }): Promise<CalibrationRule[]> {
425
507
  if (!options.calibrationEnabled) {
426
508
  return [];
@@ -431,6 +513,7 @@ export async function runCalibrationIfEnabled(options: {
431
513
  gatewayAgentId: options.gatewayAgentId,
432
514
  modelChain: options.modelChain,
433
515
  workspaceDir: options.workspaceDir,
516
+ pluginConfig: options.pluginConfig,
434
517
  });
435
518
  }
436
519
 
@@ -552,14 +552,8 @@ export class CompoundingEngine {
552
552
  // PEDC: Run calibration consolidation during weekly synthesis
553
553
  if (resolveConsolidationCapabilities(this.config).calibration) {
554
554
  try {
555
- const { runCalibrationConsolidation } = await import("../calibration.js");
556
- const calRules = await runCalibrationConsolidation({
557
- memoryDir: this.config.memoryDir,
558
- gatewayConfig: this.config.gatewayConfig,
559
- gatewayAgentId: this.config.modelSource === "gateway" ? (this.config.gatewayAgentId || undefined) : undefined,
560
- modelChain: this.config.modelSource === "gateway" ? this.config.taskModelChain : undefined,
561
- workspaceDir: this.config.workspaceDir,
562
- });
555
+ const { calibrationConsolidationInput, runCalibrationConsolidation } = await import("../calibration.js");
556
+ const calRules = await runCalibrationConsolidation(calibrationConsolidationInput(this.config));
563
557
  log.debug(`[calibration] weekly synthesis produced ${calRules.length} calibration rule(s)`);
564
558
  } catch (error) {
565
559
  log.warn(`[calibration] weekly consolidation failed (non-fatal): ${error instanceof Error ? error.message : String(error)}`);
package/src/http-retry.ts CHANGED
@@ -13,6 +13,8 @@
13
13
  * `@remnic/core/abort-error`) — the root index stays untouched.
14
14
  */
15
15
 
16
+ import { sleep as defaultSleep } from "./utils/sleep.js";
17
+
16
18
  export interface RetryingFetchOptions {
17
19
  /** Request init for every attempt. Ignored when `buildInit` is set. */
18
20
  init?: RequestInit;
@@ -70,12 +72,6 @@ const DEFAULT_MAX_RETRIES = 3;
70
72
  const DEFAULT_MAX_RETRY_DELAY_MS = 30_000;
71
73
  const DEFAULT_BACKOFF_BASE_MS = 1_000;
72
74
 
73
- function defaultSleep(ms: number): Promise<void> {
74
- const { promise, resolve } = Promise.withResolvers<void>();
75
- setTimeout(resolve, ms);
76
- return promise;
77
- }
78
-
79
75
  /**
80
76
  * Network/timeout failures wrap Node error text that can carry loader
81
77
  * paths or stack fragments; sync errors reach MCP clients verbatim, so
@@ -0,0 +1,55 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtemp, rm } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import path from "node:path";
5
+ import test from "node:test";
6
+ import { readProjectedMemoryStates } from "./memory-projection-batch.js";
7
+ import { getMemoryProjectionPath, readProjectedMemoryState } from "./memory-projection-store.js";
8
+ import { rebuildMemoryProjection } from "./maintenance/rebuild-memory-projection.js";
9
+ import { openBetterSqlite3 } from "./runtime/better-sqlite.js";
10
+ import { StorageManager } from "./storage.js";
11
+
12
+ test("projection batches return only requested rows and preserve completeness metadata", async () => {
13
+ const memoryDir = await mkdtemp(path.join(tmpdir(), "remnic-projection-batch-"));
14
+ try {
15
+ assert.equal(readProjectedMemoryStates(memoryDir, ["missing"]), null);
16
+ const storage = new StorageManager(memoryDir);
17
+ await storage.ensureDirectories();
18
+ const source = await storage.writeMemory("fact", "batch source payload", {
19
+ source: "test", tags: ["zeta", "alpha"], entityRef: "person:narwhal", confidence: 0.9,
20
+ });
21
+ const excluded = await storage.writeMemory("fact", "unrequested source payload", { source: "test" });
22
+ await rebuildMemoryProjection({ memoryDir, storage, dryRun: false });
23
+
24
+ const batch = readProjectedMemoryStates(memoryDir, new Set([source.id, "missing"]));
25
+ assert.ok(batch);
26
+ assert.deepEqual([...batch.states.keys()], [source.id]);
27
+ assert.equal(batch.states.has(excluded.id), false);
28
+ assert.deepEqual(batch.states.get(source.id), readProjectedMemoryState(memoryDir, source.id));
29
+ assert.deepEqual(batch.states.get(source.id)?.tags, ["alpha", "zeta"]);
30
+ assert.equal(batch.states.get(source.id)?.preview, "batch source payload");
31
+ assert.equal(batch.complete, true);
32
+ assert.ok(Number.isFinite(Date.parse(batch.rebuiltAt ?? "")));
33
+ assert.deepEqual(readProjectedMemoryStates(memoryDir, []), { ...batch, states: new Map() });
34
+
35
+ const db = openBetterSqlite3(getMemoryProjectionPath(memoryDir));
36
+ try {
37
+ const stamp = db.prepare("SELECT value FROM meta WHERE key = 'rebuiltAt'").get() as { value: string };
38
+ assert.equal(batch.rebuiltAt, stamp.value);
39
+ db.prepare("UPDATE meta SET value = 'false' WHERE key = 'complete'").run();
40
+ assert.equal(readProjectedMemoryStates(memoryDir, [source.id])?.complete, false);
41
+ db.prepare("DELETE FROM meta WHERE key IN ('complete', 'rebuiltAt')").run();
42
+ const legacy = readProjectedMemoryStates(memoryDir, [source.id]);
43
+ assert.ok(legacy);
44
+ assert.equal(legacy.complete, false);
45
+ assert.equal(legacy.rebuiltAt, null);
46
+ assert.deepEqual(legacy.states, batch.states);
47
+ db.exec("DROP TABLE memory_current");
48
+ assert.equal(readProjectedMemoryStates(memoryDir, [source.id]), null, "unreadable schema must fall back");
49
+ } finally {
50
+ db.close();
51
+ }
52
+ } finally {
53
+ await rm(memoryDir, { recursive: true, force: true });
54
+ }
55
+ });