@remnic/core 1.0.2 → 1.1.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 (385) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -0
  3. package/dist/abort-error.d.ts +32 -0
  4. package/dist/abort-error.js +11 -0
  5. package/dist/access-cli.d.ts +13 -3
  6. package/dist/access-cli.js +96 -80
  7. package/dist/access-cli.js.map +1 -1
  8. package/dist/access-http.d.ts +12 -4
  9. package/dist/access-http.js +25 -18
  10. package/dist/access-mcp.d.ts +32 -4
  11. package/dist/access-mcp.js +16 -1
  12. package/dist/access-schema.d.ts +28 -28
  13. package/dist/access-schema.js +1 -1
  14. package/dist/access-service-HmO1Trrx.d.ts +732 -0
  15. package/dist/access-service.d.ts +15 -601
  16. package/dist/access-service.js +21 -15
  17. package/dist/active-memory-bridge.d.ts +66 -0
  18. package/dist/active-memory-bridge.js +11 -0
  19. package/dist/active-memory-bridge.js.map +1 -0
  20. package/dist/active-recall.d.ts +96 -0
  21. package/dist/active-recall.js +308 -0
  22. package/dist/active-recall.js.map +1 -0
  23. package/dist/behavior-learner.js +1 -1
  24. package/dist/bootstrap.d.ts +6 -3
  25. package/dist/bootstrap.js +2 -2
  26. package/dist/boxes.js +2 -2
  27. package/dist/briefing.d.ts +169 -0
  28. package/dist/briefing.js +52 -0
  29. package/dist/briefing.js.map +1 -0
  30. package/dist/buffer.d.ts +19 -5
  31. package/dist/buffer.js +2 -2
  32. package/dist/calibration.js +6 -6
  33. package/dist/causal-behavior.js +5 -5
  34. package/dist/causal-chain.js +3 -3
  35. package/dist/causal-consolidation.d.ts +22 -2
  36. package/dist/causal-consolidation.js +36 -9
  37. package/dist/causal-consolidation.js.map +1 -1
  38. package/dist/causal-retrieval.js +6 -6
  39. package/dist/causal-trajectory-graph.js +1 -1
  40. package/dist/causal-trajectory.d.ts +14 -1
  41. package/dist/causal-trajectory.js +5 -1
  42. package/dist/{chunk-KWBU5S5U.js → chunk-2ODBA7MQ.js} +9 -3
  43. package/dist/chunk-2ODBA7MQ.js.map +1 -0
  44. package/dist/{chunk-ZJLY4QSU.js → chunk-37UIFYWO.js} +130 -6
  45. package/dist/chunk-37UIFYWO.js.map +1 -0
  46. package/dist/chunk-3PG3H5TD.js +7 -0
  47. package/dist/chunk-3PG3H5TD.js.map +1 -0
  48. package/dist/{chunk-NTTLPF7F.js → chunk-3QFQGRHO.js} +5 -5
  49. package/dist/{chunk-QDOSNLB4.js → chunk-3QHL5ABG.js} +17 -15
  50. package/dist/chunk-3QHL5ABG.js.map +1 -0
  51. package/dist/{chunk-6UJQNRIO.js → chunk-3SV6CQHO.js} +92 -33
  52. package/dist/chunk-3SV6CQHO.js.map +1 -0
  53. package/dist/{chunk-U4PV25RD.js → chunk-3WHVNEN7.js} +1 -1
  54. package/dist/chunk-3WHVNEN7.js.map +1 -0
  55. package/dist/{chunk-XUHI52HK.js → chunk-44ICJRF3.js} +98 -10
  56. package/dist/chunk-44ICJRF3.js.map +1 -0
  57. package/dist/{chunk-HG2NKWR2.js → chunk-47UU5PU2.js} +49 -10
  58. package/dist/chunk-47UU5PU2.js.map +1 -0
  59. package/dist/chunk-4DJQYKMN.js +187 -0
  60. package/dist/chunk-4DJQYKMN.js.map +1 -0
  61. package/dist/chunk-4KAN3GZ3.js +225 -0
  62. package/dist/chunk-4KAN3GZ3.js.map +1 -0
  63. package/dist/chunk-4LACOVZX.js +813 -0
  64. package/dist/chunk-4LACOVZX.js.map +1 -0
  65. package/dist/{chunk-ORZMT74A.js → chunk-4NRAJUDS.js} +11 -1
  66. package/dist/chunk-4NRAJUDS.js.map +1 -0
  67. package/dist/{chunk-B7LOFDVE.js → chunk-4WMCPJWX.js} +8 -3
  68. package/dist/chunk-4WMCPJWX.js.map +1 -0
  69. package/dist/{chunk-G3AG3KZN.js → chunk-5IZL4DCV.js} +2 -2
  70. package/dist/{chunk-BRK4ODMI.js → chunk-5NPGSAVB.js} +2 -2
  71. package/dist/{chunk-QANCTXQF.js → chunk-6LX5ORAS.js} +3 -3
  72. package/dist/chunk-6MKAMLQL.js +16 -0
  73. package/dist/chunk-6MKAMLQL.js.map +1 -0
  74. package/dist/{chunk-ESSMF2FR.js → chunk-6PFRXT4K.js} +15 -6
  75. package/dist/chunk-6PFRXT4K.js.map +1 -0
  76. package/dist/{chunk-UIYZ5T3I.js → chunk-6UJ47TVX.js} +8 -8
  77. package/dist/chunk-6ZH4TU6I.js +245 -0
  78. package/dist/chunk-6ZH4TU6I.js.map +1 -0
  79. package/dist/{chunk-L5RPWGFK.js → chunk-7DHTMOND.js} +2 -2
  80. package/dist/{chunk-L7WO3MZ4.js → chunk-7ECD5ATE.js} +2 -2
  81. package/dist/{chunk-Q6FETXJA.js → chunk-7SEAZFFB.js} +2 -2
  82. package/dist/{chunk-V4YC4LUK.js → chunk-7WQ6SLIE.js} +175 -63
  83. package/dist/chunk-7WQ6SLIE.js.map +1 -0
  84. package/dist/chunk-ALXMCZEU.js +332 -0
  85. package/dist/chunk-ALXMCZEU.js.map +1 -0
  86. package/dist/{chunk-TVVVQQAK.js → chunk-BLKTA7MM.js} +58 -24
  87. package/dist/chunk-BLKTA7MM.js.map +1 -0
  88. package/dist/{chunk-SCHEKPYH.js → chunk-C2EFFULQ.js} +1 -1
  89. package/dist/{chunk-GJR6D6KC.js → chunk-D654IBA6.js} +2 -2
  90. package/dist/{chunk-OTFNI3OO.js → chunk-DEPL3635.js} +1828 -401
  91. package/dist/chunk-DEPL3635.js.map +1 -0
  92. package/dist/{chunk-UYSKNO6E.js → chunk-DHHP2Z4X.js} +15 -4
  93. package/dist/chunk-DHHP2Z4X.js.map +1 -0
  94. package/dist/{chunk-UV2FO7J4.js → chunk-E6K4NIEU.js} +2 -2
  95. package/dist/{chunk-T4WRIV2C.js → chunk-EABGC2TL.js} +2 -2
  96. package/dist/chunk-EJI5XIBB.js +232 -0
  97. package/dist/chunk-EJI5XIBB.js.map +1 -0
  98. package/dist/{chunk-ONRU4L2N.js → chunk-FEMOX5AD.js} +2 -2
  99. package/dist/{chunk-IFFFR3MR.js → chunk-FSFEQI74.js} +3 -3
  100. package/dist/chunk-G4SK7DSQ.js +121 -0
  101. package/dist/chunk-G4SK7DSQ.js.map +1 -0
  102. package/dist/{chunk-WWIQTB2Y.js → chunk-GGD5W7TB.js} +9 -2
  103. package/dist/chunk-GGD5W7TB.js.map +1 -0
  104. package/dist/{chunk-QWUUMMIK.js → chunk-GV6NLQ4X.js} +1355 -80
  105. package/dist/chunk-GV6NLQ4X.js.map +1 -0
  106. package/dist/{chunk-2PO5ZRKV.js → chunk-GZCUW5IC.js} +16 -3
  107. package/dist/chunk-GZCUW5IC.js.map +1 -0
  108. package/dist/{chunk-AAI7JARD.js → chunk-HMDCOMYU.js} +8 -11
  109. package/dist/chunk-HMDCOMYU.js.map +1 -0
  110. package/dist/chunk-IQT3XTKW.js +121 -0
  111. package/dist/chunk-IQT3XTKW.js.map +1 -0
  112. package/dist/{chunk-J3BT33K7.js → chunk-ITRLGI2T.js} +5 -5
  113. package/dist/{chunk-BDFZXRSO.js → chunk-J4IYOZZ5.js} +15 -2
  114. package/dist/chunk-J4IYOZZ5.js.map +1 -0
  115. package/dist/{chunk-J47FNDR7.js → chunk-JIU55F3X.js} +7 -7
  116. package/dist/{chunk-MDDAA2AO.js → chunk-JL2PU6AI.js} +17 -6
  117. package/dist/chunk-JL2PU6AI.js.map +1 -0
  118. package/dist/{chunk-ZKYI7UVO.js → chunk-JR4ZC3G4.js} +2 -2
  119. package/dist/{chunk-UCYSTFZR.js → chunk-JRNQ3RNA.js} +2 -2
  120. package/dist/{chunk-GPGBSNKM.js → chunk-K4FLSOR5.js} +2 -2
  121. package/dist/chunk-KVE7R4CG.js +320 -0
  122. package/dist/chunk-KVE7R4CG.js.map +1 -0
  123. package/dist/chunk-LAYN4LDC.js +267 -0
  124. package/dist/chunk-LAYN4LDC.js.map +1 -0
  125. package/dist/{chunk-ISY75RLM.js → chunk-MBJHSA7F.js} +344 -7
  126. package/dist/chunk-MBJHSA7F.js.map +1 -0
  127. package/dist/{chunk-PGK3VUHN.js → chunk-MTLYEMJB.js} +3 -2
  128. package/dist/chunk-MTLYEMJB.js.map +1 -0
  129. package/dist/{chunk-QY2BHY5O.js → chunk-MVTHXUBX.js} +297 -34
  130. package/dist/chunk-MVTHXUBX.js.map +1 -0
  131. package/dist/{chunk-LP47L3ZX.js → chunk-N42IWANG.js} +5 -5
  132. package/dist/{chunk-YNI4S5WT.js → chunk-N53K2EXC.js} +2 -2
  133. package/dist/{chunk-763GUIOU.js → chunk-NBNN5GOB.js} +2 -2
  134. package/dist/{chunk-CXWFUJR2.js → chunk-NQEVYWX6.js} +195 -5
  135. package/dist/chunk-NQEVYWX6.js.map +1 -0
  136. package/dist/{chunk-KL4CP4SB.js → chunk-O5ETUNBT.js} +17 -5
  137. package/dist/chunk-O5ETUNBT.js.map +1 -0
  138. package/dist/{chunk-OOSWAUYB.js → chunk-ODWDQNRE.js} +2 -2
  139. package/dist/chunk-OIT5QGG4.js +80 -0
  140. package/dist/chunk-OIT5QGG4.js.map +1 -0
  141. package/dist/{chunk-HLBYLYRD.js → chunk-PAORGQRI.js} +70 -13
  142. package/dist/chunk-PAORGQRI.js.map +1 -0
  143. package/dist/chunk-PVGDJXVK.js +21 -0
  144. package/dist/chunk-PVGDJXVK.js.map +1 -0
  145. package/dist/{chunk-OTAVQCSF.js → chunk-PYXS46O7.js} +2 -2
  146. package/dist/chunk-QDW3E4RD.js +108 -0
  147. package/dist/chunk-QDW3E4RD.js.map +1 -0
  148. package/dist/{chunk-YNCQ7E4M.js → chunk-QDYXG4CS.js} +4 -3
  149. package/dist/chunk-QDYXG4CS.js.map +1 -0
  150. package/dist/{chunk-HLXVTBF3.js → chunk-QNJMBKFK.js} +3 -2
  151. package/dist/chunk-QNJMBKFK.js.map +1 -0
  152. package/dist/{chunk-4A24LIM2.js → chunk-S75M5ZRK.js} +2 -2
  153. package/dist/chunk-SYUK3VLY.js +789 -0
  154. package/dist/chunk-SYUK3VLY.js.map +1 -0
  155. package/dist/{chunk-QCCCQT3O.js → chunk-TBBDFYXW.js} +2 -2
  156. package/dist/chunk-TBBDFYXW.js.map +1 -0
  157. package/dist/chunk-U66YHYC7.js +31 -0
  158. package/dist/chunk-U66YHYC7.js.map +1 -0
  159. package/dist/{chunk-MWGVGUIS.js → chunk-UEYA6UC7.js} +36 -4
  160. package/dist/chunk-UEYA6UC7.js.map +1 -0
  161. package/dist/{chunk-M5KEYE5E.js → chunk-URB2WSKZ.js} +2 -2
  162. package/dist/chunk-UVJFDP7P.js +202 -0
  163. package/dist/chunk-UVJFDP7P.js.map +1 -0
  164. package/dist/chunk-W6SL7OFG.js +180 -0
  165. package/dist/chunk-W6SL7OFG.js.map +1 -0
  166. package/dist/chunk-WBSAYXVI.js +7945 -0
  167. package/dist/chunk-WBSAYXVI.js.map +1 -0
  168. package/dist/{chunk-M5ZBBBJI.js → chunk-XZ2TIKGC.js} +39 -9
  169. package/dist/chunk-XZ2TIKGC.js.map +1 -0
  170. package/dist/chunk-Y4FHOFJ2.js +140 -0
  171. package/dist/chunk-Y4FHOFJ2.js.map +1 -0
  172. package/dist/chunk-YDBIWGNI.js +298 -0
  173. package/dist/chunk-YDBIWGNI.js.map +1 -0
  174. package/dist/chunk-YNB73F22.js +137 -0
  175. package/dist/chunk-YNB73F22.js.map +1 -0
  176. package/dist/{chunk-IZME7KW2.js → chunk-ZVBB3T7V.js} +31 -12
  177. package/dist/chunk-ZVBB3T7V.js.map +1 -0
  178. package/dist/chunking.js +1 -1
  179. package/dist/citations.d.ts +67 -0
  180. package/dist/citations.js +13 -0
  181. package/dist/citations.js.map +1 -0
  182. package/dist/cli-BneVIEvh.d.ts +1240 -0
  183. package/dist/cli.d.ts +32 -1147
  184. package/dist/cli.js +150 -7092
  185. package/dist/cli.js.map +1 -1
  186. package/dist/codex-materialize-CQlLTzke.d.ts +139 -0
  187. package/dist/codex-thread-key.d.ts +3 -0
  188. package/dist/codex-thread-key.js +7 -0
  189. package/dist/codex-thread-key.js.map +1 -0
  190. package/dist/config.js +3 -2
  191. package/dist/connectors/codex/instructions.md +160 -0
  192. package/dist/connectors/codex/resources/namespace-cheatsheet.md +48 -0
  193. package/dist/contradiction-review-WIUBAR52.js +21 -0
  194. package/dist/contradiction-review-WIUBAR52.js.map +1 -0
  195. package/dist/contradiction-scan-GR33PONM.js +376 -0
  196. package/dist/contradiction-scan-GR33PONM.js.map +1 -0
  197. package/dist/day-summary.d.ts +7 -2
  198. package/dist/day-summary.js +5 -2
  199. package/dist/direct-answer-wiring.d.ts +77 -0
  200. package/dist/direct-answer-wiring.js +75 -0
  201. package/dist/direct-answer-wiring.js.map +1 -0
  202. package/dist/direct-answer.d.ts +106 -0
  203. package/dist/direct-answer.js +10 -0
  204. package/dist/direct-answer.js.map +1 -0
  205. package/dist/embedding-fallback.d.ts +96 -2
  206. package/dist/embedding-fallback.js +6 -4
  207. package/dist/{engine-2A6J4XEX.js → engine-5TIQBYZR.js} +10 -7
  208. package/dist/engine-5TIQBYZR.js.map +1 -0
  209. package/dist/entity-retrieval.d.ts +3 -2
  210. package/dist/entity-retrieval.js +10 -7
  211. package/dist/entity-schema.d.ts +11 -0
  212. package/dist/entity-schema.js +19 -0
  213. package/dist/entity-schema.js.map +1 -0
  214. package/dist/explicit-capture.d.ts +6 -3
  215. package/dist/explicit-capture.js +2 -2
  216. package/dist/extraction-judge.d.ts +66 -0
  217. package/dist/extraction-judge.js +18 -0
  218. package/dist/extraction-judge.js.map +1 -0
  219. package/dist/extraction.d.ts +1 -0
  220. package/dist/extraction.js +12 -10
  221. package/dist/fallback-llm.d.ts +11 -2
  222. package/dist/fallback-llm.js +4 -4
  223. package/dist/graph.js +1 -1
  224. package/dist/harmonic-retrieval.js +2 -1
  225. package/dist/importance.d.ts +11 -1
  226. package/dist/importance.js +3 -1
  227. package/dist/index.d.ts +1027 -9
  228. package/dist/index.js +3303 -349
  229. package/dist/index.js.map +1 -1
  230. package/dist/intent.d.ts +2 -1
  231. package/dist/intent.js +3 -1
  232. package/dist/lifecycle.js +1 -1
  233. package/dist/local-llm.d.ts +10 -3
  234. package/dist/local-llm.js +2 -2
  235. package/dist/logger.d.ts +1 -1
  236. package/dist/logger.js +1 -1
  237. package/dist/memory-cache.d.ts +2 -2
  238. package/dist/memory-cache.js +1 -1
  239. package/dist/{memory-projection-store-NxMkbocT.d.ts → memory-projection-store-DeSXPh1j.d.ts} +1 -1
  240. package/dist/memory-projection-store.d.ts +1 -1
  241. package/dist/model-registry.js +2 -2
  242. package/dist/models-json.js +2 -2
  243. package/dist/native-knowledge.js +2 -2
  244. package/dist/negative.js +2 -2
  245. package/dist/operator-toolkit.js +20 -15
  246. package/dist/{orchestrator-zTa-Qo-1.d.ts → orchestrator-DRYA6_lW.d.ts} +273 -9
  247. package/dist/orchestrator.d.ts +6 -3
  248. package/dist/orchestrator.js +76 -63
  249. package/dist/page-versioning.d.ts +77 -0
  250. package/dist/page-versioning.js +15 -0
  251. package/dist/page-versioning.js.map +1 -0
  252. package/dist/plugin-id.d.ts +37 -0
  253. package/dist/plugin-id.js +11 -0
  254. package/dist/plugin-id.js.map +1 -0
  255. package/dist/policy-runtime.js +2 -2
  256. package/dist/profiling.js +2 -2
  257. package/dist/qmd.d.ts +5 -2
  258. package/dist/qmd.js +4 -3
  259. package/dist/recall-audit.d.ts +20 -0
  260. package/dist/recall-audit.js +50 -0
  261. package/dist/recall-audit.js.map +1 -0
  262. package/dist/recall-mmr.d.ts +152 -0
  263. package/dist/recall-mmr.js +17 -0
  264. package/dist/recall-mmr.js.map +1 -0
  265. package/dist/recall-qos.js +2 -2
  266. package/dist/recall-state.d.ts +28 -1
  267. package/dist/recall-state.js +2 -2
  268. package/dist/relevance.js +2 -2
  269. package/dist/resolution-QBTDHTG7.js +100 -0
  270. package/dist/resolution-QBTDHTG7.js.map +1 -0
  271. package/dist/resolve-provider-secret.d.ts +24 -1
  272. package/dist/resolve-provider-secret.js +4 -2
  273. package/dist/resume-bundles.js +6 -5
  274. package/dist/retrieval-agents.js +2 -2
  275. package/dist/retrieval.js +2 -2
  276. package/dist/schemas.d.ts +412 -54
  277. package/dist/schemas.js +3 -1
  278. package/dist/sdk-compat.d.ts +2 -0
  279. package/dist/sdk-compat.js +6 -3
  280. package/dist/sdk-compat.js.map +1 -1
  281. package/dist/semantic-chunking.d.ts +87 -0
  282. package/dist/semantic-chunking.js +20 -0
  283. package/dist/semantic-chunking.js.map +1 -0
  284. package/dist/semantic-consolidation-DrvSYRdB.d.ts +119 -0
  285. package/dist/semantic-consolidation.d.ts +4 -42
  286. package/dist/semantic-consolidation.js +23 -2
  287. package/dist/semantic-rule-promotion.js +9 -6
  288. package/dist/semantic-rule-verifier.js +10 -7
  289. package/dist/session-observer-state.js +2 -2
  290. package/dist/session-toggles.d.ts +22 -0
  291. package/dist/session-toggles.js +116 -0
  292. package/dist/session-toggles.js.map +1 -0
  293. package/dist/skills-registry.d.ts +47 -0
  294. package/dist/skills-registry.js +48 -0
  295. package/dist/skills-registry.js.map +1 -0
  296. package/dist/source-attribution.d.ts +169 -0
  297. package/dist/source-attribution.js +27 -0
  298. package/dist/source-attribution.js.map +1 -0
  299. package/dist/storage.d.ts +171 -10
  300. package/dist/storage.js +16 -5
  301. package/dist/summarizer.js +7 -7
  302. package/dist/temporal-supersession.d.ts +127 -0
  303. package/dist/temporal-supersession.js +20 -0
  304. package/dist/temporal-supersession.js.map +1 -0
  305. package/dist/threading.js +2 -2
  306. package/dist/tier-migration.d.ts +2 -1
  307. package/dist/tier-routing.js +2 -2
  308. package/dist/tokens.d.ts +21 -1
  309. package/dist/tokens.js +5 -1
  310. package/dist/transcript.js +2 -2
  311. package/dist/types-DJhqDJUV.d.ts +50 -0
  312. package/dist/types.d.ts +529 -3
  313. package/dist/types.js +1 -1
  314. package/dist/utility-learner.js +2 -2
  315. package/dist/utility-runtime.js +3 -3
  316. package/dist/verified-recall.js +11 -8
  317. package/dist/whitespace.d.ts +4 -0
  318. package/dist/whitespace.js +9 -0
  319. package/dist/whitespace.js.map +1 -0
  320. package/package.json +14 -8
  321. package/dist/chunk-2CJCWDMR.js +0 -87
  322. package/dist/chunk-2CJCWDMR.js.map +0 -1
  323. package/dist/chunk-2PO5ZRKV.js.map +0 -1
  324. package/dist/chunk-6UJQNRIO.js.map +0 -1
  325. package/dist/chunk-AAI7JARD.js.map +0 -1
  326. package/dist/chunk-B7LOFDVE.js.map +0 -1
  327. package/dist/chunk-BDFZXRSO.js.map +0 -1
  328. package/dist/chunk-CXWFUJR2.js.map +0 -1
  329. package/dist/chunk-DORBM6OB.js +0 -81
  330. package/dist/chunk-DORBM6OB.js.map +0 -1
  331. package/dist/chunk-ESSMF2FR.js.map +0 -1
  332. package/dist/chunk-HG2NKWR2.js.map +0 -1
  333. package/dist/chunk-HLBYLYRD.js.map +0 -1
  334. package/dist/chunk-HLXVTBF3.js.map +0 -1
  335. package/dist/chunk-ISY75RLM.js.map +0 -1
  336. package/dist/chunk-IZME7KW2.js.map +0 -1
  337. package/dist/chunk-KL4CP4SB.js.map +0 -1
  338. package/dist/chunk-KWBU5S5U.js.map +0 -1
  339. package/dist/chunk-M5ZBBBJI.js.map +0 -1
  340. package/dist/chunk-MDDAA2AO.js.map +0 -1
  341. package/dist/chunk-MWGVGUIS.js.map +0 -1
  342. package/dist/chunk-ORZMT74A.js.map +0 -1
  343. package/dist/chunk-OTFNI3OO.js.map +0 -1
  344. package/dist/chunk-PGK3VUHN.js.map +0 -1
  345. package/dist/chunk-QCCCQT3O.js.map +0 -1
  346. package/dist/chunk-QDOSNLB4.js.map +0 -1
  347. package/dist/chunk-QPKFPHOO.js +0 -178
  348. package/dist/chunk-QPKFPHOO.js.map +0 -1
  349. package/dist/chunk-QWUUMMIK.js.map +0 -1
  350. package/dist/chunk-QY2BHY5O.js.map +0 -1
  351. package/dist/chunk-TVVVQQAK.js.map +0 -1
  352. package/dist/chunk-U4PV25RD.js.map +0 -1
  353. package/dist/chunk-UYSKNO6E.js.map +0 -1
  354. package/dist/chunk-V4YC4LUK.js.map +0 -1
  355. package/dist/chunk-WWIQTB2Y.js.map +0 -1
  356. package/dist/chunk-XUHI52HK.js.map +0 -1
  357. package/dist/chunk-YNCQ7E4M.js.map +0 -1
  358. package/dist/chunk-ZJLY4QSU.js.map +0 -1
  359. /package/dist/{engine-2A6J4XEX.js.map → abort-error.js.map} +0 -0
  360. /package/dist/{chunk-NTTLPF7F.js.map → chunk-3QFQGRHO.js.map} +0 -0
  361. /package/dist/{chunk-G3AG3KZN.js.map → chunk-5IZL4DCV.js.map} +0 -0
  362. /package/dist/{chunk-BRK4ODMI.js.map → chunk-5NPGSAVB.js.map} +0 -0
  363. /package/dist/{chunk-QANCTXQF.js.map → chunk-6LX5ORAS.js.map} +0 -0
  364. /package/dist/{chunk-UIYZ5T3I.js.map → chunk-6UJ47TVX.js.map} +0 -0
  365. /package/dist/{chunk-L5RPWGFK.js.map → chunk-7DHTMOND.js.map} +0 -0
  366. /package/dist/{chunk-L7WO3MZ4.js.map → chunk-7ECD5ATE.js.map} +0 -0
  367. /package/dist/{chunk-Q6FETXJA.js.map → chunk-7SEAZFFB.js.map} +0 -0
  368. /package/dist/{chunk-SCHEKPYH.js.map → chunk-C2EFFULQ.js.map} +0 -0
  369. /package/dist/{chunk-GJR6D6KC.js.map → chunk-D654IBA6.js.map} +0 -0
  370. /package/dist/{chunk-UV2FO7J4.js.map → chunk-E6K4NIEU.js.map} +0 -0
  371. /package/dist/{chunk-T4WRIV2C.js.map → chunk-EABGC2TL.js.map} +0 -0
  372. /package/dist/{chunk-ONRU4L2N.js.map → chunk-FEMOX5AD.js.map} +0 -0
  373. /package/dist/{chunk-IFFFR3MR.js.map → chunk-FSFEQI74.js.map} +0 -0
  374. /package/dist/{chunk-J3BT33K7.js.map → chunk-ITRLGI2T.js.map} +0 -0
  375. /package/dist/{chunk-J47FNDR7.js.map → chunk-JIU55F3X.js.map} +0 -0
  376. /package/dist/{chunk-ZKYI7UVO.js.map → chunk-JR4ZC3G4.js.map} +0 -0
  377. /package/dist/{chunk-UCYSTFZR.js.map → chunk-JRNQ3RNA.js.map} +0 -0
  378. /package/dist/{chunk-GPGBSNKM.js.map → chunk-K4FLSOR5.js.map} +0 -0
  379. /package/dist/{chunk-LP47L3ZX.js.map → chunk-N42IWANG.js.map} +0 -0
  380. /package/dist/{chunk-YNI4S5WT.js.map → chunk-N53K2EXC.js.map} +0 -0
  381. /package/dist/{chunk-763GUIOU.js.map → chunk-NBNN5GOB.js.map} +0 -0
  382. /package/dist/{chunk-OOSWAUYB.js.map → chunk-ODWDQNRE.js.map} +0 -0
  383. /package/dist/{chunk-OTAVQCSF.js.map → chunk-PYXS46O7.js.map} +0 -0
  384. /package/dist/{chunk-4A24LIM2.js.map → chunk-S75M5ZRK.js.map} +0 -0
  385. /package/dist/{chunk-M5KEYE5E.js.map → chunk-URB2WSKZ.js.map} +0 -0
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-MARWOCVP.js";
4
4
  import {
5
5
  log
6
- } from "./chunk-KWBU5S5U.js";
6
+ } from "./chunk-2ODBA7MQ.js";
7
7
 
8
8
  // src/resolve-provider-secret.ts
9
9
  import path from "path";
@@ -53,13 +53,25 @@ async function getGatewayResolver() {
53
53
  async function findRuntimeModules() {
54
54
  const { readdirSync } = await import("fs");
55
55
  const { createRequire } = await import("module");
56
+ const { execFileSync } = await import("child_process");
56
57
  const candidates = [];
57
58
  const distDirs = [];
59
+ const pushDistDirs = (entryPath) => {
60
+ const resolvedEntryDir = path.dirname(entryPath);
61
+ const packageRoot = path.basename(resolvedEntryDir) === "dist" ? path.resolve(resolvedEntryDir, "..") : resolvedEntryDir;
62
+ const candidateDistDirs = [
63
+ path.join(packageRoot, "dist"),
64
+ path.join(packageRoot, "..", "dist")
65
+ ];
66
+ for (const candidate of candidateDistDirs) {
67
+ const resolved = path.resolve(candidate);
68
+ if (!distDirs.includes(resolved)) distDirs.push(resolved);
69
+ }
70
+ };
58
71
  try {
59
72
  const req = createRequire(import.meta.url);
60
73
  const openclawMain = req.resolve("openclaw");
61
- const openclawDist = path.join(path.dirname(openclawMain), "..", "dist");
62
- if (openclawDist) distDirs.push(path.resolve(openclawDist));
74
+ pushDistDirs(openclawMain);
63
75
  } catch {
64
76
  }
65
77
  try {
@@ -68,12 +80,22 @@ async function findRuntimeModules() {
68
80
  if (mainScript) {
69
81
  const realScript = realpathSync(mainScript);
70
82
  if (realScript.includes("openclaw")) {
71
- const distDir = path.dirname(realScript);
72
- if (!distDirs.includes(distDir)) distDirs.push(distDir);
83
+ pushDistDirs(realScript);
73
84
  }
74
85
  }
75
86
  } catch {
76
87
  }
88
+ try {
89
+ const openclawBin = execFileSync("which", ["openclaw"], {
90
+ encoding: "utf8",
91
+ stdio: ["ignore", "pipe", "ignore"]
92
+ }).trim();
93
+ if (openclawBin) {
94
+ const { realpathSync } = await import("fs");
95
+ pushDistDirs(realpathSync(openclawBin));
96
+ }
97
+ } catch {
98
+ }
77
99
  for (const dir of distDirs) {
78
100
  try {
79
101
  const files = readdirSync(dir);
@@ -88,7 +110,10 @@ async function findRuntimeModules() {
88
110
  return candidates;
89
111
  }
90
112
  async function resolveProviderApiKey(providerId, apiKeyValue, gatewayConfig, agentDir) {
91
- const cacheKey = `provider:${providerId}`;
113
+ const resolvedAgentDir = path.resolve(
114
+ agentDir ?? path.join(os.homedir(), ".openclaw", "agents", "main", "agent")
115
+ );
116
+ const cacheKey = `provider:${providerId}:agentDir:${resolvedAgentDir}`;
92
117
  if (resolvedCache.has(cacheKey)) {
93
118
  return resolvedCache.get(cacheKey);
94
119
  }
@@ -104,7 +129,6 @@ async function resolveProviderApiKey(providerId, apiKeyValue, gatewayConfig, age
104
129
  const resolver = await getGatewayResolver();
105
130
  if (resolver) {
106
131
  try {
107
- const resolvedAgentDir = agentDir ?? path.join(os.homedir(), ".openclaw", "agents", "main", "agent");
108
132
  const auth = await resolver({ provider: providerId, cfg: gatewayConfig, agentDir: resolvedAgentDir });
109
133
  if (auth?.apiKey) {
110
134
  resolved = auth.apiKey;
@@ -154,10 +178,16 @@ function clearSecretCache() {
154
178
  _resolverLoaded = false;
155
179
  _resolverNextRetryAt = 0;
156
180
  }
181
+ function __setGatewayResolverForTest(resolver) {
182
+ _resolveApiKeyForProvider = resolver;
183
+ _resolverLoaded = resolver !== null;
184
+ _resolverNextRetryAt = 0;
185
+ }
157
186
 
158
187
  export {
159
188
  resolveProviderApiKey,
160
189
  getGatewayRuntimeAuthForModel,
161
- clearSecretCache
190
+ clearSecretCache,
191
+ __setGatewayResolverForTest
162
192
  };
163
- //# sourceMappingURL=chunk-M5ZBBBJI.js.map
193
+ //# sourceMappingURL=chunk-XZ2TIKGC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/resolve-provider-secret.ts"],"sourcesContent":["import { log } from \"./logger.js\";\nimport { readEnvVar } from \"./runtime/env.js\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\n/**\n * Resolve a provider API key using OpenClaw's own auth resolution system.\n *\n * This module delegates to the gateway's `resolveApiKeyForProvider()` function,\n * which handles all secret reference formats (SecretRef objects, auth profiles,\n * \"secretref-managed\" markers, environment variables, etc.) using the same\n * codepath the gateway uses for its own agent sessions.\n *\n * For plain-text API keys, a fast path returns them directly without\n * involving the gateway auth system.\n *\n * Results are cached per provider for the gateway process lifetime.\n */\n\ntype ResolveApiKeyFn = (params: {\n provider: string;\n cfg?: unknown;\n agentDir?: string;\n}) => Promise<{ apiKey?: string; source?: string; mode?: string } | null>;\n\n/**\n * Resolve request-ready auth for a model, including provider-owned transforms\n * (e.g., OAuth token exchange, base URL override for openai-codex).\n */\nexport type GetRuntimeAuthForModelFn = (params: {\n model: { provider: string; id: string; api?: string; baseUrl?: string };\n cfg?: unknown;\n workspaceDir?: string;\n}) => Promise<{\n apiKey?: string;\n baseUrl?: string;\n source?: string;\n mode?: string;\n profileId?: string;\n} | null>;\n\nlet _resolveApiKeyForProvider: ResolveApiKeyFn | null = null;\nlet _getRuntimeAuthForModel: GetRuntimeAuthForModelFn | null = null;\nlet _resolverLoaded = false;\nlet _resolverNextRetryAt = 0;\nconst RESOLVER_RETRY_BACKOFF_MS = 60_000; // 1 minute between retries after first failure\nconst resolvedCache = new Map<string, string | undefined>();\n\n/**\n * Lazily load the gateway's resolveApiKeyForProvider function.\n * Returns null if not available (e.g., running outside the gateway process).\n */\nasync function getGatewayResolver(): Promise<ResolveApiKeyFn | null> {\n if (_resolverLoaded) {\n return _resolveApiKeyForProvider;\n }\n // Backoff: don't re-scan filesystem on every call when module wasn't found.\n // After a failure, wait RESOLVER_RETRY_BACKOFF_MS before trying again.\n if (_resolverNextRetryAt > 0 && Date.now() < _resolverNextRetryAt) {\n return null;\n }\n\n try {\n // The gateway bundles this in a runtime chunk — import it dynamically.\n // This import path is stable across gateway versions since it's a named runtime export.\n const candidates = [\n // Try glob-matching the runtime module name (hash varies per build)\n ...await findRuntimeModules(),\n ];\n\n const { pathToFileURL } = await import(\"node:url\");\n for (const candidate of candidates) {\n try {\n // Convert native path to file:// URL for cross-platform ESM import compatibility\n const importUrl = pathToFileURL(candidate).href;\n const mod = await import(importUrl);\n if (typeof mod.resolveApiKeyForProvider === \"function\") {\n _resolveApiKeyForProvider = mod.resolveApiKeyForProvider;\n if (typeof mod.getRuntimeAuthForModel === \"function\") {\n _getRuntimeAuthForModel = mod.getRuntimeAuthForModel;\n log.debug(\"loaded gateway getRuntimeAuthForModel from runtime module\");\n }\n _resolverLoaded = true;\n log.debug(\"loaded gateway resolveApiKeyForProvider from runtime module\");\n return _resolveApiKeyForProvider;\n }\n } catch {\n // Try next candidate\n }\n }\n } catch {\n // Silent\n }\n\n // Backoff before retrying — avoid repeated fs scanning.\n // Retries after RESOLVER_RETRY_BACKOFF_MS so the resolver can\n // recover if the gateway restarts or the module becomes available.\n _resolverNextRetryAt = Date.now() + RESOLVER_RETRY_BACKOFF_MS;\n log.debug(`gateway resolveApiKeyForProvider not available — will retry after ${RESOLVER_RETRY_BACKOFF_MS / 1000}s`);\n return null;\n}\n\n/**\n * Find the gateway's model-auth runtime module by scanning the dist directory.\n * Uses require.resolve to find the openclaw package regardless of install method.\n */\nasync function findRuntimeModules(): Promise<string[]> {\n const { readdirSync } = await import(\"node:fs\");\n const { createRequire } = await import(\"node:module\");\n const { execFileSync } = await import(\"node:child_process\");\n const candidates: string[] = [];\n\n // Discover the openclaw dist directory from the installed package,\n // regardless of how it was installed (Homebrew, npm global, local, etc.)\n const distDirs: string[] = [];\n const pushDistDirs = (entryPath: string): void => {\n const resolvedEntryDir = path.dirname(entryPath);\n const packageRoot = path.basename(resolvedEntryDir) === \"dist\"\n ? path.resolve(resolvedEntryDir, \"..\")\n : resolvedEntryDir;\n const candidateDistDirs = [\n path.join(packageRoot, \"dist\"),\n path.join(packageRoot, \"..\", \"dist\"),\n ];\n for (const candidate of candidateDistDirs) {\n const resolved = path.resolve(candidate);\n if (!distDirs.includes(resolved)) distDirs.push(resolved);\n }\n };\n\n try {\n // require.resolve finds the package from the current process context\n const req = createRequire(import.meta.url);\n const openclawMain = req.resolve(\"openclaw\");\n pushDistDirs(openclawMain);\n } catch {\n // openclaw not resolvable from plugin context — try alternate paths\n }\n\n // Fallback: infer from the running process (gateway runs from its own dist/)\n // Use fs.realpathSync to resolve symlinks (e.g., /usr/local/bin/openclaw → actual path)\n try {\n const { realpathSync } = await import(\"node:fs\");\n const mainScript = process.argv[1];\n if (mainScript) {\n const realScript = realpathSync(mainScript);\n if (realScript.includes(\"openclaw\")) {\n pushDistDirs(realScript);\n }\n }\n } catch {\n // Silent\n }\n\n // Fallback: inspect the installed openclaw binary on PATH (Homebrew/global npm).\n try {\n const openclawBin = execFileSync(\"which\", [\"openclaw\"], {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n if (openclawBin) {\n const { realpathSync } = await import(\"node:fs\");\n pushDistDirs(realpathSync(openclawBin));\n }\n } catch {\n // Silent\n }\n\n for (const dir of distDirs) {\n try {\n const files = readdirSync(dir);\n for (const f of files) {\n if (f.startsWith(\"runtime-model-auth.runtime-\") && f.endsWith(\".js\")) {\n candidates.push(path.join(dir, f));\n }\n }\n } catch {\n // Directory doesn't exist — skip\n }\n }\n\n return candidates;\n}\n\n/**\n * Resolve a provider API key from various OpenClaw formats.\n *\n * Resolution order:\n * 1. Plain-text string → returned immediately\n * 2. Gateway's resolveApiKeyForProvider → handles all secret ref formats\n * 3. Environment variable fallback (PROVIDER_NAME_API_KEY)\n * 4. undefined → provider is skipped in the fallback chain\n */\nexport async function resolveProviderApiKey(\n providerId: string,\n apiKeyValue: unknown,\n gatewayConfig?: unknown,\n agentDir?: string,\n): Promise<string | undefined> {\n const resolvedAgentDir = path.resolve(\n agentDir ?? path.join(os.homedir(), \".openclaw\", \"agents\", \"main\", \"agent\"),\n );\n\n // Check cache first\n const cacheKey = `provider:${providerId}:agentDir:${resolvedAgentDir}`;\n if (resolvedCache.has(cacheKey)) {\n return resolvedCache.get(cacheKey);\n }\n\n let resolved: string | undefined;\n\n // Fast path: plain-text string that looks like an actual API key\n if (typeof apiKeyValue === \"string\" && apiKeyValue.trim().length > 0) {\n // Skip known non-API-key markers used by the gateway for auth modes\n // that don't use bearer tokens (OAuth, local endpoints, GCP credentials)\n if (\n apiKeyValue === \"secretref-managed\" ||\n apiKeyValue.endsWith(\"-oauth\") ||\n apiKeyValue.endsWith(\"-local\") ||\n apiKeyValue === \"lm-studio\" ||\n apiKeyValue.startsWith(\"gcp-\")\n ) {\n // Fall through to gateway resolver / env var fallback\n } else {\n resolved = apiKeyValue;\n resolvedCache.set(cacheKey, resolved);\n return resolved;\n }\n }\n\n // The API key is either a SecretRef object, \"secretref-managed\", or empty.\n // Try the gateway's own auth resolution system first.\n const resolver = await getGatewayResolver();\n if (resolver) {\n try {\n const auth = await resolver({ provider: providerId, cfg: gatewayConfig, agentDir: resolvedAgentDir });\n if (auth?.apiKey) {\n resolved = auth.apiKey;\n log.debug(`resolved API key for provider \"${providerId}\" via gateway auth (source: ${auth.source ?? \"unknown\"}, mode: ${auth.mode ?? \"unknown\"})`);\n resolvedCache.set(cacheKey, resolved);\n return resolved;\n }\n } catch (err) {\n log.debug(\n `gateway auth resolution failed for provider \"${providerId}\": ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n // Environment variable fallback\n resolved = resolveFromEnv(providerId);\n if (resolved) {\n log.debug(`resolved API key for provider \"${providerId}\" from environment variable`);\n } else {\n log.debug(`could not resolve API key for provider \"${providerId}\" — skipping`);\n }\n\n // Only cache successful resolutions — failures are retried on next call\n // so providers can recover after transient issues (e.g., 1Password agent restart)\n if (resolved) {\n resolvedCache.set(cacheKey, resolved);\n }\n return resolved;\n}\n\n/**\n * Try to resolve an API key from environment variables.\n */\nfunction resolveFromEnv(providerId: string): string | undefined {\n const normalized = providerId.toUpperCase().replace(/[^A-Z0-9]/g, \"_\");\n const candidates = [\n `${normalized}_API_KEY`,\n `${normalized}_TOKEN`,\n ];\n for (const envVar of candidates) {\n const value = readEnvVar(envVar);\n if (value && value.trim().length > 0) {\n return value.trim();\n }\n }\n return undefined;\n}\n\n/**\n * Get the gateway's getRuntimeAuthForModel function, if available.\n * This resolves request-ready auth including provider-owned transforms\n * (OAuth token exchange, base URL override for codex/copilot/etc.).\n * Must be called after at least one resolveProviderApiKey() call to\n * trigger the lazy module load.\n */\nexport async function getGatewayRuntimeAuthForModel(): Promise<GetRuntimeAuthForModelFn | null> {\n // Ensure the runtime module has been loaded\n await getGatewayResolver();\n return _getRuntimeAuthForModel;\n}\n\n/**\n * Clear the resolution cache (useful for testing or key rotation).\n */\nexport function clearSecretCache(): void {\n resolvedCache.clear();\n _resolveApiKeyForProvider = null;\n _getRuntimeAuthForModel = null;\n _resolverLoaded = false;\n _resolverNextRetryAt = 0;\n}\n\nexport function __setGatewayResolverForTest(resolver: ResolveApiKeyFn | null): void {\n _resolveApiKeyForProvider = resolver;\n _resolverLoaded = resolver !== null;\n _resolverNextRetryAt = 0;\n}\n"],"mappings":";;;;;;;;AAEA,OAAO,UAAU;AACjB,OAAO,QAAQ;AAsCf,IAAI,4BAAoD;AACxD,IAAI,0BAA2D;AAC/D,IAAI,kBAAkB;AACtB,IAAI,uBAAuB;AAC3B,IAAM,4BAA4B;AAClC,IAAM,gBAAgB,oBAAI,IAAgC;AAM1D,eAAe,qBAAsD;AACnE,MAAI,iBAAiB;AACnB,WAAO;AAAA,EACT;AAGA,MAAI,uBAAuB,KAAK,KAAK,IAAI,IAAI,sBAAsB;AACjE,WAAO;AAAA,EACT;AAEA,MAAI;AAGF,UAAM,aAAa;AAAA;AAAA,MAEjB,GAAG,MAAM,mBAAmB;AAAA,IAC9B;AAEA,UAAM,EAAE,cAAc,IAAI,MAAM,OAAO,KAAU;AACjD,eAAW,aAAa,YAAY;AAClC,UAAI;AAEF,cAAM,YAAY,cAAc,SAAS,EAAE;AAC3C,cAAM,MAAM,MAAM,OAAO;AACzB,YAAI,OAAO,IAAI,6BAA6B,YAAY;AACtD,sCAA4B,IAAI;AAChC,cAAI,OAAO,IAAI,2BAA2B,YAAY;AACpD,sCAA0B,IAAI;AAC9B,gBAAI,MAAM,2DAA2D;AAAA,UACvE;AACA,4BAAkB;AAClB,cAAI,MAAM,6DAA6D;AACvE,iBAAO;AAAA,QACT;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAKA,yBAAuB,KAAK,IAAI,IAAI;AACpC,MAAI,MAAM,0EAAqE,4BAA4B,GAAI,GAAG;AAClH,SAAO;AACT;AAMA,eAAe,qBAAwC;AACrD,QAAM,EAAE,YAAY,IAAI,MAAM,OAAO,IAAS;AAC9C,QAAM,EAAE,cAAc,IAAI,MAAM,OAAO,QAAa;AACpD,QAAM,EAAE,aAAa,IAAI,MAAM,OAAO,eAAoB;AAC1D,QAAM,aAAuB,CAAC;AAI9B,QAAM,WAAqB,CAAC;AAC5B,QAAM,eAAe,CAAC,cAA4B;AAChD,UAAM,mBAAmB,KAAK,QAAQ,SAAS;AAC/C,UAAM,cAAc,KAAK,SAAS,gBAAgB,MAAM,SACpD,KAAK,QAAQ,kBAAkB,IAAI,IACnC;AACJ,UAAM,oBAAoB;AAAA,MACxB,KAAK,KAAK,aAAa,MAAM;AAAA,MAC7B,KAAK,KAAK,aAAa,MAAM,MAAM;AAAA,IACrC;AACA,eAAW,aAAa,mBAAmB;AACzC,YAAM,WAAW,KAAK,QAAQ,SAAS;AACvC,UAAI,CAAC,SAAS,SAAS,QAAQ,EAAG,UAAS,KAAK,QAAQ;AAAA,IAC1D;AAAA,EACF;AAEA,MAAI;AAEF,UAAM,MAAM,cAAc,YAAY,GAAG;AACzC,UAAM,eAAe,IAAI,QAAQ,UAAU;AAC3C,iBAAa,YAAY;AAAA,EAC3B,QAAQ;AAAA,EAER;AAIA,MAAI;AACF,UAAM,EAAE,aAAa,IAAI,MAAM,OAAO,IAAS;AAC/C,UAAM,aAAa,QAAQ,KAAK,CAAC;AACjC,QAAI,YAAY;AACd,YAAM,aAAa,aAAa,UAAU;AAC1C,UAAI,WAAW,SAAS,UAAU,GAAG;AACnC,qBAAa,UAAU;AAAA,MACzB;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAGA,MAAI;AACF,UAAM,cAAc,aAAa,SAAS,CAAC,UAAU,GAAG;AAAA,MACtD,UAAU;AAAA,MACV,OAAO,CAAC,UAAU,QAAQ,QAAQ;AAAA,IACpC,CAAC,EAAE,KAAK;AACR,QAAI,aAAa;AACf,YAAM,EAAE,aAAa,IAAI,MAAM,OAAO,IAAS;AAC/C,mBAAa,aAAa,WAAW,CAAC;AAAA,IACxC;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,aAAW,OAAO,UAAU;AAC1B,QAAI;AACF,YAAM,QAAQ,YAAY,GAAG;AAC7B,iBAAW,KAAK,OAAO;AACrB,YAAI,EAAE,WAAW,6BAA6B,KAAK,EAAE,SAAS,KAAK,GAAG;AACpE,qBAAW,KAAK,KAAK,KAAK,KAAK,CAAC,CAAC;AAAA,QACnC;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AACT;AAWA,eAAsB,sBACpB,YACA,aACA,eACA,UAC6B;AAC7B,QAAM,mBAAmB,KAAK;AAAA,IAC5B,YAAY,KAAK,KAAK,GAAG,QAAQ,GAAG,aAAa,UAAU,QAAQ,OAAO;AAAA,EAC5E;AAGA,QAAM,WAAW,YAAY,UAAU,aAAa,gBAAgB;AACpE,MAAI,cAAc,IAAI,QAAQ,GAAG;AAC/B,WAAO,cAAc,IAAI,QAAQ;AAAA,EACnC;AAEA,MAAI;AAGJ,MAAI,OAAO,gBAAgB,YAAY,YAAY,KAAK,EAAE,SAAS,GAAG;AAGpE,QACE,gBAAgB,uBAChB,YAAY,SAAS,QAAQ,KAC7B,YAAY,SAAS,QAAQ,KAC7B,gBAAgB,eAChB,YAAY,WAAW,MAAM,GAC7B;AAAA,IAEF,OAAO;AACL,iBAAW;AACX,oBAAc,IAAI,UAAU,QAAQ;AACpC,aAAO;AAAA,IACT;AAAA,EACF;AAIA,QAAM,WAAW,MAAM,mBAAmB;AAC1C,MAAI,UAAU;AACZ,QAAI;AACF,YAAM,OAAO,MAAM,SAAS,EAAE,UAAU,YAAY,KAAK,eAAe,UAAU,iBAAiB,CAAC;AACpG,UAAI,MAAM,QAAQ;AAChB,mBAAW,KAAK;AAChB,YAAI,MAAM,kCAAkC,UAAU,+BAA+B,KAAK,UAAU,SAAS,WAAW,KAAK,QAAQ,SAAS,GAAG;AACjJ,sBAAc,IAAI,UAAU,QAAQ;AACpC,eAAO;AAAA,MACT;AAAA,IACF,SAAS,KAAK;AACZ,UAAI;AAAA,QACF,gDAAgD,UAAU,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAClH;AAAA,IACF;AAAA,EACF;AAGA,aAAW,eAAe,UAAU;AACpC,MAAI,UAAU;AACZ,QAAI,MAAM,kCAAkC,UAAU,6BAA6B;AAAA,EACrF,OAAO;AACL,QAAI,MAAM,2CAA2C,UAAU,mBAAc;AAAA,EAC/E;AAIA,MAAI,UAAU;AACZ,kBAAc,IAAI,UAAU,QAAQ;AAAA,EACtC;AACA,SAAO;AACT;AAKA,SAAS,eAAe,YAAwC;AAC9D,QAAM,aAAa,WAAW,YAAY,EAAE,QAAQ,cAAc,GAAG;AACrE,QAAM,aAAa;AAAA,IACjB,GAAG,UAAU;AAAA,IACb,GAAG,UAAU;AAAA,EACf;AACA,aAAW,UAAU,YAAY;AAC/B,UAAM,QAAQ,WAAW,MAAM;AAC/B,QAAI,SAAS,MAAM,KAAK,EAAE,SAAS,GAAG;AACpC,aAAO,MAAM,KAAK;AAAA,IACpB;AAAA,EACF;AACA,SAAO;AACT;AASA,eAAsB,gCAA0E;AAE9F,QAAM,mBAAmB;AACzB,SAAO;AACT;AAKO,SAAS,mBAAyB;AACvC,gBAAc,MAAM;AACpB,8BAA4B;AAC5B,4BAA0B;AAC1B,oBAAkB;AAClB,yBAAuB;AACzB;AAEO,SAAS,4BAA4B,UAAwC;AAClF,8BAA4B;AAC5B,oBAAkB,aAAa;AAC/B,yBAAuB;AACzB;","names":[]}
@@ -0,0 +1,140 @@
1
+ import {
2
+ countRecallTokenOverlap,
3
+ normalizeRecallTokens
4
+ } from "./chunk-DT5TVLJE.js";
5
+
6
+ // src/direct-answer.ts
7
+ var FILTER_LABELS = {
8
+ nonActiveStatus: "non-active-status",
9
+ notTrustedZone: "not-trusted-zone",
10
+ ineligibleTaxonomyBucket: "ineligible-taxonomy-bucket",
11
+ belowImportanceFloor: "below-importance-floor",
12
+ entityRefMismatch: "entity-ref-mismatch",
13
+ belowTokenOverlapFloor: "below-token-overlap-floor"
14
+ };
15
+ function isDirectAnswerEligible(input) {
16
+ const { query, candidates, config, queryEntityRefs } = input;
17
+ if (!config.enabled) {
18
+ return {
19
+ eligible: false,
20
+ reason: "disabled",
21
+ narrative: "direct-answer tier is disabled",
22
+ filteredBy: []
23
+ };
24
+ }
25
+ const queryTokens = new Set(normalizeRecallTokens(query));
26
+ if (queryTokens.size === 0) {
27
+ return {
28
+ eligible: false,
29
+ reason: "empty-query",
30
+ narrative: "query has no searchable tokens after normalization",
31
+ filteredBy: []
32
+ };
33
+ }
34
+ if (candidates.length === 0) {
35
+ return {
36
+ eligible: false,
37
+ reason: "no-candidates",
38
+ narrative: "no candidates supplied",
39
+ filteredBy: []
40
+ };
41
+ }
42
+ const filteredBy = [];
43
+ let working = candidates;
44
+ working = applyFilter(working, filteredBy, FILTER_LABELS.nonActiveStatus, (c) => {
45
+ const status = c.memory.frontmatter.status ?? "active";
46
+ return status === "active";
47
+ });
48
+ working = applyFilter(
49
+ working,
50
+ filteredBy,
51
+ FILTER_LABELS.notTrustedZone,
52
+ (c) => c.trustZone === "trusted"
53
+ );
54
+ working = applyFilter(
55
+ working,
56
+ filteredBy,
57
+ FILTER_LABELS.ineligibleTaxonomyBucket,
58
+ (c) => c.taxonomyBucket !== null && config.eligibleTaxonomyBuckets.includes(c.taxonomyBucket)
59
+ );
60
+ working = applyFilter(working, filteredBy, FILTER_LABELS.belowImportanceFloor, (c) => {
61
+ if (c.memory.frontmatter.verificationState === "user_confirmed") return true;
62
+ return c.importanceScore >= config.importanceFloor;
63
+ });
64
+ if (queryEntityRefs && queryEntityRefs.length > 0) {
65
+ const normRefs = new Set(queryEntityRefs.map((r) => r.toLowerCase()));
66
+ working = applyFilter(working, filteredBy, FILTER_LABELS.entityRefMismatch, (c) => {
67
+ const ref = c.memory.frontmatter.entityRef;
68
+ if (!ref) return true;
69
+ return normRefs.has(ref.toLowerCase());
70
+ });
71
+ }
72
+ if (working.length === 0) {
73
+ return {
74
+ eligible: false,
75
+ reason: "no-eligible-candidates",
76
+ narrative: "no candidates survived eligibility filters",
77
+ filteredBy
78
+ };
79
+ }
80
+ const scored = working.map((candidate) => {
81
+ const searchable = `${candidate.memory.frontmatter.tags?.join(" ") ?? ""} ${candidate.memory.content}`.trim();
82
+ const matches = countRecallTokenOverlap(queryTokens, searchable);
83
+ return { candidate, tokenOverlap: matches / queryTokens.size };
84
+ });
85
+ const overlapSurvivors = scored.filter((s) => s.tokenOverlap >= config.tokenOverlapFloor);
86
+ if (overlapSurvivors.length < scored.length) {
87
+ filteredBy.push(FILTER_LABELS.belowTokenOverlapFloor);
88
+ }
89
+ if (overlapSurvivors.length === 0) {
90
+ return {
91
+ eligible: false,
92
+ reason: "below-token-overlap-floor",
93
+ narrative: `no candidate met token-overlap floor ${config.tokenOverlapFloor}`,
94
+ filteredBy
95
+ };
96
+ }
97
+ overlapSurvivors.sort(compareScored);
98
+ if (overlapSurvivors.length >= 2) {
99
+ const topScore = scoreFor(overlapSurvivors[0]);
100
+ const secondScore = scoreFor(overlapSurvivors[1]);
101
+ if (topScore - secondScore < config.ambiguityMargin) {
102
+ return {
103
+ eligible: false,
104
+ reason: "ambiguous",
105
+ narrative: `top two candidates within ambiguityMargin ${config.ambiguityMargin}`,
106
+ filteredBy
107
+ };
108
+ }
109
+ }
110
+ const winner = overlapSurvivors[0];
111
+ const bucket = winner.candidate.taxonomyBucket ?? "unknown";
112
+ return {
113
+ eligible: true,
114
+ reason: "eligible",
115
+ winner: winner.candidate,
116
+ tokenOverlap: winner.tokenOverlap,
117
+ narrative: `trusted ${bucket}, unambiguous, token-overlap ${winner.tokenOverlap.toFixed(2)}`,
118
+ filteredBy
119
+ };
120
+ }
121
+ function applyFilter(working, filteredBy, label, keep) {
122
+ const before = working.length;
123
+ const next = working.filter(keep);
124
+ if (next.length < before) filteredBy.push(label);
125
+ return next;
126
+ }
127
+ function scoreFor(s) {
128
+ return s.candidate.matchScore ?? s.tokenOverlap;
129
+ }
130
+ function compareScored(a, b) {
131
+ const diff = scoreFor(b) - scoreFor(a);
132
+ if (diff !== 0) return diff;
133
+ return a.candidate.memory.path.localeCompare(b.candidate.memory.path);
134
+ }
135
+
136
+ export {
137
+ FILTER_LABELS,
138
+ isDirectAnswerEligible
139
+ };
140
+ //# sourceMappingURL=chunk-Y4FHOFJ2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/direct-answer.ts"],"sourcesContent":["/**\n * Direct-answer retrieval tier eligibility (issue #518 slice 2).\n *\n * This module is a pure decision layer. It takes a query, a set of\n * caller-resolved candidates (each already decorated with trust-zone,\n * taxonomy-bucket, and importance information), and the direct-answer\n * config, then returns an eligibility verdict.\n *\n * Keeping the module pure means:\n *\n * - Tests do not need a trust-zones store, taxonomy resolver, or importance\n * scorer on disk.\n * - Slice 3 (retrieval.ts wiring) is responsible for resolving those signals\n * before calling in; the wiring layer decides where candidates come from\n * (entity index, token prefilter, etc.). This module only decides\n * whether the surfaced candidates add up to a confident direct answer.\n *\n * Not wired into retrieval yet — see slice 3.\n */\n\nimport type { MemoryFile, MemoryStatus } from \"./types.js\";\nimport type { TrustZoneName } from \"./trust-zones.js\";\nimport {\n countRecallTokenOverlap,\n normalizeRecallTokens,\n} from \"./recall-tokenization.js\";\n\n/**\n * Caller-supplied candidate.\n *\n * `trustZone`, `taxonomyBucket`, and `importanceScore` are resolved outside\n * this module because each comes from a different subsystem. Passing them\n * as inputs keeps the function deterministic and easy to unit-test.\n *\n * `matchScore` is optional; if omitted, candidates are ranked by\n * token-overlap ratio. Callers that already computed a better ranking\n * score (e.g. BM25, vector similarity) can supply it to drive the\n * ambiguity check.\n */\nexport interface DirectAnswerCandidate {\n memory: MemoryFile;\n trustZone: TrustZoneName | null;\n taxonomyBucket: string | null;\n importanceScore: number;\n matchScore?: number;\n}\n\nexport interface DirectAnswerConfig {\n enabled: boolean;\n tokenOverlapFloor: number;\n importanceFloor: number;\n ambiguityMargin: number;\n eligibleTaxonomyBuckets: string[];\n}\n\nexport interface DirectAnswerInput {\n query: string;\n candidates: DirectAnswerCandidate[];\n config: DirectAnswerConfig;\n /**\n * Optional entity-ref hints resolved from the query upstream. When\n * supplied, a candidate with a set `entityRef` must match one of these\n * (case-insensitive) to remain eligible. Candidates without an\n * `entityRef` are allowed through regardless.\n */\n queryEntityRefs?: string[];\n}\n\nexport type DirectAnswerReason =\n | \"disabled\"\n | \"empty-query\"\n | \"no-candidates\"\n | \"no-eligible-candidates\"\n | \"below-token-overlap-floor\"\n | \"ambiguous\"\n | \"eligible\";\n\nexport interface DirectAnswerResult {\n eligible: boolean;\n reason: DirectAnswerReason;\n /** Winning candidate when eligible. */\n winner?: DirectAnswerCandidate;\n /** Computed token-overlap ratio (0..1) of the winner. */\n tokenOverlap?: number;\n /**\n * Human-readable summary suitable for\n * `RecallTierExplain.tierReason`.\n */\n narrative: string;\n /**\n * Filter labels that eliminated at least one candidate along the way.\n * Populated regardless of eligibility so the caller can surface the\n * narrowing steps in `RecallTierExplain.filteredBy`.\n */\n filteredBy: string[];\n}\n\n/** Filter labels — exported so callers and tests can match them structurally. */\nexport const FILTER_LABELS = {\n nonActiveStatus: \"non-active-status\",\n notTrustedZone: \"not-trusted-zone\",\n ineligibleTaxonomyBucket: \"ineligible-taxonomy-bucket\",\n belowImportanceFloor: \"below-importance-floor\",\n entityRefMismatch: \"entity-ref-mismatch\",\n belowTokenOverlapFloor: \"below-token-overlap-floor\",\n} as const;\n\ninterface ScoredCandidate {\n candidate: DirectAnswerCandidate;\n tokenOverlap: number;\n}\n\n/**\n * Determine whether a query can be served by the direct-answer tier.\n *\n * Decision ladder, in order:\n *\n * 1. config.enabled === false → \"disabled\"\n * 2. empty query tokens → \"empty-query\"\n * 3. empty candidates → \"no-candidates\"\n * 4. hard filters drop all candidates → \"no-eligible-candidates\"\n * 5. token-overlap floor drops all → \"below-token-overlap-floor\"\n * 6. top two candidates within ambiguityMargin → \"ambiguous\"\n * 7. otherwise → \"eligible\"\n */\nexport function isDirectAnswerEligible(\n input: DirectAnswerInput,\n): DirectAnswerResult {\n const { query, candidates, config, queryEntityRefs } = input;\n\n if (!config.enabled) {\n return {\n eligible: false,\n reason: \"disabled\",\n narrative: \"direct-answer tier is disabled\",\n filteredBy: [],\n };\n }\n\n const queryTokens = new Set(normalizeRecallTokens(query));\n if (queryTokens.size === 0) {\n return {\n eligible: false,\n reason: \"empty-query\",\n narrative: \"query has no searchable tokens after normalization\",\n filteredBy: [],\n };\n }\n\n if (candidates.length === 0) {\n return {\n eligible: false,\n reason: \"no-candidates\",\n narrative: \"no candidates supplied\",\n filteredBy: [],\n };\n }\n\n const filteredBy: string[] = [];\n let working: DirectAnswerCandidate[] = candidates;\n\n working = applyFilter(working, filteredBy, FILTER_LABELS.nonActiveStatus, (c) => {\n const status: MemoryStatus = c.memory.frontmatter.status ?? \"active\";\n return status === \"active\";\n });\n\n working = applyFilter(working, filteredBy, FILTER_LABELS.notTrustedZone, (c) =>\n c.trustZone === \"trusted\",\n );\n\n working = applyFilter(\n working,\n filteredBy,\n FILTER_LABELS.ineligibleTaxonomyBucket,\n (c) =>\n c.taxonomyBucket !== null &&\n config.eligibleTaxonomyBuckets.includes(c.taxonomyBucket),\n );\n\n working = applyFilter(working, filteredBy, FILTER_LABELS.belowImportanceFloor, (c) => {\n if (c.memory.frontmatter.verificationState === \"user_confirmed\") return true;\n return c.importanceScore >= config.importanceFloor;\n });\n\n if (queryEntityRefs && queryEntityRefs.length > 0) {\n const normRefs = new Set(queryEntityRefs.map((r) => r.toLowerCase()));\n working = applyFilter(working, filteredBy, FILTER_LABELS.entityRefMismatch, (c) => {\n const ref = c.memory.frontmatter.entityRef;\n if (!ref) return true;\n return normRefs.has(ref.toLowerCase());\n });\n }\n\n if (working.length === 0) {\n return {\n eligible: false,\n reason: \"no-eligible-candidates\",\n narrative: \"no candidates survived eligibility filters\",\n filteredBy,\n };\n }\n\n const scored: ScoredCandidate[] = working.map((candidate) => {\n const searchable =\n `${candidate.memory.frontmatter.tags?.join(\" \") ?? \"\"} ${candidate.memory.content}`.trim();\n const matches = countRecallTokenOverlap(queryTokens, searchable);\n return { candidate, tokenOverlap: matches / queryTokens.size };\n });\n\n const overlapSurvivors = scored.filter((s) => s.tokenOverlap >= config.tokenOverlapFloor);\n if (overlapSurvivors.length < scored.length) {\n filteredBy.push(FILTER_LABELS.belowTokenOverlapFloor);\n }\n\n if (overlapSurvivors.length === 0) {\n return {\n eligible: false,\n reason: \"below-token-overlap-floor\",\n narrative: `no candidate met token-overlap floor ${config.tokenOverlapFloor}`,\n filteredBy,\n };\n }\n\n overlapSurvivors.sort(compareScored);\n\n if (overlapSurvivors.length >= 2) {\n const topScore = scoreFor(overlapSurvivors[0]);\n const secondScore = scoreFor(overlapSurvivors[1]);\n if (topScore - secondScore < config.ambiguityMargin) {\n return {\n eligible: false,\n reason: \"ambiguous\",\n narrative: `top two candidates within ambiguityMargin ${config.ambiguityMargin}`,\n filteredBy,\n };\n }\n }\n\n const winner = overlapSurvivors[0];\n const bucket = winner.candidate.taxonomyBucket ?? \"unknown\";\n return {\n eligible: true,\n reason: \"eligible\",\n winner: winner.candidate,\n tokenOverlap: winner.tokenOverlap,\n narrative: `trusted ${bucket}, unambiguous, token-overlap ${winner.tokenOverlap.toFixed(2)}`,\n filteredBy,\n };\n}\n\nfunction applyFilter(\n working: DirectAnswerCandidate[],\n filteredBy: string[],\n label: string,\n keep: (c: DirectAnswerCandidate) => boolean,\n): DirectAnswerCandidate[] {\n const before = working.length;\n const next = working.filter(keep);\n if (next.length < before) filteredBy.push(label);\n return next;\n}\n\nfunction scoreFor(s: ScoredCandidate): number {\n return s.candidate.matchScore ?? s.tokenOverlap;\n}\n\nfunction compareScored(a: ScoredCandidate, b: ScoredCandidate): number {\n const diff = scoreFor(b) - scoreFor(a);\n if (diff !== 0) return diff;\n // Stable secondary key on path so the comparator returns 0 only for equal\n // entries (CLAUDE.md rule 19).\n return a.candidate.memory.path.localeCompare(b.candidate.memory.path);\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,298 @@
1
+ // src/recall-mmr.ts
2
+ var DEFAULT_LAMBDA = 0.7;
3
+ var DEFAULT_TOP_N = 40;
4
+ var DEFAULT_DIVERSITY_SAMPLE_SIZE = 10;
5
+ function applyMmrToCandidates(opts) {
6
+ const candidates = Array.isArray(opts.candidates) ? opts.candidates : [];
7
+ if (candidates.length === 0) return [];
8
+ const lambda = clampLambda(opts.lambda);
9
+ const topN = clampPositiveInt(opts.topN, DEFAULT_TOP_N);
10
+ const budget = clampPositiveInt(opts.budget, candidates.length);
11
+ if (budget <= 0) return [];
12
+ if (candidates.length === 1) return [candidates[0]];
13
+ const pool = candidates.slice(0, topN);
14
+ const tail = candidates.slice(topN);
15
+ const relevance = computeRelevanceScores(pool, opts.queryEmbedding);
16
+ const pairSim = /* @__PURE__ */ new Map();
17
+ const pairKey = (i, j) => i < j ? `${i}:${j}` : `${j}:${i}`;
18
+ const sim = (i, j) => {
19
+ if (i === j) return 1;
20
+ const key = pairKey(i, j);
21
+ const cached = pairSim.get(key);
22
+ if (cached !== void 0) return cached;
23
+ const a = pool[i];
24
+ const b = pool[j];
25
+ const s = similarity(a, b);
26
+ pairSim.set(key, s);
27
+ return s;
28
+ };
29
+ const selectedIdx = [];
30
+ const remaining = /* @__PURE__ */ new Set();
31
+ for (let i = 0; i < pool.length; i += 1) remaining.add(i);
32
+ while (selectedIdx.length < budget && remaining.size > 0) {
33
+ let bestIdx = -1;
34
+ let bestMmr = Number.NEGATIVE_INFINITY;
35
+ for (const idx of remaining) {
36
+ const rel = relevance[idx] ?? 0;
37
+ let maxSimToSelected = 0;
38
+ if (selectedIdx.length > 0) {
39
+ for (const s of selectedIdx) {
40
+ const pairwise = sim(idx, s);
41
+ if (pairwise > maxSimToSelected) maxSimToSelected = pairwise;
42
+ }
43
+ }
44
+ const mmr = lambda * rel - (1 - lambda) * maxSimToSelected;
45
+ if (mmr > bestMmr || // Stable tie-breaker: prefer the earlier original position.
46
+ mmr === bestMmr && (bestIdx < 0 || idx < bestIdx)) {
47
+ bestMmr = mmr;
48
+ bestIdx = idx;
49
+ }
50
+ }
51
+ if (bestIdx < 0) break;
52
+ selectedIdx.push(bestIdx);
53
+ remaining.delete(bestIdx);
54
+ }
55
+ const selected = selectedIdx.map((i) => pool[i]);
56
+ if (selected.length < budget && tail.length > 0) {
57
+ for (const c of tail) {
58
+ if (selected.length >= budget) break;
59
+ selected.push(c);
60
+ }
61
+ }
62
+ return selected;
63
+ }
64
+ function summarizeMmrDiversity(before, after, sampleSize = DEFAULT_DIVERSITY_SAMPLE_SIZE) {
65
+ const n = clampPositiveInt(sampleSize, DEFAULT_DIVERSITY_SAMPLE_SIZE);
66
+ const beforeSlice = before.slice(0, n);
67
+ const afterSlice = after.slice(0, n);
68
+ let headReorderCount = 0;
69
+ const compareLength = Math.min(beforeSlice.length, afterSlice.length);
70
+ for (let i = 0; i < compareLength; i += 1) {
71
+ if (beforeSlice[i].id !== afterSlice[i].id) headReorderCount += 1;
72
+ }
73
+ return {
74
+ considered: before.length,
75
+ kept: after.length,
76
+ headReorderCount,
77
+ avgPairwiseSimBefore: averagePairwiseSimilarity(beforeSlice),
78
+ avgPairwiseSimAfter: averagePairwiseSimilarity(afterSlice)
79
+ };
80
+ }
81
+ function clampLambda(value) {
82
+ if (typeof value !== "number" || !Number.isFinite(value)) return DEFAULT_LAMBDA;
83
+ if (value < 0) return 0;
84
+ if (value > 1) return 1;
85
+ return value;
86
+ }
87
+ function clampPositiveInt(value, fallback) {
88
+ if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
89
+ if (value <= 0) return 0;
90
+ return Math.floor(value);
91
+ }
92
+ function computeRelevanceScores(pool, queryEmbedding) {
93
+ const canUseQueryEmbedding = Array.isArray(queryEmbedding) && queryEmbedding.length > 0;
94
+ if (canUseQueryEmbedding) {
95
+ const scores = [];
96
+ for (const c of pool) {
97
+ if (Array.isArray(c.embedding) && c.embedding.length > 0) {
98
+ scores.push(cosineSimilarity(queryEmbedding, c.embedding));
99
+ } else {
100
+ scores.push(normalizeFinite(c.score));
101
+ }
102
+ }
103
+ return normalizeVector(scores);
104
+ }
105
+ const raw = pool.map((c) => normalizeFinite(c.score));
106
+ return normalizeVector(raw);
107
+ }
108
+ function similarity(a, b) {
109
+ if (Array.isArray(a.embedding) && a.embedding.length > 0 && Array.isArray(b.embedding) && b.embedding.length > 0 && a.embedding.length === b.embedding.length) {
110
+ return cosineSimilarity(a.embedding, b.embedding);
111
+ }
112
+ return jaccardSimilarity(a.content ?? "", b.content ?? "");
113
+ }
114
+ function cosineSimilarity(a, b) {
115
+ if (a.length === 0 || b.length === 0) return 0;
116
+ const len = Math.min(a.length, b.length);
117
+ let dot = 0;
118
+ let na = 0;
119
+ let nb = 0;
120
+ for (let i = 0; i < len; i += 1) {
121
+ const av = a[i] ?? 0;
122
+ const bv = b[i] ?? 0;
123
+ dot += av * bv;
124
+ na += av * av;
125
+ nb += bv * bv;
126
+ }
127
+ if (na === 0 || nb === 0) return 0;
128
+ const cos = dot / (Math.sqrt(na) * Math.sqrt(nb));
129
+ if (cos < 0) return 0;
130
+ if (cos > 1) return 1;
131
+ return cos;
132
+ }
133
+ function normalizeTokens(text) {
134
+ if (!text) return /* @__PURE__ */ new Set();
135
+ const cleaned = text.toLowerCase().replace(/[^\p{L}\p{N}]+/gu, " ").trim();
136
+ if (cleaned.length === 0) {
137
+ const chars = /* @__PURE__ */ new Set();
138
+ for (const ch of text.toLowerCase()) {
139
+ if (/\s/.test(ch)) continue;
140
+ chars.add(ch);
141
+ }
142
+ return chars;
143
+ }
144
+ const tokens = /* @__PURE__ */ new Set();
145
+ for (const token of cleaned.split(/\s+/)) {
146
+ if (!token) continue;
147
+ if (token.length >= 2 && hasUnsegmentableScript(token)) {
148
+ for (const ch of token) tokens.add(ch);
149
+ } else {
150
+ tokens.add(token);
151
+ }
152
+ }
153
+ return tokens;
154
+ }
155
+ function hasUnsegmentableScript(token) {
156
+ return /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u.test(
157
+ token
158
+ );
159
+ }
160
+ function jaccardSimilarity(a, b) {
161
+ const ta = normalizeTokens(a);
162
+ const tb = normalizeTokens(b);
163
+ if (ta.size === 0 && tb.size === 0) return 0;
164
+ let intersection = 0;
165
+ for (const t of ta) if (tb.has(t)) intersection += 1;
166
+ const union = ta.size + tb.size - intersection;
167
+ if (union === 0) return 0;
168
+ return intersection / union;
169
+ }
170
+ function normalizeFinite(value) {
171
+ if (typeof value !== "number" || !Number.isFinite(value)) return 0;
172
+ return value;
173
+ }
174
+ function normalizeVector(values) {
175
+ if (values.length === 0) return values;
176
+ let max = 0;
177
+ let min = Number.POSITIVE_INFINITY;
178
+ for (const v of values) {
179
+ if (!Number.isFinite(v)) continue;
180
+ const a = Math.abs(v);
181
+ if (a > max) max = a;
182
+ if (v < min) min = v;
183
+ }
184
+ if (!Number.isFinite(min)) {
185
+ return values.map(() => 0);
186
+ }
187
+ if (max === 0) {
188
+ return values.map(() => 1);
189
+ }
190
+ if (min >= 0 && max <= 1) {
191
+ return values.map(
192
+ (v) => Number.isFinite(v) ? v < 0 ? 0 : v > 1 ? 1 : v : 0
193
+ );
194
+ }
195
+ return values.map((v) => {
196
+ if (!Number.isFinite(v)) return 0;
197
+ const scaled = v / max;
198
+ if (scaled < 0) return 0;
199
+ if (scaled > 1) return 1;
200
+ return scaled;
201
+ });
202
+ }
203
+ function averagePairwiseSimilarity(candidates) {
204
+ if (candidates.length < 2) return 0;
205
+ let sum = 0;
206
+ let count = 0;
207
+ for (let i = 0; i < candidates.length; i += 1) {
208
+ for (let j = i + 1; j < candidates.length; j += 1) {
209
+ sum += similarity(candidates[i], candidates[j]);
210
+ count += 1;
211
+ }
212
+ }
213
+ if (count === 0) return 0;
214
+ return sum / count;
215
+ }
216
+ function reorderRecallResultsWithMmr(results, options = {}) {
217
+ const emptyReport = {
218
+ considered: 0,
219
+ kept: 0,
220
+ headReorderCount: 0,
221
+ avgPairwiseSimBefore: 0,
222
+ avgPairwiseSimAfter: 0
223
+ };
224
+ const lambda = clampLambda(options.lambda);
225
+ if (!Array.isArray(results) || results.length === 0) {
226
+ return { reordered: [], diversity: emptyReport, lambda };
227
+ }
228
+ if (results.length < 2) {
229
+ return {
230
+ reordered: [results[0]],
231
+ diversity: {
232
+ considered: 1,
233
+ kept: 1,
234
+ headReorderCount: 0,
235
+ avgPairwiseSimBefore: 0,
236
+ avgPairwiseSimAfter: 0
237
+ },
238
+ lambda
239
+ };
240
+ }
241
+ const topN = clampPositiveInt(options.topN, DEFAULT_TOP_N);
242
+ const candidates = results.map((r, index) => ({
243
+ id: makeRecallKey(r, index),
244
+ content: r.snippet ?? "",
245
+ score: typeof r.score === "number" ? r.score : 0,
246
+ embedding: null
247
+ }));
248
+ const indexById = /* @__PURE__ */ new Map();
249
+ for (let i = 0; i < candidates.length; i += 1) {
250
+ indexById.set(candidates[i].id, i);
251
+ }
252
+ const selectedMmr = applyMmrToCandidates({
253
+ candidates,
254
+ lambda,
255
+ topN,
256
+ budget: results.length
257
+ });
258
+ const reordered = [];
259
+ const reorderedCandidates = [];
260
+ const seen = /* @__PURE__ */ new Set();
261
+ for (const c of selectedMmr) {
262
+ if (seen.has(c.id)) continue;
263
+ const origIndex = indexById.get(c.id);
264
+ if (origIndex === void 0) continue;
265
+ seen.add(c.id);
266
+ reordered.push(results[origIndex]);
267
+ reorderedCandidates.push(candidates[origIndex]);
268
+ }
269
+ if (reordered.length < results.length) {
270
+ for (let i = 0; i < results.length; i += 1) {
271
+ const origCandidate = candidates[i];
272
+ if (seen.has(origCandidate.id)) continue;
273
+ seen.add(origCandidate.id);
274
+ reordered.push(results[i]);
275
+ reorderedCandidates.push(origCandidate);
276
+ }
277
+ }
278
+ const diversity = summarizeMmrDiversity(
279
+ candidates,
280
+ reorderedCandidates,
281
+ options.diversitySampleSize
282
+ );
283
+ return { reordered, diversity, lambda };
284
+ }
285
+ function makeRecallKey(r, index) {
286
+ const baseKey = r.path || r.docid || "";
287
+ return `${baseKey}::${index}`;
288
+ }
289
+
290
+ export {
291
+ DEFAULT_LAMBDA,
292
+ DEFAULT_TOP_N,
293
+ applyMmrToCandidates,
294
+ summarizeMmrDiversity,
295
+ normalizeTokens,
296
+ reorderRecallResultsWithMmr
297
+ };
298
+ //# sourceMappingURL=chunk-YDBIWGNI.js.map