@graphrefly/graphrefly 0.44.0 → 0.46.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 (720) hide show
  1. package/README.md +22 -19
  2. package/dist/_internal-B23BagFd.d.cts +33 -0
  3. package/dist/_internal-B23BagFd.d.ts +33 -0
  4. package/dist/adaptive-rate-limiter-Dch_xYIi.d.cts +111 -0
  5. package/dist/adaptive-rate-limiter-Dch_xYIi.d.ts +111 -0
  6. package/dist/agents-C0Ji9ldU.d.cts +629 -0
  7. package/dist/agents-C9zexT7I.d.ts +629 -0
  8. package/dist/audit-BAXb3VOg.d.ts +246 -0
  9. package/dist/audit-C_bPfkqS.d.cts +246 -0
  10. package/dist/backoff-7KIK3WQW.js +24 -0
  11. package/dist/backoff-7KIK3WQW.js.map +1 -0
  12. package/dist/backoff-Bnb9OoPh.d.cts +6 -0
  13. package/dist/backoff-Bnb9OoPh.d.ts +6 -0
  14. package/dist/base/composition/index.cjs +811 -0
  15. package/dist/base/composition/index.cjs.map +1 -0
  16. package/dist/base/composition/index.d.cts +469 -0
  17. package/dist/base/composition/index.d.ts +469 -0
  18. package/dist/base/composition/index.js +40 -0
  19. package/dist/base/composition/index.js.map +1 -0
  20. package/dist/base/index.cjs +6336 -0
  21. package/dist/base/index.cjs.map +1 -0
  22. package/dist/base/index.d.cts +22 -0
  23. package/dist/base/index.d.ts +22 -0
  24. package/dist/base/index.js +259 -0
  25. package/dist/base/index.js.map +1 -0
  26. package/dist/base/io/index.cjs +3270 -0
  27. package/dist/base/io/index.cjs.map +1 -0
  28. package/dist/base/io/index.d.cts +2245 -0
  29. package/dist/base/io/index.d.ts +2245 -0
  30. package/dist/base/io/index.js +117 -0
  31. package/dist/base/io/index.js.map +1 -0
  32. package/dist/base/meta/index.cjs +43 -0
  33. package/dist/base/meta/index.cjs.map +1 -0
  34. package/dist/base/meta/index.d.cts +45 -0
  35. package/dist/base/meta/index.d.ts +45 -0
  36. package/dist/base/meta/index.js +13 -0
  37. package/dist/base/meta/index.js.map +1 -0
  38. package/dist/base/mutation/index.cjs +200 -0
  39. package/dist/base/mutation/index.cjs.map +1 -0
  40. package/dist/base/mutation/index.d.cts +177 -0
  41. package/dist/base/mutation/index.d.ts +177 -0
  42. package/dist/base/mutation/index.js +22 -0
  43. package/dist/base/mutation/index.js.map +1 -0
  44. package/dist/base/render/index.cjs +1120 -0
  45. package/dist/base/render/index.cjs.map +1 -0
  46. package/dist/{extra/render/index.d.ts → base/render/index.d.cts} +75 -31
  47. package/dist/{extra/render/index.d.cts → base/render/index.d.ts} +75 -31
  48. package/dist/base/render/index.js +24 -0
  49. package/dist/base/render/index.js.map +1 -0
  50. package/dist/base/sources/browser/index.cjs +172 -0
  51. package/dist/base/sources/browser/index.cjs.map +1 -0
  52. package/dist/base/sources/browser/index.d.cts +84 -0
  53. package/dist/base/sources/browser/index.d.ts +84 -0
  54. package/dist/base/sources/browser/index.js +151 -0
  55. package/dist/base/sources/browser/index.js.map +1 -0
  56. package/dist/base/sources/event/index.cjs +98 -0
  57. package/dist/base/sources/event/index.cjs.map +1 -0
  58. package/dist/base/sources/event/index.d.cts +91 -0
  59. package/dist/base/sources/event/index.d.ts +91 -0
  60. package/dist/base/sources/event/index.js +13 -0
  61. package/dist/base/sources/event/index.js.map +1 -0
  62. package/dist/base/sources/index.cjs +755 -0
  63. package/dist/base/sources/index.cjs.map +1 -0
  64. package/dist/{extra/sources.d.ts → base/sources/index.d.cts} +74 -301
  65. package/dist/{extra/sources.d.cts → base/sources/index.d.ts} +74 -301
  66. package/dist/base/sources/index.js +42 -0
  67. package/dist/base/sources/index.js.map +1 -0
  68. package/dist/base/sources/node/index.cjs +320 -0
  69. package/dist/base/sources/node/index.cjs.map +1 -0
  70. package/dist/{extra/node.d.ts → base/sources/node/index.d.cts} +35 -37
  71. package/dist/{extra/node.d.cts → base/sources/node/index.d.ts} +35 -37
  72. package/dist/base/sources/node/index.js +306 -0
  73. package/dist/base/sources/node/index.js.map +1 -0
  74. package/dist/base/utils/index.cjs +37 -0
  75. package/dist/base/utils/index.cjs.map +1 -0
  76. package/dist/base/utils/index.d.cts +37 -0
  77. package/dist/base/utils/index.d.ts +37 -0
  78. package/dist/base/utils/index.js +11 -0
  79. package/dist/base/utils/index.js.map +1 -0
  80. package/dist/base/worker/index.cjs +548 -0
  81. package/dist/base/worker/index.cjs.map +1 -0
  82. package/dist/base/worker/index.d.cts +207 -0
  83. package/dist/base/worker/index.d.ts +207 -0
  84. package/dist/base/worker/index.js +20 -0
  85. package/dist/base/worker/index.js.map +1 -0
  86. package/dist/breaker-C9skL3d8.d.ts +175 -0
  87. package/dist/breaker-ugSdq54q.d.cts +175 -0
  88. package/dist/{cascading-BglDkMdX.d.cts → cascading-CSSbKGrJ.d.ts} +3 -3
  89. package/dist/{cascading-MFgxu7Yo.d.ts → cascading-baGkiihI.d.cts} +3 -3
  90. package/dist/chunk-255UCBG4.js +58 -0
  91. package/dist/chunk-255UCBG4.js.map +1 -0
  92. package/dist/chunk-2LO3EL4W.js +1 -0
  93. package/dist/chunk-2LO3EL4W.js.map +1 -0
  94. package/dist/chunk-2OB3CEJS.js +1065 -0
  95. package/dist/chunk-2OB3CEJS.js.map +1 -0
  96. package/dist/chunk-36NMM65U.js +144 -0
  97. package/dist/chunk-36NMM65U.js.map +1 -0
  98. package/dist/chunk-3CEXCBN6.js +1 -0
  99. package/dist/chunk-3CEXCBN6.js.map +1 -0
  100. package/dist/chunk-3MUSLI6E.js +105 -0
  101. package/dist/chunk-3MUSLI6E.js.map +1 -0
  102. package/dist/chunk-3PSLNJDU.js +884 -0
  103. package/dist/chunk-3PSLNJDU.js.map +1 -0
  104. package/dist/chunk-3QZY5BI7.js +92 -0
  105. package/dist/chunk-3QZY5BI7.js.map +1 -0
  106. package/dist/chunk-42FQ27MQ.js +594 -0
  107. package/dist/chunk-42FQ27MQ.js.map +1 -0
  108. package/dist/chunk-4GYMCUDZ.js +1085 -0
  109. package/dist/chunk-4GYMCUDZ.js.map +1 -0
  110. package/dist/chunk-4S53H2KR.js +382 -0
  111. package/dist/chunk-4S53H2KR.js.map +1 -0
  112. package/dist/chunk-4XCHZRUJ.js +128 -0
  113. package/dist/chunk-4XCHZRUJ.js.map +1 -0
  114. package/dist/chunk-5THCXDWY.js +725 -0
  115. package/dist/chunk-5THCXDWY.js.map +1 -0
  116. package/dist/chunk-6XZYT4SW.js +256 -0
  117. package/dist/chunk-6XZYT4SW.js.map +1 -0
  118. package/dist/chunk-7EGRP2VX.js +76 -0
  119. package/dist/chunk-7EGRP2VX.js.map +1 -0
  120. package/dist/chunk-A7KV5UK4.js +150 -0
  121. package/dist/chunk-A7KV5UK4.js.map +1 -0
  122. package/dist/chunk-APY2SS5X.js +156 -0
  123. package/dist/chunk-APY2SS5X.js.map +1 -0
  124. package/dist/chunk-AZDQPQ3V.js +66 -0
  125. package/dist/chunk-AZDQPQ3V.js.map +1 -0
  126. package/dist/chunk-BU3SEFA5.js +90 -0
  127. package/dist/chunk-BU3SEFA5.js.map +1 -0
  128. package/dist/chunk-BXGZFGZ4.js +189 -0
  129. package/dist/chunk-BXGZFGZ4.js.map +1 -0
  130. package/dist/chunk-CGHORL6G.js +579 -0
  131. package/dist/chunk-CGHORL6G.js.map +1 -0
  132. package/dist/chunk-CXANAIZU.js +530 -0
  133. package/dist/chunk-CXANAIZU.js.map +1 -0
  134. package/dist/chunk-CZQHCKKG.js +1 -0
  135. package/dist/chunk-CZQHCKKG.js.map +1 -0
  136. package/dist/chunk-DKNHAICT.js +133 -0
  137. package/dist/chunk-DKNHAICT.js.map +1 -0
  138. package/dist/chunk-DM4OMPWK.js +584 -0
  139. package/dist/chunk-DM4OMPWK.js.map +1 -0
  140. package/dist/chunk-DMSNO6ZB.js +452 -0
  141. package/dist/chunk-DMSNO6ZB.js.map +1 -0
  142. package/dist/chunk-E5OZPDIW.js +229 -0
  143. package/dist/chunk-E5OZPDIW.js.map +1 -0
  144. package/dist/chunk-EVYY4X5A.js +509 -0
  145. package/dist/chunk-EVYY4X5A.js.map +1 -0
  146. package/dist/chunk-FDFD67UO.js +1 -0
  147. package/dist/chunk-FDFD67UO.js.map +1 -0
  148. package/dist/chunk-FMPF42Q4.js +13 -0
  149. package/dist/chunk-FMPF42Q4.js.map +1 -0
  150. package/dist/chunk-FR6RGA3B.js +1277 -0
  151. package/dist/chunk-FR6RGA3B.js.map +1 -0
  152. package/dist/chunk-FW23JYNQ.js +454 -0
  153. package/dist/chunk-FW23JYNQ.js.map +1 -0
  154. package/dist/chunk-GBCENOLN.js +1575 -0
  155. package/dist/chunk-GBCENOLN.js.map +1 -0
  156. package/dist/chunk-HL7HUJIX.js +1 -0
  157. package/dist/chunk-HL7HUJIX.js.map +1 -0
  158. package/dist/chunk-HULCUY35.js +2508 -0
  159. package/dist/chunk-HULCUY35.js.map +1 -0
  160. package/dist/chunk-IHTWQEDR.js +169 -0
  161. package/dist/chunk-IHTWQEDR.js.map +1 -0
  162. package/dist/chunk-IJRR6YAI.js +128 -0
  163. package/dist/chunk-IJRR6YAI.js.map +1 -0
  164. package/dist/chunk-JGFRAFDL.js +221 -0
  165. package/dist/chunk-JGFRAFDL.js.map +1 -0
  166. package/dist/chunk-KIIXR252.js +211 -0
  167. package/dist/chunk-KIIXR252.js.map +1 -0
  168. package/dist/chunk-KN3H5CNT.js +11 -0
  169. package/dist/chunk-KN3H5CNT.js.map +1 -0
  170. package/dist/chunk-KPG3DGLA.js +1 -0
  171. package/dist/chunk-KPG3DGLA.js.map +1 -0
  172. package/dist/chunk-KRNQ6RGQ.js +1 -0
  173. package/dist/chunk-KRNQ6RGQ.js.map +1 -0
  174. package/dist/chunk-LBAJK24K.js +1071 -0
  175. package/dist/chunk-LBAJK24K.js.map +1 -0
  176. package/dist/chunk-MLTPJMH6.js +417 -0
  177. package/dist/chunk-MLTPJMH6.js.map +1 -0
  178. package/dist/chunk-N3SZ7BMH.js +95 -0
  179. package/dist/chunk-N3SZ7BMH.js.map +1 -0
  180. package/dist/chunk-NDUD3IMO.js +540 -0
  181. package/dist/chunk-NDUD3IMO.js.map +1 -0
  182. package/dist/chunk-NY2PYHNC.js +873 -0
  183. package/dist/chunk-NY2PYHNC.js.map +1 -0
  184. package/dist/chunk-O3MT7DYI.js +225 -0
  185. package/dist/chunk-O3MT7DYI.js.map +1 -0
  186. package/dist/chunk-OCUDSN63.js +2386 -0
  187. package/dist/chunk-OCUDSN63.js.map +1 -0
  188. package/dist/chunk-OIWU3NYV.js +199 -0
  189. package/dist/chunk-OIWU3NYV.js.map +1 -0
  190. package/dist/chunk-OO5BM6CJ.js +1153 -0
  191. package/dist/chunk-OO5BM6CJ.js.map +1 -0
  192. package/dist/chunk-OQUIJT7A.js +1 -0
  193. package/dist/chunk-OQUIJT7A.js.map +1 -0
  194. package/dist/chunk-P5LBT622.js +105 -0
  195. package/dist/chunk-P5LBT622.js.map +1 -0
  196. package/dist/chunk-PKGQG5QQ.js +519 -0
  197. package/dist/chunk-PKGQG5QQ.js.map +1 -0
  198. package/dist/chunk-PKPO3JTZ.js +561 -0
  199. package/dist/chunk-PKPO3JTZ.js.map +1 -0
  200. package/dist/chunk-PL5UDIQ5.js +118 -0
  201. package/dist/chunk-PL5UDIQ5.js.map +1 -0
  202. package/dist/chunk-PZWISPIQ.js +432 -0
  203. package/dist/chunk-PZWISPIQ.js.map +1 -0
  204. package/dist/chunk-Q3EYOCZB.js +510 -0
  205. package/dist/chunk-Q3EYOCZB.js.map +1 -0
  206. package/dist/chunk-QMBYUVRL.js +15 -0
  207. package/dist/chunk-QMBYUVRL.js.map +1 -0
  208. package/dist/chunk-RAGGHLCV.js +200 -0
  209. package/dist/chunk-RAGGHLCV.js.map +1 -0
  210. package/dist/chunk-RGL53X5G.js +574 -0
  211. package/dist/chunk-RGL53X5G.js.map +1 -0
  212. package/dist/chunk-RJOG4IJU.js +1039 -0
  213. package/dist/chunk-RJOG4IJU.js.map +1 -0
  214. package/dist/chunk-SOOKUYVM.js +403 -0
  215. package/dist/chunk-SOOKUYVM.js.map +1 -0
  216. package/dist/chunk-T5BN5KG7.js +1 -0
  217. package/dist/chunk-T5BN5KG7.js.map +1 -0
  218. package/dist/chunk-TP7244Y6.js +207 -0
  219. package/dist/chunk-TP7244Y6.js.map +1 -0
  220. package/dist/chunk-TSBFTJKM.js +57 -0
  221. package/dist/chunk-TSBFTJKM.js.map +1 -0
  222. package/dist/chunk-URQ2CBBF.js +143 -0
  223. package/dist/chunk-URQ2CBBF.js.map +1 -0
  224. package/dist/chunk-W2BOPXTI.js +1 -0
  225. package/dist/chunk-W2BOPXTI.js.map +1 -0
  226. package/dist/chunk-WKSWLSCX.js +207 -0
  227. package/dist/chunk-WKSWLSCX.js.map +1 -0
  228. package/dist/chunk-Y52CS6YA.js +88 -0
  229. package/dist/chunk-Y52CS6YA.js.map +1 -0
  230. package/dist/chunk-YCBUWK77.js +92 -0
  231. package/dist/chunk-YCBUWK77.js.map +1 -0
  232. package/dist/chunk-YJ4U2D2C.js +314 -0
  233. package/dist/chunk-YJ4U2D2C.js.map +1 -0
  234. package/dist/chunk-Z4YXAUDN.js +239 -0
  235. package/dist/chunk-Z4YXAUDN.js.map +1 -0
  236. package/dist/chunk-Z6EGP5D7.js +92 -0
  237. package/dist/chunk-Z6EGP5D7.js.map +1 -0
  238. package/dist/compat/index.cjs +3100 -9
  239. package/dist/compat/index.cjs.map +1 -0
  240. package/dist/compat/index.d.cts +112 -18
  241. package/dist/compat/index.d.ts +112 -18
  242. package/dist/compat/index.js +176 -1
  243. package/dist/compat/index.js.map +1 -0
  244. package/dist/compat/jotai/index.cjs +149 -1
  245. package/dist/compat/jotai/index.cjs.map +1 -0
  246. package/dist/compat/jotai/index.d.cts +2 -2
  247. package/dist/compat/jotai/index.d.ts +2 -2
  248. package/dist/compat/jotai/index.js +8 -1
  249. package/dist/compat/jotai/index.js.map +1 -0
  250. package/dist/compat/nanostores/index.cjs +205 -1
  251. package/dist/compat/nanostores/index.cjs.map +1 -0
  252. package/dist/compat/nanostores/index.d.cts +2 -2
  253. package/dist/compat/nanostores/index.d.ts +2 -2
  254. package/dist/compat/nanostores/index.js +22 -1
  255. package/dist/compat/nanostores/index.js.map +1 -0
  256. package/dist/compat/nestjs/index.cjs +2241 -9
  257. package/dist/compat/nestjs/index.cjs.map +1 -0
  258. package/dist/compat/nestjs/index.d.cts +7 -10
  259. package/dist/compat/nestjs/index.d.ts +7 -10
  260. package/dist/compat/nestjs/index.js +78 -1
  261. package/dist/compat/nestjs/index.js.map +1 -0
  262. package/dist/compat/react/index.cjs +114 -1
  263. package/dist/compat/react/index.cjs.map +1 -0
  264. package/dist/compat/react/index.d.cts +2 -2
  265. package/dist/compat/react/index.d.ts +2 -2
  266. package/dist/compat/react/index.js +12 -1
  267. package/dist/compat/react/index.js.map +1 -0
  268. package/dist/compat/solid/index.cjs +101 -1
  269. package/dist/compat/solid/index.cjs.map +1 -0
  270. package/dist/compat/solid/index.d.cts +2 -2
  271. package/dist/compat/solid/index.d.ts +2 -2
  272. package/dist/compat/solid/index.js +12 -1
  273. package/dist/compat/solid/index.js.map +1 -0
  274. package/dist/compat/svelte/index.cjs +104 -1
  275. package/dist/compat/svelte/index.cjs.map +1 -0
  276. package/dist/compat/svelte/index.d.cts +2 -2
  277. package/dist/compat/svelte/index.d.ts +2 -2
  278. package/dist/compat/svelte/index.js +12 -1
  279. package/dist/compat/svelte/index.js.map +1 -0
  280. package/dist/compat/vue/index.cjs +119 -1
  281. package/dist/compat/vue/index.cjs.map +1 -0
  282. package/dist/compat/vue/index.d.cts +2 -2
  283. package/dist/compat/vue/index.d.ts +2 -2
  284. package/dist/compat/vue/index.js +12 -1
  285. package/dist/compat/vue/index.js.map +1 -0
  286. package/dist/compat/zustand/index.cjs +69 -3
  287. package/dist/compat/zustand/index.cjs.map +1 -0
  288. package/dist/compat/zustand/index.d.cts +2 -6
  289. package/dist/compat/zustand/index.d.ts +2 -6
  290. package/dist/compat/zustand/index.js +8 -1
  291. package/dist/compat/zustand/index.js.map +1 -0
  292. package/dist/distill-De6Rnn15.d.cts +48 -0
  293. package/dist/distill-De6Rnn15.d.ts +48 -0
  294. package/dist/external-register-CWyroXb_.d.cts +138 -0
  295. package/dist/external-register-CWyroXb_.d.ts +138 -0
  296. package/dist/{fallback-74oxi34l.d.cts → fallback-Bx46zqky.d.cts} +3 -10
  297. package/dist/{fallback-DUyyBTBK.d.ts → fallback-pIWW8A2d.d.ts} +3 -10
  298. package/dist/guarded-execution-BcdtxeBk.d.ts +207 -0
  299. package/dist/guarded-execution-C-3hnP6A.d.cts +207 -0
  300. package/dist/{index-CBGUK09R.d.ts → index-5SU_O78r.d.cts} +5 -5
  301. package/dist/{index-BmZXHqkE.d.ts → index-B6pxYJzO.d.cts} +1 -1
  302. package/dist/{index-hcDJ8PSI.d.cts → index-B6pxYJzO.d.ts} +1 -1
  303. package/dist/{index-C5stwKcw.d.cts → index-BFsng6v1.d.cts} +1 -1
  304. package/dist/{index-CdAlHFEt.d.ts → index-BFsng6v1.d.ts} +1 -1
  305. package/dist/{index-_6ODbuOu.d.cts → index-Bg-LwEt-.d.cts} +1 -1
  306. package/dist/{index-CviRnE4K.d.ts → index-Bg-LwEt-.d.ts} +1 -1
  307. package/dist/{index-CBBLl_rc.d.ts → index-Brp888t0.d.cts} +1 -1
  308. package/dist/{index-BQSKmbuG.d.cts → index-Brp888t0.d.ts} +1 -1
  309. package/dist/{index-sqkqlb1p.d.ts → index-CDfk6jHN.d.cts} +1 -1
  310. package/dist/{index-ZVQhLa2i.d.cts → index-CDfk6jHN.d.ts} +1 -1
  311. package/dist/{index-Climxqsu.d.cts → index-CEXCtYYJ.d.ts} +5 -5
  312. package/dist/index-DLAxYaN5.d.cts +169 -0
  313. package/dist/index-DLAxYaN5.d.ts +169 -0
  314. package/dist/{index-CK29LV56.d.cts → index-DeWbQzMe.d.cts} +1 -1
  315. package/dist/{index-CPQlGA29.d.ts → index-DeWbQzMe.d.ts} +1 -1
  316. package/dist/{index-BrPrLl4e.d.cts → index-dX9IzPqj.d.cts} +1 -1
  317. package/dist/{index-Dgl1HpPn.d.ts → index-dX9IzPqj.d.ts} +1 -1
  318. package/dist/index.cjs +25934 -191
  319. package/dist/index.cjs.map +1 -0
  320. package/dist/index.d.cts +58 -94
  321. package/dist/index.d.ts +58 -94
  322. package/dist/index.js +852 -1
  323. package/dist/index.js.map +1 -0
  324. package/dist/layout-types-B5aiHYgk.d.cts +72 -0
  325. package/dist/layout-types-B5aiHYgk.d.ts +72 -0
  326. package/dist/memory-composers-BryDrRBX.d.cts +529 -0
  327. package/dist/memory-composers-CVQqPYEV.d.ts +529 -0
  328. package/dist/{observable-DWjNfLvC.d.ts → observable-BXQoW1P-.d.cts} +1 -1
  329. package/dist/{observable-e3eiPPFy.d.cts → observable-BXQoW1P-.d.ts} +1 -1
  330. package/dist/{pipeline-graph-Sgj0gCwn.d.ts → pipeline-graph-Ce47CB6Y.d.cts} +13 -10
  331. package/dist/{pipeline-graph-CIKhynsF.d.cts → pipeline-graph-DXCwY9vG.d.ts} +13 -10
  332. package/dist/presets/ai/index.cjs +4377 -0
  333. package/dist/presets/ai/index.cjs.map +1 -0
  334. package/dist/presets/ai/index.d.cts +98 -0
  335. package/dist/presets/ai/index.d.ts +98 -0
  336. package/dist/presets/ai/index.js +54 -0
  337. package/dist/presets/ai/index.js.map +1 -0
  338. package/dist/presets/harness/index.cjs +5929 -0
  339. package/dist/presets/harness/index.cjs.map +1 -0
  340. package/dist/presets/harness/index.d.cts +566 -0
  341. package/dist/presets/harness/index.d.ts +566 -0
  342. package/dist/presets/harness/index.js +71 -0
  343. package/dist/presets/harness/index.js.map +1 -0
  344. package/dist/presets/index.cjs +9782 -0
  345. package/dist/presets/index.cjs.map +1 -0
  346. package/dist/presets/index.d.cts +28 -0
  347. package/dist/presets/index.d.ts +28 -0
  348. package/dist/presets/index.js +129 -0
  349. package/dist/presets/index.js.map +1 -0
  350. package/dist/presets/inspect/index.cjs +1087 -0
  351. package/dist/presets/inspect/index.cjs.map +1 -0
  352. package/dist/presets/inspect/index.d.cts +172 -0
  353. package/dist/presets/inspect/index.d.ts +172 -0
  354. package/dist/presets/inspect/index.js +21 -0
  355. package/dist/presets/inspect/index.js.map +1 -0
  356. package/dist/presets/resilience/index.cjs +1593 -0
  357. package/dist/presets/resilience/index.cjs.map +1 -0
  358. package/dist/presets/resilience/index.d.cts +205 -0
  359. package/dist/presets/resilience/index.d.ts +205 -0
  360. package/dist/presets/resilience/index.js +18 -0
  361. package/dist/presets/resilience/index.js.map +1 -0
  362. package/dist/rate-limiter-CEALq4N1.d.ts +559 -0
  363. package/dist/rate-limiter-DpVbSYdH.d.cts +559 -0
  364. package/dist/{reactive-layout-DOTs9P3X.d.ts → reactive-layout-fswlBUvX.d.cts} +19 -7
  365. package/dist/{reactive-layout-DgctbqZo.d.cts → reactive-layout-fswlBUvX.d.ts} +19 -7
  366. package/dist/retry-BDbRZ_gx.d.ts +125 -0
  367. package/dist/retry-DWuhjvsA.d.cts +125 -0
  368. package/dist/solutions/index.cjs +8200 -0
  369. package/dist/solutions/index.cjs.map +1 -0
  370. package/dist/solutions/index.d.cts +23 -0
  371. package/dist/solutions/index.d.ts +23 -0
  372. package/dist/solutions/index.js +55 -0
  373. package/dist/solutions/index.js.map +1 -0
  374. package/dist/spawnable-5mDY501F.d.cts +746 -0
  375. package/dist/spawnable-D3lR0oQu.d.ts +746 -0
  376. package/dist/status-U-rUI79b.d.cts +84 -0
  377. package/dist/status-U-rUI79b.d.ts +84 -0
  378. package/dist/timeout-U5O4ESK3.js +12 -0
  379. package/dist/timeout-U5O4ESK3.js.map +1 -0
  380. package/dist/{types-CWFysE9E.d.ts → types-BB5Lw-pB.d.cts} +3 -3
  381. package/dist/{types-C0_yquda.d.cts → types-BB5Lw-pB.d.ts} +3 -3
  382. package/dist/types-CJWIMJiZ.d.ts +548 -0
  383. package/dist/types-vCq7ShIm.d.cts +548 -0
  384. package/dist/utils/ai/browser.cjs +2169 -0
  385. package/dist/utils/ai/browser.cjs.map +1 -0
  386. package/dist/{patterns → utils}/ai/browser.d.cts +7 -5
  387. package/dist/{patterns → utils}/ai/browser.d.ts +7 -5
  388. package/dist/utils/ai/browser.js +255 -0
  389. package/dist/utils/ai/browser.js.map +1 -0
  390. package/dist/utils/ai/index.cjs +8468 -0
  391. package/dist/utils/ai/index.cjs.map +1 -0
  392. package/dist/{index-CR8QpwX8.d.ts → utils/ai/index.d.cts} +73 -976
  393. package/dist/{index-UPSiS-X7.d.cts → utils/ai/index.d.ts} +73 -976
  394. package/dist/utils/ai/index.js +173 -0
  395. package/dist/utils/ai/index.js.map +1 -0
  396. package/dist/utils/ai/node.cjs +648 -0
  397. package/dist/utils/ai/node.cjs.map +1 -0
  398. package/dist/{patterns → utils}/ai/node.d.cts +5 -7
  399. package/dist/{patterns → utils}/ai/node.d.ts +5 -7
  400. package/dist/utils/ai/node.js +84 -0
  401. package/dist/utils/ai/node.js.map +1 -0
  402. package/dist/utils/cqrs/index.cjs +1036 -0
  403. package/dist/utils/cqrs/index.cjs.map +1 -0
  404. package/dist/{index-CeFiHtAg.d.ts → utils/cqrs/index.d.cts} +7 -37
  405. package/dist/{index-B-_tFaqV.d.cts → utils/cqrs/index.d.ts} +7 -37
  406. package/dist/utils/cqrs/index.js +18 -0
  407. package/dist/utils/cqrs/index.js.map +1 -0
  408. package/dist/utils/demo-shell/index.cjs +865 -0
  409. package/dist/utils/demo-shell/index.cjs.map +1 -0
  410. package/dist/{index-B8YnZpIR.d.ts → utils/demo-shell/index.d.cts} +4 -16
  411. package/dist/{index-Cwv0KWcU.d.cts → utils/demo-shell/index.d.ts} +4 -16
  412. package/dist/utils/demo-shell/index.js +13 -0
  413. package/dist/utils/demo-shell/index.js.map +1 -0
  414. package/dist/utils/domain-templates/index.cjs +732 -0
  415. package/dist/utils/domain-templates/index.cjs.map +1 -0
  416. package/dist/{index-CzLVrjxn.d.ts → utils/domain-templates/index.d.cts} +3 -20
  417. package/dist/{index-BaQaY_IQ.d.cts → utils/domain-templates/index.d.ts} +3 -20
  418. package/dist/utils/domain-templates/index.js +17 -0
  419. package/dist/utils/domain-templates/index.js.map +1 -0
  420. package/dist/utils/graphspec/index.cjs +1174 -0
  421. package/dist/utils/graphspec/index.cjs.map +1 -0
  422. package/dist/{index-CMh5Rz1y.d.ts → utils/graphspec/index.d.cts} +106 -42
  423. package/dist/{index-CS0LTlB8.d.cts → utils/graphspec/index.d.ts} +106 -42
  424. package/dist/utils/graphspec/index.js +35 -0
  425. package/dist/utils/graphspec/index.js.map +1 -0
  426. package/dist/utils/harness/index.cjs +656 -0
  427. package/dist/utils/harness/index.cjs.map +1 -0
  428. package/dist/utils/harness/index.d.cts +542 -0
  429. package/dist/utils/harness/index.d.ts +542 -0
  430. package/dist/utils/harness/index.js +56 -0
  431. package/dist/utils/harness/index.js.map +1 -0
  432. package/dist/utils/index.cjs +17609 -0
  433. package/dist/utils/index.cjs.map +1 -0
  434. package/dist/utils/index.d.cts +96 -0
  435. package/dist/utils/index.d.ts +96 -0
  436. package/dist/utils/index.js +514 -0
  437. package/dist/utils/index.js.map +1 -0
  438. package/dist/utils/inspect/index.cjs +807 -0
  439. package/dist/utils/inspect/index.cjs.map +1 -0
  440. package/dist/utils/inspect/index.d.cts +123 -0
  441. package/dist/utils/inspect/index.d.ts +123 -0
  442. package/dist/utils/inspect/index.js +30 -0
  443. package/dist/utils/inspect/index.js.map +1 -0
  444. package/dist/utils/job-queue/index.cjs +717 -0
  445. package/dist/utils/job-queue/index.cjs.map +1 -0
  446. package/dist/{index-DisjX8a-.d.ts → utils/job-queue/index.d.cts} +5 -26
  447. package/dist/{index-DV_1YuVk.d.cts → utils/job-queue/index.d.ts} +5 -26
  448. package/dist/utils/job-queue/index.js +18 -0
  449. package/dist/utils/job-queue/index.js.map +1 -0
  450. package/dist/utils/memory/index.cjs +1451 -0
  451. package/dist/utils/memory/index.cjs.map +1 -0
  452. package/dist/{index-CZ3r5Rxp.d.ts → utils/memory/index.d.cts} +242 -34
  453. package/dist/{index-B17QddL1.d.cts → utils/memory/index.d.ts} +242 -34
  454. package/dist/utils/memory/index.js +19 -0
  455. package/dist/utils/memory/index.js.map +1 -0
  456. package/dist/utils/messaging/index.cjs +666 -0
  457. package/dist/utils/messaging/index.cjs.map +1 -0
  458. package/dist/utils/messaging/index.d.cts +562 -0
  459. package/dist/utils/messaging/index.d.ts +562 -0
  460. package/dist/utils/messaging/index.js +50 -0
  461. package/dist/utils/messaging/index.js.map +1 -0
  462. package/dist/utils/orchestration/index.cjs +876 -0
  463. package/dist/utils/orchestration/index.cjs.map +1 -0
  464. package/dist/utils/orchestration/index.d.cts +233 -0
  465. package/dist/utils/orchestration/index.d.ts +233 -0
  466. package/dist/utils/orchestration/index.js +19 -0
  467. package/dist/utils/orchestration/index.js.map +1 -0
  468. package/dist/utils/process/index.cjs +743 -0
  469. package/dist/utils/process/index.cjs.map +1 -0
  470. package/dist/{index-p09KSrTN.d.ts → utils/process/index.d.cts} +97 -44
  471. package/dist/{index-CasX6Pfq.d.cts → utils/process/index.d.ts} +97 -44
  472. package/dist/utils/process/index.js +14 -0
  473. package/dist/utils/process/index.js.map +1 -0
  474. package/dist/utils/reactive-layout/index.cjs +1607 -0
  475. package/dist/utils/reactive-layout/index.cjs.map +1 -0
  476. package/dist/{index-B5S8ULbU.d.ts → utils/reactive-layout/index.d.cts} +58 -81
  477. package/dist/{index-Dc4AYqrJ.d.cts → utils/reactive-layout/index.d.ts} +58 -81
  478. package/dist/utils/reactive-layout/index.js +52 -0
  479. package/dist/utils/reactive-layout/index.js.map +1 -0
  480. package/dist/utils/reduction/index.cjs +203 -0
  481. package/dist/utils/reduction/index.cjs.map +1 -0
  482. package/dist/{index-Byu-OpX_.d.ts → utils/reduction/index.d.cts} +6 -17
  483. package/dist/{index-tRCxuAXF.d.cts → utils/reduction/index.d.ts} +6 -17
  484. package/dist/utils/reduction/index.js +14 -0
  485. package/dist/utils/reduction/index.js.map +1 -0
  486. package/dist/utils/resilience/index.cjs +1617 -0
  487. package/dist/utils/resilience/index.cjs.map +1 -0
  488. package/dist/utils/resilience/index.d.cts +9 -0
  489. package/dist/utils/resilience/index.d.ts +9 -0
  490. package/dist/utils/resilience/index.js +44 -0
  491. package/dist/utils/resilience/index.js.map +1 -0
  492. package/dist/utils/surface/index.cjs +1070 -0
  493. package/dist/utils/surface/index.cjs.map +1 -0
  494. package/dist/{index-CYq8vAyV.d.ts → utils/surface/index.d.cts} +7 -58
  495. package/dist/{index-CSOmP7xT.d.cts → utils/surface/index.d.ts} +7 -58
  496. package/dist/utils/surface/index.js +30 -0
  497. package/dist/utils/surface/index.js.map +1 -0
  498. package/dist/utils/topology-view/index.cjs +620 -0
  499. package/dist/utils/topology-view/index.cjs.map +1 -0
  500. package/dist/utils/topology-view/index.d.cts +68 -0
  501. package/dist/utils/topology-view/index.d.ts +68 -0
  502. package/dist/utils/topology-view/index.js +11 -0
  503. package/dist/utils/topology-view/index.js.map +1 -0
  504. package/package.json +664 -584
  505. package/dist/backoff-HPZMEZNF.js +0 -1
  506. package/dist/chunk-2T7U5EU6.js +0 -1
  507. package/dist/chunk-3G5U5QNE.js +0 -5
  508. package/dist/chunk-4VVTGLXJ.js +0 -1
  509. package/dist/chunk-5M4CCMMD.js +0 -45
  510. package/dist/chunk-5QDBSZBV.js +0 -1
  511. package/dist/chunk-5XJ6B66J.js +0 -1
  512. package/dist/chunk-6QZNQS5B.js +0 -1
  513. package/dist/chunk-6X7AFUJV.js +0 -9
  514. package/dist/chunk-7K6PWTDQ.js +0 -1
  515. package/dist/chunk-7LIAPXJB.js +0 -1
  516. package/dist/chunk-7WPU3UHQ.js +0 -1
  517. package/dist/chunk-A5WCQ5NO.js +0 -1
  518. package/dist/chunk-APPIWSGD.js +0 -84
  519. package/dist/chunk-BEZWM2SY.js +0 -1
  520. package/dist/chunk-C72GO4IZ.js +0 -1
  521. package/dist/chunk-CB676TKJ.js +0 -1
  522. package/dist/chunk-CE6TI2TL.js +0 -1
  523. package/dist/chunk-CE72X3WO.js +0 -1
  524. package/dist/chunk-CK2E7BTU.js +0 -1
  525. package/dist/chunk-CLVB32RD.js +0 -1
  526. package/dist/chunk-CRVT7D2P.js +0 -1
  527. package/dist/chunk-D5RFJOZ2.js +0 -1
  528. package/dist/chunk-D7GPHKFH.js +0 -1
  529. package/dist/chunk-DHRX7JX4.js +0 -2
  530. package/dist/chunk-ESMPEKEV.js +0 -1
  531. package/dist/chunk-F672GV32.js +0 -1
  532. package/dist/chunk-FZMYDOWV.js +0 -1
  533. package/dist/chunk-GHBWHMRZ.js +0 -1
  534. package/dist/chunk-GLERH466.js +0 -1
  535. package/dist/chunk-GPW2V3RE.js +0 -1
  536. package/dist/chunk-HIDYF36O.js +0 -1
  537. package/dist/chunk-HITNVN6B.js +0 -3
  538. package/dist/chunk-HY4DJBA7.js +0 -5
  539. package/dist/chunk-KZIEYVXN.js +0 -1
  540. package/dist/chunk-L6NSJVJZ.js +0 -1
  541. package/dist/chunk-N4MQX6JU.js +0 -18
  542. package/dist/chunk-N7FHEL4D.js +0 -1
  543. package/dist/chunk-NTEURFZH.js +0 -1
  544. package/dist/chunk-OIVP6KFV.js +0 -1
  545. package/dist/chunk-OPHBU3LG.js +0 -1
  546. package/dist/chunk-OYQOZP2F.js +0 -5
  547. package/dist/chunk-PTZK576G.js +0 -1
  548. package/dist/chunk-QYADASLV.js +0 -1
  549. package/dist/chunk-ST7UXLWR.js +0 -1
  550. package/dist/chunk-SVY7VUYU.js +0 -1
  551. package/dist/chunk-TK3NWWD4.js +0 -1
  552. package/dist/chunk-TSOYJ743.js +0 -1
  553. package/dist/chunk-UNGSTR4X.js +0 -61
  554. package/dist/chunk-VIMF6LGM.js +0 -1
  555. package/dist/chunk-VJLMUKOI.js +0 -1
  556. package/dist/chunk-VN6RDSK2.js +0 -1
  557. package/dist/chunk-VV4N5P64.js +0 -1
  558. package/dist/chunk-W3I423PS.js +0 -1
  559. package/dist/chunk-WJR24TAG.js +0 -1
  560. package/dist/chunk-XTGKMHSW.js +0 -1
  561. package/dist/chunk-YBB7ZGTY.js +0 -1
  562. package/dist/chunk-Z4NPUARF.js +0 -1
  563. package/dist/chunk-ZGNQRPDT.js +0 -1
  564. package/dist/chunk-ZKPSFFKU.js +0 -1
  565. package/dist/chunk-ZLV5SQSX.js +0 -1
  566. package/dist/content-addressed-storage-4-ST1tYk.d.cts +0 -124
  567. package/dist/content-addressed-storage-DuYMjV7o.d.ts +0 -124
  568. package/dist/core/index.cjs +0 -1
  569. package/dist/core/index.d.cts +0 -3
  570. package/dist/core/index.d.ts +0 -3
  571. package/dist/core/index.js +0 -1
  572. package/dist/decay-BvOWTZ00.d.ts +0 -112
  573. package/dist/decay-CFlLvXUT.d.cts +0 -112
  574. package/dist/extra/browser.cjs +0 -1
  575. package/dist/extra/browser.d.cts +0 -4
  576. package/dist/extra/browser.d.ts +0 -4
  577. package/dist/extra/browser.js +0 -1
  578. package/dist/extra/index.cjs +0 -20
  579. package/dist/extra/index.d.cts +0 -17
  580. package/dist/extra/index.d.ts +0 -17
  581. package/dist/extra/index.js +0 -1
  582. package/dist/extra/node.cjs +0 -2
  583. package/dist/extra/node.js +0 -2
  584. package/dist/extra/operators.cjs +0 -1
  585. package/dist/extra/operators.d.cts +0 -958
  586. package/dist/extra/operators.d.ts +0 -958
  587. package/dist/extra/operators.js +0 -1
  588. package/dist/extra/reactive.cjs +0 -1
  589. package/dist/extra/reactive.d.cts +0 -353
  590. package/dist/extra/reactive.d.ts +0 -353
  591. package/dist/extra/reactive.js +0 -1
  592. package/dist/extra/render/index.cjs +0 -5
  593. package/dist/extra/render/index.js +0 -1
  594. package/dist/extra/sources.cjs +0 -3
  595. package/dist/extra/sources.js +0 -1
  596. package/dist/extra/storage-browser.cjs +0 -1
  597. package/dist/extra/storage-browser.d.cts +0 -37
  598. package/dist/extra/storage-browser.d.ts +0 -37
  599. package/dist/extra/storage-browser.js +0 -1
  600. package/dist/extra/storage-core.cjs +0 -1
  601. package/dist/extra/storage-core.d.cts +0 -28
  602. package/dist/extra/storage-core.d.ts +0 -28
  603. package/dist/extra/storage-core.js +0 -1
  604. package/dist/extra/storage-node.cjs +0 -1
  605. package/dist/extra/storage-node.d.cts +0 -2
  606. package/dist/extra/storage-node.d.ts +0 -2
  607. package/dist/extra/storage-node.js +0 -0
  608. package/dist/extra/storage-tiers-browser.cjs +0 -1
  609. package/dist/extra/storage-tiers-browser.d.cts +0 -120
  610. package/dist/extra/storage-tiers-browser.d.ts +0 -120
  611. package/dist/extra/storage-tiers-browser.js +0 -1
  612. package/dist/extra/storage-tiers-node.cjs +0 -1
  613. package/dist/extra/storage-tiers-node.d.cts +0 -210
  614. package/dist/extra/storage-tiers-node.d.ts +0 -210
  615. package/dist/extra/storage-tiers-node.js +0 -1
  616. package/dist/extra/storage-tiers.cjs +0 -1
  617. package/dist/extra/storage-tiers.d.cts +0 -412
  618. package/dist/extra/storage-tiers.d.ts +0 -412
  619. package/dist/extra/storage-tiers.js +0 -1
  620. package/dist/graph/index.cjs +0 -7
  621. package/dist/graph/index.d.cts +0 -7
  622. package/dist/graph/index.d.ts +0 -7
  623. package/dist/graph/index.js +0 -1
  624. package/dist/graph-CWvEUQAq.d.cts +0 -1861
  625. package/dist/graph-D9LFnda9.d.ts +0 -1861
  626. package/dist/index-5k1T6jl0.d.cts +0 -121
  627. package/dist/index-9770hRuQ.d.cts +0 -779
  628. package/dist/index-B1F8Enjf.d.ts +0 -704
  629. package/dist/index-BHskSB8v.d.ts +0 -3413
  630. package/dist/index-BIYAkbAi.d.cts +0 -26
  631. package/dist/index-BoJ5JHxI.d.ts +0 -557
  632. package/dist/index-BocU7pqs.d.ts +0 -779
  633. package/dist/index-BxNs2HB9.d.cts +0 -1858
  634. package/dist/index-C1T3d7V-.d.cts +0 -704
  635. package/dist/index-C5ri2Axc.d.cts +0 -301
  636. package/dist/index-C9l6OEBL.d.ts +0 -26
  637. package/dist/index-CC-AvFTy.d.cts +0 -557
  638. package/dist/index-CJF1URuX.d.ts +0 -121
  639. package/dist/index-CdTelp1M.d.ts +0 -202
  640. package/dist/index-Cj3WohTd.d.cts +0 -202
  641. package/dist/index-Co7uli2l.d.cts +0 -3413
  642. package/dist/index-D0aciIex.d.cts +0 -209
  643. package/dist/index-DHen9Klo.d.ts +0 -1858
  644. package/dist/index-Yq60JP3s.d.ts +0 -209
  645. package/dist/index-nozs3fFC.d.ts +0 -301
  646. package/dist/node-kK3CvTrR.d.cts +0 -1347
  647. package/dist/node-kK3CvTrR.d.ts +0 -1347
  648. package/dist/patterns/ai/browser.cjs +0 -8
  649. package/dist/patterns/ai/browser.js +0 -3
  650. package/dist/patterns/ai/index.cjs +0 -74
  651. package/dist/patterns/ai/index.d.cts +0 -20
  652. package/dist/patterns/ai/index.d.ts +0 -20
  653. package/dist/patterns/ai/index.js +0 -1
  654. package/dist/patterns/ai/node.cjs +0 -1
  655. package/dist/patterns/ai/node.js +0 -1
  656. package/dist/patterns/cqrs/index.cjs +0 -3
  657. package/dist/patterns/cqrs/index.d.cts +0 -8
  658. package/dist/patterns/cqrs/index.d.ts +0 -8
  659. package/dist/patterns/cqrs/index.js +0 -1
  660. package/dist/patterns/demo-shell/index.cjs +0 -5
  661. package/dist/patterns/demo-shell/index.d.cts +0 -7
  662. package/dist/patterns/demo-shell/index.d.ts +0 -7
  663. package/dist/patterns/demo-shell/index.js +0 -1
  664. package/dist/patterns/domain-templates/index.cjs +0 -3
  665. package/dist/patterns/domain-templates/index.d.cts +0 -6
  666. package/dist/patterns/domain-templates/index.d.ts +0 -6
  667. package/dist/patterns/domain-templates/index.js +0 -1
  668. package/dist/patterns/graphspec/index.cjs +0 -86
  669. package/dist/patterns/graphspec/index.d.cts +0 -8
  670. package/dist/patterns/graphspec/index.d.ts +0 -8
  671. package/dist/patterns/graphspec/index.js +0 -1
  672. package/dist/patterns/harness/index.cjs +0 -48
  673. package/dist/patterns/harness/index.d.cts +0 -13
  674. package/dist/patterns/harness/index.d.ts +0 -13
  675. package/dist/patterns/harness/index.js +0 -1
  676. package/dist/patterns/inspect/index.cjs +0 -3
  677. package/dist/patterns/inspect/index.d.cts +0 -9
  678. package/dist/patterns/inspect/index.d.ts +0 -9
  679. package/dist/patterns/inspect/index.js +0 -1
  680. package/dist/patterns/job-queue/index.cjs +0 -3
  681. package/dist/patterns/job-queue/index.d.cts +0 -9
  682. package/dist/patterns/job-queue/index.d.ts +0 -9
  683. package/dist/patterns/job-queue/index.js +0 -1
  684. package/dist/patterns/memory/index.cjs +0 -3
  685. package/dist/patterns/memory/index.d.cts +0 -8
  686. package/dist/patterns/memory/index.d.ts +0 -8
  687. package/dist/patterns/memory/index.js +0 -1
  688. package/dist/patterns/messaging/index.cjs +0 -3
  689. package/dist/patterns/messaging/index.d.cts +0 -7
  690. package/dist/patterns/messaging/index.d.ts +0 -7
  691. package/dist/patterns/messaging/index.js +0 -1
  692. package/dist/patterns/orchestration/index.cjs +0 -3
  693. package/dist/patterns/orchestration/index.d.cts +0 -8
  694. package/dist/patterns/orchestration/index.d.ts +0 -8
  695. package/dist/patterns/orchestration/index.js +0 -1
  696. package/dist/patterns/process/index.cjs +0 -3
  697. package/dist/patterns/process/index.d.cts +0 -10
  698. package/dist/patterns/process/index.d.ts +0 -10
  699. package/dist/patterns/process/index.js +0 -1
  700. package/dist/patterns/reactive-layout/index.cjs +0 -4
  701. package/dist/patterns/reactive-layout/index.d.cts +0 -7
  702. package/dist/patterns/reactive-layout/index.d.ts +0 -7
  703. package/dist/patterns/reactive-layout/index.js +0 -1
  704. package/dist/patterns/reduction/index.cjs +0 -3
  705. package/dist/patterns/reduction/index.d.cts +0 -6
  706. package/dist/patterns/reduction/index.d.ts +0 -6
  707. package/dist/patterns/reduction/index.js +0 -1
  708. package/dist/patterns/surface/index.cjs +0 -13
  709. package/dist/patterns/surface/index.d.cts +0 -9
  710. package/dist/patterns/surface/index.d.ts +0 -9
  711. package/dist/patterns/surface/index.js +0 -1
  712. package/dist/reactive-log-BKALbfal.d.ts +0 -223
  713. package/dist/reactive-log-DIGdYqQ6.d.cts +0 -223
  714. package/dist/reactive-map-CEFGp8TK.d.cts +0 -296
  715. package/dist/reactive-map-DS_SIAxv.d.ts +0 -296
  716. package/dist/resilience-6LYQJAC5.js +0 -1
  717. package/dist/sugar-DQjFmVqb.d.cts +0 -399
  718. package/dist/sugar-fhLIE7TT.d.ts +0 -399
  719. package/dist/topology-tree-Bcz27hpF.d.cts +0 -25
  720. package/dist/topology-tree-xvaD0fOX.d.ts +0 -25
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/base/resilience/_internal.ts","../../../src/base/resilience/backoff.ts","../../../src/utils/ai/index.ts","../../../src/utils/ai/adapters/core/capabilities.ts","../../../src/utils/ai/adapters/providers/anthropic.ts","../../../src/base/io/http-error.ts","../../../src/base/io/sse.ts","../../../src/utils/ai/adapters/providers/dry-run.ts","../../../src/utils/ai/adapters/providers/fallback.ts","../../../src/utils/ai/adapters/middleware/replay-cache.ts","../../../src/base/composition/single-from-any.ts","../../../src/base/sources/settled.ts","../../../src/utils/ai/adapters/_internal/content-addressed-cache.ts","../../../src/utils/ai/adapters/_internal/wrappers.ts","../../../src/utils/ai/adapters/providers/google.ts","../../../src/utils/ai/adapters/providers/openai-compat.ts","../../../src/utils/ai/adapters/core/factory.ts","../../../src/utils/ai/adapters/core/observable.ts","../../../src/utils/ai/adapters/core/types.ts","../../../src/utils/ai/adapters/core/pricing.ts","../../../src/utils/ai/adapters/middleware/breaker.ts","../../../src/base/resilience/retry.ts","../../../src/utils/resilience/breaker.ts","../../../src/base/meta/domain-meta.ts","../../../src/utils/resilience/rate-limiter.ts","../../../src/utils/resilience/adaptive-rate-limiter.ts","../../../src/utils/ai/adapters/middleware/budget-gate.ts","../../../src/utils/ai/adapters/middleware/dry-run.ts","../../../src/utils/ai/adapters/middleware/http429-parser.ts","../../../src/utils/ai/adapters/middleware/rate-limiter.ts","../../../src/utils/ai/adapters/routing/cascading.ts","../../../src/utils/ai/adapters/middleware/retry.ts","../../../src/utils/ai/adapters/middleware/timeout.ts","../../../src/utils/ai/adapters/middleware/resilient-adapter.ts","../../../src/utils/ai/prompts/frozen-context.ts","../../../src/utils/ai/_internal.ts","../../../src/utils/ai/prompts/prompt-call.ts","../../../src/utils/ai/prompts/prompt-node.ts","../../../src/utils/ai/prompts/streaming.ts","../../../src/utils/messaging/index.ts","../../../src/base/mutation/index.ts","../../../src/utils/orchestration/pipeline-graph.ts","../../../src/utils/ai/prompts/system-prompt.ts","../../../src/utils/ai/extractors/cost-meter.ts","../../../src/utils/ai/extractors/keyword-flag.ts","../../../src/utils/ai/extractors/stream-extractor.ts","../../../src/utils/ai/extractors/tool-call.ts","../../../src/utils/ai/safety/content-gate.ts","../../../src/utils/ai/safety/redactor.ts","../../../src/utils/ai/agents/chat-stream.ts","../../../src/utils/ai/agents/handoff.ts","../../../src/utils/ai/agents/tool-execution.ts","../../../src/utils/ai/agents/tool-registry.ts","../../../src/utils/ai/agents/tool-selector.ts","../../../src/utils/ai/memory/admission.ts","../../../src/utils/ai/memory/memory-composers.ts","../../../src/base/composition/distill.ts","../../../src/base/sources/async.ts","../../../src/base/utils/decay.ts","../../../src/utils/memory/index.ts","../../../src/utils/ai/graph-integration/gauges-as-context.ts","../../../src/utils/ai/graph-integration/graph-from-spec.ts","../../../src/utils/graphspec/index.ts","../../../src/utils/reduction/index.ts","../../../src/utils/ai/graph-integration/knobs-as-tools.ts","../../../src/utils/ai/graph-integration/suggest-strategy.ts","../../../src/utils/ai/graph-integration/validate-graph-def.ts"],"sourcesContent":["/**\n * Internal helpers shared by resilience sub-files.\n *\n * Not part of the public surface. The base-layer resilience operators\n * co-located here (`retry.ts`, `status.ts`, `timeout.ts`) import what they\n * need from this file directly; the utils-layer resilience primitives that\n * stayed in `utils/resilience/` (`breaker.ts`, `rate-limiter.ts`,\n * `fallback.ts`) import it top-down via `../../base/resilience/_internal.js`.\n *\n * `NodeOrValue<T>` is the only export re-surfaced publicly — there is no\n * `base/resilience/index.ts`; it ships through `utils/resilience/index.ts`\n * (and `utils/memory/index.ts`). Every resilience primitive that accepts\n * reactive options uses it as the option-arg shape.\n */\n\nimport type { Node, NodeOptions } from \"@graphrefly/pure-ts/core\";\nimport { DATA, type Message } from \"@graphrefly/pure-ts/core\";\n\nexport type ExtraOpts = Omit<NodeOptions, \"describeKind\">;\n\nexport function operatorOpts<T>(opts?: ExtraOpts): NodeOptions<T> {\n\treturn { describeKind: \"derived\", ...opts } as NodeOptions<T>;\n}\n\nexport function clampNonNegative(value: number): number {\n\treturn value < 0 ? 0 : value;\n}\n\nexport function msgVal(m: Message): unknown {\n\treturn m[1];\n}\n\nexport function coerceDelayNs(raw: number): number {\n\tif (typeof raw !== \"number\" || !Number.isFinite(raw)) {\n\t\tthrow new TypeError(\"backoff strategy must return a finite number\");\n\t}\n\treturn raw < 0 ? 0 : raw;\n}\n\nexport function isNode(x: unknown): x is Node {\n\treturn (\n\t\tx != null &&\n\t\ttypeof x === \"object\" &&\n\t\t\"cache\" in x &&\n\t\ttypeof (x as Node).subscribe === \"function\"\n\t);\n}\n\n/**\n * Either a literal value or a reactive Node carrying it. Mirrors\n * {@link FallbackInput}'s precedent for \"options that may be reactive.\"\n *\n * Used by {@link timeout} / {@link retry} / {@link rateLimiter} /\n * {@link circuitBreaker} / {@link budgetGate} to accept reactive option\n * configurations (Tier 6.5 3.2, 2026-04-29). Each primitive subscribes\n * to the option Node via {@link resolveReactiveOption} and rebinds\n * internal state per its locked swap-semantic rule (see each primitive's\n * JSDoc for the rule).\n *\n * @category extra\n */\nexport type NodeOrValue<T> = T | Node<T>;\n\n/**\n * Closure-mirror helper for `NodeOrValue<T>` options\n * (COMPOSITION-GUIDE §28). Returns:\n * - `current()` — read the latest value (cached at construction; updated\n * on each Node DATA emission).\n * - `unsub()` — release the subscription. Static-form arg never\n * subscribes; `unsub` is a no-op there.\n *\n * `onChange` fires on each DATA after the initial value (skips the\n * cache-seed read). Use to rebind primitive-internal state per the\n * primitive's locked swap-semantic rule.\n *\n * @internal\n */\nexport function resolveReactiveOption<T>(\n\targ: NodeOrValue<T>,\n\tonChange?: (next: T) => void,\n): { current: () => T; unsub: () => void } {\n\tif (!isNode(arg)) {\n\t\treturn { current: () => arg, unsub: () => undefined };\n\t}\n\tconst node = arg as Node<T>;\n\tlet latest: T = node.cache as T;\n\tconst unsub = node.subscribe((msgs) => {\n\t\tfor (const m of msgs) {\n\t\t\tif (m[0] === DATA) {\n\t\t\t\tlatest = m[1] as T;\n\t\t\t\tif (onChange) onChange(latest);\n\t\t\t}\n\t\t}\n\t});\n\treturn {\n\t\tcurrent: () => latest,\n\t\tunsub,\n\t};\n}\n\nexport function isThenable(x: unknown): x is PromiseLike<unknown> {\n\treturn x != null && typeof (x as PromiseLike<unknown>).then === \"function\";\n}\n\nexport function isAsyncIterable(x: unknown): x is AsyncIterable<unknown> {\n\treturn (\n\t\tx != null &&\n\t\ttypeof x === \"object\" &&\n\t\ttypeof (x as AsyncIterable<unknown>)[Symbol.asyncIterator] === \"function\"\n\t);\n}\n","/**\n * Backoff strategies for {@link retry} (roadmap §3.1). Delays are in **nanoseconds**.\n *\n * Convention: all graphrefly-ts timestamps and durations use nanoseconds (`_ns` suffix).\n * 1 second = 1_000_000_000 ns, 1 ms = 1_000_000 ns.\n */\n\nexport const NS_PER_MS = 1_000_000;\nexport const NS_PER_SEC = 1_000_000_000;\n\nexport type JitterMode = \"none\" | \"full\" | \"equal\";\n\nexport type BackoffPreset =\n\t| \"constant\"\n\t| \"linear\"\n\t| \"exponential\"\n\t| \"fibonacci\"\n\t| \"decorrelatedJitter\";\n\n/** `(attempt, error?, previousDelayNs?) => delayNs | null` — `null` means zero delay. */\nexport type BackoffStrategy = (\n\tattempt: number,\n\terror?: unknown,\n\tprevDelayNs?: number | null,\n) => number | null;\n\nfunction clampNonNegative(value: number): number {\n\treturn value < 0 ? 0 : value;\n}\n\nfunction applyJitter(delay: number, jitter: JitterMode): number {\n\tif (jitter === \"none\") return delay;\n\tif (jitter === \"full\") return Math.random() * delay;\n\treturn delay / 2 + Math.random() * (delay / 2);\n}\n\nfunction randomBetween(min: number, max: number): number {\n\treturn min + Math.random() * (max - min);\n}\n\n/**\n * Builds a strategy that always returns the same delay in nanoseconds.\n *\n * @param delayNs - Non-negative delay in nanoseconds; values below zero are clamped to zero.\n * @returns `BackoffStrategy` for use with {@link retry} or custom timers.\n *\n * @example\n * ```ts\n * import { constant, retry, NS_PER_SEC } from \"@graphrefly/graphrefly-ts\";\n *\n * const out = retry(source, { count: 3, backoff: constant(0.25 * NS_PER_SEC) });\n * ```\n *\n * @category extra\n */\nexport function constant(delayNs: number): BackoffStrategy {\n\tconst safe = clampNonNegative(delayNs);\n\treturn () => safe;\n}\n\n/**\n * Builds linear backoff: `baseNs + stepNs * attempt` (`stepNs` defaults to `baseNs`).\n *\n * @param baseNs - Base delay in nanoseconds (clamped non-negative).\n * @param stepNs - Added per retry attempt in nanoseconds (clamped non-negative).\n * @returns `BackoffStrategy` for {@link retry}.\n *\n * @example\n * ```ts\n * import { linear, retry, NS_PER_SEC } from \"@graphrefly/graphrefly-ts\";\n *\n * // Attempt 0 → 1 s, attempt 1 → 2 s, attempt 2 → 3 s …\n * const out = retry(source, { count: 4, backoff: linear(NS_PER_SEC) });\n * ```\n *\n * @category extra\n */\nexport function linear(baseNs: number, stepNs?: number): BackoffStrategy {\n\tconst safeBase = clampNonNegative(baseNs);\n\tconst safeStep = stepNs === undefined ? safeBase : clampNonNegative(stepNs);\n\treturn (attempt: number) => safeBase + safeStep * Math.max(0, attempt);\n}\n\nexport type ExponentialBackoffOptions = {\n\tbaseNs?: number;\n\tfactor?: number;\n\tmaxDelayNs?: number;\n\tjitter?: JitterMode;\n};\n\n/**\n * Builds exponential backoff in nanoseconds, capped by `maxDelayNs`, with optional jitter.\n *\n * @param options - Base, factor, cap, and jitter mode.\n * @returns `BackoffStrategy` for {@link retry}.\n *\n * @remarks\n * **Jitter:** `\"full\"` spreads delay across `[0, delay]`; `\"equal\"` uses `[delay/2, delay]`.\n *\n * @example\n * ```ts\n * import { exponential, retry, NS_PER_SEC } from \"@graphrefly/graphrefly-ts\";\n *\n * // 100 ms → 200 ms → 400 ms … capped at 30 s, with full jitter\n * const out = retry(source, {\n * count: 5,\n * backoff: exponential({ baseNs: 100 * NS_PER_SEC / 1000, jitter: \"full\" }),\n * });\n * ```\n *\n * @category extra\n */\nexport function exponential(options?: ExponentialBackoffOptions): BackoffStrategy {\n\tconst baseNs = clampNonNegative(options?.baseNs ?? 100 * NS_PER_MS);\n\tconst factor = options?.factor !== undefined && options.factor < 1 ? 1 : (options?.factor ?? 2);\n\tconst maxDelayNs = clampNonNegative(options?.maxDelayNs ?? 30 * NS_PER_SEC);\n\tconst jitter = options?.jitter ?? \"none\";\n\n\treturn (attempt: number) => {\n\t\tlet delay: number;\n\t\tif (baseNs === 0) {\n\t\t\tdelay = 0;\n\t\t} else if (factor === 1) {\n\t\t\tdelay = baseNs;\n\t\t} else {\n\t\t\tconst capRatio = maxDelayNs / baseNs;\n\t\t\tlet growth = 1;\n\t\t\tfor (let i = 0; i < Math.max(0, attempt); i++) {\n\t\t\t\tif (growth >= capRatio) {\n\t\t\t\t\tgrowth = capRatio;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tgrowth *= factor;\n\t\t\t}\n\t\t\tdelay = baseNs * growth;\n\t\t\tif (delay > maxDelayNs) delay = maxDelayNs;\n\t\t}\n\t\treturn applyJitter(delay, jitter);\n\t};\n}\n\n/**\n * Builds Fibonacci-scaled delays: `1, 2, 3, 5, … × baseNs`, capped at `maxDelayNs`.\n *\n * @param baseNs - Multiplier applied to the Fibonacci unit (default `100ms` in nanoseconds).\n * @param maxDelayNs - Upper bound in nanoseconds (default `30s`).\n * @returns `BackoffStrategy` for {@link retry}.\n *\n * @example\n * ```ts\n * import { fibonacci, retry, NS_PER_MS } from \"@graphrefly/graphrefly-ts\";\n *\n * // Delays: 100 ms, 200 ms, 300 ms, 500 ms, 800 ms … (× 100 ms base)\n * const out = retry(source, { count: 5, backoff: fibonacci(100 * NS_PER_MS) });\n * ```\n *\n * @category extra\n */\nexport function fibonacci(baseNs = 100 * NS_PER_MS, maxDelayNs = 30 * NS_PER_SEC): BackoffStrategy {\n\tconst safeBase = clampNonNegative(baseNs);\n\tconst safeMax = clampNonNegative(maxDelayNs);\n\n\tfunction fibUnit(attempt: number): number {\n\t\tif (attempt <= 0) return 1;\n\t\tlet prev = 1;\n\t\tlet cur = 2;\n\t\tfor (let i = 1; i < attempt; i++) {\n\t\t\tconst next = prev + cur;\n\t\t\tprev = cur;\n\t\t\tcur = next;\n\t\t}\n\t\treturn cur;\n\t}\n\n\treturn (attempt: number) => {\n\t\tconst raw = fibUnit(attempt) * safeBase;\n\t\treturn raw <= safeMax ? raw : safeMax;\n\t};\n}\n\n/**\n * Decorrelated jitter (AWS-recommended): `random(baseNs, min(maxNs, lastDelay * 3))`.\n *\n * Stateless — uses `prevDelayNs` (passed by the consumer) instead of closure state.\n * Safe to share across concurrent retry sequences.\n *\n * @param baseNs - Floor of the random range (default `100ms` in nanoseconds).\n * @param maxNs - Ceiling cap (default `30s` in nanoseconds).\n * @returns `BackoffStrategy` for {@link retry}.\n *\n * @example\n * ```ts\n * import { decorrelatedJitter, retry, NS_PER_MS, NS_PER_SEC } from \"@graphrefly/graphrefly-ts\";\n *\n * const out = retry(source, {\n * count: 6,\n * backoff: decorrelatedJitter(100 * NS_PER_MS, 10 * NS_PER_SEC),\n * });\n * ```\n *\n * @category extra\n */\nexport function decorrelatedJitter(\n\tbaseNs = 100 * NS_PER_MS,\n\tmaxNs = 30 * NS_PER_SEC,\n): BackoffStrategy {\n\treturn (_attempt, _error, prevDelayNs) => {\n\t\tconst last = prevDelayNs ?? baseNs;\n\t\tconst ceiling = Math.min(maxNs, last * 3);\n\t\treturn randomBetween(baseNs, ceiling);\n\t};\n}\n\n/**\n * Decorator that caps any strategy at `maxAttempts`. Returns `null` (stop retrying) after the cap.\n *\n * @param strategy - Inner strategy to wrap.\n * @param maxAttempts - Maximum number of attempts (inclusive).\n * @returns Wrapped `BackoffStrategy`.\n *\n * @example\n * ```ts\n * import { withMaxAttempts, exponential } from \"@graphrefly/graphrefly-ts\";\n *\n * const capped = withMaxAttempts(exponential(), 3);\n * capped(3); // null — no more retries beyond attempt 3\n * ```\n *\n * @category extra\n */\nexport function withMaxAttempts(strategy: BackoffStrategy, maxAttempts: number): BackoffStrategy {\n\treturn (attempt, error, prevDelayNs) => {\n\t\tif (attempt >= maxAttempts) return null;\n\t\treturn strategy(attempt, error, prevDelayNs);\n\t};\n}\n\n/**\n * Maps a preset name to a concrete {@link BackoffStrategy} with library-default parameters.\n *\n * @param name - One of `constant`, `linear`, `exponential`, `fibonacci`, or `decorrelatedJitter`.\n * @returns Configured strategy with default parameters.\n * @throws Error when `name` is not a known preset.\n *\n * @example\n * ```ts\n * import { resolveBackoffPreset, retry } from \"@graphrefly/graphrefly-ts\";\n *\n * const out = retry(source, { count: 3, backoff: resolveBackoffPreset(\"exponential\") });\n * // Equivalent to retry(source, { count: 3, backoff: exponential() })\n * ```\n *\n * @category extra\n */\nexport function resolveBackoffPreset(name: BackoffPreset): BackoffStrategy {\n\tif (name === \"constant\") return constant(1 * NS_PER_SEC);\n\tif (name === \"linear\") return linear(1 * NS_PER_SEC);\n\tif (name === \"exponential\") return exponential();\n\tif (name === \"fibonacci\") return fibonacci();\n\tif (name === \"decorrelatedJitter\") return decorrelatedJitter();\n\tthrow new Error(\n\t\t`Unknown backoff preset: \"${String(name)}\". Use one of: constant, linear, exponential, fibonacci, decorrelatedJitter`,\n\t);\n}\n","/**\n * AI surface patterns (roadmap §4.4).\n *\n * Domain-layer factories for LLM-backed agents, chat, tool registries, and\n * agentic memory. Composed from core + extra + Phase 3–4.3 primitives.\n *\n * This file is the public barrel — it re-exports symbols from the sibling\n * folders (`prompts/`, `extractors/`, `safety/`, `agents/`, `memory/`,\n * `graph-integration/`, and the existing `adapters/` tree). No implementation\n * code lives here; see each sibling folder for the actual primitives.\n *\n * @module\n */\n\n// ---------------------------------------------------------------------------\n// Adapter layer (§9.3d) — providers, middleware, routing primitives.\n// Browser-only adapters (WebLLM, ChromeNano) stay behind the `patterns/ai/browser`\n// subpath to keep Node bundles lean.\n// ---------------------------------------------------------------------------\n\nexport * from \"./adapters/core/capabilities.js\";\nexport * from \"./adapters/core/factory.js\";\nexport * from \"./adapters/core/observable.js\";\nexport * from \"./adapters/core/pricing.js\";\nexport * from \"./adapters/middleware/breaker.js\";\nexport * from \"./adapters/middleware/budget-gate.js\";\nexport * from \"./adapters/middleware/dry-run.js\";\nexport * from \"./adapters/middleware/http429-parser.js\";\nexport * from \"./adapters/middleware/rate-limiter.js\";\nexport * from \"./adapters/middleware/replay-cache.js\";\nexport * from \"./adapters/middleware/resilient-adapter.js\";\nexport * from \"./adapters/middleware/retry.js\";\nexport * from \"./adapters/middleware/timeout.js\";\nexport * from \"./adapters/providers/anthropic.js\";\nexport * from \"./adapters/providers/dry-run.js\";\nexport * from \"./adapters/providers/fallback.js\";\nexport * from \"./adapters/providers/google.js\";\nexport * from \"./adapters/providers/openai-compat.js\";\nexport * from \"./adapters/routing/cascading.js\";\n\n// ---------------------------------------------------------------------------\n// Types — single source of truth lives in ./adapters/core/types.ts\n// ---------------------------------------------------------------------------\n\nexport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n\tStreamDelta,\n\tTokenUsage,\n\tToolCall,\n\tToolDefinition,\n} from \"./adapters/core/types.js\";\n\n// ---------------------------------------------------------------------------\n// Prompt primitives\n// ---------------------------------------------------------------------------\n\n// `fromLLM` was folded into `promptNode({ format: \"raw\", tools })` per\n// Tier 2.3 — see `prompts/prompt-node.ts`.\nexport * from \"./prompts/frozen-context.js\";\nexport * from \"./prompts/prompt-call.js\";\nexport * from \"./prompts/prompt-node.js\";\nexport * from \"./prompts/streaming.js\";\nexport * from \"./prompts/system-prompt.js\";\n\n// ---------------------------------------------------------------------------\n// Stream extractors (taps on streamingPromptNode.stream topics)\n// ---------------------------------------------------------------------------\n\nexport * from \"./extractors/cost-meter.js\";\nexport * from \"./extractors/keyword-flag.js\";\nexport * from \"./extractors/stream-extractor.js\";\nexport * from \"./extractors/tool-call.js\";\n\n// ---------------------------------------------------------------------------\n// Content safety\n// ---------------------------------------------------------------------------\n\nexport * from \"./safety/content-gate.js\";\nexport * from \"./safety/redactor.js\";\n\n// ---------------------------------------------------------------------------\n// Agents (chat, tools, multi-agent routing — building blocks)\n// ---------------------------------------------------------------------------\n\nexport * from \"./agents/chat-stream.js\";\nexport * from \"./agents/handoff.js\";\nexport * from \"./agents/tool-execution.js\";\nexport * from \"./agents/tool-registry.js\";\nexport * from \"./agents/tool-selector.js\";\n\n// ---------------------------------------------------------------------------\n// Agentic memory building blocks (admission, composers, retrieval, tiers)\n// ---------------------------------------------------------------------------\n\nexport * from \"./memory/admission.js\";\nexport * from \"./memory/memory-composers.js\";\nexport * from \"./memory/retrieval.js\";\nexport * from \"./memory/tiers.js\";\n\n// ---------------------------------------------------------------------------\n// Graph ↔ LLM integration (knobs, gauges, spec round-trip)\n// ---------------------------------------------------------------------------\n\nexport * from \"./graph-integration/gauges-as-context.js\";\nexport * from \"./graph-integration/graph-from-spec.js\";\nexport * from \"./graph-integration/knobs-as-tools.js\";\nexport * from \"./graph-integration/suggest-strategy.js\";\nexport * from \"./graph-integration/validate-graph-def.js\";\n","/**\n * Pluggable model capabilities (roadmap §9.3d).\n *\n * The library defines the **shape** of what's knowable about a model\n * (context window, rate limits, features, pricing reference) and provides\n * a registry factory. Capability **data** is user-supplied — no baked-in\n * tables, no drift-prone catalog.\n */\n\nimport type { Node } from \"@graphrefly/pure-ts/core\";\nimport { node } from \"@graphrefly/pure-ts/core\";\n\nimport { reactiveMap } from \"@graphrefly/pure-ts/extra\";\nimport type { ModelPricing } from \"./pricing.js\";\n\n// ---------------------------------------------------------------------------\n// Limits\n// ---------------------------------------------------------------------------\n\n/**\n * Rate and size limits for a single model at the user's service tier.\n *\n * Where providers expose distinct standard / batch / flex limits, register\n * each as a separate model id with its own `ModelLimits`.\n */\nexport interface ModelLimits {\n\t/** Total tokens the model can process per request (input + output). */\n\tcontextWindow?: number;\n\t/** Max input tokens if distinct from contextWindow. */\n\tmaxInputTokens?: number;\n\t/** Max generated output tokens (excludes reasoning unless provider folds them). */\n\tmaxOutputTokens?: number;\n\t/** Max reasoning/thinking tokens budget. */\n\tmaxReasoningTokens?: number;\n\t/** Minimum prompt size for prompt caching to activate. */\n\tminCacheTokens?: number;\n\t/** Requests-per-minute rate limit. */\n\trpm?: number;\n\t/** Requests-per-day rate limit. */\n\trpd?: number;\n\t/** Tokens-per-minute rate limit (input + output, per provider convention). */\n\ttpm?: number;\n\t/** Tokens-per-day rate limit. */\n\ttpd?: number;\n\t/** Max concurrent in-flight requests. */\n\tconcurrentRequests?: number;\n\t/** Provider-specific limits not covered above. */\n\textensions?: Record<string, number>;\n}\n\n// ---------------------------------------------------------------------------\n// Features\n// ---------------------------------------------------------------------------\n\nexport interface ModelFeatures {\n\ttoolUse?: boolean;\n\tvision?: boolean;\n\taudioInput?: boolean;\n\taudioOutput?: boolean;\n\treasoning?: boolean;\n\tstreaming?: boolean;\n\tpromptCache?: boolean;\n\tbatchApi?: boolean;\n\t/** Provider-specific feature flags. */\n\textensions?: Record<string, boolean>;\n}\n\n// ---------------------------------------------------------------------------\n// ModelCapabilities\n// ---------------------------------------------------------------------------\n\n/** Static facts about a model. Pricing is optional; keep a separate registry if preferred. */\nexport interface ModelCapabilities {\n\tid: string;\n\tprovider: string;\n\tpricing?: ModelPricing;\n\tlimits?: ModelLimits;\n\tfeatures?: ModelFeatures;\n\t/** Free-form metadata (release date, deprecation flag, provider notes). */\n\tmetadata?: Record<string, unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// CapabilitiesRegistry\n// ---------------------------------------------------------------------------\n\nexport interface CapabilitiesRegistry {\n\tlookup(provider: string, model: string): ModelCapabilities | undefined;\n\tregister(cap: ModelCapabilities): void;\n\tremove(provider: string, model: string): boolean;\n\tentries(): IterableIterator<ModelCapabilities>;\n\t// Reactive views (Unit 10 Q4) ---------------------------------------------\n\t/**\n\t * Reactive view of `(provider, model)` → `ModelCapabilities`. Re-emits\n\t * whenever any `register()` / `remove()` touches the underlying store, so\n\t * UIs and gated middleware (capability-aware retry, feature flags) can\n\t * subscribe instead of polling. Prefix fallback mirrors the imperative\n\t * `lookup()`: exact match first, then longest-prefix within provider.\n\t */\n\tlookupNode(provider: string, model: string): Node<ModelCapabilities | undefined>;\n\t/** Reactive view of every registered entry. */\n\treadonly entriesNode: Node<readonly ModelCapabilities[]>;\n\t/** Reactive slice of entries for a single provider. */\n\tbyProvider(provider: string): Node<readonly ModelCapabilities[]>;\n}\n\nfunction capKey(provider: string, model: string): string {\n\treturn `${provider}::${model}`;\n}\n\n/** Create a fresh `CapabilitiesRegistry`. Optionally seed with entries. */\nexport function createCapabilitiesRegistry(\n\tinitial?: readonly ModelCapabilities[],\n): CapabilitiesRegistry {\n\t// Reactive storage (Unit 10 Q4). We keep the imperative `lookup` fast path\n\t// (O(1) exact match + prefix fallback) by reading the bundle's snapshot via\n\t// `.cache`. Reactive views (`lookupNode`, `entriesNode`, `byProvider`) are\n\t// `derived` nodes over the bundle's `entries` node.\n\tconst bundle = reactiveMap<string, ModelCapabilities>({\n\t\tname: \"capabilitiesRegistry\",\n\t});\n\n\tconst register = (cap: ModelCapabilities): void => {\n\t\tbundle.set(capKey(cap.provider, cap.id), cap);\n\t};\n\n\tif (initial) for (const cap of initial) register(cap);\n\n\tconst lookupSync = (provider: string, model: string): ModelCapabilities | undefined => {\n\t\tconst exact = bundle.get(capKey(provider, model));\n\t\tif (exact) return exact;\n\t\t// Prefix fallback within provider via snapshot iteration. The fast\n\t\t// path (`maxSize` unset → all entries live) keeps this O(|models|).\n\t\tconst snapshot = bundle.entries.cache;\n\t\tif (!snapshot) return undefined;\n\t\tlet best: ModelCapabilities | undefined;\n\t\tfor (const [, cap] of snapshot) {\n\t\t\tif (cap.provider !== provider) continue;\n\t\t\tconst candidate = cap.id;\n\t\t\tif (model.startsWith(candidate)) {\n\t\t\t\tif (!best || candidate.length > best.id.length) {\n\t\t\t\t\tbest = cap;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn best;\n\t};\n\n\t// Reactive views — derived over the bundle's entries snapshot. Caches\n\t// per-(provider, model) pair so re-invoking `lookupNode(\"anthropic\", \"X\")`\n\t// returns the same node (keepalive stays attached, no churn).\n\t//\n\t// LRU cap protects callers that mint `lookupNode(provider, userSupplied)`\n\t// from unbounded growth. Native `Map` insertion-order iteration gives us\n\t// O(1) eviction: the oldest insertion is the first key. 128 is large\n\t// enough to cover realistic provider × model combos (every shipped\n\t// Anthropic / OpenAI / Google model fits well under this).\n\tconst LOOKUP_CACHE_MAX = 128;\n\tconst lookupCache = new Map<string, Node<ModelCapabilities | undefined>>();\n\tconst byProviderCache = new Map<string, Node<readonly ModelCapabilities[]>>();\n\tconst lruTouch = <V>(cache: Map<string, V>, key: string, value: V, max: number): void => {\n\t\t// Delete-then-reinsert moves the key to the LRU end; evict the oldest\n\t\t// (first-inserted) entry when we overflow.\n\t\tif (cache.has(key)) cache.delete(key);\n\t\tcache.set(key, value);\n\t\twhile (cache.size > max) {\n\t\t\tconst oldest = cache.keys().next().value as string | undefined;\n\t\t\tif (oldest === undefined) break;\n\t\t\tcache.delete(oldest);\n\t\t}\n\t};\n\n\tconst entriesNode = node<readonly ModelCapabilities[]>(\n\t\t[bundle.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0];\n\t\t\t// Defensive coercion: `ReactiveMapBundle.entries` always emits a\n\t\t\t// real `Map` on the live emit path, but a snapshot-restore round\n\t\t\t// trip can deliver a plain `{}` (the default codec serializes\n\t\t\t// `Map` to a non-Map shape). Without the `instanceof` guard,\n\t\t\t// `.values()` would be `undefined`. Same defense pattern as\n\t\t\t// `mapFromSnapshot` in `extra/composite.ts`.\n\t\t\tactions.emit(\n\t\t\t\tsnapshot instanceof Map\n\t\t\t\t\t? Array.from((snapshot as ReadonlyMap<string, ModelCapabilities>).values())\n\t\t\t\t\t: [],\n\t\t\t);\n\t\t},\n\t\t{\n\t\t\tdescribeKind: \"derived\",\n\t\t\tname: \"capabilitiesRegistry/entries\",\n\t\t\tinitial: [] as ModelCapabilities[],\n\t\t},\n\t);\n\n\treturn {\n\t\tregister,\n\t\tlookup: lookupSync,\n\t\tremove(provider, model) {\n\t\t\tconst existed = bundle.has(capKey(provider, model));\n\t\t\tif (existed) bundle.delete(capKey(provider, model));\n\t\t\treturn existed;\n\t\t},\n\t\tentries() {\n\t\t\t// Snapshot via bundle — matches legacy behavior.\n\t\t\tconst snapshot = bundle.entries.cache;\n\t\t\treturn (function* () {\n\t\t\t\tif (!snapshot) return;\n\t\t\t\tfor (const cap of snapshot.values()) yield cap;\n\t\t\t})();\n\t\t},\n\t\tlookupNode(provider, model) {\n\t\t\tconst cacheKey = capKey(provider, model);\n\t\t\tconst cached = lookupCache.get(cacheKey);\n\t\t\tif (cached) {\n\t\t\t\t// LRU touch: move to end so it survives eviction.\n\t\t\t\tlookupCache.delete(cacheKey);\n\t\t\t\tlookupCache.set(cacheKey, cached);\n\t\t\t\treturn cached;\n\t\t\t}\n\t\t\tconst lookupNode = node<ModelCapabilities | undefined>(\n\t\t\t\t[bundle.entries],\n\t\t\t\t(_batchData, actions) => {\n\t\t\t\t\tactions.emit(lookupSync(provider, model));\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\t\tname: `capabilitiesRegistry/lookup/${provider}::${model}`,\n\t\t\t\t\tinitial: undefined,\n\t\t\t\t},\n\t\t\t);\n\t\t\tlruTouch(lookupCache, cacheKey, lookupNode, LOOKUP_CACHE_MAX);\n\t\t\treturn lookupNode;\n\t\t},\n\t\tentriesNode,\n\t\tbyProvider(provider) {\n\t\t\tconst cached = byProviderCache.get(provider);\n\t\t\tif (cached) {\n\t\t\t\tbyProviderCache.delete(provider);\n\t\t\t\tbyProviderCache.set(provider, cached);\n\t\t\t\treturn cached;\n\t\t\t}\n\t\t\tconst providerNode = node<readonly ModelCapabilities[]>(\n\t\t\t\t[entriesNode],\n\t\t\t\t(batchData, actions, ctx) => {\n\t\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t\t);\n\t\t\t\t\tconst entries = data[0] as readonly ModelCapabilities[];\n\t\t\t\t\tactions.emit(entries.filter((c) => c.provider === provider));\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\t\tname: `capabilitiesRegistry/byProvider/${provider}`,\n\t\t\t\t\tinitial: [],\n\t\t\t\t},\n\t\t\t);\n\t\t\tlruTouch(byProviderCache, provider, providerNode, LOOKUP_CACHE_MAX);\n\t\t\treturn providerNode;\n\t\t},\n\t};\n}\n","/**\n * AnthropicAdapter — default fetch-backed, optional SDK-backed.\n *\n * - `anthropicAdapter({ apiKey })` uses native `fetch` + SSE parsing.\n * - `anthropicAdapter({ sdk })` delegates to a user-provided `@anthropic-ai/sdk` instance.\n *\n * Token usage mapping:\n * - `input_tokens` → `input.regular`\n * - `cache_read_input_tokens` → `input.cacheRead`\n * - `cache_creation.ephemeral_5m_input_tokens` → `input.cacheWrite5m`\n * - `cache_creation.ephemeral_1h_input_tokens` → `input.cacheWrite1h`\n * - `cache_creation_input_tokens` (legacy) → `input.cacheWrite5m` (default TTL)\n * - `output_tokens` → `output.regular`\n * - `server_tool_use.web_search_requests` → `auxiliary.webSearchRequests`\n */\n\nimport { monotonicNs } from \"@graphrefly/pure-ts/core\";\nimport { makeHttpError } from \"../../../../base/io/http-error.js\";\nimport { parseSSEStream } from \"../../../../base/io/sse.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n\tStreamDelta,\n\tTokenUsage,\n\tToolDefinition,\n} from \"../core/types.js\";\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface AnthropicAdapterOptions {\n\t/** API key. Falls back to `process.env.ANTHROPIC_API_KEY` on Node. */\n\tapiKey?: string;\n\t/** Default model (overridable per-call via `LLMInvokeOptions.model`). */\n\tmodel?: string;\n\t/** Override the base URL. Default `https://api.anthropic.com`. */\n\tbaseURL?: string;\n\t/** API version header. Default `\"2023-06-01\"`. */\n\tanthropicVersion?: string;\n\t/** Additional headers to send on every request (overridden by per-call). */\n\theaders?: Record<string, string>;\n\t/**\n\t * User-provided SDK instance. When present, the adapter delegates to it\n\t * (uses `.messages.create`) instead of native fetch.\n\t * Shape matches `@anthropic-ai/sdk` `.messages` API; any object with a\n\t * compatible `create`/`stream` contract works.\n\t */\n\tsdk?: AnthropicSdkLike;\n\t/** Custom fetch (useful for tests). Default `globalThis.fetch`. */\n\tfetchImpl?: typeof fetch;\n}\n\n/** Minimal SDK shape we interoperate with. */\nexport interface AnthropicSdkLike {\n\tmessages: {\n\t\tcreate(\n\t\t\tparams: Record<string, unknown>,\n\t\t\topts?: { signal?: AbortSignal },\n\t\t): Promise<AnthropicMessageResponse>;\n\t\tstream?(\n\t\t\tparams: Record<string, unknown>,\n\t\t\topts?: { signal?: AbortSignal },\n\t\t): AsyncIterable<AnthropicStreamEvent>;\n\t};\n}\n\ninterface AnthropicMessageResponse {\n\tid: string;\n\tcontent: ReadonlyArray<\n\t\t| { type: \"text\"; text: string }\n\t\t| { type: \"tool_use\"; id: string; name: string; input: Record<string, unknown> }\n\t\t| { type: \"thinking\"; thinking: string }\n\t\t| { type: string; [key: string]: unknown }\n\t>;\n\tstop_reason?: string;\n\tusage: AnthropicUsage;\n\tmodel?: string;\n}\n\ninterface AnthropicUsage {\n\tinput_tokens?: number;\n\toutput_tokens?: number;\n\tcache_read_input_tokens?: number;\n\tcache_creation_input_tokens?: number;\n\tcache_creation?: {\n\t\tephemeral_5m_input_tokens?: number;\n\t\tephemeral_1h_input_tokens?: number;\n\t};\n\tserver_tool_use?: {\n\t\tweb_search_requests?: number;\n\t};\n}\n\ntype AnthropicStreamEvent =\n\t| { type: \"message_start\"; message: { usage: AnthropicUsage } }\n\t| { type: \"content_block_start\"; index: number; content_block: Record<string, unknown> }\n\t| { type: \"content_block_delta\"; index: number; delta: Record<string, unknown> }\n\t| { type: \"content_block_stop\"; index: number }\n\t| { type: \"message_delta\"; delta: { stop_reason?: string; usage?: AnthropicUsage } }\n\t| { type: \"message_stop\" }\n\t| { type: string; [key: string]: unknown };\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function anthropicAdapter(opts: AnthropicAdapterOptions = {}): LLMAdapter {\n\tif (opts.sdk) return sdkBackedAnthropic(opts);\n\treturn fetchBackedAnthropic(opts);\n}\n\n// ---------------------------------------------------------------------------\n// Request/response mapping\n// ---------------------------------------------------------------------------\n\nfunction toAnthropicRequest(\n\tmessages: readonly ChatMessage[],\n\tinvokeOpts: LLMInvokeOptions | undefined,\n\tdefaultModel: string | undefined,\n\tstream: boolean,\n): Record<string, unknown> {\n\tconst model = invokeOpts?.model ?? defaultModel;\n\tif (!model)\n\t\tthrow new Error(\"anthropicAdapter: model must be set via options.model or invokeOpts.model\");\n\n\tconst { system, chat } = partitionSystem(messages, invokeOpts?.systemPrompt);\n\n\tconst body: Record<string, unknown> = {\n\t\tmodel,\n\t\tmessages: chat.map(toAnthropicMessage),\n\t\tmax_tokens: invokeOpts?.maxTokens ?? 4096,\n\t};\n\tif (system) body.system = system;\n\tif (invokeOpts?.temperature != null) body.temperature = invokeOpts.temperature;\n\tif (invokeOpts?.tools && invokeOpts.tools.length > 0)\n\t\tbody.tools = invokeOpts.tools.map(toAnthropicTool);\n\tif (invokeOpts?.maxReasoningTokens != null) {\n\t\tbody.thinking = { type: \"enabled\", budget_tokens: invokeOpts.maxReasoningTokens };\n\t}\n\tif (invokeOpts?.cacheHint) {\n\t\t// Cache-control injected per-message by the user (Anthropic cache is\n\t\t// block-level). We surface the hint via metadata, but the canonical\n\t\t// cacheHint API is informational — power users pass cache_control\n\t\t// directly on messages via providerExtras.\n\t}\n\tif (stream) body.stream = true;\n\tif (invokeOpts?.providerExtras) Object.assign(body, invokeOpts.providerExtras);\n\treturn body;\n}\n\nfunction partitionSystem(\n\tmessages: readonly ChatMessage[],\n\tsystemPrompt: string | undefined,\n): { system: string | undefined; chat: readonly ChatMessage[] } {\n\tconst systemParts: string[] = [];\n\tif (systemPrompt) systemParts.push(systemPrompt);\n\tconst chat: ChatMessage[] = [];\n\tfor (const m of messages) {\n\t\tif (m.role === \"system\") systemParts.push(m.content);\n\t\telse chat.push(m);\n\t}\n\treturn { system: systemParts.length > 0 ? systemParts.join(\"\\n\\n\") : undefined, chat };\n}\n\nfunction toAnthropicMessage(m: ChatMessage): Record<string, unknown> {\n\tif (m.role === \"tool\") {\n\t\treturn {\n\t\t\trole: \"user\",\n\t\t\tcontent: [\n\t\t\t\t{\n\t\t\t\t\ttype: \"tool_result\",\n\t\t\t\t\ttool_use_id: m.toolCallId,\n\t\t\t\t\tcontent: m.content,\n\t\t\t\t},\n\t\t\t],\n\t\t};\n\t}\n\tif (m.role === \"assistant\" && m.toolCalls && m.toolCalls.length > 0) {\n\t\tconst blocks: unknown[] = [];\n\t\tif (m.content) blocks.push({ type: \"text\", text: m.content });\n\t\tfor (const tc of m.toolCalls) {\n\t\t\tblocks.push({ type: \"tool_use\", id: tc.id, name: tc.name, input: tc.arguments });\n\t\t}\n\t\treturn { role: \"assistant\", content: blocks };\n\t}\n\treturn { role: m.role, content: m.content };\n}\n\nfunction toAnthropicTool(t: ToolDefinition): Record<string, unknown> {\n\treturn {\n\t\tname: t.name,\n\t\tdescription: t.description,\n\t\tinput_schema: t.parameters,\n\t};\n}\n\n/**\n * Merge an incoming Anthropic usage update into the running snapshot. Unlike\n * a shallow spread, this preserves nested `cache_creation` fields when the\n * update omits them (or sends an empty object). Applied to both SSE and SDK\n * streaming paths.\n */\nfunction mergeAnthropicUsage(\n\tprev: AnthropicUsage | undefined,\n\tnext: AnthropicUsage,\n): AnthropicUsage {\n\tif (!prev) return { ...next };\n\tconst merged: AnthropicUsage = { ...prev };\n\t// Scalar fields: overwrite when present in `next`.\n\tif (next.input_tokens != null) merged.input_tokens = next.input_tokens;\n\tif (next.output_tokens != null) merged.output_tokens = next.output_tokens;\n\tif (next.cache_read_input_tokens != null)\n\t\tmerged.cache_read_input_tokens = next.cache_read_input_tokens;\n\tif (next.cache_creation_input_tokens != null)\n\t\tmerged.cache_creation_input_tokens = next.cache_creation_input_tokens;\n\t// Nested `cache_creation`: shallow-merge its own fields so a non-empty\n\t// update doesn't wipe a prior ephemeral_5m/1h value.\n\tif (next.cache_creation) {\n\t\tmerged.cache_creation = {\n\t\t\t...(prev.cache_creation ?? {}),\n\t\t\t...next.cache_creation,\n\t\t};\n\t}\n\tif (next.server_tool_use) {\n\t\tmerged.server_tool_use = {\n\t\t\t...(prev.server_tool_use ?? {}),\n\t\t\t...next.server_tool_use,\n\t\t};\n\t}\n\treturn merged;\n}\n\nfunction mapUsage(u: AnthropicUsage | undefined): TokenUsage {\n\tconst usage: TokenUsage = {\n\t\tinput: { regular: u?.input_tokens ?? 0 },\n\t\toutput: { regular: u?.output_tokens ?? 0 },\n\t\traw: u,\n\t};\n\tif (u?.cache_read_input_tokens) usage.input.cacheRead = u.cache_read_input_tokens;\n\tif (u?.cache_creation) {\n\t\tif (u.cache_creation.ephemeral_5m_input_tokens)\n\t\t\tusage.input.cacheWrite5m = u.cache_creation.ephemeral_5m_input_tokens;\n\t\tif (u.cache_creation.ephemeral_1h_input_tokens)\n\t\t\tusage.input.cacheWrite1h = u.cache_creation.ephemeral_1h_input_tokens;\n\t} else if (u?.cache_creation_input_tokens) {\n\t\t// Legacy flat field — default to 5m TTL.\n\t\tusage.input.cacheWrite5m = u.cache_creation_input_tokens;\n\t}\n\tif (u?.server_tool_use?.web_search_requests) {\n\t\tusage.auxiliary = { webSearchRequests: u.server_tool_use.web_search_requests };\n\t}\n\treturn usage;\n}\n\nfunction toLLMResponse(msg: AnthropicMessageResponse, latencyMs: number): LLMResponse {\n\tconst textParts: string[] = [];\n\tconst toolCalls: { id: string; name: string; arguments: Record<string, unknown> }[] = [];\n\tfor (const block of msg.content) {\n\t\tif (block.type === \"text\" && typeof (block as { text?: unknown }).text === \"string\") {\n\t\t\ttextParts.push((block as { text: string }).text);\n\t\t} else if (block.type === \"tool_use\") {\n\t\t\tconst tb = block as { id: string; name: string; input: Record<string, unknown> };\n\t\t\ttoolCalls.push({ id: tb.id, name: tb.name, arguments: tb.input ?? {} });\n\t\t}\n\t}\n\treturn {\n\t\tcontent: textParts.join(\"\"),\n\t\ttoolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n\t\tusage: mapUsage(msg.usage),\n\t\tfinishReason: msg.stop_reason,\n\t\tlatencyMs,\n\t\tmodel: msg.model,\n\t\tprovider: \"anthropic\",\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Fetch-backed impl\n// ---------------------------------------------------------------------------\n\nfunction fetchBackedAnthropic(opts: AnthropicAdapterOptions): LLMAdapter {\n\tconst apiKey =\n\t\topts.apiKey ??\n\t\t(globalThis as { process?: { env?: Record<string, string> } }).process?.env?.ANTHROPIC_API_KEY;\n\tif (!apiKey) {\n\t\t// Don't throw at construction — allow test harnesses / dry-run setups\n\t\t// that never call invoke. Throw at first use instead.\n\t}\n\tconst baseURL = opts.baseURL ?? \"https://api.anthropic.com\";\n\tconst anthropicVersion = opts.anthropicVersion ?? \"2023-06-01\";\n\tconst fetchImpl = opts.fetchImpl ?? fetch;\n\n\tconst commonHeaders = (): Record<string, string> => {\n\t\tif (!apiKey)\n\t\t\tthrow new Error(\"anthropicAdapter: apiKey required for invoke/stream (or provide opts.sdk)\");\n\t\treturn {\n\t\t\t\"x-api-key\": apiKey,\n\t\t\t\"anthropic-version\": anthropicVersion,\n\t\t\t\"content-type\": \"application/json\",\n\t\t\t...(opts.headers ?? {}),\n\t\t};\n\t};\n\n\treturn {\n\t\tprovider: \"anthropic\",\n\t\tmodel: opts.model,\n\n\t\tasync invoke(messages, invokeOpts): Promise<LLMResponse> {\n\t\t\tconst body = toAnthropicRequest(messages, invokeOpts, opts.model, false);\n\t\t\tconst start = monotonicNs();\n\t\t\tconst resp = await fetchImpl(`${baseURL}/v1/messages`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: commonHeaders(),\n\t\t\t\tbody: JSON.stringify(body),\n\t\t\t\tsignal: invokeOpts?.signal,\n\t\t\t});\n\t\t\tif (!resp.ok) throw await makeHttpError(resp, \"Anthropic\");\n\t\t\tconst json = (await resp.json()) as AnthropicMessageResponse;\n\t\t\tconst latencyMs = Math.max(0, (monotonicNs() - start) / 1e6);\n\t\t\treturn toLLMResponse(json, latencyMs);\n\t\t},\n\n\t\tasync *stream(messages, invokeOpts): AsyncGenerator<StreamDelta> {\n\t\t\tconst body = toAnthropicRequest(messages, invokeOpts, opts.model, true);\n\t\t\tconst resp = await fetchImpl(`${baseURL}/v1/messages`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { ...commonHeaders(), accept: \"text/event-stream\" },\n\t\t\t\tbody: JSON.stringify(body),\n\t\t\t\tsignal: invokeOpts?.signal,\n\t\t\t});\n\t\t\tif (!resp.ok) throw await makeHttpError(resp, \"Anthropic\");\n\t\t\tif (!resp.body) throw new Error(\"anthropicAdapter: streaming response has no body\");\n\n\t\t\tlet finalUsage: AnthropicUsage | undefined;\n\t\t\tlet finishReason: string | undefined;\n\t\t\tconst toolCallsByIndex: Map<number, { id: string; name: string; argBuf: string }> = new Map();\n\n\t\t\tfor await (const event of parseSSEStream(resp.body, { signal: invokeOpts?.signal })) {\n\t\t\t\tconst data = event.data;\n\t\t\t\tif (!data) continue;\n\t\t\t\tlet parsed: AnthropicStreamEvent;\n\t\t\t\ttry {\n\t\t\t\t\tparsed = JSON.parse(data) as AnthropicStreamEvent;\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tswitch (parsed.type) {\n\t\t\t\t\tcase \"message_start\": {\n\t\t\t\t\t\tconst ms = parsed as { message: { usage: AnthropicUsage } };\n\t\t\t\t\t\tfinalUsage = mergeAnthropicUsage(finalUsage, ms.message.usage);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"content_block_start\": {\n\t\t\t\t\t\tconst cb = parsed as { index: number; content_block: Record<string, unknown> };\n\t\t\t\t\t\tconst b = cb.content_block;\n\t\t\t\t\t\tif (b.type === \"tool_use\") {\n\t\t\t\t\t\t\ttoolCallsByIndex.set(cb.index, {\n\t\t\t\t\t\t\t\tid: String(b.id ?? \"\"),\n\t\t\t\t\t\t\t\tname: String(b.name ?? \"\"),\n\t\t\t\t\t\t\t\targBuf: \"\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\t\ttype: \"tool-call-delta\",\n\t\t\t\t\t\t\t\tdelta: { id: String(b.id ?? \"\"), name: String(b.name ?? \"\") },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"content_block_delta\": {\n\t\t\t\t\t\tconst cbd = parsed as { index: number; delta: Record<string, unknown> };\n\t\t\t\t\t\tconst d = cbd.delta;\n\t\t\t\t\t\tif (d.type === \"text_delta\" && typeof d.text === \"string\") {\n\t\t\t\t\t\t\tyield { type: \"token\", delta: d.text };\n\t\t\t\t\t\t} else if (d.type === \"input_json_delta\" && typeof d.partial_json === \"string\") {\n\t\t\t\t\t\t\tconst existing = toolCallsByIndex.get(cbd.index);\n\t\t\t\t\t\t\tif (existing) existing.argBuf += d.partial_json;\n\t\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\t\ttype: \"tool-call-delta\",\n\t\t\t\t\t\t\t\tdelta: { argumentsDelta: d.partial_json },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t} else if (d.type === \"thinking_delta\" && typeof d.thinking === \"string\") {\n\t\t\t\t\t\t\tyield { type: \"thinking\", delta: d.thinking };\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"message_delta\": {\n\t\t\t\t\t\tconst md = parsed as { delta: { stop_reason?: string; usage?: AnthropicUsage } };\n\t\t\t\t\t\tif (md.delta.stop_reason) finishReason = md.delta.stop_reason;\n\t\t\t\t\t\tif (md.delta.usage) {\n\t\t\t\t\t\t\tfinalUsage = mergeAnthropicUsage(finalUsage, md.delta.usage);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"message_stop\":\n\t\t\t\t\t\t// Fall through to finalize after the loop.\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (finalUsage) yield { type: \"usage\", usage: mapUsage(finalUsage) };\n\t\t\tyield { type: \"finish\", reason: finishReason ?? \"stop\" };\n\t\t},\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// SDK-backed impl\n// ---------------------------------------------------------------------------\n\nfunction sdkBackedAnthropic(opts: AnthropicAdapterOptions): LLMAdapter {\n\tconst sdk = opts.sdk;\n\tif (!sdk) throw new Error(\"sdkBackedAnthropic: sdk instance required\");\n\treturn {\n\t\tprovider: \"anthropic\",\n\t\tmodel: opts.model,\n\n\t\tasync invoke(messages, invokeOpts): Promise<LLMResponse> {\n\t\t\tconst body = toAnthropicRequest(messages, invokeOpts, opts.model, false);\n\t\t\tconst start = monotonicNs();\n\t\t\tconst resp = (await sdk.messages.create(body, {\n\t\t\t\tsignal: invokeOpts?.signal,\n\t\t\t})) as AnthropicMessageResponse;\n\t\t\tconst latencyMs = Math.max(0, (monotonicNs() - start) / 1e6);\n\t\t\treturn toLLMResponse(resp, latencyMs);\n\t\t},\n\n\t\tasync *stream(messages, invokeOpts): AsyncGenerator<StreamDelta> {\n\t\t\tif (!sdk.messages.stream) {\n\t\t\t\tthrow new Error(\"sdkBackedAnthropic: SDK instance does not expose .messages.stream\");\n\t\t\t}\n\t\t\tconst body = toAnthropicRequest(messages, invokeOpts, opts.model, true);\n\t\t\tlet finalUsage: AnthropicUsage | undefined;\n\t\t\tlet finishReason: string | undefined;\n\t\t\tfor await (const event of sdk.messages.stream(body, { signal: invokeOpts?.signal })) {\n\t\t\t\tswitch (event.type) {\n\t\t\t\t\tcase \"message_start\":\n\t\t\t\t\t\tfinalUsage = mergeAnthropicUsage(\n\t\t\t\t\t\t\tfinalUsage,\n\t\t\t\t\t\t\t(event as { message: { usage: AnthropicUsage } }).message.usage,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"content_block_delta\": {\n\t\t\t\t\t\tconst d = (event as { delta: Record<string, unknown> }).delta;\n\t\t\t\t\t\tif (d?.type === \"text_delta\" && typeof d.text === \"string\") {\n\t\t\t\t\t\t\tyield { type: \"token\", delta: d.text };\n\t\t\t\t\t\t} else if (d?.type === \"input_json_delta\" && typeof d.partial_json === \"string\") {\n\t\t\t\t\t\t\tyield { type: \"tool-call-delta\", delta: { argumentsDelta: d.partial_json } };\n\t\t\t\t\t\t} else if (d?.type === \"thinking_delta\" && typeof d.thinking === \"string\") {\n\t\t\t\t\t\t\tyield { type: \"thinking\", delta: d.thinking };\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"message_delta\": {\n\t\t\t\t\t\tconst md = event as { delta: { stop_reason?: string; usage?: AnthropicUsage } };\n\t\t\t\t\t\tif (md.delta.stop_reason) finishReason = md.delta.stop_reason;\n\t\t\t\t\t\tif (md.delta.usage) finalUsage = mergeAnthropicUsage(finalUsage, md.delta.usage);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (finalUsage) yield { type: \"usage\", usage: mapUsage(finalUsage) };\n\t\t\tyield { type: \"finish\", reason: finishReason ?? \"stop\" };\n\t\t},\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// SSE parser\n// ---------------------------------------------------------------------------\n","/**\n * HTTP error builder — companion to {@link ./adapters.ts}'s `fromHTTP` /\n * `fromHTTPStream` / `toHTTP`. Pure, zero-dep function that turns a failed\n * `Response` into an `Error` exposing the `{status, headers, message}` shape\n * that `HttpErrorLike` consumers (rate-limit parsers, retry predicates,\n * observability layers) expect.\n *\n * Universal tier — safe for browser and Node. No Node-only imports.\n */\n\n/**\n * Construct an `Error` carrying `status` + `headers` fields from a non-ok\n * `Response`. Reads the body with `resp.text()` for diagnostic context; a\n * body read failure is swallowed (empty string) so the returned error always\n * reflects the original status/statusText at minimum.\n *\n * @param resp - The offending `Response` object.\n * @param provider - Optional prefix (e.g. `\"Anthropic\"`, `\"openai\"`) used in\n * the error message. Defaults to `\"HTTP\"`.\n * @returns An `Error` whose `message` is `\"${provider} API <status>: <statusText>[ — body]\"`,\n * with `status: number` and `headers: Headers` attached.\n *\n * @category extra\n */\nexport async function makeHttpError(resp: Response, provider?: string): Promise<Error> {\n\tlet body: string;\n\ttry {\n\t\tbody = await resp.text();\n\t} catch {\n\t\tbody = \"\";\n\t}\n\tconst prefix = provider ?? \"HTTP\";\n\tconst err = new Error(\n\t\t`${prefix} API ${resp.status}: ${resp.statusText}${body ? ` — ${body}` : \"\"}`,\n\t) as Error & {\n\t\tstatus: number;\n\t\theaders: Headers;\n\t};\n\terr.status = resp.status;\n\terr.headers = resp.headers;\n\treturn err;\n}\n","/**\n * Server-Sent Events IO — `toSSE` / `toSSEBytes` (encode any node into the\n * `text/event-stream` wire format), `toReadableStream` (web-stream sink),\n * `parseSSEStream` (async-iterator parser), `fromSSE` (line-delimited parser\n * source).\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tDIRTY,\n\tdefaultConfig,\n\tERROR,\n\ttype Node,\n\tnode,\n\tRESOLVED,\n} from \"@graphrefly/pure-ts/core\";\nimport { type ExtraOpts, sourceOpts } from \"./_internal.js\";\n\n/** Options for {@link toSSE}. */\nexport type ToSSEOptions = {\n\t/** Custom payload serializer for non-string payloads. Default: `JSON.stringify` fallback to `String(value)`. */\n\tserialize?: (value: unknown) => string;\n\t/** Event name for DATA tuples. Default: `\"data\"`. */\n\tdataEvent?: string;\n\t/** Event name for ERROR tuples. Default: `\"error\"`. */\n\terrorEvent?: string;\n\t/** Event name for COMPLETE tuples. Default: `\"complete\"`. */\n\tcompleteEvent?: string;\n\t/** Emit `event: resolved` when RESOLVED arrives. Default: `false`. */\n\tincludeResolved?: boolean;\n\t/** Emit `event: dirty` when DIRTY arrives. Default: `false`. */\n\tincludeDirty?: boolean;\n\t/** Add SSE comment keepalive frames (`: keepalive`) on an interval. Disabled when unset. */\n\tkeepAliveMs?: number;\n\t/** Optional abort signal to terminate the stream early. */\n\tsignal?: AbortSignal;\n\t/** Maps custom message types to SSE event names. */\n\teventNameResolver?: (type: symbol) => string;\n};\n\nfunction messageTypeLabel(t: symbol): string {\n\treturn Symbol.keyFor(t) ?? t.description ?? \"message\";\n}\n\nfunction serializeSseData(value: unknown, serialize: (value: unknown) => string): string {\n\tif (typeof value === \"string\") return value;\n\treturn serialize(value);\n}\n\nfunction sseFrame(event: string, data?: string): string {\n\tlet out = `event: ${event}\\n`;\n\tif (data !== undefined) {\n\t\tconst lines = data.split(/\\r?\\n/);\n\t\tfor (const line of lines) {\n\t\t\tout += `data: ${line}\\n`;\n\t\t}\n\t}\n\treturn `${out}\\n`;\n}\n\n/**\n * Creates a standard Server-Sent Events stream from node messages.\n *\n * @category extra\n */\nexport function toSSE<T>(source: Node<T>, opts?: ToSSEOptions): ReadableStream<Uint8Array> {\n\tconst {\n\t\tserialize = (value: unknown) => {\n\t\t\tif (value instanceof Error) return value.message;\n\t\t\ttry {\n\t\t\t\treturn JSON.stringify(value);\n\t\t\t} catch {\n\t\t\t\treturn String(value);\n\t\t\t}\n\t\t},\n\t\tdataEvent = \"data\",\n\t\terrorEvent = \"error\",\n\t\tcompleteEvent = \"complete\",\n\t\tincludeResolved = false,\n\t\tincludeDirty = false,\n\t\tkeepAliveMs,\n\t\tsignal,\n\t\teventNameResolver = messageTypeLabel,\n\t} = opts ?? {};\n\tconst encoder = new TextEncoder();\n\tlet stop: (() => void) | undefined;\n\n\treturn new ReadableStream<Uint8Array>({\n\t\tstart(controller) {\n\t\t\tlet closed = false;\n\t\t\tlet keepAlive: ReturnType<typeof setInterval> | undefined;\n\t\t\tlet unsub: () => void = () => {};\n\t\t\tconst close = () => {\n\t\t\t\tif (closed) return;\n\t\t\t\tclosed = true;\n\t\t\t\tif (keepAlive !== undefined) clearInterval(keepAlive);\n\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\tunsub();\n\t\t\t\tcontroller.close();\n\t\t\t};\n\t\t\tstop = close;\n\t\t\tconst write = (event: string, data?: string) => {\n\t\t\t\tif (closed) return;\n\t\t\t\tcontroller.enqueue(encoder.encode(sseFrame(event, data)));\n\t\t\t};\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (closed) return;\n\t\t\t\tclose();\n\t\t\t};\n\t\t\tunsub = source.subscribe((msgs) => {\n\t\t\t\tfor (const msg of msgs) {\n\t\t\t\t\tconst t = msg[0];\n\t\t\t\t\t// Skip graph-local signals (tier < 3: START, DIRTY, INVALIDATE,\n\t\t\t\t\t// PAUSE, RESUME). DIRTY is opt-in for observability.\n\t\t\t\t\tif (defaultConfig.isLocalOnly(t)) {\n\t\t\t\t\t\tif (t === DIRTY && includeDirty) {\n\t\t\t\t\t\t\t/* fall through to write */\n\t\t\t\t\t\t} else continue;\n\t\t\t\t\t}\n\t\t\t\t\tif (t === DATA) {\n\t\t\t\t\t\twrite(dataEvent, serializeSseData(msg[1], serialize));\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (t === ERROR) {\n\t\t\t\t\t\twrite(errorEvent, serializeSseData(msg[1], serialize));\n\t\t\t\t\t\tclose();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (t === COMPLETE) {\n\t\t\t\t\t\twrite(completeEvent);\n\t\t\t\t\t\tclose();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// RESOLVED (tier 3) is opt-in for observability.\n\t\t\t\t\tif (!includeResolved && t === RESOLVED) continue;\n\t\t\t\t\twrite(\n\t\t\t\t\t\teventNameResolver(t),\n\t\t\t\t\t\tmsg.length > 1 ? serializeSseData(msg[1], serialize) : undefined,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\t\t\tif (keepAliveMs !== undefined && keepAliveMs > 0) {\n\t\t\t\tkeepAlive = setInterval(() => {\n\t\t\t\t\tif (closed) return;\n\t\t\t\t\tcontroller.enqueue(encoder.encode(\": keepalive\\n\\n\"));\n\t\t\t\t}, keepAliveMs);\n\t\t\t}\n\t\t\tif (signal?.aborted) onAbort();\n\t\t\telse signal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t},\n\t\tcancel() {\n\t\t\tstop?.();\n\t\t},\n\t});\n}\n\n/**\n * Composable variant of {@link toSSE} — emits encoded SSE frames as\n * `Uint8Array` through a reactive `Node`. Use this when you want to pipe SSE\n * bytes through the reactive graph (persist to file, tee to multiple streams,\n * etc.). Wrap with {@link toReadableStream} to expose a `ReadableStream` for\n * `new Response(...)` use cases.\n *\n * @category extra\n */\nexport function toSSEBytes<T>(source: Node<T>, opts?: ToSSEOptions): Node<Uint8Array> {\n\tconst {\n\t\tserialize = (value: unknown) => {\n\t\t\tif (value instanceof Error) return value.message;\n\t\t\ttry {\n\t\t\t\treturn JSON.stringify(value);\n\t\t\t} catch {\n\t\t\t\treturn String(value);\n\t\t\t}\n\t\t},\n\t\tdataEvent = \"data\",\n\t\terrorEvent = \"error\",\n\t\tcompleteEvent = \"complete\",\n\t\tincludeResolved = false,\n\t\tincludeDirty = false,\n\t\tkeepAliveMs,\n\t\tsignal,\n\t\teventNameResolver = messageTypeLabel,\n\t} = opts ?? {};\n\tconst encoder = new TextEncoder();\n\treturn node<Uint8Array>([], (_data, a) => {\n\t\tlet active = true;\n\t\tlet keepAlive: ReturnType<typeof setInterval> | undefined;\n\t\tconst emitFrame = (event: string, data?: string) => {\n\t\t\tif (!active) return;\n\t\t\ta.emit(encoder.encode(sseFrame(event, data)));\n\t\t};\n\t\tconst onAbort = () => {\n\t\t\tif (!active) return;\n\t\t\tactive = false;\n\t\t\ta.down([[COMPLETE]]);\n\t\t};\n\t\tconst unsub = source.subscribe((msgs) => {\n\t\t\tif (!active) return;\n\t\t\tfor (const msg of msgs) {\n\t\t\t\tconst t = msg[0];\n\t\t\t\tif (defaultConfig.isLocalOnly(t)) {\n\t\t\t\t\tif (t === DIRTY && includeDirty) {\n\t\t\t\t\t\t/* fall through */\n\t\t\t\t\t} else continue;\n\t\t\t\t}\n\t\t\t\tif (t === DATA) {\n\t\t\t\t\temitFrame(dataEvent, serializeSseData(msg[1], serialize));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (t === ERROR) {\n\t\t\t\t\temitFrame(errorEvent, serializeSseData(msg[1], serialize));\n\t\t\t\t\tactive = false;\n\t\t\t\t\ta.down([[COMPLETE]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (t === COMPLETE) {\n\t\t\t\t\temitFrame(completeEvent);\n\t\t\t\t\tactive = false;\n\t\t\t\t\ta.down([[COMPLETE]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!includeResolved && t === RESOLVED) continue;\n\t\t\t\temitFrame(\n\t\t\t\t\teventNameResolver(t),\n\t\t\t\t\tmsg.length > 1 ? serializeSseData(msg[1], serialize) : undefined,\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t\tif (keepAliveMs !== undefined && keepAliveMs > 0) {\n\t\t\tkeepAlive = setInterval(() => {\n\t\t\t\tif (!active) return;\n\t\t\t\ta.emit(encoder.encode(\": keepalive\\n\\n\"));\n\t\t\t}, keepAliveMs);\n\t\t}\n\t\tif (signal?.aborted) onAbort();\n\t\telse signal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\treturn () => {\n\t\t\tactive = false;\n\t\t\tif (keepAlive !== undefined) clearInterval(keepAlive);\n\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\tunsub();\n\t\t};\n\t});\n}\n\n/**\n * Converts a `Node<Uint8Array>` into a WHATWG `ReadableStream<Uint8Array>`.\n * Useful for composing with `new Response(...)` / `fetch` bodies.\n *\n * @category extra\n */\nexport function toReadableStream(bytes: Node<Uint8Array>): ReadableStream<Uint8Array> {\n\tlet unsub: (() => void) | undefined;\n\tlet closed = false;\n\treturn new ReadableStream<Uint8Array>({\n\t\tstart(controller) {\n\t\t\tunsub = bytes.subscribe((msgs) => {\n\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\tconst t = m[0];\n\t\t\t\t\tif (closed) return;\n\t\t\t\t\tif (t === DATA) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tcontroller.enqueue(m[1] as Uint8Array);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t/* controller closed mid-batch — upstream unsub will follow */\n\t\t\t\t\t\t\tclosed = true;\n\t\t\t\t\t\t\tunsub?.();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (t === ERROR) {\n\t\t\t\t\t\tclosed = true;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tcontroller.error(m[1]);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t/* controller already closed */\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} else if (t === COMPLETE) {\n\t\t\t\t\t\tclosed = true;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t/* controller already closed */\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tcancel() {\n\t\t\tclosed = true;\n\t\t\tunsub?.();\n\t\t},\n\t});\n}\n\n/** Parsed Server-Sent Event. */\nexport type SSEEvent<T = string> = {\n\tevent: string;\n\tdata: T;\n\tid?: string;\n\tretry?: number;\n};\n\n/** Options for {@link fromSSE}. */\nexport type FromSSEOptions<T = string> = ExtraOpts & {\n\t/** Parse the raw `data:` payload. Default: identity (string). */\n\tparse?: (raw: string) => T;\n};\n\n/** Options for {@link parseSSEStream}. */\nexport type ParseSSEStreamOptions<T = string> = {\n\t/** Parse the raw `data:` payload. Default: identity (string). */\n\tparse?: (raw: string) => T;\n\t/**\n\t * External abort signal. If aborted, the generator returns early after\n\t * cancelling the underlying reader / iterator. Does not emit an error —\n\t * the generator simply ends.\n\t */\n\tsignal?: AbortSignal;\n};\n\n/**\n * Parses a Server-Sent Events byte stream into an async-iterator of structured\n * `{event, data, id, retry}` records. Pure async generator with no reactive\n * dependency — safe to consume anywhere an `AsyncIterable<SSEEvent>` is\n * expected (LLM provider adapters, tests, non-reactive transports).\n *\n * Handles:\n * - Arbitrary chunk boundaries (internal text buffer + `TextDecoder` streaming).\n * - `\\n` and `\\r\\n` line endings.\n * - `event:` / `data:` (multi-line via repeated fields) / `id:` / `retry:`.\n * - Comments (`:` prefix).\n * - Cancels the underlying reader / iterator on external abort or consumer\n * break, so a quiet stream doesn't leak pending `read()` calls.\n *\n * Used internally by {@link fromSSE} (reactive `Node<SSEEvent>`) — exposed as a\n * pure helper so LLM provider adapters (Anthropic, OpenAI, Google) can parse\n * their SSE streams without building a reactive node per call.\n *\n * @param source - SSE byte source (`ReadableStream`, `Response`, or `AsyncIterable<Uint8Array>`).\n * @param opts - `{ parse?, signal? }`.\n * @returns `AsyncGenerator<SSEEvent<T>>` — yields one event per SSE block; returns on stream end / abort.\n *\n * @category extra\n */\nexport async function* parseSSEStream<T = string>(\n\tsource: ReadableStream<Uint8Array> | Response | AsyncIterable<Uint8Array>,\n\topts?: ParseSSEStreamOptions<T>,\n): AsyncGenerator<SSEEvent<T>, void, unknown> {\n\tconst parse = opts?.parse ?? ((raw: string) => raw as unknown as T);\n\tconst externalSignal = opts?.signal;\n\n\tconst decoder = new TextDecoder();\n\tlet buffer = \"\";\n\tlet currentEvent = \"message\";\n\tlet currentData: string[] = [];\n\tlet currentId: string | undefined;\n\tlet currentRetry: number | undefined;\n\tconst queue: SSEEvent<T>[] = [];\n\n\tconst flushEvent = () => {\n\t\tif (currentData.length === 0 && currentEvent === \"message\" && currentId === undefined) {\n\t\t\tcurrentData = [];\n\t\t\treturn;\n\t\t}\n\t\tconst raw = currentData.join(\"\\n\");\n\t\tqueue.push({\n\t\t\tevent: currentEvent,\n\t\t\tdata: parse(raw),\n\t\t\tid: currentId,\n\t\t\tretry: currentRetry,\n\t\t});\n\t\tcurrentEvent = \"message\";\n\t\tcurrentData = [];\n\t\tcurrentId = undefined;\n\t\tcurrentRetry = undefined;\n\t};\n\n\tconst processLine = (line: string) => {\n\t\tif (line === \"\") {\n\t\t\tflushEvent();\n\t\t\treturn;\n\t\t}\n\t\tif (line.startsWith(\":\")) return; // comment\n\t\tconst colon = line.indexOf(\":\");\n\t\tconst field = colon < 0 ? line : line.slice(0, colon);\n\t\tlet value = colon < 0 ? \"\" : line.slice(colon + 1);\n\t\tif (value.startsWith(\" \")) value = value.slice(1);\n\t\tswitch (field) {\n\t\t\tcase \"event\":\n\t\t\t\tcurrentEvent = value;\n\t\t\t\tbreak;\n\t\t\tcase \"data\":\n\t\t\t\tcurrentData.push(value);\n\t\t\t\tbreak;\n\t\t\tcase \"id\":\n\t\t\t\tif (!value.includes(\"\\0\")) currentId = value;\n\t\t\t\tbreak;\n\t\t\tcase \"retry\": {\n\t\t\t\tconst n = Number(value);\n\t\t\t\tif (Number.isFinite(n)) currentRetry = n;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t};\n\n\tconst processChunk = (chunk: Uint8Array, done: boolean) => {\n\t\tbuffer += decoder.decode(chunk, { stream: !done });\n\t\tconst parts = buffer.split(/\\r?\\n/);\n\t\tbuffer = parts.pop() ?? \"\";\n\t\tfor (const line of parts) processLine(line);\n\t};\n\n\t// Resolve the underlying byte source into either a `ReadableStream` or an\n\t// `AsyncIterator<Uint8Array>` — identical dispatch as the legacy fromSSE.\n\tconst resp = source as Response;\n\tconst stream =\n\t\tsource instanceof ReadableStream\n\t\t\t? source\n\t\t\t: resp && typeof resp === \"object\" && resp.body instanceof ReadableStream\n\t\t\t\t? resp.body\n\t\t\t\t: null;\n\n\tlet reader: ReadableStreamDefaultReader<Uint8Array> | undefined;\n\tlet iter: AsyncIterator<Uint8Array> | undefined;\n\t// `cleanupDone` flips once we've invoked `reader.cancel()` / `iter.return()`\n\t// — guards against the `onAbort` listener + the `finally` path both\n\t// cancelling the same underlying resource (WHATWG streams allow double-\n\t// cancel but custom `AsyncIterator.return` implementations are not\n\t// required to be idempotent).\n\tlet cleanupDone = false;\n\tconst cleanupReader = (): void => {\n\t\tif (cleanupDone) return;\n\t\tcleanupDone = true;\n\t\tif (reader) {\n\t\t\tvoid reader.cancel().catch(() => undefined);\n\t\t}\n\t\tif (iter && typeof iter.return === \"function\") {\n\t\t\tvoid Promise.resolve(iter.return()).catch(() => undefined);\n\t\t}\n\t};\n\n\t// Wire the external abort signal to cancel the reader / iterator promptly\n\t// instead of waiting for the next chunk.\n\tconst onAbort = (): void => {\n\t\tcleanupReader();\n\t};\n\tif (externalSignal) {\n\t\tif (externalSignal.aborted) return;\n\t\texternalSignal.addEventListener(\"abort\", onAbort, { once: true });\n\t}\n\n\ttry {\n\t\tif (stream) {\n\t\t\treader = stream.getReader();\n\t\t\twhile (!externalSignal?.aborted) {\n\t\t\t\tconst { value, done } = await reader.read();\n\t\t\t\tif (done) break;\n\t\t\t\tprocessChunk(value, false);\n\t\t\t\twhile (queue.length > 0) {\n\t\t\t\t\tconst ev = queue.shift() as SSEEvent<T>;\n\t\t\t\t\tyield ev;\n\t\t\t\t}\n\t\t\t}\n\t\t\tprocessChunk(new Uint8Array(), true);\n\t\t} else {\n\t\t\tconst asyncIter = source as AsyncIterable<Uint8Array>;\n\t\t\titer = asyncIter[Symbol.asyncIterator]();\n\t\t\twhile (!externalSignal?.aborted) {\n\t\t\t\tconst step = await iter.next();\n\t\t\t\tif (step.done) break;\n\t\t\t\tprocessChunk(step.value, false);\n\t\t\t\twhile (queue.length > 0) {\n\t\t\t\t\tconst ev = queue.shift() as SSEEvent<T>;\n\t\t\t\t\tyield ev;\n\t\t\t\t}\n\t\t\t}\n\t\t\tprocessChunk(new Uint8Array(), true);\n\t\t}\n\t\tif (buffer.trim()) {\n\t\t\tfor (const line of buffer.split(/\\r?\\n/)) processLine(line);\n\t\t\tflushEvent();\n\t\t}\n\t\twhile (queue.length > 0) {\n\t\t\tconst ev = queue.shift() as SSEEvent<T>;\n\t\t\tyield ev;\n\t\t}\n\t} finally {\n\t\tif (externalSignal) {\n\t\t\texternalSignal.removeEventListener(\"abort\", onAbort);\n\t\t}\n\t\t// Idempotent cleanup — if `onAbort` already ran the cancel, this is a\n\t\t// no-op. Covers the normal consumer-break path (generator exits → finally\n\t\t// runs → cancel underlying reader / iterator so a quiet upstream\n\t\t// doesn't leak its `read()` call).\n\t\tcleanupReader();\n\t}\n}\n\n/**\n * Parses a Server-Sent Events stream into structured `{event, data, id}` records.\n *\n * @param source - SSE byte source (`ReadableStream`, `Response`, or `AsyncIterable<Uint8Array>`).\n * @param opts - Parse function and node options.\n * @returns `Node<SSEEvent<T>>` — one `DATA` per SSE event; `COMPLETE` on stream end.\n *\n * @category extra\n */\nexport function fromSSE<T = string>(\n\tsource: ReadableStream<Uint8Array> | Response | AsyncIterable<Uint8Array>,\n\topts?: FromSSEOptions<T>,\n): Node<SSEEvent<T>> {\n\tconst { parse, ...rest } = opts ?? {};\n\treturn node<SSEEvent<T>>(\n\t\t[],\n\t\t(_data, a) => {\n\t\t\tlet active = true;\n\t\t\tconst ctrl = new AbortController();\n\t\t\tconst run = async () => {\n\t\t\t\ttry {\n\t\t\t\t\tfor await (const ev of parseSSEStream<T>(source, { parse, signal: ctrl.signal })) {\n\t\t\t\t\t\tif (!active) return;\n\t\t\t\t\t\ta.emit(ev);\n\t\t\t\t\t}\n\t\t\t\t\tif (active) a.down([[COMPLETE]]);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (active) a.down([[ERROR, err]]);\n\t\t\t\t}\n\t\t\t};\n\t\t\tvoid run();\n\t\t\treturn () => {\n\t\t\t\tactive = false;\n\t\t\t\tctrl.abort();\n\t\t\t};\n\t\t},\n\t\tsourceOpts(rest),\n\t);\n}\n","/**\n * DryRunAdapter — zero-cost mock provider.\n *\n * Returns a deterministic fake response (plus a configurable hook for\n * customization). Useful for: pipeline smoke tests, CI without API keys,\n * local development, and as the leaf of a `cascadingLlmAdapter` when every\n * real tier fails.\n *\n * The library ships a minimal implementation only — richer scenario-\n * scripted mocks (per-stage responses, call recording) belong at the test\n * harness layer, not in the shipped library.\n *\n * Uses `ResettableTimer` for simulated latency (spec §5.10 escape hatch\n * documented on the class), and throws an `AbortError`-named Error on\n * abort so retry/timeout middleware can classify it.\n */\n\nimport { ResettableTimer } from \"@graphrefly/pure-ts/core\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n\tStreamDelta,\n\tTokenUsage,\n} from \"../core/types.js\";\n\nexport interface DryRunAdapterOptions {\n\tprovider?: string;\n\tmodel?: string;\n\t/** Generate the fake response. Defaults to echoing the last user message. */\n\trespond?: (messages: readonly ChatMessage[], opts?: LLMInvokeOptions) => string;\n\t/**\n\t * Generate a fake usage object. Defaults to a simple character-count\n\t * heuristic (`input = sum(messages) / 4`, `output = content / 4`).\n\t */\n\tusage?: (messages: readonly ChatMessage[], content: string) => TokenUsage;\n\t/** Simulated latency in milliseconds (applied to both invoke and stream). */\n\tlatencyMs?: number;\n\t/** Stream chunk size in characters. Default 16. */\n\tstreamChunkSize?: number;\n}\n\nfunction makeAbortError(): Error {\n\tconst err = new Error(\"aborted\") as Error & { name: string };\n\terr.name = \"AbortError\";\n\treturn err;\n}\n\n/**\n * Abort-aware sleep using `ResettableTimer`. Spec §5.10 escape hatch.\n * No-op if `ms <= 0`; rejects with `AbortError` if the signal aborts.\n */\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\tif (ms <= 0) return Promise.resolve();\n\tif (signal?.aborted) return Promise.reject(makeAbortError());\n\treturn new Promise((resolve, reject) => {\n\t\tconst timer = new ResettableTimer();\n\t\tlet onAbort: (() => void) | undefined;\n\t\tconst cleanup = (): void => {\n\t\t\ttimer.cancel();\n\t\t\tif (signal && onAbort) signal.removeEventListener(\"abort\", onAbort);\n\t\t};\n\t\ttimer.start(ms, () => {\n\t\t\tcleanup();\n\t\t\tresolve();\n\t\t});\n\t\tif (signal) {\n\t\t\tonAbort = (): void => {\n\t\t\t\tcleanup();\n\t\t\t\treject(makeAbortError());\n\t\t\t};\n\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t}\n\t});\n}\n\n/**\n * Create a DryRun adapter.\n *\n * @example\n * ```ts\n * const adapter = dryRunAdapter({ respond: (msgs) => \"hello from dry-run\" });\n * const resp = await Promise.resolve(adapter.invoke([{ role: \"user\", content: \"hi\" }]));\n * ```\n */\nexport function dryRunAdapter(opts: DryRunAdapterOptions = {}): LLMAdapter {\n\tconst provider = opts.provider ?? \"dry-run\";\n\tconst model = opts.model ?? \"dry-run-v1\";\n\tconst latencyMs = opts.latencyMs ?? 0;\n\tconst streamChunkSize = Math.max(1, opts.streamChunkSize ?? 16);\n\n\tconst respondFn =\n\t\topts.respond ??\n\t\t((msgs: readonly ChatMessage[]): string => {\n\t\t\tconst lastUser = [...msgs].reverse().find((m) => m.role === \"user\");\n\t\t\treturn lastUser ? `echo: ${lastUser.content}` : \"dry-run: no user message\";\n\t\t});\n\n\tconst usageFn =\n\t\topts.usage ??\n\t\t((msgs: readonly ChatMessage[], content: string): TokenUsage => {\n\t\t\tconst totalInput = msgs.reduce((s, m) => s + m.content.length, 0);\n\t\t\treturn {\n\t\t\t\tinput: { regular: Math.ceil(totalInput / 4) },\n\t\t\t\toutput: { regular: Math.ceil(content.length / 4) },\n\t\t\t};\n\t\t});\n\n\treturn {\n\t\tprovider,\n\t\tmodel,\n\n\t\tasync invoke(messages, invokeOpts): Promise<LLMResponse> {\n\t\t\tawait sleep(latencyMs, invokeOpts?.signal);\n\t\t\tif (invokeOpts?.signal?.aborted) throw makeAbortError();\n\t\t\tconst content = respondFn(messages, invokeOpts);\n\t\t\tconst usage = usageFn(messages, content);\n\t\t\treturn {\n\t\t\t\tcontent,\n\t\t\t\tusage,\n\t\t\t\tfinishReason: \"stop\",\n\t\t\t\tmodel: invokeOpts?.model ?? model,\n\t\t\t\tprovider,\n\t\t\t\ttier: invokeOpts?.tier,\n\t\t\t\tmetadata: { dryRun: true },\n\t\t\t};\n\t\t},\n\n\t\tasync *stream(messages, invokeOpts): AsyncGenerator<StreamDelta> {\n\t\t\tconst content = respondFn(messages, invokeOpts);\n\t\t\tconst usage = usageFn(messages, content);\n\t\t\tconst chunkCount = Math.ceil(content.length / streamChunkSize) || 1;\n\t\t\tconst perChunkMs = latencyMs > 0 ? latencyMs / chunkCount : 0;\n\t\t\tfor (let i = 0; i < content.length; i += streamChunkSize) {\n\t\t\t\tif (invokeOpts?.signal?.aborted) throw makeAbortError();\n\t\t\t\tawait sleep(perChunkMs, invokeOpts?.signal);\n\t\t\t\tyield { type: \"token\", delta: content.slice(i, i + streamChunkSize) };\n\t\t\t}\n\t\t\tyield { type: \"usage\", usage };\n\t\t\tyield { type: \"finish\", reason: \"stop\" };\n\t\t},\n\t};\n}\n","/**\n * `fallbackAdapter` — fixture-backed {@link LLMAdapter} for offline demos,\n * deterministic tests, and graceful degradation in production.\n *\n * A peer of `anthropicAdapter` / `openAICompatAdapter` / `googleAdapter` /\n * `ollamaAdapter` / `dryRunAdapter`, but whose role is to serve pre-recorded\n * or canned responses when real providers aren't reachable. Install it as a\n * tier via the existing routing primitives (no new composer needed):\n *\n * ```ts\n * // Graceful offline fallback for a user app:\n * resilientAdapter(anthropicAdapter({ ... }), {\n * fallback: fallbackAdapter({ fixturesDir: \"./fixtures\" }),\n * });\n *\n * // Or the general N-tier shape:\n * cascadingLlmAdapter([\n * { name: \"primary\", adapter: anthropicAdapter({ ... }) },\n * { name: \"fallback\", adapter: fallbackAdapter({ fixturesDir: \"./fixtures\" }) },\n * ]);\n * ```\n *\n * The `provider` field is `\"fallback\"` so its role is self-documenting in\n * logs, stats, cost tables, and audit trails.\n *\n * ## Three fixture sources (mutually exclusive)\n *\n * Pick exactly one of:\n *\n * 1. **`fixtures: FallbackFixture[]`** — inline, hand-authored. Supports\n * both hash-keyed and messages-keyed shapes; the adapter computes the\n * canonical hash for messages-keyed entries at init time. Ideal when you\n * want full control in code (tests, small demos).\n *\n * 2. **`fixturesStorage: KvStorageTier`** — the escape hatch for any backend.\n * Pass a `memoryKv()`, `indexedDbKv(...)`, `sqliteKv(...)`,\n * `cascadingCache(...)`, or a custom tier. You own the layout — no\n * auto-namespacing.\n *\n * **Filesystem directories (Node only):** the core `fallbackAdapter`\n * does NOT import `node:fs` / `node:path` — it's safe to bundle for\n * browsers. For a directory convenience, import `fallbackAdapter` from\n * `@graphrefly/graphrefly/patterns/ai/node` (node subpath);\n * that variant adds `fixturesDir: string` (auto-namespaced to\n * `join(dir, keyPrefix)`, cache-format validated at init).\n *\n * ## Record mode\n *\n * `record: { adapter: real, storage }` proxies every call to `real` AND\n * persists the response through the provided tier. Use the node subpath's\n * `fallbackAdapter` for `record.dir` (auto-namespaced + `record.dir` defaults\n * to `fixturesDir` when both are file-backed).\n *\n * ## Three use cases, one implementation\n *\n * | Use case | Config |\n * |---|---|\n * | **User apps** — degrade when the cloud provider errors or network is down | `fallbackAdapter({ fixturesStorage: ... })` installed as a fallback tier |\n * | **Tests** — deterministic replays, fail loudly on miss | `fallbackAdapter({ fixturesStorage: ..., onMiss: \"throw\" })` |\n * | **Eval offline replay** — zero-spend repeat runs | `fallbackAdapter({ fixturesStorage: ... })` as the only adapter |\n *\n * ## Implementation\n *\n * Thin sugar over {@link withReplayCache}. Key shape comes from its\n * `canonicalJson` — fixtures written by either tool are interchangeable.\n *\n * @module\n */\n\nimport { sha256Hex, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport { canonicalJson, type KvStorageTier, memoryKv } from \"@graphrefly/pure-ts/extra\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n\tStreamDelta,\n} from \"../core/types.js\";\nimport {\n\ttype ReplayCacheKeyContext,\n\tReplayCacheMissError,\n\twithReplayCache,\n} from \"../middleware/replay-cache.js\";\nimport { dryRunAdapter } from \"./dry-run.js\";\n\nexport type FallbackMissPolicy = \"throw\" | \"respond\";\n\n/**\n * Thrown when `fallbackAdapter({ onMiss: \"throw\" })` receives a request that\n * has no matching fixture. Alias of `ReplayCacheMissError` for now — the\n * adapter is a thin sugar over `withReplayCache` and shares its miss-error.\n */\nexport const FallbackMissError = ReplayCacheMissError;\nexport type FallbackMissError = ReplayCacheMissError;\n\n/**\n * One recorded fixture. Two authoring shapes:\n * - **Hash-keyed** — `{ key, response, stream? }`. Key is `sha256(canonicalJson({messages, opts}))`\n * with `fallback:` prefix. This is what `record` mode writes.\n * - **Messages-keyed** — `{ messages, invokeOpts?, response }`. The adapter\n * computes the key at init time. Ergonomic for hand-authored fixtures.\n */\nexport type FallbackFixture =\n\t| {\n\t\t\treadonly key: string;\n\t\t\treadonly response: LLMResponse;\n\t\t\treadonly stream?: {\n\t\t\t\treadonly chunks: readonly StreamDelta[];\n\t\t\t\treadonly delaysMs?: readonly number[];\n\t\t\t};\n\t }\n\t| {\n\t\t\treadonly messages: readonly ChatMessage[];\n\t\t\treadonly invokeOpts?: Omit<LLMInvokeOptions, \"signal\">;\n\t\t\treadonly response: LLMResponse;\n\t };\n\nexport interface FallbackAdapterOptions {\n\t/** Adapter provider label. Default `\"fallback\"`. */\n\treadonly provider?: string;\n\t/** Adapter model label. Default `\"fallback\"`. */\n\treadonly model?: string;\n\t/**\n\t * Inline hand-authored fixtures. Supports both hash-keyed (`{key, response, stream?}`)\n\t * and messages-keyed (`{messages, invokeOpts?, response}`) shapes — the adapter\n\t * computes the canonical hash for messages-keyed entries at init time. Held in\n\t * an internal `memoryKv`. Mutually exclusive with `fixturesDir` and\n\t * `fixturesStorage`.\n\t */\n\treadonly fixtures?: readonly FallbackFixture[];\n\t/**\n\t * Bring-your-own `KvStorageTier` (`memoryKv`, `sqliteKv`,\n\t * `indexedDbKv`, `cascadingCache`, or a custom tier). You own the\n\t * layout — no auto-namespacing. Mutually exclusive with `fixtures`.\n\t *\n\t * For filesystem directories, use the node subpath's `fallbackAdapter`\n\t * with its `fixturesDir` option (auto-namespaced + validated).\n\t */\n\treadonly fixturesStorage?: KvStorageTier;\n\t/**\n\t * Called on fixture miss when `onMiss === \"respond\"`. If not provided and\n\t * `onMiss === \"respond\"`, a canned \"service unavailable\" response is\n\t * returned (marked with `metadata.degraded: true`).\n\t */\n\treadonly respond?: (\n\t\tmessages: readonly ChatMessage[],\n\t\topts?: LLMInvokeOptions,\n\t) => string | LLMResponse;\n\t/** Miss policy. Default `\"respond\"`. */\n\treadonly onMiss?: FallbackMissPolicy;\n\t/**\n\t * Record mode. Proxies every call to `record.adapter` AND persists the\n\t * result through `record.storage`. For filesystem `record.dir` convenience,\n\t * use the node subpath's `fallbackAdapter`.\n\t */\n\treadonly record?: {\n\t\treadonly adapter: LLMAdapter;\n\t\treadonly storage?: KvStorageTier;\n\t};\n\t/** Stream replay speed multiplier. See {@link withReplayCache}. Default `1`. */\n\treadonly replaySpeed?: number;\n\t/** Key prefix. Kept compatible with `withReplayCache` defaults. Default `\"fallback\"`. */\n\treadonly keyPrefix?: string;\n\t/**\n\t * Custom key function — forwarded directly to the underlying\n\t * {@link withReplayCache}. Use to shard fixtures by `invokeOpts.keyContext`\n\t * (tenant, session, feature flag). Accepts either the new\n\t * {@link ReplayCacheKeyContext} object form or the legacy 2-arg\n\t * `(messages, opts?)` form.\n\t */\n\treadonly keyFn?:\n\t\t| ((ctx: ReplayCacheKeyContext) => string)\n\t\t| ((messages: readonly ChatMessage[], opts?: LLMInvokeOptions) => string);\n}\n\n// ---------------------------------------------------------------------------\n// Canned degraded response\n// ---------------------------------------------------------------------------\n\nfunction degradedResponse(provider: string, model: string): LLMResponse {\n\treturn {\n\t\tcontent: \"[fallback: no cached response available for this request]\",\n\t\tusage: { input: { regular: 0 }, output: { regular: 0 } },\n\t\tfinishReason: \"stop\",\n\t\tmodel,\n\t\tprovider,\n\t\tmetadata: { degraded: true, reason: \"no-fixture\" },\n\t};\n}\n\nfunction normalizeRespondResult(\n\traw: string | LLMResponse,\n\tprovider: string,\n\tmodel: string,\n): LLMResponse {\n\tif (typeof raw === \"string\") {\n\t\treturn {\n\t\t\tcontent: raw,\n\t\t\tusage: { input: { regular: 0 }, output: { regular: 0 } },\n\t\t\tfinishReason: \"stop\",\n\t\t\tmodel,\n\t\t\tprovider,\n\t\t\tmetadata: { degraded: true, reason: \"respond\" },\n\t\t};\n\t}\n\treturn raw;\n}\n\n// ---------------------------------------------------------------------------\n// Fixture → storage tier conversion\n// ---------------------------------------------------------------------------\n\n/**\n * Compute the key a `FallbackFixture` would hash to. Messages-keyed fixtures\n * get their key derived on the spot; hash-keyed fixtures pass through. Async\n * because `sha256Hex` uses `globalThis.crypto.subtle` (universal, no\n * `node:crypto` leak) — see {@link sha256Hex}.\n */\nasync function fixtureKey(fixture: FallbackFixture, keyPrefix: string): Promise<string> {\n\tif (\"key\" in fixture) return fixture.key;\n\tconst canonical = canonicalJson({ messages: fixture.messages, opts: fixture.invokeOpts ?? {} });\n\tconst hex = await sha256Hex(canonical);\n\treturn `${keyPrefix}:${hex}`;\n}\n\n/**\n * `withReplayCache` stores values as `CachedEntry = { response, storedAtNs, streamChunks?, streamCadenceMs? }`.\n * Convert a `FallbackFixture` into that shape so inline fixtures can be\n * seeded into a memory tier alongside file-authored ones.\n */\nfunction toCachedEntry(fixture: FallbackFixture): unknown {\n\tconst base: { response: LLMResponse; storedAtNs: number } = {\n\t\tresponse: fixture.response,\n\t\t// Real timestamp so future TTL-aware tiers don't treat inline fixtures\n\t\t// as Epoch-old and evict them on first pass. Matches the wall-clock\n\t\t// write `withReplayCache` uses for disk-written entries.\n\t\tstoredAtNs: wallClockNs(),\n\t};\n\tif (\"key\" in fixture && fixture.stream) {\n\t\tconst tokenChunks = fixture.stream.chunks.filter(\n\t\t\t(c): c is Extract<StreamDelta, { type: \"token\" }> => c.type === \"token\",\n\t\t);\n\t\treturn {\n\t\t\t...base,\n\t\t\tstreamChunks: tokenChunks.map((c) => ({ delta: c.delta })),\n\t\t\tstreamCadenceMs: fixture.stream.delaysMs ?? tokenChunks.map(() => 0),\n\t\t};\n\t}\n\treturn base;\n}\n\n/**\n * Resolve the fixture source to a `KvStorageTier`. Enforces mutual exclusion\n * between `fixtures` and `fixturesStorage`. When `fixtures` is provided, the\n * seeded memory tier is returned synchronously but keys are populated\n * asynchronously via the returned seeding promise (await before first use).\n */\nfunction resolveFixtureStorage(\n\topts: FallbackAdapterOptions,\n\tkeyPrefix: string,\n): { tier: KvStorageTier | undefined; seedReady: Promise<void> } {\n\tconst sources: string[] = [];\n\tif (opts.fixtures != null) sources.push(\"fixtures\");\n\tif (opts.fixturesStorage != null) sources.push(\"fixturesStorage\");\n\tif (sources.length > 1) {\n\t\tthrow new TypeError(\n\t\t\t`fallbackAdapter: \\`fixtures\\` and \\`fixturesStorage\\` are mutually ` +\n\t\t\t\t`exclusive; got both ${sources.join(\" and \")}. Pick one source. ` +\n\t\t\t\t`For filesystem directories use the node subpath's \\`fallbackAdapter\\`.`,\n\t\t);\n\t}\n\tif (opts.fixtures) {\n\t\tconst tier = memoryKv();\n\t\tconst fixtures = opts.fixtures;\n\t\tconst seedReady = (async () => {\n\t\t\tfor (const fixture of fixtures) {\n\t\t\t\tconst key = await fixtureKey(fixture, keyPrefix);\n\t\t\t\tawait tier.save(key, toCachedEntry(fixture));\n\t\t\t}\n\t\t})();\n\t\t// Attach a no-op catch so a failure inside the IIFE (e.g. `sha256Hex`\n\t\t// throws because `globalThis.crypto.subtle` is unavailable) does NOT\n\t\t// become an unhandled rejection when the adapter is constructed but\n\t\t// never invoked. V8 records the handler attachment via this branch\n\t\t// of the promise graph, so the Node `unhandledRejection` hook stays\n\t\t// silent — yet subsequent `await seedReady` inside `invoke`/`stream`\n\t\t// still throws the original error for the caller to see.\n\t\tseedReady.catch(() => {});\n\t\treturn { tier, seedReady };\n\t}\n\tif (opts.fixturesStorage) return { tier: opts.fixturesStorage, seedReady: Promise.resolve() };\n\treturn { tier: undefined, seedReady: Promise.resolve() };\n}\n\n// ---------------------------------------------------------------------------\n// fallbackAdapter\n// ---------------------------------------------------------------------------\n\n/**\n * Build a fixture-backed {@link LLMAdapter}. See module docs for use cases\n * (offline demo, tests, degraded-mode) and recipe snippets.\n */\nexport function fallbackAdapter(opts: FallbackAdapterOptions = {}): LLMAdapter {\n\tconst provider = opts.provider ?? \"fallback\";\n\tconst model = opts.model ?? \"fallback\";\n\tconst onMiss: FallbackMissPolicy = opts.onMiss ?? \"respond\";\n\tconst keyPrefix = opts.keyPrefix ?? \"fallback\";\n\n\t// Pick the inner leaf adapter based on mode.\n\tconst leaf: LLMAdapter = (() => {\n\t\tif (opts.record) return opts.record.adapter;\n\t\tif (onMiss === \"throw\") {\n\t\t\t// `withReplayCache({ mode: \"read-strict\" })` throws on miss before\n\t\t\t// ever calling the inner. Supply a no-op to satisfy the type.\n\t\t\treturn dryRunAdapter({\n\t\t\t\tprovider,\n\t\t\t\tmodel,\n\t\t\t\trespond: () => \"[unreachable: read-strict mode throws on miss]\",\n\t\t\t});\n\t\t}\n\t\t// Custom leaf (not `dryRunAdapter`) so `metadata.degraded` is preserved\n\t\t// — `dryRunAdapter` returns a string and constructs its own response,\n\t\t// discarding our metadata. For the respond-on-miss path we want full\n\t\t// `LLMResponse` control.\n\t\treturn {\n\t\t\tprovider,\n\t\t\tmodel,\n\t\t\tasync invoke(messages, invokeOpts): Promise<LLMResponse> {\n\t\t\t\tconst raw = opts.respond\n\t\t\t\t\t? opts.respond(messages, invokeOpts)\n\t\t\t\t\t: degradedResponse(provider, model);\n\t\t\t\treturn normalizeRespondResult(raw, provider, model);\n\t\t\t},\n\t\t\tasync *stream(messages, invokeOpts): AsyncGenerator<StreamDelta> {\n\t\t\t\tconst raw = opts.respond\n\t\t\t\t\t? opts.respond(messages, invokeOpts)\n\t\t\t\t\t: degradedResponse(provider, model);\n\t\t\t\tconst r = normalizeRespondResult(raw, provider, model);\n\t\t\t\tyield { type: \"token\", delta: r.content };\n\t\t\t\tif (r.usage) yield { type: \"usage\", usage: r.usage };\n\t\t\t\tyield { type: \"finish\", reason: r.finishReason ?? \"stop\" };\n\t\t\t},\n\t\t} satisfies LLMAdapter;\n\t})();\n\n\t// Resolve the storage tier.\n\t// - `record` mode: require `record.storage`.\n\t// - Replay-only: `fixtures` seeds an in-memory tier (async) OR\n\t// `fixturesStorage` passes through.\n\tlet storage: KvStorageTier;\n\tlet seedReady: Promise<void> = Promise.resolve();\n\tif (opts.record) {\n\t\tif (!opts.record.storage) {\n\t\t\tthrow new TypeError(\n\t\t\t\t\"fallbackAdapter: `record.storage` is required in record mode. For filesystem \" +\n\t\t\t\t\t\"`record.dir` convenience, use the node subpath's `fallbackAdapter`.\",\n\t\t\t);\n\t\t}\n\t\tstorage = opts.record.storage;\n\t} else {\n\t\tconst resolved = resolveFixtureStorage(opts, keyPrefix);\n\t\tstorage = resolved.tier ?? memoryKv();\n\t\tseedReady = resolved.seedReady;\n\t}\n\n\tconst mode = opts.record ? \"read-write\" : onMiss === \"throw\" ? \"read-strict\" : \"read\";\n\n\tconst cached = withReplayCache(leaf, {\n\t\tstorage,\n\t\tmode,\n\t\tkeyPrefix,\n\t\tcacheStreaming: true,\n\t\tcaptureStreamCadence: true,\n\t\treplaySpeed: opts.replaySpeed,\n\t\t...(opts.keyFn ? { keyFn: opts.keyFn } : {}),\n\t});\n\n\t// Wrap invoke/stream so the first call awaits the seed-complete Promise.\n\t// Adapter construction stays synchronous (`fallbackAdapter(...)` returns\n\t// immediately); inline fixture hashing happens lazily on first use.\n\treturn {\n\t\tprovider,\n\t\tmodel,\n\t\tcapabilities: cached.capabilities?.bind(cached),\n\t\tasync invoke(messages, invokeOpts): Promise<LLMResponse> {\n\t\t\tawait seedReady;\n\t\t\t// `cached` came from `withReplayCache`, whose `invoke` always returns\n\t\t\t// `Promise<LLMResponse>`. The `LLMAdapter` interface types it as the\n\t\t\t// broader `NodeInput<LLMResponse>` union; narrow here to the actual\n\t\t\t// shape so the wrapper surface stays `Promise<LLMResponse>`.\n\t\t\treturn cached.invoke(messages, invokeOpts) as Promise<LLMResponse>;\n\t\t},\n\t\tasync *stream(messages, invokeOpts): AsyncGenerator<StreamDelta> {\n\t\t\tawait seedReady;\n\t\t\tfor await (const delta of cached.stream(messages, invokeOpts)) yield delta;\n\t\t},\n\t};\n}\n","/**\n * `withReplayCache` — content-addressed response cache over `KvStorageTier`.\n *\n * - Key: sha256 of canonicalized (messages + invoke options minus `signal`).\n * - `\"read-write\"` (default): returns cached response if present; on miss,\n * passes through and stores the result.\n * - `\"write-only\"`: never reads; populates the cache for later runs.\n * - `\"read\"`: reads only; on miss, passes through without writing.\n * - `\"read-strict\"`: reads only; on miss, **throws `ReplayCacheMissError`**\n * instead of passing through. Use for fixture-driven tests or offline\n * fallback adapters where any cache miss is a test failure or a signal to\n * degrade.\n *\n * Reuses the library's existing `KvStorageTier` abstraction — any kv tier\n * (memoryKv / fileKv / sqliteKv / indexedDbKv / custom).\n *\n * **Concurrent cache-miss dedup:** uses `singleFromAny` so two concurrent\n * calls with the same key share one upstream request. Second caller sees the\n * same response that the first caller fetched; no duplicate provider spend.\n *\n * **Circular-ref safe:** `canonicalJson` uses a seen-set replacer so\n * user-supplied `ToolDefinition.parameters` with `$ref` cycles don't stack-\n * overflow the key computation.\n *\n * **Stream cadence capture:** when `cacheStreaming: true` AND\n * `captureStreamCadence: true`, per-chunk delays (ms since previous chunk)\n * are recorded alongside the content. Replay honors the recorded cadence\n * unless `replaySpeed` is set, which multiplies the effective per-chunk\n * delay (`replaySpeed: 2` → 2× faster; `replaySpeed: 0` → instant).\n * Without `captureStreamCadence`, replay is instant regardless.\n */\n\nimport { monotonicNs, ResettableTimer, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport type { KvStorageTier } from \"@graphrefly/pure-ts/extra\";\nimport { fromAny } from \"@graphrefly/pure-ts/extra\";\nimport { singleFromAny } from \"../../../../base/composition/single-from-any.js\";\nimport { firstValueFrom } from \"../../../../base/sources/settled.js\";\nimport { contentAddressedCache } from \"../_internal/content-addressed-cache.js\";\nimport { adapterWrapper, withLayer } from \"../_internal/wrappers.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n\tStreamDelta,\n} from \"../core/types.js\";\n\nexport type ReplayCacheMode = \"read\" | \"read-strict\" | \"write-only\" | \"read-write\";\n\nexport class ReplayCacheMissError extends Error {\n\toverride name = \"ReplayCacheMissError\";\n\tconstructor(\n\t\tpublic readonly key: string,\n\t\tpublic readonly method: \"invoke\" | \"stream\",\n\t) {\n\t\tsuper(`withReplayCache: no cached response for ${method} (key=${key}, mode=read-strict)`);\n\t}\n}\n\n/**\n * Context object passed to {@link WithReplayCacheOptions.keyFn}. Extending\n * with additional fields is forward-compatible — current implementations\n * ignoring unknown fields continue to work.\n */\nexport interface ReplayCacheKeyContext {\n\treadonly messages: readonly ChatMessage[];\n\treadonly opts: LLMInvokeOptions | undefined;\n\t/** Shortcut to `opts?.keyContext` — avoids an extra guard in callers. */\n\treadonly context: unknown;\n}\n\nexport interface WithReplayCacheOptions {\n\tstorage: KvStorageTier;\n\tmode?: ReplayCacheMode;\n\t/**\n\t * Custom key function. Receives a {@link ReplayCacheKeyContext} with the\n\t * chat messages, the invoke options, and the caller-supplied\n\t * `opts.keyContext`. Defaults to sha256 of canonical JSON over\n\t * `(messages, opts without signal/keyContext)`.\n\t *\n\t * Legacy 2-arg form `(messages, opts?)` also accepted — the adapter\n\t * detects arity and dispatches. Prefer the object form for new code.\n\t */\n\tkeyFn?:\n\t\t| ((ctx: ReplayCacheKeyContext) => string | Promise<string>)\n\t\t| ((messages: readonly ChatMessage[], opts?: LLMInvokeOptions) => string | Promise<string>);\n\t/** Prefix for cached keys (useful when sharing a tier across domains). */\n\tkeyPrefix?: string;\n\t/**\n\t * Whether to cache streaming responses (by consuming the full stream\n\t * and replaying it as one synthetic token chunk). Default `false`.\n\t */\n\tcacheStreaming?: boolean;\n\t/**\n\t * When `cacheStreaming: true`, also record per-chunk delays (ms since\n\t * previous chunk) so replay can honor the original streaming cadence.\n\t * Default `false` (chunks replay instantly).\n\t */\n\tcaptureStreamCadence?: boolean;\n\t/**\n\t * Stream replay speed multiplier. `1` = original cadence (requires\n\t * `captureStreamCadence`). `2` = 2× faster. `0` = instant. Default `1`.\n\t */\n\treplaySpeed?: number;\n}\n\ninterface CachedEntry {\n\tresponse: LLMResponse;\n\tstoredAtNs: number;\n\t/**\n\t * Per-chunk deltas in milliseconds — populated only when `captureStreamCadence`\n\t * is `true` during the write. Replayed via `ResettableTimer` in stream().\n\t */\n\tstreamCadenceMs?: readonly number[];\n\t/**\n\t * Per-chunk bodies in order (tokens only — `usage`/`finish` are reconstructed\n\t * from `response.usage` / `response.finishReason`). Populated only when\n\t * `captureStreamCadence` is `true`, used for cadence-faithful replay.\n\t */\n\tstreamChunks?: ReadonlyArray<{ delta: string }>;\n}\n\ntype ResolveArgs = {\n\tmessages: readonly ChatMessage[];\n\tinvokeOpts: LLMInvokeOptions | undefined;\n};\ntype ResolveArgsWithKey = ResolveArgs & { _precomputedKey: string };\n\n/** Wrap an adapter with a replay cache. */\nexport function withReplayCache(inner: LLMAdapter, opts: WithReplayCacheOptions): LLMAdapter {\n\tconst mode = opts.mode ?? \"read-write\";\n\tconst cacheStreaming = opts.cacheStreaming ?? false;\n\tconst captureStreamCadence = opts.captureStreamCadence ?? false;\n\tconst replaySpeed = opts.replaySpeed ?? 1;\n\tconst keyPrefix = opts.keyPrefix ?? \"llm-replay\";\n\tconst isReadOnly = mode === \"read\" || mode === \"read-strict\";\n\n\t// Content-addressed substrate — keys via canonicalJson + sha256 over\n\t// (messages, opts minus signal/keyContext) or the caller's custom keyFn.\n\t// Value type is `CachedEntry` so we can persist stream cadence alongside\n\t// the response. Uses the shared substrate in `src/extra/content-addressed-\n\t// storage.ts` via the LLM-specific wrapper in `_internal/`.\n\t//\n\t// Mode translation: `ReplayCacheMode` uses `\"write-only\"` (legacy name);\n\t// the substrate uses `\"write\"`. All other modes map 1:1.\n\tconst cache = contentAddressedCache<CachedEntry>({\n\t\tstorage: opts.storage,\n\t\tmode: mode === \"write-only\" ? \"write\" : mode,\n\t\tkeyFn: opts.keyFn,\n\t\tkeyPrefix,\n\t});\n\n\tconst sleepMs = (ms: number): Promise<void> =>\n\t\tms <= 0\n\t\t\t? Promise.resolve()\n\t\t\t: new Promise<void>((resolve) => {\n\t\t\t\t\tconst t = new ResettableTimer();\n\t\t\t\t\tt.start(ms, () => resolve());\n\t\t\t\t});\n\n\t// Singleflight — concurrent cache-miss requests with the same key share one\n\t// upstream call. `keyFn` must be synchronous (singleflight needs the key\n\t// before dispatching), so we compute the key eagerly in `invoke`/`stream`\n\t// and thread it through as `_precomputedKey`. The passed `keyFn` reads\n\t// that precomputed value instead of re-hashing.\n\tconst upstreamInFlight = singleFromAny<ResolveArgsWithKey, LLMResponse>(\n\t\tasync ({ messages, invokeOpts }) => {\n\t\t\treturn await firstValueFrom(fromAny(inner.invoke(messages, invokeOpts)));\n\t\t},\n\t\t{ keyFn: ({ _precomputedKey }) => _precomputedKey },\n\t);\n\n\tconst wrap = adapterWrapper(inner, {\n\t\tasync invoke(messages, invokeOpts): Promise<LLMResponse> {\n\t\t\tconst key = await cache.keyFor(messages, invokeOpts);\n\t\t\tconst entry = await cache.lookup(messages, invokeOpts);\n\t\t\tif (entry?.response) {\n\t\t\t\tconst cached = entry.response;\n\t\t\t\treturn { ...cached, metadata: { ...(cached.metadata ?? {}), replayCache: \"hit\" } };\n\t\t\t}\n\n\t\t\tif (mode === \"read-strict\") throw new ReplayCacheMissError(key, \"invoke\");\n\t\t\tconst resp = await upstreamInFlight({ messages, invokeOpts, _precomputedKey: key });\n\t\t\tif (!isReadOnly) {\n\t\t\t\tawait cache.store(messages, invokeOpts, { response: resp, storedAtNs: wallClockNs() });\n\t\t\t}\n\t\t\treturn resp;\n\t\t},\n\n\t\tasync *stream(messages, invokeOpts): AsyncGenerator<StreamDelta> {\n\t\t\tif (!cacheStreaming) {\n\t\t\t\t// `read-strict` only applies to cache-checked paths. When\n\t\t\t\t// `cacheStreaming: false` the cache isn't consulted for\n\t\t\t\t// streams at all, so passthrough is correct — throwing would\n\t\t\t\t// make the adapter's stream() permanently unusable.\n\t\t\t\tfor await (const delta of inner.stream(messages, invokeOpts)) yield delta;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst key = await cache.keyFor(messages, invokeOpts);\n\t\t\tconst entry = await cache.lookup(messages, invokeOpts);\n\t\t\tif (entry) {\n\t\t\t\tconst cached = entry.response;\n\t\t\t\t// Cadence-faithful replay when both recorded chunks + delays are present.\n\t\t\t\tif (entry.streamChunks && entry.streamCadenceMs) {\n\t\t\t\t\tfor (let i = 0; i < entry.streamChunks.length; i++) {\n\t\t\t\t\t\tconst delay = entry.streamCadenceMs[i] ?? 0;\n\t\t\t\t\t\tconst effective = replaySpeed > 0 ? delay / replaySpeed : 0;\n\t\t\t\t\t\tif (effective > 0) await sleepMs(effective);\n\t\t\t\t\t\tyield { type: \"token\", delta: entry.streamChunks[i]?.delta ?? \"\" };\n\t\t\t\t\t}\n\t\t\t\t} else if (cached.content) {\n\t\t\t\t\tyield { type: \"token\", delta: cached.content };\n\t\t\t\t}\n\t\t\t\tif (cached.usage) yield { type: \"usage\", usage: cached.usage };\n\t\t\t\tyield { type: \"finish\", reason: cached.finishReason ?? \"stop\" };\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (mode === \"read-strict\") throw new ReplayCacheMissError(key, \"stream\");\n\t\t\t// Miss: accumulate, store, re-yield.\n\t\t\tlet content = \"\";\n\t\t\tlet usage: LLMResponse[\"usage\"] | undefined;\n\t\t\tlet finishReason: string | undefined;\n\t\t\tconst chunks: { delta: string }[] = [];\n\t\t\tconst delaysMs: number[] = [];\n\t\t\t// Time-to-first-token (TTFT — provider latency / network / queue\n\t\t\t// warmup) is NOT cadence; setting lastNs inside the loop on first\n\t\t\t// chunk means chunk-0's delay is 0 (boundary-clean) and subsequent\n\t\t\t// delays measure only inter-chunk gaps. Use the central clock so\n\t\t\t// the scale matches every other cadence measurement in the library\n\t\t\t// and the module stays browser-safe (spec §5.11).\n\t\t\tlet lastNs: number | undefined;\n\t\t\tfor await (const delta of inner.stream(messages, invokeOpts)) {\n\t\t\t\tif (delta.type === \"token\") {\n\t\t\t\t\tcontent += delta.delta;\n\t\t\t\t\tif (captureStreamCadence) {\n\t\t\t\t\t\tconst now = monotonicNs();\n\t\t\t\t\t\tconst gap = lastNs === undefined ? 0 : (now - lastNs) / 1e6;\n\t\t\t\t\t\tdelaysMs.push(gap);\n\t\t\t\t\t\tlastNs = now;\n\t\t\t\t\t\tchunks.push({ delta: delta.delta });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (delta.type === \"usage\") usage = delta.usage;\n\t\t\t\tif (delta.type === \"finish\") finishReason = delta.reason;\n\t\t\t\tyield delta;\n\t\t\t}\n\t\t\tif ((content || usage) && !isReadOnly) {\n\t\t\t\tconst resp: LLMResponse = {\n\t\t\t\t\tcontent,\n\t\t\t\t\tusage: usage ?? { input: { regular: 0 }, output: { regular: 0 } },\n\t\t\t\t\tfinishReason,\n\t\t\t\t\tmodel: inner.model ?? invokeOpts?.model ?? \"\",\n\t\t\t\t\tprovider: inner.provider,\n\t\t\t\t};\n\t\t\t\tconst entryToStore: CachedEntry = {\n\t\t\t\t\tresponse: resp,\n\t\t\t\t\tstoredAtNs: wallClockNs(),\n\t\t\t\t\t...(captureStreamCadence ? { streamChunks: chunks, streamCadenceMs: delaysMs } : {}),\n\t\t\t\t};\n\t\t\t\tawait cache.store(messages, invokeOpts, entryToStore);\n\t\t\t}\n\t\t},\n\t});\n\twithLayer(wrap, \"withReplayCache\", inner);\n\treturn wrap;\n}\n\n// canonicalJson is no longer re-exported here — consumers import directly from\n// @graphrefly/pure-ts/extra. The presentation-layer re-export caused a\n// duplicate-export conflict at the root barrel level (A3 build gate).\n","/**\n * `singleFromAny` — keyed promise/Node de-duplication (\"singleflight\").\n *\n * Given a `factory: (key) => NodeInput<T>`, returns a callable that dedupes\n * concurrent invocations sharing the same key — all callers with the same\n * key while a request is in-flight receive the same `Promise<T>`. Once the\n * underlying source settles (DATA, ERROR, or COMPLETE), the cache entry is\n * cleared so the next call re-invokes the factory.\n *\n * This is the classic \"singleflight\" pattern from Go, generalised over the\n * library's `NodeInput<T>` bridge so callers can pass Promise-returning\n * factories, Node-returning factories, or plain value factories with\n * identical semantics.\n *\n * Use cases:\n * - `withReplayCache` cache-miss thundering-herd dedup\n * - Shared HTTP fetches keyed by URL\n * - Expensive compute keyed by request fingerprint\n *\n * @example\n * ```ts\n * const fetchUser = singleFromAny<string, User>((id) => fetch(`/users/${id}`).then(r => r.json()));\n * // Two concurrent callers with id=\"42\" → one underlying fetch, two Promises resolving to the same User.\n * const [a, b] = await Promise.all([fetchUser(\"42\"), fetchUser(\"42\")]);\n * ```\n *\n * @category extra\n */\n\nimport type { Node } from \"@graphrefly/pure-ts/core\";\nimport { COMPLETE, ERROR } from \"@graphrefly/pure-ts/core\";\n// Import directly from the source sub-files (rather than the `./sources.js`\n// barrel) so the `single-from-any` module is NOT part of any cycle that runs\n// through `extra/sources/index.ts` — eager re-exports through the barrel were\n// observed to leave `firstValueFrom` / `keepalive` unresolved during nested\n// import chains under vite-node.\nimport { fromAny, type NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport { firstValueFrom } from \"../sources/settled.js\";\n\nexport interface SingleFromAnyOptions<K> {\n\t/**\n\t * Convert a typed key into a cache-string. Defaults to `String(key)`, which\n\t * works for primitive keys; callers with object keys should provide a\n\t * stable serializer (e.g., canonical JSON).\n\t */\n\tkeyFn?: (key: K) => string;\n}\n\n/**\n * Dedupe concurrent `factory(key)` invocations. Returns a bound callable.\n *\n * @param factory - Produces a `NodeInput<T>` for each unique key.\n * @param opts - Optional key-stringification.\n * @returns A function `(key: K) => Promise<T>` whose inflight results are shared per key.\n */\nexport function singleFromAny<K, T>(\n\tfactory: (key: K) => NodeInput<T>,\n\topts: SingleFromAnyOptions<K> = {},\n): (key: K) => Promise<T> {\n\tconst keyFn = opts.keyFn ?? ((k: K) => String(k));\n\tconst inFlight = new Map<string, Promise<T>>();\n\n\treturn (key: K): Promise<T> => {\n\t\tconst k = keyFn(key);\n\t\tconst existing = inFlight.get(k);\n\t\tif (existing) return existing;\n\n\t\tconst input = factory(key);\n\n\t\t// Resolve the NodeInput to a Promise<T>. Different input shapes need\n\t\t// different bridges — Promise/Node/AsyncIterable/Iterable/plain value.\n\t\tlet rawPromise: Promise<T>;\n\t\tif (input != null && typeof (input as PromiseLike<T>).then === \"function\") {\n\t\t\trawPromise = Promise.resolve(input as PromiseLike<T>);\n\t\t} else if (\n\t\t\tinput != null &&\n\t\t\ttypeof input === \"object\" &&\n\t\t\t\"subscribe\" in (input as object) &&\n\t\t\t\"cache\" in (input as object)\n\t\t) {\n\t\t\t// Node: bridge via firstValueFrom.\n\t\t\trawPromise = firstValueFrom(input as Node<T>);\n\t\t} else if (\n\t\t\tinput != null &&\n\t\t\ttypeof input === \"object\" &&\n\t\t\tSymbol.asyncIterator in (input as object)\n\t\t) {\n\t\t\t// AsyncIterable — take the first value, then close the iterator so\n\t\t\t// any owned resources (HTTP body, subscription, timer) are released.\n\t\t\trawPromise = (async () => {\n\t\t\t\tconst iter = (input as AsyncIterable<T>)[Symbol.asyncIterator]();\n\t\t\t\ttry {\n\t\t\t\t\tconst { value, done } = await iter.next();\n\t\t\t\t\tif (done) throw new Error(\"singleFromAny: factory returned empty async iterable\");\n\t\t\t\t\treturn value as T;\n\t\t\t\t} finally {\n\t\t\t\t\tawait iter.return?.();\n\t\t\t\t}\n\t\t\t})();\n\t\t} else if (input != null && typeof input === \"object\" && Symbol.iterator in (input as object)) {\n\t\t\t// Iterable — take the first value, close the iterator.\n\t\t\trawPromise = (async () => {\n\t\t\t\tconst iter = (input as Iterable<T>)[Symbol.iterator]();\n\t\t\t\ttry {\n\t\t\t\t\tconst { value, done } = iter.next();\n\t\t\t\t\tif (done) throw new Error(\"singleFromAny: factory returned empty iterable\");\n\t\t\t\t\treturn value as T;\n\t\t\t\t} finally {\n\t\t\t\t\titer.return?.();\n\t\t\t\t}\n\t\t\t})();\n\t\t} else {\n\t\t\t// Plain value.\n\t\t\trawPromise = Promise.resolve(input as T);\n\t\t}\n\n\t\t// Install the cache entry BEFORE attaching `.finally`. Otherwise a\n\t\t// sync-resolved Promise's finally microtask could run before the\n\t\t// `inFlight.set` below, leaving a stale entry installed afterwards.\n\t\t// We wrap in a holder whose reference we capture *before* chaining.\n\t\tlet tracked!: Promise<T>;\n\t\tconst cleanup = (): void => {\n\t\t\tif (inFlight.get(k) === tracked) inFlight.delete(k);\n\t\t};\n\t\ttracked = rawPromise.then(\n\t\t\t(v) => {\n\t\t\t\tcleanup();\n\t\t\t\treturn v;\n\t\t\t},\n\t\t\t(e) => {\n\t\t\t\tcleanup();\n\t\t\t\tthrow e;\n\t\t\t},\n\t\t);\n\t\tinFlight.set(k, tracked);\n\t\treturn tracked;\n\t};\n}\n\n/**\n * Reactive variant: returns a bound callable that hands out `Node<T>` values.\n * All concurrent callers with the same key during an in-flight source share\n * the same Node. When the underlying source **terminally** settles (ERROR\n * or COMPLETE), the Node is removed from the cache so the next call\n * re-invokes `factory`. DATA is NOT terminal — callers subscribing after\n * the first DATA still receive the shared Node (and push-on-subscribe per\n * the spec's cached-DATA contract).\n *\n * Use when downstream wants reactive subscription (not a one-shot Promise).\n *\n * @category extra\n */\nexport function singleNodeFromAny<K, T>(\n\tfactory: (key: K) => NodeInput<T>,\n\topts: SingleFromAnyOptions<K> = {},\n): (key: K) => Node<T> {\n\tconst keyFn = opts.keyFn ?? ((k: K) => String(k));\n\tconst inFlight = new Map<string, Node<T>>();\n\n\treturn (key: K): Node<T> => {\n\t\tconst k = keyFn(key);\n\t\tconst existing = inFlight.get(k);\n\t\tif (existing) return existing;\n\n\t\tconst node = fromAny(factory(key));\n\t\tinFlight.set(k, node);\n\n\t\t// Evict on terminal settle only — ERROR or COMPLETE. DATA is a value\n\t\t// emission, not a lifecycle transition; multi-emitting Nodes should\n\t\t// continue to share across subscribers after the first value.\n\t\tconst unsub = node.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] === ERROR || m[0] === COMPLETE) {\n\t\t\t\t\tif (inFlight.get(k) === node) inFlight.delete(k);\n\t\t\t\t\tunsub();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\treturn node;\n\t};\n}\n","/**\n * Settled/signal helpers.\n *\n * Moved from extra/sources/settled.ts during cleave A2.\n * `keepalive` is substrate — it lives at `@graphrefly/pure-ts`\n * (`packages/pure-ts/src/extra/sources/_keepalive.ts`), not here.\n */\n\n/**\n * Settled / signal helpers — boundary primitives for converting reactive\n * sources into Promise/AbortSignal endpoints.\n *\n * - {@link firstValueFrom} / {@link firstWhere} — Promise of the first\n * matching DATA.\n * - {@link awaitSettled} — composition over `firstWhere` + reactive\n * `timeout` from `extra/resilience` (lazy import to avoid a\n * resilience → sources cycle).\n * - {@link nodeSignal} — `Node<boolean>` → `AbortSignal` bridge.\n * - {@link reactiveCounter} — capped counter exposed as a `Node<number>`.\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tDIRTY,\n\tERROR,\n\ttype Messages,\n\ttype Node,\n\tnode,\n} from \"@graphrefly/pure-ts/core\";\n\n/**\n * Converts the first `DATA` on `source` into a Promise; rejects on `ERROR` or `COMPLETE` without data.\n *\n * **Important:** This subscribes and waits for a **future** emission. Data that\n * has already flowed is gone and will not be seen. Call this *before* the upstream\n * emits, or use `source.cache` / `source.status` for already-cached state.\n * See COMPOSITION-GUIDE §2 (subscription ordering).\n *\n * @param source - Node to read once.\n * @returns Promise of the first value.\n *\n * @example\n * ```ts\n * import { firstValueFrom, of } from \"@graphrefly/graphrefly-ts\";\n *\n * await firstValueFrom(of(42));\n * ```\n *\n * @category extra\n */\nexport function firstValueFrom<T>(source: Node<T>): Promise<T> {\n\treturn new Promise<T>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tlet shouldUnsub = false;\n\t\tlet unsub: (() => void) | undefined;\n\t\tunsub = source.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (settled) return;\n\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tresolve(m[1] as T);\n\t\t\t\t\tif (unsub) {\n\t\t\t\t\t\tunsub();\n\t\t\t\t\t\tunsub = undefined;\n\t\t\t\t\t} else shouldUnsub = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (m[0] === ERROR) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\treject(m[1]);\n\t\t\t\t\tif (unsub) {\n\t\t\t\t\t\tunsub();\n\t\t\t\t\t\tunsub = undefined;\n\t\t\t\t\t} else shouldUnsub = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\treject(new Error(\"completed without DATA\"));\n\t\t\t\t\tif (unsub) {\n\t\t\t\t\t\tunsub();\n\t\t\t\t\t\tunsub = undefined;\n\t\t\t\t\t} else shouldUnsub = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tif (shouldUnsub) {\n\t\t\tunsub?.();\n\t\t\tunsub = undefined;\n\t\t}\n\t});\n}\n\n/**\n * Wait for the first DATA value from `source` that satisfies `predicate`.\n *\n * Subscribes directly and resolves on the first DATA value where\n * `predicate` returns true. Reactive, no polling. Use in tests and\n * bridging code where you need a single matching value as a Promise.\n *\n * **Important:** This only captures **future** emissions — data that has\n * already flowed through the node is gone. Call this *before* the upstream\n * emits. For already-cached values, use `source.cache` / `source.status`.\n * See COMPOSITION-GUIDE §2 (subscription ordering).\n *\n * ```ts\n * const val = await firstWhere(strategy.snapshot, snap => snap.size > 0);\n * ```\n *\n * @param source - Upstream node to observe.\n * @param predicate - Returns `true` for the value to resolve on.\n * @param opts - `{ skipCurrent?: boolean }`. When `skipCurrent: true`, any DATA\n * delivered during the synchronous `subscribe()` call (push-on-subscribe §2.2\n * replay of the cached value) is ignored — the promise resolves only on the\n * next future emission. Useful when the caller wants to await the next\n * settlement event after an imperative action (e.g. `run()` minting a new\n * runVersion, where the currently-cached value belongs to the previous run).\n *\n * @category extra\n */\nexport function firstWhere<T>(\n\tsource: Node<T>,\n\tpredicate: (value: T) => boolean,\n\topts?: { skipCurrent?: boolean; kick?: () => void },\n): Promise<T> {\n\t// Lock 3.A (Phase 13.6.B): subscribe synchronously inside the function\n\t// body — NOT inside the Promise executor. Subscribing inside the\n\t// executor would defer the subscription past any synchronous `kick()`\n\t// the caller fires after the call returns, race-losing the very wave\n\t// the caller wants to observe.\n\t//\n\t// To bridge sync-subscribe with the async Promise contract, we record\n\t// any settlement that fires *before* the Promise constructor runs, and\n\t// the executor immediately resolves/rejects with the recorded value.\n\t// Settlements after the executor runs go straight through resolve/reject.\n\ttype Pending =\n\t\t| { kind: \"data\"; value: T }\n\t\t| { kind: \"error\"; err: unknown }\n\t\t| { kind: \"complete\" };\n\tlet pending: Pending | undefined;\n\tlet resolveFn: ((value: T) => void) | undefined;\n\tlet rejectFn: ((err: unknown) => void) | undefined;\n\tlet settled = false;\n\tlet shouldUnsub = false;\n\tlet unsub: (() => void) | undefined;\n\tlet inInitialSyncPhase = opts?.skipCurrent === true;\n\n\t// QA P1: every settler short-circuits when `settled === true` so a\n\t// later settle attempt (e.g. `kick()` throwing AFTER it synchronously\n\t// fired matching DATA, OR a `[DATA matched, ERROR]` wave during\n\t// push-on-subscribe) cannot overwrite an earlier `pending` outcome.\n\t// Without this gate, a kick that races sink-callback settlement could\n\t// reject a Promise the user already has resolved-DATA for.\n\tconst settleData = (v: T): void => {\n\t\tif (settled) return;\n\t\tsettled = true;\n\t\tif (resolveFn != null) resolveFn(v);\n\t\telse pending = { kind: \"data\", value: v };\n\t};\n\tconst settleError = (err: unknown): void => {\n\t\tif (settled) return;\n\t\tsettled = true;\n\t\tif (rejectFn != null) rejectFn(err);\n\t\telse pending = { kind: \"error\", err };\n\t};\n\tconst settleComplete = (): void => {\n\t\tif (settled) return;\n\t\tsettled = true;\n\t\tconst err = new Error(\"completed without matching value\");\n\t\tif (rejectFn != null) rejectFn(err);\n\t\telse pending = { kind: \"complete\" };\n\t};\n\tconst detach = (): void => {\n\t\tif (unsub) {\n\t\t\tunsub();\n\t\t\tunsub = undefined;\n\t\t} else shouldUnsub = true;\n\t};\n\n\tconst sink: (msgs: Messages) => void = (msgs) => {\n\t\tif (settled) return;\n\t\tfor (const m of msgs) {\n\t\t\tif (settled) return;\n\t\t\t// During the initial sync phase, swallow only cached DATA\n\t\t\t// (push-on-subscribe §2.2). Terminal ERROR / COMPLETE must\n\t\t\t// still reject the promise — otherwise an already-terminated\n\t\t\t// source synchronously delivering `[[ERROR, ...]]` or\n\t\t\t// `[[COMPLETE]]` during `subscribe()` would hang forever\n\t\t\t// under `skipCurrent: true`.\n\t\t\tif (inInitialSyncPhase && m[0] === DATA) continue;\n\t\t\tif (m[0] === DATA) {\n\t\t\t\tconst v = m[1] as T;\n\t\t\t\tif (predicate(v)) {\n\t\t\t\t\tsettleData(v);\n\t\t\t\t\tdetach();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (m[0] === ERROR) {\n\t\t\t\tsettleError(m[1]);\n\t\t\t\tdetach();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\tsettleComplete();\n\t\t\t\tdetach();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t};\n\tunsub = source.subscribe(sink);\n\tinInitialSyncPhase = false;\n\t// Lock 3.A: fire `kick` AFTER subscribe is in place. With sync\n\t// subscribe + sync kick, the resulting wave reaches `sink` before\n\t// control returns — making subscribe-before-kick ordering structurally\n\t// impossible to misuse.\n\tif (opts?.kick != null && !settled) {\n\t\ttry {\n\t\t\topts.kick();\n\t\t} catch (err) {\n\t\t\tsettleError(err);\n\t\t\tdetach();\n\t\t}\n\t}\n\tif (shouldUnsub) {\n\t\tunsub?.();\n\t\tunsub = undefined;\n\t}\n\n\treturn new Promise<T>((resolve, reject) => {\n\t\t// If a settlement landed synchronously before the executor runs,\n\t\t// flush it through immediately.\n\t\tif (pending != null) {\n\t\t\tif (pending.kind === \"data\") resolve(pending.value);\n\t\t\telse if (pending.kind === \"error\") reject(pending.err);\n\t\t\telse reject(new Error(\"completed without matching value\"));\n\t\t\treturn;\n\t\t}\n\t\tresolveFn = resolve;\n\t\trejectFn = reject;\n\t});\n}\n\n/**\n * Await the first non-nullish DATA value from `source`, with optional\n * timeout. Composition sugar over `firstWhere` + reactive timeout.\n *\n * Designed as the CLI/boundary sink for reactive pipelines that end in a\n * nullable node (e.g. `promptNode` — per COMPOSITION-GUIDE §8, it emits\n * `null` before it settles with a real value). Replaces the common pattern\n * `firstValueFrom(filter(source, v => v != null))` with a deadline.\n *\n * - Rejects with `TimeoutError` (from `extra/resilience`) if no matching\n * value arrives within `timeoutMs`. Omit `timeoutMs` for unbounded wait.\n * - `predicate` defaults to `v => v != null`. Pass a custom predicate to\n * gate on a stronger condition (e.g. `v => typeof v === \"string\"`).\n * - Pass `skipCurrent: true` to ignore the currently-cached value delivered\n * synchronously via push-on-subscribe and resolve only on the *next*\n * matching emission. Useful after an imperative action that should produce\n * a fresh settlement (e.g. `run()` minting a new version — the stale\n * cached value from the previous run must not resolve the new caller).\n *\n * ```ts\n * const brief = await awaitSettled(briefNode, { timeoutMs: 120_000 });\n * // or with a predicate:\n * const rich = await awaitSettled(node, {\n * predicate: (v): v is MyShape => typeof v === \"object\" && v != null && \"key\" in v,\n * timeoutMs: 60_000,\n * });\n * // or after kicking off a fresh run:\n * kickOff();\n * const fresh = await awaitSettled(resultNode, { skipCurrent: true });\n * ```\n *\n * Reactive inside, sync propagation — the one async boundary is the\n * returned `Promise<T>` (spec §5.10: async belongs at sources and\n * boundaries, not in the graph).\n *\n * @param source - Upstream node to observe.\n * @param opts - `{ predicate?, timeoutMs?, skipCurrent? }`.\n * @returns Promise that resolves with the first matching value, or rejects on timeout / ERROR / COMPLETE-without-DATA.\n *\n * @category extra\n */\n// Lazy module-cache for the `withTimeout` resilience operator. The dynamic\n// import keeps `settled` free of an eager edge into the resilience family;\n// first call pays the one-shot import, subsequent calls hit cached refs.\nlet _timeoutOp: typeof import(\"../resilience/timeout.js\").withTimeout | undefined;\nlet _nsPerMs: number | undefined;\n\nexport async function awaitSettled<T>(\n\tsource: Node<T>,\n\topts?: {\n\t\tpredicate?: (value: T) => boolean;\n\t\ttimeoutMs?: number;\n\t\tskipCurrent?: boolean;\n\t\t/**\n\t\t * Lock 3.A (Phase 13.6.B): fired AFTER subscribe is in place but\n\t\t * BEFORE the helper's async boundary is exposed to the caller.\n\t\t * Subscribe-before-kick is structurally enforced — the kick's\n\t\t * synchronous wave reaches `sink` before control returns. Replaces\n\t\t * the prior load-bearing-comment pattern (M.20-load-bearing) with\n\t\t * a misuse-impossible API shape.\n\t\t *\n\t\t * Common pattern:\n\t\t * await awaitSettled(node, {\n\t\t * skipCurrent: true,\n\t\t * kick: () => producer.emit(value),\n\t\t * });\n\t\t *\n\t\t * Omit `kick` for external-trigger cases where the wave is fired\n\t\t * by code outside the helper's caller; subscribe still lands\n\t\t * synchronously inside the helper body so the next external wave\n\t\t * is not lost.\n\t\t */\n\t\tkick?: () => void;\n\t},\n): Promise<NonNullable<T>> {\n\tconst predicate = opts?.predicate ?? ((v: T) => v != null);\n\tconst skipCurrent = opts?.skipCurrent;\n\tconst kick = opts?.kick;\n\tif (opts?.timeoutMs == null || opts.timeoutMs <= 0) {\n\t\treturn (await firstWhere(source, predicate, { skipCurrent, kick })) as NonNullable<T>;\n\t}\n\t// Reactive composition: `timeout()` wraps the source as a Node that\n\t// emits ERROR(TimeoutError) on deadline. `firstWhere` then resolves on\n\t// the first matching DATA or rejects on that ERROR. One async boundary\n\t// (the returned Promise), everything inside is sync reactive.\n\tif (_timeoutOp === undefined) {\n\t\tconst [timeoutMod, backoff] = await Promise.all([\n\t\t\timport(\"../resilience/timeout.js\"),\n\t\t\timport(\"../resilience/backoff.js\"),\n\t\t]);\n\t\t_timeoutOp = timeoutMod.withTimeout;\n\t\t_nsPerMs = backoff.NS_PER_MS;\n\t}\n\tconst guarded = _timeoutOp(source, { ns: opts.timeoutMs * (_nsPerMs as number) }).node;\n\treturn (await firstWhere(guarded, predicate, { skipCurrent, kick })) as NonNullable<T>;\n}\n\n/**\n * Converts a reactive `Node<boolean>` into a browser-standard `AbortSignal`\n * that fires when the node settles on `true`. Useful for threading a reactive\n * \"cancel\" flag into any async boundary that accepts a signal (fetch, LLM SDK\n * calls, child-process APIs, timers).\n *\n * **Contract.**\n * - `signal.abort(reason)` fires exactly once, on the first DATA emission with\n * a truthy value. Subsequent emissions are ignored (AbortSignal is\n * single-shot).\n * - Null / `false` / sentinel values are ignored. Push-on-subscribe will\n * check the currently-cached value on subscribe and abort immediately if\n * it's already `true`.\n * - `reason` defaults to `\"cancelled via nodeSignal\"`; pass `opts.reason` to\n * override (`DOMException`, `Error`, or any value accepted by\n * `AbortController.abort`).\n *\n * **Lifecycle.**\n * - Returns a `{signal, dispose}` bundle. Call `dispose()` when you're done\n * with the signal (e.g. in a `finally` after the async operation completes).\n * `dispose()` unsubscribes from the node and is a no-op once the signal has\n * fired.\n * - **Memory note:** without `dispose()` the subscription keeps the reactive\n * node alive for the lifetime of the process. For bridge calls inside a\n * `switchMap` project fn, the switchMap supersede tears the inner subgraph\n * down, which is usually the right lifetime — but still call `dispose()`\n * from the caller's `finally` for clarity.\n *\n * @example\n * ```ts\n * const aborted = state(false);\n * const { signal, dispose } = nodeSignal(aborted);\n * try {\n * const resp = await adapter.invoke(msgs, { signal });\n * return resp;\n * } finally {\n * dispose();\n * }\n * ```\n *\n * @category extra\n */\nexport function nodeSignal(\n\tsource: Node<boolean>,\n\topts?: { reason?: unknown },\n): { signal: AbortSignal; dispose: () => void } {\n\tconst ctrl = new AbortController();\n\tconst reason = opts?.reason ?? new Error(\"cancelled via nodeSignal\");\n\tlet unsub: (() => void) | undefined;\n\tlet shouldUnsub = false;\n\tconst done = () => {\n\t\tif (unsub) {\n\t\t\tunsub();\n\t\t\tunsub = undefined;\n\t\t} else shouldUnsub = true;\n\t};\n\tunsub = source.subscribe((msgs) => {\n\t\tif (ctrl.signal.aborted) return;\n\t\tfor (const m of msgs) {\n\t\t\tif (m[0] === DATA && m[1] === true) {\n\t\t\t\tctrl.abort(reason);\n\t\t\t\tdone();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (m[0] === ERROR) {\n\t\t\t\t// Treat an ERROR on the abort source as a cancel signal too —\n\t\t\t\t// a broken control channel should fail closed, not leak the\n\t\t\t\t// in-flight call. Use the error as the abort reason.\n\t\t\t\tctrl.abort(m[1]);\n\t\t\t\tdone();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\t// Source completed without aborting — no-op. `done()` already\n\t\t\t\t// released the subscription here, so a later `dispose()` call\n\t\t\t\t// from the caller is a no-op (safe / idempotent).\n\t\t\t\tdone();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t});\n\tif (shouldUnsub) {\n\t\tunsub?.();\n\t\tunsub = undefined;\n\t}\n\treturn {\n\t\tsignal: ctrl.signal,\n\t\tdispose: () => {\n\t\t\tif (unsub) {\n\t\t\t\tunsub();\n\t\t\t\tunsub = undefined;\n\t\t\t}\n\t\t},\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// reactiveCounter\n// ---------------------------------------------------------------------------\n\n/** Bundle returned by {@link reactiveCounter}. */\nexport type ReactiveCounterBundle = {\n\t/** Reactive node holding the current count. */\n\treadonly node: Node<number>;\n\t/** Increment by 1. Returns `false` if cap would be exceeded. */\n\tincrement(): boolean;\n\t/** Current count (synchronous read). */\n\tget(): number;\n\t/** Whether the counter has reached its cap. */\n\tatCap(): boolean;\n};\n\n/**\n * Reactive counter with a cap — the building block for circuit breakers.\n *\n * Wraps a `state(0)` node with `increment()` that respects a maximum.\n * The `node` is subscribable and composable like any reactive node. When\n * the cap is reached, `increment()` returns `false`.\n *\n * ```ts\n * const retries = reactiveCounter(10);\n * retries.increment(); // true — count is now 1\n * retries.node.subscribe(...); // reactive updates\n * retries.atCap(); // false\n * ```\n *\n * @param cap - Maximum value (inclusive). 0 = no increments allowed.\n * @category extra\n */\nexport function reactiveCounter(cap: number): ReactiveCounterBundle {\n\tconst counter = node([], { initial: 0 });\n\treturn {\n\t\tnode: counter,\n\t\tincrement() {\n\t\t\tconst current = counter.cache ?? 0;\n\t\t\tif (current >= cap) return false;\n\t\t\tcounter.down([[DIRTY], [DATA, current + 1]]);\n\t\t\treturn true;\n\t\t},\n\t\tget() {\n\t\t\treturn counter.cache ?? 0;\n\t\t},\n\t\tatCap() {\n\t\t\treturn (counter.cache ?? 0) >= cap;\n\t\t},\n\t};\n}\n","/**\n * LLM-specific content-addressed cache wrapper over the generic\n * {@link contentAddressedStorage} substrate in `src/extra/`. Handles the\n * ChatMessage + LLMInvokeOptions → stable key shape that both\n * `withReplayCache` and `fallbackAdapter` need, so the two middleware files\n * don't drift on key construction.\n *\n * The generic substrate does the sha256 + canonicalJson + tier IO; this\n * wrapper owns:\n * - Stripping non-serializable `signal` (AbortSignal) and `keyContext`\n * (caller-opaque context) from the default key.\n * - Arity-dispatched legacy `keyFn` support (1-arg ctx-object form vs 2-arg\n * `(messages, opts)` form).\n * - LLM-conventional `llm-replay` default key prefix (override via `keyPrefix`).\n *\n * @module\n */\n\nimport type { KvStorageTier } from \"@graphrefly/pure-ts/extra\";\nimport {\n\ttype ContentAddressedMode,\n\ttype ContentAddressedStorage,\n\tcontentAddressedStorage,\n} from \"@graphrefly/pure-ts/extra\";\nimport type { ChatMessage, LLMInvokeOptions } from \"../core/types.js\";\n\n/**\n * Context object passed to the 1-arg {@link ContentAddressedCacheOptions.keyFn}\n * form. Adding fields here is forward-compatible — existing 1-arg consumers\n * that ignore unknowns keep working.\n */\nexport interface LLMCacheKeyContext {\n\treadonly messages: readonly ChatMessage[];\n\treadonly opts: LLMInvokeOptions | undefined;\n\t/** Shortcut to `opts?.keyContext` — no extra guard in callers. */\n\treadonly context: unknown;\n}\n\nexport interface ContentAddressedCacheOptions<V> {\n\tstorage: KvStorageTier;\n\tmode?: ContentAddressedMode;\n\t/**\n\t * Custom key function. Receives either {@link LLMCacheKeyContext} (1-arg\n\t * form) or `(messages, opts?)` (legacy 2-arg form) — the wrapper dispatches\n\t * on `Function.length`. Return `string` or `Promise<string>`.\n\t */\n\tkeyFn?:\n\t\t| ((ctx: LLMCacheKeyContext) => string | Promise<string>)\n\t\t| ((messages: readonly ChatMessage[], opts?: LLMInvokeOptions) => string | Promise<string>);\n\t/** Prefix applied as `${keyPrefix}:${hash}`. Default `\"llm-replay\"`. */\n\tkeyPrefix?: string;\n\t/**\n\t * Optional value type hint — callers may store anything JSON-serializable.\n\t * `withReplayCache` stores `CachedEntry` (response + stream cadence);\n\t * `fallbackAdapter` stores the raw `LLMResponse`.\n\t */\n\t_valueType?: V;\n}\n\n/** Handle returned by {@link contentAddressedCache}. */\nexport interface ContentAddressedCache<V> {\n\tkeyFor(messages: readonly ChatMessage[], invokeOpts?: LLMInvokeOptions): Promise<string>;\n\tlookup(messages: readonly ChatMessage[], invokeOpts?: LLMInvokeOptions): Promise<V | undefined>;\n\tstore(\n\t\tmessages: readonly ChatMessage[],\n\t\tinvokeOpts: LLMInvokeOptions | undefined,\n\t\tvalue: V,\n\t): Promise<void>;\n\tforget(messages: readonly ChatMessage[], invokeOpts?: LLMInvokeOptions): Promise<void>;\n}\n\n/**\n * Builds an LLM-shaped content-addressed cache over `storage`. Default keying\n * hashes `(messages, opts minus signal/keyContext)` via\n * {@link contentAddressedStorage} — the generic extra-tier substrate.\n *\n * Used by `withReplayCache` (full response cache) and `fallbackAdapter`\n * (fixture lookup). Both consumers wrap this to add their divergent features\n * (singleflight / stream cadence / canned miss response) around the shared\n * substrate.\n *\n * @category internal\n */\nexport function contentAddressedCache<V>(\n\topts: ContentAddressedCacheOptions<V>,\n): ContentAddressedCache<V> {\n\tconst { storage, mode = \"read-write\", keyFn, keyPrefix = \"llm-replay\" } = opts;\n\n\t// Substrate mode: translate `\"read-strict\"` to `\"read\"` so the substrate\n\t// returns `undefined` on miss. The LLM-middleware callers (`withReplayCache`,\n\t// `fallbackAdapter`) own the strict-mode throw because they emit\n\t// domain-specific error types (`ReplayCacheMissError` / `FallbackMissError`)\n\t// that carry context the substrate shouldn't know about.\n\tconst substrateMode = mode === \"read-strict\" ? \"read\" : mode;\n\n\t// When `keyFn` is supplied, we wire it through the substrate's raw-key API\n\t// (via a synthesized keyContext passthrough). When omitted, we let the\n\t// substrate hash the default shape (messages + opts minus non-serializable\n\t// fields) with the standard prefix.\n\tconst substrate: ContentAddressedStorage<\n\t\t{ messages: readonly ChatMessage[]; opts: LLMInvokeOptions | undefined },\n\t\tV\n\t> = contentAddressedStorage({\n\t\tstorage,\n\t\tkeyPrefix,\n\t\tmode: substrateMode,\n\t\tkeyContext: ({ messages, opts: invokeOpts }) => {\n\t\t\t// Drop `signal` (not serializable) and `keyContext` (caller-opaque\n\t\t\t// context should only participate when user opts in via keyFn).\n\t\t\tconst { signal: _signal, keyContext: _keyContext, ...rest } = invokeOpts ?? {};\n\t\t\treturn { messages, opts: rest };\n\t\t},\n\t});\n\n\tasync function keyFor(\n\t\tmessages: readonly ChatMessage[],\n\t\tinvokeOpts?: LLMInvokeOptions,\n\t): Promise<string> {\n\t\tif (keyFn) {\n\t\t\t// Arity-dispatch: Function.length === 1 → ctx-object form;\n\t\t\t// otherwise → legacy 2-arg (messages, opts). Both may return\n\t\t\t// sync or async strings.\n\t\t\tif (keyFn.length <= 1) {\n\t\t\t\tconst ctx: LLMCacheKeyContext = {\n\t\t\t\t\tmessages,\n\t\t\t\t\topts: invokeOpts,\n\t\t\t\t\tcontext: invokeOpts?.keyContext,\n\t\t\t\t};\n\t\t\t\tconst raw = await (keyFn as (c: LLMCacheKeyContext) => string | Promise<string>)(ctx);\n\t\t\t\treturn `${keyPrefix}:${raw}`;\n\t\t\t}\n\t\t\tconst raw = await (\n\t\t\t\tkeyFn as (m: readonly ChatMessage[], o?: LLMInvokeOptions) => string | Promise<string>\n\t\t\t)(messages, invokeOpts);\n\t\t\treturn `${keyPrefix}:${raw}`;\n\t\t}\n\t\treturn substrate.keyFor({ messages, opts: invokeOpts });\n\t}\n\n\treturn {\n\t\tkeyFor,\n\n\t\tasync lookup(messages, invokeOpts) {\n\t\t\tif (mode === \"write\") return undefined;\n\t\t\tif (keyFn) {\n\t\t\t\t// Custom keyFn path: we can't use substrate.lookup (it hashes\n\t\t\t\t// from its own keyContext). Build the key ourselves and load.\n\t\t\t\t// Strict-mode throw is the CALLER'S responsibility — we return\n\t\t\t\t// undefined on miss so callers can wrap the throw with their\n\t\t\t\t// domain-specific error type.\n\t\t\t\tconst key = await keyFor(messages, invokeOpts);\n\t\t\t\tconst raw = await storage.load(key);\n\t\t\t\tif (raw === undefined) return undefined;\n\t\t\t\treturn raw as V;\n\t\t\t}\n\t\t\treturn substrate.lookup({ messages, opts: invokeOpts });\n\t\t},\n\n\t\tasync store(messages, invokeOpts, value) {\n\t\t\tif (mode === \"read\") return;\n\t\t\tif (keyFn) {\n\t\t\t\tconst key = await keyFor(messages, invokeOpts);\n\t\t\t\tawait storage.save(key, value as unknown);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait substrate.store({ messages, opts: invokeOpts }, value);\n\t\t},\n\n\t\tasync forget(messages, invokeOpts) {\n\t\t\tif (mode === \"read\" || mode === \"write\") return;\n\t\t\tif (!storage.delete) return;\n\t\t\tif (keyFn) {\n\t\t\t\tconst key = await keyFor(messages, invokeOpts);\n\t\t\t\tawait storage.delete(key);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait substrate.forget({ messages, opts: invokeOpts });\n\t\t},\n\t};\n}\n","/**\n * Shared shell + shape-dispatch helpers for the LLM adapter layer.\n *\n * Wave A Unit 11 decision: the 9 middleware files and the observable adapter\n * all repeated the same three boilerplate patterns:\n *\n * 1. Building the returned `LLMAdapter` shell (provider/model/capabilities\n * pass-through). → `adapterWrapper(inner, {invoke, stream})`.\n * 2. Dispatching the adapter's `NodeInput<LLMResponse>` result across its\n * three possible shapes (Promise / Node / plain value) + a `recordedOnce`\n * double-record guard on the reactive path. → `adaptInvokeResult`.\n * 3. Constructing a `CallStatsEvent` from provider / model / tier / usage /\n * latency. → `buildCallStats`.\n *\n * Two small additions:\n * - `withLayer(adapter, layerName)` stamps a `meta.middlewareLayer` tag on\n * the returned adapter via a non-enumerable property, enabling\n * `describeAdapterStack(adapter)` to walk the wrap chain bottom-up.\n * - `describeAdapterStack(adapter)` returns the list of layer names from\n * innermost to outermost so users can inspect the resilient stack the same\n * way they inspect graph topology.\n */\n\nimport { ERROR, monotonicNs, type Node, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport { fromAny, onFirstData } from \"@graphrefly/pure-ts/extra\";\nimport type { CallStatsEvent } from \"../core/observable.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n\tNodeInput,\n\tStreamDelta,\n\tTokenUsage,\n} from \"../core/types.js\";\n\n// ---------------------------------------------------------------------------\n// adapterWrapper — LLMAdapter shell with provider/model/capabilities pass-through\n// ---------------------------------------------------------------------------\n\n/** Callable shape for the invoke / stream bodies that `adapterWrapper` composes. */\nexport type AdapterInvokeFn = (\n\tmessages: readonly ChatMessage[],\n\topts?: LLMInvokeOptions,\n) => NodeInput<LLMResponse>;\n\nexport type AdapterStreamFn = (\n\tmessages: readonly ChatMessage[],\n\topts?: LLMInvokeOptions,\n) => AsyncIterable<StreamDelta>;\n\n/**\n * Builds an `LLMAdapter` shell around the given `invoke` / `stream`\n * implementations. Pass-through fields — `provider`, `model`, `capabilities`\n * — come from `inner` unless the caller overrides (`override.provider` etc.).\n *\n * Middleware files used to repeat `provider: inner.provider, model: inner.model,\n * capabilities: inner.capabilities?.bind(inner)` verbatim; this helper\n * captures that once.\n *\n * @category internal\n */\nexport function adapterWrapper(\n\tinner: LLMAdapter,\n\timpl: { invoke: AdapterInvokeFn; stream: AdapterStreamFn },\n\toverride?: Partial<Pick<LLMAdapter, \"provider\" | \"model\" | \"capabilities\">>,\n): LLMAdapter {\n\treturn {\n\t\tprovider: override?.provider ?? inner.provider,\n\t\tmodel: override?.model ?? inner.model,\n\t\tcapabilities: override?.capabilities ?? inner.capabilities?.bind(inner),\n\t\tinvoke: impl.invoke,\n\t\tstream: impl.stream,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// adaptInvokeResult — shape-dispatch for NodeInput<LLMResponse>\n// ---------------------------------------------------------------------------\n\n/**\n * Shape-dispatch helper for `inner.invoke(...)` return values. Converts any of\n * the three `NodeInput<LLMResponse>` shapes (Promise, plain value, Node /\n * iterable) into the caller-requested output, applying `onResp` exactly once\n * on the first DATA emission.\n *\n * **Paths.**\n * - `Promise<LLMResponse>` → `Promise<R>` (chains `onResp` via `.then`; if\n * `onError` is provided, wires `.catch` so rejected Promises flow to the\n * error path just like the stream body does).\n * - Plain `LLMResponse` (object with `content` field) → `R` (calls `onResp`\n * synchronously and returns the mapped value).\n * - Anything else → reactive `Node<R>` via `fromAny` + `onFirstData(onResp)`\n * so late subscribers don't re-fire the side effect.\n *\n * @category internal\n */\nexport function adaptInvokeResult<R>(\n\tinput: NodeInput<LLMResponse>,\n\topts: {\n\t\tonResp: (resp: LLMResponse) => R;\n\t\t/**\n\t\t * If provided, rejected Promises are piped through this handler (for\n\t\t * stats / budget recording) before re-throwing. Signature mirrors the\n\t\t * stream try/catch shape so callers can share a single error-recording\n\t\t * closure across both paths.\n\t\t */\n\t\tonError?: (err: unknown) => void;\n\t\t/** Optional node name for the reactive-path derived (describe-friendly). */\n\t\tname?: string;\n\t},\n): Promise<R> | R | Node<R> {\n\tconst { onResp, onError, name } = opts;\n\n\t// Promise / thenable: chain .then, optionally .catch.\n\tif (input != null && typeof (input as PromiseLike<LLMResponse>).then === \"function\") {\n\t\tconst p = input as Promise<LLMResponse>;\n\t\tif (onError) {\n\t\t\treturn p.then(onResp).catch((err: unknown) => {\n\t\t\t\tonError(err);\n\t\t\t\tthrow err;\n\t\t\t});\n\t\t}\n\t\treturn p.then(onResp);\n\t}\n\t// Plain LLMResponse (synchronous).\n\tif (input != null && typeof input === \"object\" && \"content\" in (input as object)) {\n\t\treturn onResp(input as LLMResponse);\n\t}\n\t// Reactive / iterable — map inside a `derived` guarded by `onFirstData`\n\t// so the side-effect fires exactly once per node lifetime (push-on-\n\t// subscribe replay on late subscribers is silent).\n\tconst bridged = fromAny(input);\n\t// Wire `onError` via a side-subscription on the bridged node. `onFirstData`\n\t// only handles DATA — ERROR messages need their own hook so stats /\n\t// budget recording fires symmetrically with the Promise path. The\n\t// subscription runs for the lifetime of the derived below (keepalive via\n\t// the downstream derived's activation), and fires at most once per ERROR\n\t// frame. Without this, ERRORs on Node-shaped adapter returns silently\n\t// bypass budget/observable recording.\n\tif (onError) {\n\t\tlet errored = false;\n\t\tbridged.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (errored) return;\n\t\t\t\tif ((m as readonly [symbol, unknown])[0] === ERROR) {\n\t\t\t\t\terrored = true;\n\t\t\t\t\tonError((m as readonly [symbol, unknown])[1]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\t// `captured` holds the mapped value from the first DATA so re-subscribers\n\t// and re-emissions see a stable mapped value without re-firing `onResp`.\n\t// Use a distinct `mapped` sentinel (not nullish) because `onResp` may\n\t// legitimately return `null` / `undefined` / `0` — the prior\n\t// `captured ?? onResp(v)` guard re-fired `onResp` on falsy captured, which\n\t// broke the \"exactly once per node lifetime\" contract.\n\tlet captured: R;\n\tlet mapped = false;\n\tconst tapped = onFirstData(bridged, (v) => {\n\t\tcaptured = onResp(v);\n\t\tmapped = true;\n\t});\n\treturn node<R>(\n\t\t[tapped],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst v = data[0];\n\t\t\tif (v == null) {\n\t\t\t\tactions.emit(null as R);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (mapped) {\n\t\t\t\tactions.emit(captured);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tactions.emit(onResp(v as LLMResponse));\n\t\t},\n\t\t{ describeKind: \"derived\", name: name ?? \"adapt/invokeTap\" },\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// buildCallStats — CallStatsEvent constructor\n// ---------------------------------------------------------------------------\n\nexport interface BuildCallStatsArgs {\n\tprovider: string;\n\tmodel: string;\n\ttier?: string;\n\tusage: TokenUsage;\n\tstartNs: number;\n\tmethod: \"invoke\" | \"stream\";\n\terror?: { readonly type: string; readonly message: string };\n\t/** Override the wall-clock stamp (useful for tests / replay). */\n\tstartWallClockNs?: number;\n\t/** Override the monotonic end stamp (useful for tests). */\n\tendNs?: number;\n}\n\n/**\n * Constructs a {@link CallStatsEvent} from the arguments observable.ts and\n * budget-gate.ts used to assemble inline. The `timestamp` / `latencyMs` are\n * computed from `startNs` + (optional) `endNs`; `wallClock` is snapshot at\n * call-start via `wallClockNs()` unless overridden.\n *\n * @category internal\n */\nexport function buildCallStats(args: BuildCallStatsArgs): CallStatsEvent {\n\tconst end = args.endNs ?? monotonicNs();\n\treturn {\n\t\ttimestamp: end,\n\t\twallClock: args.startWallClockNs ?? wallClockNs(),\n\t\tprovider: args.provider,\n\t\tmodel: args.model,\n\t\ttier: args.tier,\n\t\tusage: args.usage,\n\t\tlatencyMs: Math.max(0, (end - args.startNs) / 1e6),\n\t\tmethod: args.method,\n\t\t...(args.error ? { error: args.error } : {}),\n\t};\n}\n\n/** Convenience — empty disaggregated usage stub used by every middleware. */\nexport function emptyUsageStub(): TokenUsage {\n\treturn { input: { regular: 0 }, output: { regular: 0 } };\n}\n\n// ---------------------------------------------------------------------------\n// meta.middlewareLayer + describeAdapterStack (Unit 11 Q1 user directive)\n// ---------------------------------------------------------------------------\n\n/** Symbol key carrying the wrap chain on the returned adapter. Non-enumerable. */\nconst MIDDLEWARE_LAYERS = Symbol.for(\"graphrefly.adapter.middlewareLayers\");\n\n/**\n * Stamp `adapter` with a middleware-layer name and return it. The stamp is a\n * non-enumerable property keyed by `Symbol.for(\"graphrefly.adapter.middlewareLayers\")`\n * — opaque to users, visible via {@link describeAdapterStack}.\n *\n * Each wrap prepends its layer to `inner`'s chain so the stack can be walked\n * bottom-up (innermost first). Providers have no layer stamp — they show up\n * as the bottom of the chain via their `provider` / `model` identity.\n *\n * @category internal\n */\nexport function withLayer<A extends LLMAdapter>(\n\tadapter: A,\n\tlayerName: string,\n\tinner?: LLMAdapter,\n): A {\n\tconst innerLayers = inner ? readLayers(inner) : [];\n\tconst chain = [...innerLayers, layerName];\n\tObject.defineProperty(adapter, MIDDLEWARE_LAYERS, {\n\t\tvalue: Object.freeze(chain),\n\t\tenumerable: false,\n\t\twritable: false,\n\t\tconfigurable: false,\n\t});\n\treturn adapter;\n}\n\n/**\n * Returns the middleware-layer names stamped on `adapter`, innermost first.\n * An adapter that has never been wrapped returns `[]` — callers combine the\n * result with `adapter.provider` / `adapter.model` for a full stack render.\n *\n * @example\n * ```ts\n * const stack = describeAdapterStack(resilientAdapter(anthropicAdapter(), opts).adapter);\n * // → [\"withLLMTimeout\", \"withRetry\", \"withLLMBreaker\", \"withBudgetGate\", \"withRateLimiter\", \"cascade\"]\n * ```\n *\n * @category extra\n */\nexport function describeAdapterStack(adapter: LLMAdapter): readonly string[] {\n\treturn readLayers(adapter);\n}\n\nfunction readLayers(adapter: LLMAdapter): readonly string[] {\n\tconst v = (adapter as unknown as Record<symbol, unknown>)[MIDDLEWARE_LAYERS];\n\treturn Array.isArray(v) ? (v as readonly string[]) : [];\n}\n","/**\n * GoogleAdapter — default fetch-backed, optional SDK-backed.\n *\n * The SDK-backed path targets the `@google/genai` SDK shape:\n * `client.models.generateContent({ model, contents, config })` — single\n * param, with generation params and `abortSignal` under `config`. The\n * legacy `@google/generative-ai` two-arg `(params, {signal})` shape is no\n * longer accepted; pass a `GoogleGenAI` instance via `opts.sdk`.\n *\n * Maps Gemini `usageMetadata`:\n * - `promptTokenCount` minus `cachedContentTokenCount` → `input.regular`\n * - `cachedContentTokenCount` → `input.cacheRead`\n * - `candidatesTokenCount` → `output.regular`\n * - `thoughtsTokenCount` → `output.reasoning`\n * - `toolUsePromptTokenCount` → `input.toolUse`\n * - `promptTokensDetails[]` → `input.{image,audio,video}` per modality\n */\n\nimport { monotonicNs } from \"@graphrefly/pure-ts/core\";\nimport { makeHttpError } from \"../../../../base/io/http-error.js\";\nimport { parseSSEStream } from \"../../../../base/io/sse.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n\tStreamDelta,\n\tTokenUsage,\n\tToolDefinition,\n} from \"../core/types.js\";\n\nexport interface GoogleAdapterOptions {\n\t/** API key. Falls back to `process.env.GOOGLE_API_KEY` / `GEMINI_API_KEY` on Node. */\n\tapiKey?: string;\n\tmodel?: string;\n\tbaseURL?: string;\n\t/** Extra headers on every request. */\n\theaders?: Record<string, string>;\n\t/**\n\t * Optional `@google/genai` SDK instance (e.g. `new GoogleGenAI({apiKey})`).\n\t * When omitted, the adapter uses the fetch-backed path against the\n\t * Generative Language REST API.\n\t */\n\tsdk?: GoogleSdkLike;\n\tfetchImpl?: typeof fetch;\n}\n\n/**\n * Duck-type matching the `@google/genai` (`GoogleGenAI`) SDK shape:\n * single-param `generateContent({ model, contents, config })` where\n * generation parameters and `abortSignal` live under `config`.\n *\n * The `@google/generative-ai` predecessor's two-arg `(params, {signal})`\n * shape is no longer accepted.\n */\nexport interface GoogleSdkLike {\n\tmodels: {\n\t\tgenerateContent(params: GoogleSdkRequestParams): Promise<GeminiResponse>;\n\t\tgenerateContentStream?(\n\t\t\tparams: GoogleSdkRequestParams,\n\t\t): Promise<AsyncIterable<GeminiResponse>> | AsyncIterable<GeminiResponse>;\n\t};\n}\n\n/** Single-param request shape consumed by `@google/genai`'s `models.generateContent`. */\nexport interface GoogleSdkRequestParams {\n\tmodel: string;\n\tcontents: unknown;\n\tconfig?: GoogleSdkRequestConfig;\n}\n\n/**\n * Generation config under the new SDK. `abortSignal` is the cancellation\n * channel — there is no second-arg `{signal}`.\n */\nexport interface GoogleSdkRequestConfig {\n\tabortSignal?: AbortSignal;\n\ttemperature?: number;\n\tmaxOutputTokens?: number;\n\tsystemInstruction?: unknown;\n\ttools?: unknown;\n\tthinkingConfig?: unknown;\n\t[extra: string]: unknown;\n}\n\ninterface GeminiResponse {\n\tcandidates?: ReadonlyArray<{\n\t\tcontent?: {\n\t\t\trole?: string;\n\t\t\tparts?: ReadonlyArray<{\n\t\t\t\ttext?: string;\n\t\t\t\tthought?: boolean;\n\t\t\t\tfunctionCall?: { name: string; args: Record<string, unknown> };\n\t\t\t}>;\n\t\t};\n\t\tfinishReason?: string;\n\t}>;\n\tusageMetadata?: GeminiUsage;\n\tmodelVersion?: string;\n}\n\ninterface GeminiUsage {\n\tpromptTokenCount?: number;\n\tcandidatesTokenCount?: number;\n\ttotalTokenCount?: number;\n\tthoughtsTokenCount?: number;\n\tcachedContentTokenCount?: number;\n\ttoolUsePromptTokenCount?: number;\n\tpromptTokensDetails?: ReadonlyArray<{ modality: string; tokenCount: number }>;\n\tcandidatesTokensDetails?: ReadonlyArray<{ modality: string; tokenCount: number }>;\n\tcacheTokensDetails?: ReadonlyArray<{ modality: string; tokenCount: number }>;\n}\n\nexport function googleAdapter(opts: GoogleAdapterOptions = {}): LLMAdapter {\n\tif (opts.sdk) return sdkBackedGoogle(opts);\n\treturn fetchBackedGoogle(opts);\n}\n\n// ---------------------------------------------------------------------------\n// Mapping\n// ---------------------------------------------------------------------------\n\nfunction toGeminiRequest(\n\tmessages: readonly ChatMessage[],\n\tinvokeOpts: LLMInvokeOptions | undefined,\n): Record<string, unknown> {\n\tconst systemParts: string[] = [];\n\tconst contents: Array<{\n\t\trole: string;\n\t\tparts: Array<{ text?: string; functionCall?: unknown; functionResponse?: unknown }>;\n\t}> = [];\n\tif (invokeOpts?.systemPrompt) systemParts.push(invokeOpts.systemPrompt);\n\n\tfor (const m of messages) {\n\t\tif (m.role === \"system\") {\n\t\t\tsystemParts.push(m.content);\n\t\t\tcontinue;\n\t\t}\n\t\tif (m.role === \"tool\") {\n\t\t\tcontents.push({\n\t\t\t\trole: \"user\",\n\t\t\t\tparts: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfunctionResponse: {\n\t\t\t\t\t\t\tname: m.name ?? m.toolCallId ?? \"tool\",\n\t\t\t\t\t\t\tresponse: { result: m.content },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (m.role === \"assistant\" && m.toolCalls && m.toolCalls.length > 0) {\n\t\t\tconst parts: Array<{ text?: string; functionCall?: unknown }> = [];\n\t\t\tif (m.content) parts.push({ text: m.content });\n\t\t\tfor (const tc of m.toolCalls) {\n\t\t\t\tparts.push({ functionCall: { name: tc.name, args: tc.arguments } });\n\t\t\t}\n\t\t\tcontents.push({ role: \"model\", parts });\n\t\t\tcontinue;\n\t\t}\n\t\tcontents.push({\n\t\t\trole: m.role === \"assistant\" ? \"model\" : \"user\",\n\t\t\tparts: [{ text: m.content }],\n\t\t});\n\t}\n\n\tconst body: Record<string, unknown> = { contents };\n\tif (systemParts.length > 0) {\n\t\tbody.systemInstruction = { role: \"system\", parts: [{ text: systemParts.join(\"\\n\\n\") }] };\n\t}\n\tconst genConfig: Record<string, unknown> = {};\n\tif (invokeOpts?.maxTokens != null) genConfig.maxOutputTokens = invokeOpts.maxTokens;\n\tif (invokeOpts?.temperature != null) genConfig.temperature = invokeOpts.temperature;\n\tif (invokeOpts?.maxReasoningTokens != null) {\n\t\tgenConfig.thinkingConfig = { thinkingBudget: invokeOpts.maxReasoningTokens };\n\t}\n\tif (Object.keys(genConfig).length > 0) body.generationConfig = genConfig;\n\tif (invokeOpts?.tools && invokeOpts.tools.length > 0) {\n\t\tbody.tools = [{ functionDeclarations: invokeOpts.tools.map(toGeminiTool) }];\n\t}\n\tif (invokeOpts?.providerExtras) Object.assign(body, invokeOpts.providerExtras);\n\treturn body;\n}\n\nfunction toGeminiTool(t: ToolDefinition): Record<string, unknown> {\n\treturn {\n\t\tname: t.name,\n\t\tdescription: t.description,\n\t\tparameters: t.parameters,\n\t};\n}\n\n/**\n * Reshape the fetch-API request body into the SDK's `{ model, contents,\n * config }` form. Generation params (`temperature`, `maxOutputTokens`,\n * `thinkingConfig`) move from `body.generationConfig.*` to `config.*`;\n * `systemInstruction` and `tools` move from top-level body keys into\n * `config`; `abortSignal` is threaded into `config`. `providerExtras` keys\n * spread into `config` so escape-hatch usage remains identical.\n */\nfunction toSdkParams(\n\tbody: Record<string, unknown>,\n\tmodel: string,\n\tsignal: AbortSignal | undefined,\n): GoogleSdkRequestParams {\n\tconst config: GoogleSdkRequestConfig = {};\n\tconst gen = body.generationConfig as Record<string, unknown> | undefined;\n\tif (gen) {\n\t\tif (typeof gen.maxOutputTokens === \"number\") config.maxOutputTokens = gen.maxOutputTokens;\n\t\tif (typeof gen.temperature === \"number\") config.temperature = gen.temperature;\n\t\tif (gen.thinkingConfig) config.thinkingConfig = gen.thinkingConfig;\n\t}\n\tif (body.systemInstruction) config.systemInstruction = body.systemInstruction;\n\tif (body.tools) config.tools = body.tools;\n\tfor (const [k, v] of Object.entries(body)) {\n\t\tif (\n\t\t\tk === \"contents\" ||\n\t\t\tk === \"generationConfig\" ||\n\t\t\tk === \"systemInstruction\" ||\n\t\t\tk === \"tools\" ||\n\t\t\t// Skip `abortSignal` so a caller-supplied entry in `providerExtras`\n\t\t\t// can't briefly land in `config.abortSignal` before being\n\t\t\t// overwritten — the canonical signal channel is the second\n\t\t\t// `signal` argument (set on `config.abortSignal` below).\n\t\t\tk === \"abortSignal\" ||\n\t\t\t// Skip `model` so a stray `body.model` (not produced by\n\t\t\t// `toGeminiRequest` today, but defensively guarded) doesn't\n\t\t\t// duplicate the top-level `model` field on the SDK request.\n\t\t\tk === \"model\"\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\tconfig[k] = v;\n\t}\n\tif (signal) config.abortSignal = signal;\n\treturn {\n\t\tmodel,\n\t\tcontents: body.contents,\n\t\tconfig: Object.keys(config).length > 0 ? config : undefined,\n\t};\n}\n\nfunction mapUsage(u: GeminiUsage | undefined): TokenUsage {\n\tconst usage: TokenUsage = {\n\t\tinput: { regular: 0 },\n\t\toutput: { regular: 0 },\n\t\traw: u,\n\t};\n\tif (!u) return usage;\n\tconst promptTotal = u.promptTokenCount ?? 0;\n\tconst cached = u.cachedContentTokenCount ?? 0;\n\tusage.input.regular = Math.max(0, promptTotal - cached);\n\tif (cached > 0) usage.input.cacheRead = cached;\n\tif (u.toolUsePromptTokenCount) usage.input.toolUse = u.toolUsePromptTokenCount;\n\tif (u.promptTokensDetails) {\n\t\tfor (const d of u.promptTokensDetails) {\n\t\t\tconst modality = d.modality?.toLowerCase();\n\t\t\tif (modality === \"image\") usage.input.image = (usage.input.image ?? 0) + d.tokenCount;\n\t\t\telse if (modality === \"audio\") usage.input.audio = (usage.input.audio ?? 0) + d.tokenCount;\n\t\t\telse if (modality === \"video\") usage.input.video = (usage.input.video ?? 0) + d.tokenCount;\n\t\t}\n\t}\n\tusage.output.regular = u.candidatesTokenCount ?? 0;\n\tif (u.thoughtsTokenCount) usage.output.reasoning = u.thoughtsTokenCount;\n\treturn usage;\n}\n\nfunction toLLMResponse(json: GeminiResponse, latencyMs: number): LLMResponse {\n\tconst cand = json.candidates?.[0];\n\tconst parts = cand?.content?.parts ?? [];\n\tconst textParts: string[] = [];\n\tconst toolCalls: { id: string; name: string; arguments: Record<string, unknown> }[] = [];\n\tlet i = 0;\n\tfor (const p of parts) {\n\t\tif (typeof p.text === \"string\") textParts.push(p.text);\n\t\tif (p.functionCall) {\n\t\t\ttoolCalls.push({\n\t\t\t\tid: `${p.functionCall.name}-${i++}`,\n\t\t\t\tname: p.functionCall.name,\n\t\t\t\targuments: p.functionCall.args ?? {},\n\t\t\t});\n\t\t}\n\t}\n\treturn {\n\t\tcontent: textParts.join(\"\"),\n\t\ttoolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n\t\tusage: mapUsage(json.usageMetadata),\n\t\tfinishReason: cand?.finishReason,\n\t\tlatencyMs,\n\t\tmodel: json.modelVersion,\n\t\tprovider: \"google\",\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Fetch-backed\n// ---------------------------------------------------------------------------\n\nfunction resolveApiKey(opts: GoogleAdapterOptions): string | undefined {\n\tif (opts.apiKey) return opts.apiKey;\n\tconst env = (globalThis as { process?: { env?: Record<string, string> } }).process?.env;\n\treturn env?.GOOGLE_API_KEY ?? env?.GEMINI_API_KEY;\n}\n\nfunction fetchBackedGoogle(opts: GoogleAdapterOptions): LLMAdapter {\n\tconst baseURL = opts.baseURL ?? \"https://generativelanguage.googleapis.com/v1beta\";\n\tconst fetchImpl = opts.fetchImpl ?? fetch;\n\n\tconst pickModel = (invokeOpts: LLMInvokeOptions | undefined): string => {\n\t\tconst model = invokeOpts?.model ?? opts.model;\n\t\tif (!model)\n\t\t\tthrow new Error(\"googleAdapter: model must be set via options.model or invokeOpts.model\");\n\t\treturn model;\n\t};\n\n\tconst keyParam = (): string => {\n\t\tconst key = resolveApiKey(opts);\n\t\tif (!key) throw new Error(\"googleAdapter: apiKey required for invoke/stream\");\n\t\treturn `key=${encodeURIComponent(key)}`;\n\t};\n\n\treturn {\n\t\tprovider: \"google\",\n\t\tmodel: opts.model,\n\n\t\tasync invoke(messages, invokeOpts): Promise<LLMResponse> {\n\t\t\tconst model = pickModel(invokeOpts);\n\t\t\tconst body = toGeminiRequest(messages, invokeOpts);\n\t\t\tconst start = monotonicNs();\n\t\t\tconst url = `${baseURL}/models/${encodeURIComponent(model)}:generateContent?${keyParam()}`;\n\t\t\tconst resp = await fetchImpl(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"content-type\": \"application/json\", ...(opts.headers ?? {}) },\n\t\t\t\tbody: JSON.stringify(body),\n\t\t\t\tsignal: invokeOpts?.signal,\n\t\t\t});\n\t\t\tif (!resp.ok) throw await makeHttpError(resp, \"Google\");\n\t\t\tconst json = (await resp.json()) as GeminiResponse;\n\t\t\tconst latencyMs = Math.max(0, (monotonicNs() - start) / 1e6);\n\t\t\treturn toLLMResponse(json, latencyMs);\n\t\t},\n\n\t\tasync *stream(messages, invokeOpts): AsyncGenerator<StreamDelta> {\n\t\t\tconst model = pickModel(invokeOpts);\n\t\t\tconst body = toGeminiRequest(messages, invokeOpts);\n\t\t\tconst url = `${baseURL}/models/${encodeURIComponent(model)}:streamGenerateContent?alt=sse&${keyParam()}`;\n\t\t\tconst resp = await fetchImpl(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"content-type\": \"application/json\",\n\t\t\t\t\taccept: \"text/event-stream\",\n\t\t\t\t\t...(opts.headers ?? {}),\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify(body),\n\t\t\t\tsignal: invokeOpts?.signal,\n\t\t\t});\n\t\t\tif (!resp.ok) throw await makeHttpError(resp, \"Google\");\n\t\t\tif (!resp.body) throw new Error(\"googleAdapter: streaming response has no body\");\n\n\t\t\tlet finalUsage: GeminiUsage | undefined;\n\t\t\tlet finishReason: string | undefined;\n\n\t\t\tfor await (const event of parseSSEStream(resp.body, { signal: invokeOpts?.signal })) {\n\t\t\t\tif (!event.data) continue;\n\t\t\t\tlet parsed: GeminiResponse;\n\t\t\t\ttry {\n\t\t\t\t\tparsed = JSON.parse(event.data) as GeminiResponse;\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst cand = parsed.candidates?.[0];\n\t\t\t\tfor (const p of cand?.content?.parts ?? []) {\n\t\t\t\t\tif (typeof p.text === \"string\") {\n\t\t\t\t\t\tif (p.thought) yield { type: \"thinking\", delta: p.text };\n\t\t\t\t\t\telse yield { type: \"token\", delta: p.text };\n\t\t\t\t\t}\n\t\t\t\t\tif (p.functionCall) {\n\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\ttype: \"tool-call-delta\",\n\t\t\t\t\t\t\tdelta: {\n\t\t\t\t\t\t\t\tname: p.functionCall.name,\n\t\t\t\t\t\t\t\targumentsDelta: JSON.stringify(p.functionCall.args ?? {}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (cand?.finishReason) finishReason = cand.finishReason;\n\t\t\t\tif (parsed.usageMetadata) finalUsage = parsed.usageMetadata;\n\t\t\t}\n\t\t\tif (finalUsage) yield { type: \"usage\", usage: mapUsage(finalUsage) };\n\t\t\tyield { type: \"finish\", reason: finishReason ?? \"stop\" };\n\t\t},\n\t};\n}\n\nfunction sdkBackedGoogle(opts: GoogleAdapterOptions): LLMAdapter {\n\tconst sdk = opts.sdk;\n\tif (!sdk) throw new Error(\"sdkBackedGoogle: sdk instance required\");\n\n\treturn {\n\t\tprovider: \"google\",\n\t\tmodel: opts.model,\n\n\t\tasync invoke(messages, invokeOpts): Promise<LLMResponse> {\n\t\t\tconst body = toGeminiRequest(messages, invokeOpts);\n\t\t\tconst model = invokeOpts?.model ?? opts.model;\n\t\t\tif (!model) throw new Error(\"googleAdapter: model required\");\n\t\t\tconst params = toSdkParams(body, model, invokeOpts?.signal);\n\t\t\tconst start = monotonicNs();\n\t\t\tconst resp = await sdk.models.generateContent(params);\n\t\t\tconst latencyMs = Math.max(0, (monotonicNs() - start) / 1e6);\n\t\t\treturn toLLMResponse(resp, latencyMs);\n\t\t},\n\n\t\tasync *stream(messages, invokeOpts): AsyncGenerator<StreamDelta> {\n\t\t\tif (!sdk.models.generateContentStream) {\n\t\t\t\tthrow new Error(\"sdkBackedGoogle: SDK instance does not expose generateContentStream\");\n\t\t\t}\n\t\t\tconst body = toGeminiRequest(messages, invokeOpts);\n\t\t\tconst model = invokeOpts?.model ?? opts.model;\n\t\t\tif (!model) throw new Error(\"googleAdapter: model required\");\n\t\t\tconst params = toSdkParams(body, model, invokeOpts?.signal);\n\t\t\tlet finalUsage: GeminiUsage | undefined;\n\t\t\tlet finishReason: string | undefined;\n\t\t\t// `@google/genai` returns `Promise<AsyncIterable<...>>`; older shapes\n\t\t\t// returned the iterable directly. Awaiting a non-thenable resolves\n\t\t\t// to itself, so this works for both.\n\t\t\tconst stream = await sdk.models.generateContentStream(params);\n\t\t\tfor await (const chunk of stream) {\n\t\t\t\tconst cand = chunk.candidates?.[0];\n\t\t\t\tfor (const p of cand?.content?.parts ?? []) {\n\t\t\t\t\tif (typeof p.text === \"string\") {\n\t\t\t\t\t\tif (p.thought) yield { type: \"thinking\", delta: p.text };\n\t\t\t\t\t\telse yield { type: \"token\", delta: p.text };\n\t\t\t\t\t}\n\t\t\t\t\tif (p.functionCall) {\n\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\ttype: \"tool-call-delta\",\n\t\t\t\t\t\t\tdelta: {\n\t\t\t\t\t\t\t\tname: p.functionCall.name,\n\t\t\t\t\t\t\t\targumentsDelta: JSON.stringify(p.functionCall.args ?? {}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (cand?.finishReason) finishReason = cand.finishReason;\n\t\t\t\tif (chunk.usageMetadata) finalUsage = chunk.usageMetadata;\n\t\t\t}\n\t\t\tif (finalUsage) yield { type: \"usage\", usage: mapUsage(finalUsage) };\n\t\t\tyield { type: \"finish\", reason: finishReason ?? \"stop\" };\n\t\t},\n\t};\n}\n","/**\n * OpenAICompatAdapter — default fetch-backed, optional SDK-backed.\n *\n * Covers any provider that speaks OpenAI chat/completions. Preset base URLs\n * for OpenAI, OpenRouter, Groq, Ollama, DeepSeek, xAI Grok (all expose the\n * same `/v1/chat/completions` shape).\n *\n * Token usage mapping:\n * - `prompt_tokens` → `input.regular` (minus cached_tokens)\n * - `prompt_tokens_details.cached_tokens` → `input.cacheRead`\n * - `prompt_tokens_details.audio_tokens` → `input.audio`\n * - `completion_tokens` → `output.regular` (minus reasoning)\n * - `completion_tokens_details.reasoning_tokens` → `output.reasoning`\n * - `completion_tokens_details.audio_tokens` → `output.audio`\n * - `completion_tokens_details.accepted_prediction_tokens` → `output.predictionAccepted`\n * - `completion_tokens_details.rejected_prediction_tokens` → `output.predictionRejected`\n *\n * DeepSeek compatibility: `prompt_cache_hit_tokens` / `prompt_cache_miss_tokens`\n * are surfaced in the `raw` field of `TokenUsage`; when present we prefer\n * them over the OpenAI-style `cached_tokens` for cache-read attribution.\n */\n\nimport { monotonicNs } from \"@graphrefly/pure-ts/core\";\nimport { makeHttpError } from \"../../../../base/io/http-error.js\";\nimport { parseSSEStream } from \"../../../../base/io/sse.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n\tStreamDelta,\n\tTokenUsage,\n\tToolDefinition,\n} from \"../core/types.js\";\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport type OpenAICompatPreset = \"openai\" | \"openrouter\" | \"groq\" | \"ollama\" | \"deepseek\" | \"xai\";\n\nconst PRESETS: Record<\n\tOpenAICompatPreset,\n\t{ baseURL: string; apiKeyEnv?: string; provider: string }\n> = {\n\topenai: { baseURL: \"https://api.openai.com/v1\", apiKeyEnv: \"OPENAI_API_KEY\", provider: \"openai\" },\n\topenrouter: {\n\t\tbaseURL: \"https://openrouter.ai/api/v1\",\n\t\tapiKeyEnv: \"OPENROUTER_API_KEY\",\n\t\tprovider: \"openrouter\",\n\t},\n\tgroq: { baseURL: \"https://api.groq.com/openai/v1\", apiKeyEnv: \"GROQ_API_KEY\", provider: \"groq\" },\n\tollama: { baseURL: \"http://localhost:11434/v1\", provider: \"ollama\" },\n\tdeepseek: {\n\t\tbaseURL: \"https://api.deepseek.com/v1\",\n\t\tapiKeyEnv: \"DEEPSEEK_API_KEY\",\n\t\tprovider: \"deepseek\",\n\t},\n\txai: { baseURL: \"https://api.x.ai/v1\", apiKeyEnv: \"XAI_API_KEY\", provider: \"xai\" },\n};\n\nexport interface OpenAICompatAdapterOptions {\n\tpreset?: OpenAICompatPreset;\n\t/** Explicit provider label (defaults to preset's provider). */\n\tprovider?: string;\n\t/** API key. Falls back to the preset's default env var on Node. */\n\tapiKey?: string;\n\tmodel?: string;\n\t/** Override base URL (wins over `preset`). */\n\tbaseURL?: string;\n\t/** Extra request headers. */\n\theaders?: Record<string, string>;\n\t/** Extra request-body fields merged on every request (OpenRouter routing etc.). */\n\tbodyExtras?: Record<string, unknown>;\n\t/** User-provided SDK instance (OpenAI-family shape). */\n\tsdk?: OpenAISdkLike;\n\t/** Custom fetch (for tests). */\n\tfetchImpl?: typeof fetch;\n}\n\nexport interface OpenAISdkLike {\n\tchat: {\n\t\tcompletions: {\n\t\t\tcreate(\n\t\t\t\tparams: Record<string, unknown>,\n\t\t\t\topts?: { signal?: AbortSignal },\n\t\t\t): Promise<OpenAIChatResponse>;\n\t\t};\n\t};\n}\n\ninterface OpenAIChatResponse {\n\tid: string;\n\tchoices: ReadonlyArray<{\n\t\tmessage: {\n\t\t\trole: string;\n\t\t\tcontent?: string | null;\n\t\t\ttool_calls?: ReadonlyArray<{\n\t\t\t\tid: string;\n\t\t\t\ttype: \"function\";\n\t\t\t\tfunction: { name: string; arguments: string };\n\t\t\t}>;\n\t\t\treasoning_content?: string;\n\t\t};\n\t\tfinish_reason?: string;\n\t}>;\n\tusage?: OpenAIUsage;\n\tmodel?: string;\n}\n\ninterface OpenAIUsage {\n\tprompt_tokens?: number;\n\tcompletion_tokens?: number;\n\ttotal_tokens?: number;\n\tprompt_tokens_details?: {\n\t\tcached_tokens?: number;\n\t\taudio_tokens?: number;\n\t};\n\tcompletion_tokens_details?: {\n\t\treasoning_tokens?: number;\n\t\taudio_tokens?: number;\n\t\taccepted_prediction_tokens?: number;\n\t\trejected_prediction_tokens?: number;\n\t};\n\t// DeepSeek\n\tprompt_cache_hit_tokens?: number;\n\tprompt_cache_miss_tokens?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function openAICompatAdapter(opts: OpenAICompatAdapterOptions = {}): LLMAdapter {\n\tif (opts.sdk) return sdkBackedOpenAI(opts);\n\treturn fetchBackedOpenAI(opts);\n}\n\n// ---------------------------------------------------------------------------\n// Mapping\n// ---------------------------------------------------------------------------\n\nfunction toOpenAIRequest(\n\tmessages: readonly ChatMessage[],\n\tinvokeOpts: LLMInvokeOptions | undefined,\n\tdefaultModel: string | undefined,\n\tstream: boolean,\n\tbodyExtras: Record<string, unknown> | undefined,\n): Record<string, unknown> {\n\tconst model = invokeOpts?.model ?? defaultModel;\n\tif (!model)\n\t\tthrow new Error(\"openAICompatAdapter: model must be set via options.model or invokeOpts.model\");\n\tconst mapped = messages.map(toOpenAIMessage);\n\tif (invokeOpts?.systemPrompt && !messages.some((m) => m.role === \"system\")) {\n\t\tmapped.unshift({ role: \"system\", content: invokeOpts.systemPrompt });\n\t}\n\tconst body: Record<string, unknown> = { model, messages: mapped };\n\tif (invokeOpts?.maxTokens != null) body.max_tokens = invokeOpts.maxTokens;\n\tif (invokeOpts?.temperature != null) body.temperature = invokeOpts.temperature;\n\tif (invokeOpts?.tools && invokeOpts.tools.length > 0) {\n\t\tbody.tools = invokeOpts.tools.map(toOpenAITool);\n\t}\n\tif (invokeOpts?.maxReasoningTokens != null) {\n\t\tbody.reasoning = { max_tokens: invokeOpts.maxReasoningTokens };\n\t}\n\tif (stream) {\n\t\tbody.stream = true;\n\t\tbody.stream_options = { include_usage: true };\n\t}\n\tif (bodyExtras) Object.assign(body, bodyExtras);\n\tif (invokeOpts?.providerExtras) Object.assign(body, invokeOpts.providerExtras);\n\treturn body;\n}\n\nfunction toOpenAIMessage(m: ChatMessage): Record<string, unknown> {\n\tif (m.role === \"tool\") {\n\t\treturn { role: \"tool\", tool_call_id: m.toolCallId, content: m.content };\n\t}\n\tif (m.role === \"assistant\" && m.toolCalls && m.toolCalls.length > 0) {\n\t\treturn {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: m.content || null,\n\t\t\ttool_calls: m.toolCalls.map((tc) => ({\n\t\t\t\tid: tc.id,\n\t\t\t\ttype: \"function\",\n\t\t\t\tfunction: { name: tc.name, arguments: JSON.stringify(tc.arguments) },\n\t\t\t})),\n\t\t};\n\t}\n\treturn { role: m.role, content: m.content };\n}\n\nfunction toOpenAITool(t: ToolDefinition): Record<string, unknown> {\n\treturn {\n\t\ttype: \"function\",\n\t\tfunction: {\n\t\t\tname: t.name,\n\t\t\tdescription: t.description,\n\t\t\tparameters: t.parameters,\n\t\t},\n\t};\n}\n\nfunction mapUsage(u: OpenAIUsage | undefined): TokenUsage {\n\tconst usage: TokenUsage = {\n\t\tinput: { regular: 0 },\n\t\toutput: { regular: 0 },\n\t\traw: u,\n\t};\n\tif (!u) return usage;\n\tconst inputTotal = u.prompt_tokens ?? 0;\n\tlet cacheRead = u.prompt_tokens_details?.cached_tokens ?? 0;\n\tif (u.prompt_cache_hit_tokens != null) {\n\t\t// DeepSeek: prefer explicit hit/miss split when present\n\t\tcacheRead = u.prompt_cache_hit_tokens;\n\t\tusage.input.regular = u.prompt_cache_miss_tokens ?? Math.max(0, inputTotal - cacheRead);\n\t} else {\n\t\tusage.input.regular = Math.max(0, inputTotal - cacheRead);\n\t}\n\tif (cacheRead > 0) usage.input.cacheRead = cacheRead;\n\tif (u.prompt_tokens_details?.audio_tokens)\n\t\tusage.input.audio = u.prompt_tokens_details.audio_tokens;\n\n\tconst outputTotal = u.completion_tokens ?? 0;\n\tconst reasoning = u.completion_tokens_details?.reasoning_tokens ?? 0;\n\tusage.output.regular = Math.max(0, outputTotal - reasoning);\n\tif (reasoning > 0) usage.output.reasoning = reasoning;\n\tif (u.completion_tokens_details?.audio_tokens)\n\t\tusage.output.audio = u.completion_tokens_details.audio_tokens;\n\tif (u.completion_tokens_details?.accepted_prediction_tokens) {\n\t\tusage.output.predictionAccepted = u.completion_tokens_details.accepted_prediction_tokens;\n\t}\n\tif (u.completion_tokens_details?.rejected_prediction_tokens) {\n\t\tusage.output.predictionRejected = u.completion_tokens_details.rejected_prediction_tokens;\n\t}\n\treturn usage;\n}\n\nfunction toLLMResponse(json: OpenAIChatResponse, latencyMs: number, provider: string): LLMResponse {\n\tconst choice = json.choices[0];\n\tconst msg = choice?.message;\n\tconst content = msg?.content ?? \"\";\n\tconst toolCalls = (msg?.tool_calls ?? []).map((tc) => ({\n\t\tid: tc.id,\n\t\tname: tc.function.name,\n\t\targuments: safeJsonParse(tc.function.arguments),\n\t}));\n\treturn {\n\t\tcontent,\n\t\ttoolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n\t\tusage: mapUsage(json.usage),\n\t\tfinishReason: choice?.finish_reason,\n\t\tlatencyMs,\n\t\tmodel: json.model,\n\t\tprovider,\n\t};\n}\n\nfunction safeJsonParse(s: string): Record<string, unknown> {\n\ttry {\n\t\tconst parsed = JSON.parse(s);\n\t\treturn typeof parsed === \"object\" && parsed != null\n\t\t\t? (parsed as Record<string, unknown>)\n\t\t\t: { _raw: s };\n\t} catch {\n\t\treturn { _raw: s };\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Fetch-backed\n// ---------------------------------------------------------------------------\n\nfunction resolveConfig(opts: OpenAICompatAdapterOptions): {\n\tprovider: string;\n\tbaseURL: string;\n\tapiKey: string | undefined;\n} {\n\tconst preset = opts.preset ?? \"openai\";\n\tconst base = PRESETS[preset];\n\tconst baseURL = opts.baseURL ?? base.baseURL;\n\tconst provider = opts.provider ?? base.provider;\n\tconst envKey = base.apiKeyEnv;\n\tconst apiKey =\n\t\topts.apiKey ??\n\t\t(envKey\n\t\t\t? (globalThis as { process?: { env?: Record<string, string> } }).process?.env?.[envKey]\n\t\t\t: undefined);\n\treturn { provider, baseURL, apiKey };\n}\n\nfunction fetchBackedOpenAI(opts: OpenAICompatAdapterOptions): LLMAdapter {\n\tconst { provider, baseURL, apiKey } = resolveConfig(opts);\n\tconst fetchImpl = opts.fetchImpl ?? fetch;\n\tconst needsKey = provider !== \"ollama\"; // Ollama local default: no key required.\n\n\tconst commonHeaders = (): Record<string, string> => {\n\t\tconst h: Record<string, string> = {\n\t\t\t\"content-type\": \"application/json\",\n\t\t\t...(opts.headers ?? {}),\n\t\t};\n\t\tif (needsKey) {\n\t\t\tif (!apiKey)\n\t\t\t\tthrow new Error(`openAICompatAdapter[${provider}]: apiKey required for invoke/stream`);\n\t\t\th.authorization = `Bearer ${apiKey}`;\n\t\t}\n\t\treturn h;\n\t};\n\n\treturn {\n\t\tprovider,\n\t\tmodel: opts.model,\n\n\t\tasync invoke(messages, invokeOpts): Promise<LLMResponse> {\n\t\t\tconst body = toOpenAIRequest(messages, invokeOpts, opts.model, false, opts.bodyExtras);\n\t\t\tconst start = monotonicNs();\n\t\t\tconst resp = await fetchImpl(`${baseURL}/chat/completions`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: commonHeaders(),\n\t\t\t\tbody: JSON.stringify(body),\n\t\t\t\tsignal: invokeOpts?.signal,\n\t\t\t});\n\t\t\tif (!resp.ok) throw await makeHttpError(resp, provider);\n\t\t\tconst json = (await resp.json()) as OpenAIChatResponse;\n\t\t\tconst latencyMs = Math.max(0, (monotonicNs() - start) / 1e6);\n\t\t\treturn toLLMResponse(json, latencyMs, provider);\n\t\t},\n\n\t\tasync *stream(messages, invokeOpts): AsyncGenerator<StreamDelta> {\n\t\t\tconst body = toOpenAIRequest(messages, invokeOpts, opts.model, true, opts.bodyExtras);\n\t\t\tconst resp = await fetchImpl(`${baseURL}/chat/completions`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { ...commonHeaders(), accept: \"text/event-stream\" },\n\t\t\t\tbody: JSON.stringify(body),\n\t\t\t\tsignal: invokeOpts?.signal,\n\t\t\t});\n\t\t\tif (!resp.ok) throw await makeHttpError(resp, provider);\n\t\t\tif (!resp.body)\n\t\t\t\tthrow new Error(`openAICompatAdapter[${provider}]: streaming response has no body`);\n\n\t\t\tlet finalUsage: OpenAIUsage | undefined;\n\t\t\tlet finishReason: string | undefined;\n\n\t\t\tfor await (const event of parseSSEStream(resp.body, { signal: invokeOpts?.signal })) {\n\t\t\t\tif (!event.data || event.data === \"[DONE]\") continue;\n\t\t\t\tlet parsed: Record<string, unknown>;\n\t\t\t\ttry {\n\t\t\t\t\tparsed = JSON.parse(event.data) as Record<string, unknown>;\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Streaming shape: choices[0].delta.{content?, tool_calls?, reasoning_content?}\n\t\t\t\tconst choices = parsed.choices as\n\t\t\t\t\t| ReadonlyArray<{\n\t\t\t\t\t\t\tdelta?: {\n\t\t\t\t\t\t\t\tcontent?: string;\n\t\t\t\t\t\t\t\ttool_calls?: ReadonlyArray<{\n\t\t\t\t\t\t\t\t\tindex: number;\n\t\t\t\t\t\t\t\t\tid?: string;\n\t\t\t\t\t\t\t\t\tfunction?: { name?: string; arguments?: string };\n\t\t\t\t\t\t\t\t}>;\n\t\t\t\t\t\t\t\treasoning_content?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tfinish_reason?: string;\n\t\t\t\t\t }>\n\t\t\t\t\t| undefined;\n\t\t\t\tif (choices) {\n\t\t\t\t\tconst c = choices[0];\n\t\t\t\t\tif (c?.delta?.content) yield { type: \"token\", delta: c.delta.content };\n\t\t\t\t\tif (c?.delta?.reasoning_content) {\n\t\t\t\t\t\tyield { type: \"thinking\", delta: c.delta.reasoning_content };\n\t\t\t\t\t}\n\t\t\t\t\tif (c?.delta?.tool_calls) {\n\t\t\t\t\t\tfor (const tc of c.delta.tool_calls) {\n\t\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\t\ttype: \"tool-call-delta\",\n\t\t\t\t\t\t\t\tdelta: {\n\t\t\t\t\t\t\t\t\tid: tc.id,\n\t\t\t\t\t\t\t\t\tname: tc.function?.name,\n\t\t\t\t\t\t\t\t\targumentsDelta: tc.function?.arguments,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (c?.finish_reason) finishReason = c.finish_reason;\n\t\t\t\t}\n\t\t\t\t// Yield every usage delta the provider emits (Anthropic, Groq, and\n\t\t\t\t// some OpenAI-compat providers can emit mid-stream usage). Downstream\n\t\t\t\t// consumers treat the most-recent delta as authoritative. See D5b in\n\t\t\t\t// adapter QA session.\n\t\t\t\tif (parsed.usage) {\n\t\t\t\t\tfinalUsage = parsed.usage as OpenAIUsage;\n\t\t\t\t\tyield { type: \"usage\", usage: mapUsage(finalUsage) };\n\t\t\t\t}\n\t\t\t}\n\t\t\tyield { type: \"finish\", reason: finishReason ?? \"stop\" };\n\t\t},\n\t};\n}\n\nfunction sdkBackedOpenAI(opts: OpenAICompatAdapterOptions): LLMAdapter {\n\tconst sdk = opts.sdk;\n\tif (!sdk) throw new Error(\"sdkBackedOpenAI: sdk instance required\");\n\tconst { provider } = resolveConfig(opts);\n\treturn {\n\t\tprovider,\n\t\tmodel: opts.model,\n\n\t\tasync invoke(messages, invokeOpts): Promise<LLMResponse> {\n\t\t\tconst body = toOpenAIRequest(messages, invokeOpts, opts.model, false, opts.bodyExtras);\n\t\t\tconst start = monotonicNs();\n\t\t\tconst resp = await sdk.chat.completions.create(body, { signal: invokeOpts?.signal });\n\t\t\tconst latencyMs = Math.max(0, (monotonicNs() - start) / 1e6);\n\t\t\treturn toLLMResponse(resp, latencyMs, provider);\n\t\t},\n\n\t\tasync *stream(messages, invokeOpts): AsyncGenerator<StreamDelta> {\n\t\t\tconst body = toOpenAIRequest(messages, invokeOpts, opts.model, true, opts.bodyExtras);\n\t\t\tconst stream = (await sdk.chat.completions.create(body, {\n\t\t\t\tsignal: invokeOpts?.signal,\n\t\t\t})) as unknown as AsyncIterable<Record<string, unknown>>;\n\t\t\tlet finalUsage: OpenAIUsage | undefined;\n\t\t\tlet finishReason: string | undefined;\n\t\t\tfor await (const chunk of stream) {\n\t\t\t\tconst choices = (\n\t\t\t\t\tchunk as {\n\t\t\t\t\t\tchoices?: ReadonlyArray<{\n\t\t\t\t\t\t\tdelta?: {\n\t\t\t\t\t\t\t\tcontent?: string;\n\t\t\t\t\t\t\t\ttool_calls?: ReadonlyArray<{\n\t\t\t\t\t\t\t\t\tid?: string;\n\t\t\t\t\t\t\t\t\tfunction?: { name?: string; arguments?: string };\n\t\t\t\t\t\t\t\t}>;\n\t\t\t\t\t\t\t\treasoning_content?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tfinish_reason?: string;\n\t\t\t\t\t\t}>;\n\t\t\t\t\t}\n\t\t\t\t).choices;\n\t\t\t\tif (choices) {\n\t\t\t\t\tconst c = choices[0];\n\t\t\t\t\tif (c?.delta?.content) yield { type: \"token\", delta: c.delta.content };\n\t\t\t\t\tif (c?.delta?.reasoning_content)\n\t\t\t\t\t\tyield { type: \"thinking\", delta: c.delta.reasoning_content };\n\t\t\t\t\tif (c?.delta?.tool_calls) {\n\t\t\t\t\t\tfor (const tc of c.delta.tool_calls) {\n\t\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\t\ttype: \"tool-call-delta\",\n\t\t\t\t\t\t\t\tdelta: {\n\t\t\t\t\t\t\t\t\tid: tc.id,\n\t\t\t\t\t\t\t\t\tname: tc.function?.name,\n\t\t\t\t\t\t\t\t\targumentsDelta: tc.function?.arguments,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (c?.finish_reason) finishReason = c.finish_reason;\n\t\t\t\t}\n\t\t\t\tconst u = (chunk as { usage?: OpenAIUsage }).usage;\n\t\t\t\tif (u) {\n\t\t\t\t\tfinalUsage = u;\n\t\t\t\t\tyield { type: \"usage\", usage: mapUsage(u) };\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!finalUsage) {\n\t\t\t\t// No usage emitted — yield nothing; downstream consumers default\n\t\t\t\t// to empty usage via their own fallback.\n\t\t\t}\n\t\t\tyield { type: \"finish\", reason: finishReason ?? \"stop\" };\n\t\t},\n\t};\n}\n","/**\n * `createAdapter` — provider-dispatching factory.\n *\n * One entry point, one config object. Picks the right concrete adapter by\n * `provider`, forwards everything else. Users who want finer control import\n * the concrete adapter directly (`anthropicAdapter`, `openAICompatAdapter`,\n * `googleAdapter`, `dryRunAdapter`, `webllmAdapter`, `chromeNanoAdapter`).\n */\n\nimport { type AnthropicAdapterOptions, anthropicAdapter } from \"../providers/anthropic.js\";\nimport { type DryRunAdapterOptions, dryRunAdapter } from \"../providers/dry-run.js\";\nimport { type FallbackAdapterOptions, fallbackAdapter } from \"../providers/fallback.js\";\nimport { type GoogleAdapterOptions, googleAdapter } from \"../providers/google.js\";\nimport {\n\ttype OpenAICompatAdapterOptions,\n\ttype OpenAICompatPreset,\n\topenAICompatAdapter,\n} from \"../providers/openai-compat.js\";\nimport type { LLMAdapter } from \"./types.js\";\n\nexport type AdapterProvider =\n\t| \"anthropic\"\n\t| OpenAICompatPreset // \"openai\" | \"openrouter\" | \"groq\" | \"ollama\" | \"deepseek\" | \"xai\"\n\t| \"google\"\n\t| \"dry-run\"\n\t| \"fallback\";\n\nexport interface CreateAdapterOptions {\n\tprovider: AdapterProvider;\n\tapiKey?: string;\n\tmodel?: string;\n\tbaseURL?: string;\n\theaders?: Record<string, string>;\n\t/** OpenAI-compat bodyExtras (OpenRouter routing, etc.). */\n\tbodyExtras?: Record<string, unknown>;\n\t/** Provider-specific SDK instance (any of AnthropicSdkLike / OpenAISdkLike / GoogleSdkLike). */\n\tsdk?: unknown;\n\t/** Custom fetch (for tests). */\n\tfetchImpl?: typeof fetch;\n\t/** Extra per-provider options forwarded verbatim. */\n\textras?: Record<string, unknown>;\n}\n\nexport function createAdapter(opts: CreateAdapterOptions): LLMAdapter {\n\tswitch (opts.provider) {\n\t\tcase \"anthropic\": {\n\t\t\tconst a: AnthropicAdapterOptions = {\n\t\t\t\tapiKey: opts.apiKey,\n\t\t\t\tmodel: opts.model,\n\t\t\t\tbaseURL: opts.baseURL,\n\t\t\t\theaders: opts.headers,\n\t\t\t\tsdk: opts.sdk as AnthropicAdapterOptions[\"sdk\"],\n\t\t\t\tfetchImpl: opts.fetchImpl,\n\t\t\t\t...(opts.extras as AnthropicAdapterOptions | undefined),\n\t\t\t};\n\t\t\treturn anthropicAdapter(a);\n\t\t}\n\t\tcase \"google\": {\n\t\t\tconst g: GoogleAdapterOptions = {\n\t\t\t\tapiKey: opts.apiKey,\n\t\t\t\tmodel: opts.model,\n\t\t\t\tbaseURL: opts.baseURL,\n\t\t\t\theaders: opts.headers,\n\t\t\t\tsdk: opts.sdk as GoogleAdapterOptions[\"sdk\"],\n\t\t\t\tfetchImpl: opts.fetchImpl,\n\t\t\t\t...(opts.extras as GoogleAdapterOptions | undefined),\n\t\t\t};\n\t\t\treturn googleAdapter(g);\n\t\t}\n\t\tcase \"dry-run\": {\n\t\t\tconst d: DryRunAdapterOptions = {\n\t\t\t\tmodel: opts.model,\n\t\t\t\t...(opts.extras as DryRunAdapterOptions | undefined),\n\t\t\t};\n\t\t\treturn dryRunAdapter(d);\n\t\t}\n\t\tcase \"fallback\": {\n\t\t\t// `provider`/`model` threaded as labels; `fixtures`/`record`/etc.\n\t\t\t// must come through `extras` since `CreateAdapterOptions` doesn't\n\t\t\t// have dedicated slots for them.\n\t\t\tconst f: FallbackAdapterOptions = {\n\t\t\t\tprovider: opts.provider,\n\t\t\t\tmodel: opts.model,\n\t\t\t\t...(opts.extras as FallbackAdapterOptions | undefined),\n\t\t\t};\n\t\t\treturn fallbackAdapter(f);\n\t\t}\n\t\t// OpenAI-compat presets\n\t\tcase \"openai\":\n\t\tcase \"openrouter\":\n\t\tcase \"groq\":\n\t\tcase \"ollama\":\n\t\tcase \"deepseek\":\n\t\tcase \"xai\": {\n\t\t\tconst c: OpenAICompatAdapterOptions = {\n\t\t\t\tpreset: opts.provider,\n\t\t\t\tapiKey: opts.apiKey,\n\t\t\t\tmodel: opts.model,\n\t\t\t\tbaseURL: opts.baseURL,\n\t\t\t\theaders: opts.headers,\n\t\t\t\tbodyExtras: opts.bodyExtras,\n\t\t\t\tsdk: opts.sdk as OpenAICompatAdapterOptions[\"sdk\"],\n\t\t\t\tfetchImpl: opts.fetchImpl,\n\t\t\t\t...(opts.extras as OpenAICompatAdapterOptions | undefined),\n\t\t\t};\n\t\t\treturn openAICompatAdapter(c);\n\t\t}\n\t\tdefault: {\n\t\t\tconst never: never = opts.provider;\n\t\t\tthrow new Error(`createAdapter: unknown provider: ${String(never)}`);\n\t\t}\n\t}\n}\n","/**\n * Observable adapter wrapper — the \"inverted statistics\" surface.\n *\n * The library emits structured facts (token counts, latency, timestamps)\n * as reactive nodes. Users compose interpretation (pricing, dashboards,\n * telemetry, budget breakers) as derived layers on top.\n */\n\nimport { monotonicNs, type Node, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport { keepalive, type ReactiveLogBundle, reactiveLog } from \"@graphrefly/pure-ts/extra\";\nimport {\n\tadapterWrapper,\n\tadaptInvokeResult,\n\tbuildCallStats,\n\temptyUsageStub,\n\twithLayer,\n} from \"../_internal/wrappers.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n\tStreamDelta,\n\tTokenUsage,\n} from \"./types.js\";\nimport { sumInputTokens, sumOutputTokens } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// CallStatsEvent\n// ---------------------------------------------------------------------------\n\n/** One call's structured statistics — emitted after `invoke()` / `stream()` settles. */\nexport interface CallStatsEvent {\n\t/** `monotonicNs()` at call completion — use for event ordering. */\n\treadonly timestamp: number;\n\t/** `wallClockNs()` at call start — use for human-readable attribution. */\n\treadonly wallClock: number;\n\treadonly provider: string;\n\treadonly model: string;\n\treadonly tier?: string;\n\treadonly usage: TokenUsage;\n\treadonly latencyMs: number;\n\t/** `\"invoke\"` or `\"stream\"`. */\n\treadonly method: \"invoke\" | \"stream\";\n\t/** Populated when the call errored — usage may be zero or partial. */\n\treadonly error?: { readonly type: string; readonly message: string };\n}\n\n// ---------------------------------------------------------------------------\n// AdapterStats bundle\n// ---------------------------------------------------------------------------\n\nexport interface AdapterStats {\n\t/**\n\t * Reactive node for the most-recent call event. Emits `null` initially\n\t * (no calls yet); emits a {@link CallStatsEvent} after each call. Subscribe\n\t * and filter `!= null` if you want a `Node<CallStatsEvent>`.\n\t */\n\treadonly lastCall: Node<CallStatsEvent | null>;\n\t/** Full event log (bounded by `opts.logMax`, default 1000). */\n\treadonly allCalls: ReactiveLogBundle<CallStatsEvent>;\n\t/** Total calls observed since last reset. */\n\treadonly totalCalls: Node<number>;\n\t/** Sum of every input-token class across observed calls. */\n\treadonly totalInputTokens: Node<number>;\n\t/** Sum of every output-token class across observed calls. */\n\treadonly totalOutputTokens: Node<number>;\n\t/** Reset all counters + clear the log. */\n\treset(): void;\n\t/**\n\t * Release the internal keepalive subscriptions on the three counter\n\t * derives (`totalCalls` / `totalInputTokens` / `totalOutputTokens`) so the\n\t * bundle can be GC'd when the caller discards it. Idempotent. Long-lived\n\t * adapter bundles (module-level singletons) can ignore; transient bundles\n\t * (per-request / per-user) should call on teardown.\n\t */\n\tdispose(): void;\n}\n\n// ---------------------------------------------------------------------------\n// observableAdapter\n// ---------------------------------------------------------------------------\n\n/**\n * Wrap any {@link LLMAdapter} with a reactive stats bundle.\n *\n * Implementation (Unit 10 B):\n * - `stats.lastCall` is a `state<CallStatsEvent | null>`.\n * - Counters (`totalCalls` / `totalInputTokens` / `totalOutputTokens`) are\n * **derived views** over `allCalls.entries` — self-maintaining, no manual\n * `.cache + 1 + emit` pattern, visible topology in `describe()`.\n * - `stats.allCalls` is a `reactiveLog<CallStatsEvent>` — bounded, supports\n * `tail(n)` / `slice(start, stop)` for dashboard views.\n * - The wrapped adapter passes DATA through via `adaptInvokeResult`, which\n * uses `onFirstData` internally to guard against re-subscription double-fire\n * and wires `.catch` for Promise-path error recording (Unit 10 A).\n */\nexport function observableAdapter(\n\tinner: LLMAdapter,\n\topts?: { logMax?: number; name?: string },\n): { adapter: LLMAdapter; stats: AdapterStats } {\n\tconst logMax = opts?.logMax ?? 1000;\n\tconst allCalls = reactiveLog<CallStatsEvent>(undefined, {\n\t\tname: opts?.name ? `${opts.name}/stats` : \"adapterStats\",\n\t\tmaxSize: logMax,\n\t});\n\n\tconst lastCall = node<CallStatsEvent | null>([], {\n\t\tname: \"adapterStats/lastCall\",\n\t\tinitial: null,\n\t});\n\n\t// Counters as derived views over the log — self-maintaining (Unit 10 B).\n\t// `initial` seeds them so late subscribers see 0 before any call lands.\n\tconst totalCalls = node<number>(\n\t\t[allCalls.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst entries = data[0] as readonly CallStatsEvent[];\n\t\t\tactions.emit(entries.length);\n\t\t},\n\t\t{ describeKind: \"derived\", name: \"adapterStats/totalCalls\", initial: 0 },\n\t);\n\tconst totalInputTokens = node<number>(\n\t\t[allCalls.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst entries = data[0] as readonly CallStatsEvent[];\n\t\t\tactions.emit(entries.reduce((acc, ev) => acc + sumInputTokens(ev.usage), 0));\n\t\t},\n\t\t{ describeKind: \"derived\", name: \"adapterStats/totalInputTokens\", initial: 0 },\n\t);\n\tconst totalOutputTokens = node<number>(\n\t\t[allCalls.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst entries = data[0] as readonly CallStatsEvent[];\n\t\t\tactions.emit(entries.reduce((acc, ev) => acc + sumOutputTokens(ev.usage), 0));\n\t\t},\n\t\t{ describeKind: \"derived\", name: \"adapterStats/totalOutputTokens\", initial: 0 },\n\t);\n\t// Keepalive — counters track the log whether or not an external subscriber\n\t// is attached, so `.cache` on the counters stays current. Captured as an\n\t// array so `AdapterStats.dispose()` can release them all.\n\tconst unsubKeepalives: Array<() => void> = [\n\t\tkeepalive(totalCalls),\n\t\tkeepalive(totalInputTokens),\n\t\tkeepalive(totalOutputTokens),\n\t];\n\n\tconst record = (ev: CallStatsEvent): void => {\n\t\tallCalls.append(ev);\n\t\tlastCall.emit(ev);\n\t};\n\n\tconst reset = (): void => {\n\t\tallCalls.clear();\n\t\tlastCall.emit(null);\n\t};\n\n\tconst wrap = adapterWrapper(inner, {\n\t\tinvoke(messages, invokeOpts) {\n\t\t\tconst startNs = monotonicNs();\n\t\t\tconst startWallClockNs = wallClockNs();\n\t\t\tconst model = inner.model ?? invokeOpts?.model ?? \"\";\n\t\t\tconst recordResp = (resp: LLMResponse): LLMResponse => {\n\t\t\t\trecord(\n\t\t\t\t\tbuildCallStats({\n\t\t\t\t\t\tprovider: inner.provider,\n\t\t\t\t\t\tmodel: inner.model ?? invokeOpts?.model ?? resp.model ?? \"\",\n\t\t\t\t\t\ttier: invokeOpts?.tier ?? resp.tier,\n\t\t\t\t\t\tusage: resp.usage ?? emptyUsageStub(),\n\t\t\t\t\t\tstartNs,\n\t\t\t\t\t\tstartWallClockNs,\n\t\t\t\t\t\tmethod: \"invoke\",\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn resp;\n\t\t\t};\n\t\t\tconst recordErr = (err: unknown): void => {\n\t\t\t\tconst e = err as Error | undefined;\n\t\t\t\trecord(\n\t\t\t\t\tbuildCallStats({\n\t\t\t\t\t\tprovider: inner.provider,\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\ttier: invokeOpts?.tier,\n\t\t\t\t\t\tusage: emptyUsageStub(),\n\t\t\t\t\t\tstartNs,\n\t\t\t\t\t\tstartWallClockNs,\n\t\t\t\t\t\tmethod: \"invoke\",\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\ttype: e?.name ?? \"Error\",\n\t\t\t\t\t\t\tmessage: e?.message ?? String(err),\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t};\n\t\t\treturn adaptInvokeResult(inner.invoke(messages, invokeOpts), {\n\t\t\t\tonResp: recordResp,\n\t\t\t\tonError: recordErr,\n\t\t\t\tname: \"adapterStats/invokeTap\",\n\t\t\t});\n\t\t},\n\n\t\tasync *stream(messages, invokeOpts) {\n\t\t\tconst startNs = monotonicNs();\n\t\t\tconst startWallClockNs = wallClockNs();\n\t\t\tconst model = inner.model ?? invokeOpts?.model ?? \"\";\n\t\t\tlet finalUsage: TokenUsage | undefined;\n\t\t\ttry {\n\t\t\t\tfor await (const delta of inner.stream(messages, invokeOpts)) {\n\t\t\t\t\tif (delta.type === \"usage\") finalUsage = delta.usage;\n\t\t\t\t\tyield delta;\n\t\t\t\t}\n\t\t\t\trecord(\n\t\t\t\t\tbuildCallStats({\n\t\t\t\t\t\tprovider: inner.provider,\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\ttier: invokeOpts?.tier,\n\t\t\t\t\t\tusage: finalUsage ?? emptyUsageStub(),\n\t\t\t\t\t\tstartNs,\n\t\t\t\t\t\tstartWallClockNs,\n\t\t\t\t\t\tmethod: \"stream\",\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t} catch (err) {\n\t\t\t\tconst e = err as Error | undefined;\n\t\t\t\trecord(\n\t\t\t\t\tbuildCallStats({\n\t\t\t\t\t\tprovider: inner.provider,\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\ttier: invokeOpts?.tier,\n\t\t\t\t\t\tusage: finalUsage ?? emptyUsageStub(),\n\t\t\t\t\t\tstartNs,\n\t\t\t\t\t\tstartWallClockNs,\n\t\t\t\t\t\tmethod: \"stream\",\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\ttype: e?.name ?? \"Error\",\n\t\t\t\t\t\t\tmessage: e?.message ?? String(err),\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t},\n\t});\n\n\twithLayer(wrap, \"observableAdapter\", inner);\n\n\tlet disposed = false;\n\tconst dispose = (): void => {\n\t\tif (disposed) return;\n\t\tdisposed = true;\n\t\tfor (const fn of unsubKeepalives) fn();\n\t\tunsubKeepalives.length = 0;\n\t};\n\n\tconst stats: AdapterStats = {\n\t\tlastCall,\n\t\tallCalls,\n\t\ttotalCalls,\n\t\ttotalInputTokens,\n\t\ttotalOutputTokens,\n\t\treset,\n\t\tdispose,\n\t};\n\n\treturn { adapter: wrap, stats };\n}\n\nexport type { ChatMessage, LLMAdapter, LLMInvokeOptions, LLMResponse, StreamDelta, TokenUsage };\n","/**\n * Core types for LLM adapters (roadmap §9.3d).\n *\n * The library defines the shape of:\n * - Token usage (raw, disaggregated; user decides how to combine)\n * - Responses and streaming deltas\n * - The `LLMAdapter` protocol (reactive-friendly via `NodeInput`)\n * - Chat, tool, and invocation option shapes\n *\n * It ships **zero model data**. Pricing and capability registries are\n * user-populated (see `pricing.ts` and `capabilities.ts`).\n */\n\nimport type { Node } from \"@graphrefly/pure-ts/core\";\nimport type { NodeInput } from \"@graphrefly/pure-ts/extra\";\n\n// ---------------------------------------------------------------------------\n// Token usage — raw, disaggregated, extensible\n// ---------------------------------------------------------------------------\n\n/**\n * Input token classes.\n *\n * Every provider's native usage object maps into this shape without loss.\n * All fields except `regular` are optional — providers that don't expose\n * the class simply leave it undefined.\n */\nexport interface InputTokens {\n\t/** Uncached regular input tokens (cache miss or never-cached). */\n\tregular: number;\n\t/** Read from prompt cache (all TTLs — providers don't split reads by TTL today). */\n\tcacheRead?: number;\n\t/** Written to cache with 5-min TTL (Anthropic `ephemeral_5m_input_tokens`). */\n\tcacheWrite5m?: number;\n\t/** Written to cache with 1-hour TTL (Anthropic `ephemeral_1h_input_tokens`). */\n\tcacheWrite1h?: number;\n\t/** Written to cache with other/unspecified TTL (Gemini explicit caches). */\n\tcacheWriteOther?: number;\n\t/** Audio input tokens (OpenAI realtime, Gemini audio). */\n\taudio?: number;\n\t/** Image input tokens (Gemini per-modality). */\n\timage?: number;\n\t/** Video input tokens (Gemini per-modality). */\n\tvideo?: number;\n\t/** Tool-use result tokens fed back to the model (Gemini `toolUsePromptTokenCount`). */\n\ttoolUse?: number;\n\t/** Provider-specific classes not covered above. Open-ended by design. */\n\textensions?: Record<string, number>;\n}\n\n/** Output token classes. */\nexport interface OutputTokens {\n\t/** Regular generated output (non-reasoning, non-audio). */\n\tregular: number;\n\t/** Reasoning / thinking tokens (OpenAI o-series, Gemini thoughts, Grok reasoning). */\n\treasoning?: number;\n\t/** Audio output tokens. */\n\taudio?: number;\n\t/** Predicted-output tokens accepted (OpenAI predictions API). */\n\tpredictionAccepted?: number;\n\t/** Predicted-output tokens rejected (still billed at output rate). */\n\tpredictionRejected?: number;\n\textensions?: Record<string, number>;\n}\n\n/** Per-call token usage in canonical shape. No pricing, no interpretation. */\nexport interface TokenUsage {\n\tinput: InputTokens;\n\toutput: OutputTokens;\n\t/**\n\t * Per-call non-token costs (web-search requests, tool invocations, cache\n\t * storage-hours, etc.). Units are domain-specific — pricing functions\n\t * interpret them via `ModelPricing.auxiliary`.\n\t */\n\tauxiliary?: Record<string, number>;\n\t/**\n\t * Raw provider usage object, unmodified. Escape hatch for anything the\n\t * canonical shape doesn't model.\n\t */\n\traw?: unknown;\n}\n\n/** Sum of every input-token class. Helper for pricing + budget gating. */\nexport function sumInputTokens(u: TokenUsage): number {\n\tconst i = u.input;\n\tconst base =\n\t\ti.regular +\n\t\t(i.cacheRead ?? 0) +\n\t\t(i.cacheWrite5m ?? 0) +\n\t\t(i.cacheWrite1h ?? 0) +\n\t\t(i.cacheWriteOther ?? 0) +\n\t\t(i.audio ?? 0) +\n\t\t(i.image ?? 0) +\n\t\t(i.video ?? 0) +\n\t\t(i.toolUse ?? 0);\n\tif (!i.extensions) return base;\n\tlet ext = 0;\n\tfor (const v of Object.values(i.extensions)) ext += v;\n\treturn base + ext;\n}\n\n/** Sum of every output-token class. */\nexport function sumOutputTokens(u: TokenUsage): number {\n\tconst o = u.output;\n\tconst base =\n\t\to.regular +\n\t\t(o.reasoning ?? 0) +\n\t\t(o.audio ?? 0) +\n\t\t(o.predictionAccepted ?? 0) +\n\t\t(o.predictionRejected ?? 0);\n\tif (!o.extensions) return base;\n\tlet ext = 0;\n\tfor (const v of Object.values(o.extensions)) ext += v;\n\treturn base + ext;\n}\n\n/** Empty `TokenUsage` — useful as a default / starting point. */\nexport function emptyUsage(): TokenUsage {\n\treturn { input: { regular: 0 }, output: { regular: 0 } };\n}\n\n// ---------------------------------------------------------------------------\n// Chat message / tool types (single source of truth for the AI layer)\n// ---------------------------------------------------------------------------\n\n/** A single chat message in a conversation. */\nexport type ChatMessage = {\n\treadonly role: \"system\" | \"user\" | \"assistant\" | \"tool\";\n\treadonly content: string;\n\treadonly name?: string;\n\treadonly toolCallId?: string;\n\treadonly toolCalls?: readonly ToolCall[];\n\treadonly metadata?: Record<string, unknown>;\n};\n\n/** A tool invocation request from an LLM. */\nexport type ToolCall = {\n\treadonly id: string;\n\treadonly name: string;\n\treadonly arguments: Record<string, unknown>;\n};\n\n/** A tool definition for LLM consumption. */\nexport type ToolDefinition = {\n\treadonly name: string;\n\treadonly description: string;\n\treadonly parameters: Record<string, unknown>; // JSON Schema\n\t/**\n\t * Handler invoked when the LLM requests this tool.\n\t *\n\t * The optional `opts.signal` fires when the reactive surface that owns\n\t * this invocation is torn down (e.g. the agent's `switchMap` over\n\t * `toolCalls` superseded with a fresh batch, the agent was aborted, or\n\t * the parent graph destroyed). Signal-aware handlers should thread it\n\t * into `fetch(url, {signal})`, child-process kill, DB cancel, etc., so\n\t * in-flight side effects actually stop. Handlers that ignore the\n\t * signal still work — but their work continues to completion regardless\n\t * of supersede.\n\t */\n\treadonly handler: (\n\t\targs: Record<string, unknown>,\n\t\topts?: { signal?: AbortSignal },\n\t) => NodeInput<unknown>;\n\t/**\n\t * V0 version of the backing node at tool-definition-creation time.\n\t * Snapshot — re-create the tool definition to refresh.\n\t */\n\treadonly version?: { id: string; version: number };\n};\n\n// ---------------------------------------------------------------------------\n// Response / streaming\n// ---------------------------------------------------------------------------\n\n/** The response from an LLM invocation. */\nexport interface LLMResponse {\n\treadonly content: string;\n\treadonly toolCalls?: readonly ToolCall[];\n\t/**\n\t * Token usage. Optional — provider adapters should always populate it, but\n\t * test mocks and adapter middlewares that synthesize responses can omit it.\n\t * Downstream consumers that compute cost should default to {@link emptyUsage}.\n\t */\n\treadonly usage?: TokenUsage;\n\treadonly finishReason?: string;\n\treadonly latencyMs?: number;\n\treadonly model?: string;\n\treadonly provider?: string;\n\t/** Service tier the call was served with (standard / batch / flex / priority). */\n\treadonly tier?: string;\n\treadonly metadata?: Record<string, unknown>;\n}\n\n/**\n * Adapter-facing incremental stream event.\n *\n * Provider adapters emit these; higher-level surfaces (`streamingPromptNode`,\n * `agentLoop`) assemble them into consumer-facing `StreamChunk` with their own\n * `source`/`accumulated`/`index` context.\n *\n * **Shape rationale — why object tagged-union vs. the framework `[TYPE, data]`\n * tuple?** `StreamDelta` is an *application-layer event payload* that flows\n * inside a single framework `DATA` message, one abstraction level above the\n * reactive protocol. The framework's `[Type, Data?]` tuple (DIRTY / DATA /\n * RESOLVED / COMPLETE / ERROR) is the protocol message form delivered through\n * `subscribe`. Using the protocol form here would force us to invent new\n * framework-level symbols (`TOKEN`, `USAGE`, etc.) that leak into user code,\n * and TypeScript discriminated-union exhaustiveness works much better with\n * objects than tuples. Object-tagged unions match the idiomatic JS/TS\n * convention for discriminated events (Redux actions, DOM events).\n */\nexport type StreamDelta =\n\t| { readonly type: \"token\"; readonly delta: string }\n\t| {\n\t\t\treadonly type: \"tool-call-delta\";\n\t\t\treadonly delta: {\n\t\t\t\treadonly id?: string;\n\t\t\t\treadonly name?: string;\n\t\t\t\treadonly argumentsDelta?: string;\n\t\t\t};\n\t }\n\t| { readonly type: \"thinking\"; readonly delta: string }\n\t| { readonly type: \"usage\"; readonly usage: TokenUsage }\n\t| { readonly type: \"finish\"; readonly reason: string };\n\n// ---------------------------------------------------------------------------\n// Invocation options\n// ---------------------------------------------------------------------------\n\n/** Options passed to `invoke()` / `stream()`. */\nexport interface LLMInvokeOptions {\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\t/** Budget for reasoning/thinking tokens, if the model supports it. */\n\tmaxReasoningTokens?: number;\n\ttools?: readonly ToolDefinition[];\n\tsystemPrompt?: string;\n\t/** Hint the adapter to cache the prompt. TTL values depend on provider. */\n\tcacheHint?: { ttl?: \"5m\" | \"1h\" | string; minTokens?: number };\n\t/** Service tier: \"standard\" | \"batch\" | \"flex\" | \"priority\" | provider-custom. */\n\ttier?: string;\n\tsignal?: AbortSignal;\n\t/**\n\t * Provider-specific passthrough — merged into the native request body.\n\t * Escape hatch for features not yet in the canonical options.\n\t */\n\tproviderExtras?: Record<string, unknown>;\n\t/**\n\t * Open-ended per-call context threaded to cache / fallback key functions.\n\t * Callers who want to shard caches by tenant, session, feature flag, or\n\t * any other dimension populate this and supply a custom `keyFn` that\n\t * incorporates it. Not sent to providers — stripped from canonical key\n\t * hashing when no custom `keyFn` is supplied. Type is `unknown` to avoid\n\t * prescribing a shape; callers pick their own.\n\t */\n\tkeyContext?: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// LLMAdapter protocol\n// ---------------------------------------------------------------------------\n\n/**\n * Provider-agnostic LLM adapter (spec §5.10 compliant).\n *\n * - `invoke()` returns a `NodeInput<LLMResponse>` — the caller bridges to\n * reactive via `fromAny(...)`. Adapter implementations may return a\n * Promise (simplest), a Node (reactive), or a plain value (testing).\n * - `stream()` returns `AsyncIterable<StreamDelta>` — the terminal delta of\n * type `\"usage\"` carries the final `TokenUsage` for the streamed call.\n */\nexport interface LLMAdapter {\n\treadonly provider: string;\n\treadonly model?: string;\n\tinvoke(messages: readonly ChatMessage[], opts?: LLMInvokeOptions): NodeInput<LLMResponse>;\n\tstream(messages: readonly ChatMessage[], opts?: LLMInvokeOptions): AsyncIterable<StreamDelta>;\n\t/** Optional capability lookup; typically delegates to a `CapabilitiesRegistry`. */\n\tcapabilities?(model?: string): import(\"./capabilities.js\").ModelCapabilities | undefined;\n\t/**\n\t * DS-14.5 / AB-1 — honoring `opts.signal: AbortSignal` end-to-end is a\n\t * **hard adapter contract**, not an opt-in capability. Every adapter MUST\n\t * thread `opts.signal` into its underlying I/O (`fetch` request,\n\t * child-process kill, DB cancel) so a mid-call abort cancels the work and\n\t * surfaces as a rejection / thrown error. The prior optional\n\t * `abortCapable?: boolean` flag (Lock 3.C / QA D3) was removed pre-1.0:\n\t * the capability-flag escape hatch silently permitted token burn-through\n\t * past `valve`-close / `switchMap`-supersede / budget exhaustion. There is\n\t * no longer a flag to set and no dev-mode warning — abort just works.\n\t */\n}\n\n/** Discriminator for downstream type guards. */\nexport function isLLMAdapter(x: unknown): x is LLMAdapter {\n\tif (x == null || typeof x !== \"object\") return false;\n\tconst a = x as Partial<LLMAdapter>;\n\treturn (\n\t\ttypeof a.provider === \"string\" &&\n\t\ttypeof a.invoke === \"function\" &&\n\t\ttypeof a.stream === \"function\"\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Public re-export surface\n// ---------------------------------------------------------------------------\n\nexport type { Node, NodeInput };\n","/**\n * Pluggable pricing for LLM adapters.\n *\n * The library ships the **shape** (types + computation helpers + registry\n * factory) and **zero model data**. Users populate a `PricingRegistry` with\n * the prices for the models they use — either by hand, from a curated table,\n * or by importing a third-party dataset (litellm JSON, etc.).\n *\n * Pricing is a pure function of raw `TokenUsage`. The library does not\n * know current prices, regional rates, tier thresholds, or promotional\n * discounts — those are all user domain.\n */\n\nimport type { TokenUsage } from \"./types.js\";\nimport { sumInputTokens } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Rate shape\n// ---------------------------------------------------------------------------\n\n/**\n * A rate per 1M tokens. Supports threshold-based tiering (Anthropic\n * long-context >200K, Gemini >200K) via optional `thresholdTokens` +\n * `pricePerMillionAbove`.\n *\n * `total input tokens` (sum of every input class) is the axis the threshold\n * applies to — matches how Anthropic and Gemini measure it.\n */\nexport interface TieredRate {\n\tpricePerMillion: number;\n\tthresholdTokens?: number;\n\tpricePerMillionAbove?: number;\n}\n\n/** Shorthand: a plain `number` stands for `{pricePerMillion: n}`. */\nexport type Rate = TieredRate | number;\n\nfunction rateAt(rate: Rate | undefined, totalInput: number): number {\n\tif (rate == null) return 0;\n\tif (typeof rate === \"number\") return rate;\n\tif (\n\t\trate.thresholdTokens != null &&\n\t\trate.pricePerMillionAbove != null &&\n\t\ttotalInput > rate.thresholdTokens\n\t) {\n\t\treturn rate.pricePerMillionAbove;\n\t}\n\treturn rate.pricePerMillion;\n}\n\n// ---------------------------------------------------------------------------\n// ModelPricing\n// ---------------------------------------------------------------------------\n\n/** USD-per-1M rates per token class. All fields optional. */\nexport interface ModelPricing {\n\tinput?: {\n\t\tregular?: Rate;\n\t\tcacheRead?: Rate;\n\t\tcacheWrite5m?: Rate;\n\t\tcacheWrite1h?: Rate;\n\t\tcacheWriteOther?: Rate;\n\t\taudio?: Rate;\n\t\timage?: Rate;\n\t\tvideo?: Rate;\n\t\ttoolUse?: Rate;\n\t\textensions?: Record<string, Rate>;\n\t};\n\toutput?: {\n\t\tregular?: Rate;\n\t\treasoning?: Rate;\n\t\taudio?: Rate;\n\t\tpredictionAccepted?: Rate;\n\t\tpredictionRejected?: Rate;\n\t\textensions?: Record<string, Rate>;\n\t};\n\t/**\n\t * Per-unit costs for non-token axes. Values are USD per unit; units\n\t * match `TokenUsage.auxiliary` keys (e.g. `webSearchRequests`, `cacheStorageHours`).\n\t */\n\tauxiliary?: Record<string, number>;\n\t/**\n\t * Service-tier multipliers. Applied to the summed per-class price.\n\t * E.g. `{ batch: 0.5, flex: 0.5, priority: 1.25 }`. Default (no tier or\n\t * tier not present in the map): multiplier = 1.\n\t */\n\ttierMultipliers?: Record<string, number>;\n\t/** Currency code (ISO 4217). Defaults to \"USD\" when constructed via helpers. */\n\tcurrency: string;\n}\n\n// ---------------------------------------------------------------------------\n// Price breakdown\n// ---------------------------------------------------------------------------\n\n/** Result of computing a price from usage + pricing. */\nexport interface PriceBreakdown {\n\t/** Total charge in `currency`. */\n\ttotal: number;\n\tcurrency: string;\n\t/**\n\t * Optional per-class subtotals. Keys are dot-separated paths like\n\t * `\"input.regular\"`, `\"output.reasoning\"`, `\"auxiliary.webSearchRequests\"`.\n\t */\n\tbreakdown?: Record<string, number>;\n}\n\n/** Zero-charge breakdown — returned when no pricing is available for a model. */\nexport function zeroPrice(currency = \"USD\"): PriceBreakdown {\n\treturn { total: 0, currency };\n}\n\n// ---------------------------------------------------------------------------\n// computePrice — the math\n// ---------------------------------------------------------------------------\n\n/**\n * Compute price from a usage object + model pricing.\n *\n * - Tier-threshold math uses `sumInputTokens(usage)` as the axis.\n * - Service tier (`opts.tier`) multiplies the final total via `tierMultipliers`.\n * - Each token class is priced independently using the matching `Rate` lookup.\n * - `breakdown` is populated when `opts.withBreakdown = true` (default false\n * to keep hot-path allocations low).\n */\nexport function computePrice(\n\tusage: TokenUsage,\n\tpricing: ModelPricing,\n\topts?: { tier?: string; withBreakdown?: boolean },\n): PriceBreakdown {\n\tconst totalInput = sumInputTokens(usage);\n\tconst currency = pricing.currency ?? \"USD\";\n\tconst withBreakdown = opts?.withBreakdown === true;\n\tconst breakdown: Record<string, number> = withBreakdown ? {} : (null as never);\n\n\tlet total = 0;\n\n\tconst addLine = (key: string, tokens: number, rate: Rate | undefined): void => {\n\t\tif (!tokens || rate == null) return;\n\t\tconst rateUsd = rateAt(rate, totalInput);\n\t\tconst line = (tokens * rateUsd) / 1_000_000;\n\t\ttotal += line;\n\t\tif (withBreakdown) breakdown[key] = (breakdown[key] ?? 0) + line;\n\t};\n\n\t// Input classes\n\tconst i = usage.input;\n\tconst pi = pricing.input;\n\tif (pi) {\n\t\taddLine(\"input.regular\", i.regular, pi.regular);\n\t\taddLine(\"input.cacheRead\", i.cacheRead ?? 0, pi.cacheRead);\n\t\taddLine(\"input.cacheWrite5m\", i.cacheWrite5m ?? 0, pi.cacheWrite5m);\n\t\taddLine(\"input.cacheWrite1h\", i.cacheWrite1h ?? 0, pi.cacheWrite1h);\n\t\taddLine(\"input.cacheWriteOther\", i.cacheWriteOther ?? 0, pi.cacheWriteOther);\n\t\taddLine(\"input.audio\", i.audio ?? 0, pi.audio);\n\t\taddLine(\"input.image\", i.image ?? 0, pi.image);\n\t\taddLine(\"input.video\", i.video ?? 0, pi.video);\n\t\taddLine(\"input.toolUse\", i.toolUse ?? 0, pi.toolUse);\n\t\tif (i.extensions && pi.extensions) {\n\t\t\tfor (const [k, v] of Object.entries(i.extensions)) {\n\t\t\t\taddLine(`input.ext.${k}`, v, pi.extensions[k]);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Output classes\n\tconst o = usage.output;\n\tconst po = pricing.output;\n\tif (po) {\n\t\taddLine(\"output.regular\", o.regular, po.regular);\n\t\taddLine(\"output.reasoning\", o.reasoning ?? 0, po.reasoning);\n\t\taddLine(\"output.audio\", o.audio ?? 0, po.audio);\n\t\taddLine(\"output.predictionAccepted\", o.predictionAccepted ?? 0, po.predictionAccepted);\n\t\taddLine(\"output.predictionRejected\", o.predictionRejected ?? 0, po.predictionRejected);\n\t\tif (o.extensions && po.extensions) {\n\t\t\tfor (const [k, v] of Object.entries(o.extensions)) {\n\t\t\t\taddLine(`output.ext.${k}`, v, po.extensions[k]);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Service-tier multiplier applies to token costs only. Auxiliary costs\n\t// (per-request web-search fees, cache storage-hours, etc.) are typically\n\t// priced flat regardless of tier — e.g., Anthropic batch discount applies\n\t// to input/output tokens but NOT to web_search_requests. Apply the\n\t// multiplier to the token total before adding auxiliary lines.\n\tconst tier = opts?.tier;\n\tif (tier && pricing.tierMultipliers) {\n\t\tconst mult = pricing.tierMultipliers[tier];\n\t\tif (mult != null) {\n\t\t\ttotal *= mult;\n\t\t\tif (withBreakdown) {\n\t\t\t\tfor (const k of Object.keys(breakdown)) breakdown[k] *= mult;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Auxiliary (per-unit, not per-million; not tier-multiplied)\n\tconst aux = usage.auxiliary;\n\tconst paux = pricing.auxiliary;\n\tif (aux && paux) {\n\t\tfor (const [k, units] of Object.entries(aux)) {\n\t\t\tconst rate = paux[k];\n\t\t\tif (rate == null || !units) continue;\n\t\t\tconst line = units * rate;\n\t\t\ttotal += line;\n\t\t\tif (withBreakdown) breakdown[`auxiliary.${k}`] = line;\n\t\t}\n\t}\n\n\treturn withBreakdown ? { total, currency, breakdown } : { total, currency };\n}\n\n// ---------------------------------------------------------------------------\n// PricingFn\n// ---------------------------------------------------------------------------\n\n/** Pure function: given usage + call context, produce a price. */\nexport type PricingFn = (\n\tusage: TokenUsage,\n\tctx: { model: string; provider: string; tier?: string; withBreakdown?: boolean },\n) => PriceBreakdown;\n\n// ---------------------------------------------------------------------------\n// PricingRegistry\n// ---------------------------------------------------------------------------\n\n/**\n * A keyed store of `ModelPricing`. Users populate it at app startup.\n * The library ships the factory and zero data.\n *\n * Keys are `(provider, model)` pairs. Lookup attempts exact match first,\n * then longest-prefix match on model (e.g. `\"claude-sonnet-4-6\"` matches a\n * stored `\"claude-sonnet-4-6\"` entry when looking up\n * `\"claude-sonnet-4-6-20260401\"`).\n *\n * **Prefix-match footgun:** a registered `\"gemini-1\"` will also match a\n * lookup for `\"gemini-1.5-pro\"` (since `\"gemini-1.5-pro\".startsWith(\"gemini-1\")`\n * is true). Longest-match tie-breaking mitigates most cases, but when\n * registering a short family-prefix alongside versioned descendants, make sure\n * the versioned entry is present — otherwise the family prefix wins. Best\n * practice: register exact versioned model ids; use short family aliases\n * sparingly and only when all version variants share one pricing schedule.\n */\nexport interface PricingRegistry {\n\tlookup(provider: string, model: string): ModelPricing | undefined;\n\tregister(provider: string, model: string, pricing: ModelPricing): void;\n\t/** Remove a model's entry; returns `true` if it existed. */\n\tremove(provider: string, model: string): boolean;\n\t/** Enumerate all entries (for debugging / dump). */\n\tentries(): IterableIterator<[string, string, ModelPricing]>;\n}\n\nfunction registryKey(provider: string, model: string): string {\n\treturn `${provider}::${model}`;\n}\n\n/** Create a fresh `PricingRegistry`. Optionally seed with entries. */\nexport function createPricingRegistry(\n\tinitial?: ReadonlyArray<readonly [provider: string, model: string, pricing: ModelPricing]>,\n): PricingRegistry {\n\tconst map = new Map<string, { provider: string; model: string; pricing: ModelPricing }>();\n\tconst indexByProvider = new Map<string, Set<string>>();\n\n\tconst register = (provider: string, model: string, pricing: ModelPricing): void => {\n\t\tmap.set(registryKey(provider, model), { provider, model, pricing });\n\t\tlet models = indexByProvider.get(provider);\n\t\tif (!models) {\n\t\t\tmodels = new Set();\n\t\t\tindexByProvider.set(provider, models);\n\t\t}\n\t\tmodels.add(model);\n\t};\n\n\tif (initial) {\n\t\tfor (const [p, m, pricing] of initial) register(p, m, pricing);\n\t}\n\n\treturn {\n\t\tregister,\n\t\tlookup(provider, model) {\n\t\t\tconst exact = map.get(registryKey(provider, model));\n\t\t\tif (exact) return exact.pricing;\n\t\t\t// Prefix fallback within provider.\n\t\t\tconst models = indexByProvider.get(provider);\n\t\t\tif (!models) return undefined;\n\t\t\t// Pick the longest prefix match for stability.\n\t\t\tlet best: { key: string; pricing: ModelPricing } | undefined;\n\t\t\tfor (const candidate of models) {\n\t\t\t\tif (model.startsWith(candidate)) {\n\t\t\t\t\tif (!best || candidate.length > best.key.length) {\n\t\t\t\t\t\tconst entry = map.get(registryKey(provider, candidate));\n\t\t\t\t\t\tif (entry) best = { key: candidate, pricing: entry.pricing };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn best?.pricing;\n\t\t},\n\t\tremove(provider, model) {\n\t\t\tconst existed = map.delete(registryKey(provider, model));\n\t\t\tif (existed) {\n\t\t\t\tconst models = indexByProvider.get(provider);\n\t\t\t\tmodels?.delete(model);\n\t\t\t\tif (models && models.size === 0) indexByProvider.delete(provider);\n\t\t\t}\n\t\t\treturn existed;\n\t\t},\n\t\tentries(): IterableIterator<[string, string, ModelPricing]> {\n\t\t\tconst iter = map.values();\n\t\t\treturn (function* () {\n\t\t\t\tfor (const { provider, model, pricing } of iter) {\n\t\t\t\t\tyield [provider, model, pricing];\n\t\t\t\t}\n\t\t\t})();\n\t\t},\n\t};\n}\n\n/**\n * Build a `PricingFn` from a `PricingRegistry`. If no entry matches, returns\n * `{ total: 0, currency: \"USD\" }` (never throws). Callers who need \"unknown\n * model\" failures can compose their own `PricingFn`.\n */\nexport function registryPricing(registry: PricingRegistry, defaultCurrency = \"USD\"): PricingFn {\n\treturn (usage, ctx) => {\n\t\tconst pricing = registry.lookup(ctx.provider, ctx.model);\n\t\tif (!pricing) return zeroPrice(defaultCurrency);\n\t\treturn computePrice(usage, pricing, { tier: ctx.tier, withBreakdown: ctx.withBreakdown });\n\t};\n}\n\n/** Compose multiple `PricingFn`s — first non-zero wins. Useful for registry layering. */\nexport function composePricing(...fns: readonly PricingFn[]): PricingFn {\n\treturn (usage, ctx) => {\n\t\tfor (const fn of fns) {\n\t\t\tconst p = fn(usage, ctx);\n\t\t\tif (p.total !== 0) return p;\n\t\t}\n\t\treturn fns.length > 0 ? fns[0](usage, ctx) : zeroPrice();\n\t};\n}\n\n/**\n * Convenience: compute a {@link PriceBreakdown} directly from a\n * {@link import(\"./capabilities.js\").ModelCapabilities} object + usage.\n *\n * When callers look up capabilities themselves (via\n * `capabilitiesRegistry.lookup(...)` or `adapter.capabilities?.(model)`),\n * this helper skips the pricing-registry round-trip and computes the price\n * from `capabilities.pricing` directly.\n *\n * Returns `zeroPrice()` when `capabilities.pricing` is undefined — never throws.\n *\n * @param capabilities - Model capabilities object (`capabilities.pricing` may be absent).\n * @param usage - Per-call usage to price.\n * @param opts - Pass-through to {@link computePrice}.\n *\n * @example\n * ```ts\n * const cap = registry.lookup(\"anthropic\", \"claude-sonnet-4-6\");\n * const price = pricingFor(cap, resp.usage, { tier: \"batch\", withBreakdown: true });\n * ```\n *\n * @category ai\n */\nexport function pricingFor(\n\tcapabilities: import(\"./capabilities.js\").ModelCapabilities | undefined,\n\tusage: TokenUsage,\n\topts?: { tier?: string; withBreakdown?: boolean },\n): PriceBreakdown {\n\tif (!capabilities?.pricing) return zeroPrice();\n\treturn computePrice(usage, capabilities.pricing, opts);\n}\n","/**\n * `withBreaker` — circuit-breaker middleware for LLM adapters.\n *\n * Reuses the library's existing `circuitBreaker` primitive from\n * `extra/resilience.ts`. When the breaker is open, calls throw\n * `CircuitOpenError` instead of hitting the provider.\n */\n\nimport { fromAny } from \"@graphrefly/pure-ts/extra\";\nimport { firstValueFrom } from \"../../../../base/sources/settled.js\";\nimport {\n\ttype CircuitBreaker,\n\ttype CircuitBreakerOptions,\n\tCircuitOpenError,\n\tcircuitBreaker,\n} from \"../../../../utils/resilience/index.js\";\nimport { adapterWrapper, withLayer } from \"../_internal/wrappers.js\";\nimport type { LLMAdapter, LLMResponse, StreamDelta } from \"../core/types.js\";\n\nexport interface WithBreakerOptions extends CircuitBreakerOptions {\n\t/**\n\t * Optional external breaker — pass a shared instance to wire the same\n\t * breaker across multiple adapters (e.g. all tiers of a `cascadingLlmAdapter`).\n\t */\n\tbreaker?: CircuitBreaker;\n}\n\nexport function withLLMBreaker(\n\tinner: LLMAdapter,\n\topts: WithBreakerOptions = {},\n): { adapter: LLMAdapter; breaker: CircuitBreaker } {\n\tconst breaker = opts.breaker ?? circuitBreaker(opts);\n\n\tconst adapter: LLMAdapter = adapterWrapper(inner, {\n\t\tasync invoke(messages, invokeOpts): Promise<LLMResponse> {\n\t\t\tif (!breaker.canExecute()) throw new CircuitOpenError();\n\t\t\ttry {\n\t\t\t\tconst resp = await firstValueFrom(fromAny(inner.invoke(messages, invokeOpts)));\n\t\t\t\tbreaker.recordSuccess();\n\t\t\t\treturn resp;\n\t\t\t} catch (err) {\n\t\t\t\tbreaker.recordFailure(err);\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t},\n\n\t\tasync *stream(messages, invokeOpts): AsyncGenerator<StreamDelta> {\n\t\t\tif (!breaker.canExecute()) throw new CircuitOpenError();\n\t\t\ttry {\n\t\t\t\tfor await (const d of inner.stream(messages, invokeOpts)) yield d;\n\t\t\t\tbreaker.recordSuccess();\n\t\t\t} catch (err) {\n\t\t\t\tbreaker.recordFailure(err);\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t},\n\t});\n\twithLayer(adapter, \"withLLMBreaker\", inner);\n\n\treturn { adapter, breaker };\n}\n\nexport { CircuitOpenError };\n","/**\n * Retry — re-attempt a node on terminal failure.\n *\n * Two modes selected by the type of `input`:\n * - **Source mode** (`Node<T>`): resubscribes the same node after each ERROR.\n * Upstream must be `resubscribable: true` or retries are silent no-ops.\n * - **Factory mode** (`() => Node<T>`): builds a fresh node per attempt.\n *\n * Shared with `circuitBreaker` / `rateLimiter`: `NodeOrValue<RetryOptions>`\n * lets callers swap retry config reactively (re-validates on each attempt).\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tDIRTY,\n\tERROR,\n\tfactoryTag,\n\ttype Message,\n\ttype Node,\n\tnode,\n\tRESOLVED,\n\tResettableTimer,\n} from \"@graphrefly/pure-ts/core\";\nimport { coerceDelayNs, isNode, msgVal, type NodeOrValue, operatorOpts } from \"./_internal.js\";\nimport {\n\ttype BackoffPreset,\n\ttype BackoffStrategy,\n\tNS_PER_MS,\n\tresolveBackoffPreset,\n} from \"./backoff.js\";\nimport type { StatusValue } from \"./status.js\";\n\n/**\n * Lifecycle-shaped state companion emitted by {@link retry} (DS-13.5.B,\n * locked 2026-05-01). Tracks the retry state machine's current status,\n * the attempt counter, and the last scheduled delay (null before the\n * first retry).\n *\n * @category extra/resilience\n */\nexport interface RetryState {\n\tstatus: StatusValue;\n\tattempt: number;\n\tlastDelay_ns: number | null;\n}\n\n/**\n * Bundle returned by {@link retry}: the retry-wrapped output node and its\n * lifecycle state companion. Pre-1.0 break vs the prior `Node<T>` return.\n *\n * **Single-subscriber / pipeline-only contract (DS-13.5.B QA, N1, 2026-05-03).**\n * The `retryState` companion is allocated once at factory time and shared\n * across all subscribers to `node`. With one subscriber (the typical use\n * case — wire `node` into your downstream chain, optionally observe\n * `retryState` separately) the companion reflects a coherent timeline.\n * With **two or more subscribers** to `node`, each subscriber re-runs the\n * producer body and writes into the same `retryState`, including\n * `publish(\"pending\")` resets that can clobber an in-flight machine's\n * `running`/`paused` state. Don't fan out `node` to multiple subscribers\n * and rely on `retryState` accuracy unless you use\n * {@link keepalive} / `share`-style consolidation.\n *\n * @category extra/resilience\n */\nexport interface RetryBundle<T> {\n\tnode: Node<T>;\n\tretryState: Node<RetryState>;\n}\n\nexport type RetryOptions = {\n\t/**\n\t * Max retry attempts after each terminal `ERROR` (not counting the first failure).\n\t *\n\t * **Required when `backoff` is set.** Pass `Infinity` to opt in to unbounded retries\n\t * — the explicit value rules out the silent-infinite-budget footgun (a flaky provider\n\t * + exponential backoff + omitted `count` would previously default to ~2.1B retries).\n\t */\n\tcount?: number;\n\t/** Delay between attempts; strategies use **nanoseconds**. */\n\tbackoff?: BackoffStrategy | BackoffPreset;\n\t/**\n\t * Caller-supplied metadata merged into the produced node's `meta` (Tier 5.2\n\t * D8 widening). Use {@link domainMeta} to tag the layer for `describe()`\n\t * grouping. The primitive's `factoryTag(\"retry\", …)` always wins against\n\t * caller keys.\n\t */\n\tmeta?: Record<string, unknown>;\n};\n\n/** Factory-mode-only options. `initial` seeds the outer node's cache before the first attempt. */\nexport type RetryFactoryOptions<T> = RetryOptions & {\n\t/** Initial cache value for the outer node before the factory runs the first time. */\n\tinitial?: T;\n};\n\n/**\n * Resolved retry config shared by source-mode and factory-mode wrappers.\n * Centralises the unbounded-retry footgun guard and strategy resolution.\n */\ntype ResolvedRetryConfig = {\n\tmaxRetries: number;\n\tstrategy: BackoffStrategy | null;\n};\n\nfunction resolveRetryConfig(opts?: RetryOptions): ResolvedRetryConfig {\n\tconst count = opts?.count;\n\tconst backoffOpt = opts?.backoff;\n\n\t// Unbounded-retry footgun fix: if `backoff` is set without explicit `count`,\n\t// throw at construction time. Caller must opt in to `Infinity` for unbounded.\n\tif (backoffOpt !== undefined && count === undefined) {\n\t\tthrow new RangeError(\n\t\t\t\"retry({ backoff }) requires explicit count to prevent unbounded retries; pass { count: <n>, backoff: ... }\",\n\t\t);\n\t}\n\n\tconst maxRetries = count !== undefined ? count : 0;\n\tif (maxRetries < 0) throw new RangeError(\"retry count must be >= 0\");\n\n\tconst strategy: BackoffStrategy | null =\n\t\tbackoffOpt === undefined\n\t\t\t? null\n\t\t\t: typeof backoffOpt === \"string\"\n\t\t\t\t? resolveBackoffPreset(backoffOpt)\n\t\t\t\t: backoffOpt;\n\n\treturn { maxRetries, strategy };\n}\n\nfunction retryFactoryArgs(opts?: RetryOptions): Record<string, unknown> | undefined {\n\tconst args: Record<string, unknown> = {};\n\tif (opts?.count !== undefined) args.count = opts.count;\n\tif (typeof opts?.backoff === \"string\") args.backoff = opts.backoff;\n\treturn Object.keys(args).length > 0 ? args : undefined;\n}\n\n/**\n * Shared retry state machine. Both `_retrySource` and `_retryFactory` thin-wrap this:\n * the only per-mode logic is supplied via `acquireSource` (returns a fresh `Node<T>`\n * per attempt — for source-mode it just returns the captured `Node`; for factory-mode\n * it calls the user factory and forwards synchronous throws into the same retry path).\n *\n * **Reactive cfg (Tier 6.5 3.2.2, 2026-04-29).** `getCfg` is invoked at\n * every decision point (`scheduleRetryOrFinish` count + strategy reads)\n * so option swaps mid-flight take effect at the next attempt boundary\n * per the locked semantic rule: \"next attempt fails immediately if\n * already exhausted under new count; `backoff` swap takes effect at next\n * retry's delay calculation.\"\n */\nfunction _runRetryStateMachine<T>(\n\tgetCfg: () => ResolvedRetryConfig,\n\tacquireSource: () => Node<T>,\n\ta: { emit: (v: T) => void; down: (msgs: Message[]) => void },\n\temitState?: (next: RetryState) => void,\n): () => void {\n\tlet attempt = 0;\n\tlet stopped = false;\n\tlet prevDelay: number | null = null;\n\tlet unsub: (() => void) | undefined;\n\tconst timer = new ResettableTimer();\n\tconst publish = (status: StatusValue): void => {\n\t\temitState?.({ status, attempt, lastDelay_ns: prevDelay });\n\t};\n\tpublish(\"pending\");\n\n\tfunction disconnectUpstream(): void {\n\t\tunsub?.();\n\t\tunsub = undefined;\n\t}\n\n\tfunction scheduleRetryOrFinish(err: unknown): void {\n\t\tif (stopped) return;\n\t\tconst cfg = getCfg();\n\t\tif (attempt >= cfg.maxRetries) {\n\t\t\tdisconnectUpstream();\n\t\t\tpublish(\"errored\");\n\t\t\ta.down([[ERROR, err]]);\n\t\t\treturn;\n\t\t}\n\t\tconst raw = cfg.strategy === null ? 0 : cfg.strategy(attempt, err, prevDelay);\n\t\t// null from strategy = \"stop retrying\" (e.g. withMaxAttempts cap reached)\n\t\tif (raw === null || raw === undefined) {\n\t\t\tdisconnectUpstream();\n\t\t\tpublish(\"errored\");\n\t\t\ta.down([[ERROR, err]]);\n\t\t\treturn;\n\t\t}\n\t\t// A misbehaving strategy (returns NaN / non-finite / negative) MUST NOT\n\t\t// escape into the upstream drain. Treat it like `strategy === null`\n\t\t// (stop retrying) and emit the original error — the strategy bug is a\n\t\t// separate concern the user can inspect via the emitted error's stack.\n\t\tlet delayNs: number;\n\t\ttry {\n\t\t\tdelayNs = coerceDelayNs(raw);\n\t\t} catch {\n\t\t\tdisconnectUpstream();\n\t\t\tpublish(\"errored\");\n\t\t\ta.down([[ERROR, err]]);\n\t\t\treturn;\n\t\t}\n\t\tprevDelay = delayNs;\n\t\tattempt += 1;\n\t\tdisconnectUpstream();\n\t\tpublish(\"paused\");\n\t\t// `Math.max(1, …)` floor: every backoff schedule floors at 1ms even when\n\t\t// the strategy returns 0ns. Avoids 0-delay re-entrancy on the active\n\t\t// stack frame (which would risk stack overflow on a tight ERROR loop).\n\t\tconst delayMs = delayNs > 0 ? delayNs / NS_PER_MS : 1;\n\t\t// §5.10: setTimeout (not fromTimer) — retry delay needs clearTimeout/setTimeout;\n\t\t// fromTimer creates a new Node per reset, adding lifecycle overhead per retry.\n\t\ttimer.start(delayMs, () => {\n\t\t\tif (stopped) return;\n\t\t\tconnect();\n\t\t});\n\t}\n\n\tfunction connect(): void {\n\t\ttimer.cancel();\n\t\tdisconnectUpstream();\n\t\tlet src: Node<T>;\n\t\ttry {\n\t\t\tsrc = acquireSource();\n\t\t} catch (err) {\n\t\t\tscheduleRetryOrFinish(err);\n\t\t\treturn;\n\t\t}\n\t\tpublish(\"running\");\n\t\tunsub = src.subscribe((msgs) => {\n\t\t\tif (stopped) return;\n\t\t\tfor (const m of msgs) {\n\t\t\t\tconst t = m[0];\n\t\t\t\tif (t === DIRTY) a.down([[DIRTY]]);\n\t\t\t\telse if (t === DATA) {\n\t\t\t\t\tattempt = 0;\n\t\t\t\t\tprevDelay = null;\n\t\t\t\t\ta.emit(m[1] as T);\n\t\t\t\t\tpublish(\"running\");\n\t\t\t\t} else if (t === RESOLVED) a.down([[RESOLVED]]);\n\t\t\t\telse if (t === COMPLETE) {\n\t\t\t\t\t// DF2 (2026-04-29): set `stopped = true` BEFORE\n\t\t\t\t\t// `disconnectUpstream()` so a re-entrant ERROR delivered\n\t\t\t\t\t// in the same wave (after disconnect runs but before the\n\t\t\t\t\t// teardown closure fires `stopped = true`) hits the\n\t\t\t\t\t// `if (stopped) return` guard at line 159 and cannot\n\t\t\t\t\t// schedule a new retry timer.\n\t\t\t\t\tstopped = true;\n\t\t\t\t\tdisconnectUpstream();\n\t\t\t\t\tpublish(\"completed\");\n\t\t\t\t\ta.down([[COMPLETE]]);\n\t\t\t\t} else if (t === ERROR) {\n\t\t\t\t\tscheduleRetryOrFinish(msgVal(m));\n\t\t\t\t\treturn;\n\t\t\t\t} else a.down([m]);\n\t\t\t}\n\t\t});\n\t}\n\n\tconnect();\n\n\treturn () => {\n\t\tconst wasStopped = stopped;\n\t\tstopped = true;\n\t\ttimer.cancel();\n\t\tdisconnectUpstream();\n\t\tif (!wasStopped) publish(\"cancelled\");\n\t};\n}\n\n/**\n * Retry operator — two modes selected by the type of `input`:\n *\n * **Source mode** (`input: Node<T>`): resubscribes to the same node after each terminal\n * `ERROR`. The upstream should use `resubscribable: true` if it must emit again after `ERROR`.\n *\n * **Factory mode** (`input: () => Node<T>`): invokes the factory to build a fresh `Node<T>`\n * on every connect / reconnect. Ideal for producers that capture per-attempt resources\n * (sockets, clients, file handles) that become unusable after an error. Synchronous\n * exceptions thrown by the factory are treated as terminal ERROR and run through the\n * same retry pipeline as inner-node ERROR.\n *\n * @param input - Upstream node or factory that returns a fresh node per attempt.\n * @param opts - `count` caps attempts (**required when `backoff` is set**; pass `Infinity` to opt in to unbounded); `backoff` supplies delay in **nanoseconds** (or a preset name); `initial` seeds the outer node cache (factory mode only).\n * @returns Node that retries on error.\n *\n * @throws {RangeError} when `backoff` is provided without an explicit `count` (unbounded-retry footgun guard) or when `count < 0`.\n *\n * @remarks\n * **Protocol:** Forwards unknown message tuples unchanged; handles `DIRTY`, `DATA`, `RESOLVED`, `COMPLETE`, `ERROR`.\n *\n * **Backoff floor:** every scheduled delay is floored at 1ms via `Math.max(1, delayNs / NS_PER_MS)` even when the strategy returns 0ns. This avoids 0-delay re-entrancy on the active stack frame on a tight ERROR loop. Strategies that return `null`/`undefined` stop retrying immediately and forward the original error.\n *\n * @example\n * ```ts\n * // Source mode — resubscribe the same node:\n * import { ERROR, NS_PER_SEC, producer, retry, constant } from \"@graphrefly/graphrefly-ts\";\n *\n * const src = producer(\n * (a) => { a.down([[ERROR, new Error(\"x\")]]); },\n * { resubscribable: true },\n * );\n * const out = retry(src, { count: 2, backoff: constant(0.25 * NS_PER_SEC) });\n *\n * // Factory mode — fresh node per attempt (e.g. reconnecting WebSocket):\n * import { NS_PER_SEC, exponential, retry, fromWebSocket } from \"@graphrefly/graphrefly-ts\";\n *\n * const connected$ = retry(\n * () => fromWebSocket(new WebSocket(\"wss://example/stream\")),\n * { count: 10, backoff: exponential({ baseNs: 1 * NS_PER_SEC }) },\n * );\n * ```\n *\n * @category extra\n */\nexport function retry<T>(input: Node<T>, opts?: NodeOrValue<RetryOptions>): RetryBundle<T>;\nexport function retry<T>(\n\tinput: () => Node<T>,\n\topts?: NodeOrValue<RetryFactoryOptions<T>>,\n): RetryBundle<T>;\nexport function retry<T>(\n\tinput: Node<T> | (() => Node<T>),\n\topts?: NodeOrValue<RetryOptions | RetryFactoryOptions<T>>,\n): RetryBundle<T> {\n\tconst retryState = node<RetryState>([], {\n\t\tname: \"retryState\",\n\t\tdescribeKind: \"state\",\n\t\tinitial: { status: \"pending\", attempt: 0, lastDelay_ns: null },\n\t\tequals: (a, b) =>\n\t\t\ta === b ||\n\t\t\t(a != null &&\n\t\t\t\tb != null &&\n\t\t\t\ttypeof a === \"object\" &&\n\t\t\t\ttypeof b === \"object\" &&\n\t\t\t\tJSON.stringify(a) === JSON.stringify(b)),\n\t});\n\tconst emit = (s: RetryState): void => {\n\t\tretryState.down([[DIRTY], [DATA, s]]);\n\t};\n\tif (typeof input === \"function\") {\n\t\treturn {\n\t\t\tnode: _retryFactory(input, opts as NodeOrValue<RetryFactoryOptions<T>> | undefined, emit),\n\t\t\tretryState,\n\t\t};\n\t}\n\treturn {\n\t\tnode: _retrySource(input, opts as NodeOrValue<RetryOptions> | undefined, emit),\n\t\tretryState,\n\t};\n}\n\n// DS-13.5.B helper: like `resolveReactiveOption` but shallow-merges each\n// reactive emit over the prior opts and treats empty `{}` as a no-op\n// (per the locked cross-cutting rule). Static-form arg returns the value\n// as-is and never subscribes.\nfunction makeMergedOptsMirror<R extends Record<string, unknown>>(\n\targ: NodeOrValue<R> | undefined,\n): { current: () => R | undefined; unsub: () => void } {\n\tif (arg === undefined) {\n\t\treturn { current: () => undefined, unsub: () => undefined };\n\t}\n\tif (!isNode(arg)) {\n\t\treturn { current: () => arg as R, unsub: () => undefined };\n\t}\n\tconst optsNode = arg as Node<R>;\n\tlet merged: R | undefined = (optsNode.cache as R | undefined) ?? undefined;\n\tconst unsub = optsNode.subscribe((msgs) => {\n\t\tfor (const m of msgs) {\n\t\t\tif (m[0] !== DATA) continue;\n\t\t\tconst next = m[1] as R | undefined;\n\t\t\tif (next == null || typeof next !== \"object\") continue;\n\t\t\tif (Object.keys(next).length === 0) continue; // empty {} no-op\n\t\t\tmerged = { ...(merged ?? ({} as R)), ...next } as R;\n\t\t}\n\t});\n\treturn { current: () => merged, unsub };\n}\n\n// DF6 (2026-04-29): once-per-source dedup for the source-mode-retry warn.\n// Mirrors the `_bumpCursorWarned` pattern in `extra/mutation/index.ts`.\nconst _retrySourceNonResubscribableWarned = new WeakSet<Node<unknown>>();\n\nfunction _retrySource<T>(\n\tsource: Node<T>,\n\topts?: NodeOrValue<RetryOptions>,\n\temitState?: (s: RetryState) => void,\n): Node<T> {\n\t// Source-mode retry re-subscribes to the SAME source node after each\n\t// terminal ERROR. If the upstream was constructed with the default\n\t// `resubscribable: false`, the second subscribe-after-terminal is a\n\t// silent no-op and retries effectively never re-deliver. Surface\n\t// once-per-source so misconfigurations fail loud without log spam.\n\tconst sourceWithFlag = source as unknown as { _resubscribable?: boolean };\n\tif (\n\t\tsourceWithFlag._resubscribable === false &&\n\t\t!_retrySourceNonResubscribableWarned.has(source)\n\t) {\n\t\t_retrySourceNonResubscribableWarned.add(source);\n\t\tconsole.warn(\n\t\t\t\"retry(source, opts): source-mode requires `resubscribable: true` on the upstream \" +\n\t\t\t\t\"node. Retries will be silent no-ops after the first ERROR. Either pass \" +\n\t\t\t\t\"`resubscribable: true` to the source factory, OR use factory-mode retry \" +\n\t\t\t\t\"`retry(() => buildSource(), opts)` so each attempt builds a fresh node.\",\n\t\t);\n\t}\n\tconst staticOpts = isNode(opts) ? undefined : (opts as RetryOptions | undefined);\n\t// Eager validation for static-form opts (preserves construction-time\n\t// \"backoff without count\" RangeError). Reactive-form opts re-validate\n\t// per `getCfg()` call inside the state machine.\n\tif (!isNode(opts)) resolveRetryConfig(staticOpts);\n\treturn node<T>(\n\t\t(_data, a) => {\n\t\t\tconst merged = makeMergedOptsMirror<RetryOptions>(opts);\n\t\t\tconst getCfg = (): ResolvedRetryConfig => resolveRetryConfig(merged.current());\n\t\t\tconst inner = _runRetryStateMachine(getCfg, () => source, a, emitState);\n\t\t\treturn () => {\n\t\t\t\tinner();\n\t\t\t\tmerged.unsub();\n\t\t\t};\n\t\t},\n\t\t{\n\t\t\t...operatorOpts(),\n\t\t\tinitial: source.cache,\n\t\t\tmeta: {\n\t\t\t\t...(staticOpts?.meta ?? {}),\n\t\t\t\t...factoryTag(\n\t\t\t\t\t\"retry\",\n\t\t\t\t\tisNode(opts) ? { reactiveOpts: true } : retryFactoryArgs(staticOpts),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t);\n}\n\nfunction _retryFactory<T>(\n\tfactory: () => Node<T>,\n\topts?: NodeOrValue<RetryFactoryOptions<T>>,\n\temitState?: (s: RetryState) => void,\n): Node<T> {\n\tconst staticOpts = isNode(opts) ? undefined : (opts as RetryFactoryOptions<T> | undefined);\n\t// Eager validation for static-form opts (Tier 3.1 footgun preservation).\n\tif (!isNode(opts)) resolveRetryConfig(staticOpts);\n\treturn node<T>(\n\t\t(_data, a) => {\n\t\t\tconst merged = makeMergedOptsMirror<RetryFactoryOptions<T>>(opts);\n\t\t\tconst getCfg = (): ResolvedRetryConfig => resolveRetryConfig(merged.current());\n\t\t\tconst inner = _runRetryStateMachine(getCfg, factory, a, emitState);\n\t\t\treturn () => {\n\t\t\t\tinner();\n\t\t\t\tmerged.unsub();\n\t\t\t};\n\t\t},\n\t\t{\n\t\t\t...operatorOpts(),\n\t\t\tinitial: staticOpts?.initial as T | undefined,\n\t\t\tmeta: {\n\t\t\t\t...(staticOpts?.meta ?? {}),\n\t\t\t\t...factoryTag(\n\t\t\t\t\t\"retry\",\n\t\t\t\t\tisNode(opts) ? { reactiveOpts: true } : retryFactoryArgs(staticOpts),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t);\n}\n","/**\n * Circuit breaker — open/half-open/closed state machine + companion bundle.\n *\n * - {@link circuitBreaker} returns a synchronous breaker handle (counters,\n * state machine, optional reactive-options subscription).\n * - {@link withBreaker} wraps a `Node<T>` and surfaces a reactive\n * `Node<CircuitState>` companion (`bundle.breakerState`) for telemetry.\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tDIRTY,\n\tERROR,\n\tfactoryTag,\n\tmonotonicNs,\n\ttype Node,\n\tnode,\n\tRESOLVED,\n} from \"@graphrefly/pure-ts/core\";\nimport {\n\tclampNonNegative,\n\tisNode,\n\tmsgVal,\n\ttype NodeOrValue,\n\toperatorOpts,\n} from \"../../base/resilience/_internal.js\";\nimport { type BackoffStrategy, NS_PER_SEC } from \"../../base/resilience/backoff.js\";\nimport type { GateState } from \"./gate-state.js\";\n\nexport type CircuitState = \"closed\" | \"open\" | \"half-open\";\n\n/**\n * Lifecycle-shaped state companion emitted by {@link withBreaker}\n * (DS-13.5.B, locked 2026-05-01). Pre-1.0 break vs the prior\n * `Node<CircuitState>` (string-only) shape.\n *\n * `status` extends {@link GateState} with `\"half-open\"`. The numeric\n * fields surface the breaker's full internal state for telemetry and\n * `describe()` traversal.\n *\n * @category extra/resilience\n */\nexport interface BreakerState {\n\treadonly status: GateState | \"half-open\";\n\treadonly failureCount: number;\n\treadonly openCycle: number;\n\treadonly lastOpenedAtNs: number;\n\treadonly halfOpenAttempts: number;\n\treadonly lastCooldownNs: number;\n}\n\n/**\n * Thrown when {@link withBreaker} is configured with `onOpen: \"error\"` and the breaker rejects work.\n *\n * @category extra\n */\nexport class CircuitOpenError extends Error {\n\toverride name = \"CircuitOpenError\";\n\tconstructor() {\n\t\tsuper(\"Circuit breaker is open\");\n\t}\n}\n\nexport interface CircuitBreakerOptions {\n\t/** Number of consecutive failures before opening. Default: 5. */\n\tfailureThreshold?: number;\n\t/** Base cooldown in nanoseconds before transitioning to half-open. Default: 30s. */\n\tcooldownNs?: number;\n\t/** Backoff strategy for cooldown escalation across consecutive open cycles. Overrides `cooldownNs` when provided. */\n\tcooldown?: BackoffStrategy;\n\t/** Max trial requests allowed in half-open state. Default: 1. */\n\thalfOpenMax?: number;\n\t/**\n\t * Clock function returning **nanoseconds** with `monotonicNs()` semantics\n\t * (monotonically non-decreasing; suitable for elapsed-time arithmetic — never\n\t * use `Date.now()` because wall-clock skew can flip elapsed math negative).\n\t * Default: `monotonicNs` from `core/clock`. Override for deterministic tests.\n\t */\n\tnow?: () => number;\n}\n\nexport interface CircuitBreaker {\n\t/** Whether a request should be allowed through. Triggers open→half-open transition when cooldown expires. */\n\tcanExecute(): boolean;\n\t/** Record a successful execution. Resets to closed. */\n\trecordSuccess(): void;\n\t/** Record a failed execution. May transition to open. */\n\trecordFailure(error?: unknown): void;\n\t/**\n\t * Current circuit state (read-only, does not trigger transitions).\n\t *\n\t * **Telemetry:** wrap with {@link withBreaker} to surface this as a reactive\n\t * `Node<CircuitState>` companion (`bundle.breakerState`) — every state\n\t * transition (`closed`/`open`/`half-open`) emits to subscribers.\n\t */\n\treadonly state: CircuitState;\n\t/** Number of consecutive failures in the current closed period. */\n\treadonly failureCount: number;\n\t/** Manually reset to closed state, clearing all counters. */\n\treset(): void;\n\t/**\n\t * Release the reactive-options subscription (Tier 6.5 3.2.4, 2026-04-29).\n\t * No-op when constructed with static options. Call when retiring a\n\t * breaker whose options came from a `Node<CircuitBreakerOptions>` to\n\t * avoid leaking the option-Node subscription.\n\t */\n\tdispose(): void;\n}\n\n/**\n * Factory for a synchronous circuit breaker with `closed`, `open`, and `half-open` states.\n *\n * Supports escalating cooldown via an optional {@link BackoffStrategy} — each consecutive\n * open→half-open→open cycle increments the backoff attempt.\n *\n * @param options - Threshold, cooldown, half-open limit, and optional clock\n * override; OR a `Node<CircuitBreakerOptions>` carrying the same shape\n * reactively (Tier 6.5 3.2.4).\n * @returns {@link CircuitBreaker} instance.\n *\n * @remarks\n * **Timing:** Uses `monotonicNs()` by default (nanoseconds). Override `now` for tests.\n *\n * **Reactive options (locked semantics, Tier 6.5 3.2.4, 2026-04-29).**\n * When `options` is a `Node<CircuitBreakerOptions>`, the breaker\n * subscribes at construction and re-reads `failureThreshold` /\n * `cooldownNs` / `cooldown` / `halfOpenMax` / `now` on each DATA. **An\n * option swap RESETS the breaker to `\"closed\"`** with all counters\n * cleared — operators tuning a runaway breaker get a clean baseline.\n * If retaining failure history across re-tunings matters, derive a new\n * breaker per-tuning instead. Call `breaker.dispose()` when retiring to\n * release the option-Node subscription.\n *\n * @example\n * ```ts\n * import { circuitBreaker, exponential, NS_PER_SEC } from \"@graphrefly/graphrefly-ts\";\n *\n * const b = circuitBreaker({\n * failureThreshold: 3,\n * cooldown: exponential({ baseNs: 1 * NS_PER_SEC }),\n * });\n * ```\n *\n * @category extra\n */\nexport function circuitBreaker(options?: NodeOrValue<CircuitBreakerOptions>): CircuitBreaker {\n\tlet threshold = 5;\n\tlet baseCooldownNs = 30 * NS_PER_SEC;\n\tlet cooldownStrategy: BackoffStrategy | null = null;\n\tlet halfOpenMax = 1;\n\tlet now: () => number = monotonicNs;\n\n\tfunction applyOptions(o: CircuitBreakerOptions | undefined): void {\n\t\tthreshold = Math.max(1, o?.failureThreshold ?? 5);\n\t\tbaseCooldownNs = clampNonNegative(o?.cooldownNs ?? 30 * NS_PER_SEC);\n\t\tcooldownStrategy = o?.cooldown ?? null;\n\t\thalfOpenMax = Math.max(1, o?.halfOpenMax ?? 1);\n\t\tnow = o?.now ?? monotonicNs;\n\t}\n\n\tlet _state: CircuitState = \"closed\";\n\tlet _failureCount = 0;\n\tlet _openCycle = 0;\n\tlet _lastOpenedAt = 0;\n\tlet _lastCooldownNs = baseCooldownNs;\n\tlet _halfOpenAttempts = 0;\n\n\t// DS-13.5.B (locked 2026-05-01): reactive option swaps preserve\n\t// internal state — no reset across rebind. `now` is mode-locked at\n\t// construction (clock override is structural); a mid-flight `now`\n\t// change is logged and skipped (the prior `now` is preserved).\n\t// Empty `{}` emits are no-ops.\n\t//\n\t// QA A2 (2026-05-03): bad-`now` mid-flight does NOT throw — sync\n\t// throw inside a subscribe callback corrupts host scheduler state\n\t// (mirrors timeout's `actions.down([[ERROR]])` rationale; sink-side\n\t// throws break the wave's dispatch contract).\n\t//\n\t// QA A8 (2026-05-03): the push-on-subscribe re-delivery of the\n\t// cached opts fires the subscribe callback once at attach time with\n\t// the same value used for the eager `applyOptions(initialOpts)`\n\t// call above. Skip the first cached emit so opts are not re-applied\n\t// twice on construction.\n\tlet initialOpts: CircuitBreakerOptions | undefined;\n\tlet optsUnsub: (() => void) | undefined;\n\tif (isNode(options)) {\n\t\tconst optsNode = options as Node<CircuitBreakerOptions>;\n\t\tinitialOpts = optsNode.cache as CircuitBreakerOptions | undefined;\n\t\tapplyOptions(initialOpts);\n\t\tconst lockedNow = initialOpts?.now;\n\t\tconst hadInitialCache = initialOpts !== undefined;\n\t\tlet firstEmit = hadInitialCache;\n\t\toptsUnsub = optsNode.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] !== DATA) continue;\n\t\t\t\tif (firstEmit) {\n\t\t\t\t\tfirstEmit = false;\n\t\t\t\t\tcontinue; // QA A8: skip push-on-subscribe replay of cached opts\n\t\t\t\t}\n\t\t\t\tconst next = m[1] as CircuitBreakerOptions | undefined;\n\t\t\t\tif (next == null || typeof next !== \"object\") continue;\n\t\t\t\tif (Object.keys(next).length === 0) continue; // empty {} no-op\n\t\t\t\tif (\"now\" in next && next.now !== lockedNow) {\n\t\t\t\t\t// QA A2: log + skip; do NOT throw inside a subscribe\n\t\t\t\t\t// callback — host scheduler corruption hazard.\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\"circuitBreaker: ignoring mid-flight `now` change — clock override is mode-locked at construction. Prior `now` preserved.\",\n\t\t\t\t\t);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// State-preserving merge: only re-apply the axes that\n\t\t\t\t// changed; preserve `_state`, `_failureCount`, etc.\n\t\t\t\tconst merged: CircuitBreakerOptions = {\n\t\t\t\t\t...(initialOpts ?? {}),\n\t\t\t\t\t...next,\n\t\t\t\t\t...(lockedNow !== undefined ? { now: lockedNow } : {}),\n\t\t\t\t};\n\t\t\t\tapplyOptions(merged);\n\t\t\t\tinitialOpts = merged;\n\t\t\t}\n\t\t});\n\t} else {\n\t\tapplyOptions(options as CircuitBreakerOptions | undefined);\n\t}\n\t_lastCooldownNs = baseCooldownNs;\n\n\tfunction getCooldownNs(): number {\n\t\tif (!cooldownStrategy) return baseCooldownNs;\n\t\tconst delayNs = cooldownStrategy(_openCycle);\n\t\treturn delayNs !== null ? delayNs : baseCooldownNs;\n\t}\n\n\tfunction transitionToOpen(): void {\n\t\t_state = \"open\";\n\t\t_lastCooldownNs = getCooldownNs();\n\t\t_lastOpenedAt = now();\n\t\t_halfOpenAttempts = 0;\n\t}\n\n\tconst breaker: CircuitBreaker = {\n\t\tcanExecute(): boolean {\n\t\t\tif (_state === \"closed\") return true;\n\n\t\t\tif (_state === \"open\") {\n\t\t\t\tconst elapsed = now() - _lastOpenedAt;\n\t\t\t\tif (elapsed >= _lastCooldownNs) {\n\t\t\t\t\t_state = \"half-open\";\n\t\t\t\t\t_halfOpenAttempts = 1;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (_halfOpenAttempts < halfOpenMax) {\n\t\t\t\t_halfOpenAttempts++;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t},\n\n\t\trecordSuccess(): void {\n\t\t\tif (_state === \"half-open\") {\n\t\t\t\t_state = \"closed\";\n\t\t\t\t_failureCount = 0;\n\t\t\t\t_openCycle = 0;\n\t\t\t} else if (_state === \"closed\") {\n\t\t\t\t_failureCount = 0;\n\t\t\t}\n\t\t},\n\n\t\trecordFailure(_error?: unknown): void {\n\t\t\tif (_state === \"half-open\") {\n\t\t\t\t_openCycle++;\n\t\t\t\ttransitionToOpen();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (_state === \"closed\") {\n\t\t\t\t_failureCount++;\n\t\t\t\tif (_failureCount >= threshold) {\n\t\t\t\t\ttransitionToOpen();\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tget state(): CircuitState {\n\t\t\treturn _state;\n\t\t},\n\n\t\tget failureCount(): number {\n\t\t\treturn _failureCount;\n\t\t},\n\n\t\treset(): void {\n\t\t\t_state = \"closed\";\n\t\t\t_failureCount = 0;\n\t\t\t_openCycle = 0;\n\t\t\t_halfOpenAttempts = 0;\n\t\t},\n\n\t\tdispose(): void {\n\t\t\toptsUnsub?.();\n\t\t},\n\n\t\t// Internal accessors used by withBreaker for the BreakerState\n\t\t// companion (DS-13.5.B). Not part of the public CircuitBreaker\n\t\t// interface but exposed for the bundle wiring.\n\t};\n\t(breaker as unknown as { _stateSnapshot: () => BreakerState })._stateSnapshot = () => ({\n\t\tstatus: _state,\n\t\tfailureCount: _failureCount,\n\t\topenCycle: _openCycle,\n\t\tlastOpenedAtNs: _lastOpenedAt,\n\t\thalfOpenAttempts: _halfOpenAttempts,\n\t\tlastCooldownNs: _lastCooldownNs,\n\t});\n\n\treturn breaker;\n}\n\nexport type WithBreakerBundle<T> = {\n\tnode: Node<T>;\n\tbreakerState: Node<BreakerState>;\n};\n\n/**\n * Returns a unary wrapper that gates upstream `DATA` through a {@link CircuitBreaker}.\n *\n * @param breaker - Shared breaker instance (typically one per resource).\n * @param options - `onOpen: \"skip\"` emits `RESOLVED` when open; `\"error\"` emits {@link CircuitOpenError}.\n * @returns Function mapping `Node<T>` to `{ node, breakerState }` companion nodes.\n *\n * @remarks\n * **Success path:** `COMPLETE` calls {@link CircuitBreaker.recordSuccess}. **Failure path:** upstream `ERROR` calls {@link CircuitBreaker.recordFailure} and is forwarded.\n *\n * **State telemetry:** `breakerState: Node<CircuitState>` is a reactive companion that mirrors `breaker.state` — every transition (`closed`/`open`/`half-open`) emits a `DATA`. Also accessible via `node.meta.breakerState` for `describe()` traversal.\n *\n * @example\n * ```ts\n * import { state, withBreaker, circuitBreaker } from \"@graphrefly/graphrefly-ts\";\n *\n * const b = circuitBreaker({ failureThreshold: 2 });\n * const s = state(1);\n * const { node, breakerState } = withBreaker(b)(s);\n * ```\n *\n * @category extra\n */\nexport function withBreaker<T>(\n\tbreaker: CircuitBreaker,\n\toptions?: { onOpen?: \"skip\" | \"error\"; meta?: Record<string, unknown> },\n): (source: Node<T>) => WithBreakerBundle<T> {\n\tconst onOpen = options?.onOpen ?? \"skip\";\n\tconst callerMeta = options?.meta;\n\n\treturn (source: Node<T>): WithBreakerBundle<T> => {\n\t\tconst snapshot = (breaker as unknown as { _stateSnapshot?: () => BreakerState })._stateSnapshot;\n\t\tconst initialSnapshot: BreakerState = snapshot\n\t\t\t? snapshot()\n\t\t\t: {\n\t\t\t\t\tstatus: breaker.state,\n\t\t\t\t\tfailureCount: breaker.failureCount,\n\t\t\t\t\topenCycle: 0,\n\t\t\t\t\tlastOpenedAtNs: 0,\n\t\t\t\t\thalfOpenAttempts: 0,\n\t\t\t\t\tlastCooldownNs: 0,\n\t\t\t\t};\n\t\tconst wrapped = node<T>(\n\t\t\t[],\n\t\t\t(_deps, a) => {\n\t\t\t\tfunction syncState(): void {\n\t\t\t\t\tconst s = snapshot\n\t\t\t\t\t\t? snapshot()\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\tstatus: breaker.state,\n\t\t\t\t\t\t\t\tfailureCount: breaker.failureCount,\n\t\t\t\t\t\t\t\topenCycle: 0,\n\t\t\t\t\t\t\t\tlastOpenedAtNs: 0,\n\t\t\t\t\t\t\t\thalfOpenAttempts: 0,\n\t\t\t\t\t\t\t\tlastCooldownNs: 0,\n\t\t\t\t\t\t\t};\n\t\t\t\t\twrapped.meta.breakerState.down([[DIRTY], [DATA, s]]);\n\t\t\t\t}\n\n\t\t\t\tconst unsub = source.subscribe((msgs) => {\n\t\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\t\tconst t = m[0];\n\t\t\t\t\t\tif (t === DIRTY) a.down([[DIRTY]]);\n\t\t\t\t\t\telse if (t === DATA) {\n\t\t\t\t\t\t\tif (breaker.canExecute()) {\n\t\t\t\t\t\t\t\tsyncState();\n\t\t\t\t\t\t\t\ta.emit(m[1] as T);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tsyncState();\n\t\t\t\t\t\t\t\tif (onOpen === \"error\") a.down([[ERROR, new CircuitOpenError()]]);\n\t\t\t\t\t\t\t\telse a.down([[RESOLVED]]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (t === RESOLVED) a.down([[RESOLVED]]);\n\t\t\t\t\t\telse if (t === COMPLETE) {\n\t\t\t\t\t\t\tbreaker.recordSuccess();\n\t\t\t\t\t\t\tsyncState();\n\t\t\t\t\t\t\ta.down([[COMPLETE]]);\n\t\t\t\t\t\t} else if (t === ERROR) {\n\t\t\t\t\t\t\tbreaker.recordFailure(msgVal(m));\n\t\t\t\t\t\t\tsyncState();\n\t\t\t\t\t\t\ta.down([m]);\n\t\t\t\t\t\t} else a.down([m]);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tsyncState();\n\t\t\t\treturn unsub;\n\t\t\t},\n\t\t\t{\n\t\t\t\t...operatorOpts(),\n\t\t\t\tmeta: {\n\t\t\t\t\t...(callerMeta ?? {}),\n\t\t\t\t\tbreakerState: initialSnapshot,\n\t\t\t\t\t...factoryTag(\"withBreaker\", { onOpen }),\n\t\t\t\t},\n\t\t\t\tcompleteWhenDepsComplete: false,\n\t\t\t\tinitial: source.cache,\n\t\t\t},\n\t\t);\n\n\t\treturn { node: wrapped, breakerState: wrapped.meta.breakerState as Node<BreakerState> };\n\t};\n}\n","/**\n * Metadata helpers for pattern-layer nodes (Tier 2.2 promotion from\n * `patterns/_internal/`).\n *\n * Each domain (orchestration, messaging, reduction, ai, cqrs, domain_template,\n * memory, lens, audit, harness) shares the same metadata convention. Promoted\n * to `extra/` so non-patterns code (and downstream consumers building their\n * own domain primitives) can use the same shape.\n *\n * @module\n */\n\n/**\n * Build a domain metadata object for pattern-layer nodes.\n *\n * Each domain follows the same shape: `{ [domain]: true, [domain]_type: kind, ...extra }`.\n *\n * @param domain - The domain tag (e.g. `\"orchestration\"`, `\"ai\"`, `\"cqrs\"`).\n * @param kind - The specific type within the domain (e.g. `\"gate\"`, `\"prompt\"`).\n * @param extra - Additional metadata to merge.\n * @returns Metadata object.\n */\nexport function domainMeta(\n\tdomain: string,\n\tkind: string,\n\textra?: Record<string, unknown>,\n): Record<string, unknown> {\n\treturn {\n\t\t[domain]: true,\n\t\t[`${domain}_type`]: kind,\n\t\t...(extra ?? {}),\n\t};\n}\n","/**\n * Rate limiters — `tokenBucket` (raw meter), `rateLimiter` (operator with\n * bounded queue + reactive backpressure companions), and the re-export of\n * `adaptiveRateLimiter` from its standalone module.\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tDIRTY,\n\tERROR,\n\tfactoryTag,\n\tmonotonicNs,\n\ttype Node,\n\tnode,\n\tRESOLVED,\n\tResettableTimer,\n\tRingBuffer,\n\tTEARDOWN,\n} from \"@graphrefly/pure-ts/core\";\nimport {\n\tisNode,\n\ttype NodeOrValue,\n\toperatorOpts,\n\tresolveReactiveOption,\n} from \"../../base/resilience/_internal.js\";\nimport { NS_PER_MS, NS_PER_SEC } from \"../../base/resilience/backoff.js\";\nimport type { GateState } from \"./gate-state.js\";\n\n// `adaptiveRateLimiter` lives in extra/adaptive-rate-limiter.ts (kept independent\n// because it has its own internal control-loop machinery).\nexport * from \"./adaptive-rate-limiter.js\";\n\nexport interface TokenBucket {\n\t/**\n\t * Number of tokens currently available (after refill).\n\t *\n\t * **Float-valued.** When `refillPerSecond` is fractional (or `capacity` × elapsed-fraction\n\t * yields a non-integer), the bucket accumulates fractional refill credit between\n\t * `tryConsume`s. Consumers should not assume integer tokens — e.g. with\n\t * `tokenBucket(10, 2.5)` after 100ms of elapsed time `available()` may report `0.25`.\n\t */\n\tavailable(): number;\n\t/** Try to consume `cost` tokens. Returns `true` if successful. */\n\ttryConsume(cost?: number): boolean;\n\t/**\n\t * Return `cost` tokens to the bucket (capped at capacity). Used when a\n\t * multi-bucket admission fails partway — e.g., `adaptiveRateLimiter`\n\t * consumes from an rpm bucket, then a tpm bucket; if tpm fails, call\n\t * `rpmBucket.putBack(requestCost)` so the rpm slot isn't wasted.\n\t * No-op for non-positive `cost`.\n\t */\n\tputBack(cost?: number): void;\n}\n\n/** Optional configuration for {@link tokenBucket}. */\nexport interface TokenBucketOptions {\n\t/**\n\t * Clock function returning **nanoseconds** with `monotonicNs()` semantics\n\t * (monotonically non-decreasing). Default: `monotonicNs` from `core/clock`.\n\t * Override for deterministic tests — eliminates the need for `vi.useFakeTimers`\n\t * to drive token-refill scheduling.\n\t */\n\tclock?: () => number;\n}\n\n/**\n * Token-bucket meter (capacity + refill rate per second). Use with {@link rateLimiter} or custom gates.\n *\n * @param capacity - Maximum tokens (must be positive).\n * @param refillPerSecond - Tokens added per elapsed second (non-negative; may be fractional).\n * @param opts - Optional `clock` override for deterministic testing.\n * @returns {@link TokenBucket} instance.\n *\n * @remarks\n * **Float behavior:** the internal token counter is float-valued — fractional refill\n * accumulates between `tryConsume` calls. See {@link TokenBucket.available} for caveats.\n *\n * **Clock injection:** pass `opts.clock` to drive refill scheduling deterministically\n * in tests. The contract matches {@link circuitBreaker}'s `now` option: must return\n * `monotonicNs()`-style nanoseconds, never `Date.now()` (wall-clock skew breaks\n * elapsed math).\n *\n * @example\n * ```ts\n * import { tokenBucket } from \"@graphrefly/graphrefly-ts\";\n *\n * const bucket = tokenBucket(10, 2); // capacity 10, refill 2 tokens/sec\n * bucket.tryConsume(3); // true — 7 tokens remaining\n * bucket.available(); // ~7 (plus any elapsed refill — float-valued)\n *\n * // Deterministic test:\n * let t = 0;\n * const tb = tokenBucket(5, 1, { clock: () => t });\n * tb.tryConsume(5); // exhausts\n * t = 1_000_000_000; // advance 1s → +1 refill\n * tb.tryConsume(1); // true\n * ```\n *\n * @category extra\n */\nexport function tokenBucket(\n\tcapacity: number,\n\trefillPerSecond: number,\n\topts?: TokenBucketOptions,\n): TokenBucket {\n\tif (capacity <= 0) throw new RangeError(\"capacity must be > 0\");\n\tif (refillPerSecond < 0) throw new RangeError(\"refillPerSecond must be >= 0\");\n\n\tconst clock = opts?.clock ?? monotonicNs;\n\n\tlet tokens = capacity;\n\tlet updatedAt = clock();\n\n\tfunction refill(now: number): void {\n\t\tif (refillPerSecond > 0) {\n\t\t\tconst elapsedNs = now - updatedAt;\n\t\t\ttokens = Math.min(capacity, tokens + (elapsedNs / NS_PER_SEC) * refillPerSecond);\n\t\t}\n\t\tupdatedAt = now;\n\t}\n\n\treturn {\n\t\tavailable(): number {\n\t\t\trefill(clock());\n\t\t\treturn tokens;\n\t\t},\n\t\ttryConsume(cost = 1): boolean {\n\t\t\tif (cost <= 0) return true;\n\t\t\tconst now = clock();\n\t\t\trefill(now);\n\t\t\tif (tokens >= cost) {\n\t\t\t\ttokens -= cost;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t},\n\t\tputBack(cost = 1): void {\n\t\t\tif (cost <= 0) return;\n\t\t\trefill(clock());\n\t\t\ttokens = Math.min(capacity, tokens + cost);\n\t\t},\n\t};\n}\n\nexport type RateLimiterOverflowPolicy = \"drop-oldest\" | \"drop-newest\" | \"error\";\n\nexport type RateLimiterOptions = {\n\t/** Maximum `DATA` emissions per window (must be > 0). */\n\tmaxEvents: number;\n\t/** Window length in nanoseconds (must be > 0). */\n\twindowNs: number;\n\t/**\n\t * Cap on items queued while waiting for token refill.\n\t *\n\t * **Required.** Pass a finite positive integer (>= 1) for a bounded queue, OR\n\t * the literal `Infinity` to opt in to an unbounded queue (caller acknowledges\n\t * the unbounded-memory-growth risk on a high-rate source). Omitting this\n\t * throws at construction time — the silent-unbounded-buffer footgun is the\n\t * most common rateLimiter mis-configuration.\n\t */\n\tmaxBuffer: number;\n\t/** Overflow policy when `maxBuffer` is exceeded. Default: `\"drop-newest\"`. */\n\tonOverflow?: RateLimiterOverflowPolicy;\n\t/**\n\t * Caller-supplied metadata merged into the produced node's `meta` (Tier 5.2\n\t * D8 widening). Use {@link domainMeta} to tag the layer for `describe()` /\n\t * mermaid grouping (e.g. `domainMeta(\"resilient\", \"rate-limit\")`). The\n\t * primitive's own `factoryTag(\"rateLimiter\", opts)` and the `droppedCount`\n\t * / `rateLimitState` companion seeds always win against caller-supplied\n\t * keys so the audit trail can't be silently overwritten.\n\t */\n\tmeta?: Record<string, unknown>;\n};\n\n/**\n * Thrown by {@link rateLimiter} when `onOverflow: \"error\"` and the pending buffer is full.\n *\n * @category extra\n */\nexport class RateLimiterOverflowError extends Error {\n\toverride name = \"RateLimiterOverflowError\";\n\tconstructor(maxBuffer: number) {\n\t\tsuper(`rateLimiter buffer overflow (maxBuffer=${maxBuffer})`);\n\t}\n}\n\n/**\n * Combined runtime state surfaced by {@link rateLimiter} alongside `droppedCount`.\n * Tier 5.2 D7 widening — exposes pending-buffer occupancy and a `paused`\n * flag so consumers can render backpressure (UI), feed `lens.health`, or\n * gate downstream effects.\n */\n/**\n * Lifecycle-shaped state companion emitted by {@link rateLimiter}.\n *\n * **DS-13.5.B widening (2026-05-01).** `status` extends {@link GateState}\n * with `\"throttled\"` (= `paused === true`). Pre-1.0 break vs the prior\n * shape (which omitted `status`).\n *\n * - `\"open\"` — passing through (no buffering, no recent overflow drops).\n * - `\"throttled\"` — at least one item queued awaiting a token refill.\n * - `\"closed\"` — reserved for future terminal lifecycle reporting.\n */\nexport type RateLimiterState = {\n\t/** DS-13.5.B status field — `\"open\" | \"closed\" | \"throttled\"`. */\n\tstatus: GateState | \"throttled\";\n\t/** Cumulative `DATA` items dropped due to overflow since this subscription cycle started. */\n\tdroppedCount: number;\n\t/** Items currently buffered awaiting a token refill. `0` when the limiter is passing through. */\n\tpendingCount: number;\n\t/** `true` when at least one item is queued (the limiter is actively throttling). */\n\tpaused: boolean;\n};\n\nfunction rateLimiterStateEqual(a: RateLimiterState, b: RateLimiterState): boolean {\n\treturn (\n\t\ta.status === b.status &&\n\t\ta.droppedCount === b.droppedCount &&\n\t\ta.pendingCount === b.pendingCount &&\n\t\ta.paused === b.paused\n\t);\n}\n\nconst RATE_LIMITER_INITIAL_STATE: RateLimiterState = Object.freeze({\n\tstatus: \"open\" as const,\n\tdroppedCount: 0,\n\tpendingCount: 0,\n\tpaused: false,\n});\n\n/** Bundle returned by {@link rateLimiter}. */\nexport type RateLimiterBundle<T> = {\n\t/** The throttled stream — at most `maxEvents` `DATA` per `windowNs`. */\n\tnode: Node<T>;\n\t/**\n\t * Reactive companion: count of `DATA` items dropped since the producer\n\t * activated.\n\t *\n\t * - Increments on every drop under any overflow policy (`drop-newest`,\n\t * `drop-oldest`). The `error` policy terminates the stream after a single\n\t * overflow, so `droppedCount` increments at most once in that path.\n\t * - **Lifecycle scoping (qa A1 + EC7):** the counter retains its final\n\t * value through terminal (`COMPLETE` / `ERROR` / `TEARDOWN`) so consumers\n\t * see the final drop count, not zero. The closure-held counter resets to\n\t * `0` only when the producer fn re-runs — which only happens on a new\n\t * subscription cycle, and only if the producer was constructed with\n\t * `resubscribable: true`. The default `rateLimiter` producer is NOT\n\t * resubscribable, so a single producer-fn run is the typical lifetime.\n\t * - Producer-pattern note: this companion is invisible to `describe()`\n\t * traversal from `node` (effect-mirror limitation; same shape as\n\t * `withBreaker.breakerState` and `withStatus.status`). Surface it via\n\t * `node.meta.droppedCount` if you need it in topology snapshots.\n\t */\n\tdroppedCount: Node<number>;\n\t/**\n\t * Reactive companion: combined `{droppedCount, pendingCount, paused}` view.\n\t *\n\t * - `pendingCount` reflects the live buffer occupancy and updates on every\n\t * push / shift / overflow drop; `paused` is shorthand for\n\t * `pendingCount > 0`.\n\t * - Equality-deduped — re-emits only when one of the three fields actually\n\t * changes (so a busy steady-state where every DATA passes immediately\n\t * produces one `paused: false` emission, not one per DATA).\n\t * - **Lifecycle scoping (qa EC7):** same contract as `droppedCount` —\n\t * retains its final value through terminal; resets to the initial\n\t * `{droppedCount: 0, pendingCount: 0, paused: false}` only on a new\n\t * producer-fn run (resubscribable upstream required).\n\t * - Same producer-pattern caveat as `droppedCount` re: `describe()` visibility.\n\t */\n\trateLimitState: Node<RateLimiterState>;\n};\n\n/**\n * Token-bucket rate limiter: at most `maxEvents` `DATA` values per `windowNs`.\n *\n * Uses {@link tokenBucket} internally (capacity = `maxEvents`, refill = `maxEvents / windowSeconds`).\n * Excess items are queued FIFO (in a fixed-capacity {@link RingBuffer} for O(1) push/shift)\n * until a token is available. The queue is bounded by the **required** `maxBuffer` option\n * with a configurable overflow policy.\n *\n * @param source - Upstream node.\n * @param opts - Rate + bounded-buffer configuration. `maxBuffer` is required (use `Infinity` to opt in to unbounded).\n * @returns `{ node, droppedCount }` bundle. Subscribe to `node` for the throttled stream and to `droppedCount` for backpressure pressure.\n *\n * @throws {RangeError} when `maxEvents` / `windowNs` is non-positive, when `maxBuffer` is omitted, or when `maxBuffer` is a finite value < 1.\n *\n * @remarks\n * **Terminal:** `COMPLETE` / `ERROR` cancel the refill timer, drop the pending queue,\n * reset `droppedCount` to `0`, and propagate.\n *\n * @example\n * ```ts\n * import { rateLimiter, state, NS_PER_SEC } from \"@graphrefly/graphrefly-ts\";\n *\n * const src = state(0);\n * // Allow at most 5 DATA values per second; queue up to 100 excess items, drop newest beyond.\n * const { node: limited, droppedCount } = rateLimiter(src, {\n * maxEvents: 5,\n * windowNs: NS_PER_SEC,\n * maxBuffer: 100,\n * });\n * droppedCount.subscribe(([m]) => console.log(\"dropped so far:\", m[1]));\n * ```\n *\n * @category extra\n */\nexport function rateLimiter<T>(\n\tsource: Node<T>,\n\topts: NodeOrValue<RateLimiterOptions>,\n): RateLimiterBundle<T> {\n\t// Eager validation of static-form opts. Reactive-form opts re-validate\n\t// on each emit via `applyOpts` (invalid runtime config keeps the previous\n\t// values rather than throwing — the producer body's swap path never\n\t// throws into the dataplane).\n\tconst isReactive = isNode(opts);\n\tif (!isReactive) {\n\t\tconst o = opts as RateLimiterOptions;\n\t\tif (o.maxEvents <= 0) throw new RangeError(\"maxEvents must be > 0\");\n\t\tif (o.windowNs <= 0) throw new RangeError(\"windowNs must be > 0\");\n\t\tif (o.maxBuffer === undefined) {\n\t\t\tthrow new RangeError(\n\t\t\t\t\"rateLimiter requires explicit maxBuffer (use Infinity to opt in to unbounded)\",\n\t\t\t);\n\t\t}\n\t\tconst isUnbounded0 = o.maxBuffer === Infinity;\n\t\tif (!isUnbounded0 && (!Number.isInteger(o.maxBuffer) || o.maxBuffer < 1)) {\n\t\t\tthrow new RangeError(\"maxBuffer must be a positive integer (or Infinity for unbounded)\");\n\t\t}\n\t}\n\t// Mode (bounded vs unbounded) is locked at construction time per the\n\t// Tier 6.5 3.2.3 swap rule — runtime opt swaps change the cap WITHIN\n\t// the same mode. Toggling between bounded/unbounded requires re-mounting\n\t// the rateLimiter; the queue type is structural, not a tunable. For\n\t// reactive opts we read the FIRST value (cached or undefined) to lock\n\t// the mode; if the cache is undefined at construction we conservatively\n\t// default to bounded with a placeholder cap, and the first emit re-locks.\n\tconst initialOpts: RateLimiterOptions | undefined = isReactive\n\t\t? ((opts as Node<RateLimiterOptions>).cache as RateLimiterOptions | undefined)\n\t\t: (opts as RateLimiterOptions);\n\tconst initialMaxBuffer = initialOpts?.maxBuffer;\n\tconst isUnbounded = initialMaxBuffer === Infinity;\n\n\tconst out = node<T>(\n\t\t(_data, a) => {\n\t\t\t// Mutable closure-state — replaced on each option swap.\n\t\t\tlet maxEvents = initialOpts?.maxEvents ?? 1;\n\t\t\tlet windowNs = initialOpts?.windowNs ?? NS_PER_SEC;\n\t\t\tlet maxBuffer = initialMaxBuffer ?? 1;\n\t\t\tlet onOverflow: RateLimiterOverflowPolicy = initialOpts?.onOverflow ?? \"drop-newest\";\n\t\t\tlet refillPerSec = (maxEvents * NS_PER_SEC) / windowNs;\n\t\t\tlet tokenTimeNs = NS_PER_SEC / refillPerSec;\n\t\t\tlet bucket = tokenBucket(maxEvents, refillPerSec);\n\n\t\t\t// RingBuffer for O(1) push + shift. Unbounded mode falls back to a plain\n\t\t\t// array (RingBuffer requires a positive integer capacity); the caller\n\t\t\t// explicitly opted in via `maxBuffer: Infinity` and accepts the cost.\n\t\t\t// Bounded mode allocates with the INITIAL `maxBuffer`; runtime cap\n\t\t\t// reductions enforce drop-oldest at push time without resizing the ring.\n\t\t\tconst pending: { push: (v: T) => void; shift: () => T | undefined; size: number } =\n\t\t\t\tisUnbounded ? makeArrayQueue<T>() : ringBufferQueue<T>(Math.max(1, maxBuffer));\n\t\t\tconst timer = new ResettableTimer();\n\t\t\tlet terminated = false;\n\t\t\tlet dropped = 0;\n\n\t\t\t// Mirror the dropped counter + combined state to the meta companions.\n\t\t\t// The `emit` call is the same subscribe-callback effect-mirror\n\t\t\t// pattern used by `withBreaker.breakerState` / `withStatus.status`\n\t\t\t// (sanctioned per audit § F.7).\n\t\t\tconst droppedNode = out.meta.droppedCount;\n\t\t\tconst stateNode = out.meta.rateLimitState;\n\t\t\tlet lastState: RateLimiterState = RATE_LIMITER_INITIAL_STATE;\n\t\t\tfunction syncState(): void {\n\t\t\t\tdroppedNode.emit(dropped);\n\t\t\t\tconst isPaused = pending.size > 0;\n\t\t\t\tconst next: RateLimiterState = {\n\t\t\t\t\tstatus: isPaused ? \"throttled\" : \"open\",\n\t\t\t\t\tdroppedCount: dropped,\n\t\t\t\t\tpendingCount: pending.size,\n\t\t\t\t\tpaused: isPaused,\n\t\t\t\t};\n\t\t\t\t// Equality-dedup at the emit boundary so steady-state pass-through\n\t\t\t\t// (every DATA passes immediately — pendingCount stays 0, paused\n\t\t\t\t// stays false) doesn't generate one state DATA per source DATA.\n\t\t\t\tif (!rateLimiterStateEqual(lastState, next)) {\n\t\t\t\t\tlastState = next;\n\t\t\t\t\tstateNode.emit(next);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Reset for this subscription cycle — `dropped` is the closure\n\t\t\t// variable (already 0 at construction); `pending.size` is also 0\n\t\t\t// (fresh queue per producer activation). The companion Node caches\n\t\t\t// may still hold a prior cycle's terminal values, so re-emit the\n\t\t\t// initial state explicitly.\n\t\t\tlastState = RATE_LIMITER_INITIAL_STATE;\n\t\t\tdroppedNode.emit(0);\n\t\t\tstateNode.emit(RATE_LIMITER_INITIAL_STATE);\n\n\t\t\t// Tier 6.5 3.2.3 (2026-04-29): reactive option swap handler.\n\t\t\t// Locked semantics: `maxEvents`/`windowNs` swap rebuilds the\n\t\t\t// token bucket at the next refill window (tokens reset to new\n\t\t\t// capacity, refill rate updates immediately). `maxBuffer` shrink\n\t\t\t// drops oldest pending entries until size ≤ new cap. `onOverflow`\n\t\t\t// swap takes effect at the next overflow check. Mode toggling\n\t\t\t// (bounded ↔ unbounded) is NOT supported — locked at construction.\n\t\t\tconst optMirror = resolveReactiveOption<RateLimiterOptions>(\n\t\t\t\topts as NodeOrValue<RateLimiterOptions>,\n\t\t\t\t(next) => {\n\t\t\t\t\tif (terminated) return;\n\t\t\t\t\tif (next == null) return;\n\t\t\t\t\t// QA A9 (2026-05-03): explicit empty `{}` short-circuit\n\t\t\t\t\t// for symmetry with timeout / retry / circuitBreaker\n\t\t\t\t\t// (DS-13.5.B locked rule: empty `{}` is a no-op — no\n\t\t\t\t\t// rebind, no companion fire). Pre-fix, empty `{}` was\n\t\t\t\t\t// implicitly a no-op via the validation gate's\n\t\t\t\t\t// `next.maxEvents > 0` check on `undefined`; this\n\t\t\t\t\t// makes the rule explicit and resilient to future\n\t\t\t\t\t// validation refactors.\n\t\t\t\t\tif (typeof next === \"object\" && Object.keys(next).length === 0) return;\n\t\t\t\t\t// Validate; if invalid, keep previous values (no throw into dataplane).\n\t\t\t\t\tif (!(next.maxEvents > 0) || !(next.windowNs > 0)) return;\n\t\t\t\t\tconst nextBuf = next.maxBuffer;\n\t\t\t\t\tif (nextBuf === undefined) return;\n\t\t\t\t\tconst nextUnbounded = nextBuf === Infinity;\n\t\t\t\t\tif (nextUnbounded !== isUnbounded) {\n\t\t\t\t\t\t// Mode toggle not supported — skip silently. Caller using\n\t\t\t\t\t\t// reactive opts must keep maxBuffer in the same mode.\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (!nextUnbounded && (!Number.isInteger(nextBuf) || nextBuf < 1)) return;\n\n\t\t\t\t\t// qa F-C (Tier 5 /qa pass, 2026-04-29): reactive `maxBuffer`\n\t\t\t\t\t// is monotonically non-increasing. The pending RingBuffer is\n\t\t\t\t\t// allocated once at construction; growing the cap reactively\n\t\t\t\t\t// would let the overflow check pass more pushes than the\n\t\t\t\t\t// ring's capacity → silent drop-oldest at the substrate level\n\t\t\t\t\t// (RingBuffer.push wraps), bypassing our `dropped` counter\n\t\t\t\t\t// and `onOverflow: \"error\"` arm. Reject grow swaps with a\n\t\t\t\t\t// console.warn and keep the previous cap. Shrink stays\n\t\t\t\t\t// supported (drop-oldest below).\n\t\t\t\t\tif (!nextUnbounded && nextBuf > maxBuffer) {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`rateLimiter: reactive maxBuffer grow (${maxBuffer} → ${nextBuf}) ` +\n\t\t\t\t\t\t\t\t\"rejected. The pending ring buffer is allocated at construction; \" +\n\t\t\t\t\t\t\t\t\"reactive maxBuffer is monotonically non-increasing. Recreate \" +\n\t\t\t\t\t\t\t\t\"the rateLimiter with the larger cap if growth is required.\",\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tmaxEvents = next.maxEvents;\n\t\t\t\t\twindowNs = next.windowNs;\n\t\t\t\t\tmaxBuffer = nextBuf;\n\t\t\t\t\tonOverflow = next.onOverflow ?? \"drop-newest\";\n\t\t\t\t\trefillPerSec = (maxEvents * NS_PER_SEC) / windowNs;\n\t\t\t\t\ttokenTimeNs = NS_PER_SEC / refillPerSec;\n\t\t\t\t\t// Rebuild bucket — tokens snap to new capacity. The old refill\n\t\t\t\t\t// timer continues to fire `tryEmit` which will use the new\n\t\t\t\t\t// bucket (same closure variable).\n\t\t\t\t\tbucket = tokenBucket(maxEvents, refillPerSec);\n\n\t\t\t\t\t// Drop-oldest until pending.size <= maxBuffer (bounded only).\n\t\t\t\t\tif (!nextUnbounded) {\n\t\t\t\t\t\twhile (pending.size > maxBuffer) {\n\t\t\t\t\t\t\tpending.shift();\n\t\t\t\t\t\t\tdropped += 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tsyncState();\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tfunction tryEmit(): void {\n\t\t\t\twhile (pending.size > 0) {\n\t\t\t\t\tif (bucket.tryConsume(1)) {\n\t\t\t\t\t\ta.emit(pending.shift() as T);\n\t\t\t\t\t\tsyncState();\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Wait one full token-refill interval. Avoids calling bucket.available()\n\t\t\t\t\t\t// which would advance the internal refill clock and steal fractional credit.\n\t\t\t\t\t\t// §5.10: setTimeout (not fromTimer) — refill-delay scheduling needs clearTimeout/setTimeout;\n\t\t\t\t\t\t// fromTimer creates a new Node per reset, adding lifecycle overhead per retry.\n\t\t\t\t\t\ttimer.start(Math.max(1, tokenTimeNs / NS_PER_MS), tryEmit);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction recordDrop(): void {\n\t\t\t\tdropped += 1;\n\t\t\t\tsyncState();\n\t\t\t}\n\n\t\t\tfunction resetForTerminal(): void {\n\t\t\t\tterminated = true;\n\t\t\t\ttimer.cancel();\n\t\t\t\t// RingBuffer.clear-equivalent: drain remaining slots so refs GC.\n\t\t\t\twhile (pending.size > 0) pending.shift();\n\t\t\t\t// qa A1: companions retain their last-emitted DATA value\n\t\t\t\t// through terminal (consumer sees the final drop count, not 0).\n\t\t\t\t// The closure-held `dropped` resets to 0 so a re-subscribe\n\t\t\t\t// cycle starts fresh; the activation block above re-emits\n\t\t\t\t// `RATE_LIMITER_INITIAL_STATE` at that point.\n\t\t\t\tdropped = 0;\n\t\t\t}\n\n\t\t\tconst unsub = source.subscribe((msgs) => {\n\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\tif (terminated) return;\n\t\t\t\t\tconst t = m[0];\n\t\t\t\t\tif (t === DIRTY) a.down([[DIRTY]]);\n\t\t\t\t\telse if (t === DATA) {\n\t\t\t\t\t\tif (!isUnbounded && pending.size >= maxBuffer) {\n\t\t\t\t\t\t\tif (onOverflow === \"drop-newest\") {\n\t\t\t\t\t\t\t\trecordDrop();\n\t\t\t\t\t\t\t} else if (onOverflow === \"drop-oldest\") {\n\t\t\t\t\t\t\t\tpending.shift();\n\t\t\t\t\t\t\t\tpending.push(m[1] as T);\n\t\t\t\t\t\t\t\trecordDrop();\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\trecordDrop();\n\t\t\t\t\t\t\t\tresetForTerminal();\n\t\t\t\t\t\t\t\ta.down([[ERROR, new RateLimiterOverflowError(maxBuffer)]]);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpending.push(m[1] as T);\n\t\t\t\t\t\t\tsyncState();\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttryEmit();\n\t\t\t\t\t} else if (t === RESOLVED) a.down([[RESOLVED]]);\n\t\t\t\t\telse if (t === COMPLETE) {\n\t\t\t\t\t\tresetForTerminal();\n\t\t\t\t\t\ta.down([[COMPLETE]]);\n\t\t\t\t\t} else if (t === ERROR) {\n\t\t\t\t\t\tresetForTerminal();\n\t\t\t\t\t\ta.down([m]);\n\t\t\t\t\t} else if (t === TEARDOWN) {\n\t\t\t\t\t\tresetForTerminal();\n\t\t\t\t\t\ta.down([m]);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} else a.down([m]);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn () => {\n\t\t\t\tterminated = true;\n\t\t\t\ttimer.cancel();\n\t\t\t\tunsub();\n\t\t\t\toptMirror.unsub();\n\t\t\t};\n\t\t},\n\t\t{\n\t\t\t...operatorOpts(),\n\t\t\tinitial: source.cache,\n\t\t\tmeta: {\n\t\t\t\t// Caller-supplied meta first; companion seeds + factoryTag\n\t\t\t\t// override below so they always win.\n\t\t\t\t...(isReactive ? {} : ((opts as RateLimiterOptions).meta ?? {})),\n\t\t\t\tdroppedCount: 0,\n\t\t\t\trateLimitState: RATE_LIMITER_INITIAL_STATE,\n\t\t\t\t...factoryTag(\"rateLimiter\", isReactive ? { reactiveOpts: true } : opts),\n\t\t\t},\n\t\t},\n\t);\n\n\treturn {\n\t\tnode: out,\n\t\tdroppedCount: out.meta.droppedCount as Node<number>,\n\t\trateLimitState: out.meta.rateLimitState as Node<RateLimiterState>,\n\t};\n}\n\n/**\n * RingBuffer-backed queue adapter — exposes the small `{ push, shift, size }`\n * shape rateLimiter needs without leaking the rest of `RingBuffer`'s API.\n */\nfunction ringBufferQueue<T>(capacity: number): {\n\tpush: (v: T) => void;\n\tshift: () => T | undefined;\n\tsize: number;\n} {\n\tconst buf = new RingBuffer<T>(capacity);\n\treturn {\n\t\tpush: (v: T) => buf.push(v),\n\t\tshift: () => buf.shift(),\n\t\tget size(): number {\n\t\t\treturn buf.size;\n\t\t},\n\t} as { push: (v: T) => void; shift: () => T | undefined; size: number };\n}\n\n/**\n * Plain-array fallback queue for `maxBuffer: Infinity`. Accepts the O(N) shift\n * cost — the caller opted in to unbounded growth.\n */\nfunction makeArrayQueue<T>(): {\n\tpush: (v: T) => void;\n\tshift: () => T | undefined;\n\tsize: number;\n} {\n\tconst arr: T[] = [];\n\treturn {\n\t\tpush: (v: T) => {\n\t\t\tarr.push(v);\n\t\t},\n\t\tshift: () => arr.shift(),\n\t\tget size(): number {\n\t\t\treturn arr.length;\n\t\t},\n\t} as { push: (v: T) => void; shift: () => T | undefined; size: number };\n}\n","/**\n * Adaptive rate limiter — reactive, live-tunable, 429-aware.\n *\n * Wraps two `tokenBucket` instances (requests, tokens) with:\n * - Reactive `rpm` / `tpm` knobs that can be re-tuned at runtime via `NodeInput<number>`.\n * - An adaptation signal input (`Node<RateLimitSignal>`) that feeds back\n * provider 429 / retry-after / x-ratelimit-* headers to tighten limits.\n * - A `clampCooldownMs` TTL on signal-induced caps so a transient 429 doesn't\n * permanently throttle — caps decay back to user-configured values after\n * the cooldown elapses.\n * - TPM-miss recovery: consumed RPM tokens are returned to the request\n * bucket when the TPM admit fails, via `TokenBucket.putBack`.\n * - Imperative `acquire()` for bridging to Promise-based call paths\n * (used by the `withRateLimiter` adapter middleware).\n *\n * **Timer policy:** sleeps use `ResettableTimer` (documented spec §5.10\n * escape hatch in `src/extra/timer.ts`) rather than `fromTimer` to avoid\n * allocating a new Node per acquire cycle.\n *\n * Design lives in `docs/optimizations.md` § \"Reactive adaptive rate limiter\".\n */\n\nimport { DATA, monotonicNs, type Node, node, ResettableTimer } from \"@graphrefly/pure-ts/core\";\nimport { fromAny, type NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport { NS_PER_SEC } from \"../../base/resilience/backoff.js\";\nimport { type TokenBucket, tokenBucket } from \"./rate-limiter.js\";\n\n// ---------------------------------------------------------------------------\n// Signal shape\n// ---------------------------------------------------------------------------\n\n/**\n * Rate-limit signal emitted by an adaptation source (e.g., an HTTP 429 parser).\n *\n * Any subset of fields may be present. The adaptive rate limiter uses:\n * - `retryAfterMs` — blocks acquire() for this duration.\n * - `rpmCap` / `tpmCap` — tightens effective rpm/tpm to this value (decays\n * back to the user-configured cap after `clampCooldownMs`).\n * - `usageHint` — updates the last-known rpm/tpm usage ratio for logging.\n */\nexport interface RateLimitSignal {\n\t/** Throttle duration — pause acquire() for this long. */\n\tretryAfterMs?: number;\n\t/** Hard cap for requests-per-minute; effective rpm = min(current, rpmCap) while clamp is active. */\n\trpmCap?: number;\n\t/** Hard cap for tokens-per-minute; effective tpm = min(current, tpmCap) while clamp is active. */\n\ttpmCap?: number;\n\t/** Observed usage-percentage hint (0..1) — for observability, not gating. */\n\tusageHint?: { rpm?: number; tpm?: number };\n\t/** Free-form provider-specific payload. */\n\tmetadata?: Record<string, unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface AdaptiveRateLimiterOptions {\n\tname?: string;\n\t/** Effective requests-per-minute cap. Reactive — reads push-on-subscribe. */\n\trpm?: NodeInput<number>;\n\t/** Effective tokens-per-minute cap. Reactive. */\n\ttpm?: NodeInput<number>;\n\t/** Source of adaptation signals (429 parser output, etc.). */\n\tadaptation?: NodeInput<RateLimitSignal>;\n\t/**\n\t * How long (ms) a signal-induced `rpmCap` / `tpmCap` stays in effect before\n\t * relaxing back to the user-configured value. Default 60_000 (one minute).\n\t * Set to `Infinity` to make signal caps sticky until manually cleared.\n\t * A fresh signal with the same cap resets the cooldown.\n\t */\n\tclampCooldownMs?: number;\n\t/** Burst capacity overshoot above the steady-state rpm/tpm. Default 1 (no burst). */\n\tburstMultiplier?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Bundle\n// ---------------------------------------------------------------------------\n\nexport interface AdaptiveRateLimiterBundle {\n\t/** Effective requests-per-minute (post-signal-clamp). Reactive. */\n\treadonly effectiveRpm: Node<number>;\n\t/** Effective tokens-per-minute (post-signal-clamp). Reactive. */\n\treadonly effectiveTpm: Node<number>;\n\t/** Last adaptation signal observed. */\n\treadonly lastSignal: Node<RateLimitSignal>;\n\t/** Pending `acquire()` callers waiting for capacity. */\n\treadonly pending: Node<number>;\n\t/** Current request-token-bucket fill (approximate). */\n\treadonly rpmAvailable: Node<number>;\n\t/** Current token-bucket fill (approximate). */\n\treadonly tpmAvailable: Node<number>;\n\t/**\n\t * Imperative bridge: wait until `requestCost` request-tokens and\n\t * `tokenCost` tokens are available, then consume them. Honors the\n\t * most recent `retryAfterMs` from adaptation signals. Rejects with\n\t * an `AbortError`-named error if `signal` aborts while waiting.\n\t * `requestCost` defaults to 1; `tokenCost` defaults to 0 (rpm-only gating).\n\t */\n\tacquire(opts?: { requestCost?: number; tokenCost?: number; signal?: AbortSignal }): Promise<void>;\n\t/**\n\t * Feed back observed token usage (post-call) so the TPM bucket reflects\n\t * real consumption rather than the pre-call estimate. A positive `delta`\n\t * debits additional TPM (undershot estimate); a negative `delta` credits\n\t * back overshoot (`putBack`).\n\t */\n\trecordUsage(delta: number): void;\n\t/** Manually feed an adaptation signal — useful for tests. */\n\trecordSignal(sig: RateLimitSignal): void;\n\t/** Dispose internal subscriptions and pending timers. */\n\tdispose(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Error construction\n// ---------------------------------------------------------------------------\n\nfunction makeAbortError(reason: string): Error {\n\tconst err = new Error(reason) as Error & { name: string };\n\terr.name = \"AbortError\";\n\treturn err;\n}\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\n/**\n * Create an adaptive rate limiter. Compose with any call source via\n * `await limiter.acquire({ requestCost, tokenCost, signal })`.\n */\nexport function adaptiveRateLimiter(\n\topts: AdaptiveRateLimiterOptions = {},\n): AdaptiveRateLimiterBundle {\n\tconst burst = Math.max(1, opts.burstMultiplier ?? 1);\n\tconst clampCooldownMs = opts.clampCooldownMs ?? 60_000;\n\n\t// Resolve reactive rpm/tpm inputs. Callers may pass `NodeInput` which\n\t// could be a literal number or a Node. `fromAny` normalizes to a Node.\n\tconst rpmInputNode =\n\t\topts.rpm != null\n\t\t\t? fromAny(opts.rpm as NodeInput<number>)\n\t\t\t: node<number>([], { initial: Number.POSITIVE_INFINITY });\n\tconst tpmInputNode =\n\t\topts.tpm != null\n\t\t\t? fromAny(opts.tpm as NodeInput<number>)\n\t\t\t: node<number>([], { initial: Number.POSITIVE_INFINITY });\n\n\t// Signal cap state — updated by recordSignal() / adaptation source.\n\t// The decay timer relaxes the cap back to Infinity after `clampCooldownMs`.\n\tconst signalRpmCap = node<number>([], {\n\t\tinitial: Number.POSITIVE_INFINITY,\n\t\tname: \"adaptiveRateLimiter/signalRpmCap\",\n\t});\n\tconst signalTpmCap = node<number>([], {\n\t\tinitial: Number.POSITIVE_INFINITY,\n\t\tname: \"adaptiveRateLimiter/signalTpmCap\",\n\t});\n\tconst lastSignal = node<RateLimitSignal>([], {\n\t\tinitial: {},\n\t\tname: \"adaptiveRateLimiter/lastSignal\",\n\t});\n\n\t// Compute effective rpm/tpm: min of user-configured cap and signal cap.\n\tconst effectiveRpm = node<number>(\n\t\t[rpmInputNode, signalRpmCap],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tactions.emit(Math.min(Number(data[0] ?? Infinity), Number(data[1] ?? Infinity)));\n\t\t},\n\t\t{ name: \"adaptiveRateLimiter/effectiveRpm\", describeKind: \"derived\" },\n\t);\n\tconst effectiveTpm = node<number>(\n\t\t[tpmInputNode, signalTpmCap],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tactions.emit(Math.min(Number(data[0] ?? Infinity), Number(data[1] ?? Infinity)));\n\t\t},\n\t\t{ name: \"adaptiveRateLimiter/effectiveTpm\", describeKind: \"derived\" },\n\t);\n\n\t// Token buckets — rebuilt when effective caps change.\n\tlet rpmBucket: TokenBucket = makeBucket(\n\t\tNumber(rpmInputNode.cache ?? Number.POSITIVE_INFINITY),\n\t\tburst,\n\t);\n\tlet tpmBucket: TokenBucket = makeBucket(\n\t\tNumber(tpmInputNode.cache ?? Number.POSITIVE_INFINITY),\n\t\tburst,\n\t);\n\n\t// A signal `rpmCap`/`tpmCap` of 0 means \"halt admission entirely\" (e.g.,\n\t// some providers emit this during hard quota exhaustion). We honor it by\n\t// marking the bucket as closed via a long throttle-until; the bucket itself\n\t// stays at its previous capacity so decay can relax it naturally.\n\tlet rpmHardStop = false;\n\tlet tpmHardStop = false;\n\n\tconst unsubRpm = effectiveRpm.subscribe((msgs) => {\n\t\tfor (const msg of msgs) {\n\t\t\tif (msg[0] === DATA) {\n\t\t\t\tconst v = Number(msg[1]);\n\t\t\t\tif (Number.isFinite(v) && v > 0) {\n\t\t\t\t\trpmBucket = makeBucket(v, burst);\n\t\t\t\t\trpmHardStop = false;\n\t\t\t\t} else if (v === Infinity) {\n\t\t\t\t\trpmBucket = makeBucket(Infinity, burst);\n\t\t\t\t\trpmHardStop = false;\n\t\t\t\t} else if (v <= 0) {\n\t\t\t\t\t// Hard stop — no admission until cap relaxes.\n\t\t\t\t\trpmHardStop = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\tconst unsubTpm = effectiveTpm.subscribe((msgs) => {\n\t\tfor (const msg of msgs) {\n\t\t\tif (msg[0] === DATA) {\n\t\t\t\tconst v = Number(msg[1]);\n\t\t\t\tif (Number.isFinite(v) && v > 0) {\n\t\t\t\t\ttpmBucket = makeBucket(v, burst);\n\t\t\t\t\ttpmHardStop = false;\n\t\t\t\t} else if (v === Infinity) {\n\t\t\t\t\ttpmBucket = makeBucket(Infinity, burst);\n\t\t\t\t\ttpmHardStop = false;\n\t\t\t\t} else if (v <= 0) {\n\t\t\t\t\ttpmHardStop = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\t// Throttle-until: set by retryAfterMs signals.\n\tlet throttleUntilNs = 0;\n\n\t// Clamp-decay timers — when they fire, the signal cap is relaxed back to Infinity.\n\tconst rpmDecayTimer = new ResettableTimer();\n\tconst tpmDecayTimer = new ResettableTimer();\n\n\t// Adaptation source subscription.\n\tlet unsubAdapt: (() => void) | undefined;\n\tif (opts.adaptation != null) {\n\t\tconst adaptNode = fromAny(opts.adaptation as NodeInput<RateLimitSignal>);\n\t\tunsubAdapt = adaptNode.subscribe((msgs) => {\n\t\t\tfor (const msg of msgs) {\n\t\t\t\tif (msg[0] === DATA) applySignal(msg[1] as RateLimitSignal);\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction applySignal(sig: RateLimitSignal): void {\n\t\tlastSignal.emit(sig);\n\t\t// Accept `rpmCap`/`tpmCap` of 0 as a valid hard-stop signal. Only\n\t\t// reject non-finite caps (NaN/Infinity).\n\t\tif (sig.rpmCap != null && Number.isFinite(sig.rpmCap) && sig.rpmCap >= 0) {\n\t\t\tsignalRpmCap.emit(sig.rpmCap);\n\t\t\t// Schedule decay. Uses ResettableTimer — each new clamp resets the cooldown.\n\t\t\tif (Number.isFinite(clampCooldownMs) && clampCooldownMs > 0) {\n\t\t\t\trpmDecayTimer.start(clampCooldownMs, () => signalRpmCap.emit(Number.POSITIVE_INFINITY));\n\t\t\t}\n\t\t}\n\t\tif (sig.tpmCap != null && Number.isFinite(sig.tpmCap) && sig.tpmCap >= 0) {\n\t\t\tsignalTpmCap.emit(sig.tpmCap);\n\t\t\tif (Number.isFinite(clampCooldownMs) && clampCooldownMs > 0) {\n\t\t\t\ttpmDecayTimer.start(clampCooldownMs, () => signalTpmCap.emit(Number.POSITIVE_INFINITY));\n\t\t\t}\n\t\t}\n\t\tif (sig.retryAfterMs != null && sig.retryAfterMs > 0) {\n\t\t\tconst resumeAt = monotonicNs() + sig.retryAfterMs * 1_000_000;\n\t\t\tif (resumeAt > throttleUntilNs) throttleUntilNs = resumeAt;\n\t\t}\n\t}\n\n\tconst pending = node<number>([], { initial: 0, name: \"adaptiveRateLimiter/pending\" });\n\tconst rpmAvailableNode = node<number>([], {\n\t\tinitial: Number.POSITIVE_INFINITY,\n\t\tname: \"adaptiveRateLimiter/rpmAvailable\",\n\t});\n\tconst tpmAvailableNode = node<number>([], {\n\t\tinitial: Number.POSITIVE_INFINITY,\n\t\tname: \"adaptiveRateLimiter/tpmAvailable\",\n\t});\n\n\tconst bumpPending = (delta: number): void => {\n\t\tpending.emit((pending.cache ?? 0) + delta);\n\t};\n\tconst refreshAvailable = (): void => {\n\t\trpmAvailableNode.emit(rpmBucket.available());\n\t\ttpmAvailableNode.emit(tpmBucket.available());\n\t};\n\n\tasync function acquire(\n\t\tacquireOpts: { requestCost?: number; tokenCost?: number; signal?: AbortSignal } = {},\n\t): Promise<void> {\n\t\tconst requestCost = acquireOpts.requestCost ?? 1;\n\t\tconst tokenCost = acquireOpts.tokenCost ?? 0;\n\t\tconst abortSignal = acquireOpts.signal;\n\n\t\tbumpPending(1);\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tif (abortSignal?.aborted) throw makeAbortError(\"AdaptiveRateLimiter.acquire aborted\");\n\n\t\t\t\t// Honor retry-after window.\n\t\t\t\tconst now = monotonicNs();\n\t\t\t\tif (throttleUntilNs > now) {\n\t\t\t\t\tconst waitMs = Math.ceil((throttleUntilNs - now) / 1_000_000);\n\t\t\t\t\tawait sleepReactive(waitMs, abortSignal);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Hard-stop (cap=0) → wait for the decay timer to relax.\n\t\t\t\tif ((requestCost > 0 && rpmHardStop) || (tokenCost > 0 && tpmHardStop)) {\n\t\t\t\t\tawait sleepReactive(250, abortSignal);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Capture local refs so a concurrent rpm/tpm cap-change rebuilding\n\t\t\t\t// the bucket doesn't send `putBack` to a different bucket than\n\t\t\t\t// `tryConsume` debited. If the cap relaxes mid-flight, the OLD\n\t\t\t\t// bucket gets the credit (safe — it's closed over a closure the\n\t\t\t\t// new acquires don't see), and new acquires pick up the new\n\t\t\t\t// bucket on their own next iteration.\n\t\t\t\tconst rpmAtAcquire = rpmBucket;\n\t\t\t\tconst tpmAtAcquire = tpmBucket;\n\n\t\t\t\t// Try consume RPM first.\n\t\t\t\tconst gotRpm = rpmAtAcquire.tryConsume(requestCost);\n\t\t\t\tif (!gotRpm) {\n\t\t\t\t\tawait sleepReactive(estimateWaitMs(rpmAtAcquire, requestCost), abortSignal);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Then TPM — if it fails, return the RPM token (no wasted slot).\n\t\t\t\tconst gotTpm = tokenCost > 0 ? tpmAtAcquire.tryConsume(tokenCost) : true;\n\t\t\t\tif (!gotTpm) {\n\t\t\t\t\trpmAtAcquire.putBack(requestCost);\n\t\t\t\t\tawait sleepReactive(estimateWaitMs(tpmAtAcquire, tokenCost), abortSignal);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\trefreshAvailable();\n\t\t\t\treturn;\n\t\t\t}\n\t\t} finally {\n\t\t\tbumpPending(-1);\n\t\t}\n\t}\n\n\tfunction recordUsage(delta: number): void {\n\t\tif (delta > 0) {\n\t\t\t// Undershoot: debit additional tokens. Non-blocking — if it fails, the\n\t\t\t// next acquire will just wait longer.\n\t\t\ttpmBucket.tryConsume(delta);\n\t\t} else if (delta < 0) {\n\t\t\t// Overshoot: credit back.\n\t\t\ttpmBucket.putBack(-delta);\n\t\t}\n\t\trefreshAvailable();\n\t}\n\n\tfunction dispose(): void {\n\t\tunsubRpm();\n\t\tunsubTpm();\n\t\tunsubAdapt?.();\n\t\trpmDecayTimer.cancel();\n\t\ttpmDecayTimer.cancel();\n\t}\n\n\treturn {\n\t\teffectiveRpm,\n\t\teffectiveTpm,\n\t\tlastSignal,\n\t\tpending,\n\t\trpmAvailable: rpmAvailableNode,\n\t\ttpmAvailable: tpmAvailableNode,\n\t\tacquire,\n\t\trecordUsage,\n\t\trecordSignal: applySignal,\n\t\tdispose,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------\n\nfunction makeBucket(perMinute: number, burst: number): TokenBucket {\n\tif (!Number.isFinite(perMinute) || perMinute === Infinity) {\n\t\treturn tokenBucket(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);\n\t}\n\tconst capacity = Math.max(1, perMinute * burst);\n\tconst refillPerSecond = perMinute / 60;\n\treturn tokenBucket(capacity, refillPerSecond);\n}\n\nfunction estimateWaitMs(bucket: TokenBucket, needed: number): number {\n\tconst have = bucket.available();\n\tconst deficit = Math.max(0, needed - have);\n\tif (deficit <= 0) return 25; // retry quickly; primary path already failed so pacing is forced\n\t// Heuristic: wait 100ms per missing unit, clamped.\n\treturn Math.min(5_000, Math.max(50, deficit * 100));\n}\n\n/**\n * Promise-based sleep using `ResettableTimer` (spec §5.10 escape hatch).\n * Cleanly removes abort listener on both the timer-fires and abort paths;\n * no leaked `AbortSignal.addEventListener` registrations.\n */\nfunction sleepReactive(ms: number, signal?: AbortSignal): Promise<void> {\n\tif (ms <= 0) return Promise.resolve();\n\tif (signal?.aborted) return Promise.reject(makeAbortError(\"AdaptiveRateLimiter.acquire aborted\"));\n\treturn new Promise((resolve, reject) => {\n\t\tconst timer = new ResettableTimer();\n\t\tlet onAbort: (() => void) | undefined;\n\t\tconst cleanup = (): void => {\n\t\t\ttimer.cancel();\n\t\t\tif (signal && onAbort) signal.removeEventListener(\"abort\", onAbort);\n\t\t};\n\t\ttimer.start(ms, () => {\n\t\t\tcleanup();\n\t\t\tresolve();\n\t\t});\n\t\tif (signal) {\n\t\t\tonAbort = (): void => {\n\t\t\t\tcleanup();\n\t\t\t\treject(makeAbortError(\"AdaptiveRateLimiter.acquire aborted\"));\n\t\t\t};\n\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t}\n\t});\n}\n\nexport { NS_PER_SEC };\n","/**\n * `withBudgetGate` — cap an adapter by calls / tokens / USD.\n *\n * Totals are an O(1)-per-event running accumulator (a `state<BudgetTotals>`\n * updated imperatively inside `record()`), not a derived reduce over the\n * full log — avoids the quadratic cost at sustained traffic while preserving\n * the reactive surface. The full log is still exposed via the bundle for\n * dashboards / auditors.\n *\n * Budgets are enforced imperatively at `invoke()` / `stream()` entry — the\n * running totals + `isOpen.cache` are read; if closed, the call rejects /\n * throws `BudgetExhaustedError` without hitting the wrapped adapter. On\n * success, the call's usage is appended to the log AND debits the running\n * totals in a single synchronous update.\n *\n * Wave A Unit 11 Q4: rejected-Promise path now wires `.catch` (via\n * `adaptInvokeResult.onError`) so failed invoke calls record a CallStatsEvent\n * with `error` populated. Prior code silently dropped rejection from the\n * `totals` / `log` surface.\n */\n\nimport { DATA, monotonicNs, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { keepalive, type ReactiveLogBundle, reactiveLog } from \"@graphrefly/pure-ts/extra\";\nimport {\n\tadapterWrapper,\n\tadaptInvokeResult,\n\tbuildCallStats,\n\temptyUsageStub,\n\twithLayer,\n} from \"../_internal/wrappers.js\";\nimport type { CallStatsEvent } from \"../core/observable.js\";\nimport type { PricingFn } from \"../core/pricing.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n\tStreamDelta,\n\tTokenUsage,\n} from \"../core/types.js\";\nimport { sumInputTokens, sumOutputTokens } from \"../core/types.js\";\n\nexport class BudgetExhaustedError extends Error {\n\toverride name = \"BudgetExhaustedError\";\n\tconstructor(\n\t\tpublic readonly which: string,\n\t\tpublic readonly limit: number,\n\t\tpublic readonly observed: number,\n\t) {\n\t\tsuper(`Budget exhausted: ${which} (limit=${limit}, observed=${observed})`);\n\t}\n}\n\nexport interface BudgetCaps {\n\tcalls?: number;\n\tinputTokens?: number;\n\toutputTokens?: number;\n\tusd?: number;\n}\n\nexport interface BudgetTotals {\n\tcalls: number;\n\tinputTokens: number;\n\toutputTokens: number;\n\tusd: number;\n}\n\nexport interface LLMBudgetGateBundle {\n\ttotals: Node<BudgetTotals>;\n\tisOpen: Node<boolean>;\n\tlog: ReactiveLogBundle<CallStatsEvent>;\n\treset(): void;\n\t/**\n\t * QA D2 (Phase 13.6.B QA pass): release every long-lived\n\t * subscription this gate holds — `keepalive(isOpen)`, the optional\n\t * `onExhausted` subscription, and the Lock 3.C abort fan-out\n\t * subscription on `isOpen`. Aborts any in-flight controllers as a\n\t * defensive last gasp so callers waiting on a soon-to-be-disposed\n\t * adapter don't hang.\n\t *\n\t * Idempotent: subsequent calls are no-ops. After `dispose()` the\n\t * adapter wrapper continues to wrap `inner.invoke` / `inner.stream`\n\t * but the budget machinery is best-effort: `record()` no longer\n\t * emits `totals` updates, abort fan-out no longer fires. Treat the\n\t * bundle as terminated once disposed; long-running apps should\n\t * `dispose()` per gate instance to avoid the sub-leak documented\n\t * in `docs/optimizations.md`.\n\t */\n\tdispose(): void;\n}\n\nexport interface WithBudgetGateOptions {\n\tcaps: BudgetCaps;\n\t/**\n\t * Optional pricing function for USD gating. If omitted, `caps.usd` is\n\t * ignored (caps.calls / caps.inputTokens / caps.outputTokens still apply).\n\t */\n\tpricingFn?: PricingFn;\n\t/**\n\t * Edge-triggered: fires exactly once when the gate transitions from\n\t * open to closed. Subsequent invoke/stream attempts against a closed\n\t * gate do NOT re-fire `onExhausted` — use the reactive `isOpen` node\n\t * if you need per-attempt notifications. Receives the cap key that\n\t * triggered the transition.\n\t */\n\tonExhausted?: (which: keyof BudgetCaps) => void;\n\t/** Name for logs / describe output. */\n\tname?: string;\n\t/** Max events retained in the log (default 1000). */\n\tlogMax?: number;\n}\n\n// Frozen baseline shared for `totals.cache ?? EMPTY_TOTALS` reads. Consumers\n// that mutate their snapshot in place would otherwise poison every budget-gate\n// instance in the process. `reset()` emits a freshly-constructed object so\n// downstream identity-equals checks on the frozen constant don't false-equal.\nconst EMPTY_TOTALS: Readonly<BudgetTotals> = Object.freeze({\n\tcalls: 0,\n\tinputTokens: 0,\n\toutputTokens: 0,\n\tusd: 0,\n});\nconst makeEmptyTotals = (): BudgetTotals => ({\n\tcalls: 0,\n\tinputTokens: 0,\n\toutputTokens: 0,\n\tusd: 0,\n});\n\n/**\n * Wrap an adapter with budget enforcement. Returns `{adapter, budget}` so\n * callers can subscribe to the bundle for dashboards.\n */\nexport function withBudgetGate(\n\tinner: LLMAdapter,\n\topts: WithBudgetGateOptions,\n): { adapter: LLMAdapter; budget: LLMBudgetGateBundle } {\n\tconst log = reactiveLog<CallStatsEvent>(undefined, {\n\t\tname: opts.name ? `${opts.name}/log` : \"budgetGate/log\",\n\t\tmaxSize: opts.logMax ?? 1000,\n\t});\n\n\t// O(1) running totals — incremented per `record()` rather than reduced over\n\t// the full log. Reactive surface preserved via `state<BudgetTotals>`.\n\tconst totals = node<BudgetTotals>([], {\n\t\tname: opts.name ? `${opts.name}/totals` : \"budgetGate/totals\",\n\t\tinitial: makeEmptyTotals(),\n\t});\n\n\tconst isOpen = node<boolean>(\n\t\t[totals],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst tt = data[0] as BudgetTotals;\n\t\t\tif (opts.caps.calls != null && tt.calls >= opts.caps.calls) {\n\t\t\t\tactions.emit(false);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (opts.caps.inputTokens != null && tt.inputTokens >= opts.caps.inputTokens) {\n\t\t\t\tactions.emit(false);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (opts.caps.outputTokens != null && tt.outputTokens >= opts.caps.outputTokens) {\n\t\t\t\tactions.emit(false);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (opts.caps.usd != null && tt.usd >= opts.caps.usd) {\n\t\t\t\tactions.emit(false);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tactions.emit(true);\n\t\t},\n\t\t{\n\t\t\tdescribeKind: \"derived\",\n\t\t\tname: opts.name ? `${opts.name}/isOpen` : \"budgetGate/isOpen\",\n\t\t\tinitial: true,\n\t\t},\n\t);\n\t// QA D2: capture every subscription/keepalive disposer so `dispose()`\n\t// can release the lot. Pre-D2 these were leaked for the process\n\t// lifetime; the leak grew with B9's abort-wire subscription.\n\tconst disposers: Array<() => void> = [];\n\tlet disposed = false;\n\t// Keep the isOpen derived live so `.cache` stays current without an external subscriber.\n\tdisposers.push(keepalive(isOpen));\n\n\t// Edge-trigger `onExhausted` on the open→closed transition. Subscribing\n\t// here (instead of firing from `buildClosedError`) ensures the callback\n\t// fires exactly once per transition, regardless of how many invoke/stream\n\t// attempts hit the closed gate afterward. Callers that want per-attempt\n\t// notifications should subscribe to `isOpen` directly.\n\tif (opts.onExhausted != null) {\n\t\tconst handler = opts.onExhausted;\n\t\t// Seed `wasOpen` from the FIRST observed DATA rather than assuming\n\t\t// `true`. If caps are already exhausted at construction (e.g.\n\t\t// `calls: 0` or a pre-filled totals source), the push-on-subscribe\n\t\t// DATA=`false` would otherwise be interpreted as an open→closed\n\t\t// transition and fire `onExhausted` before any invoke has been\n\t\t// attempted. `seeded` guards that first observation.\n\t\tlet seeded = false;\n\t\tlet wasOpen = true;\n\t\tconst unsub = isOpen.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\tconst v = m[1] as boolean;\n\t\t\t\t\tif (seeded && wasOpen && v === false) {\n\t\t\t\t\t\tconst which = pickExhaustedKey(totals.cache ?? EMPTY_TOTALS, opts.caps);\n\t\t\t\t\t\tif (which) handler(which);\n\t\t\t\t\t}\n\t\t\t\t\twasOpen = v;\n\t\t\t\t\tseeded = true;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tdisposers.push(unsub);\n\t}\n\n\tconst buildClosedError = (): BudgetExhaustedError | undefined => {\n\t\tif (isOpen.cache === false) {\n\t\t\tconst t = totals.cache ?? EMPTY_TOTALS;\n\t\t\tconst which = pickExhaustedKey(t, opts.caps);\n\t\t\treturn new BudgetExhaustedError(\n\t\t\t\twhich ?? \"budget\",\n\t\t\t\topts.caps[which ?? \"calls\"] ?? 0,\n\t\t\t\twhichValue(t, which ?? \"calls\"),\n\t\t\t);\n\t\t}\n\t\treturn undefined;\n\t};\n\n\tconst record = (\n\t\tusage: TokenUsage,\n\t\tmeta: {\n\t\t\tmodel: string;\n\t\t\ttier?: string;\n\t\t\tstartNs: number;\n\t\t\tmethod: \"invoke\" | \"stream\";\n\t\t\terror?: { type: string; message: string };\n\t\t},\n\t): void => {\n\t\tconst provider = inner.provider;\n\t\tconst event: CallStatsEvent = buildCallStats({\n\t\t\tprovider,\n\t\t\tmodel: meta.model,\n\t\t\ttier: meta.tier,\n\t\t\tusage,\n\t\t\tstartNs: meta.startNs,\n\t\t\tmethod: meta.method,\n\t\t\t...(meta.error ? { error: meta.error } : {}),\n\t\t});\n\t\tlog.append(event);\n\t\tconst prev = totals.cache ?? EMPTY_TOTALS;\n\t\tconst usd = opts.pricingFn\n\t\t\t? prev.usd + opts.pricingFn(usage, { model: meta.model, provider, tier: meta.tier }).total\n\t\t\t: prev.usd;\n\t\ttotals.emit({\n\t\t\tcalls: prev.calls + 1,\n\t\t\tinputTokens: prev.inputTokens + sumInputTokens(usage),\n\t\t\toutputTokens: prev.outputTokens + sumOutputTokens(usage),\n\t\t\tusd,\n\t\t});\n\t};\n\n\tconst reset = (): void => {\n\t\tlog.clear();\n\t\ttotals.emit(makeEmptyTotals());\n\t};\n\n\t// Lock 3.C (Phase 13.6.B): auto-wire adapter abort. Track in-flight\n\t// controllers so the open→closed transition can cancel calls that\n\t// started before the budget exhausted. Encodes L2.42-honest-cost's\n\t// \"two pieces needed\" rule (observability bubble + auto-wired abort)\n\t// into the primitive itself — no manual hookup required.\n\t//\n\t// DS-14.5 / AB-1: honoring `opts.signal` is now a hard adapter\n\t// contract (the `abortCapable` flag + this dev-mode warning were\n\t// removed pre-1.0). The budget gate fans out the AbortSignal on\n\t// exhaustion and every adapter is required to cancel its underlying\n\t// I/O — no escape hatch, no silent burn-through.\n\tconst inflight = new Set<AbortController>();\n\tlet isOpenSeeded = false;\n\tlet isOpenWasOpen = true;\n\tconst isOpenAbortUnsub = isOpen.subscribe((msgs) => {\n\t\tfor (const m of msgs) {\n\t\t\tif (m[0] !== DATA) continue;\n\t\t\tconst v = m[1] as boolean;\n\t\t\tif (isOpenSeeded && isOpenWasOpen && v === false && inflight.size > 0) {\n\t\t\t\tconst reason = buildClosedError() ?? new Error(\"budget exhausted\");\n\t\t\t\tfor (const ctrl of inflight) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tctrl.abort(reason);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t/* best-effort abort fan-out */\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tisOpenWasOpen = v;\n\t\t\tisOpenSeeded = true;\n\t\t}\n\t});\n\tdisposers.push(isOpenAbortUnsub);\n\n\tfunction combineSignals(callerSignal: AbortSignal | undefined): {\n\t\tctrl: AbortController;\n\t\tcleanup: () => void;\n\t} {\n\t\tconst ctrl = new AbortController();\n\t\t// If the budget is already closed when invoke starts, abort\n\t\t// immediately so the inner call never starts.\n\t\tif (isOpen.cache === false) {\n\t\t\tctrl.abort(buildClosedError() ?? new Error(\"budget exhausted\"));\n\t\t}\n\t\tconst onCallerAbort = (): void => {\n\t\t\tif (!ctrl.signal.aborted) ctrl.abort((callerSignal as AbortSignal).reason);\n\t\t};\n\t\tif (callerSignal != null) {\n\t\t\tif (callerSignal.aborted) {\n\t\t\t\tctrl.abort(callerSignal.reason);\n\t\t\t} else {\n\t\t\t\tcallerSignal.addEventListener(\"abort\", onCallerAbort, { once: true });\n\t\t\t}\n\t\t}\n\t\tinflight.add(ctrl);\n\t\tconst cleanup = (): void => {\n\t\t\tinflight.delete(ctrl);\n\t\t\tif (callerSignal != null) callerSignal.removeEventListener(\"abort\", onCallerAbort);\n\t\t};\n\t\treturn { ctrl, cleanup };\n\t}\n\n\tconst wrap: LLMAdapter = adapterWrapper(inner, {\n\t\tinvoke(messages, invokeOpts) {\n\t\t\tconst closedErr = buildClosedError();\n\t\t\tif (closedErr) return Promise.reject(closedErr);\n\t\t\tconst startNs = monotonicNs();\n\t\t\tconst model = inner.model ?? invokeOpts?.model ?? \"\";\n\t\t\tconst { ctrl, cleanup } = combineSignals(invokeOpts?.signal);\n\t\t\tconst recordResp = (resp: LLMResponse): LLMResponse => {\n\t\t\t\tcleanup();\n\t\t\t\trecord(resp.usage ?? emptyUsageStub(), {\n\t\t\t\t\tmodel: inner.model ?? invokeOpts?.model ?? resp.model ?? \"\",\n\t\t\t\t\ttier: invokeOpts?.tier ?? resp.tier,\n\t\t\t\t\tstartNs,\n\t\t\t\t\tmethod: \"invoke\",\n\t\t\t\t});\n\t\t\t\treturn resp;\n\t\t\t};\n\t\t\tconst recordErr = (err: unknown): void => {\n\t\t\t\tcleanup();\n\t\t\t\tconst e = err as Error | undefined;\n\t\t\t\trecord(emptyUsageStub(), {\n\t\t\t\t\tmodel,\n\t\t\t\t\ttier: invokeOpts?.tier,\n\t\t\t\t\tstartNs,\n\t\t\t\t\tmethod: \"invoke\",\n\t\t\t\t\terror: { type: e?.name ?? \"Error\", message: e?.message ?? String(err) },\n\t\t\t\t});\n\t\t\t};\n\t\t\tconst innerOpts = { ...(invokeOpts ?? {}), signal: ctrl.signal };\n\t\t\treturn adaptInvokeResult(inner.invoke(messages, innerOpts), {\n\t\t\t\tonResp: recordResp,\n\t\t\t\tonError: recordErr,\n\t\t\t\tname: \"budgetGate/invokeTap\",\n\t\t\t});\n\t\t},\n\n\t\tasync *stream(messages, invokeOpts): AsyncGenerator<StreamDelta> {\n\t\t\tconst closedErr = buildClosedError();\n\t\t\tif (closedErr) throw closedErr;\n\t\t\tconst startNs = monotonicNs();\n\t\t\tlet finalUsage: TokenUsage | undefined;\n\t\t\tconst { ctrl, cleanup } = combineSignals(invokeOpts?.signal);\n\t\t\tconst innerOpts = { ...(invokeOpts ?? {}), signal: ctrl.signal };\n\t\t\ttry {\n\t\t\t\tfor await (const delta of inner.stream(messages, innerOpts)) {\n\t\t\t\t\tif (delta.type === \"usage\") finalUsage = delta.usage;\n\t\t\t\t\tyield delta;\n\t\t\t\t}\n\t\t\t\tcleanup();\n\t\t\t\trecord(finalUsage ?? emptyUsageStub(), {\n\t\t\t\t\tmodel: inner.model ?? invokeOpts?.model ?? \"\",\n\t\t\t\t\ttier: invokeOpts?.tier,\n\t\t\t\t\tstartNs,\n\t\t\t\t\tmethod: \"stream\",\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tcleanup();\n\t\t\t\tconst error = err as Error;\n\t\t\t\trecord(finalUsage ?? emptyUsageStub(), {\n\t\t\t\t\tmodel: inner.model ?? invokeOpts?.model ?? \"\",\n\t\t\t\t\ttier: invokeOpts?.tier,\n\t\t\t\t\tstartNs,\n\t\t\t\t\tmethod: \"stream\",\n\t\t\t\t\terror: { type: error?.name ?? \"Error\", message: error?.message ?? String(err) },\n\t\t\t\t});\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t},\n\t});\n\n\twithLayer(wrap, \"withBudgetGate\", inner);\n\n\tconst dispose = (): void => {\n\t\tif (disposed) return;\n\t\tdisposed = true;\n\t\t// Defensive last gasp: abort any in-flight controllers so the\n\t\t// awaited Promises don't strand their callers waiting on a soon-\n\t\t// to-be-disposed adapter.\n\t\tconst reason = new Error(\"withBudgetGate disposed\");\n\t\tfor (const ctrl of inflight) {\n\t\t\ttry {\n\t\t\t\tctrl.abort(reason);\n\t\t\t} catch {\n\t\t\t\t/* best-effort */\n\t\t\t}\n\t\t}\n\t\tinflight.clear();\n\t\tfor (const d of disposers) {\n\t\t\ttry {\n\t\t\t\td();\n\t\t\t} catch {\n\t\t\t\t/* best-effort */\n\t\t\t}\n\t\t}\n\t\tdisposers.length = 0;\n\t};\n\n\treturn { adapter: wrap, budget: { totals, isOpen, log, reset, dispose } };\n}\n\nfunction pickExhaustedKey(t: BudgetTotals, caps: BudgetCaps): keyof BudgetCaps | undefined {\n\tif (caps.calls != null && t.calls >= caps.calls) return \"calls\";\n\tif (caps.inputTokens != null && t.inputTokens >= caps.inputTokens) return \"inputTokens\";\n\tif (caps.outputTokens != null && t.outputTokens >= caps.outputTokens) return \"outputTokens\";\n\tif (caps.usd != null && t.usd >= caps.usd) return \"usd\";\n\treturn undefined;\n}\n\nfunction whichValue(t: BudgetTotals, which: keyof BudgetCaps): number {\n\tswitch (which) {\n\t\tcase \"calls\":\n\t\t\treturn t.calls;\n\t\tcase \"inputTokens\":\n\t\t\treturn t.inputTokens;\n\t\tcase \"outputTokens\":\n\t\t\treturn t.outputTokens;\n\t\tcase \"usd\":\n\t\t\treturn t.usd;\n\t}\n}\n\nexport type { ChatMessage, LLMInvokeOptions };\n","/**\n * `withDryRun` — short-circuit to a fake adapter when a flag is on.\n *\n * Useful for CI / preflight / cost-safety pipelines: wrap a real adapter,\n * pass `enabled: true` (or a reactive flag) to bypass the wire call. Default\n * shim is {@link dryRunAdapter}; callers can supply their own.\n *\n * **Returns `{adapter, dispose}`** — call `dispose()` to release the internal\n * keepalive on the reactive `enabled` input. Long-lived adapter instances\n * (module-level singletons) can ignore dispose; transient adapters (per-\n * request or per-user) should call it on teardown to allow the source to\n * be GC'd.\n */\n\nimport { fromAny, keepalive, type NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport { adapterWrapper, withLayer } from \"../_internal/wrappers.js\";\nimport type { LLMAdapter } from \"../core/types.js\";\nimport { dryRunAdapter } from \"../providers/dry-run.js\";\n\nexport interface WithDryRunOptions {\n\t/**\n\t * Toggle — `true` always dry-runs; `false` always passes through; a\n\t * `NodeInput<boolean>` reads the current value at call time (factory-time\n\t * seed pattern, live-tunable).\n\t */\n\tenabled: NodeInput<boolean>;\n\t/** Dry-run adapter override. Default: `dryRunAdapter({ provider: inner.provider, model: inner.model })`. */\n\tmock?: LLMAdapter;\n}\n\nexport interface WithDryRunBundle {\n\tadapter: LLMAdapter;\n\t/**\n\t * Release the internal keepalive subscription on the reactive `enabled`\n\t * input. Idempotent. Safe to ignore on long-lived adapters.\n\t */\n\tdispose(): void;\n}\n\nexport function withDryRun(inner: LLMAdapter, opts: WithDryRunOptions): WithDryRunBundle {\n\tconst mock = opts.mock ?? dryRunAdapter({ provider: inner.provider, model: inner.model });\n\n\t// Normalize the enabled input: literal boolean stays literal; NodeInput<boolean>\n\t// gets bridged so we can read .cache at call time (factory-time seed per\n\t// COMPOSITION-GUIDE §28). Keep the node alive so push-on-subscribe and\n\t// derived-chain recomputation keep the cache current — otherwise a reactive\n\t// flag would stay at its initial value forever.\n\tconst enabledLiteral = typeof opts.enabled === \"boolean\" ? (opts.enabled as boolean) : undefined;\n\tconst enabledNode =\n\t\tenabledLiteral === undefined ? fromAny(opts.enabled as NodeInput<boolean>) : undefined;\n\tlet unsubKeepalive: (() => void) | undefined;\n\tif (enabledNode) unsubKeepalive = keepalive(enabledNode);\n\n\tconst isEnabled = (): boolean => {\n\t\tif (enabledLiteral !== undefined) return enabledLiteral;\n\t\treturn Boolean(enabledNode?.cache);\n\t};\n\n\tconst adapter: LLMAdapter = adapterWrapper(inner, {\n\t\tinvoke(messages, invokeOpts) {\n\t\t\treturn isEnabled() ? mock.invoke(messages, invokeOpts) : inner.invoke(messages, invokeOpts);\n\t\t},\n\n\t\tstream(messages, invokeOpts) {\n\t\t\treturn isEnabled() ? mock.stream(messages, invokeOpts) : inner.stream(messages, invokeOpts);\n\t\t},\n\t});\n\twithLayer(adapter, \"withDryRun\", inner);\n\n\tconst dispose = (): void => {\n\t\tif (unsubKeepalive) {\n\t\t\tunsubKeepalive();\n\t\t\tunsubKeepalive = undefined;\n\t\t}\n\t};\n\n\treturn { adapter, dispose };\n}\n","/**\n * HTTP 429 / rate-limit parser.\n *\n * Produces a {@link RateLimitSignal} from provider HTTP errors so adaptive\n * rate limiters can tighten effective limits. Normalizes:\n * - `Retry-After` (seconds or HTTP-date)\n * - `x-ratelimit-reset` / `x-ratelimit-reset-tokens` (epoch secs or duration)\n * - `x-ratelimit-remaining-{requests,tokens}` + `x-ratelimit-limit-*`\n * - Anthropic `anthropic-ratelimit-*` headers\n * - OpenAI / OpenRouter / Groq headers (same family)\n * - Error message regex fallbacks for providers without structured headers\n */\n\nimport type { RateLimitSignal } from \"../../../resilience/adaptive-rate-limiter.js\";\n\nexport interface HttpErrorLike {\n\tstatus?: number;\n\theaders?: Headers | Record<string, string | string[] | undefined>;\n\tmessage?: string;\n}\n\n/**\n * Extract a {@link RateLimitSignal} from a fetch-style error object, a Response,\n * or any object exposing `.status` + `.headers` + `.message`.\n *\n * Returns `undefined` if no rate-limit information can be extracted.\n */\nexport function parseRateLimitFromError(err: unknown): RateLimitSignal | undefined {\n\tif (err == null || typeof err !== \"object\") return undefined;\n\tconst like = err as HttpErrorLike;\n\tconst status = like.status;\n\tconst headerLookup = toHeaderGetter(like.headers);\n\n\t// Only respond on 429 or 503 (some providers use 503 for rate-limits).\n\tif (status !== 429 && status !== 503 && !looksLikeRateLimitMessage(like.message)) {\n\t\treturn undefined;\n\t}\n\n\tconst sig: RateLimitSignal = {};\n\n\tconst retryAfter = headerLookup(\"retry-after\");\n\tconst retryAfterMs = parseRetryAfter(retryAfter);\n\tif (retryAfterMs != null) sig.retryAfterMs = retryAfterMs;\n\n\t// Anthropic: anthropic-ratelimit-requests-reset (ISO-8601 timestamp)\n\tconst anthReqReset = headerLookup(\"anthropic-ratelimit-requests-reset\");\n\tif (anthReqReset) {\n\t\tconst ms = parseIsoResetHeaderToDelayMs(anthReqReset);\n\t\tif (ms != null) sig.retryAfterMs = Math.max(sig.retryAfterMs ?? 0, ms);\n\t}\n\tconst anthTokReset = headerLookup(\"anthropic-ratelimit-tokens-reset\");\n\tif (anthTokReset) {\n\t\tconst ms = parseIsoResetHeaderToDelayMs(anthTokReset);\n\t\tif (ms != null) sig.retryAfterMs = Math.max(sig.retryAfterMs ?? 0, ms);\n\t}\n\n\t// OpenAI / OpenRouter / Groq: x-ratelimit-limit-requests, -reset-requests, etc.\n\tconst limitRequests = numHeader(headerLookup, \"x-ratelimit-limit-requests\");\n\tif (limitRequests != null) sig.rpmCap = limitRequests;\n\tconst limitTokens = numHeader(headerLookup, \"x-ratelimit-limit-tokens\");\n\tif (limitTokens != null) sig.tpmCap = limitTokens;\n\n\t// Usage hint: remaining / limit\n\tconst remainingReq = numHeader(headerLookup, \"x-ratelimit-remaining-requests\");\n\tconst remainingTok = numHeader(headerLookup, \"x-ratelimit-remaining-tokens\");\n\tif (remainingReq != null && limitRequests != null && limitRequests > 0) {\n\t\tsig.usageHint ??= {};\n\t\tsig.usageHint.rpm = 1 - remainingReq / limitRequests;\n\t}\n\tif (remainingTok != null && limitTokens != null && limitTokens > 0) {\n\t\tsig.usageHint ??= {};\n\t\tsig.usageHint.tpm = 1 - remainingTok / limitTokens;\n\t}\n\n\t// Fallback: parse retry-after from error message if no header was found.\n\tif (sig.retryAfterMs == null && like.message) {\n\t\tconst msgMs = parseRetryAfterFromMessage(like.message);\n\t\tif (msgMs != null) sig.retryAfterMs = msgMs;\n\t}\n\n\t// Preserve raw headers for user-specific downstream logic.\n\tif (like.headers) sig.metadata = { headers: serializeHeaders(like.headers) };\n\n\tif (\n\t\tsig.retryAfterMs == null &&\n\t\tsig.rpmCap == null &&\n\t\tsig.tpmCap == null &&\n\t\tsig.usageHint == null\n\t) {\n\t\t// Nothing actionable extracted — still emit empty signal so consumers can\n\t\t// count occurrences (metadata carries the headers).\n\t\treturn sig.metadata ? sig : undefined;\n\t}\n\n\treturn sig;\n}\n\n// ---------------------------------------------------------------------------\n// Header access\n// ---------------------------------------------------------------------------\n\ntype HeaderGetter = (name: string) => string | undefined;\n\nfunction toHeaderGetter(h: HttpErrorLike[\"headers\"]): HeaderGetter {\n\tif (!h) return () => undefined;\n\tif (typeof (h as Headers).get === \"function\") {\n\t\tconst hh = h as Headers;\n\t\treturn (name) => hh.get(name) ?? hh.get(name.toLowerCase()) ?? undefined;\n\t}\n\tconst record = h as Record<string, string | string[] | undefined>;\n\tconst lc: Record<string, string | undefined> = {};\n\tfor (const [k, v] of Object.entries(record)) {\n\t\tconst sv = Array.isArray(v) ? v.join(\", \") : v;\n\t\tif (sv != null) lc[k.toLowerCase()] = sv;\n\t}\n\treturn (name) => lc[name.toLowerCase()];\n}\n\nfunction serializeHeaders(h: NonNullable<HttpErrorLike[\"headers\"]>): Record<string, string> {\n\tconst out: Record<string, string> = {};\n\tif (typeof (h as Headers).forEach === \"function\") {\n\t\t(h as Headers).forEach((v, k) => {\n\t\t\tout[k] = v;\n\t\t});\n\t\treturn out;\n\t}\n\tfor (const [k, v] of Object.entries(h as Record<string, string | string[] | undefined>)) {\n\t\tif (v != null) out[k] = Array.isArray(v) ? v.join(\", \") : v;\n\t}\n\treturn out;\n}\n\nfunction numHeader(getter: HeaderGetter, name: string): number | undefined {\n\tconst raw = getter(name);\n\tif (raw == null) return undefined;\n\tconst n = Number(raw);\n\treturn Number.isFinite(n) ? n : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Retry-after parsing\n// ---------------------------------------------------------------------------\n\nfunction parseRetryAfter(raw: string | undefined): number | undefined {\n\tif (!raw) return undefined;\n\tconst trimmed = raw.trim();\n\tconst asNum = Number(trimmed);\n\tif (Number.isFinite(asNum) && asNum >= 0) return asNum * 1000;\n\t// HTTP-date fallback.\n\tconst ts = Date.parse(trimmed);\n\tif (Number.isFinite(ts)) {\n\t\tconst delta = ts - Date.now();\n\t\tif (delta > 0) return delta;\n\t}\n\treturn undefined;\n}\n\n/**\n * Parse an Anthropic `anthropic-ratelimit-{requests,tokens}-reset` header\n * into a delay (milliseconds until reset). These headers are documented\n * as ISO-8601 absolute timestamps; we use `Date.parse` and clamp to zero\n * for headers that have already elapsed. Returns `undefined` for unparseable\n * values — no numeric-epoch heuristic (providers don't send numeric resets\n * here, and the old heuristic was ambiguous across seconds-vs-millis).\n */\nfunction parseIsoResetHeaderToDelayMs(raw: string): number | undefined {\n\tif (!raw) return undefined;\n\tconst ts = Date.parse(raw);\n\tif (Number.isFinite(ts)) return Math.max(0, ts - Date.now());\n\treturn undefined;\n}\n\nconst RETRY_MSG_RE = /retry\\s+(?:in|after)\\s+(\\d+(?:\\.\\d+)?)\\s*(ms|s|sec|seconds?|m|min|minutes?)/i;\n\nfunction parseRetryAfterFromMessage(msg: string): number | undefined {\n\tconst m = RETRY_MSG_RE.exec(msg);\n\tif (!m) return undefined;\n\tconst n = Number(m[1]);\n\tif (!Number.isFinite(n)) return undefined;\n\tconst unit = (m[2] ?? \"s\").toLowerCase();\n\tif (unit === \"ms\") return n;\n\tif (unit.startsWith(\"s\")) return n * 1000;\n\tif (unit.startsWith(\"m\")) return n * 60_000;\n\treturn undefined;\n}\n\nconst RATE_LIMIT_MSG_RE = /rate\\s*limit|too\\s*many\\s*requests|quota|429/i;\n\nfunction looksLikeRateLimitMessage(msg: string | undefined): boolean {\n\treturn !!msg && RATE_LIMIT_MSG_RE.test(msg);\n}\n","/**\n * `withRateLimiter` — adapter middleware bridging to the reactive\n * `adaptiveRateLimiter` primitive.\n *\n * - Consumes live `rpm`/`tpm` caps as reactive `NodeInput<number>` so\n * callers can retune at runtime (e.g. from a `ModelLimits.rpm` node).\n * - Adapts to provider 429 responses via `http429Parser` fed into the\n * limiter's `adaptation` signal.\n * - `costFn` estimates token cost pre-call (e.g. char-based approximation);\n * the post-call actual usage is fed back via `limiter.recordUsage()`.\n */\n\nimport { fromAny, type NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport { firstValueFrom } from \"../../../../base/sources/settled.js\";\nimport {\n\ttype AdaptiveRateLimiterBundle,\n\tadaptiveRateLimiter,\n\ttype RateLimitSignal,\n} from \"../../../resilience/adaptive-rate-limiter.js\";\nimport { adapterWrapper, withLayer } from \"../_internal/wrappers.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n\tStreamDelta,\n} from \"../core/types.js\";\nimport { emptyUsage, sumInputTokens, sumOutputTokens } from \"../core/types.js\";\nimport { parseRateLimitFromError } from \"./http429-parser.js\";\n\nexport interface WithRateLimiterOptions {\n\t/** Live rpm cap (defaults to `Infinity`). */\n\trpm?: NodeInput<number>;\n\t/** Live tpm cap (defaults to `Infinity`). */\n\ttpm?: NodeInput<number>;\n\t/**\n\t * Pre-call token-cost estimate. Default: 0 (only rpm gates). Override with\n\t * e.g. a char-based heuristic:\n\t * `(msgs) => Math.ceil(msgs.reduce((s, m) => s + m.content.length, 0) / 4)`.\n\t */\n\tcostFn?: (messages: readonly ChatMessage[], opts?: LLMInvokeOptions) => number;\n\t/**\n\t * Manual adaptation signal source. Defaults to a signal derived from\n\t * provider errors via `parseRateLimitFromError` — users can supply a\n\t * custom signal chain if they route errors elsewhere.\n\t */\n\tadaptation?: NodeInput<RateLimitSignal>;\n\tburstMultiplier?: number;\n\tname?: string;\n\t/**\n\t * Share an existing {@link AdaptiveRateLimiterBundle} across multiple\n\t * adapter wraps. When provided, `withRateLimiter` reuses this bundle\n\t * instead of constructing a new one — useful when the RPM/TPM cap is\n\t * logically per-provider but the caller wants to harden multiple adapters\n\t * (e.g. primary + fallback of the same vendor) against the shared cap.\n\t *\n\t * When `limiter` is set, `rpm` / `tpm` / `adaptation` / `burstMultiplier`\n\t * / `name` are ignored (the supplied bundle owns those). `costFn` is still\n\t * used per-wrap — each wrap supplies its own cost estimator.\n\t */\n\tlimiter?: AdaptiveRateLimiterBundle;\n}\n\n/**\n * Wrap an adapter with adaptive rate limiting. Returns `{adapter, limiter}`\n * so callers can subscribe to limiter internals (rpmAvailable, pending, etc.)\n * for dashboards.\n */\nexport function withRateLimiter(\n\tinner: LLMAdapter,\n\topts: WithRateLimiterOptions = {},\n): { adapter: LLMAdapter; limiter: AdaptiveRateLimiterBundle } {\n\tconst limiter =\n\t\topts.limiter ??\n\t\tadaptiveRateLimiter({\n\t\t\tname: opts.name ?? \"rateLimiter\",\n\t\t\trpm: opts.rpm,\n\t\t\ttpm: opts.tpm,\n\t\t\tadaptation: opts.adaptation,\n\t\t\tburstMultiplier: opts.burstMultiplier,\n\t\t});\n\n\tconst estimateCost = (\n\t\tmessages: readonly ChatMessage[],\n\t\tinvokeOpts: LLMInvokeOptions | undefined,\n\t): number => {\n\t\tif (opts.costFn) return opts.costFn(messages, invokeOpts);\n\t\treturn 0;\n\t};\n\n\tconst handleError = (err: unknown): void => {\n\t\tconst sig = parseRateLimitFromError(err);\n\t\tif (sig) limiter.recordSignal(sig);\n\t};\n\n\tconst wrap: LLMAdapter = adapterWrapper(inner, {\n\t\tasync invoke(messages, invokeOpts): Promise<LLMResponse> {\n\t\t\tconst tokenCost = estimateCost(messages, invokeOpts);\n\t\t\tawait limiter.acquire({ requestCost: 1, tokenCost, signal: invokeOpts?.signal });\n\t\t\ttry {\n\t\t\t\tconst resp = await firstValueFrom(fromAny(inner.invoke(messages, invokeOpts)));\n\t\t\t\tconst usage = resp.usage ?? emptyUsage();\n\t\t\t\tconst actual = sumInputTokens(usage) + sumOutputTokens(usage);\n\t\t\t\tconst delta = actual - tokenCost;\n\t\t\t\tif (delta > 0) limiter.recordUsage(delta);\n\t\t\t\treturn resp;\n\t\t\t} catch (err) {\n\t\t\t\thandleError(err);\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t},\n\n\t\tasync *stream(messages, invokeOpts): AsyncGenerator<StreamDelta> {\n\t\t\tconst tokenCost = estimateCost(messages, invokeOpts);\n\t\t\tawait limiter.acquire({ requestCost: 1, tokenCost, signal: invokeOpts?.signal });\n\t\t\ttry {\n\t\t\t\tlet finalTokens = 0;\n\t\t\t\tfor await (const delta of inner.stream(messages, invokeOpts)) {\n\t\t\t\t\tif (delta.type === \"usage\") {\n\t\t\t\t\t\tfinalTokens = sumInputTokens(delta.usage) + sumOutputTokens(delta.usage);\n\t\t\t\t\t}\n\t\t\t\t\tyield delta;\n\t\t\t\t}\n\t\t\t\tconst d = finalTokens - tokenCost;\n\t\t\t\tif (d > 0) limiter.recordUsage(d);\n\t\t\t} catch (err) {\n\t\t\t\thandleError(err);\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t},\n\t});\n\twithLayer(wrap, \"withRateLimiter\", inner);\n\n\treturn { adapter: wrap, limiter };\n}\n","/**\n * `cascadingLlmAdapter` — N-tier fallback over any mix of LLM adapters.\n *\n * Same structural pattern as `cascadingCache` and `Graph.attachSnapshotStorage`:\n * ordered list, first-success wins, per-tier breaker optional, filter gates\n * per request. Semantics:\n *\n * - `invoke()`: try tier 0 first. On error (or breaker-open), fall through\n * to tier 1, 2, ... until one succeeds or all fail.\n * - `stream()`: tries to start the stream on tier 0; once tokens begin, it\n * commits — failures in mid-stream surface rather than re-starting on the\n * next tier (would double-bill and confuse consumers). **State-machine\n * consumers (usage accounting, UI accumulators) must handle errors in a\n * catch block — no synthetic `{type: \"finish\"}` is emitted after a thrown\n * stream error.**\n * - `filter`: skips a tier for requests that use features it doesn't\n * support (e.g., Chrome Nano can't do tool use).\n * - `breaker`: per-tier circuit; when open, cascade treats the tier as\n * unavailable and moves on immediately.\n *\n * On exhaustion, throws `AllTiersExhaustedError` with separate `skipped` and\n * `failed` collections so consumers can distinguish \"no tier applicable\"\n * from \"all tiers failed\".\n */\n\nimport { fromAny } from \"@graphrefly/pure-ts/extra\";\nimport { firstValueFrom } from \"../../../../base/sources/settled.js\";\nimport {\n\ttype CircuitBreaker,\n\ttype CircuitBreakerOptions,\n\tcircuitBreaker,\n} from \"../../../../utils/resilience/index.js\";\nimport { withLayer } from \"../_internal/wrappers.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n\tStreamDelta,\n} from \"../core/types.js\";\n\nexport interface AdapterTier {\n\tname: string;\n\tadapter: LLMAdapter;\n\t/** Per-tier circuit breaker. If omitted, no breaker on this tier. */\n\tbreaker?: CircuitBreakerOptions | CircuitBreaker;\n\t/** Skip this tier when the request doesn't fit (e.g. Chrome Nano + tools). */\n\tfilter?: (messages: readonly ChatMessage[], opts?: LLMInvokeOptions) => boolean;\n}\n\nexport interface CascadeExhaustionReport {\n\t/** Tiers that never ran (filter returned false, or breaker was open). */\n\treadonly skipped: ReadonlyArray<{ name: string; reason: \"filter\" | \"breaker\" }>;\n\t/** Tiers that ran and threw. */\n\treadonly failed: ReadonlyMap<string, unknown>;\n}\n\nexport interface CascadingLlmAdapterOptions {\n\tonFallback?: (from: string, to: string, error: unknown) => void;\n\tonExhausted?: (report: CascadeExhaustionReport) => void;\n\t/** Whether to attempt stream retry on subsequent tiers before first chunk. Default true. */\n\tstreamRetryBeforeFirstChunk?: boolean;\n}\n\ninterface ResolvedTier {\n\tname: string;\n\tadapter: LLMAdapter;\n\tbreaker?: CircuitBreaker;\n\tfilter?: (messages: readonly ChatMessage[], opts?: LLMInvokeOptions) => boolean;\n}\n\nexport class AllTiersExhaustedError extends Error {\n\toverride name = \"AllTiersExhaustedError\";\n\treadonly skipped: ReadonlyArray<{ name: string; reason: \"filter\" | \"breaker\" }>;\n\treadonly failed: ReadonlyMap<string, unknown>;\n\tconstructor(report: CascadeExhaustionReport) {\n\t\tconst parts: string[] = [];\n\t\tif (report.failed.size > 0) parts.push(`failed=[${[...report.failed.keys()].join(\",\")}]`);\n\t\tif (report.skipped.length > 0) {\n\t\t\tparts.push(`skipped=[${report.skipped.map((s) => `${s.name}(${s.reason})`).join(\",\")}]`);\n\t\t}\n\t\tsuper(`All LLM adapter tiers exhausted: ${parts.join(\" \")}`);\n\t\tthis.skipped = report.skipped;\n\t\tthis.failed = report.failed;\n\t}\n}\n\nexport function cascadingLlmAdapter(\n\ttiers: readonly AdapterTier[],\n\topts: CascadingLlmAdapterOptions = {},\n): LLMAdapter {\n\tif (tiers.length === 0) throw new RangeError(\"cascadingLlmAdapter: tiers must be non-empty\");\n\n\tconst resolved: ResolvedTier[] = tiers.map((t) => ({\n\t\tname: t.name,\n\t\tadapter: t.adapter,\n\t\tfilter: t.filter,\n\t\tbreaker: t.breaker\n\t\t\t? \"canExecute\" in t.breaker\n\t\t\t\t? (t.breaker as CircuitBreaker)\n\t\t\t\t: circuitBreaker(t.breaker as CircuitBreakerOptions)\n\t\t\t: undefined,\n\t}));\n\n\tconst streamRetryBeforeFirstChunk = opts.streamRetryBeforeFirstChunk ?? true;\n\n\tconst cascade: LLMAdapter = {\n\t\tprovider: \"cascading\",\n\t\tmodel: undefined,\n\n\t\tasync invoke(messages, invokeOpts): Promise<LLMResponse> {\n\t\t\tconst skipped: Array<{ name: string; reason: \"filter\" | \"breaker\" }> = [];\n\t\t\tconst failed = new Map<string, unknown>();\n\t\t\tfor (let i = 0; i < resolved.length; i++) {\n\t\t\t\tconst t = resolved[i];\n\t\t\t\tif (t.filter && !t.filter(messages, invokeOpts)) {\n\t\t\t\t\tskipped.push({ name: t.name, reason: \"filter\" });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (t.breaker && !t.breaker.canExecute()) {\n\t\t\t\t\tskipped.push({ name: t.name, reason: \"breaker\" });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tconst resp = await firstValueFrom(fromAny(t.adapter.invoke(messages, invokeOpts)));\n\t\t\t\t\tt.breaker?.recordSuccess();\n\t\t\t\t\treturn { ...resp, metadata: { ...(resp.metadata ?? {}), tier: t.name } };\n\t\t\t\t} catch (err) {\n\t\t\t\t\tfailed.set(t.name, err);\n\t\t\t\t\tt.breaker?.recordFailure(err);\n\t\t\t\t\tconst next = resolved[i + 1];\n\t\t\t\t\tif (next) opts.onFallback?.(t.name, next.name, err);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst report: CascadeExhaustionReport = { skipped, failed };\n\t\t\topts.onExhausted?.(report);\n\t\t\tthrow new AllTiersExhaustedError(report);\n\t\t},\n\n\t\tasync *stream(messages, invokeOpts): AsyncGenerator<StreamDelta> {\n\t\t\tconst skipped: Array<{ name: string; reason: \"filter\" | \"breaker\" }> = [];\n\t\t\tconst failed = new Map<string, unknown>();\n\t\t\tfor (let i = 0; i < resolved.length; i++) {\n\t\t\t\tconst t = resolved[i];\n\t\t\t\tif (t.filter && !t.filter(messages, invokeOpts)) {\n\t\t\t\t\tskipped.push({ name: t.name, reason: \"filter\" });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (t.breaker && !t.breaker.canExecute()) {\n\t\t\t\t\tskipped.push({ name: t.name, reason: \"breaker\" });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tlet yieldedAny = false;\n\t\t\t\ttry {\n\t\t\t\t\tfor await (const delta of t.adapter.stream(messages, invokeOpts)) {\n\t\t\t\t\t\tyieldedAny = true;\n\t\t\t\t\t\tyield delta;\n\t\t\t\t\t}\n\t\t\t\t\tt.breaker?.recordSuccess();\n\t\t\t\t\treturn;\n\t\t\t\t} catch (err) {\n\t\t\t\t\tfailed.set(t.name, err);\n\t\t\t\t\tt.breaker?.recordFailure(err);\n\t\t\t\t\tif (yieldedAny || !streamRetryBeforeFirstChunk) {\n\t\t\t\t\t\t// Past first chunk — stream commitment. Propagate immediately.\n\t\t\t\t\t\t// Consumers handle the thrown error in their catch; no synthetic\n\t\t\t\t\t\t// finish delta is emitted (see JSDoc at top of file). We do NOT\n\t\t\t\t\t\t// call `onExhausted` here because other tiers were never tried —\n\t\t\t\t\t\t// the error is a single-tier commitment failure, not a\n\t\t\t\t\t\t// \"no-tier-worked\" condition.\n\t\t\t\t\t\tthrow err;\n\t\t\t\t\t}\n\t\t\t\t\tconst next = resolved[i + 1];\n\t\t\t\t\tif (next) opts.onFallback?.(t.name, next.name, err);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst report: CascadeExhaustionReport = { skipped, failed };\n\t\t\topts.onExhausted?.(report);\n\t\t\tthrow new AllTiersExhaustedError(report);\n\t\t},\n\t};\n\twithLayer(cascade, `cascade[${resolved.map((t) => t.name).join(\",\")}]`);\n\treturn cascade;\n}\n\n/**\n * Tiny type-safe constructor for an {@link AdapterTier}. Cleans up the\n * heterogeneous array-type cast users (and `browser-presets.ts`) had to write\n * by hand. Per Wave A Unit 13 decision.\n *\n * @example\n * ```ts\n * cascadingLlmAdapter([\n * tier(\"local\", webllmAdapter(...)),\n * tier(\"cloud\", anthropicAdapter(...), { breaker: { failureThreshold: 5 } }),\n * ]);\n * ```\n *\n * @category ai\n */\nexport function tier(\n\tname: string,\n\tadapter: LLMAdapter,\n\topts?: { breaker?: CircuitBreakerOptions | CircuitBreaker; filter?: AdapterTier[\"filter\"] },\n): AdapterTier {\n\tconst out: AdapterTier = { name, adapter };\n\tif (opts?.breaker) out.breaker = opts.breaker;\n\tif (opts?.filter) out.filter = opts.filter;\n\treturn out;\n}\n","/**\n * `withRetry` — retry `invoke()` / `stream()` on transient errors.\n *\n * Streaming retry is tricky: we retry only if the stream fails before\n * yielding any tokens. Once tokens have started flowing, we surface the\n * error to avoid replaying from scratch (which would double-bill and\n * confuse consumers). Opt out of streaming retry via `opts.retryStreaming = false`.\n *\n * Uses `ResettableTimer` for backoff sleeps (spec §5.10 escape hatch, same\n * pattern as `extra/resilience.ts`). Abort-aware — early-aborts before the\n * first attempt and cleans up the abort listener on both the timer-fires\n * and abort paths.\n */\n\nimport { ResettableTimer } from \"@graphrefly/pure-ts/core\";\nimport { fromAny } from \"@graphrefly/pure-ts/extra\";\nimport { firstValueFrom } from \"../../../../base/sources/settled.js\";\nimport { adapterWrapper, withLayer } from \"../_internal/wrappers.js\";\nimport type { LLMAdapter, LLMResponse, StreamDelta } from \"../core/types.js\";\n\nexport interface WithRetryOptions {\n\t/** Max total attempts (including the first). Default 3. */\n\tattempts?: number;\n\t/** Base delay in ms. Default 500. */\n\tbaseDelayMs?: number;\n\t/** Max delay in ms. Default 10_000. */\n\tmaxDelayMs?: number;\n\t/**\n\t * Delay strategy. Default `\"decorrelated\"` — AWS-style `random(baseDelay,\n\t * min(maxDelay, prev * 3))` which smooths retry storms and matches common\n\t * SDK expectations. `\"exp\"` and `\"linear\"` produce deterministic schedules\n\t * when `jitter: false`.\n\t */\n\tstrategy?: \"exp\" | \"linear\" | \"decorrelated\";\n\t/**\n\t * Add randomized jitter. Ignored for `strategy: \"decorrelated\"` (which is\n\t * inherently jittered). For `exp`/`linear`, symmetric jitter in `[0.5x,\n\t * 1.5x]` of the nominal delay.\n\t */\n\tjitter?: boolean;\n\t/**\n\t * Predicate: should this error trigger a retry? Default retries network /\n\t * 5xx / 429 / transient errors, but not 4xx (other than 429), aborts, or\n\t * `BudgetExhaustedError` from upstream middleware.\n\t */\n\tshouldRetry?: (err: unknown, attempt: number) => boolean;\n\t/** Retry streaming calls if they fail pre-first-token. Default true. */\n\tretryStreaming?: boolean;\n}\n\nfunction makeAbortError(reason = \"aborted\"): Error {\n\tconst err = new Error(reason) as Error & { name: string };\n\terr.name = \"AbortError\";\n\treturn err;\n}\n\n/**\n * Promise-based abort-aware sleep using `ResettableTimer`.\n * Spec §5.10 escape hatch — same pattern as `extra/resilience.ts`.\n */\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\tif (ms <= 0) return Promise.resolve();\n\tif (signal?.aborted) return Promise.reject(makeAbortError());\n\treturn new Promise((resolve, reject) => {\n\t\tconst timer = new ResettableTimer();\n\t\tlet onAbort: (() => void) | undefined;\n\t\tconst cleanup = (): void => {\n\t\t\ttimer.cancel();\n\t\t\tif (signal && onAbort) signal.removeEventListener(\"abort\", onAbort);\n\t\t};\n\t\ttimer.start(ms, () => {\n\t\t\tcleanup();\n\t\t\tresolve();\n\t\t});\n\t\tif (signal) {\n\t\t\tonAbort = (): void => {\n\t\t\t\tcleanup();\n\t\t\t\treject(makeAbortError());\n\t\t\t};\n\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t}\n\t});\n}\n\nexport function withRetry(inner: LLMAdapter, opts: WithRetryOptions = {}): LLMAdapter {\n\tconst attempts = opts.attempts ?? 3;\n\tconst baseDelayMs = opts.baseDelayMs ?? 500;\n\tconst maxDelayMs = opts.maxDelayMs ?? 10_000;\n\tconst strategy = opts.strategy ?? \"decorrelated\";\n\tconst jitter = opts.jitter ?? true;\n\tconst shouldRetry = opts.shouldRetry ?? defaultShouldRetry;\n\tconst retryStreaming = opts.retryStreaming ?? true;\n\n\t// Decorrelated state — carried across the same acquire's retries.\n\tconst delay = (attempt: number, prevDelay: number): number => {\n\t\tif (strategy === \"decorrelated\") {\n\t\t\t// AWS-style: random(baseDelay, min(maxDelay, prevDelay * 3))\n\t\t\tconst upper = Math.min(maxDelayMs, Math.max(baseDelayMs, prevDelay * 3));\n\t\t\treturn baseDelayMs + Math.random() * (upper - baseDelayMs);\n\t\t}\n\t\tconst nominal = strategy === \"exp\" ? baseDelayMs * 2 ** (attempt - 1) : baseDelayMs * attempt;\n\t\tconst bounded = Math.min(maxDelayMs, nominal);\n\t\tif (!jitter) return bounded;\n\t\t// Symmetric jitter: bounded * [0.5, 1.5), clamped.\n\t\tconst jittered = bounded * (0.5 + Math.random());\n\t\treturn Math.min(maxDelayMs, jittered);\n\t};\n\n\tconst wrap = adapterWrapper(inner, {\n\t\tasync invoke(messages, invokeOpts): Promise<LLMResponse> {\n\t\t\tif (invokeOpts?.signal?.aborted) throw makeAbortError();\n\t\t\tlet lastErr: unknown;\n\t\t\tlet prevDelay = baseDelayMs;\n\t\t\tfor (let attempt = 1; attempt <= attempts; attempt++) {\n\t\t\t\ttry {\n\t\t\t\t\treturn await firstValueFrom(fromAny(inner.invoke(messages, invokeOpts)));\n\t\t\t\t} catch (err) {\n\t\t\t\t\tlastErr = err;\n\t\t\t\t\tif (attempt >= attempts || !shouldRetry(err, attempt)) throw err;\n\t\t\t\t\tconst waitMs = delay(attempt, prevDelay);\n\t\t\t\t\tprevDelay = waitMs;\n\t\t\t\t\tawait sleep(waitMs, invokeOpts?.signal);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow lastErr;\n\t\t},\n\n\t\tasync *stream(messages, invokeOpts): AsyncGenerator<StreamDelta> {\n\t\t\tif (invokeOpts?.signal?.aborted) throw makeAbortError();\n\t\t\tif (!retryStreaming) {\n\t\t\t\tfor await (const d of inner.stream(messages, invokeOpts)) yield d;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet lastErr: unknown;\n\t\t\tlet prevDelay = baseDelayMs;\n\t\t\tfor (let attempt = 1; attempt <= attempts; attempt++) {\n\t\t\t\tlet yieldedAny = false;\n\t\t\t\ttry {\n\t\t\t\t\tfor await (const d of inner.stream(messages, invokeOpts)) {\n\t\t\t\t\t\tyieldedAny = true;\n\t\t\t\t\t\tyield d;\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t} catch (err) {\n\t\t\t\t\tlastErr = err;\n\t\t\t\t\tif (yieldedAny) throw err;\n\t\t\t\t\tif (attempt >= attempts || !shouldRetry(err, attempt)) throw err;\n\t\t\t\t\tconst waitMs = delay(attempt, prevDelay);\n\t\t\t\t\tprevDelay = waitMs;\n\t\t\t\t\tawait sleep(waitMs, invokeOpts?.signal);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow lastErr;\n\t\t},\n\t});\n\twithLayer(wrap, \"withRetry\", inner);\n\treturn wrap;\n}\n\nfunction defaultShouldRetry(err: unknown, _attempt: number): boolean {\n\tif (err == null) return false;\n\tconst e = err as { name?: string; status?: number; code?: string; message?: string };\n\t// Timeout-family errors — retry by default so each attempt re-arms the\n\t// per-attempt deadline set by `withLLMTimeout`. Checked BEFORE the abort\n\t// guards below because `withLLMTimeout` re-throws its timer-fire path as\n\t// `LLMTimeoutError` even when the underlying fetch rejected with\n\t// AbortError.\n\tif (e.name === \"LLMTimeoutError\") return true;\n\t// Abort-family errors — never retry (caller initiated).\n\tif (e.name === \"AbortError\") return false;\n\tif (e.message === \"aborted\") return false;\n\tif (e.name === \"DOMException\" && e.code != null && Number(e.code) === 20 /* ABORT_ERR */) {\n\t\treturn false;\n\t}\n\tif (e.name === \"BudgetExhaustedError\") return false;\n\tif (e.name === \"CircuitOpenError\") return false;\n\tif (e.status != null) {\n\t\tif (e.status === 429) return true;\n\t\tif (e.status >= 500 && e.status < 600) return true;\n\t\treturn false;\n\t}\n\t// Network-level errors often have codes like ECONNRESET, ENOTFOUND, etc.\n\tif (e.code && typeof e.code === \"string\") {\n\t\tif (/^E[A-Z]+$/.test(e.code)) return true;\n\t}\n\tif (e.message) {\n\t\treturn /network|timeout|socket|fetch|econn|eai_/i.test(e.message);\n\t}\n\treturn false;\n}\n","/**\n * `withLLMTimeout` — cancel `invoke()` / `stream()` after `ms` elapse.\n *\n * Wires a child AbortSignal so provider adapters can honor the cancellation\n * (all shipped adapters forward `signal` through to their fetch / SDK call).\n *\n * Uses `ResettableTimer` rather than raw `setTimeout` — same pattern as\n * `extra/resilience.ts` (spec §5.10 escape hatch documented on the class).\n */\n\nimport { ResettableTimer } from \"@graphrefly/pure-ts/core\";\nimport { fromAny } from \"@graphrefly/pure-ts/extra\";\nimport { firstValueFrom } from \"../../../../base/sources/settled.js\";\nimport { adapterWrapper, withLayer } from \"../_internal/wrappers.js\";\nimport type { LLMAdapter, LLMResponse, StreamDelta } from \"../core/types.js\";\n\nexport class LLMTimeoutError extends Error {\n\toverride name = \"LLMTimeoutError\";\n\tconstructor(public readonly ms: number) {\n\t\tsuper(`LLM call timed out after ${ms}ms`);\n\t}\n}\n\nexport function withLLMTimeout(inner: LLMAdapter, ms: number): LLMAdapter {\n\tif (ms <= 0) throw new RangeError(\"withLLMTimeout: ms must be > 0\");\n\n\tconst linkedSignal = (\n\t\tparent?: AbortSignal,\n\t): {\n\t\tsignal: AbortSignal;\n\t\tcancel: () => void;\n\t\t/** `true` once our timer fired — distinguishes our-timeout vs external abort. */\n\t\ttimedOut: () => boolean;\n\t} => {\n\t\tconst ac = new AbortController();\n\t\tlet timerFired = false;\n\t\tlet onParentAbort: (() => void) | undefined;\n\t\tconst timer = new ResettableTimer();\n\t\t// Cancel the timer synchronously when the parent aborts — otherwise a\n\t\t// parent-abort at `t = ms - ε` followed by our timer firing at\n\t\t// `t = ms` would set `timerFired = true`, causing\n\t\t// `convertAbortToTimeout` to incorrectly promote the user-initiated\n\t\t// abort to an `LLMTimeoutError`.\n\t\tif (parent) {\n\t\t\tif (parent.aborted) ac.abort(parent.reason);\n\t\t\telse {\n\t\t\t\tonParentAbort = () => {\n\t\t\t\t\ttimer.cancel();\n\t\t\t\t\tac.abort(parent.reason);\n\t\t\t\t};\n\t\t\t\tparent.addEventListener(\"abort\", onParentAbort, { once: true });\n\t\t\t}\n\t\t}\n\t\ttimer.start(ms, () => {\n\t\t\ttimerFired = true;\n\t\t\tac.abort(new LLMTimeoutError(ms));\n\t\t});\n\t\treturn {\n\t\t\tsignal: ac.signal,\n\t\t\tcancel: () => {\n\t\t\t\ttimer.cancel();\n\t\t\t\tif (parent && onParentAbort) parent.removeEventListener(\"abort\", onParentAbort);\n\t\t\t},\n\t\t\ttimedOut: () => timerFired,\n\t\t};\n\t};\n\n\t/**\n\t * When our own timer fired, real `fetch`/SDK adapters reject with\n\t * `AbortError`/DOMException regardless of `signal.reason`. We convert\n\t * that rejection into {@link LLMTimeoutError} so downstream predicates\n\t * (notably {@link defaultShouldRetry}) can distinguish \"we hit the\n\t * deadline\" from \"caller aborted us\" without relying on the adapter\n\t * preserving `signal.reason`.\n\t *\n\t * External aborts bubble through unchanged so caller-supplied\n\t * `invokeOpts.signal` still propagates as an abort.\n\t */\n\tconst convertAbortToTimeout = (err: unknown, timedOut: boolean): never => {\n\t\tif (!timedOut) throw err;\n\t\tif (err instanceof LLMTimeoutError) throw err;\n\t\tconst e = err as { name?: string; code?: string | number };\n\t\tconst isAbort =\n\t\t\te?.name === \"AbortError\" ||\n\t\t\t(e?.name === \"DOMException\" && Number(e.code) === 20) /* ABORT_ERR */ ||\n\t\t\t(err as Error)?.message === \"aborted\";\n\t\tif (isAbort) {\n\t\t\tconst timeout = new LLMTimeoutError(ms);\n\t\t\t(timeout as Error & { cause?: unknown }).cause = err;\n\t\t\tthrow timeout;\n\t\t}\n\t\tthrow err;\n\t};\n\n\tconst wrap = adapterWrapper(inner, {\n\t\tasync invoke(messages, invokeOpts): Promise<LLMResponse> {\n\t\t\tconst { signal, cancel, timedOut } = linkedSignal(invokeOpts?.signal);\n\t\t\ttry {\n\t\t\t\treturn await firstValueFrom(fromAny(inner.invoke(messages, { ...invokeOpts, signal })));\n\t\t\t} catch (err) {\n\t\t\t\treturn convertAbortToTimeout(err, timedOut());\n\t\t\t} finally {\n\t\t\t\tcancel();\n\t\t\t}\n\t\t},\n\n\t\tasync *stream(messages, invokeOpts): AsyncGenerator<StreamDelta> {\n\t\t\tconst { signal, cancel, timedOut } = linkedSignal(invokeOpts?.signal);\n\t\t\ttry {\n\t\t\t\tfor await (const d of inner.stream(messages, { ...invokeOpts, signal })) yield d;\n\t\t\t} catch (err) {\n\t\t\t\tconvertAbortToTimeout(err, timedOut());\n\t\t\t} finally {\n\t\t\t\tcancel();\n\t\t\t}\n\t\t},\n\t});\n\twithLayer(wrap, \"withLLMTimeout\", inner);\n\treturn wrap;\n}\n","/**\n * `resilientAdapter` — compose `withRateLimiter` + `withBudgetGate` +\n * `withLLMBreaker` + `withLLMTimeout` + `withRetry` + fallback over an {@link LLMAdapter}.\n *\n * Call-path peer of {@link resilientPipeline} (which operates on a reactive\n * `Node<T>` chain). Use `resilientPipeline` when composing graph sources; use\n * `resilientAdapter` when wrapping an adapter so downstream users see a\n * single hardened `invoke`/`stream` surface.\n *\n * Composition order (innermost to outermost, mirrors `resilientPipeline`):\n *\n * ```text\n * rateLimit → budget → breaker → timeout → retry → fallback\n * ```\n *\n * Rationale:\n * - **rateLimit innermost** — each attempt acquires a fresh slot; a retry\n * after a 429 waits for admission rather than bursting past the cap.\n * - **budget next** — per-attempt gate close short-circuits retries once a\n * cap trips.\n * - **breaker next** — each attempt observes circuit health; open breaker\n * fast-fails retries into fallback.\n * - **timeout before retry** — each retry re-arms a fresh per-attempt\n * deadline. If `timeout` wrapped `retry`, a single deadline would cover\n * the entire retry chain — surprising for callers.\n * - **retry before fallback** — fallback is entered only after the primary\n * exhausts its retry budget (or immediately fails in a way the predicate\n * doesn't retry).\n *\n * Every option is optional — omit the field and that layer is skipped. The\n * returned bundle exposes the primary adapter plus the internal bundles\n * (`rateLimiter`, `budget`, `breaker`) so callers can wire them into\n * dashboards, alerts, or `graphLens`.\n *\n * Fallback is implemented via {@link cascadingLlmAdapter}: when `fallback`\n * is provided, the wrapped primary adapter is placed at tier 0 and the\n * fallback adapter at tier 1. For N-tier cascades, use `cascadingLlmAdapter`\n * directly and wrap each tier with `resilientAdapter`.\n *\n * @module\n */\n\nimport type { AdaptiveRateLimiterBundle } from \"../../../resilience/adaptive-rate-limiter.js\";\nimport type { CircuitBreaker } from \"../../../resilience/breaker.js\";\nimport type { LLMAdapter } from \"../core/types.js\";\nimport type { CascadeExhaustionReport } from \"../routing/cascading.js\";\nimport { cascadingLlmAdapter } from \"../routing/cascading.js\";\nimport { type WithBreakerOptions, withLLMBreaker } from \"./breaker.js\";\nimport {\n\ttype LLMBudgetGateBundle,\n\ttype WithBudgetGateOptions,\n\twithBudgetGate,\n} from \"./budget-gate.js\";\nimport { type WithRateLimiterOptions, withRateLimiter } from \"./rate-limiter.js\";\nimport { type WithReplayCacheOptions, withReplayCache } from \"./replay-cache.js\";\nimport { type WithRetryOptions, withRetry } from \"./retry.js\";\nimport { withLLMTimeout } from \"./timeout.js\";\n\n/** Options for {@link resilientAdapter}. Every field is optional — omit to skip that layer. */\nexport interface ResilientAdapterOptions {\n\t/** Admission control. See {@link withRateLimiter}. */\n\trateLimit?: WithRateLimiterOptions;\n\t/** Cost/cap gate. See {@link withBudgetGate}. */\n\tbudget?: WithBudgetGateOptions;\n\t/** Circuit breaker. See {@link withBreaker}. */\n\tbreaker?: WithBreakerOptions;\n\t/** Per-attempt deadline in milliseconds. Omit to skip the timeout wrap. */\n\ttimeoutMs?: number;\n\t/** Retry policy on transient errors. See {@link withRetry}. */\n\tretry?: WithRetryOptions;\n\t/**\n\t * Fallback adapter engaged when the primary (post-retry) fails. Implemented\n\t * via {@link cascadingLlmAdapter} — the primary becomes tier 0, the\n\t * fallback becomes tier 1. For N-tier cascades, use `cascadingLlmAdapter`\n\t * directly and wrap each tier with `resilientAdapter` as needed.\n\t */\n\tfallback?: LLMAdapter;\n\t/** Name used as the primary tier name in the fallback cascade. Default `\"primary\"`. */\n\tname?: string;\n\t/**\n\t * Called when the cascade switches from one tier to the next after a\n\t * failure. Only fires when `fallback` is set. Threaded directly to the\n\t * inner {@link cascadingLlmAdapter}.\n\t */\n\tonFallback?: (from: string, to: string, error: unknown) => void;\n\t/**\n\t * Called when every tier in the cascade has been exhausted (all failed,\n\t * skipped by filter, or skipped by breaker). Only fires when `fallback`\n\t * is set. Threaded directly to the inner {@link cascadingLlmAdapter}.\n\t */\n\tonExhausted?: (report: CascadeExhaustionReport) => void;\n\t/**\n\t * Content-addressed replay cache wrapped OUTERMOST — a cache HIT short-\n\t * circuits the entire stack (rate-limit / budget / breaker / retry /\n\t * fallback), saving money and latency. Cache MISSes flow through the\n\t * normal stack; the successful result is stored on success. See\n\t * {@link withReplayCache}.\n\t */\n\tcache?: WithReplayCacheOptions;\n}\n\n/** Output bundle of {@link resilientAdapter}. */\nexport interface ResilientAdapterBundle {\n\t/** The final hardened adapter. */\n\tadapter: LLMAdapter;\n\t/** Rate-limiter internals (for dashboards). Present only when `opts.rateLimit` was set. */\n\trateLimiter?: AdaptiveRateLimiterBundle;\n\t/** Budget gate internals (for dashboards). Present only when `opts.budget` was set. */\n\tbudget?: LLMBudgetGateBundle;\n\t/** Circuit breaker (for dashboards). Present only when `opts.breaker` was set. */\n\tbreaker?: CircuitBreaker;\n}\n\n/**\n * Wrap `inner` with the standard resilience stack. See module docs for the\n * composition order and rationale.\n *\n * @example\n * ```ts\n * const { adapter, budget, breaker } = resilientAdapter(openai, {\n * rateLimit: { rpm: 60, tpm: 90_000 },\n * budget: { caps: { usd: 5 } },\n * breaker: { failureThreshold: 5, resetTimeoutMs: 30_000 },\n * timeoutMs: 30_000,\n * retry: { attempts: 3 },\n * fallback: webllm, // cascades to local on exhaustion\n * });\n *\n * // `adapter` is drop-in for anything expecting LLMAdapter.\n * // Subscribe to `budget.totals`, `breaker.state`, etc. for dashboards.\n * ```\n */\nexport function resilientAdapter(\n\tinner: LLMAdapter,\n\topts: ResilientAdapterOptions = {},\n): ResilientAdapterBundle {\n\tconst bundle: ResilientAdapterBundle = { adapter: inner };\n\tlet current: LLMAdapter = inner;\n\n\tif (opts.rateLimit) {\n\t\tconst wrapped = withRateLimiter(current, opts.rateLimit);\n\t\tcurrent = wrapped.adapter;\n\t\tbundle.rateLimiter = wrapped.limiter;\n\t}\n\tif (opts.budget) {\n\t\tconst wrapped = withBudgetGate(current, opts.budget);\n\t\tcurrent = wrapped.adapter;\n\t\tbundle.budget = wrapped.budget;\n\t}\n\tif (opts.breaker) {\n\t\tconst wrapped = withLLMBreaker(current, opts.breaker);\n\t\tcurrent = wrapped.adapter;\n\t\tbundle.breaker = wrapped.breaker;\n\t}\n\tif (opts.timeoutMs != null) {\n\t\tcurrent = withLLMTimeout(current, opts.timeoutMs);\n\t}\n\tif (opts.retry) {\n\t\tcurrent = withRetry(current, opts.retry);\n\t}\n\tif (opts.fallback) {\n\t\t// Secondary tier is named `\"fallback\"` internally; reject the same\n\t\t// label as the primary name so CascadeExhaustionReport.failed (a\n\t\t// Map keyed by tier name) and `resp.metadata.tier` stamping stay\n\t\t// unambiguous.\n\t\tif (opts.name === \"fallback\") {\n\t\t\tthrow new RangeError(\n\t\t\t\t'resilientAdapter: `name` cannot be \"fallback\" — collides with the secondary tier label.',\n\t\t\t);\n\t\t}\n\t\tconst cascadeOpts: {\n\t\t\tonFallback?: (from: string, to: string, error: unknown) => void;\n\t\t\tonExhausted?: (report: CascadeExhaustionReport) => void;\n\t\t} = {};\n\t\tif (opts.onFallback) cascadeOpts.onFallback = opts.onFallback;\n\t\tif (opts.onExhausted) cascadeOpts.onExhausted = opts.onExhausted;\n\t\tcurrent = cascadingLlmAdapter(\n\t\t\t[\n\t\t\t\t{ name: opts.name ?? \"primary\", adapter: current },\n\t\t\t\t{ name: \"fallback\", adapter: opts.fallback },\n\t\t\t],\n\t\t\tcascadeOpts,\n\t\t);\n\t}\n\tif (opts.cache) {\n\t\t// Outermost — a cache HIT skips the entire stack below.\n\t\tcurrent = withReplayCache(current, opts.cache);\n\t}\n\n\tbundle.adapter = current;\n\treturn bundle;\n}\n","/**\n * `frozenContext` — prefix-cache-friendly snapshot of upstream context.\n *\n * @module\n */\n\nimport { factoryTag, type Node, node as nodeFactory } from \"@graphrefly/pure-ts/core\";\nimport { fromAny, type NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport { aiMeta } from \"../_internal.js\";\n\nexport type FrozenContextOptions = {\n\t/**\n\t * Reactive signal that triggers re-materialization. Each `DATA` emission\n\t * from this node re-reads the source and refreshes the frozen value.\n\t * Typical shapes: `fromTimer(ms)` for periodic refresh, a stage-transition\n\t * node for event-driven refresh, or a manual `state<number>` the caller\n\t * increments via `setState(n + 1)`.\n\t *\n\t * When omitted, the frozen value is materialized exactly once (on first\n\t * subscribe) and never refreshes for the lifetime of the activation —\n\t * use this for session-start snapshots that must stay stable. The\n\t * single-shot latch IS reset on `INVALIDATE` (graph-wide flush via\n\t * `graph.signal([[INVALIDATE]])`), so callers who need an \"evict and\n\t * re-materialize\" escape hatch get one through the standard graph\n\t * lifecycle without having to wire a `refreshTrigger`.\n\t */\n\trefreshTrigger?: NodeInput<unknown>;\n\tname?: string;\n};\n\n/**\n * Freeze a reactive source into a stable snapshot that only re-materializes\n * on explicit trigger. Built for long-running harness loops where system\n * prompts include `agentMemory` / stage context — every reactive change to\n * the source invalidates the LLM provider's prefix cache, so re-rendering\n * the prompt every turn is expensive.\n *\n * `frozenContext(source)` reads the source once and caches the value;\n * downstream `promptNode` compositions see a stable reference until the\n * optional `refreshTrigger` fires.\n *\n * Trade-off: slightly stale context vs. prefix cache hit rate. For most\n * harness apps, the memory snapshot at session start is \"good enough\" —\n * refreshing on a coarse-grained trigger (`fromCron(\"*\\/30min\")`, stage\n * transition) preserves 90%+ prefix cache hits while keeping context useful.\n *\n * @example\n * ```ts\n * // Freeze agent memory for the duration of a stage.\n * const frozen = frozenContext(memory.context, {\n * refreshTrigger: stage, // re-materialize on stage change\n * });\n * const reply = promptNode({ context: frozen, ... });\n * ```\n *\n * @category patterns.ai\n */\nexport function frozenContext<T>(\n\tsource: NodeInput<T>,\n\topts?: FrozenContextOptions,\n): Node<T | null> {\n\tconst src = fromAny(source);\n\tconst trigger = opts?.refreshTrigger != null ? fromAny(opts.refreshTrigger) : null;\n\n\t// JSON-serializable subset of opts: omit `refreshTrigger` (a NodeInput).\n\tconst frozenArgs: Record<string, unknown> | undefined =\n\t\topts?.name !== undefined ? { name: opts.name } : undefined;\n\tconst frozenTag = factoryTag(\"frozenContext\", frozenArgs);\n\n\t// Single-shot path: deps = [src] only. Emit the first src value and then\n\t// hold regardless of source drift.\n\tif (trigger == null) {\n\t\treturn nodeFactory<T | null>(\n\t\t\t[src],\n\t\t\t(data, actions, ctx) => {\n\t\t\t\tconst alreadyEmitted = ctx.store.emitted === true;\n\t\t\t\tif (alreadyEmitted) return;\n\t\t\t\tconst srcBatch = data[0];\n\t\t\t\tconst srcValue =\n\t\t\t\t\tsrcBatch != null && srcBatch.length > 0 ? srcBatch.at(-1) : ctx.prevData[0];\n\t\t\t\t// Only emit once src has produced a settled value.\n\t\t\t\tif (srcValue === undefined) return;\n\t\t\t\tctx.store.emitted = true;\n\t\t\t\tactions.emit(srcValue as T);\n\t\t\t\t// On INVALIDATE (graph-wide flush), reset the \"already emitted\"\n\t\t\t\t// latch so the next fn re-run captures a fresh snapshot.\n\t\t\t\t// Without this, INVALIDATE clears the cache but the latch stays\n\t\t\t\t// armed, so subscribers stay on the cleared (null) state forever.\n\t\t\t\t//\n\t\t\t\t// Lock 6.D (Phase 13.6.B): clear `emitted` on deactivation —\n\t\t\t\t// the pre-flip auto-wipe handled this implicitly.\n\t\t\t\t//\n\t\t\t\t// QA D1 (Phase 13.6.B QA pass): `onResubscribableReset` covers\n\t\t\t\t// the multi-sub-stayed terminal-resubscribable path where\n\t\t\t\t// `_deactivate` does NOT run but the lifecycle reset still\n\t\t\t\t// needs to clear the latch. Without this slot, a sibling sink\n\t\t\t\t// that keeps the node alive past terminal would pin\n\t\t\t\t// `emitted === true` into the next subscription cycle and\n\t\t\t\t// suppress every future emission.\n\t\t\t\tconst store = ctx.store;\n\t\t\t\treturn {\n\t\t\t\t\tonInvalidate: () => {\n\t\t\t\t\t\tstore.emitted = false;\n\t\t\t\t\t},\n\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\tdelete store.emitted;\n\t\t\t\t\t},\n\t\t\t\t\tonResubscribableReset: () => {\n\t\t\t\t\t\tdelete store.emitted;\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: opts?.name ?? \"frozenContext\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tinitial: null,\n\t\t\t\tmeta: aiMeta(\"frozen_context\", { ...frozenTag }),\n\t\t\t},\n\t\t);\n\t}\n\n\t// Refresh-on-trigger path: deps = [src, trigger]. Emit the current src\n\t// value ONLY when the trigger dep is involved in the wave. Source-only\n\t// changes are silently held so downstream prompt composition sees the\n\t// same value between triggers, preserving the LLM provider's prefix cache.\n\t//\n\t// Uses raw `node()` to inspect per-dep wave involvement — `derived` fires\n\t// on any dep change and can't distinguish. The declaration-order semantic\n\t// gap in multi-dep push-on-subscribe (§2.7) works in our favor on\n\t// activation: src fires first (captured into ctx.prevData), trigger fires\n\t// in a second wave → emit via prevData[0] fallback.\n\treturn nodeFactory<T | null>(\n\t\t[src, trigger],\n\t\t(data, actions, ctx) => {\n\t\t\tconst triggerBatch = data[1];\n\t\t\tconst triggered = triggerBatch != null && triggerBatch.length > 0;\n\t\t\tif (!triggered) return;\n\t\t\tconst srcBatch = data[0];\n\t\t\tconst srcValue = srcBatch != null && srcBatch.length > 0 ? srcBatch.at(-1) : ctx.prevData[0];\n\t\t\tactions.emit(srcValue as T);\n\t\t},\n\t\t{\n\t\t\tname: opts?.name ?? \"frozenContext\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: null,\n\t\t\tmeta: aiMeta(\"frozen_context\", { ...frozenTag }),\n\t\t},\n\t);\n}\n","/**\n * @internal — shared helpers for the AI pattern modules.\n *\n * NOT part of the public API. Consumers reach public symbols through\n * `@graphrefly/graphrefly/patterns/ai` (the barrel).\n *\n * @module\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tERROR,\n\ttype Messages,\n\ttype Node,\n\tnode,\n\tResettableTimer,\n} from \"@graphrefly/pure-ts/core\";\nimport { fromAny, type NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n} from \"./adapters/core/types.js\";\n\nexport function aiMeta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"ai\", kind, extra);\n}\n\nexport function isPromiseLike(x: unknown): x is PromiseLike<unknown> {\n\treturn x != null && typeof (x as PromiseLike<unknown>).then === \"function\";\n}\n\nexport function isNodeLike(x: unknown): x is Node<unknown> {\n\treturn (\n\t\ttypeof x === \"object\" &&\n\t\tx !== null &&\n\t\t\"subscribe\" in x &&\n\t\ttypeof (x as Node<unknown>).subscribe === \"function\" &&\n\t\t\"cache\" in x\n\t);\n}\n\nexport function isAsyncIterableLike(x: unknown): x is AsyncIterable<unknown> {\n\treturn (\n\t\tx != null &&\n\t\ttypeof x === \"object\" &&\n\t\tSymbol.asyncIterator in x &&\n\t\ttypeof (x as AsyncIterable<unknown>)[Symbol.asyncIterator] === \"function\"\n\t);\n}\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/** First settled `DATA` from a `Node` (do not pass plain strings — `fromAny` would iterate chars). */\nexport function firstDataFromNode(\n\tresolved: Node<unknown>,\n\topts?: { timeoutMs?: number },\n): Promise<unknown> {\n\tif ((resolved as { status?: string }).status === \"settled\") {\n\t\tconst immediate = resolved.cache;\n\t\tif (immediate !== undefined) {\n\t\t\treturn Promise.resolve(immediate);\n\t\t}\n\t}\n\tconst timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\treturn new Promise((resolve, reject) => {\n\t\tconst timer = new ResettableTimer();\n\t\tconst unsub = resolved.subscribe((messages) => {\n\t\t\tfor (const msg of messages) {\n\t\t\t\tif (msg[0] === DATA) {\n\t\t\t\t\ttimer.cancel();\n\t\t\t\t\tunsub();\n\t\t\t\t\tresolve(msg[1]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (msg[0] === ERROR) {\n\t\t\t\t\ttimer.cancel();\n\t\t\t\t\tunsub();\n\t\t\t\t\treject(msg[1]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (msg[0] === COMPLETE) {\n\t\t\t\t\ttimer.cancel();\n\t\t\t\t\tunsub();\n\t\t\t\t\treject(new Error(\"firstDataFromNode: completed without producing a value\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\ttimer.start(timeoutMs, () => {\n\t\t\tunsub();\n\t\t\treject(new Error(`firstDataFromNode: timed out after ${timeoutMs}ms`));\n\t\t});\n\t});\n}\n\n/** Await Promise-likes, then resolve `Node` / async-iterable inputs via `fromAny` + first `DATA`. */\nexport async function resolveToolHandlerResult(value: unknown): Promise<unknown> {\n\tif (isPromiseLike(value)) {\n\t\treturn resolveToolHandlerResult(await value);\n\t}\n\tif (isNodeLike(value)) {\n\t\treturn firstDataFromNode(value);\n\t}\n\tif (isAsyncIterableLike(value)) {\n\t\treturn firstDataFromNode(fromAny(value as NodeInput<unknown>));\n\t}\n\treturn value;\n}\n\n/** Strip markdown code fences, handling trailing commentary after closing fence. */\nexport function stripFences(text: string): string {\n\tconst match = text.match(/^```(?:json)?\\s*([\\s\\S]*?)\\s*```[\\s\\S]*$/);\n\treturn match ? match[1]! : text;\n}\n\n/**\n * Bridge-layer failure kind reported to {@link OneShotLlmCallConfig.onFailure}.\n *\n * - `\"throw\"` — synchronous throw from `adapter.invoke()`.\n * - `\"error\"` — `[ERROR, value]` message on the bridged Node.\n * - `\"complete\"` — the bridged Node closed without emitting DATA.\n * - `\"onSuccess-threw\"` — `onSuccess(resp)` itself threw (uncaught parse /\n * builder error). Caller's `onFailure` decides the failure-payload shape.\n */\nexport type OneShotLlmFailureKind = \"throw\" | \"error\" | \"complete\" | \"onSuccess-threw\";\n\n/** Configuration for {@link _oneShotLlmCall}. */\nexport interface OneShotLlmCallConfig<T> {\n\t/**\n\t * Build the success payload from the adapter's first DATA message.\n\t * MAY throw — the helper catches and routes through `onFailure(kind:\n\t * \"onSuccess-threw\", err)` so callers don't need their own try/catch.\n\t */\n\tonSuccess: (resp: LLMResponse) => T;\n\t/**\n\t * Build a failure payload when the bridge layer reports any of the\n\t * {@link OneShotLlmFailureKind} categories. Caller chooses the detail\n\t * string format and any error-class metadata.\n\t */\n\tonFailure: (kind: OneShotLlmFailureKind, err: unknown) => T;\n\t/**\n\t * Forwarded to `adapter.invoke(messages, opts)` — `signal` is set\n\t * by the helper from the producer's AbortController and CANNOT be\n\t * overridden here (cancellation is a hard contract of this helper).\n\t */\n\tinvokeOpts?: Omit<LLMInvokeOptions, \"signal\">;\n\t/**\n\t * Optional parent abort signal (e.g. JobFlow pump's per-claim signal).\n\t * When the parent aborts, the helper aborts its inner AbortController —\n\t * so `adapter.invoke({ signal })` and `fromAny({ signal })` see the\n\t * cascade and cancel in-flight work. Pump-driven harness teardown\n\t * (`harness.destroy()`) propagates through this hook (Tier 6.5 2.5b).\n\t */\n\tparentSignal?: AbortSignal;\n}\n\n/**\n * Internal — one-shot bridge from `adapter.invoke()` (a `NodeInput<LLMResponse>`)\n * into a producer that emits exactly one DATA + COMPLETE.\n *\n * **Why this exists.** The harness's `defaultLlmExecutor` and\n * `defaultLlmVerifier` (Tier 6.5 C2) both call `adapter.invoke()` once\n * per claimed JobFlow job and need to:\n * 1. Subscribe to the bridged Node, capture the first DATA, parse, emit\n * a domain payload.\n * 2. Map adapter throws / ERROR / COMPLETE-without-DATA to a domain\n * failure payload (rather than nack the JobFlow claim).\n * 3. Thread `signal: ac.signal` into BOTH `adapter.invoke()` (via\n * `LLMInvokeOptions.signal`) and `fromAny()` (covers Node-shaped\n * invokeResults) so teardown actually aborts in-flight HTTP work.\n * 4. Tear down the inner subscription cleanly when DATA captures or\n * when the producer is unsubscribed.\n *\n * Pre-extraction this body was duplicated ~80 LOC across the two default\n * bridges; symmetric fixes had to land twice (qa F1 / F2 / F5). This\n * helper centralizes the producer body so future bridge-layer fixes apply\n * once.\n *\n * **Not part of the public API.** Callers in `patterns/ai/_internal.ts`'s\n * import surface (the harness defaults today) use this; user code should\n * use `promptNode` for cross-wave reactive transforms or call\n * `adapter.invoke()` directly.\n */\nexport function _oneShotLlmCall<T>(\n\tadapter: LLMAdapter,\n\tmessages: readonly ChatMessage[],\n\tconfig: OneShotLlmCallConfig<T>,\n): NodeInput<T> {\n\treturn node<T>(\n\t\t(_data, actions) => {\n\t\t\tconst ac = new AbortController();\n\t\t\t// Link parent signal (e.g. pump per-claim signal) so cascading\n\t\t\t// teardown propagates: parent abort → inner ac.abort → adapter +\n\t\t\t// fromAny cancel.\n\t\t\tconst parentSignal = config.parentSignal;\n\t\t\tlet unlinkParent: () => void = () => undefined;\n\t\t\tif (parentSignal) {\n\t\t\t\tif (parentSignal.aborted) {\n\t\t\t\t\tac.abort();\n\t\t\t\t} else {\n\t\t\t\t\tconst onParentAbort = (): void => ac.abort();\n\t\t\t\t\tparentSignal.addEventListener(\"abort\", onParentAbort, { once: true });\n\t\t\t\t\tunlinkParent = () => parentSignal.removeEventListener(\"abort\", onParentAbort);\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet captured = false;\n\t\t\tlet unsub: (() => void) | null = null;\n\t\t\tconst emitOnce = (value: T): void => {\n\t\t\t\tif (captured) return;\n\t\t\t\tcaptured = true;\n\t\t\t\tactions.down([[DATA, value], [COMPLETE]] satisfies Messages);\n\t\t\t\tunsub?.();\n\t\t\t\tunsub = null;\n\t\t\t};\n\t\t\tlet invokeResult: NodeInput<LLMResponse>;\n\t\t\ttry {\n\t\t\t\tinvokeResult = adapter.invoke(messages, { ...config.invokeOpts, signal: ac.signal });\n\t\t\t} catch (err) {\n\t\t\t\temitOnce(config.onFailure(\"throw\", err));\n\t\t\t\treturn () => {\n\t\t\t\t\tunlinkParent();\n\t\t\t\t\tac.abort();\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst callNode = fromAny<LLMResponse>(invokeResult, { signal: ac.signal });\n\t\t\tunsub = callNode.subscribe((batch) => {\n\t\t\t\tfor (const m of batch) {\n\t\t\t\t\tif (captured) return;\n\t\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\temitOnce(config.onSuccess(m[1] as LLMResponse));\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\temitOnce(config.onFailure(\"onSuccess-threw\", err));\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (m[0] === ERROR) {\n\t\t\t\t\t\temitOnce(config.onFailure(\"error\", m[1]));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\t\t\t// COMPLETE without prior DATA — without this arm the JobFlow\n\t\t\t\t\t\t// pump's claim would stall (qa F1 regression). Helper handles\n\t\t\t\t\t\t// for ALL callers; defaults can't regress.\n\t\t\t\t\t\temitOnce(config.onFailure(\"complete\", undefined));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t// Sync DATA delivery (cached state / `fromAny` over a sync value):\n\t\t\t// the callback ran reentrantly before `unsub` was assigned, so the\n\t\t\t// `unsub?.()` call inside `emitOnce` was a no-op. Drop the upstream\n\t\t\t// subscription now that we have the handle.\n\t\t\tif (captured && unsub) {\n\t\t\t\tunsub();\n\t\t\t\tunsub = null;\n\t\t\t}\n\t\t\treturn () => {\n\t\t\t\tunlinkParent();\n\t\t\t\tac.abort();\n\t\t\t\tunsub?.();\n\t\t\t\tunsub = null;\n\t\t\t};\n\t\t},\n\t\t{ describeKind: \"producer\" },\n\t);\n}\n","// ---------------------------------------------------------------------------\n// promptCall — public single-shot LLM JSON helper (Tier 4.6 Wave AM Unit 4\n// promotion from the previously-internal `llmJsonCall` in\n// `patterns/ai/memory/llm-memory.ts`).\n//\n// Wraps {@link promptNode} for the common \"one-shot LLM JSON call per input\"\n// shape: a per-call `node([], { initial: input })` is wrapped, the prompt builder runs against\n// it, and the returned `NodeInput<TOut>` slots into reactive callbacks like\n// `distill`'s `extractFn` / `consolidateFn`. Inherits markdown-fence stripping\n// and content-preview parse errors from `promptNode({format: \"json\"})`.\n//\n// `llmExtractor` / `llmConsolidator` are now thin wrappers over `promptCall`.\n// ---------------------------------------------------------------------------\n\nimport { node } from \"@graphrefly/pure-ts/core\";\nimport type { NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport type { Extraction } from \"../../../base/composition/distill.js\";\nimport type { LLMAdapter } from \"../adapters/core/types.js\";\nimport { promptNode } from \"./prompt-node.js\";\n\n/** Options accepted by {@link promptCall}, {@link llmExtractor}, and {@link llmConsolidator}. */\nexport type PromptCallOptions = {\n\tadapter: LLMAdapter;\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\t/**\n\t * Optional name forwarded to the underlying `promptNode` (used as the\n\t * `<name>::messages` / `<name>::response` / `<name>::output` path prefix).\n\t * Defaults differ per call site so multiple `promptCall`s wired into the\n\t * same graph don't collide on `prompt_node::output`.\n\t */\n\tname?: string;\n};\n\n/**\n * Build a one-shot LLM JSON-call factory: each invocation wraps `input` in a\n * fresh `node([], { initial: input })`, delegates to `promptNode({format: \"json\"})`, and\n * returns a `NodeInput<TOut>` that the caller plugs into `distill` /\n * `agentLoop` / any reactive composition that accepts `NodeInput`.\n *\n * **Per-call lifecycle.** The returned `NodeInput<TOut>` is a producer that\n * emits exactly one `DATA` per upstream input (per Tier 1.2 Session C lock —\n * `promptNode` guarantees one DATA per wave). When the consumer's switchMap\n * supersedes it, the per-call `node([], { initial: input })` and the inner `prompt_node::response`\n * tear down together.\n *\n * @param systemPrompt - System message sent on every call.\n * @param buildUserContent - Per-input user-content builder (must be JSON-stringifiable).\n * @param opts - Adapter + model/temperature/maxTokens + optional name prefix.\n * @param defaultName - Path-prefix fallback when `opts.name` is omitted.\n * @returns Factory `(input: TIn) => NodeInput<TOut>`.\n *\n * @category patterns\n */\nexport function promptCall<TIn, TOut>(\n\tsystemPrompt: string,\n\tbuildUserContent: (input: TIn) => string,\n\topts: PromptCallOptions,\n\tdefaultName: string,\n): (input: TIn) => NodeInput<TOut> {\n\tconst name = opts.name ?? defaultName;\n\treturn (input: TIn) => {\n\t\t// One-shot node([], { initial: input }) per call — switchMap teardown inside the\n\t\t// consumer (e.g. distill) reclaims the node when the next upstream\n\t\t// arrives or the bundle disposes.\n\t\tconst inputState = node<TIn>([], { initial: input });\n\t\treturn promptNode<TOut>(\n\t\t\topts.adapter,\n\t\t\t[inputState as never],\n\t\t\t(value: unknown) => buildUserContent(value as TIn),\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tformat: \"json\",\n\t\t\t\tsystemPrompt,\n\t\t\t\tmodel: opts.model,\n\t\t\t\ttemperature: opts.temperature ?? 0,\n\t\t\t\tmaxTokens: opts.maxTokens,\n\t\t\t},\n\t\t) as NodeInput<TOut>;\n\t};\n}\n\n/** Options accepted by {@link llmExtractor} and {@link llmConsolidator}. */\nexport type LLMExtractorOptions = PromptCallOptions & {\n\t/**\n\t * Cap the dedup-hint slice of `existingKeys` passed to the LLM. Larger\n\t * stores ship more keys (better dedup recall) at the cost of prompt size.\n\t * Default 100. Set to `Infinity` to forward every key.\n\t */\n\tmaxExistingKeys?: number;\n};\n\n/** Alias for backward compatibility. */\nexport type LLMConsolidatorOptions = LLMExtractorOptions;\n\n/**\n * Returns an `extractFn` callback for `distill()` that invokes an LLM to\n * extract structured memories from raw input.\n *\n * The system prompt should instruct the LLM to return JSON matching\n * `Extraction<TMem>` shape: `{ upsert: [{ key, value }], remove?: [key] }`.\n *\n * Built on `promptNode({format: \"json\"})` — inherits markdown-fence stripping\n * and content-preview parse errors. Stack `withRetry` on the adapter for\n * transient-error tolerance (see `patterns/ai/adapters/middleware/retry.ts`).\n */\nexport function llmExtractor<TRaw, TMem>(\n\tsystemPrompt: string,\n\topts: LLMExtractorOptions,\n): (raw: TRaw, existing: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>> {\n\tconst cap = opts.maxExistingKeys ?? 100;\n\tconst call = promptCall<{ raw: TRaw; existingKeys: string[] }, Extraction<TMem>>(\n\t\tsystemPrompt,\n\t\t(input) => JSON.stringify({ input: input.raw, existingKeys: input.existingKeys }),\n\t\topts,\n\t\t\"llmExtractor\",\n\t);\n\treturn (raw: TRaw, existing: ReadonlyMap<string, TMem>) => {\n\t\tconst existingKeys =\n\t\t\tcap === Number.POSITIVE_INFINITY ? [...existing.keys()] : [...existing.keys()].slice(0, cap);\n\t\treturn call({ raw, existingKeys });\n\t};\n}\n\n/**\n * Returns a `consolidateFn` callback for `distill()` that invokes an LLM to\n * cluster and merge related memories.\n */\nexport function llmConsolidator<TMem>(\n\tsystemPrompt: string,\n\topts: LLMConsolidatorOptions,\n): (entries: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>> {\n\tconst call = promptCall<readonly { key: string; value: TMem }[], Extraction<TMem>>(\n\t\tsystemPrompt,\n\t\t(memories) => JSON.stringify({ memories }),\n\t\topts,\n\t\t\"llmConsolidator\",\n\t);\n\treturn (entries: ReadonlyMap<string, TMem>) => {\n\t\tconst memories = [...entries.entries()].map(([key, value]) => ({ key, value }));\n\t\treturn call(memories);\n\t};\n}\n","/**\n * `promptNode` — universal LLM transform as a reactive derived node.\n *\n * The shape: `deps → messagesNode (derived) → switchMap → response (producer) → output`.\n * Each upstream wave is one LLM call; superseding waves cancel the in-flight\n * call via the abort signal threaded through `nodeSignal(opts.abort)`.\n *\n * The producer-shape on the inner is load-bearing: it emits exactly one DATA\n * + COMPLETE per wave, so the outer switchMap sees one DATA per wave (matches\n * the `HarnessExecutor` contract). A `node([response], (batchData, actions, ctx) => {\n * const data = ...; actions.emit(parse(data[0]));\n * }, { describeKind: \"derived\" })` would have its\n * own first-run / push-on-subscribe semantics that can leak a transient null\n * before the real response arrives — observed and reverted in an earlier\n * attempt; see SESSION-ai-harness-module-review.md line 3654 for context.\n * Locked as path (b) producer-based by Session C (2026-04-27); inner-node\n * naming aligned to `prompt_node::response` per the C+D widening (2026-04-30).\n *\n * **Retry / replay-cache.** Stack middleware on the adapter:\n *\n * ```ts\n * import { withRetry, withReplayCache } from \"@graphrefly/graphrefly/patterns/ai\";\n *\n * const adapter = withRetry(\n * withReplayCache(baseAdapter, { keyFn: (ctx) => ctx.messages[0].content }),\n * { count: 3, backoff: 200 },\n * );\n * const result = promptNode(adapter, [input], (q) => q);\n * ```\n *\n * `promptNode` no longer ships `retries` / `cache` options — they duplicated\n * middleware already at the adapter layer.\n *\n * **Cross-wave cache (COMPOSITION-GUIDE §32).** The switchMap output cache\n * survives across new outer DATAs — `promptNode`'s cached value persists\n * until the next wave fully resolves. Consumers that need to distinguish\n * \"fresh value for THIS session\" from \"stale cache from a prior session\"\n * (e.g. `agentLoop` resetting on new `run()`) must add a `node([])` mirror\n * at their session boundary and depend on the mirror, not the `promptNode`\n * output directly. `promptNode` itself stays primitive — it does not\n * embed a state-mirror.\n *\n * @module\n */\n\nimport { COMPLETE, DATA, ERROR, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { fromAny, type NodeInput, switchMap } from \"@graphrefly/pure-ts/extra\";\nimport { nodeSignal } from \"../../../base/sources/settled.js\";\nimport { aiMeta, stripFences } from \"../_internal.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n\tToolDefinition,\n} from \"../adapters/core/types.js\";\n\nexport type PromptNodeOptions = {\n\tname?: string;\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\t/**\n\t * Output format:\n\t * - `\"text\"` (default) — emit the response content as a string.\n\t * - `\"json\"` — `JSON.parse` the content (markdown fences stripped).\n\t * - `\"raw\"` — emit the full {@link LLMResponse} object (subsumes the\n\t * pre-Tier-2.3 `fromLLM` shape; use this when you need `usage` /\n\t * `toolCalls` / `finishReason` alongside `content`).\n\t */\n\tformat?: \"text\" | \"json\" | \"raw\";\n\t/**\n\t * Reactive tool definitions forwarded to the adapter. Pair with\n\t * `format: \"raw\"` (or read `toolCalls` from a downstream parser) when\n\t * tool-calling is in scope.\n\t *\n\t * **Reactive declared edge** (DF12, Tier 7): `tools` is a `Node` so the\n\t * tools list participates in `describe()` topology and `explain()` causal\n\t * chains. The tools Node is added to `messagesNode`'s declared deps —\n\t * tools changes re-invoke the LLM (treated as a new call envelope).\n\t * Wrap with `distinctUntilChanged` upstream if your tool selector emits\n\t * noisy duplicates that would otherwise spam the adapter. See\n\t * COMPOSITION-GUIDE §31 (Dynamic tool selection) for the canonical\n\t * `toolSelector` pattern that produces this Node.\n\t *\n\t * **Activation note:** since `tools` is a real declared dep, `messagesNode`\n\t * waits for the tools Node to DATA at least once before firing\n\t * (push-on-subscribe SENTINEL gate). Pass a `node<ToolDefinition[]>([], { initial: [] })`\n\t * if you want immediate activation with no tools, or the latest published\n\t * `toolSelector.tools` Node.\n\t */\n\ttools?: Node<readonly ToolDefinition[]>;\n\t/**\n\t * Optional system prompt. Forwarded via `opts.systemPrompt` to the adapter\n\t * only — never pushed as a `{role:\"system\"}` message (avoiding the\n\t * double-send class of bug where adapters that normalize both shapes end\n\t * up with two system entries).\n\t */\n\tsystemPrompt?: string;\n\t/**\n\t * Optional reactive abort signal. When the node emits `true`, the in-flight\n\t * `adapter.invoke()` call is cancelled via `AbortController.abort()`.\n\t * Threaded through `nodeSignal(abort)` — a one-shot bridge. Useful inside\n\t * agent state machines where a separate `aborted` state should cancel the\n\t * current LLM call without superseding via switchMap.\n\t */\n\tabort?: Node<boolean>;\n\tmeta?: Record<string, unknown>;\n};\n\n/** Extract text content from an LLM response, handling various response shapes. */\nfunction extractContent(resp: unknown): string {\n\tif (resp != null && typeof resp === \"object\" && \"content\" in resp) {\n\t\treturn String((resp as LLMResponse).content);\n\t}\n\tif (typeof resp === \"string\") return resp;\n\treturn String(resp);\n}\n\nfunction previewContent(text: string, max = 200): string {\n\tif (text.length <= max) return text;\n\treturn `${text.slice(0, max)}…`;\n}\n\n/**\n * Universal LLM transform: wraps a prompt template + model adapter into a reactive derived node.\n * Re-invokes the LLM whenever any dep changes. Suitable for triage, QA, hypothesis, parity, etc.\n *\n * **Topology** (visible in `describe()`):\n * ```\n * <deps...>, [tools?] → <name>::messages (derived, meta.ai = prompt_node::messages)\n * <name>::messages → <name>::output (switchMap product, meta.ai = prompt_node::output)\n * per-wave inner: <name>::response (producer, meta.ai = prompt_node::response)\n * ```\n * When `opts.tools` is supplied, the tools `Node` is appended to\n * `messagesNode`'s declared deps so it appears as a real edge in `describe()`\n * / `explain()` (DF12, Tier 7).\n *\n * **No-input semantics** (matches the codebase-wide SENTINEL convention):\n * - **Initial no-input** (no real input has ever arrived) — emits nothing.\n * Outer cache stays `undefined`; `subscribe` consumers see no DATA event.\n * Use this to keep downstream gating clean: a `withLatestFrom`-paired\n * trigger won't fire until the LLM has actually produced something.\n * - **Mid-flow no-input** (input dropped to nullish after at least one\n * real LLM call) — emits `null` as a domain \"input went away\" signal.\n * Downstream consumers can distinguish \"haven't started\" from \"input\n * gone.\"\n *\n * **Retries / caching:** stack `withRetry` / `withReplayCache` middleware on the\n * `adapter` argument — `promptNode` no longer ships its own duplicated retry /\n * cache loops (pre-1.0 cleanup, see review session 1).\n *\n * @param adapter - LLM adapter (provider-agnostic). Wrap with `withRetry` /\n * `withReplayCache` middleware for transient-error tolerance\n * or replay caching.\n * @param deps - Input nodes whose values feed the prompt.\n * @param prompt - Static string or template function receiving dep values.\n * @param opts - Optional configuration.\n * @returns `Node` emitting LLM responses (string or parsed JSON).\n */\n// Overload 1: `format: \"raw\"` constrains the emit type to `LLMResponse | null`\n// (the full adapter response, with `usage` / `toolCalls` / `finishReason`).\n// Subsumes the pre-Tier-2.3 `fromLLM` shape.\nexport function promptNode(\n\tadapter: LLMAdapter,\n\tdeps: readonly Node<unknown>[],\n\tprompt: string | ((...depValues: unknown[]) => string),\n\topts: PromptNodeOptions & { format: \"raw\" },\n): Node<LLMResponse | null>;\n// Overload 2: `format: \"text\" | \"json\"` (default text) — emit-type is the\n// caller's `T` (defaults to `string`). For `\"json\"` callers typically pass\n// the parsed shape (e.g. `promptNode<MyShape>(...)`).\nexport function promptNode<T = string>(\n\tadapter: LLMAdapter,\n\tdeps: readonly Node<unknown>[],\n\tprompt: string | ((...depValues: unknown[]) => string),\n\topts?: Omit<PromptNodeOptions, \"format\"> & { format?: \"text\" | \"json\" },\n): Node<T | null>;\nexport function promptNode<T = string>(\n\tadapter: LLMAdapter,\n\tdeps: readonly Node<unknown>[],\n\tprompt: string | ((...depValues: unknown[]) => string),\n\topts?: PromptNodeOptions,\n): Node<T | null> {\n\tconst format = opts?.format ?? \"text\";\n\tconst baseName = opts?.name ?? \"prompt_node\";\n\n\t// qa A8: tools without `format: \"raw\"` is a footgun — adapter receives\n\t// the tool definitions and may produce `toolCalls`, but the emit path\n\t// only extracts `content`. Warn at construction; downstream parsers\n\t// reading `toolCalls` from a custom `format: \"raw\"` consumer pattern\n\t// can ignore by setting `format: \"raw\"` (intent now matches behavior).\n\tif (opts?.tools !== undefined && format !== \"raw\") {\n\t\tconsole.warn(\n\t\t\t\"promptNode: `tools` is set but `format !== 'raw'`. \" +\n\t\t\t\t\"Tool calls in the response will be silently dropped — set \" +\n\t\t\t\t\"`format: 'raw'` to receive the full LLMResponse with `toolCalls`.\",\n\t\t);\n\t}\n\n\t// SENTINEL semantics rely on the universal first-run gate + standard\n\t// prevData semantics (undefined = SENTINEL, any other value = DATA seen):\n\t// - **Initial no-input** (no dep has ever DATA'd, so prevData is\n\t// undefined across the board): the `derived`'s first-run gate blocks\n\t// `messagesNode`'s fn entirely. It never emits, switchMap never\n\t// fires, outer cache stays `undefined`.\n\t// - **Mid-flow no-input** (deps previously DATA'd then went nullish):\n\t// fn runs, returns `[]`, switchMap dispatches the `node([], { initial: null })`\n\t// branch → outer emits `null` as the domain \"input went away\" signal.\n\t// No `initial: []` and no closure flag — `prevData === undefined` is\n\t// already the sentinel marker, and the gate already enforces \"don't fire\n\t// fn until every dep has DATA'd at least once.\"\n\t//\n\t// DF12: when `opts.tools` is a Node, it's appended to `messagesNode`'s\n\t// declared deps. The fn slices values into user-deps + tools, and emits\n\t// an envelope `{ messages, tools }` so switchMap's per-wave inner can\n\t// read the latest tools via the reactive edge instead of a closure.\n\ttype Envelope = {\n\t\tmessages: readonly ChatMessage[];\n\t\ttools: readonly ToolDefinition[] | undefined;\n\t};\n\tconst userDepsLength = deps.length;\n\tconst allDeps: readonly Node<unknown>[] =\n\t\topts?.tools !== undefined ? [...deps, opts.tools as Node<unknown>] : deps;\n\tconst messagesNode = node<Envelope>(\n\t\tallDeps as Node<unknown>[],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst userValues = data.slice(0, userDepsLength);\n\t\t\tconst toolsValue =\n\t\t\t\topts?.tools !== undefined\n\t\t\t\t\t? (data[userDepsLength] as readonly ToolDefinition[] | undefined)\n\t\t\t\t\t: undefined;\n\t\t\t// Dep-level null guard (composition guide §8): if any USER dep is\n\t\t\t// nullish, emit empty messages → switchMap emits null (mid-flow\n\t\t\t// drop-out). The tools dep can legitimately be empty `[]`; only\n\t\t\t// user deps gate the call.\n\t\t\tif (userValues.some((v) => v == null)) {\n\t\t\t\tactions.emit({ messages: [], tools: toolsValue });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst text = typeof prompt === \"string\" ? prompt : prompt(...userValues);\n\t\t\tif (!text) {\n\t\t\t\tactions.emit({ messages: [], tools: toolsValue });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// systemPrompt forwarded through invoke opts only (no double-send).\n\t\t\tactions.emit({\n\t\t\t\tmessages: [{ role: \"user\" as const, content: text }],\n\t\t\t\ttools: toolsValue,\n\t\t\t});\n\t\t},\n\t\t{\n\t\t\tname: `${baseName}::messages`,\n\t\t\tmeta: aiMeta(\"prompt_node::messages\"),\n\t\t},\n\t);\n\n\tconst result = switchMap<Envelope, T | null>(\n\t\tmessagesNode,\n\t\t(envelope) => {\n\t\t\tconst { messages: msgs, tools } = envelope;\n\t\t\tif (!msgs || msgs.length === 0) {\n\t\t\t\treturn node<T | null>([], { initial: null }) as NodeInput<T | null>;\n\t\t\t}\n\n\t\t\t// Producer ensures exactly one DATA + COMPLETE per wave; switchMap\n\t\t\t// sees one DATA, the harness's \"one emission per wave\" contract is\n\t\t\t// honored. Earlier attempts using a derived node leaked\n\t\t\t// transient nulls via the derived's first-run gate.\n\t\t\treturn node<T | null>(\n\t\t\t\t(_data, actions) => {\n\t\t\t\t\tlet done = false;\n\t\t\t\t\tlet cancelled = false;\n\t\t\t\t\tlet abortDispose: (() => void) | undefined;\n\n\t\t\t\t\tconst invokeOpts: LLMInvokeOptions = {\n\t\t\t\t\t\tmodel: opts?.model,\n\t\t\t\t\t\ttemperature: opts?.temperature,\n\t\t\t\t\t\tmaxTokens: opts?.maxTokens,\n\t\t\t\t\t\tsystemPrompt: opts?.systemPrompt,\n\t\t\t\t\t\t...(tools !== undefined ? { tools } : {}),\n\t\t\t\t\t};\n\t\t\t\t\tif (opts?.abort) {\n\t\t\t\t\t\tconst sig = nodeSignal(opts.abort);\n\t\t\t\t\t\tinvokeOpts.signal = sig.signal;\n\t\t\t\t\t\tabortDispose = sig.dispose;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet invokeResult: NodeInput<LLMResponse>;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tinvokeResult = adapter.invoke(msgs, invokeOpts);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\tactions.down([[ERROR, err]]);\n\t\t\t\t\t\treturn () => {\n\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tconst callNode = fromAny(invokeResult);\n\n\t\t\t\t\tconst sub = callNode.subscribe((batch) => {\n\t\t\t\t\t\tif (cancelled || done) return;\n\t\t\t\t\t\tfor (const msg of batch) {\n\t\t\t\t\t\t\t// F-11: re-check `cancelled` (and `done`) at the top of\n\t\t\t\t\t\t\t// each per-message iteration so a teardown / abort that\n\t\t\t\t\t\t\t// fires synchronously between messages stops processing\n\t\t\t\t\t\t\t// further batched messages immediately.\n\t\t\t\t\t\t\tif (cancelled || done) return;\n\t\t\t\t\t\t\tif (msg[0] === DATA) {\n\t\t\t\t\t\t\t\tconst resp = msg[1] as LLMResponse;\n\t\t\t\t\t\t\t\t// `format: \"raw\"` bypasses parsing — emit the full\n\t\t\t\t\t\t\t\t// LLMResponse object (subsumes the pre-Tier-2.3 `fromLLM`\n\t\t\t\t\t\t\t\t// output shape).\n\t\t\t\t\t\t\t\tif (format === \"raw\") {\n\t\t\t\t\t\t\t\t\tactions.emit(resp as unknown as T);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t// F-12: cache the extracted content once on the\n\t\t\t\t\t\t\t\t\t// parse-failure path so we don't call\n\t\t\t\t\t\t\t\t\t// `extractContent(resp)` twice (once for parsing,\n\t\t\t\t\t\t\t\t\t// once for the error-message preview).\n\t\t\t\t\t\t\t\t\tlet content: string;\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tcontent = extractContent(resp);\n\t\t\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\t\t\t// extractContent itself failed — propagate as\n\t\t\t\t\t\t\t\t\t\t// an ERROR with a generic raw-extraction message.\n\t\t\t\t\t\t\t\t\t\tconst wrapped = new Error(\n\t\t\t\t\t\t\t\t\t\t\t`promptNode: failed to extract content from LLM response: ${\n\t\t\t\t\t\t\t\t\t\t\t\t(err as Error).message\n\t\t\t\t\t\t\t\t\t\t\t}`,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t// F-7: dispose abort hook on terminal-error\n\t\t\t\t\t\t\t\t\t\t// branches so we don't retain the AbortController\n\t\t\t\t\t\t\t\t\t\t// after the wave terminates. Idempotent.\n\t\t\t\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t\t\t\t\tabortDispose = undefined;\n\t\t\t\t\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\t\t\t\t\tactions.down([[ERROR, wrapped]]);\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tconst parsed: T =\n\t\t\t\t\t\t\t\t\t\t\tformat === \"json\"\n\t\t\t\t\t\t\t\t\t\t\t\t? (JSON.parse(stripFences(content)) as T)\n\t\t\t\t\t\t\t\t\t\t\t\t: (content as unknown as T);\n\t\t\t\t\t\t\t\t\t\tactions.emit(parsed);\n\t\t\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\t\t\tconst wrapped = new Error(\n\t\t\t\t\t\t\t\t\t\t\t`promptNode: failed to parse LLM response as JSON: ${\n\t\t\t\t\t\t\t\t\t\t\t\t(err as Error).message\n\t\t\t\t\t\t\t\t\t\t\t}\\n Raw content (first 200 chars): ${previewContent(content)}`,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t// F-7: dispose abort hook on parse-error\n\t\t\t\t\t\t\t\t\t\t// terminal branch.\n\t\t\t\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t\t\t\t\tabortDispose = undefined;\n\t\t\t\t\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\t\t\t\t\tactions.down([[ERROR, wrapped]]);\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if (msg[0] === ERROR) {\n\t\t\t\t\t\t\t\t// F-7: dispose abort hook on terminal ERROR branch.\n\t\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t\t\tabortDispose = undefined;\n\t\t\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\t\t\tactions.down([[ERROR, msg[1]]]);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t} else if (msg[0] === COMPLETE) {\n\t\t\t\t\t\t\t\t// Adapter completed — propagate. emit() above already\n\t\t\t\t\t\t\t\t// queued the parsed value so the wave carries DATA + COMPLETE.\n\t\t\t\t\t\t\t\t// F-7: dispose abort hook on terminal COMPLETE branch.\n\t\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t\t\tabortDispose = undefined;\n\t\t\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\t\t\tactions.down([[COMPLETE]]);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// Spec §1.3.6 forward-unknown — DIRTY/RESOLVED/INVALIDATE/\n\t\t\t\t\t\t\t\t// PAUSE/RESUME etc. should propagate so downstream caches /\n\t\t\t\t\t\t\t\t// flow-control hooks aren't starved. Re-typed `as never`\n\t\t\t\t\t\t\t\t// because the call's NodeInput<LLMResponse> message tuple\n\t\t\t\t\t\t\t\t// is wider than the unbound `T` projection.\n\t\t\t\t\t\t\t\tactions.down([msg as never]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tcancelled = true;\n\t\t\t\t\t\tsub();\n\t\t\t\t\t\t// F-7: cleanup callback's abortDispose call is idempotent —\n\t\t\t\t\t\t// the terminal-branch dispose above sets `abortDispose =\n\t\t\t\t\t\t// undefined` so this is a no-op when terminal-fired.\n\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\tabortDispose = undefined;\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdescribeKind: \"producer\",\n\t\t\t\t\tname: `${baseName}::response`,\n\t\t\t\t\tmeta: aiMeta(\"prompt_node::response\"),\n\t\t\t\t},\n\t\t\t) as NodeInput<T | null>;\n\t\t},\n\t\t{\n\t\t\tname: `${baseName}::output`,\n\t\t\tmeta: opts?.meta\n\t\t\t\t? { ...aiMeta(\"prompt_node::output\"), ...opts.meta }\n\t\t\t\t: aiMeta(\"prompt_node::output\"),\n\t\t},\n\t);\n\n\treturn result;\n}\n","/**\n * `streamingPromptNode` + `gatedStream` — streaming LLM transforms.\n *\n * **Wave A Unit 2 rewrite:**\n * - `StreamChunk` retired. The live stream surface is now `deltaTopic:\n * TopicGraph<StreamDelta & {seq, ts}>` — every adapter delta (token,\n * thinking, tool-call, usage, finish) is published in order. The previous\n * shape retained the accumulated text per-chunk, producing O(N²) memory;\n * the new shape stores only per-delta payloads (O(N)).\n * - New `accumulatedText: Node<string>` on the bundle — lazy-built via\n * `ctx.store` over token-type deltas. Text-only extractors (`streamExtractor`,\n * `keywordFlagExtractor`, `toolCallExtractor`) consume this node.\n * - `retainedLimit?: number` option exposed for the delta topic (no default —\n * session scale is domain-specific per Unit 2 Q2).\n * - Unconditional `keepalive(output)` removed — callers subscribe as needed.\n * - System-prompt double-send fixed (matches promptNode Unit 1 fix).\n * - `format: \"json\"` throws on parse error with a content-preview diagnostic\n * (parity with `promptNode`).\n * - Shared body between `streamingPromptNode` and `gatedStream` extracted\n * into `streamingInvoke` per Unit 2 locked scope.\n *\n * @module\n */\n\nimport { batch, factoryTag, type Node, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport { filter, fromAny, keepalive, type NodeInput, switchMap } from \"@graphrefly/pure-ts/extra\";\nimport type { Graph } from \"@graphrefly/pure-ts/graph\";\nimport { type TopicGraph, topic } from \"../../messaging/index.js\";\nimport { type GateController, type GateOptions, pipelineGraph } from \"../../orchestration/index.js\";\nimport { aiMeta, stripFences } from \"../_internal.js\";\nimport type { ChatMessage, LLMAdapter, StreamDelta } from \"../adapters/core/types.js\";\n\n/**\n * A single delta published to the `deltaTopic`. Every adapter emission is\n * forwarded — not just token deltas — so consumers see the full event log\n * (thinking, tool-call-delta, usage, finish).\n */\nexport type StampedDelta = StreamDelta & {\n\t/** Monotonic per-stream counter starting at 0. */\n\treadonly seq: number;\n\t/** Wall-clock nanoseconds at publish time (spec §5.11 central timer). */\n\treadonly ts: number;\n};\n\nexport type StreamingPromptNodeOptions = {\n\tname?: string;\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\t/** Output format — `\"json\"` attempts JSON.parse on accumulated text. Throws on parse failure. Default: `\"text\"`. */\n\tformat?: \"text\" | \"json\";\n\tsystemPrompt?: string;\n\tmeta?: Record<string, unknown>;\n\t/**\n\t * Optional retention cap on the delta topic. Omit for unbounded retention\n\t * (the topic grows until `dispose()`). Recommended values: `8_192` for\n\t * single-shot 8K-token responses, `1_000_000` for persistent session\n\t * topics, or explicit `dispose()` for worker-pool patterns.\n\t */\n\tretainedLimit?: number;\n};\n\n/**\n * Bundle returned by {@link streamingPromptNode}.\n */\nexport type StreamingPromptNodeHandle<T> = {\n\t/** Final parsed result (emits once per invocation, after stream completes). */\n\toutput: Node<T | null>;\n\t/** Live delta topic — every adapter delta in order, stamped with `seq` + `ts`. */\n\tdeltaTopic: TopicGraph<StampedDelta>;\n\t/**\n\t * Reactive accumulated-text view — lazy-built over `deltaTopic.latest`\n\t * filtered on `type === \"token\"`. Text-only extractors compose on this.\n\t * Emits the empty string before any token arrives.\n\t */\n\taccumulatedText: Node<string>;\n\t/** Tear down the delta topic and release resources. */\n\tdispose: () => void;\n};\n\n/**\n * Internal pump: open a stream against `adapter`, stamp each delta, publish\n * to `deltaTopic`, and return the final accumulated text. Extracted so\n * `gatedStream` can reuse the body (Unit 2 locked scope).\n */\nasync function streamingInvoke(\n\tadapter: LLMAdapter,\n\tmsgs: readonly ChatMessage[],\n\tinvokeOpts: {\n\t\tmodel?: string;\n\t\ttemperature?: number;\n\t\tmaxTokens?: number;\n\t\tsystemPrompt?: string;\n\t\tsignal: AbortSignal;\n\t},\n\tdeltaTopic: TopicGraph<StampedDelta>,\n): Promise<string> {\n\tlet accumulated = \"\";\n\tlet seq = 0;\n\tfor await (const delta of adapter.stream(msgs, invokeOpts)) {\n\t\tdeltaTopic.publish({ ...delta, seq: seq++, ts: wallClockNs() } as StampedDelta);\n\t\tif (delta.type === \"token\") accumulated += delta.delta;\n\t}\n\treturn accumulated;\n}\n\n/** Parse accumulated text per `format`. Throws on JSON parse failure. */\nfunction parseAccumulated<T>(accumulated: string, format: \"text\" | \"json\"): T | null {\n\tif (format === \"json\") {\n\t\ttry {\n\t\t\treturn JSON.parse(stripFences(accumulated)) as T;\n\t\t} catch (err) {\n\t\t\tconst preview = accumulated.slice(0, 160);\n\t\t\tthrow new Error(\n\t\t\t\t`streamingPromptNode: format:\"json\" — failed to parse accumulated text as JSON: ${(err as Error).message}; content preview: ${preview}`,\n\t\t\t);\n\t\t}\n\t}\n\treturn accumulated as unknown as T;\n}\n\n/**\n * Build the lazy `accumulatedText` derived that maintains a running string\n * over `deltaTopic.latest` filtered on token deltas. Uses `ctx.store` per\n * COMPOSITION-GUIDE §20 — accumulator clears on deactivation.\n */\nfunction makeAccumulatedText(deltaTopic: TopicGraph<StampedDelta>, name: string): Node<string> {\n\t// Lock 6.D (Phase 13.6.B): clear acc on deactivation so a resubscribed\n\t// accumulator starts fresh. Pre-flip this came for free via\n\t// `_deactivate`'s store wipe.\n\tlet cleanup: { onDeactivation: () => void } | undefined;\n\treturn node<string>(\n\t\t[deltaTopic.latest],\n\t\t(batchData, actions, ctx) => {\n\t\t\tif (cleanup === undefined) {\n\t\t\t\tconst store = ctx.store;\n\t\t\t\tcleanup = {\n\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\tdelete store.acc;\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst d = data[0];\n\t\t\tconst store = ctx.store as { acc?: string };\n\t\t\tif (d === undefined) {\n\t\t\t\tactions.emit(store.acc ?? \"\");\n\t\t\t\treturn cleanup;\n\t\t\t}\n\t\t\tconst delta = d as StampedDelta;\n\t\t\t// `seq === 0` marks the first delta of a fresh invocation — reset\n\t\t\t// the accumulator so runs don't concatenate across switchMap\n\t\t\t// supersedes. Without this, invocation 2's text would be appended\n\t\t\t// to invocation 1's text (the `deltaTopic` outlives each switchMap\n\t\t\t// inner, so `ctx.store.acc` would otherwise persist).\n\t\t\tif (delta.seq === 0) store.acc = \"\";\n\t\t\tif (delta.type === \"token\") {\n\t\t\t\tstore.acc = (store.acc ?? \"\") + delta.delta;\n\t\t\t}\n\t\t\tactions.emit(store.acc ?? \"\");\n\t\t\treturn cleanup;\n\t\t},\n\t\t{\n\t\t\tname,\n\t\t\tdescribeKind: \"derived\",\n\t\t\tmeta: aiMeta(\"accumulated_text\"),\n\t\t\tinitial: \"\",\n\t\t},\n\t);\n}\n\n/**\n * Streaming LLM transform: wraps a prompt template + adapter into a reactive\n * streaming pipeline. Re-invokes the LLM whenever any dep changes; the\n * previous in-flight stream is canceled automatically via `switchMap`.\n *\n * Every adapter delta is published to `deltaTopic` stamped with `seq` + `ts`.\n * Text consumers subscribe to `accumulatedText` (auto-maintained). Delta-\n * specific consumers (`costMeterExtractor` on `usage` deltas) subscribe to\n * `deltaTopic` directly and filter by `delta.type`.\n *\n * The async boundary is handled by `fromAny(asyncGenerator)` (spec §5.10).\n */\nexport function streamingPromptNode<T = string>(\n\tadapter: LLMAdapter,\n\tdeps: readonly Node<unknown>[],\n\tprompt: string | ((...depValues: unknown[]) => string),\n\topts?: StreamingPromptNodeOptions,\n): StreamingPromptNodeHandle<T> {\n\tconst sourceName = opts?.name ?? \"llm\";\n\tconst format = opts?.format ?? \"text\";\n\tconst deltaTopic = topic<StampedDelta>(`${sourceName}/stream`, {\n\t\t...(opts?.retainedLimit != null ? { retainedLimit: opts.retainedLimit } : {}),\n\t});\n\n\tconst messagesNode = node<readonly ChatMessage[]>(\n\t\tdeps as Node<unknown>[],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tif (data.some((v) => v == null)) {\n\t\t\t\tactions.emit([]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst text = typeof prompt === \"string\" ? prompt : prompt(...data);\n\t\t\tif (!text) {\n\t\t\t\tactions.emit([]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tactions.emit([{ role: \"user\", content: text }]);\n\t\t},\n\t\t{\n\t\t\tname: `${sourceName}::messages`,\n\t\t\tmeta: aiMeta(\"prompt_node::messages\"),\n\t\t\tinitial: [] as readonly ChatMessage[],\n\t\t},\n\t);\n\n\tconst output = switchMap(\n\t\tmessagesNode,\n\t\t(msgs) => {\n\t\t\tconst chatMsgs = msgs as readonly ChatMessage[];\n\t\t\tif (!chatMsgs || chatMsgs.length === 0) {\n\t\t\t\treturn node<T | null>([], { initial: null }) as NodeInput<T | null>;\n\t\t\t}\n\t\t\tconst ac = new AbortController();\n\t\t\tasync function* pumpAndCollect(): AsyncGenerator<T | null> {\n\t\t\t\ttry {\n\t\t\t\t\tconst accumulated = await streamingInvoke(\n\t\t\t\t\t\tadapter,\n\t\t\t\t\t\tchatMsgs,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmodel: opts?.model,\n\t\t\t\t\t\t\ttemperature: opts?.temperature,\n\t\t\t\t\t\t\tmaxTokens: opts?.maxTokens,\n\t\t\t\t\t\t\tsystemPrompt: opts?.systemPrompt,\n\t\t\t\t\t\t\tsignal: ac.signal,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tdeltaTopic,\n\t\t\t\t\t);\n\t\t\t\t\tyield parseAccumulated<T>(accumulated, format);\n\t\t\t\t} finally {\n\t\t\t\t\tac.abort();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn fromAny(pumpAndCollect());\n\t\t},\n\t\t{ meta: factoryTag(\"streamingPromptNode\") },\n\t);\n\n\tconst accumulatedText = makeAccumulatedText(deltaTopic, `${sourceName}::accumulatedText`);\n\n\t// Keepalive on `output` — a caller who subscribes ONLY to `deltaTopic` or\n\t// `accumulatedText` expects the stream to run (that's the bundle contract\n\t// — three reactive surfaces, any one of them activates the pipeline).\n\t// Without this, the lazy `switchMap` stays cold until someone subscribes\n\t// to `.output` directly, and deltas never flow. The original\n\t// `streamingPromptNode` carried this keepalive; the Unit 2 \"zero overhead\n\t// if nobody subscribes\" removal broke the bundle-activation contract.\n\t// Restored here with explicit dispose so the keepalive follows the bundle.\n\tconst unsubOutput = keepalive(output);\n\n\treturn {\n\t\toutput,\n\t\tdeltaTopic,\n\t\taccumulatedText,\n\t\tdispose: () => {\n\t\t\tunsubOutput();\n\t\t\tdeltaTopic.destroy();\n\t\t},\n\t};\n}\n\nexport type GatedStreamOptions = StreamingPromptNodeOptions & {\n\t/** Gate options (maxPending, startOpen). */\n\tgate?: Omit<GateOptions, \"meta\">;\n};\n\n/**\n * Bundle returned by {@link gatedStream}.\n */\nexport type GatedStreamHandle<T> = {\n\t/** Final parsed result (after gate approval). */\n\toutput: Node<T | null>;\n\t/** Live delta topic — every adapter delta in order, stamped with `seq` + `ts`. */\n\tdeltaTopic: TopicGraph<StampedDelta>;\n\t/** Reactive accumulated-text view. */\n\taccumulatedText: Node<string>;\n\t/**\n\t * Gate controller — approve, reject (aborts in-flight stream), modify.\n\t * The gate's DATA domain is `T` (not `T | null`): the pre-gate `filter`\n\t * drops nulls, so the pending queue never holds a null. The controller's\n\t * `node` output type stays `T | null` only because `gate.approve()` on an\n\t * empty queue would surface `null` — callers should treat `null` as \"no\n\t * value\" rather than as a modeled null signal.\n\t */\n\tgate: GateController<T>;\n\t/** Tear down the delta topic + gate keepalive. */\n\tdispose: () => void;\n};\n\n/**\n * Streaming LLM transform with human-in-the-loop gate integration.\n *\n * Composes {@link streamingPromptNode} with `gate` so that:\n * - `gate.reject()` discards the pending value **and** aborts the in-flight\n * stream (toggles an internal cancel signal → switchMap restart → abort).\n * - `gate.modify()` transforms the pending value before forwarding downstream.\n * - `gate.approve()` forwards the final result as normal.\n *\n * Wave A Unit 2 defers full `gatedStream` review to Wave B Unit 17 (the\n * `gate()` primitive itself is reviewed there). This implementation retains\n * the existing gate API while adopting the Unit 2 delta-topic shape.\n */\nexport function gatedStream<T = string>(\n\tgraph: Graph,\n\tname: string,\n\tadapter: LLMAdapter,\n\tdeps: readonly Node<unknown>[],\n\tprompt: string | ((...depValues: unknown[]) => string),\n\topts?: GatedStreamOptions,\n): GatedStreamHandle<T> {\n\tconst cancelSignal = node<number>([], { name: `${name}/cancel`, initial: 0 });\n\tlet cancelCounter = 0;\n\n\tconst allDeps = [...deps, cancelSignal] as readonly Node<unknown>[];\n\n\tconst sourceName = opts?.name ?? name;\n\tconst format = opts?.format ?? \"text\";\n\tconst deltaTopic = topic<StampedDelta>(`${sourceName}/stream`, {\n\t\t...(opts?.retainedLimit != null ? { retainedLimit: opts.retainedLimit } : {}),\n\t});\n\n\tconst messagesNode = node<readonly ChatMessage[]>(\n\t\tallDeps as Node<unknown>[],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\t// Last dep is the cancel signal — exclude from prompt args.\n\t\t\tconst depValues = data.slice(0, -1);\n\t\t\tif (depValues.some((v) => v == null)) {\n\t\t\t\tactions.emit([]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst text = typeof prompt === \"string\" ? prompt : prompt(...depValues);\n\t\t\tif (!text) {\n\t\t\t\tactions.emit([]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tactions.emit([{ role: \"user\", content: text }]);\n\t\t},\n\t\t{\n\t\t\tname: `${sourceName}::messages`,\n\t\t\tmeta: aiMeta(\"prompt_node::messages\"),\n\t\t\tinitial: [] as readonly ChatMessage[],\n\t\t},\n\t);\n\n\tconst output = switchMap(\n\t\tmessagesNode,\n\t\t(msgs) => {\n\t\t\tconst chatMsgs = msgs as readonly ChatMessage[];\n\t\t\tif (!chatMsgs || chatMsgs.length === 0) {\n\t\t\t\treturn node<T | null>([], { initial: null }) as NodeInput<T | null>;\n\t\t\t}\n\t\t\tconst ac = new AbortController();\n\t\t\tasync function* pumpAndCollect(): AsyncGenerator<T | null> {\n\t\t\t\ttry {\n\t\t\t\t\tconst accumulated = await streamingInvoke(\n\t\t\t\t\t\tadapter,\n\t\t\t\t\t\tchatMsgs,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmodel: opts?.model,\n\t\t\t\t\t\t\ttemperature: opts?.temperature,\n\t\t\t\t\t\t\tmaxTokens: opts?.maxTokens,\n\t\t\t\t\t\t\tsystemPrompt: opts?.systemPrompt,\n\t\t\t\t\t\t\tsignal: ac.signal,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tdeltaTopic,\n\t\t\t\t\t);\n\t\t\t\t\tyield parseAccumulated<T>(accumulated, format);\n\t\t\t\t} finally {\n\t\t\t\t\tac.abort();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn fromAny(pumpAndCollect());\n\t\t},\n\t\t{ meta: factoryTag(\"gatedStream\") },\n\t);\n\n\tconst accumulatedText = makeAccumulatedText(deltaTopic, `${sourceName}::accumulatedText`);\n\n\t// Filter out null stream results so the gate only sees real values. Using\n\t// `filter()` (not a `derived` with `return undefined`) is load-bearing:\n\t// `derived`'s wrapper always calls `actions.emit(fn(data))`, so returning\n\t// `undefined` would still emit `DATA(undefined)` into the gate's pending\n\t// queue — approve/modify would then surface `undefined` to downstream\n\t// consumers. `filter` propagates RESOLVED for falsey matches, keeping the\n\t// queue clean. (This was the second half of the gatedStream activation\n\t// fix — the first was keepalive-ing `gateCtrl.output`.)\n\tconst nonNullOutput = filter<T | null>(output, (v) => v != null) as Node<T>;\n\tgraph.add(nonNullOutput, { name: `${name}/raw` });\n\n\t// Wire gate on the output. Type parameter is `T` (not `T | null`) — the\n\t// `filter` above drops nulls before they reach the gate, so the pending\n\t// queue's DATA domain is `T` only.\n\t//\n\t// C3 — `nonNullOutput` is owned by the parent `graph`. Pass it as a Node\n\t// ref to `approvalGate`; the gate's foreign-source path wraps it in a\n\t// local proxy derived registered under `${name}/gate/source` inside\n\t// gateSubgraph. The dual-add pattern (`graph.add` + `gateSubgraph.add`)\n\t// is retired — Session B.1's \"no wrapper\" invariant gave way to the\n\t// single-owner invariant per the C3 lock.\n\tconst gateSubgraph = pipelineGraph(`${name}/gate-graph`);\n\tgraph.mount(`${name}/gate-graph`, gateSubgraph);\n\tconst gateCtrl = gateSubgraph.approvalGate<T>(\n\t\t`${name}/gate`,\n\t\tnonNullOutput as Node<unknown>,\n\t\topts?.gate,\n\t);\n\n\t// Keepalive the switchMap product, the gate's output node, AND the\n\t// accumulator so the full bundle contract (\"three reactive surfaces, any\n\t// one activates the pipeline\") holds:\n\t//\n\t// - `keepalive(output)` activates the streaming switchMap so the adapter\n\t// generator runs even before a downstream subscriber attaches.\n\t// - `keepalive(gateCtrl.output)` activates the gate's fn body — which is\n\t// what writes into the internal `pending` queue. Without it, a caller\n\t// that only subscribes to `gate.count` / `gate.pending` / `deltaTopic`\n\t// (but not `gate.output`) would see `count` stuck at 0 indefinitely:\n\t// stream values reach the gate's input but the gate's fn never runs.\n\t// - `keepalive(accumulatedText)` ensures `.cache` reflects the running\n\t// total for callers that read the accumulator as a snapshot instead of\n\t// subscribing to it.\n\t//\n\t// Dropping any of the three surfaces as a silent stall in `ai.test.ts`'s\n\t// gatedStream suite.\n\t//\n\t// All three unsubs are also registered with the host graph so\n\t// `parent.destroy()` reclaims them even if the caller forgets to call\n\t// `dispose()`. `dispose()` itself runs them eagerly for prompt teardown.\n\tconst unsubOutput = keepalive(output);\n\tconst unsubGate = keepalive(gateCtrl.output);\n\tconst unsubAccumulated = keepalive(accumulatedText);\n\tgraph.addDisposer(unsubOutput);\n\tgraph.addDisposer(unsubGate);\n\tgraph.addDisposer(unsubAccumulated);\n\n\t// Wrap reject to also abort the in-flight stream. Both mutations happen\n\t// inside `batch()` so downstream subscribers never observe a torn state\n\t// where `gate.count` has decremented but `cancelSignal` hasn't yet\n\t// advanced (spec §2 two-phase DIRTY-before-DATA atomicity).\n\tconst originalReject = gateCtrl.reject.bind(gateCtrl);\n\tconst gateWithAbort: GateController<T> = {\n\t\t...gateCtrl,\n\t\treject(count = 1) {\n\t\t\tbatch(() => {\n\t\t\t\toriginalReject(count);\n\t\t\t\tcancelSignal.emit(++cancelCounter);\n\t\t\t});\n\t\t},\n\t};\n\n\treturn {\n\t\toutput: gateCtrl.output,\n\t\tdeltaTopic,\n\t\taccumulatedText,\n\t\tgate: gateWithAbort,\n\t\tdispose: () => {\n\t\t\tunsubOutput();\n\t\t\tunsubGate();\n\t\t\tunsubAccumulated();\n\t\t\tdeltaTopic.destroy();\n\t\t},\n\t};\n}\n","/**\n * Messaging patterns (roadmap §4.2).\n *\n * Pulsar-inspired messaging primitives modeled as graph factories:\n * - `topic()` for append-only topic streams with a retained window.\n * - `subscription()` for cursor-based consumers.\n * - `topicBridge()` for autonomous topic-to-topic relay.\n * - `messagingHub()` for a lazy topic registry.\n *\n * Plus the Phase 13.B standard `Message<T>` envelope and well-known topic\n * name constants ({@link PROMPTS_TOPIC} / {@link RESPONSES_TOPIC} /\n * {@link INJECTIONS_TOPIC} / {@link DEFERRED_TOPIC} / {@link SPAWNS_TOPIC})\n * — recommended (not enforced) wire shape for cross-graph topic payloads.\n *\n * Job queue / job flow primitives live in `patterns/job-queue` — they are a\n * distinct domain that happens to share reactive-log / reactive-map\n * infrastructure with topics.\n */\n\nexport {\n\ttype HubRemoveTopicRecord,\n\thubRemoveTopicKeyOf,\n\ttype MessagingAuditRecord,\n\ttype SubscriptionAckRecord,\n\ttype SubscriptionPullAndAckRecord,\n\tsubscriptionAckKeyOf,\n\tsubscriptionPullAndAckKeyOf,\n\ttype TopicPublishRecord,\n\ttopicPublishKeyOf,\n} from \"./audit-records.js\";\nexport {\n\tCONTEXT_TOPIC,\n\tDEFERRED_TOPIC,\n\tINJECTIONS_TOPIC,\n\ttype JsonSchema,\n\tPROMPTS_TOPIC,\n\tRESPONSES_TOPIC,\n\tSPAWNS_TOPIC,\n\tSTANDARD_TOPICS,\n\ttype StandardTopic,\n\tTODOS_TOPIC,\n\ttype TopicMessage,\n} from \"./message.js\";\n\nimport { batch, COMPLETE, DATA, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { keepalive, reactiveLog } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport { mutate } from \"../../base/mutation/index.js\";\n\nconst DEFAULT_MAX_PER_PUMP = 256;\n\nfunction requireNonNegativeInt(value: number, label: string): number {\n\tif (!Number.isFinite(value) || !Number.isInteger(value) || value < 0) {\n\t\tthrow new Error(`${label} must be a non-negative integer`);\n\t}\n\treturn value;\n}\n\nfunction messagingMeta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"messaging\", kind, extra);\n}\n\nexport type TopicOptions = {\n\tgraph?: GraphOptions;\n\t/** Bounded retention; default 1024 per cross-cutting policy (Audit 2/4). */\n\tretainedLimit?: number;\n};\n\nconst DEFAULT_TOPIC_RETAINED_LIMIT = 1024;\n\nexport class TopicGraph<T> extends Graph {\n\tprivate readonly _log;\n\tprivate readonly _publishImpl: (value: T) => void;\n\treadonly events: Node<readonly T[]>;\n\t/**\n\t * Most recently published value. Stays in the protocol SENTINEL state\n\t * (`cache === undefined`, no DATA emitted) until the first publish, then\n\t * tracks the latest entry. Spec §5.12 reserves `undefined` as the\n\t * \"never sent DATA\" sentinel — and `TopicGraph.publish(undefined)` is\n\t * rejected — so `cache === undefined` unambiguously signals \"empty topic\"\n\t * even when `T` itself includes `null` (i.e., `topic<number | null>`).\n\t *\n\t * **Within a reactive fn:** detect the empty-topic case via\n\t * `ctx.prevData[i] === undefined` for the dep slot holding `topic.latest`,\n\t * or check `latest.cache === undefined` outside reactive code. No\n\t * separate `hasLatest` companion needed — the SENTINEL is the answer.\n\t */\n\treadonly latest: Node<T>;\n\n\tconstructor(name: string, opts: TopicOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t\tthis._log = reactiveLog<T>([], {\n\t\t\tname: \"events\",\n\t\t\tmaxSize: opts.retainedLimit ?? DEFAULT_TOPIC_RETAINED_LIMIT,\n\t\t});\n\t\tthis.events = this._log.entries;\n\t\tthis.add(this.events, { name: \"events\" });\n\t\t// `this.derived(\"latest\", [\"events\"], …)` is expressible after the\n\t\t// 2026-04-30 self-resolve fix in `Graph._resolveFromSegments` — a\n\t\t// single-segment path matching the graph's own name (e.g.\n\t\t// `topic(\"events\").resolve(\"events\")`) no longer collapses to empty\n\t\t// and falls through to local-node lookup. Replaces the prior\n\t\t// `node([events], …) + this.add(...)` workaround.\n\t\t//\n\t\t// SENTINEL on empty: returning `[]` here yields a RESOLVED-only wave\n\t\t// (no DATA), so `latest.cache` stays `undefined` until the first\n\t\t// publish. `TopicGraph.publish(undefined)` is rejected (line below),\n\t\t// so `undefined` cache is unambiguously \"empty topic\" even when `T`\n\t\t// itself includes `null`. Drops the prior `hasLatest` companion as\n\t\t// redundant.\n\t\tthis.latest = this.derived<T>(\n\t\t\t\"latest\",\n\t\t\t[\"events\"],\n\t\t\t(batchData, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst entries = data[0] as readonly T[];\n\t\t\t\treturn entries.length === 0 ? [] : [entries[entries.length - 1] as T];\n\t\t\t},\n\t\t\t{ meta: messagingMeta(\"topic_latest\") },\n\t\t);\n\t\tthis.addDisposer(keepalive(this.latest));\n\n\t\t// D1(a): on teardown, propagate COMPLETE on `events` so downstream\n\t\t// derived chains (including any externally-held SubscriptionGraph\n\t\t// sources) see the termination via their `terminalDeps` and can stop\n\t\t// serving stale caches. Tier-3 terminal per spec §2.2.\n\t\t//\n\t\t// EC16 (verified 2026-04-30): the COMPLETE-then-disposeAllViews order\n\t\t// is intentional. COMPLETE propagates SYNCHRONOUSLY through every\n\t\t// subscriber (cursor views, derived chains) so they self-unsubscribe\n\t\t// in their terminal handler before `disposeAllViews` runs. Swapping\n\t\t// the order would clear view caches before subscribers receive the\n\t\t// terminal — strictly worse. Reading `.cache` outside a reactive fn\n\t\t// across teardown is an anti-pattern (spec §5.12) and not a use case\n\t\t// this ordering needs to preserve.\n\t\tthis.addDisposer(() => {\n\t\t\tthis.events.down([[COMPLETE]]);\n\t\t});\n\t\t// P9: release any memoized tail/slice view keepalives held by the log.\n\t\t// TopicGraph itself doesn't call log.tail/slice, but plugins may have\n\t\t// attached views via `_log` — defensive (typical reactive subscribers\n\t\t// have already unsubscribed in their COMPLETE handler above).\n\t\tthis.addDisposer(() => this._log.disposeAllViews());\n\n\t\t// Tier 8 / COMPOSITION-GUIDE §35: route publish through `mutate`\n\t\t// for centralized freeze + re-throw semantics. No audit log surface\n\t\t// (per Tier 8 γ-0): the topic's `events` log already records every\n\t\t// successful publish, so a separate audit Node would be redundant.\n\t\t// `freeze: false` because topic payloads can be large and per-publish\n\t\t// cost matters on hot paths.\n\t\tthis._publishImpl = mutate<[T], void, never>(\n\t\t\t(value): void => {\n\t\t\t\tthis._log.append(value);\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\t}\n\n\tpublish(value: T): void {\n\t\t// SENTINEL alignment (Wave B.1 Unit 11 lock): `undefined` is the\n\t\t// protocol-level \"never sent DATA\" sentinel — refusing it here\n\t\t// preserves `lastValue: Node<T | undefined>` semantics.\n\t\tif (value === undefined) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`TopicGraph \"${this.name}\": publish(undefined) is not allowed (spec §5.12 SENTINEL).`,\n\t\t\t);\n\t\t}\n\t\tthis._publishImpl(value);\n\t}\n\n\t/**\n\t * Wire one or more append-log storage tiers (Audit 4). Each tier receives\n\t * appended events per wave; rollback honors the wave-as-transaction model.\n\t *\n\t * Named `attachEventStorage` (not `attachStorage`) to avoid colliding with\n\t * the inherited {@link Graph.attachSnapshotStorage} which takes the\n\t * paired `AttachSnapshotTierPair[]` shape (Phase 14.6) — distinct\n\t * concerns, distinct surfaces.\n\t *\n\t * @returns Disposer.\n\t */\n\tattachEventStorage(\n\t\ttiers: readonly import(\"@graphrefly/pure-ts/extra\").AppendLogStorageTier<T>[],\n\t): () => void {\n\t\treturn this._log.attachStorage(tiers);\n\t}\n\n\tretained(): readonly T[] {\n\t\treturn this.events.cache as readonly T[];\n\t}\n\n\t/** Internal log bundle — used by TopicBridgeGraph for `attach`. */\n\tget _logBundle() {\n\t\treturn this._log;\n\t}\n}\n\nexport type SubscriptionOptions = {\n\tgraph?: GraphOptions;\n\t/**\n\t * Starting cursor position.\n\t * @deprecated Use `from` instead.\n\t */\n\tcursor?: number;\n\t/**\n\t * Starting position for the subscription.\n\t * - `\"retained\"` (default) — cursor starts at 0; consumer sees all retained history.\n\t * - `\"now\"` — cursor starts at current topic length; consumer ignores history.\n\t * - `number` — explicit cursor position.\n\t */\n\tfrom?: \"now\" | \"retained\" | number;\n\t/**\n\t * When this signal node emits DATA, the subscription auto-advances cursor\n\t * to current `available.length`. Useful for \"ack everything when X happens\"\n\t * patterns. The reactive edge `advanceOn → cursor` is visible in `explain()`.\n\t */\n\tadvanceOn?: Node<unknown>;\n};\n\n/** Result of {@link SubscriptionGraph.pullAndAck}. */\nexport type PullAndAckResult<T> = {\n\titems: readonly T[];\n\tcursor: number;\n};\n\nexport class SubscriptionGraph<T> extends Graph {\n\treadonly cursor: Node<number>;\n\treadonly available: Node<readonly T[]>;\n\t/**\n\t * Reference to the upstream topic graph. Intentionally NOT mounted\n\t * under this subscription: a subscription is a VIEW over an\n\t * externally-owned topic. Double-mounting (e.g. hub-owned topic +\n\t * sub-mount here) would make either-side teardown leave the other\n\t * holding a dead reference. Node-level `derived([topicEvents], …)`\n\t * still wires the data dependency across graph boundaries. D1(e).\n\t */\n\treadonly topic: TopicGraph<T>;\n\n\tprivate _disposed = false;\n\tprivate readonly _ackImpl: (count: number | undefined) => number;\n\tprivate readonly _pullAndAckImpl: (limit: number | undefined) => PullAndAckResult<T>;\n\n\tconstructor(name: string, topicGraph: TopicGraph<T>, opts: SubscriptionOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t\tthis.topic = topicGraph;\n\n\t\t// Resolve initial cursor from `from` option, falling back to legacy `cursor` option.\n\t\tlet initialCursor: number;\n\t\tif (opts.from !== undefined) {\n\t\t\tif (opts.from === \"retained\") {\n\t\t\t\tinitialCursor = 0;\n\t\t\t} else if (opts.from === \"now\") {\n\t\t\t\t// §28 sanctioned factory-time boundary read.\n\t\t\t\tinitialCursor = (topicGraph.events.cache as readonly T[]).length;\n\t\t\t} else {\n\t\t\t\tinitialCursor = requireNonNegativeInt(opts.from, \"subscription from\");\n\t\t\t}\n\t\t} else {\n\t\t\tinitialCursor = requireNonNegativeInt(opts.cursor ?? 0, \"subscription cursor\");\n\t\t}\n\n\t\tthis.cursor = this.state<number>(\"cursor\", initialCursor, {\n\t\t\tmeta: messagingMeta(\"subscription_cursor\"),\n\t\t});\n\n\t\t// B.1 Unit 12 lock: `available` depends directly on topic.events + cursor\n\t\t// via `view({ kind: \"fromCursor\" })`. No `source` passthrough node —\n\t\t// describe shows `topic::events → available` (cross-graph edge) and\n\t\t// `cursor → available` (local edge). One fewer node per subscription.\n\t\tthis.available = topicGraph._logBundle.view({ kind: \"fromCursor\", cursor: this.cursor });\n\t\tthis.add(this.available, { name: \"available\" });\n\t\tthis.addDisposer(keepalive(this.available));\n\n\t\t// Optional reactive auto-advance: when `advanceOn` emits a NEW DATA\n\t\t// (after construction), cursor advances by `available.length` atomically.\n\t\t// Edge visible in describe: advancePump depends on advanceOn.\n\t\t// `_advanceInitialized` guards against the initial push-on-subscribe fire\n\t\t// that would advance cursor before the user has a chance to read.\n\t\tif (opts.advanceOn !== undefined) {\n\t\t\tconst advanceOn = opts.advanceOn;\n\t\t\tlet advanceInitialized = false;\n\t\t\tconst advancePump = node<unknown>(\n\t\t\t\t[advanceOn],\n\t\t\t\t() => {\n\t\t\t\t\t// Skip the initial push-on-subscribe wave.\n\t\t\t\t\tif (!advanceInitialized) {\n\t\t\t\t\t\tadvanceInitialized = true;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (this._disposed) return;\n\t\t\t\t\tconst avail = this.available.cache as readonly T[];\n\t\t\t\t\tif (avail.length === 0) return;\n\t\t\t\t\tconst next = (this.cursor.cache as number) + avail.length;\n\t\t\t\t\tthis.cursor.emit(next);\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"advancePump\",\n\t\t\t\t\tdescribeKind: \"effect\",\n\t\t\t\t\tmeta: messagingMeta(\"subscription_advance_pump\"),\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis.add(advancePump, { name: \"advancePump\" });\n\t\t\tthis.addDisposer(keepalive(advancePump));\n\t\t}\n\n\t\t// Tier 8 / COMPOSITION-GUIDE §35: route ack + pullAndAck through\n\t\t// `mutate` for centralized freeze + re-throw semantics. No audit\n\t\t// log surface (per Tier 8 γ-0): the cursor's own emission stream already\n\t\t// records every advance, so a separate audit Node would be redundant.\n\t\t// `freeze: false` because count/limit are simple numbers; freezing is\n\t\t// pointless overhead. Disposed-checks stay outside the wrapper so a\n\t\t// no-op call doesn't unnecessarily run the wrapper.\n\t\tthis._ackImpl = mutate<[number | undefined], number, never>(\n\t\t\t(count): number => {\n\t\t\t\tconst available = this.available.cache as readonly T[];\n\t\t\t\tconst requested =\n\t\t\t\t\tcount === undefined\n\t\t\t\t\t\t? available.length\n\t\t\t\t\t\t: requireNonNegativeInt(count, \"subscription ack count\");\n\t\t\t\tconst step = Math.min(requested, available.length);\n\t\t\t\tif (step <= 0) return this.cursor.cache as number;\n\t\t\t\tconst next = (this.cursor.cache as number) + step;\n\t\t\t\t// F8: use emit() so the pipeline auto-prefixes DIRTY, runs equals\n\t\t\t\t// substitution, and produces a proper two-phase wave (the raw\n\t\t\t\t// `down([[DATA, next]])` path bypassed those contracts).\n\t\t\t\tthis.cursor.emit(next);\n\t\t\t\treturn next;\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\n\t\tthis._pullAndAckImpl = mutate<[number | undefined], PullAndAckResult<T>, never>(\n\t\t\t(limit): PullAndAckResult<T> => {\n\t\t\t\tconst available = this.available.cache as readonly T[];\n\t\t\t\tconst max =\n\t\t\t\t\tlimit === undefined\n\t\t\t\t\t\t? available.length\n\t\t\t\t\t\t: requireNonNegativeInt(limit, \"subscription pullAndAck limit\");\n\t\t\t\tconst items = available.slice(0, max);\n\t\t\t\tif (items.length === 0) return { items, cursor: this.cursor.cache as number };\n\t\t\t\tconst next = (this.cursor.cache as number) + items.length;\n\t\t\t\tthis.cursor.emit(next);\n\t\t\t\treturn { items, cursor: next };\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\t}\n\n\tack(count?: number): number {\n\t\tif (this._disposed) return this.cursor.cache as number;\n\t\treturn this._ackImpl(count);\n\t}\n\n\tpull(limit?: number): readonly T[] {\n\t\tif (this._disposed) return [];\n\t\tconst available = this.available.cache as readonly T[];\n\t\tconst max =\n\t\t\tlimit === undefined\n\t\t\t\t? available.length\n\t\t\t\t: requireNonNegativeInt(limit, \"subscription pull limit\");\n\t\treturn available.slice(0, max);\n\t}\n\n\t/**\n\t * Atomic pull-and-acknowledge. Returns `{ items, cursor }` where `cursor`\n\t * is the new cursor position after advancing. Under single-threaded JS the\n\t * snapshot and advance are atomic; PY callers use a per-subscription Lock.\n\t *\n\t * Replaces `pull(limit, { ack: true })`.\n\t */\n\tpullAndAck(limit?: number): PullAndAckResult<T> {\n\t\tif (this._disposed) return { items: [], cursor: this.cursor.cache as number };\n\t\treturn this._pullAndAckImpl(limit);\n\t}\n\n\t/**\n\t * Release internal subscriptions and mark the subscription torn-down.\n\t * Subsequent `pull`, `pullAndAck`, `ack` return empty / current cursor.\n\t * Emits COMPLETE on `cursor` so derived consumers (e.g. `available`) see\n\t * the termination signal. Also drains `addDisposer` callbacks (including\n\t * the `keepalive(advancePump)` subscription) so no keepalive leak occurs.\n\t */\n\tdispose(): void {\n\t\tif (this._disposed) return;\n\t\tthis._disposed = true;\n\t\tthis.cursor.down([[COMPLETE]]);\n\t\t// m4: drain addDisposer callbacks to release the keepalive subscription.\n\t\tthis.destroy();\n\t}\n}\n\nexport type TopicBridgeOptions<TIn, TOut> = {\n\tgraph?: GraphOptions;\n\tcursor?: number;\n\tmaxPerPump?: number;\n\t/**\n\t * Optional transform/filter applied to each item before republishing.\n\t *\n\t * **At-most-once with silent drop:** when `map` returns `undefined`, the\n\t * input is consumed from the source cursor but NOT republished. Filtered\n\t * items are not retained for retry. If you need filter-with-retry\n\t * semantics, do the filtering in a downstream subscription on the bridged\n\t * output rather than in the `map` function.\n\t */\n\tmap?: (value: TIn) => TOut | undefined;\n};\n\nexport class TopicBridgeGraph<TIn, TOut = TIn> extends Graph {\n\tprivate readonly _sourceSub;\n\treadonly bridgedCount: Node<number>;\n\t/**\n\t * Emits each mapped batch as DATA — gives downstream observers a reactive\n\t * stream of bridged values. Also the link target for `target._log.attach`.\n\t */\n\treadonly output: Node<readonly TOut[]>;\n\n\tconstructor(\n\t\tname: string,\n\t\tsourceTopic: TopicGraph<TIn>,\n\t\ttargetTopic: TopicGraph<TOut>,\n\t\topts: TopicBridgeOptions<TIn, TOut> = {},\n\t) {\n\t\tsuper(name, opts.graph);\n\t\tthis._sourceSub = subscription<TIn>(`${name}-subscription`, sourceTopic, {\n\t\t\tcursor: opts.cursor,\n\t\t});\n\t\tthis.mount(\"subscription\", this._sourceSub);\n\n\t\tconst maxPerPump = Math.max(\n\t\t\t1,\n\t\t\trequireNonNegativeInt(opts.maxPerPump ?? DEFAULT_MAX_PER_PUMP, \"topic bridge maxPerPump\"),\n\t\t);\n\t\tconst mapValue = opts.map ?? ((value: TIn) => value as unknown as TOut);\n\n\t\t// Reactive output node: derives a mapped batch from `available`.\n\t\t// §24 compliant — output is a real derived edge, visible in describe.\n\t\t// Replaces imperative publish loop. Items where mapValue returns undefined\n\t\t// are filtered out (opt-out / filter).\n\t\tthis.output = node<readonly TOut[]>(\n\t\t\t[this._sourceSub.available],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst arr = data[0] as readonly TIn[];\n\t\t\t\tconst outBatch: TOut[] = [];\n\t\t\t\tconst take = Math.min(arr.length, maxPerPump);\n\t\t\t\tfor (let i = 0; i < take; i++) {\n\t\t\t\t\tconst mapped = mapValue(arr[i] as TIn);\n\t\t\t\t\tif (mapped !== undefined) outBatch.push(mapped);\n\t\t\t\t}\n\t\t\t\tactions.emit(outBatch);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"output\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: messagingMeta(\"topic_bridge_output\", { targetRef: targetTopic.name }),\n\t\t\t\tinitial: [],\n\t\t\t},\n\t\t);\n\t\tthis.add(this.output, { name: \"output\" });\n\t\tthis.addDisposer(keepalive(this.output));\n\n\t\t// bridgedCount: state node accumulating total bridged items.\n\t\t// Updated by ackPump after each batch — edge visible via ackPump dep on output.\n\t\tthis.bridgedCount = this.state<number>(\"bridgedCount\", 0, {\n\t\t\tmeta: messagingMeta(\"topic_bridge_count\"),\n\t\t});\n\t\tthis.addDisposer(keepalive(this.bridgedCount));\n\n\t\t// ackPump: effect that advances the subscription cursor and updates\n\t\t// bridgedCount after each batch. Runs after `output` settles.\n\t\t// Captures refs to `this.output`, `this._sourceSub`, `this.bridgedCount`\n\t\t// to avoid `this` inside the fn body.\n\t\tconst outputRef = this.output;\n\t\tconst subRef = this._sourceSub;\n\t\tconst countRef = this.bridgedCount;\n\t\tconst ackPump = this.effect(\n\t\t\t\"ackPump\",\n\t\t\t[\"output\"],\n\t\t\t() => {\n\t\t\t\tconst outBatch = outputRef.cache as readonly TOut[];\n\t\t\t\tif (outBatch.length === 0) return;\n\t\t\t\tconst availLen = (subRef.available.cache as readonly TIn[]).length;\n\t\t\t\tconst toAck = Math.min(availLen, maxPerPump);\n\t\t\t\tif (toAck > 0) {\n\t\t\t\t\tsubRef.ack(toAck);\n\t\t\t\t\tconst prev = (countRef.cache as number) ?? 0;\n\t\t\t\t\tcountRef.emit(prev + outBatch.length);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\tmeta: messagingMeta(\"topic_bridge_ack_pump\"),\n\t\t\t},\n\t\t);\n\t\tthis.addDisposer(keepalive(ackPump));\n\n\t\t// Wire output into target topic's log reactively.\n\t\t// _attachArrayToLog subscribes to output and publishes each item to targetTopic.\n\t\t// Teardown: disposer runs before mount teardown.\n\t\tconst detach = _attachArrayToLog(this.output, targetTopic);\n\t\tthis.addDisposer(detach);\n\t}\n}\n\n/**\n * Attaches each element of an array-valued Node to a TopicGraph's log.\n * Every DATA emission on `source` appends all items in the array to `targetTopic`.\n * Returns a disposer.\n */\nfunction _attachArrayToLog<T>(source: Node<readonly T[]>, targetTopic: TopicGraph<T>): () => void {\n\treturn source.subscribe((msgs) => {\n\t\tfor (const m of msgs) {\n\t\t\tif (m[0] !== DATA) continue;\n\t\t\tconst arr = m[1] as readonly T[];\n\t\t\tif (arr.length === 0) continue;\n\t\t\tbatch(() => {\n\t\t\t\tfor (const v of arr) targetTopic.publish(v);\n\t\t\t});\n\t\t}\n\t});\n}\n\n// ── TopicRegistry ─────────────────────────────────────────────────────────\n\n/**\n * Private pure data structure managing a named set of {@link TopicGraph}\n * instances. Extracted from {@link MessagingHubGraph} for separation of\n * concerns (B.2 Unit 14 lock: D — split into TopicRegistry + facade).\n *\n * Reusable if other domain consumers (e.g. cqrs.eventLogs) want a shared\n * topic registry later.\n *\n * @internal\n */\nexport class TopicRegistry {\n\tprivate readonly _map = new Map<string, TopicGraph<unknown>>();\n\t/** Reactive monotonic version counter. Advances on topic create/remove. */\n\treadonly version: Node<number>;\n\n\tconstructor(versionNode: Node<number>) {\n\t\tthis.version = versionNode;\n\t}\n\n\tget size(): number {\n\t\treturn this._map.size;\n\t}\n\n\thas(name: string): boolean {\n\t\treturn this._map.has(name);\n\t}\n\n\tget<T>(name: string): TopicGraph<T> | undefined {\n\t\treturn this._map.get(name) as TopicGraph<T> | undefined;\n\t}\n\n\tset<T>(name: string, t: TopicGraph<T>): void {\n\t\tthis._map.set(name, t as TopicGraph<unknown>);\n\t}\n\n\tdelete(name: string): boolean {\n\t\treturn this._map.delete(name);\n\t}\n\n\tkeys(): IterableIterator<string> {\n\t\treturn this._map.keys();\n\t}\n}\n\n// ── MessagingHubGraph ─────────────────────────────────────────────────────\n\nexport type MessagingHubOptions = {\n\tgraph?: GraphOptions;\n\t/**\n\t * Default `TopicOptions` applied to every topic created via `topic(name)`\n\t * without explicit options. Per-call opts override. Default: `{}`\n\t * (unbounded retention per topic unless `retainedLimit` is set per call).\n\t */\n\tdefaultTopicOptions?: TopicOptions;\n};\n\n/**\n * Lazy Pulsar-inspired topic registry. Manages a named set of {@link TopicGraph}\n * instances with retention + cursor semantics. Topics are created on first\n * access; `removeTopic(name)` unmounts and tears down via {@link Graph.remove}.\n *\n * Internally delegates to {@link TopicRegistry} for topic map management\n * (B.2 Unit 14 lock: D facade split).\n *\n * **Relationship to `pubsub()` in `src/extra/pubsub.ts`:** `pubsub` is a\n * lightweight last-value state hub (no retention, no cursors). `MessagingHubGraph`\n * is the full messaging hub — retained message logs, cursor-based subscriptions,\n * and pattern-layer lifecycle management.\n *\n * @category patterns\n */\nexport class MessagingHubGraph extends Graph {\n\tprivate readonly _registry: TopicRegistry;\n\t/** Reactive monotonic version counter — advances on topic create/remove. */\n\treadonly version: Node<number>;\n\tprivate readonly _defaultTopicOptions: TopicOptions;\n\tprivate readonly _removeTopicImpl: (name: string) => void;\n\n\tconstructor(name: string, opts: MessagingHubOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t\t// B.2 Unit 14 lock: promote _version → version: Node<number>.\n\t\tconst versionNode = this.state<number>(\"version\", 0, {\n\t\t\tmeta: messagingMeta(\"hub_version\"),\n\t\t});\n\t\tthis.version = versionNode;\n\t\tthis._registry = new TopicRegistry(versionNode);\n\t\t// P8: shallow-copy caller-provided defaults so post-construction\n\t\t// mutations by the caller don't leak into every future `topic()` call.\n\t\tthis._defaultTopicOptions = { ...(opts.defaultTopicOptions ?? {}) };\n\n\t\t// Tier 8 / COMPOSITION-GUIDE §35: route the registry-delete branch of\n\t\t// `removeTopic` through `mutate` for centralized re-throw\n\t\t// semantics. No audit log surface (per Tier 8 γ-0).\n\t\t// `freeze: false` because the only arg is a string name (freeze pointless).\n\t\t// **Closure-state caveat (γ-4):** the inner `try/finally` mutates\n\t\t// `_registry` (a `Map`) and emits the version bump. mutate has no\n\t\t// `batch()` frame, so reactive emissions are NOT rolled back on throw —\n\t\t// and even if it did, `Map.delete` on closure state is invisible to the\n\t\t// batch and can't be unwound. The pre-existing try/finally on\n\t\t// `Graph.remove` is what guarantees registry/version converge to a\n\t\t// consistent state when `remove()` throws; `mutate` adds nothing\n\t\t// to that contract beyond the re-throw.\n\t\tthis._removeTopicImpl = mutate<[string], void, never>(\n\t\t\t(topicName): void => {\n\t\t\t\ttry {\n\t\t\t\t\tthis.remove(topicName); // unmounts, drops edges, tears down\n\t\t\t\t} finally {\n\t\t\t\t\tthis._registry.delete(topicName);\n\t\t\t\t\tconst cur = (this.version.cache as number) ?? 0;\n\t\t\t\t\tthis.version.emit(cur + 1);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\t}\n\n\t/** Number of topics currently in the hub. */\n\tget size(): number {\n\t\treturn this._registry.size;\n\t}\n\n\t/** Checks topic existence without creating. */\n\thas(name: string): boolean {\n\t\treturn this._registry.has(name);\n\t}\n\n\t/** Iterator over topic names. */\n\ttopicNames(): IterableIterator<string> {\n\t\treturn this._registry.keys();\n\t}\n\n\t/**\n\t * Returns the {@link TopicGraph} for `name`, creating lazily on first call.\n\t * Subsequent calls with the same name return the same instance (options on\n\t * repeat calls are ignored — the topic is already configured).\n\t */\n\ttopic<T = unknown>(name: string, opts?: TopicOptions): TopicGraph<T> {\n\t\tlet t = this._registry.get<T>(name);\n\t\tif (t === undefined) {\n\t\t\tconst effective: TopicOptions = { ...this._defaultTopicOptions, ...(opts ?? {}) };\n\t\t\tt = new TopicGraph<T>(name, effective);\n\t\t\tthis._registry.set(name, t);\n\t\t\tthis.mount(name, t);\n\t\t\tconst cur = (this.version.cache as number) ?? 0;\n\t\t\tthis.version.emit(cur + 1);\n\t\t}\n\t\treturn t;\n\t}\n\n\t/**\n\t * Publishes a value to the topic, lazily creating it on first publish.\n\t *\n\t * **Late-subscriber caveat:** the topic is created lazily, so subscribers\n\t * that attach AFTER a publish only see the retained window (governed by\n\t * `retainedLimit` on `TopicOptions` / `defaultTopicOptions`). If\n\t * `retainedLimit === 0` is set explicitly, early publishes are\n\t * effectively dropped — prefer an unset `retainedLimit` (unbounded\n\t * retention) or subscribe before publishing when late-subscribers matter.\n\t */\n\tpublish<T = unknown>(name: string, value: T): void {\n\t\tthis.topic<T>(name).publish(value);\n\t}\n\n\t/**\n\t * Bulk publish — issues all publishes inside one outer batch. New topics\n\t * are created on demand. No-op if `entries` yields nothing.\n\t *\n\t * **Iterable consumption (F6):** `entries` is consumed once (single-pass)\n\t * INSIDE the batch frame. If the iterator throws mid-way, the batch is\n\t * discarded and NO publishes are visible to subscribers (all-or-nothing).\n\t * Pass an array or `Set` for multi-shot callers.\n\t */\n\tpublishMany(entries: Iterable<[string, unknown]>): void {\n\t\t// P2: iterate inside batch — no `[...entries]` materialization so large\n\t\t// / infinite iterables don't OOM, and iterator throws are contained.\n\t\tbatch(() => {\n\t\t\tfor (const [name, value] of entries) {\n\t\t\t\tthis.topic(name).publish(value);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Creates a {@link SubscriptionGraph} over a named topic. The topic is\n\t * lazily created if missing. Subscription lifecycle is owned by the caller —\n\t * the hub does NOT mount the subscription.\n\t *\n\t * @param subName - Local name for the subscription graph.\n\t * @param topicName - Hub topic to subscribe to.\n\t * @param opts - `SubscriptionOptions` (initial cursor, etc.).\n\t */\n\tsubscribe<T = unknown>(\n\t\tsubName: string,\n\t\ttopicName: string,\n\t\topts?: SubscriptionOptions,\n\t): SubscriptionGraph<T> {\n\t\tconst t = this.topic<T>(topicName);\n\t\treturn new SubscriptionGraph<T>(subName, t, opts);\n\t}\n\n\t/**\n\t * Unmounts and tears down the topic's graph. Returns `true` if the topic\n\t * existed. Subscribers receive `TEARDOWN` via {@link Graph.remove}.\n\t *\n\t * **Closure-state caveat:** the registry mutation (`_registry.delete`) and\n\t * version bump happen in a `try/finally`, so registry/version converge to\n\t * a consistent state even when {@link Graph.remove} throws. `mutate`\n\t * does not roll back this mutation on throw — `Map.delete` on closure\n\t * state is invisible to any batch frame. The pre-existing try/finally is\n\t * load-bearing for that invariant.\n\t */\n\tremoveTopic(name: string): boolean {\n\t\tif (!this._registry.has(name)) return false;\n\t\t// P1 / P3: Graph.remove first — if it throws, `_registry` must NOT still\n\t\t// hold the broken half-disposed topic (otherwise the next\n\t\t// `hub.topic(name)` returns the corrupted reference). The `try/finally`\n\t\t// inside `_removeTopicImpl`'s action body preserves that invariant.\n\t\tthis._removeTopicImpl(name);\n\t\treturn true;\n\t}\n}\n\n/**\n * Creates a Pulsar-inspired topic graph (append-only retained stream + latest value).\n */\nexport function topic<T>(name: string, opts?: TopicOptions): TopicGraph<T> {\n\treturn new TopicGraph<T>(name, opts);\n}\n\n/**\n * Creates a lazy Pulsar-inspired messaging hub. Topics are created on first access\n * via `hub.topic(name)`; `hub.publish(name, value)` shortcuts through the registry.\n *\n * @example\n * ```ts\n * import { messagingHub } from \"@graphrefly/graphrefly/patterns/messaging\";\n *\n * const hub = messagingHub(\"main\", { defaultTopicOptions: { retainedLimit: 256 } });\n * hub.publish(\"orders\", { id: 1 });\n * hub.publishMany([[\"shipments\", { id: 1 }], [\"orders\", { id: 2 }]]);\n * const sub = hub.subscribe(\"orders-worker\", \"orders\", { cursor: 0 });\n * ```\n */\nexport function messagingHub(name: string, opts?: MessagingHubOptions): MessagingHubGraph {\n\treturn new MessagingHubGraph(name, opts);\n}\n\n/**\n * Creates a cursor-based subscription graph over a topic.\n */\nexport function subscription<T>(\n\tname: string,\n\ttopicGraph: TopicGraph<T>,\n\topts?: SubscriptionOptions,\n): SubscriptionGraph<T> {\n\treturn new SubscriptionGraph<T>(name, topicGraph, opts);\n}\n\n/**\n * Creates an autonomous cursor-based topic relay graph.\n *\n * When `opts.map` is provided, items where `map` returns `undefined` are\n * consumed from the source cursor but NOT republished (at-most-once with\n * silent drop). For filter-with-retry semantics, apply the filter in a\n * downstream subscription on the bridge's `output` node instead.\n */\nexport function topicBridge<TIn, TOut = TIn>(\n\tname: string,\n\tsourceTopic: TopicGraph<TIn>,\n\ttargetTopic: TopicGraph<TOut>,\n\topts?: TopicBridgeOptions<TIn, TOut>,\n): TopicBridgeGraph<TIn, TOut> {\n\treturn new TopicBridgeGraph<TIn, TOut>(name, sourceTopic, targetTopic, opts);\n}\n","/**\n * Universal mutation framework (Phase 14 — DS-14 locked 2026-05-05).\n *\n * Single `mutate(act, opts)` factory replaces the prior `lightMutation` +\n * `wrapMutation` two-tier split (pre-1.0 break per Q-O2).\n *\n * Two frames:\n * - `\"inline\"` — no batch; up() runs raw. Seq bumps before action; persists\n * on throw. Hot-path-friendly for atomic single-write mutations.\n * - `\"transactional\"` — opens `batch(() => up(...))`. On throw: batch discards\n * deferred deliveries, then `down()` runs (if provided), then failure record.\n *\n * Phase-4 primitives share the same shape: imperative mutation methods +\n * closure state + reactive audit log + freeze-at-entry + rollback-on-throw.\n * This module factors out the common machinery so each primitive becomes\n * declarative wiring over typed audit records.\n */\n\nimport {\n\tbatch,\n\tDATA,\n\tDIRTY,\n\ttype Node,\n\ttype NodeGuard,\n\tnode,\n\tpolicy,\n\twallClockNs,\n} from \"@graphrefly/pure-ts/core\";\nimport {\n\ttype ReactiveLogBundle,\n\ttype ReactiveLogOptions,\n\treactiveLog,\n} from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\n\n// ── tryIncrementBounded ──────────────────────────────────────────────────\n\n/**\n * Bounded increment for a self-owned counter state node.\n *\n * Reads `counter.cache`, bumps by `by` (default 1) if `cur + by <= cap`,\n * writes back. Returns `false` when the cap would be exceeded (no-op write).\n * Documented P3 exception: the counter is not a declared dep of the caller —\n * it's a private budget read+written from a single call site. This helper\n * keeps the `.cache` access in one named place so caller bodies (which may\n * be inside reactive fn execution paths) stay free of cross-node `.cache`\n * reads.\n *\n * **Safety today:**\n * 1. Single-threaded JS runner never invokes the caller concurrently.\n * 2. `counter.down` writes the cache synchronously before returning, so\n * synchronous re-entry through a downstream publish reads the\n * freshly-incremented value — no double-count.\n *\n * **Future risk:** under a free-threaded runner (PY no-GIL or hypothetical\n * concurrent TS runner), two concurrent firings could still race. Revisit\n * when that surfaces.\n *\n * @param counter - Self-owned counter Node. Caller is the sole writer.\n * @param cap - Upper bound (inclusive). Pass `Number.MAX_SAFE_INTEGER` for\n * \"effectively unbounded\" use cases (e.g. token meters).\n * @param by - Delta to add (default `1`). Must be a finite non-negative\n * number; callers should pre-validate. Overflow-safe via\n * `by > cap - cur` check rather than `cur + by >= cap`.\n */\nexport function tryIncrementBounded(counter: Node<number>, cap: number, by = 1): boolean {\n\tconst cur = (counter.cache as number | undefined) ?? 0;\n\tif (by > cap - cur) return false;\n\tcounter.down([[DIRTY], [DATA, cur + by]]);\n\treturn true;\n}\n\n// ── Audit record schema ──────────────────────────────────────────────────\n\n/** Shared base shape for every audit record. Per-primitive types extend this. */\nexport interface BaseAuditRecord {\n\treadonly t_ns: number;\n\treadonly seq?: number;\n\treadonly handlerVersion?: { id: string; version: string | number };\n}\n\n// ── Default audit guard ──────────────────────────────────────────────────\n\n/**\n * Allow `observe` and `signal`; deny external `write` on the audit log so\n * consumers can subscribe + signal-bridge but cannot inject fake records.\n */\nexport const DEFAULT_AUDIT_GUARD: NodeGuard = policy((allow, deny) => {\n\tallow(\"observe\");\n\tallow(\"signal\");\n\tdeny(\"write\");\n});\n\n// ── createAuditLog ───────────────────────────────────────────────────────\n\nexport type AuditLogOpts<R extends BaseAuditRecord> = {\n\tname: string;\n\t/** Bounded retention; default 1024 per Audit 2 / cross-cutting bounded-default policy. */\n\tretainedLimit?: number;\n\t/** Override the default audit guard. */\n\tguard?: NodeGuard;\n\t/** Mount the audit `entries` Node under this graph (and activate withLatest). */\n\tgraph?: Graph;\n\t/** Pass-through to {@link reactiveLog}. */\n\tversioning?: ReactiveLogOptions<R>[\"versioning\"];\n};\n\n/**\n * Build a reactive audit log with sane defaults: bounded retention, deny-write\n * guard, `withLatest()` companions activated. Returns the {@link ReactiveLogBundle}\n * directly — primitives expose this as `<primitive>.events` / `.decisions` /\n * `.dispatches` / `.invocations` and alias it as `.audit`.\n *\n * @category internal\n */\nexport function createAuditLog<R extends BaseAuditRecord>(\n\topts: AuditLogOpts<R>,\n): ReactiveLogBundle<R> {\n\tconst log = reactiveLog<R>([], {\n\t\tname: opts.name,\n\t\tmaxSize: opts.retainedLimit ?? 1024,\n\t\tguard: opts.guard ?? DEFAULT_AUDIT_GUARD,\n\t\t...(opts.versioning != null ? { versioning: opts.versioning } : {}),\n\t});\n\t// Lazy companion activation up-front so `bundle.lastValue` / `hasLatest`\n\t// are queryable without an explicit `withLatest()` call.\n\tlog.withLatest();\n\tif (opts.graph) {\n\t\topts.graph.add(log.entries, { name: opts.name });\n\t}\n\treturn log;\n}\n\n// ── Universal mutation factory (Phase 14 — DS-14 lock Q-O2/Q-O3) ────────\n//\n// Single `mutate(act, opts)` factory. Two frames:\n//\n// - `\"inline\"` — no batch frame; up() runs raw. Seq bumps before action;\n// persists on throw. Hot-path-friendly for atomic single-write mutations.\n//\n// - `\"transactional\"` — opens `batch(() => up(...))`. On throw: batch discards\n// deferred deliveries, then `down()` runs, then failure record persists.\n//\n// **Heuristic:** if your imperative method's body is one or two lines (mutate\n// state, emit), use `frame: \"inline\"`. If it runs a user-supplied handler or\n// has multiple steps that could leave inconsistent state mid-throw, use\n// `frame: \"transactional\"`.\n\nexport type FailureMeta = {\n\tt_ns: number;\n\tseq?: number;\n\terrorType: string;\n};\n\nexport type SuccessMeta = {\n\tt_ns: number;\n\tseq?: number;\n};\n\n/**\n * Mutation action shape. Plain function shorthand auto-wraps as `{ up: fn }`.\n *\n * - `up` — the mutation action (the \"up migration\").\n * - `down` — optional rollback for closure mutations that `batch()` can't\n * reach. Receives the SAME frozen args as `up`. Runs AFTER batch reactive\n * rollback, BEFORE the failure record. Throws inside `down` are\n * console.error'd without masking the original error. Only meaningful\n * with `frame: \"transactional\"`.\n */\nexport type MutationAct<TArgs extends readonly unknown[], TResult> = {\n\tup: (...args: TArgs) => TResult;\n\tdown?: (...args: TArgs) => void;\n};\n\nexport type MutationFrame = \"inline\" | \"transactional\";\n\nexport type MutateOpts<TArgs extends readonly unknown[], TResult, R extends BaseAuditRecord> = {\n\t/** Frame mode. `\"inline\"` = no batch; `\"transactional\"` = batch + rollback. */\n\tframe: MutationFrame;\n\t/**\n\t * Optional log to append records to. When omitted, the wrapper still\n\t * provides freeze / seq-advance / rollback-on-throw but skips record\n\t * emission — useful for primitives that want centralized mutation\n\t * semantics without a dedicated log surface (e.g. `Topic.publish`).\n\t */\n\tlog?: ReactiveLogBundle<R>;\n\t/** Build the success record from the action's args + result + meta. */\n\tonSuccessRecord?: (args: TArgs, result: TResult, meta: SuccessMeta) => R | undefined;\n\t/** Build the failure record from the args + error + meta. */\n\tonFailureRecord?: (args: TArgs, error: unknown, meta: FailureMeta) => R | undefined;\n\t/** Deep-freeze args at entry (default `true`). Opt out for hot paths. */\n\tfreeze?: boolean;\n\t/** Optional sequence cursor — auto-advanced and stamped onto records. */\n\tseq?: Node<number>;\n\t/** Optional handler version — stamped per Audit 5. */\n\thandlerVersion?: { id: string; version: string | number };\n};\n\nfunction deepFreeze<T>(value: T): T {\n\tif (value === null || typeof value !== \"object\" || Object.isFrozen(value)) return value;\n\tfor (const k of Object.keys(value as Record<string, unknown>)) {\n\t\tdeepFreeze((value as Record<string, unknown>)[k]);\n\t}\n\treturn Object.freeze(value);\n}\n\n/**\n * Universal mutation factory (Phase 14 — DS-14 Q-O2).\n *\n * Replaces the prior `lightMutation` + `wrapMutation` two-tier split.\n * Single factory with `frame: \"inline\" | \"transactional\"` discriminant.\n *\n * @param act - The mutation action. Either a plain function (auto-wrapped as\n * `{ up: fn }`) or a `{ up, down? }` object for explicit rollback.\n * @param opts - Configuration: frame, log, record builders, freeze, seq.\n * @returns A typed wrapper function with the same signature as `act.up`.\n */\nexport function mutate<TArgs extends readonly unknown[], TResult, R extends BaseAuditRecord>(\n\tact: MutationAct<TArgs, TResult> | ((...args: TArgs) => TResult),\n\topts: MutateOpts<TArgs, TResult, R>,\n): (...args: TArgs) => TResult {\n\tconst { up, down } = typeof act === \"function\" ? { up: act, down: undefined } : act;\n\tconst freeze = opts.freeze ?? true;\n\n\tif (opts.frame === \"inline\") {\n\t\treturn function wrapped(...args: TArgs): TResult {\n\t\t\tconst sealed = freeze ? (args.map(deepFreeze) as unknown as TArgs) : args;\n\t\t\tconst t_ns = wallClockNs();\n\t\t\tconst seq = opts.seq ? bumpCursor(opts.seq) : undefined;\n\t\t\ttry {\n\t\t\t\tconst result = up(...sealed);\n\t\t\t\tif (opts.log && opts.onSuccessRecord) {\n\t\t\t\t\tappendAudit<TArgs, TResult, R, SuccessMeta>(\n\t\t\t\t\t\topts.log,\n\t\t\t\t\t\topts.onSuccessRecord,\n\t\t\t\t\t\tsealed,\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\t{ t_ns, seq },\n\t\t\t\t\t\topts.handlerVersion,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t} catch (err) {\n\t\t\t\tif (opts.log && opts.onFailureRecord) {\n\t\t\t\t\tconst errorType = err instanceof Error ? err.name : typeof err;\n\t\t\t\t\tappendAudit<TArgs, unknown, R, FailureMeta>(\n\t\t\t\t\t\topts.log,\n\t\t\t\t\t\topts.onFailureRecord,\n\t\t\t\t\t\tsealed,\n\t\t\t\t\t\terr,\n\t\t\t\t\t\t{ t_ns, seq, errorType },\n\t\t\t\t\t\topts.handlerVersion,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t};\n\t}\n\n\t// frame === \"transactional\"\n\treturn function wrapped(...args: TArgs): TResult {\n\t\tconst sealed = freeze ? (args.map(deepFreeze) as unknown as TArgs) : args;\n\t\tconst t_ns = wallClockNs();\n\t\tlet result: TResult;\n\t\tlet captured: unknown;\n\t\tlet captureSet = false;\n\t\tlet seq: number | undefined;\n\t\ttry {\n\t\t\tbatch(() => {\n\t\t\t\tif (opts.seq) seq = bumpCursor(opts.seq);\n\t\t\t\ttry {\n\t\t\t\t\tresult = up(...sealed);\n\t\t\t\t\tif (opts.log && opts.onSuccessRecord) {\n\t\t\t\t\t\tappendAudit<TArgs, TResult, R, SuccessMeta>(\n\t\t\t\t\t\t\topts.log,\n\t\t\t\t\t\t\topts.onSuccessRecord,\n\t\t\t\t\t\t\tsealed,\n\t\t\t\t\t\t\tresult,\n\t\t\t\t\t\t\t{ t_ns, seq },\n\t\t\t\t\t\t\topts.handlerVersion,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tcaptured = err;\n\t\t\t\t\tcaptureSet = true;\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (outerErr) {\n\t\t\t// Fire `down` AFTER batch's reactive rollback, BEFORE failure record.\n\t\t\t// Gate on `captureSet` — if the throw came from outside the inner try\n\t\t\t// (framework-level batch error before action ran), don't fire down.\n\t\t\tif (captureSet && down) {\n\t\t\t\ttry {\n\t\t\t\t\tdown(...sealed);\n\t\t\t\t} catch (downErr) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t`mutate: down hook threw — original action error preserved (${\n\t\t\t\t\t\t\tcaptured instanceof Error ? captured.name : typeof captured\n\t\t\t\t\t\t}). Down error:`,\n\t\t\t\t\t\tdownErr,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (captureSet && opts.log && opts.onFailureRecord) {\n\t\t\t\tconst errorType = captured instanceof Error ? captured.name : typeof captured;\n\t\t\t\tappendAudit<TArgs, unknown, R, FailureMeta>(\n\t\t\t\t\topts.log,\n\t\t\t\t\topts.onFailureRecord,\n\t\t\t\t\tsealed,\n\t\t\t\t\tcaptured,\n\t\t\t\t\t{ t_ns, seq, errorType },\n\t\t\t\t\topts.handlerVersion,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow captureSet ? captured : outerErr;\n\t\t}\n\t\treturn result!;\n\t};\n}\n\n/**\n * Advance a cursor node and return the new value. Emits `[DIRTY], [DATA, next]`\n * directly on the cursor — atomic outside a batch, rollback-discardable inside.\n *\n * Resets to `0` if the cursor cache is missing, non-numeric, `NaN`, or\n * non-finite (e.g. corrupted by `restore()` from a malformed snapshot, or\n * by a misbehaving codec). `??` alone would let `NaN` and `\"\"` pass through\n * and silently corrupt audit ordering downstream.\n *\n * **Silent reset diagnostic (EH-12).** When the cache holds a non-numeric\n * value at bump time, the cursor restarts at 0 and the next bump returns 1\n * — colliding with the seq stamped on the very first record after construct.\n * To make seq-monotonicity violations after a restore visible to operators,\n * the helper emits a one-shot `console.warn` per cursor instance describing\n * the offending value. The cursor is identified by a `WeakSet<Node<number>>`\n * so the warning fires exactly once per node — repeat malformed bumps stay\n * quiet to avoid log spam. Production callers wanting to suppress can swap\n * the global `console` (universal-safe code path; no Node-only API used).\n *\n * Works whether or not the cursor has any subscribers — `down` updates the\n * cache regardless, so primitives that bump before consumers attach (e.g.\n * `JobQueueGraph.enqueue`) still see a coherent sequence.\n *\n * @category internal\n */\nconst _bumpCursorWarned = new WeakSet<Node<number>>();\nexport function bumpCursor(seq: Node<number>): number {\n\tconst raw = seq.cache;\n\tconst valid = typeof raw === \"number\" && Number.isFinite(raw);\n\tif (!valid && raw !== undefined && !_bumpCursorWarned.has(seq)) {\n\t\t_bumpCursorWarned.add(seq);\n\t\tconsole.warn(\n\t\t\t`bumpCursor: cursor cache held a non-numeric value (${String(raw)}); resetting to 0. ` +\n\t\t\t\t\"Causes include: a snapshot codec round-tripping the cursor as a string / null / NaN, \" +\n\t\t\t\t\"OR a malformed initial seed (e.g. state<number>(NaN)). \" +\n\t\t\t\t\"Audit consumers may see colliding seq values after this point.\",\n\t\t);\n\t}\n\tconst cur = valid ? raw : 0;\n\tconst next = cur + 1;\n\tseq.down([[DIRTY], [DATA, next]]);\n\treturn next;\n}\n\n/**\n * Build a record via the supplied builder, stamp `handlerVersion` if present,\n * and append it to the audit log. `undefined` records are skipped (callers\n * pass an `onSuccess` / `onFailure` that returns `undefined` to opt out per\n * call).\n *\n * @category internal\n */\nexport function appendAudit<\n\tTArgs extends readonly unknown[],\n\tTValue,\n\tR extends BaseAuditRecord,\n\tM extends SuccessMeta | FailureMeta,\n>(\n\taudit: ReactiveLogBundle<R>,\n\tbuilder: (args: TArgs, value: TValue, meta: M) => R | undefined,\n\targs: TArgs,\n\tvalue: TValue,\n\tmeta: M,\n\thandlerVersion?: { id: string; version: string | number },\n): void {\n\tconst record = builder(args, value, meta);\n\tif (record === undefined) return;\n\tconst stamped = handlerVersion != null ? ({ ...record, handlerVersion } as R) : record;\n\taudit.append(stamped);\n}\n\n// ── registerCursor / registerCursorMap ───────────────────────────────────\n\n/**\n * Promote a closure counter to a state node mounted under `graph`.\n * Replaces ad-hoc `let _seq = 0` patterns with a node observable in\n * `describe()` and persistable via storage tiers.\n *\n * @category internal\n */\nexport function registerCursor(graph: Graph, name: string, initial = 0): Node<number> {\n\tconst cursor = node<number>([], { initial, name, describeKind: \"state\" });\n\tgraph.add(cursor, { name });\n\treturn cursor;\n}\n\n/**\n * Promote a closure `Map<K, number>` to N state nodes (one per key) mounted\n * under `<graph>::<name>::<key>`. Used by saga (per-event-type cursor).\n *\n * @category internal\n */\nexport function registerCursorMap<K extends string>(\n\tgraph: Graph,\n\tname: string,\n\tkeys: readonly K[],\n\tinitial = 0,\n): { readonly [P in K]: Node<number> } {\n\tconst out = {} as { [P in K]: Node<number> };\n\t// Mount cursors under a child plain-Graph so per-key node names stay flat\n\t// (path-separator `::` is reserved by Graph.add). Using `Graph` directly\n\t// rather than `graph.constructor` avoids spawning a typed subclass with\n\t// an incompatible constructor signature (e.g., CqrsGraph(name, opts)).\n\tconst sub = new Graph(name);\n\tfor (const k of keys) {\n\t\tconst cursor = node<number>([], {\n\t\t\tinitial,\n\t\t\tname: k,\n\t\t\tdescribeKind: \"state\",\n\t\t});\n\t\tsub.add(cursor, { name: k });\n\t\tout[k] = cursor;\n\t}\n\tgraph.mount(name, sub);\n\treturn out;\n}\n","/**\n * PipelineGraph subclass (Wave A.1 Unit 1 — locked 2026-04-24).\n *\n * Specialized {@link Graph} that hosts workflow-DAG sugar methods:\n * `task` / `classify` / `combine` / `approval` / `approvalGate` / `catch`.\n * The legacy `pipeline` / `task` / `branch` / `join` / `subPipeline` /\n * `approval` / `loop` / `onFailure` factories from {@link ./index} continue\n * to work for migration ease; new code should prefer methods on this class.\n *\n * **Tier 2.3 rename:** the prior `gate(...)` method is now `approvalGate(...)`,\n * disambiguating it from the other gate-family primitives (`budgetGate` for\n * numeric constraints, `valve` for boolean switching, `policyGate` for ABAC\n * rules). The \"gating dimension\" here is **human judgment**.\n *\n * Construction: `pipelineGraph(name, opts?)` or `new PipelineGraph(name, opts)`.\n */\n\nimport type { NodeActions } from \"@graphrefly/pure-ts/core\";\nimport {\n\tbatch,\n\tCOMPLETE,\n\tDATA,\n\tERROR,\n\tfactoryTag,\n\ttype Node,\n\ttype NodeOptions,\n\tnode,\n\tplaceholderArgs,\n\tRESOLVED,\n\twallClockNs,\n} from \"@graphrefly/pure-ts/core\";\nimport type { ReactiveLogBundle } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport { type BaseAuditRecord, createAuditLog, mutate } from \"../../base/mutation/index.js\";\n\nexport type StepRef = string | Node<unknown>;\n\nfunction meta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"orchestration\", kind, extra);\n}\n\n// ── Decision audit record (Audit 2 + Wave A.2 Unit 8) ─────────────────────\n\nexport type DecisionAction =\n\t| \"approve\"\n\t| \"reject\"\n\t| \"modify\"\n\t| \"drop\"\n\t| \"open\"\n\t| \"close\"\n\t| \"teardown\";\n\nexport interface Decision<T = unknown> extends BaseAuditRecord {\n\treadonly action: DecisionAction;\n\treadonly count?: number;\n\treadonly items?: readonly T[];\n\treadonly unflushed?: number;\n}\n\n/** Recommended `keyOf` for keyed-storage adapters (Audit 2 #7). */\nexport const decisionKeyOf = <T>(d: Decision<T>): string => d.action;\n\n// ── Gate ─────────────────────────────────────────────────────────────────\n\nexport interface GateOptions<_T = unknown> {\n\t/** Bounded default 1000 (Audit 2 cross-cutting). `Infinity` is opt-in. */\n\tmaxPending?: number;\n\tstartOpen?: boolean;\n\t/**\n\t * Reactive auto-approve: gate's `latestIsOpen` mirrors this node's truthy\n\t * value. False→true transition drains the pending queue.\n\t *\n\t * **`COMPLETE` / `ERROR` on the approver are silently ignored** — the gate\n\t * stays in its current state. For permanent-open latching, use\n\t * `onceOnly: true` (the first truthy approval latches; subsequent falsy\n\t * values are ignored). The gate has no graceful terminal-state behavior\n\t * for the approver itself.\n\t */\n\tapprover?: Node<unknown>;\n\t/** Latch — first truthy approval opens permanently; `close()` becomes no-op. */\n\tonceOnly?: boolean;\n\tmeta?: Record<string, unknown>;\n\thandlerVersion?: { id: string; version: string | number };\n}\n\nexport interface GateController<T> {\n\t/**\n\t * The post-gate output node. Renamed from `node` (Tier 5.2 / EC6,\n\t * 2026-04-29) to avoid shadowing `Graph.node(name)` when a gate is\n\t * accessed off a `PipelineGraph` instance.\n\t */\n\treadonly output: Node<T>;\n\treadonly pending: Node<readonly T[]>;\n\treadonly count: Node<number>;\n\treadonly isOpen: Node<boolean>;\n\treadonly droppedCount: Node<number>;\n\treadonly decisions: ReactiveLogBundle<Decision<T>>;\n\treadonly audit: ReactiveLogBundle<Decision<T>>;\n\tapprove(count?: number): void;\n\treject(count?: number): void;\n\tmodify(fn: (value: T, index: number, pending: readonly T[]) => T, count?: number): void;\n\topen(): void;\n\tclose(): void;\n}\n\n// ── catch (rename of onFailure; Wave A.2 Unit 10) ─────────────────────────\n\n/**\n * Terminal-cause discriminator for the {@link PipelineGraph.catch} recovery\n * handler. Tier 1.6.3 status-enum migration: was `{ kind: \"complete\" | \"error\" }`\n * pre-1.0; aligned with the canonical lifecycle enum\n * (`status: \"running\" | \"completed\" | \"errored\" | \"cancelled\"`). The variant\n * structure is preserved — `errored` still carries `error: unknown` and\n * `completed` carries no payload.\n */\nexport type TerminalCause = { kind: \"errored\"; error: unknown } | { kind: \"completed\" };\n\nexport interface CatchOptions<_T> {\n\t/**\n\t * Which terminal cause to recover. Default `\"errored\"` (Tier 1.6.3 rename\n\t * of `\"error\"`). `\"completed\"` recovers COMPLETE; `\"terminal\"` recovers\n\t * either. Aligns with the canonical lifecycle enum that\n\t * {@link TerminalCause.kind} now uses.\n\t */\n\ton?: \"errored\" | \"completed\" | \"terminal\";\n\tcompleteWhenDepsComplete?: boolean;\n\tmeta?: Record<string, unknown>;\n\thandlerVersion?: { id: string; version: string | number };\n}\n\n// ── classify result envelope (Wave A.1 Unit 3) ───────────────────────────\n\nexport interface ClassifyResult<TTag extends string, T> {\n\treadonly tag: TTag | \"error\";\n\treadonly value: T;\n\treadonly error?: unknown;\n}\n\n// ── PipelineGraph ────────────────────────────────────────────────────────\n\nexport class PipelineGraph extends Graph {\n\t// -- task -----------------------------------------------------------------\n\n\t/**\n\t * Register a workflow task (`node` + auto-add). String deps resolve via\n\t * `this.resolve(path)`; Node deps via {@link Graph.nameOf} O(1) lookup.\n\t *\n\t * `run` receives `(data: readonly unknown[], ctx)` — the snapshot of latest\n\t * values per dep (same shape as the old `DerivedFn` sugar).\n\t */\n\ttask<T>(\n\t\tname: string,\n\t\trun: (data: readonly unknown[], ctx: { prevData: readonly unknown[] }) => T | undefined | null,\n\t\topts: { deps?: ReadonlyArray<StepRef>; meta?: Record<string, unknown> } = {},\n\t): Node<T> {\n\t\tconst deps = (opts.deps ?? []).map((d) => this._resolveStep(d));\n\t\tconst step = node<T>(\n\t\t\tdeps,\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst result = run(data, ctx);\n\t\t\t\tif (result !== undefined && result !== null) actions.emit(result);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: meta(\"task\", opts.meta),\n\t\t\t} as NodeOptions<T>,\n\t\t);\n\t\tthis.add(step, { name });\n\t\treturn step;\n\t}\n\n\t// -- classify (n-way; replaces binary `branch`) --------------------------\n\n\tclassify<TTag extends string, T>(\n\t\tname: string,\n\t\tsource: StepRef,\n\t\ttagger: (value: T) => TTag,\n\t\topts: { meta?: Record<string, unknown> } = {},\n\t): Node<ClassifyResult<TTag, T>> {\n\t\tconst src = this._resolveStep(source);\n\t\tconst step = node<ClassifyResult<TTag, T>>(\n\t\t\t[src],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst value = data[0];\n\t\t\t\ttry {\n\t\t\t\t\tactions.emit({ tag: tagger(value as T), value: value as T });\n\t\t\t\t} catch (error) {\n\t\t\t\t\tactions.emit({ tag: \"error\" as const, value: value as T, error });\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: meta(\"classify\", opts.meta),\n\t\t\t} as NodeOptions<ClassifyResult<TTag, T>>,\n\t\t);\n\t\tthis.add(step, { name });\n\t\treturn step;\n\t}\n\n\t// -- combine (keyed-record fan-in; replaces positional `join`) -----------\n\n\tcombine<R extends Record<string, StepRef>>(\n\t\tname: string,\n\t\tdeps: R,\n\t\topts: { meta?: Record<string, unknown> } = {},\n\t): Node<{ [K in keyof R]: unknown }> {\n\t\tconst keys = Object.keys(deps) as Array<keyof R & string>;\n\t\tconst nodes = keys.map((k) => this._resolveStep(deps[k] as StepRef));\n\t\tconst step = node<{ [K in keyof R]: unknown }>(\n\t\t\tnodes,\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst values = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst out = {} as { [K in keyof R]: unknown };\n\t\t\t\tfor (let i = 0; i < keys.length; i++) {\n\t\t\t\t\t(out as Record<string, unknown>)[keys[i] as string] = values[i];\n\t\t\t\t}\n\t\t\t\tactions.emit(out);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: meta(\"combine\", opts.meta),\n\t\t\t} as NodeOptions<{ [K in keyof R]: unknown }>,\n\t\t);\n\t\tthis.add(step, { name });\n\t\treturn step;\n\t}\n\n\t// -- approvalGate ---------------------------------------------------------\n\n\tapprovalGate<T>(name: string, source: StepRef, opts: GateOptions<T> = {}): GateController<T> {\n\t\tconst maxPending = opts.maxPending ?? 1000;\n\t\tif (maxPending < 1 && maxPending !== Number.POSITIVE_INFINITY) {\n\t\t\tthrow new RangeError(\"approvalGate: maxPending must be >= 1\");\n\t\t}\n\t\tconst startOpen = opts.startOpen ?? false;\n\n\t\t// C3 — wrap a foreign Node source in a local proxy derived. The proxy\n\t\t// is owned by THIS graph; downstream wiring uses the proxy (not the\n\t\t// foreign Node) so the cross-graph ownership invariant holds. Causal\n\t\t// chain is preserved via the dep edge — `describe()` still surfaces\n\t\t// the foreign Node's path through the proxy.\n\t\tlet src: Node<unknown>;\n\t\tif (typeof source === \"string\") {\n\t\t\tsrc = this._resolveStep(source);\n\t\t} else if (this.nameOf(source) !== undefined) {\n\t\t\tsrc = source;\n\t\t} else {\n\t\t\tconst proxy = node<unknown>(\n\t\t\t\t[source],\n\t\t\t\t(batchData, actions) => {\n\t\t\t\t\tconst batch0 = batchData[0];\n\t\t\t\t\tif (batch0 == null || batch0.length === 0) return;\n\t\t\t\t\tfor (const v of batch0) actions.emit(v);\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\t\tmeta: factoryTag(\"proxy\"),\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis.add(proxy, { name: `${name}/source` });\n\t\t\tsrc = proxy;\n\t\t}\n\n\t\t// State subgraph\n\t\tconst internal = new Graph(`${name}-state`);\n\t\tconst pendingNode = internal.state<readonly T[]>(\"pending\", [], {\n\t\t\tequals: () => false,\n\t\t});\n\t\tconst isOpenNode = internal.state<boolean>(\"isOpen\", startOpen);\n\t\tconst countNode = internal.derived<number>(\"count\", [\"pending\"], (batchData, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\treturn [(data[0] as readonly T[]).length];\n\t\t});\n\t\tconst droppedCountNode = internal.state<number>(\"droppedCount\", 0);\n\t\tconst decisions = createAuditLog<Decision<T>>({\n\t\t\tname: \"decisions\",\n\t\t\tretainedLimit: 1024,\n\t\t\tgraph: internal,\n\t\t});\n\t\tthis.mount(`${name}-state`, internal);\n\n\t\tlet queue: T[] = [];\n\t\tlet torn = false;\n\t\tlet latched = false;\n\t\t// Closure-mirror per COMPOSITION-GUIDE §28 factory-time seed pattern.\n\t\t// `output` samples `latestIsOpen` inside its fn body when deciding\n\t\t// emit-vs-enqueue; reading a closure variable is NOT a P3 violation\n\t\t// (§28). An in-session Phase 9 plan would have relocated the value to\n\t\t// `internal.derived(\"latestIsOpen\", ...)` + `.cache` reads (which IS\n\t\t// a P3 violation); plan was reverted at the design level after\n\t\t// re-reading §28 — pattern preserved here. See `archive/docs/SESSION-\n\t\t// graph-narrow-waist.md` § \"Status of existing modifications\".\n\t\tlet latestIsOpen = startOpen;\n\t\tconst isOpenUnsub = isOpenNode.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] === DATA) latestIsOpen = m[1] as boolean;\n\t\t\t}\n\t\t});\n\t\tthis.addDisposer(isOpenUnsub);\n\n\t\tfunction syncPending(): void {\n\t\t\tpendingNode.emit([...queue]);\n\t\t}\n\n\t\tfunction recordDecision(\n\t\t\taction: DecisionAction,\n\t\t\titems?: readonly T[],\n\t\t\tunflushed?: number,\n\t\t): void {\n\t\t\tdecisions.append({\n\t\t\t\taction,\n\t\t\t\tt_ns: wallClockNs(),\n\t\t\t\t...(items !== undefined ? { items, count: items.length } : {}),\n\t\t\t\t...(unflushed !== undefined ? { unflushed } : {}),\n\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t} as Decision<T>);\n\t\t}\n\n\t\tfunction enqueue(value: T): void {\n\t\t\tqueue.push(value);\n\t\t\tif (queue.length > maxPending) {\n\t\t\t\tconst dropped = queue.shift() as T;\n\t\t\t\tdroppedCountNode.emit((droppedCountNode.cache as number) + 1);\n\t\t\t\trecordDecision(\"drop\", [dropped]);\n\t\t\t}\n\t\t\tsyncPending();\n\t\t}\n\n\t\tfunction dequeue(n: number): T[] {\n\t\t\tconst items = queue.splice(0, n);\n\t\t\tsyncPending();\n\t\t\treturn items;\n\t\t}\n\n\t\tconst output = node<T>(\n\t\t\t[src],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst terminal = ctx.terminalDeps[0];\n\t\t\t\tif (terminal !== undefined) {\n\t\t\t\t\ttorn = true;\n\t\t\t\t\tconst unflushed = queue.length;\n\t\t\t\t\tqueue = [];\n\t\t\t\t\tsyncPending();\n\t\t\t\t\trecordDecision(\"teardown\", undefined, unflushed);\n\t\t\t\t\tactions.down(terminal === true ? [[COMPLETE]] : [[ERROR, terminal]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst batch0 = batchData[0];\n\t\t\t\tif (batch0 == null || batch0.length === 0) {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tfor (const v of batch0 as T[]) {\n\t\t\t\t\tif (latestIsOpen) {\n\t\t\t\t\t\tactions.emit(v);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tenqueue(v);\n\t\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: meta(\"approval_gate\", opts.meta),\n\t\t\t},\n\t\t);\n\t\tthis.add(output, { name });\n\n\t\t// Reactive approver mode: mirror latestIsOpen to the approver's value.\n\t\t// **m1:** approver `COMPLETE` / `ERROR` are silently ignored — gate stays\n\t\t// in current state. For latching behavior, use `onceOnly: true`.\n\t\tif (opts.approver != null) {\n\t\t\tconst initialApproved = Boolean(opts.approver.cache);\n\t\t\tif (initialApproved) {\n\t\t\t\tisOpenNode.emit(true);\n\t\t\t\tlatestIsOpen = true;\n\t\t\t\tif (opts.onceOnly) latched = true;\n\t\t\t}\n\t\t\tconst approverSub = opts.approver.subscribe((msgs) => {\n\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\tif (m[0] !== DATA) continue;\n\t\t\t\t\tconst truthy = Boolean(m[1]);\n\t\t\t\t\tif (truthy && !latestIsOpen) {\n\t\t\t\t\t\t// false → true transition\n\t\t\t\t\t\tif (opts.onceOnly) {\n\t\t\t\t\t\t\tif (latched) continue;\n\t\t\t\t\t\t\tlatched = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbatch(() => {\n\t\t\t\t\t\t\tisOpenNode.emit(true);\n\t\t\t\t\t\t\tconst items = dequeue(queue.length);\n\t\t\t\t\t\t\t// M11: include items count in approver-driven open decisions\n\t\t\t\t\t\t\t// so audit consumers see how many items were flushed.\n\t\t\t\t\t\t\trecordDecision(\"open\", items);\n\t\t\t\t\t\t\tfor (const item of items) {\n\t\t\t\t\t\t\t\tif (torn) break;\n\t\t\t\t\t\t\t\toutput.emit(item);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (!truthy && latestIsOpen) {\n\t\t\t\t\t\tif (opts.onceOnly && latched) continue;\n\t\t\t\t\t\tbatch(() => {\n\t\t\t\t\t\t\tisOpenNode.emit(false);\n\t\t\t\t\t\t\trecordDecision(\"close\");\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\tthis.addDisposer(approverSub);\n\t\t}\n\n\t\tconst guardTorn = (method: string): void => {\n\t\t\tif (torn) throw new Error(`approvalGate: ${method}() called after the gate was torn down`);\n\t\t};\n\n\t\tconst approveImpl = (count = 1): void => {\n\t\t\tguardTorn(\"approve\");\n\t\t\tconst items = dequeue(count);\n\t\t\tfor (const item of items) {\n\t\t\t\tif (torn) break;\n\t\t\t\toutput.emit(item);\n\t\t\t}\n\t\t};\n\t\tconst rejectImpl = (count = 1): void => {\n\t\t\tguardTorn(\"reject\");\n\t\t\tdequeue(count);\n\t\t};\n\t\tconst modifyImpl = (\n\t\t\tfn: (value: T, index: number, pending: readonly T[]) => T,\n\t\t\tcount = 1,\n\t\t): void => {\n\t\t\tguardTorn(\"modify\");\n\t\t\tconst snapshot = [...queue] as readonly T[];\n\t\t\tconst items = dequeue(count);\n\t\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\t\tif (torn) break;\n\t\t\t\toutput.emit(fn(items[i], i, snapshot));\n\t\t\t}\n\t\t};\n\t\tconst openImpl = (): void => {\n\t\t\tguardTorn(\"open\");\n\t\t\tisOpenNode.emit(true);\n\t\t\tconst items = dequeue(queue.length);\n\t\t\tfor (const item of items) {\n\t\t\t\tif (torn) break;\n\t\t\t\toutput.emit(item);\n\t\t\t}\n\t\t};\n\t\tconst closeImpl = (): void => {\n\t\t\tguardTorn(\"close\");\n\t\t\tif (opts.onceOnly && latched) return;\n\t\t\tisOpenNode.emit(false);\n\t\t};\n\n\t\tconst approve = mutate(approveImpl, {\n\t\t\tframe: \"transactional\",\n\t\t\tlog: decisions,\n\t\t\tfreeze: false,\n\t\t\tonSuccessRecord: (args, _r, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"approve\",\n\t\t\t\t\tcount: (args[0] as number | undefined) ?? 1,\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t\tonFailureRecord: (_a, _e, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"drop\",\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\terrorType: m.errorType,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t});\n\t\tconst reject = mutate(rejectImpl, {\n\t\t\tframe: \"transactional\",\n\t\t\tlog: decisions,\n\t\t\tfreeze: false,\n\t\t\tonSuccessRecord: (args, _r, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"reject\",\n\t\t\t\t\tcount: (args[0] as number | undefined) ?? 1,\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t\tonFailureRecord: (_a, _e, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"drop\",\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\terrorType: m.errorType,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t});\n\t\tconst modify = mutate(modifyImpl, {\n\t\t\tframe: \"transactional\",\n\t\t\tlog: decisions,\n\t\t\tfreeze: false,\n\t\t\tonSuccessRecord: (args, _r, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"modify\",\n\t\t\t\t\tcount: (args[1] as number | undefined) ?? 1,\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t\tonFailureRecord: (_a, _e, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"drop\",\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\terrorType: m.errorType,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t});\n\t\tconst open = mutate(openImpl, {\n\t\t\tframe: \"transactional\",\n\t\t\tlog: decisions,\n\t\t\tfreeze: false,\n\t\t\tonSuccessRecord: (_a, _r, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"open\",\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t\tonFailureRecord: (_a, _e, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"drop\",\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\terrorType: m.errorType,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t});\n\t\tconst close = mutate(closeImpl, {\n\t\t\tframe: \"transactional\",\n\t\t\tlog: decisions,\n\t\t\tfreeze: false,\n\t\t\tonSuccessRecord: (_a, _r, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"close\",\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t\tonFailureRecord: (_a, _e, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"drop\",\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\terrorType: m.errorType,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t});\n\n\t\tthis.addDisposer(countNode.subscribe(() => undefined));\n\n\t\tconst controller: GateController<T> = {\n\t\t\toutput,\n\t\t\tpending: pendingNode,\n\t\t\tcount: countNode,\n\t\t\tisOpen: isOpenNode,\n\t\t\tdroppedCount: droppedCountNode,\n\t\t\tdecisions,\n\t\t\taudit: decisions,\n\t\t\tapprove,\n\t\t\treject,\n\t\t\tmodify,\n\t\t\topen,\n\t\t\tclose,\n\t\t};\n\t\treturn controller;\n\t}\n\n\t// -- approval (thin alias over approvalGate({ approver, maxPending: 1 })) -\n\n\t/**\n\t * Reactive approval step: passes items through when `approver` is truthy;\n\t * holds at most one pending item (maxPending: 1) when falsy. A thin alias\n\t * over `approvalGate({ approver, maxPending: 1 })` — use `approvalGate()`\n\t * directly for finer control (maxPending, onceOnly, manual approve/reject).\n\t */\n\tapproval<T>(\n\t\tname: string,\n\t\tsource: StepRef,\n\t\tapprover: Node<unknown>,\n\t\topts: Omit<GateOptions<T>, \"approver\" | \"maxPending\"> = {},\n\t): GateController<T> {\n\t\treturn this.approvalGate<T>(name, source, { ...opts, approver, maxPending: 1 });\n\t}\n\n\t// -- catch (renamed onFailure; dep-channel intercept) -------------------\n\n\tcatch<T>(\n\t\tname: string,\n\t\tsource: StepRef,\n\t\trecover: (cause: TerminalCause, actions: NodeActions) => T,\n\t\topts: CatchOptions<T> = {},\n\t): Node<T> {\n\t\tconst src = this._resolveStep(source);\n\t\tconst mode = opts.on ?? \"errored\";\n\t\tconst step = node<T>(\n\t\t\t[src],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst terminal = ctx.terminalDeps[0];\n\t\t\t\tif (terminal !== undefined) {\n\t\t\t\t\tconst cause: TerminalCause =\n\t\t\t\t\t\tterminal === true ? { kind: \"completed\" } : { kind: \"errored\", error: terminal };\n\t\t\t\t\tif (mode === \"terminal\" || mode === cause.kind) {\n\t\t\t\t\t\tactions.emit(recover(cause, actions));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tactions.down(cause.kind === \"completed\" ? [[COMPLETE]] : [[ERROR, cause.error]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst batch0 = batchData[0];\n\t\t\t\tif (batch0 == null || batch0.length === 0) {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tfor (const v of batch0 as T[]) actions.emit(v);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tcompleteWhenDepsComplete:\n\t\t\t\t\topts.completeWhenDepsComplete ?? !(mode === \"completed\" || mode === \"terminal\"),\n\t\t\t\terrorWhenDepsError: !(mode === \"errored\" || mode === \"terminal\"),\n\t\t\t\tmeta: meta(\"catch\", opts.meta),\n\t\t\t} as NodeOptions<T>,\n\t\t);\n\t\tthis.add(step, { name });\n\t\treturn step;\n\t}\n\n\t// -- internals ----------------------------------------------------------\n\n\tprivate _resolveStep(dep: StepRef): Node<unknown> {\n\t\tif (typeof dep === \"string\") return this.resolve(dep);\n\t\tconst existing = this.nameOf(dep);\n\t\tif (existing === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`PipelineGraph \"${this.name}\": Node dep is not registered. Pass a string path or call graph.add(node) first.`,\n\t\t\t);\n\t\t}\n\t\treturn dep;\n\t}\n}\n\n/** Factory wrapper — `pipelineGraph(name, opts?)`. Equivalent to `new PipelineGraph(name, opts)`. */\nexport function pipelineGraph(name: string, opts?: GraphOptions): PipelineGraph {\n\tconst g = new PipelineGraph(name, opts);\n\t// Tier 1.5.3 Phase 2.5 (DG1=B): tag the Graph with its constructing\n\t// factory so `describe()` exposes provenance. `factoryArgs` is the\n\t// constructor opts (sans the `factory`/`factoryArgs` keys themselves to\n\t// avoid recursive nesting). QA F13: route through `placeholderArgs` for\n\t// consistency with sibling factories — `GraphOptions[key: string]: unknown`\n\t// is open-ended, so user-extension keys may carry non-JSON content.\n\tconst { factory: _f, factoryArgs: _fa, ...tagArgs } = (opts ?? {}) as Record<string, unknown>;\n\tg.tagFactory(\"pipelineGraph\", placeholderArgs(tagArgs));\n\treturn g;\n}\n","/**\n * `systemPromptBuilder` — assembles a reactive system prompt from sections.\n *\n * @module\n */\n\nimport { type Node, node } from \"@graphrefly/pure-ts/core\";\n\nimport { fromAny, keepalive, type NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport { aiMeta } from \"../_internal.js\";\n\n/**\n * Assembles a system prompt from reactive sections. Each section is a\n * `NodeInput<string>` — the prompt updates when any section changes.\n */\nexport type SystemPromptHandle = Node<string> & { dispose: () => void };\n\nexport function systemPromptBuilder(\n\tsections: readonly NodeInput<string>[],\n\topts?: { separator?: string; name?: string },\n): SystemPromptHandle {\n\tconst separator = opts?.separator ?? \"\\n\\n\";\n\tconst sectionNodes = sections.map((s) =>\n\t\ttypeof s === \"string\" ? node([], { initial: s }) : fromAny(s),\n\t);\n\tconst prompt = node(\n\t\tsectionNodes,\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tactions.emit((data as string[]).filter((v) => v != null && v !== \"\").join(separator));\n\t\t},\n\t\t{\n\t\t\tname: opts?.name ?? \"systemPrompt\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tmeta: aiMeta(\"system_prompt\"),\n\t\t\tinitial: \"\",\n\t\t},\n\t);\n\tconst unsub = keepalive(prompt);\n\treturn Object.assign(prompt, { dispose: unsub });\n}\n","/**\n * Cost meter extractor — derives live cost readings from the delta topic.\n *\n * **Wave A Unit 3 rewrite:** signature takes `deltaTopic: TopicGraph<StampedDelta>`\n * instead of the old `TopicGraph<StreamChunk>`. The meter prefers real\n * `usage` deltas from the adapter; when no `usage` has been seen yet it\n * falls back to a char-based estimate over token deltas and stamps\n * `estimated: true` on the reading. Chunk count is the count of\n * token-type deltas seen (was `chunk.index + 1`).\n *\n * @module\n */\n\nimport { type Node, node } from \"@graphrefly/pure-ts/core\";\nimport type { TopicGraph } from \"../../messaging/index.js\";\nimport { aiMeta } from \"../_internal.js\";\nimport { sumInputTokens, sumOutputTokens } from \"../adapters/core/types.js\";\nimport type { StampedDelta } from \"../prompts/streaming.js\";\n\n/** A cost meter reading from the stream. */\nexport type CostMeterReading = {\n\treadonly chunkCount: number;\n\treadonly charCount: number;\n\treadonly estimatedTokens: number;\n\t/**\n\t * `true` when no adapter `usage` delta has been observed yet —\n\t * `estimatedTokens` is a char-based heuristic and should be treated as an\n\t * approximation. Flips to `false` once a real `usage` delta arrives.\n\t */\n\treadonly estimated: boolean;\n};\n\nexport type CostMeterOptions = {\n\t/** Characters per token approximation. Default: 4 (GPT-family). */\n\tcharsPerToken?: number;\n\tname?: string;\n};\n\nconst costMeterEqual = (a: CostMeterReading, b: CostMeterReading): boolean => {\n\tif (a === b) return true;\n\treturn (\n\t\ta.chunkCount === b.chunkCount &&\n\t\ta.charCount === b.charCount &&\n\t\ta.estimatedTokens === b.estimatedTokens &&\n\t\ta.estimated === b.estimated\n\t);\n};\n\n/**\n * Mounts a cost meter on the delta topic. Prefers real `usage` deltas from\n * the provider; falls back to char-based estimation on token deltas alone\n * (with `meta.estimated: true` on the reading).\n *\n * Default structural equals suppresses DATA emission when two consecutive\n * readings are identical.\n */\nexport function costMeterExtractor(\n\tdeltaTopic: TopicGraph<StampedDelta>,\n\topts?: CostMeterOptions,\n): Node<CostMeterReading> {\n\tconst charsPerToken = opts?.charsPerToken ?? 4;\n\tconst ZERO: CostMeterReading = {\n\t\tchunkCount: 0,\n\t\tcharCount: 0,\n\t\testimatedTokens: 0,\n\t\testimated: true,\n\t};\n\t// Lock 6.D (Phase 13.6.B): clear per-stream counters on deactivation\n\t// so a resubscribed cost meter starts at zero on the next cycle.\n\tlet cleanup: { onDeactivation: () => void } | undefined;\n\treturn node<CostMeterReading>(\n\t\t[deltaTopic.latest],\n\t\t(batchData, actions, ctx) => {\n\t\t\tif (cleanup === undefined) {\n\t\t\t\tconst store = ctx.store;\n\t\t\t\tcleanup = {\n\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\tdelete store.chunkCount;\n\t\t\t\t\t\tdelete store.charCount;\n\t\t\t\t\t\tdelete store.usageTokens;\n\t\t\t\t\t\tdelete store.sawUsage;\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst d = data[0];\n\t\t\tif (d === undefined) {\n\t\t\t\tactions.emit(ZERO);\n\t\t\t\treturn cleanup;\n\t\t\t}\n\t\t\tconst delta = d as StampedDelta;\n\n\t\t\tif (!(\"chunkCount\" in ctx.store)) {\n\t\t\t\tctx.store.chunkCount = 0;\n\t\t\t\tctx.store.charCount = 0;\n\t\t\t\tctx.store.usageTokens = 0;\n\t\t\t\tctx.store.sawUsage = false;\n\t\t\t}\n\t\t\tconst store = ctx.store as {\n\t\t\t\tchunkCount: number;\n\t\t\t\tcharCount: number;\n\t\t\t\tusageTokens: number;\n\t\t\t\tsawUsage: boolean;\n\t\t\t};\n\n\t\t\tif (delta.type === \"token\") {\n\t\t\t\tstore.chunkCount += 1;\n\t\t\t\tstore.charCount += delta.delta.length;\n\t\t\t} else if (delta.type === \"usage\") {\n\t\t\t\tstore.sawUsage = true;\n\t\t\t\tstore.usageTokens = sumInputTokens(delta.usage) + sumOutputTokens(delta.usage);\n\t\t\t}\n\n\t\t\tconst estimatedTokens = store.sawUsage\n\t\t\t\t? store.usageTokens\n\t\t\t\t: Math.ceil(store.charCount / charsPerToken);\n\t\t\tactions.emit({\n\t\t\t\tchunkCount: store.chunkCount,\n\t\t\t\tcharCount: store.charCount,\n\t\t\t\testimatedTokens,\n\t\t\t\testimated: !store.sawUsage,\n\t\t\t});\n\t\t\treturn cleanup;\n\t\t},\n\t\t{\n\t\t\tname: opts?.name ?? \"cost-meter\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: ZERO,\n\t\t\tmeta: aiMeta(\"cost_meter_extractor\"),\n\t\t\tequals: costMeterEqual,\n\t\t},\n\t);\n}\n","/**\n * Keyword-flag extractor — scans accumulated stream text for configured patterns.\n * @module\n */\n\nimport { type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { aiMeta } from \"../_internal.js\";\n\n/** A keyword match detected in the stream. */\nexport type KeywordFlag = {\n\treadonly label: string;\n\treadonly pattern: RegExp;\n\treadonly match: string;\n\treadonly position: number;\n};\n\nexport type KeywordFlagExtractorOptions = {\n\tpatterns: readonly { pattern: RegExp; label: string }[];\n\tname?: string;\n\t/**\n\t * Maximum length of any pattern's literal text. Used as an overlap window\n\t * when cursoring through the accumulated stream so matches that span\n\t * chunk boundaries aren't missed. Default: 128.\n\t */\n\tmaxPatternLength?: number;\n};\n\nconst keywordFlagsEqual = (\n\ta: readonly KeywordFlag[] | null,\n\tb: readonly KeywordFlag[] | null,\n): boolean => {\n\tif (a === b) return true;\n\tif (a == null || b == null) return a === b;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i++) {\n\t\tconst x = a[i];\n\t\tconst y = b[i];\n\t\tif (\n\t\t\tx.label !== y.label ||\n\t\t\tx.pattern !== y.pattern ||\n\t\t\tx.match !== y.match ||\n\t\t\tx.position !== y.position\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n};\n\n/**\n * Mounts a keyword-flag extractor on accumulated text. Scans for all\n * configured patterns and emits an array of matches.\n *\n * **Wave A Unit 3 rewrite:** signature takes `accumulatedText: Node<string>`\n * instead of the old `TopicGraph<StreamChunk>`. Patterns are compiled once\n * at factory time (was per-chunk). `maxPatternLength` is validated at\n * factory time — any pattern whose source exceeds the window throws\n * immediately.\n *\n * Use cases: design invariant violations (`setTimeout`, `EventEmitter`), PII\n * detection (SSN, email, phone), toxicity keywords, off-track reasoning.\n *\n * **Streaming optimization.** Maintains a cursor across waves in `ctx.store`\n * so each emission scans only the delta region `accumulated.slice(scannedTo -\n * maxPatternLength)` — not the full string. Reactivation clears `ctx.store`\n * and resumes from offset 0 (COMPOSITION-GUIDE §20 RAM semantics).\n *\n * Default structural equals suppresses DATA emission when no new flags were\n * found this wave.\n */\nexport function keywordFlagExtractor(\n\taccumulatedText: Node<string>,\n\topts: KeywordFlagExtractorOptions,\n): Node<readonly KeywordFlag[]> {\n\tconst maxPatternLength = opts.maxPatternLength ?? 128;\n\t// Factory-time: validate pattern literal lengths + compile once.\n\tfor (const p of opts.patterns) {\n\t\tif (p.pattern.source.length > maxPatternLength) {\n\t\t\tthrow new Error(\n\t\t\t\t`keywordFlagExtractor: pattern \"${p.label}\" literal exceeds maxPatternLength (${p.pattern.source.length} > ${maxPatternLength}); raise the option or shorten the pattern.`,\n\t\t\t);\n\t\t}\n\t}\n\tconst compiled = opts.patterns.map((p) => ({\n\t\tlabel: p.label,\n\t\tpattern: p.pattern,\n\t\tcompiled: new RegExp(p.pattern.source, `${p.pattern.flags.replace(\"g\", \"\")}g`),\n\t}));\n\t// Lock 6.D (Phase 13.6.B): clear scan state on deactivation so a\n\t// resubscribed extractor doesn't carry over per-stream cursors.\n\tlet cleanup: { onDeactivation: () => void } | undefined;\n\treturn node<readonly KeywordFlag[]>(\n\t\t[accumulatedText],\n\t\t(batchData, actions, ctx) => {\n\t\t\tif (cleanup === undefined) {\n\t\t\t\tconst store = ctx.store;\n\t\t\t\tcleanup = {\n\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\tdelete store.flags;\n\t\t\t\t\t\tdelete store.scannedTo;\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst text = data[0];\n\t\t\tif (text == null) {\n\t\t\t\tactions.emit([]);\n\t\t\t\treturn cleanup;\n\t\t\t}\n\t\t\tconst accumulated = text as string;\n\n\t\t\tif (!(\"flags\" in ctx.store)) {\n\t\t\t\tctx.store.flags = [] as KeywordFlag[];\n\t\t\t\tctx.store.scannedTo = 0;\n\t\t\t}\n\t\t\tconst flags = ctx.store.flags as KeywordFlag[];\n\t\t\tconst scannedTo = ctx.store.scannedTo as number;\n\n\t\t\t// Scan the delta plus an overlap window so matches that span\n\t\t\t// chunk boundaries (e.g. \"EventE\" + \"mitter\") are still found.\n\t\t\tconst startOffset = Math.max(0, scannedTo - maxPatternLength);\n\t\t\tconst region = accumulated.slice(startOffset);\n\t\t\tlet added = false;\n\t\t\tfor (const { pattern, label, compiled: re } of compiled) {\n\t\t\t\tre.lastIndex = 0;\n\t\t\t\tfor (const m of region.matchAll(re)) {\n\t\t\t\t\tconst pos = startOffset + (m.index ?? 0);\n\t\t\t\t\tif (pos + m[0].length <= scannedTo) continue;\n\t\t\t\t\tflags.push({ label, pattern, match: m[0], position: pos });\n\t\t\t\t\tadded = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tctx.store.scannedTo = accumulated.length;\n\t\t\tactions.emit(added ? [...flags] : flags.slice());\n\t\t\treturn cleanup;\n\t\t},\n\t\t{\n\t\t\tname: opts.name ?? \"keyword-flag-extractor\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: [],\n\t\t\tmeta: aiMeta(\"keyword_flag_extractor\"),\n\t\t\tequals: keywordFlagsEqual,\n\t\t},\n\t);\n}\n","/**\n * Generic stream extractor — mounts an extract function on accumulated text.\n *\n * **Wave A Unit 3 rewrite:** signature changed from\n * `streamExtractor(topic: TopicGraph<StreamChunk>, fn)` to\n * `streamExtractor(accumulatedText: Node<string>, fn)`. The Unit 2 delta-\n * topic redesign removed the per-chunk `accumulated` field; callers pass\n * `streamingPromptNode(...).accumulatedText` (or any other `Node<string>`\n * source of accumulated text). Source-agnostic — the extractor doesn't care\n * whether the text came from an LLM, WebSocket, SSE tail, or file reader.\n *\n * @module\n */\n\nimport { type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { aiMeta } from \"../_internal.js\";\n\n/**\n * Mounts an extractor function on a reactive accumulated-text source. Returns\n * a derived node that emits extracted values as the text grows.\n *\n * @param accumulatedText - Reactive `Node<string>` of accumulated text.\n * @param extractFn - `(accumulated: string) => T | null`.\n * @param opts - Optional name + structural equals.\n * @returns Derived node emitting extracted values.\n */\nexport function streamExtractor<T>(\n\taccumulatedText: Node<string>,\n\textractFn: (accumulated: string) => T | null,\n\topts?: {\n\t\tname?: string;\n\t\t/**\n\t\t * Optional structural equals for the extractor output. When two\n\t\t * consecutive chunks produce structurally-equal outputs, the framework\n\t\t * emits `RESOLVED` instead of `DATA`, saving downstream work. Default:\n\t\t * reference equality (`Object.is`). The library cannot know your\n\t\t * output shape — supply this when your `extractFn` returns structured\n\t\t * objects or arrays.\n\t\t */\n\t\tequals?: (a: T | null, b: T | null) => boolean;\n\t},\n): Node<T | null> {\n\treturn node<T | null>(\n\t\t[accumulatedText],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst text = data[0];\n\t\t\tactions.emit(text == null ? null : extractFn(text as string));\n\t\t},\n\t\t{\n\t\t\tname: opts?.name ?? \"extractor\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: null,\n\t\t\tmeta: aiMeta(\"stream_extractor\"),\n\t\t\t...(opts?.equals ? { equals: opts.equals } : {}),\n\t\t},\n\t);\n}\n","/**\n * Tool-call extractor — scans accumulated stream text for complete JSON tool call objects.\n * @module\n */\n\nimport { type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { aiMeta } from \"../_internal.js\";\n\n/** A tool call detected in the stream. */\nexport type ExtractedToolCall = {\n\treadonly name: string;\n\treadonly arguments: Record<string, unknown>;\n\treadonly raw: string;\n\treadonly startIndex: number;\n};\n\nconst toolCallsEqual = (\n\ta: readonly ExtractedToolCall[] | null,\n\tb: readonly ExtractedToolCall[] | null,\n): boolean => {\n\tif (a === b) return true;\n\tif (a == null || b == null) return a === b;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i++) {\n\t\tconst x = a[i];\n\t\tconst y = b[i];\n\t\tif (x.startIndex !== y.startIndex || x.name !== y.name || x.raw !== y.raw) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n};\n\n/**\n * Mounts a tool-call extractor on a streaming topic. Scans accumulated text\n * for complete JSON objects containing `\"name\"` and `\"arguments\"` keys (the\n * standard tool_call shape). Partial JSON is ignored until the closing brace.\n *\n * Feeds into the tool interception chain for reactive tool gating mid-stream.\n *\n * **Streaming optimization.** Maintains a cursor (`scanFrom`) in `ctx.store`\n * so each chunk resumes brace-scanning from the position after the last\n * complete parse (or the last incomplete open brace). Already-parsed objects\n * are not re-parsed. Default structural equals suppresses DATA emission when\n * no new tool call completed this chunk.\n */\nexport function toolCallExtractor(\n\taccumulatedText: Node<string>,\n\topts?: { name?: string },\n): Node<readonly ExtractedToolCall[]> {\n\t// Lock 6.D (Phase 13.6.B): clear scan state on deactivation so a\n\t// resubscribed extractor doesn't ship stale per-stream cursors.\n\tlet cleanup: { onDeactivation: () => void } | undefined;\n\treturn node<readonly ExtractedToolCall[]>(\n\t\t[accumulatedText],\n\t\t(batchData, actions, ctx) => {\n\t\t\tif (cleanup === undefined) {\n\t\t\t\tconst store = ctx.store;\n\t\t\t\tcleanup = {\n\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\tdelete store.calls;\n\t\t\t\t\t\tdelete store.scanFrom;\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst text = data[0];\n\t\t\tif (text == null) {\n\t\t\t\tactions.emit([]);\n\t\t\t\treturn cleanup;\n\t\t\t}\n\t\t\tconst accumulated = text as string;\n\n\t\t\tif (!(\"calls\" in ctx.store)) {\n\t\t\t\tctx.store.calls = [] as ExtractedToolCall[];\n\t\t\t\tctx.store.scanFrom = 0;\n\t\t\t}\n\t\t\tconst calls = ctx.store.calls as ExtractedToolCall[];\n\t\t\tlet i = ctx.store.scanFrom as number;\n\t\t\tlet added = false;\n\n\t\t\twhile (i < accumulated.length) {\n\t\t\t\tconst start = accumulated.indexOf(\"{\", i);\n\t\t\t\tif (start === -1) {\n\t\t\t\t\tctx.store.scanFrom = accumulated.length;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tlet depth = 0;\n\t\t\t\tlet end = -1;\n\t\t\t\tlet inString = false;\n\t\t\t\tfor (let j = start; j < accumulated.length; j++) {\n\t\t\t\t\tconst ch = accumulated[j];\n\t\t\t\t\tif (inString) {\n\t\t\t\t\t\tif (ch === \"\\\\\" && j + 1 < accumulated.length) {\n\t\t\t\t\t\t\tj++; // skip escaped character\n\t\t\t\t\t\t} else if (ch === '\"') {\n\t\t\t\t\t\t\tinString = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (ch === '\"') {\n\t\t\t\t\t\tinString = true;\n\t\t\t\t\t} else if (ch === \"{\") {\n\t\t\t\t\t\tdepth++;\n\t\t\t\t\t} else if (ch === \"}\") {\n\t\t\t\t\t\tdepth--;\n\t\t\t\t\t\tif (depth === 0) {\n\t\t\t\t\t\t\tend = j;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (end === -1) {\n\t\t\t\t\t// Incomplete — resume brace-scanning from this open brace\n\t\t\t\t\t// next chunk. Do NOT advance past it.\n\t\t\t\t\tctx.store.scanFrom = start;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tconst raw = accumulated.slice(start, end + 1);\n\t\t\t\ttry {\n\t\t\t\t\tconst parsed = JSON.parse(raw) as Record<string, unknown>;\n\t\t\t\t\tif (\n\t\t\t\t\t\ttypeof parsed.name === \"string\" &&\n\t\t\t\t\t\tparsed.arguments != null &&\n\t\t\t\t\t\ttypeof parsed.arguments === \"object\"\n\t\t\t\t\t) {\n\t\t\t\t\t\tcalls.push({\n\t\t\t\t\t\t\tname: parsed.name,\n\t\t\t\t\t\t\targuments: parsed.arguments as Record<string, unknown>,\n\t\t\t\t\t\t\traw,\n\t\t\t\t\t\t\tstartIndex: start,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tadded = true;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Not valid JSON — skip\n\t\t\t\t}\n\t\t\t\ti = end + 1;\n\t\t\t\tctx.store.scanFrom = i;\n\t\t\t}\n\n\t\t\t// Always return a fresh copy so downstream never holds a live\n\t\t\t// reference to ctx.store.calls.\n\t\t\tactions.emit(added ? [...calls] : calls.slice());\n\t\t\treturn cleanup;\n\t\t},\n\t\t{\n\t\t\tname: opts?.name ?? \"tool-call-extractor\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: [],\n\t\t\tmeta: aiMeta(\"tool_call_extractor\"),\n\t\t\tequals: toolCallsEqual,\n\t\t},\n\t);\n}\n","/**\n * Content gate — classifies accumulated stream text as allow / review / block.\n * @module\n */\n\nimport { type Node, node } from \"@graphrefly/pure-ts/core\";\n\n/** Content safety decision. */\nexport type ContentDecision = \"allow\" | \"block\" | \"review\";\n\n/** Options for {@link contentGate}. */\nexport type ContentGateOptions = {\n\t/**\n\t * Hard-block threshold multiplier (default 1.5).\n\t * Scores above `threshold * hardMultiplier` emit `\"block\"`.\n\t * Scores between `threshold` and that emit `\"review\"`.\n\t */\n\thardMultiplier?: number;\n\tname?: string;\n};\n\n/**\n * Derived node that classifies accumulated stream text as `\"allow\"`,\n * `\"review\"`, or `\"block\"` based on a classifier score.\n *\n * **Wave A Unit 3 rewrite:** signature now takes `accumulatedText: Node<string>`\n * instead of a `TopicGraph<StreamChunk>` (the `StreamChunk` shape was retired\n * when the delta topic replaced the per-chunk accumulated-text shape).\n *\n * Emits a three-way decision on every text change:\n * - `\"allow\"` — score below `threshold`\n * - `\"review\"` — score in `[threshold, threshold × hardMultiplier)`\n * - `\"block\"` — score at or above `threshold × hardMultiplier`\n *\n * @param accumulatedText - Reactive accumulated-text source\n * (`streamingPromptNode(...).accumulatedText`).\n * @param classifier - `(accumulated: string) => number` scoring function, or\n * a `Node<number>` for live scores.\n * @param threshold - Score at which output becomes `\"review\"` or `\"block\"`.\n */\nexport function contentGate(\n\taccumulatedText: Node<string>,\n\tclassifier: ((accumulated: string) => number) | Node<number>,\n\tthreshold: number,\n\topts?: ContentGateOptions,\n): Node<ContentDecision> {\n\tconst hardThreshold = threshold * (opts?.hardMultiplier ?? 1.5);\n\tconst isNodeClassifier = typeof classifier !== \"function\";\n\n\tconst deps: Node<unknown>[] = [accumulatedText];\n\tif (isNodeClassifier) deps.push(classifier as Node<unknown>);\n\n\treturn node<ContentDecision>(\n\t\tdeps,\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst text = (data[0] as string | undefined) ?? \"\";\n\t\t\tif (text.length === 0) {\n\t\t\t\tactions.emit(\"allow\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst score = isNodeClassifier\n\t\t\t\t? ((data[1] as number | undefined) ?? 0)\n\t\t\t\t: (classifier as (t: string) => number)(text);\n\n\t\t\tif (score >= hardThreshold) {\n\t\t\t\tactions.emit(\"block\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (score >= threshold) {\n\t\t\t\tactions.emit(\"review\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tactions.emit(\"allow\");\n\t\t},\n\t\t{ describeKind: \"derived\", name: opts?.name ?? \"content-gate\", initial: \"allow\" },\n\t);\n}\n","/**\n * Redactor — stream extractor that replaces matched patterns in accumulated text.\n *\n * **Wave A Unit 3 rewrite:** signature now takes `accumulatedText: Node<string>`\n * instead of the retired `TopicGraph<StreamChunk>`. The output is a\n * `Node<string>` carrying the sanitized accumulated text — compose with\n * `contentGate` or downstream UI directly.\n *\n * @module\n */\n\nimport { type Node, node } from \"@graphrefly/pure-ts/core\";\n\n/** Options for {@link redactor}. */\nexport type RedactorOptions = {\n\tname?: string;\n};\n\n/**\n * Derived node that replaces matched patterns in accumulated text.\n *\n * @param accumulatedText - Reactive accumulated-text source.\n * @param patterns - Array of RegExps to match against the text.\n * @param replaceFn - Replacement producer (default: always `\"[REDACTED]\"`).\n * @returns `Node<string>` emitting the sanitized accumulated text.\n */\nexport function redactor(\n\taccumulatedText: Node<string>,\n\tpatterns: RegExp[],\n\treplaceFn?: (match: string, pattern: RegExp) => string,\n\topts?: RedactorOptions,\n): Node<string> {\n\tconst replace = replaceFn ?? (() => \"[REDACTED]\");\n\n\tfunction sanitize(text: string): string {\n\t\tlet result = text;\n\t\tfor (const pat of patterns) {\n\t\t\tconst global = pat.global ? pat : new RegExp(pat.source, `${pat.flags}g`);\n\t\t\tresult = result.replace(global, (m) => replace(m, pat));\n\t\t}\n\t\treturn result;\n\t}\n\n\treturn node<string>(\n\t\t[accumulatedText],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tactions.emit(sanitize((data[0] as string | undefined) ?? \"\"));\n\t\t},\n\t\t{ describeKind: \"derived\", name: opts?.name ?? \"redactor\", initial: \"\" },\n\t);\n}\n","import { type Node, node, RESOLVED } from \"@graphrefly/pure-ts/core\";\nimport { keepalive, type ReactiveLogBundle, reactiveLog } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { aiMeta } from \"../_internal.js\";\nimport type { ChatMessage } from \"../adapters/core/types.js\";\n\n// ---------------------------------------------------------------------------\n// chatStream\n// ---------------------------------------------------------------------------\n\nexport type ChatStreamOptions = {\n\tgraph?: GraphOptions;\n\tmaxMessages?: number;\n};\n\nexport class ChatStreamGraph extends Graph {\n\tprivate readonly _log: ReactiveLogBundle<ChatMessage>;\n\treadonly messages: Node<readonly ChatMessage[]>;\n\t/**\n\t * Most recently appended message. Stays in the protocol SENTINEL state\n\t * (`cache === undefined`, no DATA emitted) until the first append, then\n\t * tracks the latest entry. Per COMPOSITION-GUIDE §1a, the SENTINEL is\n\t * the canonical \"no value yet\" signal — consumers detect empty via\n\t * `data[i] === undefined` inside reactive fns or `latest.cache === undefined`\n\t * outside. No `T | null` placeholder, no `hasLatest` companion.\n\t */\n\treadonly latest: Node<ChatMessage>;\n\treadonly messageCount: Node<number>;\n\n\tconstructor(name: string, opts: ChatStreamOptions = {}) {\n\t\tsuper(name, opts.graph);\n\n\t\tthis._log = reactiveLog<ChatMessage>([], {\n\t\t\tname: \"messages\",\n\t\t\tmaxSize: opts.maxMessages,\n\t\t});\n\t\tthis.messages = this._log.entries;\n\t\tthis.add(this.messages, { name: \"messages\" });\n\n\t\t// SENTINEL on empty (COMPOSITION-GUIDE §1a): return `[]` for\n\t\t// RESOLVED-only on empty stream, `[T]` to emit DATA. `latest.cache`\n\t\t// stays `undefined` until the first append.\n\t\tthis.latest = node<ChatMessage>(\n\t\t\t[this.messages],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst entries = data[0] as readonly ChatMessage[];\n\t\t\t\tif (entries.length === 0) {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tactions.emit(entries[entries.length - 1] as ChatMessage);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"latest\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"chat_latest\"),\n\t\t\t},\n\t\t);\n\t\tthis.add(this.latest, { name: \"latest\" });\n\t\tthis.addDisposer(keepalive(this.latest));\n\n\t\tthis.messageCount = node<number>(\n\t\t\t[this.messages],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tactions.emit((data[0] as readonly ChatMessage[]).length);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"messageCount\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"chat_message_count\"),\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t);\n\t\tthis.add(this.messageCount, { name: \"messageCount\" });\n\t\tthis.addDisposer(keepalive(this.messageCount));\n\t}\n\n\tappend(role: ChatMessage[\"role\"], content: string, extra?: Partial<ChatMessage>): void {\n\t\tthis._log.append({ role, content, ...extra });\n\t}\n\n\tappendToolResult(callId: string, content: string): void {\n\t\tthis._log.append({ role: \"tool\", content, toolCallId: callId });\n\t}\n\n\tclear(): void {\n\t\tthis._log.clear();\n\t}\n\n\tallMessages(): readonly ChatMessage[] {\n\t\treturn this.messages.cache as readonly ChatMessage[];\n\t}\n}\n\nexport function chatStream(name: string, opts?: ChatStreamOptions): ChatStreamGraph {\n\treturn new ChatStreamGraph(name, opts);\n}\n","import { factoryTag, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { fromAny, type NodeInput, switchMap } from \"@graphrefly/pure-ts/extra\";\n\n// ---------------------------------------------------------------------------\n// handoff — multi-agent routing sugar (B10)\n// ---------------------------------------------------------------------------\n\n/**\n * Options for {@link handoff}.\n */\nexport type HandoffOptions = {\n\t/**\n\t * Reactive gate: when this node's value is `true`, output flows from\n\t * `from` to the `to` specialist; when `false`, `from`'s output flows\n\t * through unchanged and `to` stays dormant. Omit to always hand off —\n\t * useful when `from` is itself a router whose output shape already\n\t * encodes routing intent.\n\t */\n\tcondition?: NodeInput<boolean>;\n\tname?: string;\n};\n\n/**\n * Multi-agent handoff recipe — route `from`'s output into a specialist\n * agent `toFactory` when `condition` is open. Thin composition over\n * `switchMap` + gate; not a new primitive, just a named shape.\n *\n * The \"handoff\" pattern (popularized by the OpenAI Agents SDK) covers two\n * idioms:\n *\n * 1. **Full handoff** — a triage agent routes the conversation to a\n * specialist, and the specialist becomes the active agent for the rest\n * of the turn. Accumulated context (memory, tool definitions) can travel\n * along by threading the same `agentMemory` bundle into both.\n * 2. **Agents-as-tools** — the manager keeps control and calls the\n * specialist like a tool for a bounded subtask. Build this by registering\n * a `promptNode` instance as a `ToolDefinition` on the parent via\n * `toolRegistry`.\n *\n * This sugar covers (1) — a reactive route from one agent's output into a\n * specialist factory. For (2) wire a tool registry manually; the pattern is\n * additive with this one.\n *\n * @example Full handoff on a triage signal.\n * ```ts\n * import { handoff, promptNode } from \"@graphrefly/graphrefly/patterns/ai\";\n *\n * const triage = promptNode(adapter, [userMessage], (msg) =>\n * `Classify urgency of: ${msg}. Reply \"high\" or \"normal\".`);\n * const isUrgent = derived([triage], ([v]) => v === \"high\");\n *\n * const specialist = handoff(\n * userMessage,\n * (input) => promptNode(specialistAdapter, [input], (m) => `Respond urgently: ${m}`),\n * { condition: isUrgent },\n * );\n * ```\n *\n * @param from - Source node whose value is threaded into the specialist.\n * @param toFactory - Factory that takes `from` (as a reactive source) and\n * returns the specialist node. Called once, lazily, when the first\n * subscriber activates.\n * @param opts - Optional reactive `condition` gate + name.\n * @returns Node emitting the specialist's output when the gate is open, or\n * `from`'s value when the gate is closed. Null when `from` is null.\n *\n * **Performance caveat (Wave A Unit 5):** the specialist is mounted per\n * source emission — each `v != null` DATA on `from` allocates a fresh\n * `state<T>(v)` + invokes `toFactory`, and switchMap cancels the prior\n * branch. For per-turn routing (≤1 emit/sec) this is negligible. For\n * high-frequency sources (per-token routing, tight event loops), batch\n * upstream (e.g. via `audit`, `throttle`, or `distinctUntilChanged`) before\n * handing off — each mount/unmount cycle spins up full subgraphs\n * (`messagesNode` + adapter bridge + output for a `promptNode` specialist).\n *\n * @category patterns.ai\n */\nexport function handoff<T>(\n\tfrom: NodeInput<T | null>,\n\ttoFactory: (input: Node<T>) => Node<T | null>,\n\topts?: HandoffOptions,\n): Node<T | null> {\n\tconst src = fromAny(from);\n\tconst cond = opts?.condition != null ? fromAny(opts.condition) : null;\n\n\t// Shared `null` state — reused across null source emissions so repeated\n\t// nulls don't allocate a fresh node per switchMap project call.\n\tconst nullState: Node<T | null> = node<T | null>([], {\n\t\tinitial: null,\n\t\tname: opts?.name ? `${opts.name}::null` : \"handoff::null\",\n\t});\n\n\t// When no condition is supplied, always route through the specialist.\n\tif (cond == null) {\n\t\treturn switchMap<T | null, T | null>(\n\t\t\tsrc,\n\t\t\t(v) => {\n\t\t\t\tif (v == null) return nullState as NodeInput<T | null>;\n\t\t\t\tconst input = node<T>([], { initial: v });\n\t\t\t\treturn toFactory(input) as NodeInput<T | null>;\n\t\t\t},\n\t\t\t{ meta: factoryTag(\"handoff\") },\n\t\t);\n\t}\n\n\t// With a condition: pair src + cond into a router object, then switchMap\n\t// to either the specialist (when open) or a pass-through state (when\n\t// closed). Each router emission may re-instantiate the specialist — the\n\t// switchMap cancels the stale branch.\n\tconst router = node<{ v: T | null; open: boolean }>(\n\t\t[src, cond],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tactions.emit({ v: data[0] as T | null, open: data[1] === true });\n\t\t},\n\t\t{ name: opts?.name ? `${opts.name}::router` : \"handoff::router\", describeKind: \"derived\" },\n\t);\n\treturn switchMap<{ v: T | null; open: boolean }, T | null>(\n\t\trouter,\n\t\t({ v, open }) => {\n\t\t\tif (v == null) return nullState as NodeInput<T | null>;\n\t\t\tif (!open) return node<T | null>([], { initial: v }) as NodeInput<T | null>;\n\t\t\tconst input = node<T>([], { initial: v });\n\t\t\treturn toFactory(input) as NodeInput<T | null>;\n\t\t},\n\t\t{ meta: factoryTag(\"handoff\") },\n\t);\n}\n","/**\n * `toolExecution` — reactive per-tool-call executor with retry + rescue.\n *\n * Lifted from the inlined `executeToolReactively` helper inside `agent-loop.ts`\n * so it can be consumed standalone by any caller with a reactive `toolCalls`\n * batch — not just `agentLoop`. The shape is: one input `Node<readonly\n * ToolCall[]>` + a `ToolRegistryGraph` → one output `Node<readonly\n * ToolResult[]>`. Each call maps to a per-call `retrySource(executeReactive)`\n * → optional `rescue` chain that emits the handler result on success, or a\n * JSON-wrapped `{ error }` payload on terminal failure so the LLM can see the\n * error as tool output and decide whether to try again via another tool call.\n *\n * **Cancellation.** `executeReactive` mints a per-call `AbortController` and\n * threads its signal into the handler call. When `switchMap` supersedes the\n * inner (a fresh `toolCalls` batch arrives) or the outer graph tears down,\n * the per-call node unsubscribes and `ac.abort()` fires. Signal-aware\n * handlers (`fetch(url, {signal})`, child-process kill, DB cancel) actually\n * stop in-flight work; handlers that ignore the signal still complete to\n * their original termination, but their result is discarded.\n *\n * @module\n */\n\nimport { type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { rescue, switchMap } from \"@graphrefly/pure-ts/extra\";\nimport { retry } from \"../../../base/resilience/retry.js\";\nimport type { ToolCall } from \"../adapters/core/types.js\";\nimport type { ToolRegistryGraph } from \"./tool-registry.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** A single tool execution outcome: `{id, content}` where content is a JSON string. */\nexport interface ToolResult {\n\treadonly id: string;\n\treadonly content: string;\n}\n\nexport type ToolExecutionOptions = {\n\t/**\n\t * Reactive tool-call batch. Each non-empty emission triggers a fresh\n\t * per-call execution fan-out; superseding emissions cancel the prior fan.\n\t */\n\ttoolCalls: Node<readonly ToolCall[]>;\n\t/** Registry that resolves tool name → handler. */\n\ttools: ToolRegistryGraph;\n\t/**\n\t * Retry count per individual tool call. `retrySource({count: N})` retries\n\t * up to N times on error (N retries = N+1 total attempts). Default: 1.\n\t */\n\tretryCount?: number;\n\t/**\n\t * How to surface a terminal error after retries are exhausted.\n\t * - `\"rescue\"` (default): emit `{id, content: JSON.stringify({error})}`\n\t * so the LLM sees the failure as structured tool output and can decide\n\t * how to react. Sibling calls in the same batch continue to their own\n\t * completion; one call's failure does not affect the others.\n\t * - `\"propagate\"`: let the ERROR propagate downstream. **Blast radius:**\n\t * the per-batch `derived` join auto-errors when any per-call node\n\t * terminates with ERROR, so one call's failure discards every sibling's\n\t * DATA (even ones that already settled with a valid ToolResult). Use\n\t * `\"propagate\"` only when a single tool failure should be fatal for the\n\t * whole batch; prefer `\"rescue\"` when you want the LLM to see partial\n\t * results plus per-call error markers.\n\t */\n\tonError?: \"rescue\" | \"propagate\";\n};\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Reactive executor for a batch of LLM tool calls.\n *\n * Each DATA emission on `toolCalls` dispatches a fresh per-call fan-out: for\n * every call in the batch, construct a `retrySource(fromAny(tools.execute(\n * name, args)))` node, optionally `rescue` it into a JSON error shape, and\n * join the results via a `derived` whose first-run gate waits for every call\n * to settle before emitting the batch. Empty batches (`calls.length === 0`)\n * are a caller-side invariant violation (the upstream gate should emit\n * RESOLVED for empty batches, not DATA) and trigger a loud error — callers\n * that want to accept empty batches should upstream-filter them first.\n *\n * Reference-equality + content-equality dedup is applied to the output batch\n * so duplicate re-emissions from a completing retrySource don't propagate.\n *\n * @param opts - `{ toolCalls, tools, retryCount?, onError? }`.\n * @returns `Node<readonly ToolResult[]>` — one ToolResult per input ToolCall.\n */\nexport function toolExecution(opts: ToolExecutionOptions): Node<readonly ToolResult[]> {\n\tconst { toolCalls, tools } = opts;\n\tconst retryCount = opts.retryCount ?? 1;\n\tconst onError = opts.onError ?? \"rescue\";\n\n\tconst batchEquals = (a: readonly ToolResult[], b: readonly ToolResult[]): boolean => {\n\t\tif (a === b) return true;\n\t\tif (a.length !== b.length) return false;\n\t\tfor (let i = 0; i < a.length; i++) {\n\t\t\tconst ai = a[i];\n\t\t\tconst bi = b[i];\n\t\t\tif (ai?.id !== bi?.id) return false;\n\t\t\tif (ai?.content !== bi?.content) return false;\n\t\t}\n\t\treturn true;\n\t};\n\n\treturn switchMap<readonly ToolCall[], readonly ToolResult[]>(toolCalls, (calls) => {\n\t\tif (calls == null || calls.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t\"toolExecution: received an empty tool-call batch as DATA — callers must upstream-filter empty batches (emit RESOLVED) so switchMap is only dispatched for non-empty batches.\",\n\t\t\t);\n\t\t}\n\t\tconst perCall = calls.map((call) => executeOne(call, tools, retryCount, onError));\n\t\t// `executeOne` returns `Node<ToolResult>` in both \"rescue\" and\n\t\t// \"propagate\" modes (the rescue handler builds a `ToolResult`\n\t\t// shape; the success `derived` builds one directly). The join\n\t\t// just forwards the per-call values — no shape coercion needed.\n\t\treturn node(\n\t\t\tperCall,\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tactions.emit(data as readonly ToolResult[]);\n\t\t\t},\n\t\t\t{ describeKind: \"derived\", name: \"toolExecution::batch\", equals: batchEquals },\n\t\t);\n\t});\n}\n\n// ---------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------\n\n/**\n * Per-call reactive executor. `retrySource` re-invokes the factory on ERROR\n * (each attempt mints a fresh `executeReactive` node, which in turn mints a\n * fresh `AbortController` and handler invocation). `executeReactive` itself\n * handles synchronous handler throws — they surface as `[[ERROR, err]]`\n * inside the producer, so `retrySource`'s reactive ERROR path fires\n * consistently regardless of handler shape. No `Promise.resolve().then(...)`\n * thunk needed — the reactive path is end-to-end.\n *\n * Handlers that return a plain string are surfaced as-is; anything else is\n * `JSON.stringify`'d so LLMs that parse tool results can roundtrip\n * structured data without surprise quoting.\n */\nfunction executeOne(\n\tcall: ToolCall,\n\ttools: ToolRegistryGraph,\n\tretryCount: number,\n\tonError: \"rescue\" | \"propagate\",\n): Node<ToolResult> {\n\tconst attempted: Node<unknown> = retry(() => tools.executeReactive(call.name, call.arguments), {\n\t\tcount: retryCount,\n\t}).node;\n\tconst onSuccess = node<ToolResult>(\n\t\t[attempted],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst val = data[0];\n\t\t\tactions.emit({\n\t\t\t\tid: call.id,\n\t\t\t\tcontent: typeof val === \"string\" ? val : JSON.stringify(val),\n\t\t\t});\n\t\t},\n\t\t{ describeKind: \"derived\" },\n\t);\n\tif (onError === \"propagate\") return onSuccess;\n\treturn rescue(onSuccess, (err) => ({\n\t\tid: call.id,\n\t\tcontent: JSON.stringify({ error: String(err) }),\n\t}));\n}\n","import { ERROR, type Messages, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { fromAsyncIter, fromPromise, keepalive, reactiveMap } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { aiMeta, isNodeLike } from \"../_internal.js\";\nimport type { ToolDefinition } from \"../adapters/core/types.js\";\n\n// ---------------------------------------------------------------------------\n// toolRegistry\n// ---------------------------------------------------------------------------\n\nexport type ToolRegistryOptions = {\n\tgraph?: GraphOptions;\n};\n\n/**\n * `ToolRegistryGraph` — name-keyed registry of {@link ToolDefinition}s.\n *\n * **Reactive-only execution.** The only execution path is\n * {@link executeReactive}, which returns a `Node<unknown>` for the handler\n * result. Composing factories (`toolExecution`, `agentLoop`) consume it\n * directly inside `retrySource` / `switchMap` chains. There is intentionally\n * no imperative `execute()` Promise method — the registry was originally a\n * dual-boundary class (imperative + reactive) and the imperative path was\n * the only thing in the codebase bridging through `Promise.resolve().then()`\n * to feed `fromAny`. Removing it left every consumer on a single\n * reactive-all-the-way path with real abort propagation.\n *\n * For non-reactive callers (debug scripts, one-shot tests), bridge with\n * `awaitSettled(toolRegistry.executeReactive(name, args))`.\n *\n * **Wave A Unit 6 refactor:** internal storage migrated from `state<Map>`\n * (O(N) Map-copy per mutation) to `ReactiveMapBundle<string, ToolDefinition>`\n * (O(1) mutations + version counter).\n */\nexport class ToolRegistryGraph extends Graph {\n\treadonly definitions: Node<ReadonlyMap<string, ToolDefinition>>;\n\treadonly schemas: Node<readonly ToolDefinition[]>;\n\tprivate readonly _bundle: ReturnType<typeof reactiveMap<string, ToolDefinition>>;\n\n\tconstructor(name: string, opts: ToolRegistryOptions = {}) {\n\t\tsuper(name, opts.graph);\n\n\t\tthis._bundle = reactiveMap<string, ToolDefinition>({\n\t\t\tname: \"definitions\",\n\t\t});\n\t\tthis.definitions = this._bundle.entries;\n\t\tthis.add(this.definitions, { name: \"definitions\" });\n\n\t\tthis.schemas = node<readonly ToolDefinition[]>(\n\t\t\t[this.definitions],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst defs = data[0];\n\t\t\t\tactions.emit([...((defs ?? new Map()) as ReadonlyMap<string, ToolDefinition>).values()]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"schemas\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"tool_schemas\"),\n\t\t\t\tinitial: [],\n\t\t\t},\n\t\t);\n\t\tthis.add(this.schemas, { name: \"schemas\" });\n\t\tthis.addDisposer(keepalive(this.schemas));\n\t}\n\n\tregister(tool: ToolDefinition): void {\n\t\tthis._bundle.set(tool.name, tool);\n\t}\n\n\tunregister(name: string): void {\n\t\tthis._bundle.delete(name);\n\t}\n\n\t/**\n\t * Reactive execution — returns a `Node<unknown>` that emits the handler\n\t * result. The returned node is a `producer` that:\n\t *\n\t * 1. Mints a per-call `AbortController` whose `signal` is threaded into\n\t * the handler call AND into `fromAny` (so a `fromPromise` /\n\t * `fromAsyncIter` inner abandons cleanly when the consumer\n\t * unsubscribes).\n\t * 2. Runs `tool.handler(args, {signal})` inside a try/catch — a\n\t * synchronous throw surfaces as `[[ERROR, err]]` downstream instead\n\t * of escaping the producer.\n\t * 3. Forwards every message from the inner `fromAny` chain to the\n\t * producer's outputs.\n\t * 4. On teardown (subscriber count drops to zero, e.g. `switchMap`\n\t * supersede) calls `ac.abort()` and unsubscribes the inner.\n\t * Signal-aware handlers (e.g. `fetch(url, {signal})`) actually stop.\n\t *\n\t * Each call mints a fresh node tied to a fresh `handler(args, ...)`\n\t * invocation — call `executeReactive` again for repeated invocations.\n\t *\n\t * @throws `Error` synchronously when `name` is not registered (no node is\n\t * constructed — the caller gets a pre-wiring failure rather than a\n\t * silent ERROR wave on an empty graph).\n\t */\n\texecuteReactive(name: string, args: Record<string, unknown>): Node<unknown> {\n\t\tconst tool = this._bundle.get(name);\n\t\tif (!tool) throw new Error(`toolRegistry: unknown tool \"${name}\"`);\n\t\treturn node<unknown>(\n\t\t\t[],\n\t\t\t(_data, actions) => {\n\t\t\t\tconst ac = new AbortController();\n\t\t\t\tlet inner: Node<unknown>;\n\t\t\t\ttry {\n\t\t\t\t\tconst raw = tool.handler(args, { signal: ac.signal });\n\t\t\t\t\tinner = handlerResultToNode(raw, ac.signal);\n\t\t\t\t} catch (err) {\n\t\t\t\t\t// Synchronous throw from handler → ERROR. Producer cleanup\n\t\t\t\t\t// still aborts the controller for symmetry (no-op if no\n\t\t\t\t\t// signal listeners attached).\n\t\t\t\t\tactions.down([[ERROR, err]] satisfies Messages);\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tac.abort();\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst unsub = inner.subscribe((batch) => {\n\t\t\t\t\tactions.down(batch as Messages);\n\t\t\t\t});\n\t\t\t\treturn () => {\n\t\t\t\t\tac.abort();\n\t\t\t\t\tunsub();\n\t\t\t\t};\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: `executeReactive::${name}`,\n\t\t\t\tdescribeKind: \"producer\",\n\t\t\t\tmeta: aiMeta(\"tool_execute_reactive\"),\n\t\t\t},\n\t\t);\n\t}\n\n\tgetDefinition(name: string): ToolDefinition | undefined {\n\t\t// Pure read via the snapshot cache — avoids the bundle's\n\t\t// `wrapMutation` path (which would run the version-bump check and\n\t\t// any configured retention eviction on every lookup). Safe because\n\t\t// `getDefinition` is a boundary API, not a reactive fn body.\n\t\treturn this._bundle.entries.cache?.get(name);\n\t}\n}\n\nexport function toolRegistry(name: string, opts?: ToolRegistryOptions): ToolRegistryGraph {\n\treturn new ToolRegistryGraph(name, opts);\n}\n\n/**\n * Coerce a tool handler return value into a `Node<unknown>`.\n *\n * Differs from `fromAny` by treating **strings, arrays, plain iterables, and\n * scalar objects as single DATA values** rather than iterating them. A tool\n * handler that returns `\"hello world\"` should surface as one `DATA(\"hello\n * world\")`, not 11 `DATA` events of single characters; an array `[1, 2, 3]`\n * should surface as `DATA([1, 2, 3])`, not three separate emissions.\n *\n * Reactive shapes (Node, Promise, AsyncIterable) are unwrapped as expected.\n *\n * @internal\n */\nfunction handlerResultToNode(raw: unknown, signal: AbortSignal): Node<unknown> {\n\tif (isNodeLike(raw)) {\n\t\treturn raw as Node<unknown>;\n\t}\n\tif (raw != null && typeof (raw as PromiseLike<unknown>).then === \"function\") {\n\t\treturn fromPromise(raw as PromiseLike<unknown>, { signal });\n\t}\n\tif (raw != null && typeof raw === \"object\" && Symbol.asyncIterator in (raw as object)) {\n\t\treturn fromAsyncIter(raw as AsyncIterable<unknown>, { signal });\n\t}\n\t// String, number, boolean, null, undefined, plain object, array,\n\t// sync iterable — treat as a single DATA value via a resolved Promise so\n\t// `fromPromise`'s scalar-DATA-emit + COMPLETE semantics match the\n\t// pre-refactor `tools.execute` behavior (which always wrapped via async).\n\treturn fromPromise(Promise.resolve(raw), { signal });\n}\n","import { factoryTag, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { fromAny, type NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport { aiMeta } from \"../_internal.js\";\nimport type { ToolDefinition } from \"../adapters/core/types.js\";\n\n// ---------------------------------------------------------------------------\n// toolSelector — reactive tool availability (D8 / COMPOSITION-GUIDE §31)\n// ---------------------------------------------------------------------------\n\n/**\n * Options for {@link toolSelector}.\n */\nexport interface ToolSelectorOptions {\n\treadonly name?: string;\n}\n\n/**\n * Reactive tool availability (COMPOSITION-GUIDE §31). Given a base tool set\n * (reactive or static) and one or more reactive predicates, emit the filtered\n * subset of tools currently allowed. Feeds into `promptNode({ tools: Node<...> })`\n * so the LLM sees a reactive menu instead of a frozen config.\n *\n * Each predicate is a `NodeInput<(tool) => boolean>`. A tool is included iff\n * **every** predicate returns `true`. When any predicate value is `null` /\n * `undefined` (e.g. upstream not yet ready) that predicate is treated as a\n * pass-through — the tool isn't excluded on its basis. Predicate updates\n * recompute the selected set.\n *\n * Pairs with `toolInterceptor` (§D9 / §31): **selection** controls what's\n * offered to the LLM (pre-generation UX); **interception** gates what's\n * executed after the LLM chooses (post-generation security). Tool selection\n * is NOT a security boundary — an LLM can hallucinate tool calls outside\n * its offered set; always pair with `toolInterceptor` for enforcement.\n *\n * @example\n * ```ts\n * const hasBudget = node([costMeter], (batchData, actions, ctx) => {\n * const data = batchData.map((batch, i) => batch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i]);\n * actions.emit((data[0] as CostMeter).total < BUDGET);\n * }, { describeKind: \"derived\" });\n * const canDestroy = state(false, { name: \"destructive-allowed\" });\n * const tools = toolSelector(registry.schemas, [\n * node([hasBudget], (batchData, actions, ctx) => {\n * const data = batchData.map((batch, i) => batch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i]);\n * actions.emit((t) => !t.meta?.expensive || data[0] === true);\n * }, { describeKind: \"derived\" }),\n * node([canDestroy], (batchData, actions, ctx) => {\n * const data = batchData.map((batch, i) => batch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i]);\n * actions.emit((t) => !t.meta?.destructive || data[0] === true);\n * }, { describeKind: \"derived\" }),\n * ]);\n * const agent = promptNode(graph, \"agent\", { ..., tools });\n * ```\n */\nexport function toolSelector(\n\tallTools: NodeInput<readonly ToolDefinition[]>,\n\tconstraints: readonly NodeInput<(tool: ToolDefinition) => boolean>[],\n\topts?: ToolSelectorOptions,\n): Node<readonly ToolDefinition[]> {\n\tconst allToolsNode = fromAny(allTools);\n\tconst constraintNodes = constraints.map((c) => fromAny(c));\n\tconst deps = [allToolsNode, ...constraintNodes] as const;\n\treturn node<readonly ToolDefinition[]>(\n\t\tdeps,\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst tools = (data[0] as readonly ToolDefinition[] | null | undefined) ?? [];\n\t\t\tconst preds = data.slice(1) as ReadonlyArray<\n\t\t\t\t((t: ToolDefinition) => boolean) | null | undefined\n\t\t\t>;\n\t\t\tactions.emit(\n\t\t\t\ttools.filter((tool) => {\n\t\t\t\t\tfor (const pred of preds) {\n\t\t\t\t\t\t// Pass-through when a predicate hasn't settled — callers with\n\t\t\t\t\t\t// async constraints should not have every tool silently dropped\n\t\t\t\t\t\t// on the first emit. Constraints are \"deny when false\", not\n\t\t\t\t\t\t// \"deny when not yet ready\".\n\t\t\t\t\t\tif (pred == null) continue;\n\t\t\t\t\t\tif (!pred(tool)) return false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t\t{\n\t\t\tname: opts?.name ?? \"tool-selector\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tmeta: { ...aiMeta(\"tool_selector\"), ...factoryTag(\"toolSelector\") },\n\t\t\tequals: (a, b) => {\n\t\t\t\tconst la = a as readonly ToolDefinition[];\n\t\t\t\tconst lb = b as readonly ToolDefinition[];\n\t\t\t\tif (la.length !== lb.length) return false;\n\t\t\t\tfor (let i = 0; i < la.length; i++) {\n\t\t\t\t\tif (la[i] !== lb[i]) return false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t},\n\t\t},\n\t);\n}\n","// ---------------------------------------------------------------------------\n// Admission scoring (generic + 3D sugar)\n// ---------------------------------------------------------------------------\n//\n// `admissionScored<Dims>` is the generic primitive: a user-supplied scoreFn\n// returns one number per named dimension; the filter rejects whenever any\n// scored dimension falls below its configured threshold. Dimensions absent\n// from the thresholds config are ignored — they may still be useful for\n// telemetry, but don't gate admission.\n//\n// `admissionFilter3D` is a thin wrapper for the persistence / structure /\n// personalValue triple borrowed from the LLM memory literature; ship this\n// when callers want the named-axes shape, otherwise compose `admissionScored`\n// directly with whatever dimensions fit the domain.\n//\n// The earlier `defaultAdmissionScorer` (always-0.5 across all dims) was\n// retired in Unit 8 — it admitted everything in disguise. Callers must\n// supply a real `scoreFn`.\n\n/** Generic per-dimension thresholds. Any dim below its threshold → reject. */\nexport type AdmissionThresholds<Dims extends string> = Partial<Record<Dims, number>>;\n\nexport type AdmissionScoredOptions<Dims extends string, TRaw = unknown> = {\n\t/** Score function — must return a finite number for every dimension named in `thresholds`. */\n\tscoreFn: (raw: TRaw) => Readonly<Record<Dims, number>>;\n\t/** Per-dim minimums. Dims absent here are scored but not gated. */\n\tthresholds?: AdmissionThresholds<Dims>;\n};\n\n/**\n * Generic N-dimension admission filter. Rejects any input where one of the\n * configured threshold dimensions scores below its minimum. Missing scores\n * (`undefined` / `null`) AND non-finite values (`NaN`, `±Infinity`) are\n * treated as below all thresholds — reject by default rather than admit.\n *\n * @example\n * ```ts\n * const filter = admissionScored({\n * scoreFn: (raw: Note) => ({ relevance: scoreRelevance(raw), age: ageScore(raw) }),\n * thresholds: { relevance: 0.4 }, // age scored but ungated\n * });\n * ```\n */\nexport function admissionScored<Dims extends string, TRaw = unknown>(\n\topts: AdmissionScoredOptions<Dims, TRaw>,\n): (raw: TRaw) => boolean {\n\tconst thresholds = opts.thresholds ?? ({} as AdmissionThresholds<Dims>);\n\treturn (raw: TRaw): boolean => {\n\t\tconst scores = opts.scoreFn(raw);\n\t\tfor (const dim of Object.keys(thresholds) as Dims[]) {\n\t\t\tconst min = thresholds[dim];\n\t\t\tif (min === undefined) continue;\n\t\t\tconst s = scores[dim];\n\t\t\t// `??` falls back on null/undefined but lets NaN through; we want\n\t\t\t// non-finite to also reject so a buggy scoreFn returning NaN doesn't\n\t\t\t// silently admit. `Number.isFinite(NaN) === false`.\n\t\t\tconst safe = Number.isFinite(s) ? (s as number) : Number.NEGATIVE_INFINITY;\n\t\t\tif (safe < min) return false;\n\t\t}\n\t\treturn true;\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// 3D sugar\n// ---------------------------------------------------------------------------\n\n/** Scores for the three admission dimensions. Each 0–1. */\nexport type AdmissionScores = {\n\treadonly persistence: number;\n\treadonly structure: number;\n\treadonly personalValue: number;\n};\n\nexport type AdmissionScore3DOptions = {\n\t/** Custom scoring function. Required — the previous always-0.5 default was misleading. */\n\tscoreFn: (raw: unknown) => AdmissionScores;\n\t/** Minimum persistence score to admit (default 0.3). */\n\tpersistenceThreshold?: number;\n\t/** Minimum personalValue score to admit (default 0.3). */\n\tpersonalValueThreshold?: number;\n\t/** Require structure score > 0 to admit (default false). */\n\trequireStructured?: boolean;\n};\n\n/**\n * 3D admission sugar — the persistence / structure / personalValue triple\n * commonly used in agent-memory literature. Composes `admissionScored`\n * with thresholds derived from the option fields. Use directly when those\n * three named dimensions match your domain, or use `admissionScored` with\n * an arbitrary dimension set instead.\n *\n * `requireStructured: true` rejects entries where `structure <= 0` (matches\n * the pre-Unit-8 `requireStructured && scores.structure <= 0` check).\n * Implemented as a final-step predicate around `admissionScored` rather\n * than a `Number.MIN_VALUE` threshold, which would have been a footgun for\n * future readers.\n */\nexport function admissionFilter3D(opts: AdmissionScore3DOptions): (raw: unknown) => boolean {\n\tconst thresholds: AdmissionThresholds<keyof AdmissionScores> = {\n\t\tpersistence: opts.persistenceThreshold ?? 0.3,\n\t\tpersonalValue: opts.personalValueThreshold ?? 0.3,\n\t};\n\tconst base = admissionScored<keyof AdmissionScores, unknown>({\n\t\tscoreFn: opts.scoreFn,\n\t\tthresholds,\n\t});\n\tif (!opts.requireStructured) return base;\n\treturn (raw: unknown): boolean => {\n\t\tif (!base(raw)) return false;\n\t\tconst s = opts.scoreFn(raw).structure;\n\t\treturn Number.isFinite(s) && s > 0;\n\t};\n}\n","// ---------------------------------------------------------------------------\n// memory composers — Unit 7 C-factoring (2026-04-23 doc decision).\n//\n// Each composer attaches one capability (vectors, KG, tiers, retrieval) to a\n// `DistillBundle`. `agentMemory` continues to ship as the ergonomic sugar\n// over the full pipeline; power users who want a subset call these factories\n// directly.\n//\n// Class B audit (2026-04-30): the composers were migrated from\n// bundle-returning factories to **Graph subclasses** so they participate in\n// `describe()` / `destroy()` like every other Phase 4+ Graph (mirrors\n// `AuditTrailGraph`, `PolicyGateGraph`, `CqrsGraph`). The factory functions\n// remain as ergonomic constructors (`memoryWithVectors(opts) → MemoryWithVectorsGraph`).\n//\n// Tier 4.1 B + 4.3 B (2026-04-29): `memoryWithTiers` is the construction site\n// for the distill bundle when tiers are configured (`reactiveMap.retention`\n// wired at construction eliminates the §7 feedback cycle the prior\n// `tierClassifier` effect carried). `permanentKeys` and `entryCreatedAtNs`\n// are reactive maps mounted on the graph (not closure state) so\n// `describe()`/`explain()` can walk to the inputs that fed an archival\n// decision.\n// ---------------------------------------------------------------------------\n\nimport { batch, DATA, monotonicNs, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport type { StorageHandle } from \"@graphrefly/pure-ts/extra\";\nimport {\n\tfromAny,\n\tkeepalive,\n\ttype NodeInput,\n\ttype ReactiveMapBundle,\n\ttype ReactiveMapRetention,\n\treactiveMap,\n} from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport {\n\ttype DistillBundle,\n\ttype DistillOptions,\n\tdistill,\n\ttype Extraction,\n} from \"../../../base/composition/distill.js\";\nimport { decay } from \"../../../base/utils/decay.js\";\nimport {\n\tcollection,\n\tcosineSimilarity,\n\ttype KnowledgeEdge,\n\ttype KnowledgeGraph,\n\tknowledgeGraph,\n\ttype VectorIndexGraph,\n\ttype VectorRecord,\n\ttype VectorSearchResult,\n\tvectorIndex,\n} from \"../../memory/index.js\";\nimport { aiMeta } from \"../_internal.js\";\nimport type { RetrievalEntry, RetrievalQuery, RetrievalTrace } from \"./retrieval.js\";\nimport {\n\tDEFAULT_DECAY_RATE,\n\ttype MemoryTier,\n\ttype MemoryTiersBundle,\n\ttype MemoryTiersOptions,\n} from \"./tiers.js\";\n\n// Tier 4.7 (Wave AM Unit 5 carry): the pre-rebuild defensive `extractStoreMap`\n// helper (runtime `instanceof Map` check before casting) was deleted in favor\n// of a typed `as` cast at each callsite. The upstream `ReactiveMapBundle`\n// always emits a real Map on the live emit path; non-Map snapshots only\n// surface on `Graph.restore` from a codec that round-tripped Map → JSON →\n// plain object (handled in `extra/composite.ts:mapFromSnapshot` for distill\n// internals). Empty map is the canonical \"no entries yet\" value —\n// `node([], { initial: undefined })` would stall a derived/effect's first-run gate.\n//\n// qa F3 (deferred): the typed cast lies if upstream contract ever breaks\n// (e.g. `entries` emits a non-Map non-undefined value). Failure mode is a\n// TypeError at iteration instead of a silent empty-map fallback —\n// deliberate trade-off, surfacing real upstream-contract violations beats\n// hiding them. Upstream-narrowing follow-up filed in `docs/optimizations.md`\n// under \"Tier 4.7 follow-up — narrow `ReactiveMapBundle.entries` callback typing\".\n\n// ---------------------------------------------------------------------------\n// memoryWithVectors\n// ---------------------------------------------------------------------------\n\nexport interface MemoryWithVectorsOptions<TMem> {\n\t/** Optional Graph identity — passed through to the underlying `Graph` ctor. */\n\tgraph?: GraphOptions;\n\t/** Subgraph name. Default: `\"memory-vectors\"`. */\n\tname?: string;\n\t/** The substrate distill store to index. */\n\tstore: DistillBundle<TMem>;\n\t/** Embedding dimension. Must match the `embedFn` output length. */\n\tdimension: number;\n\t/** Extract an embedding vector for a memory entry. */\n\tembedFn: (mem: TMem) => readonly number[] | undefined;\n}\n\n/**\n * Graph subclass that attaches a vector index to a `DistillBundle`. The inner\n * `VectorIndexGraph` is mounted at `\"vectorIndex\"`; an internal effect\n * subscribes to the substrate store and re-indexes on every change.\n *\n * Mirrors `AuditTrailGraph` / `PolicyGateGraph` shape — fully self-contained,\n * teardown via the Graph's `destroy()` cascade.\n */\nexport class MemoryWithVectorsGraph<TMem> extends Graph {\n\treadonly vectors: VectorIndexGraph<TMem>;\n\n\tconstructor(opts: MemoryWithVectorsOptions<TMem>) {\n\t\tsuper(opts.name ?? \"memory-vectors\", opts.graph);\n\t\tthis.vectors = vectorIndex<TMem>({ dimension: opts.dimension });\n\t\tthis.mount(\"vectorIndex\", this.vectors);\n\n\t\tconst embedFn = opts.embedFn;\n\t\tconst vectorsRef = this.vectors;\n\n\t\t// Indexer effect — subscribes to the substrate's store entries, upserts\n\t\t// vectors. Pure side-effect; restricted `effect` fn (no emit/down).\n\t\t// Cross-graph dep on `opts.store.store.entries` is fine — the substrate\n\t\t// is the upstream wired in by the parent factory.\n\t\tconst indexer = node(\n\t\t\t[opts.store.store.entries],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst storeMap =\n\t\t\t\t\t(data[0] as ReadonlyMap<string, TMem> | undefined) ?? new Map<string, TMem>();\n\t\t\t\tfor (const [key, mem] of storeMap) {\n\t\t\t\t\tconst vec = embedFn(mem);\n\t\t\t\t\tif (vec) vectorsRef.upsert(key, vec, mem);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ name: \"indexer\", describeKind: \"effect\" },\n\t\t);\n\t\tthis.add(indexer, { name: \"indexer\" });\n\t\tthis.addDisposer(keepalive(indexer));\n\t}\n}\n\n/**\n * Attach a vector index to a `DistillBundle`. Indexes every entry in the\n * store as it changes. Returns the `MemoryWithVectorsGraph` whose `vectors`\n * field exposes the underlying `VectorIndexGraph`.\n *\n * Teardown is handled by `Graph.destroy()` — typically inherited via\n * mounting the result on a parent graph (see `agentMemory`).\n */\nexport function memoryWithVectors<TMem>(\n\topts: MemoryWithVectorsOptions<TMem>,\n): MemoryWithVectorsGraph<TMem> {\n\treturn new MemoryWithVectorsGraph<TMem>(opts);\n}\n\n// ---------------------------------------------------------------------------\n// memoryWithKG\n// ---------------------------------------------------------------------------\n\nexport interface MemoryWithKGOptions<TMem> {\n\t/** Optional Graph identity. */\n\tgraph?: GraphOptions;\n\t/** Subgraph name. Default: `\"memory-kg\"`. */\n\tname?: string;\n\t/** The substrate distill store to index. */\n\tstore: DistillBundle<TMem>;\n\t/** Inner KnowledgeGraph name. Default: `${name}-kg`. */\n\tkgName?: string;\n\t/**\n\t * Mount path within this Graph for the KnowledgeGraph. Default:\n\t * `\"knowledge-kg\"` (B5c — symmetric with the outer `knowledge` mount so\n\t * describe paths render `knowledge::knowledge-kg::*`).\n\t */\n\tmountPath?: string;\n\t/**\n\t * Extract entities + relations for a memory entry. Omit to mount an empty\n\t * KG without an indexer effect — caller upserts entities / relations\n\t * directly on the `kg` field.\n\t */\n\tentityFn?: (\n\t\tkey: string,\n\t\tmem: TMem,\n\t) =>\n\t\t| {\n\t\t\t\tentities?: Array<{ id: string; value: unknown }>;\n\t\t\t\trelations?: Array<{ from: string; to: string; relation: string; weight?: number }>;\n\t\t }\n\t\t| undefined;\n}\n\n/**\n * Graph subclass that attaches a knowledge graph alongside a `DistillBundle`.\n * Mounts the inner `KnowledgeGraph` at `mountPath` (default `\"knowledge-kg\"`); when\n * `entityFn` is provided, an indexer effect populates entities/relations on\n * every store change.\n */\nexport class MemoryWithKGGraph<TMem> extends Graph {\n\treadonly kg: KnowledgeGraph<unknown, string>;\n\n\tconstructor(opts: MemoryWithKGOptions<TMem>) {\n\t\tconst name = opts.name ?? \"memory-kg\";\n\t\tsuper(name, opts.graph);\n\t\tconst kgName = opts.kgName ?? `${name}-kg`;\n\t\tconst mountPath = opts.mountPath ?? \"knowledge-kg\";\n\t\tthis.kg = knowledgeGraph<unknown, string>(kgName);\n\t\tthis.mount(mountPath, this.kg);\n\n\t\tif (!opts.entityFn) return;\n\t\tconst entityFn = opts.entityFn;\n\t\tconst kgRef = this.kg;\n\t\tconst indexer = node(\n\t\t\t[opts.store.store.entries],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst storeMap =\n\t\t\t\t\t(data[0] as ReadonlyMap<string, TMem> | undefined) ?? new Map<string, TMem>();\n\t\t\t\tfor (const [key, mem] of storeMap) {\n\t\t\t\t\tconst extracted = entityFn(key, mem);\n\t\t\t\t\tif (!extracted) continue;\n\t\t\t\t\tfor (const ent of extracted.entities ?? []) {\n\t\t\t\t\t\tkgRef.upsertEntity(ent.id, ent.value);\n\t\t\t\t\t}\n\t\t\t\t\tfor (const rel of extracted.relations ?? []) {\n\t\t\t\t\t\tkgRef.link(rel.from, rel.to, rel.relation, rel.weight);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ name: \"indexer\", describeKind: \"effect\" },\n\t\t);\n\t\tthis.add(indexer, { name: \"indexer\" });\n\t\tthis.addDisposer(keepalive(indexer));\n\t}\n}\n\n/**\n * Attach a knowledge graph alongside a `DistillBundle`. Returns the\n * `MemoryWithKGGraph` whose `kg` field exposes the inner `KnowledgeGraph`.\n */\nexport function memoryWithKG<TMem>(opts: MemoryWithKGOptions<TMem>): MemoryWithKGGraph<TMem> {\n\treturn new MemoryWithKGGraph<TMem>(opts);\n}\n\n// ---------------------------------------------------------------------------\n// memoryWithTiers\n// ---------------------------------------------------------------------------\n\n/**\n * Full options for {@link memoryWithTiers} (Tier 4.1 B + 4.3 B refactor,\n * 2026-04-29). Combines tier-policy options with the distill-side options\n * needed to construct the underlying store — `memoryWithTiers` is the\n * **construction site** for the distill bundle so it can wire\n * `reactiveMap.retention` into the store at construction (eliminating the\n * §7 feedback cycle the previous `tierClassifier` effect carried).\n */\nexport type MemoryWithTiersOptions<TRaw, TMem> = MemoryTiersOptions<TMem> &\n\tOmit<DistillOptions<TMem>, \"mapOptions\" | \"score\" | \"context\"> & {\n\t\t/** Optional Graph identity. */\n\t\tgraph?: GraphOptions;\n\t\t/** Subgraph name. Default: `\"memory-tiers\"`. */\n\t\tname?: string;\n\t\t/** Raw source feeding distill. */\n\t\tsource: NodeInput<TRaw>;\n\t\t/** Reactive extraction wiring (same shape as `distill`). */\n\t\textractFn: (\n\t\t\traw: Node<TRaw>,\n\t\t\texisting: Node<ReadonlyMap<string, TMem>>,\n\t\t) => NodeInput<Extraction<TMem>>;\n\t\t/** Score function — same signature as `agentMemory.score`. */\n\t\tscore: (mem: TMem, context: unknown) => number;\n\t\t/** Optional reactive context node (passed to `score`). */\n\t\tcontext?: NodeInput<unknown>;\n\t};\n\n/**\n * Graph subclass attaching 3-tier storage (active / archived / permanent) to\n * a fresh distill store, wiring `reactiveMap.retention` at construction so\n * archival happens synchronously inside the substrate's mutation pipeline\n * (no §7 feedback cycle). Promotes `permanentKeys` and `entryCreatedAtNs` to\n * reactive maps registered on this graph (Tier 4.3 B — Unit 7 Q3) so\n * `describe()` / `explain()` can walk to \"why was X archived?\".\n *\n * Public-face fields:\n * - `store` — the distill bundle (construction site, exposed for downstream\n * composers).\n * - `tiers` — tier classification + permanent promotion handles.\n * - `compact`, `size` — alias for `store.compact` / `store.size` (registered\n * under their canonical names so `describe()` keys match `agentMemory`'s\n * pre-migration layout).\n */\nexport class MemoryWithTiersGraph<TRaw, TMem> extends Graph {\n\treadonly store: DistillBundle<TMem>;\n\treadonly tiers: MemoryTiersBundle<TMem>;\n\treadonly compact: Node<Array<{ key: string; value: TMem; score: number }>>;\n\treadonly size: Node<number>;\n\treadonly permanent: ReturnType<typeof collection<TMem>>;\n\treadonly permanentKeys: ReactiveMapBundle<string, true>;\n\treadonly entryCreatedAtNs: ReactiveMapBundle<string, number>;\n\n\tconstructor(opts: MemoryWithTiersOptions<TRaw, TMem>) {\n\t\tsuper(opts.name ?? \"memory-tiers\", opts.graph);\n\n\t\tconst decayRate = opts.decayRate ?? DEFAULT_DECAY_RATE;\n\t\tconst maxActive = opts.maxActive ?? 1000;\n\t\tconst archiveThreshold = opts.archiveThreshold ?? 0.1;\n\t\tconst permanentFilter = opts.permanentFilter ?? (() => false);\n\n\t\t// Tier 2.3 fold: `lightCollection` was merged into\n\t\t// `collection({ranked: false})`. The unified factory returns a Graph (not\n\t\t// a detached bundle), so it's mounted as a subgraph for `describe()`.\n\t\tthis.permanent = collection<TMem>(\"permanent\", { ranked: false });\n\t\tthis.mount(\"permanent\", this.permanent);\n\n\t\t// 4.3 B (Unit 7 Q3, 2026-04-29): closure-state promotion. `permanentKeys`\n\t\t// and `entryCreatedAtNs` are reactive maps registered on this graph so\n\t\t// `describe()` can walk to them and `explain()` can trace the inputs\n\t\t// that fed an archival decision.\n\t\tthis.permanentKeys = reactiveMap<string, true>({ name: \"permanentKeys\" });\n\t\tthis.add(this.permanentKeys.entries, { name: \"permanentKeys\" });\n\t\tthis.entryCreatedAtNs = reactiveMap<string, number>({ name: \"entryCreatedAtNs\" });\n\t\tthis.add(this.entryCreatedAtNs.entries, { name: \"entryCreatedAtNs\" });\n\n\t\t// Closure-mirror for ctx (§28 factory-time seed). `score(mem, ctx)` runs\n\t\t// inside `retention.score` which is invoked synchronously from store\n\t\t// mutations — no reactive dep on contextNode there. The mirror keeps\n\t\t// `latestCtx` current via subscribe.\n\t\t//\n\t\t// Topology visibility: the local-default branch registers the context\n\t\t// state node so it appears in `describe()`. The user-supplied-Node\n\t\t// branch deliberately leaves the node unregistered — `fromAny` returns\n\t\t// the caller's owned Node, which is owned by their graph; mounting it\n\t\t// here would corrupt cross-graph ownership.\n\t\tlet contextNode: Node<unknown>;\n\t\tif (opts.context) {\n\t\t\tcontextNode = fromAny(opts.context);\n\t\t} else {\n\t\t\tcontextNode = node<unknown>([], { initial: null });\n\t\t\tthis.add(contextNode, { name: \"context\" });\n\t\t}\n\t\tlet latestCtx: unknown = contextNode.cache;\n\t\tconst ctxUnsub = contextNode.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) if (m[0] === DATA) latestCtx = m[1];\n\t\t});\n\t\tthis.addDisposer(ctxUnsub);\n\n\t\tconst permanentKeysRef = this.permanentKeys;\n\t\tconst entryCreatedAtNsRef = this.entryCreatedAtNs;\n\t\tconst score = opts.score;\n\n\t\t// Build retention. `score` runs synchronously inside store mutations.\n\t\t// Permanent matches return Infinity to bypass eviction.\n\t\t//\n\t\t// DS-13.5.F (2026-05-01): `score` is read-only against\n\t\t// `entryCreatedAtNs` — the first-write side-effect was extracted into\n\t\t// the `entryCreatedAtNs/sync` effect below. Race window for the very\n\t\t// first call on a new key is mitigated by the `?? nowNs` fallback\n\t\t// (yields ageSeconds = 0, i.e. fresh-decay), and the sync effect\n\t\t// populates the map after the wave settles so subsequent score calls\n\t\t// see the persisted timestamp.\n\t\tconst retention: ReactiveMapRetention<string, TMem> = {\n\t\t\tscore: (key, value) => {\n\t\t\t\tif (permanentFilter(key, value)) return Number.POSITIVE_INFINITY;\n\t\t\t\tif (permanentKeysRef.has(key)) return Number.POSITIVE_INFINITY;\n\t\t\t\tconst nowNs = monotonicNs();\n\t\t\t\tconst createdNs = entryCreatedAtNsRef.get(key) ?? nowNs;\n\t\t\t\tconst ageSeconds = Number(nowNs - createdNs) / 1e9;\n\t\t\t\treturn decay(score(value, latestCtx), ageSeconds, decayRate);\n\t\t\t},\n\t\t\tarchiveThreshold,\n\t\t\tmaxSize: maxActive,\n\t\t};\n\n\t\t// Construct distill with retention wired into mapOptions.\n\t\tthis.store = distill<TRaw, TMem>(opts.source, opts.extractFn, {\n\t\t\tscore: opts.score,\n\t\t\tcost: opts.cost,\n\t\t\t...(opts.budget !== undefined ? { budget: opts.budget } : {}),\n\t\t\t...(opts.evict !== undefined ? { evict: opts.evict } : {}),\n\t\t\t...(opts.consolidate !== undefined ? { consolidate: opts.consolidate } : {}),\n\t\t\t...(opts.consolidateTrigger !== undefined\n\t\t\t\t? { consolidateTrigger: opts.consolidateTrigger }\n\t\t\t\t: {}),\n\t\t\t...(opts.context !== undefined ? { context: opts.context } : {}),\n\t\t\tmapOptions: { retention },\n\t\t});\n\n\t\t// Register the distill bundle's exposed nodes under their canonical\n\t\t// names so consumers (and `describe()`) see the same shape as the\n\t\t// pre-migration top-level surface on `agentMemory`.\n\t\tthis.add(this.store.store.entries, { name: \"store\" });\n\t\tthis.compact = this.store.compact;\n\t\tthis.add(this.compact, { name: \"compact\" });\n\t\tthis.size = this.store.size;\n\t\tthis.add(this.size, { name: \"size\" });\n\n\t\tconst storeRef = this.store;\n\t\tconst tierOf = (key: string): MemoryTier => {\n\t\t\tif (permanentKeysRef.has(key)) return \"permanent\";\n\t\t\tconst m =\n\t\t\t\t(storeRef.store.entries.cache as ReadonlyMap<string, TMem> | undefined) ??\n\t\t\t\tnew Map<string, TMem>();\n\t\t\tif (m.has(key)) return \"active\";\n\t\t\treturn \"archived\";\n\t\t};\n\t\tconst permanentRef = this.permanent;\n\t\tconst markPermanent = (key: string, value: TMem): void => {\n\t\t\tpermanentKeysRef.set(key, true);\n\t\t\tpermanentRef.upsert(key, value);\n\t\t};\n\n\t\t// DS-13.5.F (2026-05-01): first-write of `entryCreatedAtNs[key]` runs\n\t\t// here (extracted from `retention.score` to keep score pure). Reads\n\t\t// `store.store.entries`, writes `entryCreatedAtNs` — distinct nodes,\n\t\t// no §7 feedback cycle. Idempotent: re-emissions for already-tracked\n\t\t// keys skip via `entryCreatedAtNsRef.has(key)`.\n\t\tconst syncCreatedAt = node(\n\t\t\t[this.store.store.entries],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst map = (data[0] as ReadonlyMap<string, TMem> | undefined) ?? new Map<string, TMem>();\n\t\t\t\tconst nowNs = monotonicNs();\n\t\t\t\tconst toAdd: string[] = [];\n\t\t\t\tfor (const key of map.keys()) {\n\t\t\t\t\tif (!entryCreatedAtNsRef.has(key)) toAdd.push(key);\n\t\t\t\t}\n\t\t\t\tif (toAdd.length > 0) {\n\t\t\t\t\tbatch(() => {\n\t\t\t\t\t\tfor (const key of toAdd) entryCreatedAtNsRef.set(key, nowNs);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ name: \"entryCreatedAtNs/sync\", describeKind: \"effect\" },\n\t\t);\n\t\tthis.add(syncCreatedAt, { name: \"entryCreatedAtNs/sync\" });\n\t\tthis.addDisposer(keepalive(syncCreatedAt));\n\n\t\t// GC entryCreatedAtNs entries that no longer exist in the active store.\n\t\t// (Adds happen via the syncCreatedAt effect above; removals piggyback\n\t\t// on the store-snapshot subscriber here so the map stays in sync.)\n\t\tconst entriesUnsub = this.store.store.entries.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] !== DATA) continue;\n\t\t\t\tconst map = m[1] as ReadonlyMap<string, TMem>;\n\t\t\t\tconst created = entryCreatedAtNsRef.entries.cache as\n\t\t\t\t\t| ReadonlyMap<string, number>\n\t\t\t\t\t| undefined;\n\t\t\t\tif (created == null) continue;\n\t\t\t\tconst toDelete: string[] = [];\n\t\t\t\tfor (const key of created.keys()) {\n\t\t\t\t\tif (!map.has(key)) toDelete.push(key);\n\t\t\t\t}\n\t\t\t\tif (toDelete.length > 0) {\n\t\t\t\t\tbatch(() => {\n\t\t\t\t\t\tfor (const key of toDelete) entryCreatedAtNsRef.delete(key);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tthis.addDisposer(entriesUnsub);\n\n\t\t// Permanent-promotion effect. Writes to `permanent` collection +\n\t\t// `permanentKeys` (NOT to the active store), so no §7 cycle: the effect's\n\t\t// dep is `store.store.entries`, but it doesn't write back to that node.\n\t\tconst promoter = node(\n\t\t\t[this.store.store.entries],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst map = (data[0] as ReadonlyMap<string, TMem> | undefined) ?? new Map<string, TMem>();\n\t\t\t\tfor (const [key, mem] of map) {\n\t\t\t\t\tif (permanentKeysRef.has(key)) continue;\n\t\t\t\t\tif (permanentFilter(key, mem)) {\n\t\t\t\t\t\tbatch(() => {\n\t\t\t\t\t\t\tmarkPermanent(key, mem);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ name: \"promoter\", describeKind: \"effect\" },\n\t\t);\n\t\tthis.add(promoter, { name: \"promoter\" });\n\t\tthis.addDisposer(keepalive(promoter));\n\n\t\tlet archiveHandle: StorageHandle | null = null;\n\t\tif (opts.archiveTier) {\n\t\t\tarchiveHandle = this.attachSnapshotStorage(\n\t\t\t\t[{ snapshot: opts.archiveTier }],\n\t\t\t\topts.archiveStorageOptions ?? {},\n\t\t\t);\n\t\t\tthis.addDisposer(() => archiveHandle?.dispose());\n\t\t}\n\n\t\tthis.tiers = {\n\t\t\tpermanent: this.permanent,\n\t\t\tactiveEntries: this.store.store.entries,\n\t\t\tarchiveHandle,\n\t\t\ttierOf,\n\t\t\tmarkPermanent,\n\t\t};\n\t}\n}\n\n/**\n * Attach 3-tier storage (active / archived / permanent) over a fresh distill\n * store. Returns a `MemoryWithTiersGraph` whose `store` and `tiers` fields\n * mirror the previous bundle shape.\n *\n * **API shape** (Class B audit, 2026-04-30 — breaking change vs.\n * pre-migration): the factory takes a single opts bag including `source`\n * and `extractFn`. The bundle is exposed as `result.store` for downstream\n * composers (vectors / KG / retrieval).\n *\n * - `permanentFilter`-matching entries score `Infinity` in retention →\n * never archived. Independent permanent-promotion effect upserts them\n * into the `permanent` collection.\n * - Below-threshold entries → retention archives synchronously.\n * - Over-`maxActive` entries → retention's `maxSize` evicts lowest-scored.\n */\nexport function memoryWithTiers<TRaw, TMem>(\n\topts: MemoryWithTiersOptions<TRaw, TMem>,\n): MemoryWithTiersGraph<TRaw, TMem> {\n\treturn new MemoryWithTiersGraph<TRaw, TMem>(opts);\n}\n\n// ---------------------------------------------------------------------------\n// memoryRetrieval\n// ---------------------------------------------------------------------------\n\nexport interface MemoryRetrievalOptions<TMem> {\n\t/** Optional Graph identity. */\n\tgraph?: GraphOptions;\n\t/** Subgraph name. Default: `\"memory-retrieval\"`. */\n\tname?: string;\n\t/** The substrate distill store. */\n\tstore: DistillBundle<TMem>;\n\t/** Optional vector index for similarity search. */\n\tvectors?: VectorIndexGraph<TMem> | null;\n\t/** Optional knowledge graph for entity-relation expansion. */\n\tkg?: KnowledgeGraph<unknown, string> | null;\n\t/** Score function (same shape as `agentMemory.score`). */\n\tscore: (mem: TMem, context: unknown) => number;\n\t/** Cost function for budget packing. */\n\tcost: (mem: TMem) => number;\n\t/** Token / cost budget. Default 2000. */\n\tbudget?: number;\n\t/** Top-K vector candidates. Default 20. */\n\ttopK?: number;\n\t/** KG expansion depth in hops. Default 1. */\n\tgraphDepth?: number;\n\t/** Hierarchical-context boost weight. Default 0. */\n\tcontextWeight?: number;\n\t/** Hierarchical-context accessor for entries. */\n\tcontextOf?: (mem: TMem) => readonly string[] | undefined;\n\t/** Optional reactive context node (passed to `score`). */\n\tcontext?: NodeInput<unknown>;\n}\n\nfunction sharedPrefixDepth(\n\tq: readonly string[] | undefined,\n\te: readonly string[] | undefined,\n): number {\n\tif (!q || !e) return 0;\n\tconst n = Math.min(q.length, e.length);\n\tlet i = 0;\n\twhile (i < n && q[i] === e[i]) i++;\n\treturn i;\n}\n\n// QA-fix: element-wise reference-equality dedup so subscribers don't wake\n// up when an identical packed array lands (runRetrieval allocates a new\n// outer array reference every call).\nconst packedEquals = <T>(a: readonly T[], b: readonly T[]): boolean => {\n\tif (a === b) return true;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n\treturn true;\n};\n\n/**\n * Graph subclass that builds the retrieval pipeline (vector + KG + budget\n * packing) over a `DistillBundle` and optional vectors / kg substrates.\n *\n * **C1 rework (2026-04-30):** retrieval is reactive-only. Each\n * `retrieveReactive(input)` call constructs its own per-input subgraph\n * mounted at `retrieve_${id}` with named nodes `context`, `result`, and\n * `projection`. Subgraphs register their own scoped disposers so teardown\n * is local to the per-call mount.\n *\n * **QA F-9 (2026-04-30):** the shared `retrieval` / `retrievalTrace`\n * state-node mirrors are dropped — they were last-writer-wins under\n * concurrent `retrieveReactive(...)` calls. Consumers must subscribe to\n * the per-call `projection` node directly. One-shot consumers use\n * `awaitSettled(retrieveReactive(input))`.\n *\n * **QA F-6 (2026-04-30):** the per-call `result` derived declares\n * `vectors.entries` / `kg.adjacencyOut` / `kg.adjacencyIn` as deps when\n * configured, so a vector upsert / KG mutation re-runs retrieval even\n * when the query / context / store-snapshot are unchanged. Resolves the\n * §28 closure-mirror gap where these `.cache` reads were undeclared.\n */\nexport class MemoryRetrievalGraph<TMem> extends Graph {\n\tprivate readonly _store: DistillBundle<TMem>;\n\tprivate readonly _vectors: VectorIndexGraph<TMem> | null;\n\tprivate readonly _kg: KnowledgeGraph<unknown, string> | null;\n\tprivate readonly _opts: MemoryRetrievalOptions<TMem>;\n\tprivate readonly _contextNode: Node<unknown>;\n\tprivate readonly _topK: number;\n\tprivate readonly _graphDepth: number;\n\tprivate readonly _budget: number;\n\tprivate readonly _contextWeight: number;\n\tprivate _retrieveSeq = 0;\n\n\tconstructor(opts: MemoryRetrievalOptions<TMem>) {\n\t\tsuper(opts.name ?? \"memory-retrieval\", opts.graph);\n\n\t\tthis._store = opts.store;\n\t\tthis._vectors = opts.vectors ?? null;\n\t\tthis._kg = opts.kg ?? null;\n\t\tthis._opts = opts;\n\t\tthis._topK = opts.topK ?? 20;\n\t\tthis._graphDepth = opts.graphDepth ?? 1;\n\t\tthis._budget = opts.budget ?? 2000;\n\t\tthis._contextWeight = opts.contextWeight ?? 0;\n\t\t// DS-13.5.C: synthesized branch (no `opts.context` supplied) registers\n\t\t// on this graph as `_context` so describe()/explain() can walk to it.\n\t\t// User-supplied branch stays unregistered — `fromAny` returns the\n\t\t// caller's owned Node, which is owned by their graph; mounting it\n\t\t// here would corrupt cross-graph ownership (mirrors MemoryWithTiers's\n\t\t// context-branch policy).\n\t\tif (opts.context) {\n\t\t\tthis._contextNode = fromAny(opts.context);\n\t\t} else {\n\t\t\tthis._contextNode = this.state<unknown>(\"_context\", null);\n\t\t}\n\t}\n\n\tprivate _runRetrieval(\n\t\tstoreMap: ReadonlyMap<string, TMem>,\n\t\tctx: unknown,\n\t\tquery: RetrievalQuery,\n\t): { packed: RetrievalEntry<TMem>[]; trace: RetrievalTrace<TMem> } {\n\t\tconst opts = this._opts;\n\t\tconst candidateMap = new Map<\n\t\t\tstring,\n\t\t\t{ value: TMem; sources: Set<\"vector\" | \"graph\" | \"store\"> }\n\t\t>();\n\n\t\tlet vectorCandidates: VectorSearchResult<TMem>[] = [];\n\t\tif (this._vectors && query.vector) {\n\t\t\t// Wave A migrated `vectorIndex` to a reactive-only read API\n\t\t\t// (`searchNode`); inline the equivalent flat-cosine snapshot scan\n\t\t\t// here since `_runRetrieval` is sync and `searchNode` is async-shaped.\n\t\t\t// `patterns/ai/memory/` is queued for its own audit per the Wave A\n\t\t\t// session doc § D.1.\n\t\t\tconst q = query.vector;\n\t\t\tconst snapshot = this._vectors.entries.cache as\n\t\t\t\t| ReadonlyMap<string, VectorRecord<TMem>>\n\t\t\t\t| undefined;\n\t\t\tif (snapshot && snapshot.size > 0 && this._topK > 0) {\n\t\t\t\tconst scored = [...snapshot.values()]\n\t\t\t\t\t.map(\n\t\t\t\t\t\t(row): VectorSearchResult<TMem> => ({\n\t\t\t\t\t\t\tid: row.id,\n\t\t\t\t\t\t\tscore: cosineSimilarity(q, row.vector),\n\t\t\t\t\t\t\t...(row.meta !== undefined ? { meta: row.meta } : {}),\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t\t.sort((a, b) => b.score - a.score)\n\t\t\t\t\t.slice(0, this._topK);\n\t\t\t\tvectorCandidates = scored;\n\t\t\t\tfor (const vc of vectorCandidates) {\n\t\t\t\t\tconst mem = storeMap.get(vc.id);\n\t\t\t\t\tif (mem) candidateMap.set(vc.id, { value: mem, sources: new Set([\"vector\"]) });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst graphExpanded: string[] = [];\n\t\tif (this._kg) {\n\t\t\t// Wave A migrated `knowledgeGraph` to a reactive-only `relatedNode`\n\t\t\t// API; inline the equivalent adjacency-snapshot scan here for the\n\t\t\t// sync expansion. `adjacencyOut` / `adjacencyIn` are kept warm by\n\t\t\t// the kg's own internal keepalive disposers, so `.cache` is always\n\t\t\t// populated post-construction.\n\t\t\tconst adjOut = this._kg.adjacencyOut.cache as\n\t\t\t\t| ReadonlyMap<string, readonly KnowledgeEdge<string>[]>\n\t\t\t\t| undefined;\n\t\t\tconst adjIn = this._kg.adjacencyIn.cache as\n\t\t\t\t| ReadonlyMap<string, readonly KnowledgeEdge<string>[]>\n\t\t\t\t| undefined;\n\t\t\tconst seedIds = [...(query.entityIds ?? []), ...[...candidateMap.keys()]];\n\t\t\tconst visited = new Set<string>();\n\t\t\tlet frontier = seedIds;\n\t\t\tfor (let depth = 0; depth < this._graphDepth; depth++) {\n\t\t\t\tconst nextFrontier: string[] = [];\n\t\t\t\tfor (const id of frontier) {\n\t\t\t\t\tif (visited.has(id)) continue;\n\t\t\t\t\tvisited.add(id);\n\t\t\t\t\tconst outEdges = adjOut?.get(id) ?? [];\n\t\t\t\t\tconst inEdges = adjIn?.get(id) ?? [];\n\t\t\t\t\tfor (const edge of outEdges) {\n\t\t\t\t\t\tconst targetId = edge.to;\n\t\t\t\t\t\tif (!visited.has(targetId)) {\n\t\t\t\t\t\t\tnextFrontier.push(targetId);\n\t\t\t\t\t\t\tconst mem = storeMap.get(targetId);\n\t\t\t\t\t\t\tif (mem) {\n\t\t\t\t\t\t\t\tconst existing = candidateMap.get(targetId);\n\t\t\t\t\t\t\t\tif (existing) existing.sources.add(\"graph\");\n\t\t\t\t\t\t\t\telse candidateMap.set(targetId, { value: mem, sources: new Set([\"graph\"]) });\n\t\t\t\t\t\t\t\tgraphExpanded.push(targetId);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Inbound edges: traverse to the `from` side. Match the\n\t\t\t\t\t// previous `kg.related(id)` semantics, which returned both\n\t\t\t\t\t// `from === id` and `to === id` matches.\n\t\t\t\t\tfor (const edge of inEdges) {\n\t\t\t\t\t\tconst targetId = edge.from;\n\t\t\t\t\t\tif (!visited.has(targetId)) {\n\t\t\t\t\t\t\tnextFrontier.push(targetId);\n\t\t\t\t\t\t\tconst mem = storeMap.get(targetId);\n\t\t\t\t\t\t\tif (mem) {\n\t\t\t\t\t\t\t\tconst existing = candidateMap.get(targetId);\n\t\t\t\t\t\t\t\tif (existing) existing.sources.add(\"graph\");\n\t\t\t\t\t\t\t\telse candidateMap.set(targetId, { value: mem, sources: new Set([\"graph\"]) });\n\t\t\t\t\t\t\t\tgraphExpanded.push(targetId);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfrontier = nextFrontier;\n\t\t\t}\n\t\t}\n\t\tfor (const [key, mem] of storeMap) {\n\t\t\tif (!candidateMap.has(key)) {\n\t\t\t\tcandidateMap.set(key, { value: mem, sources: new Set([\"store\"]) });\n\t\t\t}\n\t\t}\n\n\t\tconst qDepth = query.context?.length ?? 0;\n\t\tconst ranked: RetrievalEntry<TMem>[] = [];\n\t\tfor (const [key, { value, sources }] of candidateMap) {\n\t\t\tconst entryContext = opts.contextOf ? opts.contextOf(value) : undefined;\n\t\t\tlet score = opts.score(value, ctx);\n\t\t\tif (this._contextWeight > 0 && qDepth > 0) {\n\t\t\t\tconst shared = sharedPrefixDepth(query.context, entryContext);\n\t\t\t\tif (shared > 0) score = score * (1 + (this._contextWeight * shared) / qDepth);\n\t\t\t}\n\t\t\tconst entry: RetrievalEntry<TMem> = entryContext\n\t\t\t\t? { key, value, score, sources: [...sources], context: entryContext }\n\t\t\t\t: { key, value, score, sources: [...sources] };\n\t\t\tranked.push(entry);\n\t\t}\n\t\tranked.sort((a, b) => b.score - a.score);\n\n\t\tconst packed: RetrievalEntry<TMem>[] = [];\n\t\tlet usedBudget = 0;\n\t\tfor (const entry of ranked) {\n\t\t\tconst c = opts.cost(entry.value);\n\t\t\tif (usedBudget + c > this._budget && packed.length > 0) break;\n\t\t\tpacked.push(entry);\n\t\t\tusedBudget += c;\n\t\t}\n\n\t\treturn { packed, trace: { vectorCandidates, graphExpanded, ranked, packed } };\n\t}\n\n\t/**\n\t * Reactive consumer API — chain into the graph.\n\t *\n\t * Each call constructs its own per-input subgraph mounted at\n\t * `retrieve_${id}` (auto-incrementing within this MemoryRetrievalGraph\n\t * instance) with named nodes:\n\t *\n\t * - `context` — `fromAny(queryInput)` projection (so the input node is\n\t * visible to `describe()` even when callers pass a raw value).\n\t * - `result` — pure derived `{ packed, trace }`.\n\t * - `projection` — the packed-array node returned to the caller.\n\t *\n\t * `result` declares the substrate's `store.entries`, the optional\n\t * `context` Node, the local `context` projection, and (when configured)\n\t * `vectors.entries` / `kg.adjacencyOut` / `kg.adjacencyIn` as deps —\n\t * so vector upserts and KG mutations re-trigger retrieval even when\n\t * the input is unchanged.\n\t *\n\t * **Lifecycle contract (DS-13.5.C, 2026-05-01).** The per-call subgraph\n\t * stays mounted while the returned `projection` has at least one\n\t * subscriber. When the last subscriber unsubscribes, projection's\n\t * `deactivate` cleanup hook fires (canonical \"last unsubscribe\" signal\n\t * via the existing `NodeFnCleanup.onDeactivation` protocol), which calls\n\t * `parent.remove(retrieve_${id})` and tears the per-call topology\n\t * down via TEARDOWN cascade (post-DS-13.5.A Q16, COMPLETE auto-precedes).\n\t *\n\t * **Single-shot lifecycle.** This auto-unmount is keyed to the FIRST\n\t * last-unsubscribe event — projection is non-resubscribable from the\n\t * caller's perspective. Callers who need to subscribe / unsubscribe /\n\t * re-subscribe should hold a long-lived subscription externally (e.g.\n\t * `keepalive(projection)`) or call `retrieveReactive(...)` again to\n\t * mount a fresh per-call subgraph.\n\t *\n\t * **Caller obligation.** Either subscribe to `projection` (and\n\t * eventually unsubscribe to trigger cleanup) OR drop the returned\n\t * reference without subscribing — in the no-subscribe case the\n\t * subgraph is dormant (no compute fires) and a parent `destroy()`\n\t * cascade reclaims it. Holding `projection` without subscribing AND\n\t * without ever destroying the parent is the leak case the JSDoc above\n\t * the C1 rework covers.\n\t *\n\t * One-shot callers use `awaitSettled(retrieveReactive(input))`.\n\t */\n\tretrieveReactive(\n\t\tqueryInput: NodeInput<RetrievalQuery | null>,\n\t): Node<ReadonlyArray<RetrievalEntry<TMem>>> {\n\t\tconst id = ++this._retrieveSeq;\n\t\tconst segment = `retrieve_${id}`;\n\n\t\t// Per-call subgraph — owns the wiring, the keepalive, and the\n\t\t// teardown. Mounted on `this` so it's visible in `describe()` and\n\t\t// reachable via `${parent}::retrieve_${id}::result` etc.\n\t\tconst sub = new Graph(segment);\n\n\t\t// Wrap the input as a local pass-through so the per-call subgraph\n\t\t// shows the query source in `describe()` regardless of where the\n\t\t// caller's node lives in the broader topology. `fromAny` returns\n\t\t// the original Node when given a Node, otherwise wraps a\n\t\t// value/promise into a producer.\n\t\t//\n\t\t// DS-13.5.C: registered via `sub.derived(...)` (Graph helper) for\n\t\t// equals plumbing + automatic registration; replaces the prior raw\n\t\t// `node([inputNode], fn) + sub.add(...)` shape.\n\t\tconst inputNode = fromAny(queryInput);\n\t\tconst localContext = sub.derived<RetrievalQuery | null>(\n\t\t\t\"context\",\n\t\t\t[inputNode],\n\t\t\t(batchData, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\treturn [(data[0] as RetrievalQuery | null) ?? null];\n\t\t\t},\n\t\t\t{\n\t\t\t\tmeta: aiMeta(\"retrieval_query_input\"),\n\t\t\t\tinitial: null,\n\t\t\t},\n\t\t);\n\n\t\t// /qa F-6 (2026-04-30): declare vectors / kg substrate Node refs as\n\t\t// deps so vector upserts / KG mutations re-trigger retrieval even\n\t\t// when query / context / store snapshots are unchanged. The\n\t\t// `_runRetrieval` body reads `.cache` from these substrates; before\n\t\t// this fix those reads were undeclared §28 closure-mirrors.\n\t\tconst resultDeps: (string | Node<unknown>)[] = [\n\t\t\tthis._store.store.entries,\n\t\t\tthis._contextNode,\n\t\t\tlocalContext,\n\t\t];\n\t\tif (this._vectors) resultDeps.push(this._vectors.entries as Node<unknown>);\n\t\tif (this._kg) {\n\t\t\tresultDeps.push(this._kg.adjacencyOut as Node<unknown>);\n\t\t\tresultDeps.push(this._kg.adjacencyIn as Node<unknown>);\n\t\t}\n\n\t\t// DS-13.5.C: migrated to `sub.derived(...)` for equals plumbing +\n\t\t// automatic registration.\n\t\tconst result = sub.derived<{\n\t\t\tpacked: ReadonlyArray<RetrievalEntry<TMem>>;\n\t\t\ttrace: RetrievalTrace<TMem> | null;\n\t\t}>(\n\t\t\t\"result\",\n\t\t\tresultDeps,\n\t\t\t(batchData, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst query = data[2];\n\t\t\t\tif (query == null) {\n\t\t\t\t\treturn [{ packed: [] as ReadonlyArray<RetrievalEntry<TMem>>, trace: null }];\n\t\t\t\t}\n\t\t\t\tconst storeMap =\n\t\t\t\t\t(data[0] as ReadonlyMap<string, TMem> | undefined) ?? new Map<string, TMem>();\n\t\t\t\tconst { packed, trace } = this._runRetrieval(storeMap, data[1], query as RetrievalQuery);\n\t\t\t\treturn [{ packed, trace }];\n\t\t\t},\n\t\t\t{\n\t\t\t\tmeta: aiMeta(\"retrieval_reactive_result\"),\n\t\t\t\tinitial: { packed: [] as ReadonlyArray<RetrievalEntry<TMem>>, trace: null },\n\t\t\t},\n\t\t);\n\n\t\t// DS-13.5.C: projection stays as raw `node()` (not `sub.derived`)\n\t\t// because the keepalive disposer is wired via the fn's\n\t\t// `NodeFnCleanup.onDeactivation` hook — projection's cleanup-on-last-\n\t\t// unsubscribe is what drives `parent.remove(segment)`. The Graph\n\t\t// `.derived()` helper drops the cleanup return, so the raw form\n\t\t// is required here. `equals: packedEquals` is preserved verbatim.\n\t\tconst projection = node<ReadonlyArray<RetrievalEntry<TMem>>>(\n\t\t\t[result],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tactions.emit((data[0] as { packed: ReadonlyArray<RetrievalEntry<TMem>> }).packed);\n\t\t\t\treturn {\n\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\t// Auto-unmount on last unsubscribe (DS-13.5.C).\n\t\t\t\t\t\t// Idempotent: try/catch covers the case where the\n\t\t\t\t\t\t// segment was already removed (e.g. parent destroy\n\t\t\t\t\t\t// cascade ran first, or the caller called remove()\n\t\t\t\t\t\t// manually).\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tthis.remove(segment);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t/* best-effort cleanup */\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"projection\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"retrieval_reactive\"),\n\t\t\t\tinitial: [] as ReadonlyArray<RetrievalEntry<TMem>>,\n\t\t\t\tequals: packedEquals,\n\t\t\t},\n\t\t);\n\t\tsub.add(projection, { name: \"projection\" });\n\n\t\tthis.mount(segment, sub);\n\t\treturn projection;\n\t}\n}\n\n/**\n * Build the retrieval pipeline (vector + KG + budget packing) over a\n * `DistillBundle` and optional `vectors` / `kg` substrates. Returns a\n * `MemoryRetrievalGraph` exposing `retrieval` / `retrievalTrace` reactive\n * state and the `retrieveReactive(input)` consumer method.\n */\nexport function memoryRetrieval<TMem>(\n\topts: MemoryRetrievalOptions<TMem>,\n): MemoryRetrievalGraph<TMem> {\n\treturn new MemoryRetrievalGraph<TMem>(opts);\n}\n","/**\n * Budget-constrained reactive memory composition (roadmap §3.2b).\n *\n * Moved to base/composition/distill.ts during cleave A2.\n */\n\nimport { batch, factoryTag, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport {\n\tfromAny,\n\ttype NodeInput,\n\ttype ReactiveMapBundle,\n\ttype ReactiveMapOptions,\n\treactiveMap,\n\tswitchMap,\n\twithLatestFrom,\n} from \"@graphrefly/pure-ts/extra\";\nimport { forEach } from \"../sources/async.js\";\n\nfunction isNodeLike<T>(value: unknown): value is Node<T> {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"cache\" in (value as Node<T>) &&\n\t\ttypeof (value as Node<T>).subscribe === \"function\"\n\t);\n}\n\nexport type Extraction<TMem> = {\n\tupsert: Array<{ key: string; value: TMem }>;\n\tremove?: string[];\n};\n\nexport type DistillOptions<TMem> = {\n\tscore: (mem: TMem, context: unknown) => number;\n\tcost: (mem: TMem) => number;\n\tbudget?: number;\n\tevict?: (key: string, mem: TMem) => boolean | Node<boolean>;\n\tconsolidate?: (entries: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>>;\n\tconsolidateTrigger?: NodeInput<unknown>;\n\tcontext?: NodeInput<unknown>;\n\tmapOptions?: ReactiveMapOptions<string, TMem>;\n};\n\nexport type DistillBundle<TMem> = {\n\tstore: ReactiveMapBundle<string, TMem>;\n\tcompact: Node<Array<{ key: string; value: TMem; score: number }>>;\n\tsize: Node<number>;\n};\n\nfunction keepalive(node: Node): void {\n\tnode.subscribe(() => undefined);\n}\n\n/**\n * Defensive snapshot → ReadonlyMap coercion (D2 /qa lock, Tier 9.1).\n *\n * `ReactiveMapBundle.entries` always emits a real `Map` on the live emit\n * path. The non-Map case happens on snapshot **restore**: the default\n * `JsonGraphCodec` serializes a `Map` to `null`/`{}`/`[]` depending on the\n * codec configuration, and `Graph.restore` writes that decoded value back\n * to the cache. A naive `(snapshot as ReadonlyMap) ?? new Map()` would\n * pass a plain object through and then `.entries()` / `.size` access would\n * silently yield wrong results (or throw). The runtime `instanceof Map`\n * check below restores the safety net the previous `mapFromSnapshot` helper\n * provided before its initial deletion in Tier 10.1.\n */\nfunction mapFromSnapshot<TMem>(snapshot: unknown): ReadonlyMap<string, TMem> {\n\tif (snapshot instanceof Map) return snapshot as ReadonlyMap<string, TMem>;\n\treturn new Map<string, TMem>();\n}\n\nfunction applyExtraction<TMem>(\n\tstore: ReactiveMapBundle<string, TMem>,\n\textraction: Extraction<TMem>,\n): void {\n\tif (!Array.isArray(extraction.upsert)) {\n\t\tthrow new TypeError(\"distill extraction requires upsert: Array<{ key, value }>\");\n\t}\n\tbatch(() => {\n\t\tfor (const { key, value } of extraction.upsert) {\n\t\t\tstore.set(key, value);\n\t\t}\n\t\tfor (const key of extraction.remove ?? []) {\n\t\t\tstore.delete(key);\n\t\t}\n\t});\n}\n\n/**\n * Budget-constrained reactive memory composition.\n *\n * **Tier 1.5.4 (Session A.5 lock, 2026-04-27):** `extractFn` receives the\n * source and existing-store as `Node`s. Distill calls `extractFn` ONCE at\n * wiring time and consumes the returned stream of extractions. The user\n * controls reactive composition — wrap with `switchMap` for cancel-on-new-input,\n * `mergeMap` for parallel, `derived` for sync transforms. See COMPOSITION-GUIDE\n * §40 for the recipe.\n */\nexport function distill<TRaw, TMem>(\n\tsource: NodeInput<TRaw>,\n\textractFn: (\n\t\traw: Node<TRaw>,\n\t\texisting: Node<ReadonlyMap<string, TMem>>,\n\t) => NodeInput<Extraction<TMem>>,\n\topts: DistillOptions<TMem>,\n): DistillBundle<TMem> {\n\tconst sourceNode = fromAny(source);\n\tconst store = reactiveMap<string, TMem>(opts.mapOptions ?? {});\n\tconst budget = opts.budget ?? 2000;\n\tconst hasContext = opts.context !== undefined && opts.context !== null;\n\tconst contextNode = hasContext ? fromAny(opts.context) : node<unknown>([], { initial: null });\n\n\t// `latestStore` (formerly a §28 closure-mirror) is no longer needed —\n\t// Phase 10.5 (`withLatestFrom` flipped to `partial: false`) fixed the\n\t// W1 initial-pair drop. `consolidate` now uses\n\t// `withLatestFrom(trigger, store.entries)` below to pair each trigger\n\t// with the latest store snapshot via a real reactive edge (visible in\n\t// `describe()`). The `mapFromSnapshot` transform runs inside the\n\t// switchMap fn body.\n\n\t// Tier 1.5.4: one-shot wire. User's `extractFn` returns the reactive\n\t// extraction stream — distill just `forEach`s and applies. No internal\n\t// switchMap; user picks the cancellation / queueing semantics.\n\tconst extractionStream = fromAny(\n\t\textractFn(sourceNode, store.entries as Node<ReadonlyMap<string, TMem>>),\n\t);\n\tforEach(extractionStream, (extraction) => {\n\t\tapplyExtraction(store, extraction);\n\t});\n\n\tif (opts.evict) {\n\t\t// Track active verdict-node subscriptions so we can react to Node<boolean> changes.\n\t\tconst verdictUnsubs = new Map<string, () => void>();\n\n\t\tconst evictionKeys = node<string[]>(\n\t\t\t[store.entries],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst batch0 = batchData[0];\n\t\t\t\tconst snapshot = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0];\n\t\t\t\tconst out: string[] = [];\n\t\t\t\tconst entries = mapFromSnapshot<TMem>(snapshot);\n\t\t\t\t// Clean up verdict subscriptions for removed keys.\n\t\t\t\tfor (const key of verdictUnsubs.keys()) {\n\t\t\t\t\tif (!entries.has(key)) {\n\t\t\t\t\t\tverdictUnsubs.get(key)!();\n\t\t\t\t\t\tverdictUnsubs.delete(key);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (const [key, mem] of entries) {\n\t\t\t\t\tconst verdict = opts.evict!(key, mem);\n\t\t\t\t\tif (isNodeLike<boolean>(verdict)) {\n\t\t\t\t\t\t// Subscribe if not already — push-on-subscribe fires with\n\t\t\t\t\t\t// the verdict's current value on first subscribe, so an\n\t\t\t\t\t\t// already-true verdict deletes via the callback without\n\t\t\t\t\t\t// needing a `verdict.cache` read (closes P3 audit #3).\n\t\t\t\t\t\t// Future transitions to `true` flow through the same path.\n\t\t\t\t\t\tif (!verdictUnsubs.has(key)) {\n\t\t\t\t\t\t\tconst unsub = forEach(verdict, (val) => {\n\t\t\t\t\t\t\t\tif (val === true && store.has(key)) {\n\t\t\t\t\t\t\t\t\tstore.delete(key);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tverdictUnsubs.set(key, unsub);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (typeof verdict === \"boolean\") {\n\t\t\t\t\t\tif (verdict) out.push(key);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tthrow new TypeError(\"distill evict() must return boolean or Node<boolean>\");\n\t\t\t\t}\n\t\t\t\tactions.emit(out);\n\t\t\t},\n\t\t\t{ describeKind: \"derived\" },\n\t\t);\n\t\tforEach(evictionKeys, (keys) => {\n\t\t\tfor (const key of keys) store.delete(key);\n\t\t});\n\t}\n\n\tconst hasConsolidateTrigger =\n\t\topts.consolidateTrigger !== undefined && opts.consolidateTrigger !== null;\n\tif (opts.consolidate && hasConsolidateTrigger) {\n\t\tconst consolidateTriggerNode = fromAny(opts.consolidateTrigger);\n\t\tconst consolidatePaired = withLatestFrom(\n\t\t\tconsolidateTriggerNode,\n\t\t\tstore.entries as Node<unknown>,\n\t\t);\n\t\tconst consolidationStream = switchMap(consolidatePaired, ([, entries]) =>\n\t\t\topts.consolidate!(mapFromSnapshot<TMem>(entries)),\n\t\t);\n\t\tforEach(consolidationStream, (extraction) => {\n\t\t\tapplyExtraction(store, extraction);\n\t\t});\n\t}\n\n\tconst compact = node<Array<{ key: string; value: TMem; score: number }>>(\n\t\t[store.entries, contextNode],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0];\n\t\t\tconst context = data[1];\n\t\t\tconst map = mapFromSnapshot<TMem>(snapshot);\n\t\t\tconst entries = [...map.entries()].map(([key, value]) => ({\n\t\t\t\tkey,\n\t\t\t\tvalue,\n\t\t\t\tscore: opts.score(value, context),\n\t\t\t\tcost: opts.cost(value),\n\t\t\t}));\n\t\t\tentries.sort((a, b) => b.score - a.score);\n\n\t\t\tconst packed: Array<{ key: string; value: TMem; score: number }> = [];\n\t\t\tlet remaining = budget;\n\t\t\tfor (const item of entries) {\n\t\t\t\tif (item.cost <= remaining) {\n\t\t\t\t\tpacked.push({ key: item.key, value: item.value, score: item.score });\n\t\t\t\t\tremaining -= item.cost;\n\t\t\t\t}\n\t\t\t}\n\t\t\tactions.emit(packed);\n\t\t},\n\t\t{ describeKind: \"derived\", meta: { ...factoryTag(\"distill\", { budget }) } },\n\t);\n\n\tconst size = node<number>(\n\t\t[store.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst batch0 = batchData[0];\n\t\t\tconst snapshot = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0];\n\t\t\tactions.emit(mapFromSnapshot<TMem>(snapshot).size);\n\t\t},\n\t\t{ describeKind: \"derived\" },\n\t);\n\tkeepalive(compact);\n\tkeepalive(size);\n\n\treturn { store, compact, size };\n}\n","/**\n * Async sources, sinks, and multicast — presentation layer.\n *\n * `fromPromise`, `fromAsyncIter`, `fromAny` are substrate primitives; they are\n * re-exported here from `@graphrefly/pure-ts` for ergonomic single-import use.\n * This file owns the presentation-only async utilities: `defer`, `forEach`,\n * `toArray`, `share`, `replay`, `cached`, `shareReplay`.\n *\n * `singleFromAny` and `singleNodeFromAny` (keyed singleflight) live in\n * `base/composition/single-from-any.ts`.\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tERROR,\n\ttype Node,\n\ttype NodeOptions,\n\tnode,\n\tRESOLVED,\n\tSTART,\n} from \"@graphrefly/pure-ts/core\";\nimport { type AsyncSourceOpts, type NodeInput, sourceOpts } from \"@graphrefly/pure-ts/extra\";\n\n/** Options for presentation-layer async operators: NodeOptions without `describeKind`. */\ntype ExtraOpts = Omit<NodeOptions, \"describeKind\">;\n\n// Import fromAny from substrate — used internally by defer. The three async\n// substrate sources (fromAny, fromAsyncIter, fromPromise) are already\n// re-exported from @graphrefly/pure-ts; do NOT re-export here to avoid\n// duplicate-export conflicts at the root barrel level.\nimport { fromAny } from \"@graphrefly/pure-ts/extra\";\n\n/**\n * Lazily constructs a {@link Node} from a thunk that runs at **activation\n * time** (first subscriber after a teardown to zero sinks), not factory time.\n *\n * **Resubscribable by default.** Diverges from `fromPromise` / `fromIter` /\n * `fromAsyncIter` (which are single-shot — second subscriber sees the cached\n * terminal value). `defer`'s contract matches RxJS `defer`: every fresh\n * activation cycle re-runs the thunk. To opt out and get one-shot semantics,\n * pass `{ resubscribable: false }`.\n *\n * **Sharing across overlapping subscribers.** The thunk only re-runs on a\n * fresh activation cycle (zero → one sink). Overlapping subscribers share\n * the single activation; the thunk does NOT re-run for each subscriber. If\n * the thunk returns an existing `Node`, that Node is shared across activations\n * — `defer` will subscribe to it on each activation but does not isolate state\n * across subscribers. For per-subscriber isolation, the thunk must construct\n * a fresh source (`state(...)`, `fromPromise(fetch(...))`, etc.) on each call.\n *\n * **Use cases:**\n * - Lazy upstream construction (avoid eager evaluation of expensive factories\n * at module load — the thunk runs only when something subscribes).\n * - Per-activation resource construction (open a connection / file handle on\n * subscribe, when paired with full teardown between sessions).\n * - Bridging non-Node inputs (Promise, AsyncIterable, Iterable, scalar) into\n * the graph behind a lazy boundary.\n *\n * The thunk's return value is bridged via {@link fromAny}. Errors thrown by\n * the thunk surface as a single `[[ERROR, err]]` on the output (with `err`\n * coerced to a non-`undefined` value to satisfy spec §1.3 — bare `throw` and\n * `throw undefined` are wrapped in a `defer: thunk threw undefined` Error).\n *\n * Upstream messages are forwarded transparently (DIRTY / DATA / RESOLVED /\n * COMPLETE / ERROR / INVALIDATE / PAUSE / RESUME / TEARDOWN), preserving\n * batch boundaries. The producer's own `START` handshake is delivered to\n * subscribers automatically; the upstream's `START` is filtered.\n *\n * @param thunk - Called on each activation; returns the upstream input.\n * @param opts - Forwarded to `fromAny` (e.g. `signal` for async inputs).\n * `signal` is only consumed by `fromAny` for async input shapes (Promise,\n * AsyncIterable); it does NOT abort a Node-input or scalar-input defer.\n * @returns `Node<T>` — lazy upstream-on-activation.\n *\n * @example\n * ```ts\n * import { defer } from \"@graphrefly/graphrefly-ts\";\n *\n * // Lazy fetch — runs on the first activation, NOT at factory time.\n * // Each fresh activation cycle (after teardown) re-runs the thunk →\n * // a new fetch. Overlapping subscribers share the single activation.\n * const live = defer(() => fetch(\"/api/feed\").then((r) => r.json()));\n * ```\n *\n * @category extra\n */\nexport function defer<T>(thunk: () => NodeInput<T>, opts?: AsyncSourceOpts): Node<T> {\n\t// A4: strip `signal` before forwarding to NodeOptions — sibling sources\n\t// (fromTimer / fromPromise / fromAsyncIter) destructure first; signal\n\t// continues to flow into fromAny(input, opts) for async input shapes.\n\tconst { signal: _sig, ...nodeOpts } = (opts ?? {}) as AsyncSourceOpts;\n\tconst sOpts = sourceOpts<T>(nodeOpts);\n\tconst merged = sOpts.resubscribable === undefined ? { ...sOpts, resubscribable: true } : sOpts;\n\treturn node<T>((_data, a) => {\n\t\tlet unsub: (() => void) | undefined;\n\t\tlet stopped = false;\n\t\ttry {\n\t\t\tconst input = thunk();\n\t\t\t// `iter: true` preserves defer's RxJS-aligned per-element\n\t\t\t// streaming for sync iterable thunk returns (post DS-13.5\n\t\t\t// fromAny default flip; defer's documented contract is\n\t\t\t// \"forwards iterable values\" per-element).\n\t\t\tconst src = fromAny(input, { ...opts, iter: true });\n\t\t\tunsub = src.subscribe((msgs) => {\n\t\t\t\tif (stopped) return;\n\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\tconst t = m[0];\n\t\t\t\t\tif (t === START) continue; // producer's own START is delivered separately\n\t\t\t\t\tif (t === DATA) {\n\t\t\t\t\t\ta.emit(m[1] as T);\n\t\t\t\t\t} else if (t === COMPLETE) {\n\t\t\t\t\t\tstopped = true;\n\t\t\t\t\t\ta.down([[COMPLETE]]);\n\t\t\t\t\t\tbreak; // A2: don't forward post-terminal messages in the same batch\n\t\t\t\t\t} else if (t === ERROR) {\n\t\t\t\t\t\tstopped = true;\n\t\t\t\t\t\ta.down([[ERROR, m[1]]]);\n\t\t\t\t\t\tbreak; // A2\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Forward DIRTY / RESOLVED / INVALIDATE / PAUSE / RESUME /\n\t\t\t\t\t\t// TEARDOWN, plus any unknown types (spec §1.3.6 forward-compat).\n\t\t\t\t\t\ta.down([m]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (err) {\n\t\t\t// A5: spec §1.3 — ERROR payload must not be undefined. Wrap a\n\t\t\t// `throw` or `throw undefined` so dispatch doesn't reject the emit.\n\t\t\tconst safe = err === undefined ? new Error(\"defer: thunk threw undefined\") : err;\n\t\t\ta.down([[ERROR, safe]]);\n\t\t}\n\t\treturn () => {\n\t\t\tstopped = true;\n\t\t\tunsub?.();\n\t\t};\n\t}, merged);\n}\n\n/**\n * Subscribes immediately and runs `fn` for each upstream `DATA`; returns unsubscribe.\n *\n * @param source - Upstream node.\n * @param fn - Side effect per value.\n * @param opts - Effect node options.\n * @returns Unsubscribe function (idempotent).\n *\n * @example\n * ```ts\n * import { forEach, state } from \"@graphrefly/graphrefly-ts\";\n *\n * const u = forEach(state(1), (v) => console.log(v));\n * u();\n * ```\n *\n * @category extra\n */\nexport function forEach<T>(source: Node<T>, fn: (value: T) => void, opts?: ExtraOpts): () => void {\n\tconst inner = node(\n\t\t[source as Node],\n\t\t(data, _actions) => {\n\t\t\tconst batch0 = data[0];\n\t\t\tif (batch0 != null && batch0.length > 0) {\n\t\t\t\tfor (const v of batch0) fn(v as T);\n\t\t\t}\n\t\t},\n\t\t{ describeKind: \"effect\", ...opts } as NodeOptions,\n\t);\n\treturn inner.subscribe(() => {});\n}\n\n/**\n * Buffers every `DATA`; on upstream `COMPLETE` emits one `DATA` with the full array then `COMPLETE`.\n *\n * @param source - Upstream node.\n * @param opts - Optional node options (derived describe kind).\n * @returns `Node<T[]>` — single array emission before completion.\n *\n * @example\n * ```ts\n * import { of, toArray } from \"@graphrefly/graphrefly-ts\";\n *\n * toArray(of(1, 2, 3));\n * ```\n *\n * @category extra\n */\nexport function toArray<T>(source: Node<T>, opts?: ExtraOpts): Node<T[]> {\n\t// Lock 6.D (Phase 13.6.B): clear the accumulator buffer on\n\t// deactivation so a resubscribable toArray restarts with an empty\n\t// array on the next cycle — pre-flip this came for free via\n\t// `_deactivate`'s store wipe.\n\tlet cleanup: { onDeactivation: () => void } | undefined;\n\treturn node<T[]>(\n\t\t[source as Node],\n\t\t(data, actions, ctx) => {\n\t\t\tif (cleanup === undefined) {\n\t\t\t\tconst store = ctx.store;\n\t\t\t\tcleanup = {\n\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\tdelete store.buf;\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (!ctx.store.buf) ctx.store.buf = [];\n\t\t\tconst buf = ctx.store.buf as T[];\n\t\t\t// Accumulate DATA first — must happen before the COMPLETE check so\n\t\t\t// that a same-wave DATA+COMPLETE batch (e.g. fromTimer one-shot,\n\t\t\t// fromIter last item) is included in the emitted array.\n\t\t\tconst batch0 = data[0];\n\t\t\tif (batch0 != null && batch0.length > 0) {\n\t\t\t\tfor (const v of batch0) buf.push(v as T);\n\t\t\t}\n\t\t\t// COMPLETE: emit accumulated array then complete.\n\t\t\t// ERROR: autoError propagates; do NOT emit the partial buffer.\n\t\t\tif (ctx.terminalDeps[0] === true) {\n\t\t\t\tactions.emit([...buf]);\n\t\t\t\tactions.down([[COMPLETE]]);\n\t\t\t\treturn cleanup;\n\t\t\t}\n\t\t\t// RESOLVED wave: propagate RESOLVED. Covers first-wave case; after first\n\t\t\t// call the pre-fn skip handles this automatically.\n\t\t\tif (batch0 == null || batch0.length === 0) {\n\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t}\n\t\t\treturn cleanup;\n\t\t},\n\t\t{\n\t\t\tdescribeKind: \"derived\",\n\t\t\tcompleteWhenDepsComplete: false,\n\t\t\t...opts,\n\t\t} as NodeOptions<T[]>,\n\t);\n}\n\n/**\n * Multicasts upstream: one subscription to `source` while this wrapper has subscribers (via {@link producer}).\n *\n * @param source - Upstream node to share.\n * @param opts - Producer options; `initial` seeds from `source.cache` when set by factory.\n * @returns `Node<T>` — hot ref-counted bridge.\n *\n * @example\n * ```ts\n * import { share, state } from \"@graphrefly/graphrefly-ts\";\n *\n * share(state(0));\n * ```\n *\n * @category extra\n */\nexport function share<T>(source: Node<T>, opts?: ExtraOpts): Node<T> {\n\treturn node<T>(\n\t\t(_data, a) =>\n\t\t\tsource.subscribe((msgs) => {\n\t\t\t\ta.down(msgs);\n\t\t\t}),\n\t\t{ ...sourceOpts<T>(opts), initial: source.cache },\n\t);\n}\n\n/**\n * Like {@link share} with a bounded replay buffer: new subscribers receive the last `bufferSize`\n * `DATA` payloads (as separate batches) before live updates.\n *\n * @param source - Upstream node.\n * @param bufferSize - Maximum past values to replay (≥ 1).\n * @param opts - Producer options.\n * @returns `Node<T>` — multicast with replay on subscribe.\n *\n * @example\n * ```ts\n * import { replay, state } from \"@graphrefly/graphrefly-ts\";\n *\n * replay(state(0), 3);\n * ```\n *\n * @category extra\n */\nexport function replay<T>(source: Node<T>, bufferSize: number, opts?: ExtraOpts): Node<T> {\n\tif (bufferSize < 1) throw new RangeError(\"replay expects bufferSize >= 1\");\n\t// Spec §2.5 / Lock 6.G: the built-in `replayBuffer` NodeOption retains the\n\t// last-N outgoing DATA and `defaultOnSubscribe` delivers them to a late\n\t// subscriber INSTEAD of the cache-DATA push — so there is no double-deliver\n\t// of the most-recent value. Supersedes the old `wrapSubscribeHook` +\n\t// manual-buffer pattern (which flushed the buffer AND then push-on-\n\t// subscribed the cache, double-delivering the last value).\n\treturn node<T>(\n\t\t(_data, a) =>\n\t\t\tsource.subscribe((msgs) => {\n\t\t\t\ta.down(msgs);\n\t\t\t}),\n\t\t{ ...sourceOpts<T>(opts), initial: source.cache, replayBuffer: bufferSize },\n\t);\n}\n\n/**\n * {@link replay} with `bufferSize === 1` — replays the latest `DATA` to new subscribers.\n *\n * @param source - Upstream node.\n * @param opts - Producer options.\n * @returns `Node<T>` — share + last-value replay.\n *\n * @example\n * ```ts\n * import { cached, state } from \"@graphrefly/graphrefly-ts\";\n *\n * cached(state(0));\n * ```\n *\n * @category extra\n */\nexport function cached<T>(source: Node<T>, opts?: ExtraOpts): Node<T> {\n\treturn replay(source, 1, opts);\n}\n\n// ——————————————————————————————————————————————————————————————\n// RxJS-compatible aliases\n// ——————————————————————————————————————————————————————————————\n\n/**\n * RxJS-named alias for {@link replay} — multicast with a replay buffer of size `bufferSize`.\n *\n * @param source - Upstream node.\n * @param bufferSize - Replay depth (≥ 1).\n * @param opts - Producer options.\n * @returns Same behavior as `replay`.\n *\n * @example\n * ```ts\n * import { shareReplay, state } from \"@graphrefly/graphrefly-ts\";\n *\n * shareReplay(state(0), 5);\n * ```\n *\n * @category extra\n */\nexport const shareReplay = replay;\n","/**\n * Pure exponential-decay utility (Tier 2.2 promotion from `patterns/memory/`).\n *\n * Used by `collection`, `agentMemory`, harness `strategy.ts`, and any\n * downstream consumer that needs decay-with-floor scoring. Promoted to\n * `extra/utils/` because the math has zero domain semantics and is reusable\n * by non-memory primitives (e.g. routing weight decay, retry-attempt aging).\n *\n * @module\n */\n\n/**\n * Default exponential-decay rate corresponding to a 7-day half-life.\n *\n * `Math.LN2 / (7 × 86_400)` ≈ `1.146e-6`. Imported by memory tiers + any\n * consumer that wants the same default cadence as `agentMemory`'s active\n * tier. Tier 4.4 (Wave AM Unit 1) — promoted from\n * `patterns/ai/memory/tiers.ts` so non-memory consumers can share the\n * canonical default without reaching across domains.\n */\nexport const DEFAULT_DECAY_RATE = Math.LN2 / (7 * 86_400);\n\n/**\n * Exponential decay with floor: `score = max(minScore, baseScore * exp(-ratePerSecond * ageSeconds))`.\n *\n * Tolerant fallbacks (deliberate for use inside reactive derived fns):\n * - non-finite `baseScore` → `minScore`\n * - non-positive `ageSeconds` (incl. clock skew) → `max(minScore, baseScore)` (no decay)\n * - non-positive `ratePerSecond` → `max(minScore, baseScore)` (no decay; rate=0 disables)\n *\n * Underflow boundary: `Math.exp(-745) === 0`. For very long ages × rates the\n * result clamps to `minScore`; if you need slow decay over years, choose a\n * smaller `ratePerSecond` rather than relying on graceful underflow.\n *\n * Half-life conversion: `ratePerSecond = Math.LN2 / halfLifeSeconds`.\n */\nexport function decay(\n\tbaseScore: number,\n\tageSeconds: number,\n\tratePerSecond: number,\n\tminScore = 0,\n): number {\n\tif (!Number.isFinite(baseScore)) return minScore;\n\tif (!Number.isFinite(ageSeconds) || ageSeconds <= 0) return Math.max(minScore, baseScore);\n\tif (!Number.isFinite(ratePerSecond) || ratePerSecond <= 0) return Math.max(minScore, baseScore);\n\tconst decayed = baseScore * Math.exp(-ratePerSecond * ageSeconds);\n\treturn Math.max(minScore, decayed);\n}\n","/**\n * Memory patterns (roadmap §4.3) — public-face Phase-4 primitives audited under\n * `archive/docs/SESSION-public-face-blocks-review.md` (Wave A, locked 2026-04-25).\n *\n * Three primitives (the pure `decay` helper was promoted to `extra/utils/decay.ts`\n * per Tier 2.2 and is no longer re-exported here; `lightCollection` was folded\n * into `collection({ranked:false})` per Tier 2.3 and is no longer a separate\n * factory):\n * - {@link collection} / {@link CollectionGraph} — keyed memory store with\n * optional decay-aware ranking. Pass `{ ranked: false }` for the previous\n * `lightCollection` shape (Map + LRU + audit, no scoring).\n * - {@link vectorIndex} / {@link VectorIndexGraph} — reactive vector store with\n * optional HNSW backend, retention, and reactive {@link VectorIndexGraph.searchNode}.\n * - {@link knowledgeGraph} / {@link KnowledgeGraph} — entities + typed edges with\n * symmetric adjacency indexes and reactive {@link KnowledgeGraph.relatedNode}.\n *\n * **No imperative reads.** Per the API-style policy locked 2026-04-25, public-face\n * primitives expose reactive reads only — `itemNode` / `hasNode` / `searchNode` /\n * `relatedNode`. One-shot snapshots use `node.cache` after `awaitSettled`, or\n * `firstValueFrom(node)`.\n *\n * **Audit logs.** Every imperative mutation (`upsert / remove / clear / link /\n * unlink / rescore / reindex`) is wrapped via {@link mutate} and appends a\n * typed record to a public `events` log on the bundle / graph.\n *\n * @module\n */\n\nimport { monotonicNs, type Node, NodeImpl, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport type { ReactiveLogBundle } from \"@graphrefly/pure-ts/extra\";\nimport { fromTimer, keepalive, reactiveMap } from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport {\n\ttype BaseAuditRecord,\n\tbumpCursor,\n\tcreateAuditLog,\n\tmutate,\n\tregisterCursor,\n} from \"../../base/mutation/index.js\";\nimport type { NodeOrValue } from \"../../base/resilience/_internal.js\";\nimport { decay } from \"../../base/utils/decay.js\";\n\n// ── Shared helpers ───────────────────────────────────────────────────────\n\nconst NS_PER_SEC = 1_000_000_000;\n\nfunction memoryMeta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"memory\", kind, extra);\n}\n\n/**\n * Coerce a value-or-Node argument into a `Node<T>`. Pass-through if already a\n * Node; otherwise wraps in `state(value, {name})`. Used by reactive read\n * factories (`itemNode` / `searchNode` / `relatedNode`) so callers can supply\n * a static value without manually creating a state node.\n *\n * Heuristic: anything that is a `NodeImpl` instance is a Node; everything else\n * is treated as a raw value to wrap.\n */\nfunction toNode<T>(v: T | Node<T>, name?: string): Node<T> {\n\tif (v instanceof NodeImpl) return v as Node<T>;\n\treturn node<T>([], { initial: v as T, ...(name ? { name } : undefined) });\n}\n\nfunction ageSeconds(now: number, lastNs: number): number {\n\treturn (now - lastNs) / NS_PER_SEC;\n}\n\n// `decay` was promoted to `extra/utils/decay.ts` per Tier 2.2 — it is no longer\n// re-exported from this module. Import from `@graphrefly/graphrefly/extra` (or\n// `../../extra/utils/decay.js` internally) instead.\n\n/**\n * Cosine similarity over `(a, b)`. When lengths differ, the shorter is\n * implicitly zero-padded to the longer length. Returns `0` if either vector\n * has zero norm. Public utility — used by {@link VectorIndexGraph.searchNode}\n * and exposed for downstream consumers (e.g. `patterns/ai/memory/`) that need\n * the same scoring at the boundary.\n *\n * **Numeric guards.** Returns `0` for non-finite results (overflow producing\n * `Infinity`/`NaN` from very-large vectors, or `NaN` propagating from any\n * `NaN`/`Infinity` component). Without this guard, downstream sort\n * comparators would order NaN-scored rows arbitrarily.\n *\n * **Depth.** This is a per-call computation; no internal caching. For very\n * large indexes (>10k) consider precomputing norms or using HNSW.\n *\n * @category memory\n */\nexport function cosineSimilarity(a: readonly number[], b: readonly number[]): number {\n\tconst n = Math.max(a.length, b.length);\n\tlet dot = 0;\n\tlet na = 0;\n\tlet nb = 0;\n\tfor (let i = 0; i < n; i += 1) {\n\t\tconst av = a[i] ?? 0;\n\t\tconst bv = b[i] ?? 0;\n\t\tdot += av * bv;\n\t\tna += av * av;\n\t\tnb += bv * bv;\n\t}\n\tif (na === 0 || nb === 0) return 0;\n\tconst score = dot / Math.sqrt(na * nb);\n\treturn Number.isFinite(score) ? score : 0;\n}\n\n/**\n * Equality predicate for {@link VectorIndexGraph.searchNode} results. Compares\n * `id` AND `score` AND `meta` reference per position so that score-only changes\n * (re-upsert with new vector keeping the same top-K order) propagate to\n * downstream subscribers. The previous id-only comparator silently dropped\n * those updates.\n */\nfunction searchResultsEqual<TMeta>(\n\ta: readonly VectorSearchResult<TMeta>[] | undefined,\n\tb: readonly VectorSearchResult<TMeta>[] | undefined,\n): boolean {\n\tif (a === b) return true;\n\tif (a == null || b == null) return false;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i += 1) {\n\t\tconst x = a[i]!;\n\t\tconst y = b[i]!;\n\t\tif (x.id !== y.id || x.score !== y.score || x.meta !== y.meta) return false;\n\t}\n\treturn true;\n}\n\n// ── Common types ─────────────────────────────────────────────────────────\n\n/** Public alias for the `Node | value` shape accepted by reactive read factories. */\nexport type { NodeOrValue } from \"../../base/resilience/_internal.js\";\n\n// ── Unit 2 (Tier 2.3 fold): collection (formerly lightCollection + collection)\n//\n// Pre-Tier-2.3 the module shipped `lightCollection` (no Graph, no ranking,\n// just LRU + audit) alongside `collection` (Graph-mounted with timer-driven\n// decay-aware ranking). Per the consolidation plan §1 Rule 4, the two are\n// folded into a single `collection({ranked: true|false})` factory: when\n// `ranked: false`, no `ranked` derived / refresh tick / scoring is wired.\n// `LightCollectionEntry` is gone — `CollectionEntry<T>` is the unified entry\n// shape (`baseScore` reads `0` in unranked mode).\n\nexport type CollectionEntry<T> = {\n\treadonly id: string;\n\treadonly value: T;\n\treadonly createdAtNs: number;\n\treadonly lastAccessNs: number;\n\treadonly baseScore: number;\n};\n\nexport type RankedCollectionEntry<T> = CollectionEntry<T> & {\n\treadonly score: number;\n};\n\nexport type CollectionScoreFn<T> = (value: T) => number;\n\nexport type CollectionOptions<T> = {\n\tmaxSize?: number;\n\t/**\n\t * Whether to expose a live decay-aware `ranked` node + `rescore` mutator.\n\t * Default `true`. Pass `false` to fold in the previous `lightCollection`\n\t * shape — entries are still keyed/audited/LRU-evicted, but the timer-driven\n\t * `ranked` + scoring machinery is skipped. `ranked` then resolves to a\n\t * static empty array Node and `rescore()` is a no-op (so callers writing\n\t * type-generic code don't need to special-case the unranked path).\n\t */\n\tranked?: boolean;\n\t/**\n\t * Produces a base score at insert/update time. Static fn or a reactive\n\t * `Node<(value: T) => number>` — when supplied as a Node, `ranked` re-derives\n\t * whenever the score fn changes, but `baseScore` on each entry is only\n\t * recomputed via {@link CollectionGraph.rescore}. Default `() => 1`.\n\t *\n\t * Ignored when `ranked: false` (entries record `baseScore: 0`).\n\t */\n\tscore?: CollectionScoreFn<T> | Node<CollectionScoreFn<T>>;\n\t/**\n\t * Exponential decay rate per second. `0` disables decay (default). When\n\t * positive, `ranked` becomes fully reactive on time via a `fromTimer` source\n\t * (cadence auto-derived from `decayRate` unless overridden via\n\t * `refreshIntervalMs`). Half-life: `ratePerSecond = Math.LN2 / halfLifeSeconds`.\n\t *\n\t * Ignored when `ranked: false`.\n\t */\n\tdecayRate?: number;\n\t/** Minimum score floor after decay. Default `0`. */\n\tminScore?: number;\n\t/**\n\t * Override for the `ranked` refresh tick cadence (milliseconds). When\n\t * unset and `decayRate > 0`, defaults to `1000 * Math.LN2 / (10 * decayRate)`\n\t * — roughly one tick per 10% of the half-life (~10% staleness budget).\n\t */\n\trefreshIntervalMs?: number;\n};\n\nexport interface CollectionAuditRecord extends BaseAuditRecord {\n\treadonly action: \"upsert\" | \"remove\" | \"clear\" | \"rescore\";\n\treadonly id?: string;\n}\n\nexport type CollectionGraph<T> = Graph & {\n\treadonly events: ReactiveLogBundle<CollectionAuditRecord>;\n\treadonly items: Node<ReadonlyMap<string, CollectionEntry<T>>>;\n\t/**\n\t * Live decay-aware ranking, sorted by score descending. When the\n\t * collection was constructed with `ranked: false`, this is a static\n\t * empty-array Node (kept for type uniformity).\n\t */\n\treadonly ranked: Node<readonly RankedCollectionEntry<T>[]>;\n\treadonly size: Node<number>;\n\tupsert: (id: string, value: T, opts?: { score?: number }) => void;\n\tremove: (id: string) => void;\n\tclear: () => void;\n\t/**\n\t * Recompute every entry's `baseScore` via the latest score fn. O(N). Useful\n\t * when a reactive `score` Node has emitted a new fn and the caller wants\n\t * existing entries re-scored without an explicit re-upsert.\n\t *\n\t * No-op (still records an audit entry) when constructed with\n\t * `ranked: false`.\n\t */\n\trescore: () => void;\n\titemNode: (id: NodeOrValue<string>) => Node<CollectionEntry<T> | undefined>;\n\t/** Reactive `true` once the entry exists; tracks upsert / remove. */\n\thasNode: (id: NodeOrValue<string>) => Node<boolean>;\n};\n\nfunction rankedEqual<T>(\n\ta: readonly RankedCollectionEntry<T>[] | undefined,\n\tb: readonly RankedCollectionEntry<T>[] | undefined,\n): boolean {\n\tif (a === b) return true;\n\tif (a == null || b == null) return false;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i += 1) {\n\t\tconst x = a[i]!;\n\t\tconst y = b[i]!;\n\t\t// Compare value reference too — if `upsert(id, newValue)` runs and\n\t\t// `score(newValue) === score(oldValue)` AND timestamps coincide\n\t\t// (rare on platforms where consecutive `monotonicNs()` calls in the\n\t\t// same microtask collide), the prior comparator suppressed the\n\t\t// emission and consumers reading `entry.value` saw stale data.\n\t\t// Value identity catches it cheaply (`value !== value` only on NaN\n\t\t// payloads, which behave correctly here).\n\t\tif (\n\t\t\tx.id !== y.id ||\n\t\t\tx.score !== y.score ||\n\t\t\tx.lastAccessNs !== y.lastAccessNs ||\n\t\t\tx.value !== y.value\n\t\t)\n\t\t\treturn false;\n\t}\n\treturn true;\n}\n\n/**\n * Scored memory store with live decay-aware ranking.\n *\n * Topology (mounted on the returned graph):\n * - `items` — `reactiveMap<id, CollectionEntry<T>>` (with `retention` configured\n * for score-based eviction when `maxSize` is set).\n * - `ranked` — `Node<readonly RankedCollectionEntry<T>[]>`, sorted by live\n * decayed score. **Lazy** — does NOT compute until subscribed (no internal\n * keepalive). Use `keepalive(coll.ranked)` for eager activation.\n * - `size` — `Node<number>`, count of entries.\n * - `_refreshTick` — `fromTimer`-driven `monotonicNs()` source, mounted only\n * when `decayRate > 0`. Drives `ranked`'s time-dependent re-derivation.\n * - `_seq` — sequence cursor for the audit log.\n * - `events` — bounded reactive log of every mutation.\n *\n * **Time as a reactive dep.** When `decayRate > 0`, `ranked`'s deps are\n * `[items, refreshTick]` — the tick payload IS `monotonicNs()`, so the fn is\n * pure of deps and dry-run-reproducible with a mocked clock.\n *\n * **Lazy timer.** With no subscriber to `ranked`, the timer source does not\n * fire — the activation chain is downstream-driven. To keep the timer warm\n * without consuming results, register `graph.addDisposer(keepalive(coll.ranked))`.\n *\n * **Eviction at write-time.** Score-based retention runs on every successful\n * `upsert / remove / clear` (it is mutation-driven, not tick-driven). The\n * retention scorer reads `monotonicNs()` to compute decayed scores at eviction\n * time — this is a deliberate impurity vs. `ReactiveMapRetention.score`'s\n * \"pure of `(key, value)`\" docstring: write-time is the right moment to evict\n * stale-by-decay entries.\n *\n * **No imperative reads.** Subscribe to `items` / `ranked` for live snapshots,\n * or use `itemNode(id)` for single-key reactive reads.\n *\n * **`rescore` ordering caveat.** `rescore()` reads `items.entries.cache`\n * (the post-emission snapshot) and writes via `setMany`. When called\n * stand-alone it sees the latest committed state. When wrapped inside a\n * user-level `batch(() => { coll.upsert(...); coll.rescore(); })`, the\n * `cache` snapshot reflects state BEFORE the batch — so a just-staged\n * upsert is invisible to the rescore scan. If you need rescore to include\n * the staged upsert, either call `rescore()` after the batch settles or\n * pass the new `baseScore` directly via `upsert(id, value, { score })`.\n *\n * **Audit no-op records.** Like `lightCollection`, mutations record audit\n * entries even when the impl was a no-op (e.g., `rescore()` on an empty\n * store). Intentional — the framework records attempts.\n *\n * @category memory\n */\nexport function collection<T>(name: string, opts: CollectionOptions<T> = {}): CollectionGraph<T> {\n\tconst maxSize = opts.maxSize;\n\tconst ranked = opts.ranked ?? true;\n\t// `decayRate` / `score` / `refreshIntervalMs` are no-ops when ranked is off\n\t// (they only feed the `ranked` derived). The audit + LRU paths still run.\n\tconst decayRate = ranked ? (opts.decayRate ?? 0) : 0;\n\tconst minScore = opts.minScore ?? 0;\n\tif (maxSize !== undefined && maxSize < 1) {\n\t\tthrow new RangeError(\"collection: maxSize must be >= 1\");\n\t}\n\n\t// Resolve score fn — supports static fn or reactive Node<fn>. When\n\t// `ranked: false` the score is constant `0` and `readScoreFn` is unused\n\t// (the upsert path takes the `_opts.score ?? readScoreFn()(value)` branch\n\t// only when ranking is requested).\n\tconst scoreFnDefault: CollectionScoreFn<T> = () => (ranked ? 1 : 0);\n\tconst scoreInput = opts.score ?? scoreFnDefault;\n\tconst scoreNode: Node<CollectionScoreFn<T>> | undefined =\n\t\tranked && scoreInput instanceof NodeImpl\n\t\t\t? (scoreInput as Node<CollectionScoreFn<T>>)\n\t\t\t: undefined;\n\tconst readScoreFn = (): CollectionScoreFn<T> => {\n\t\tif (scoreNode) return scoreNode.cache ?? scoreFnDefault;\n\t\treturn scoreInput as CollectionScoreFn<T>;\n\t};\n\n\tconst graph = new Graph(name);\n\n\t// Score-based retention scorer for `reactiveMap`. When unranked the base\n\t// score is `0`, so retention falls back to LRU-by-`lastAccessNs` (the\n\t// older the access, the lower the decayed score → first to evict).\n\tconst retentionScore = (_k: string, v: CollectionEntry<T>): number =>\n\t\tranked\n\t\t\t? decay(v.baseScore, ageSeconds(monotonicNs(), v.lastAccessNs), decayRate, minScore)\n\t\t\t: v.lastAccessNs;\n\n\tconst items = reactiveMap<string, CollectionEntry<T>>({\n\t\tname: \"items\",\n\t\t...(maxSize !== undefined ? { retention: { score: retentionScore, maxSize } } : {}),\n\t});\n\n\tgraph.add(items.entries, { name: \"items\" });\n\n\t// Refresh tick — only mounted when ranking + decay are configured. Tick\n\t// payload is `monotonicNs()`, so `rankedNode`'s fn is pure-of-deps and\n\t// dry-run-reproducible.\n\tlet refreshTick: Node<number> | undefined;\n\tif (ranked && decayRate > 0) {\n\t\tconst intervalMs = opts.refreshIntervalMs ?? Math.max(1, (1000 * Math.LN2) / (10 * decayRate));\n\t\tconst tickCounter = fromTimer(intervalMs, { period: intervalMs });\n\t\t// Map each tick to the wall-clock `monotonicNs` — the tick payload IS\n\t\t// the time stamp downstream consumers use. Reading the central clock\n\t\t// inside this fn is sanctioned: this derived's purpose is to publish\n\t\t// \"now\" reactively (cf. spec §5.11 — central timer), and downstream\n\t\t// `rankedNode` reads it from its dep array, never from the clock\n\t\t// directly.\n\t\t//\n\t\t// `initial: monotonicNs()` seeds the cache with construction-time\n\t\t// `now` so push-on-subscribe delivers DATA to `rankedNode` before the\n\t\t// first tick fires — without this, `rankedNode` would stall in pending\n\t\t// status until ~`refreshIntervalMs` after first activation, and a\n\t\t// caller reading `rankedNode.cache` immediately after `upsert` would\n\t\t// see `undefined`.\n\t\trefreshTick = node(\n\t\t\t[tickCounter],\n\t\t\t(_batchData, actions) => {\n\t\t\t\tactions.emit(monotonicNs());\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"refresh_tick_ns\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tinitial: monotonicNs(),\n\t\t\t\tmeta: memoryMeta(\"clock\"),\n\t\t\t},\n\t\t);\n\t\tgraph.add(refreshTick, { name: \"refresh_tick_ns\" });\n\t}\n\n\t// `rankedNode` derived — pure of (items, refreshTick?, scoreNode?). When\n\t// `ranked: false`, `rankedNode` is a static empty-array node so the\n\t// public type stays uniform without re-running the sort.\n\tlet rankedNode: Node<readonly RankedCollectionEntry<T>[]>;\n\tif (ranked) {\n\t\tconst rankedDeps: Node<unknown>[] = [items.entries];\n\t\tif (refreshTick) rankedDeps.push(refreshTick);\n\t\tif (scoreNode) rankedDeps.push(scoreNode);\n\t\trankedNode = node(\n\t\t\trankedDeps,\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst values = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst snapshot = values[0] as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\t\t\tlet now: number;\n\t\t\t\tif (refreshTick) {\n\t\t\t\t\tconst tickValue = values[1] as number | undefined;\n\t\t\t\t\tnow = typeof tickValue === \"number\" ? tickValue : monotonicNs();\n\t\t\t\t} else {\n\t\t\t\t\tnow = monotonicNs();\n\t\t\t\t}\n\t\t\t\tif (!snapshot || snapshot.size === 0) {\n\t\t\t\t\tactions.emit([] as readonly RankedCollectionEntry<T>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst out: RankedCollectionEntry<T>[] = [];\n\t\t\t\tfor (const entry of snapshot.values()) {\n\t\t\t\t\tout.push({\n\t\t\t\t\t\t...entry,\n\t\t\t\t\t\tscore: decay(entry.baseScore, ageSeconds(now, entry.lastAccessNs), decayRate, minScore),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tout.sort((a, b) => b.score - a.score || b.lastAccessNs - a.lastAccessNs);\n\t\t\t\tactions.emit(out as readonly RankedCollectionEntry<T>[]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"ranked\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tequals: rankedEqual,\n\t\t\t\tmeta: memoryMeta(\"ranked\"),\n\t\t\t},\n\t\t) as Node<readonly RankedCollectionEntry<T>[]>;\n\t\tgraph.add(rankedNode, { name: \"ranked\" });\n\t} else {\n\t\trankedNode = node<readonly RankedCollectionEntry<T>[]>([], {\n\t\t\tinitial: [] as readonly RankedCollectionEntry<T>[],\n\t\t\tname: \"ranked\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: memoryMeta(\"ranked_disabled\"),\n\t\t}) as Node<readonly RankedCollectionEntry<T>[]>;\n\t\tgraph.add(rankedNode, { name: \"ranked\" });\n\t}\n\n\tconst size = node(\n\t\t[items.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0] as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\t\tactions.emit(((snapshot ?? new Map()) as ReadonlyMap<string, CollectionEntry<T>>).size);\n\t\t},\n\t\t{\n\t\t\tname: \"size\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: 0,\n\t\t\tmeta: memoryMeta(\"size\"),\n\t\t},\n\t);\n\tgraph.add(size, { name: \"size\" });\n\t// Keepalive only on `size` (cheap; pure of items). `ranked` is intentionally\n\t// lazy so the refresh timer doesn't fire when nothing consumes the ranking.\n\tgraph.addDisposer(keepalive(size));\n\n\t// Audit log + seq cursor.\n\tconst events = createAuditLog<CollectionAuditRecord>({\n\t\tname: \"events\",\n\t\tretainedLimit: 1024,\n\t\tgraph,\n\t});\n\tconst seqCursor = registerCursor(graph, \"seq\", 0);\n\n\tconst upsertImpl = (id: string, value: T, _opts?: { score?: number }): void => {\n\t\tconst now = monotonicNs();\n\t\tconst prev = items.get(id);\n\t\tconst baseScore = _opts?.score ?? readScoreFn()(value);\n\t\titems.set(id, {\n\t\t\tid,\n\t\t\tvalue,\n\t\t\tbaseScore,\n\t\t\tcreatedAtNs: prev?.createdAtNs ?? now,\n\t\t\tlastAccessNs: now,\n\t\t});\n\t};\n\tconst removeImpl = (id: string): void => {\n\t\tif (!items.has(id)) return;\n\t\titems.delete(id);\n\t};\n\tconst clearImpl = (): void => {\n\t\tif (items.size === 0) return;\n\t\titems.clear();\n\t};\n\tconst rescoreImpl = (): void => {\n\t\t// `ranked: false` short-circuit — there's no live `ranked` node to\n\t\t// re-derive and `baseScore` is held at its insertion-time value, so\n\t\t// rescore is a no-op. The audit record is still emitted so consumers\n\t\t// see the attempt.\n\t\tif (!ranked) return;\n\t\tconst fn = readScoreFn();\n\t\tconst snapshot = items.entries.cache as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\tif (!snapshot || snapshot.size === 0) return;\n\t\tconst updates: Array<[string, CollectionEntry<T>]> = [];\n\t\tfor (const entry of snapshot.values()) {\n\t\t\tupdates.push([entry.id, { ...entry, baseScore: fn(entry.value) }]);\n\t\t}\n\t\titems.setMany(updates);\n\t};\n\n\tconst upsert = mutate(upsertImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({ action: \"upsert\" as const, id, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst remove = mutate(removeImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({ action: \"remove\" as const, id, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst clear = mutate(clearImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: (_args, _r, m) => ({ action: \"clear\" as const, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst rescore = mutate(rescoreImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: (_args, _r, m) => ({ action: \"rescore\" as const, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\n\tfunction itemNode(id: NodeOrValue<string>): Node<CollectionEntry<T> | undefined> {\n\t\tconst idN = toNode(id, \"id\");\n\t\treturn node(\n\t\t\t[items.entries, idN],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst map = data[0] as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\t\t\tconst key = data[1] as string;\n\t\t\t\tactions.emit(map?.get(key));\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: memoryMeta(\"collection_item\"),\n\t\t\t},\n\t\t);\n\t}\n\n\tfunction hasNode(id: NodeOrValue<string>): Node<boolean> {\n\t\tconst idN = toNode(id, \"id\");\n\t\treturn node(\n\t\t\t[items.entries, idN],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst map = data[0] as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\t\t\tconst key = data[1] as string;\n\t\t\t\tactions.emit(map?.has(key) ?? false);\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: memoryMeta(\"collection_has\"),\n\t\t\t},\n\t\t);\n\t}\n\n\tconst out = Object.assign(graph, {\n\t\tevents,\n\t\titems: items.entries,\n\t\tranked: rankedNode,\n\t\tsize,\n\t\tupsert,\n\t\tremove,\n\t\tclear,\n\t\trescore,\n\t\titemNode,\n\t\thasNode,\n\t}) as CollectionGraph<T>;\n\treturn out;\n}\n\n// ── Unit 4: vectorIndex ──────────────────────────────────────────────────\n\nexport type VectorBackend = \"flat\" | \"hnsw\";\n\nexport type VectorRecord<TMeta> = {\n\treadonly id: string;\n\treadonly vector: readonly number[];\n\treadonly meta?: TMeta;\n\t/** Wall-clock-monotonic timestamp at last upsert; used for the default LRU retention. */\n\treadonly upsertedAtNs: number;\n};\n\nexport type VectorSearchResult<TMeta> = {\n\treadonly id: string;\n\treadonly score: number;\n\treadonly meta?: TMeta;\n};\n\nexport type HnswAdapter<TMeta> = {\n\tupsert: (id: string, vector: readonly number[], meta?: TMeta) => void;\n\tremove: (id: string) => void;\n\tclear: () => void;\n\tsearch: (query: readonly number[], k: number) => ReadonlyArray<VectorSearchResult<TMeta>>;\n\t/** Optional adapter teardown. Called from `graph.destroy()` via `addDisposer`. */\n\tdispose?: () => void;\n};\n\nexport type VectorIndexOptions<TMeta> = {\n\tname?: string;\n\tbackend?: VectorBackend;\n\tdimension?: number;\n\t/**\n\t * Strict-dimension default. When `true` (default) AND `dimension` is unset,\n\t * mixed-length upserts throw `RangeError`. Set `false` to opt into the\n\t * lenient zero-padding behavior of {@link VectorIndexGraph.searchNode}.\n\t */\n\tstrictDimension?: boolean;\n\t/** Optional dependency seam for HNSW. */\n\thnswFactory?: () => HnswAdapter<TMeta>;\n\t/** Maximum live entries (LRU-by-upsert-time when set; user-overridable via `retentionScore`). */\n\tmaxSize?: number;\n\t/** Custom retention scorer. Higher score = kept. Defaults to `r => r.upsertedAtNs`. */\n\tretentionScore?: (record: VectorRecord<TMeta>) => number;\n};\n\nexport interface VectorIndexAuditRecord extends BaseAuditRecord {\n\treadonly action: \"upsert\" | \"remove\" | \"clear\" | \"reindex\" | \"evict\";\n\treadonly id?: string;\n}\n\nexport type VectorIndexGraph<TMeta> = Graph & {\n\treadonly backend: VectorBackend;\n\treadonly events: ReactiveLogBundle<VectorIndexAuditRecord>;\n\treadonly entries: Node<ReadonlyMap<string, VectorRecord<TMeta>>>;\n\tupsert: (id: string, vector: readonly number[], meta?: TMeta) => void;\n\tremove: (id: string) => void;\n\tclear: () => void;\n\t/** Re-push every live entry into the optional HNSW adapter. No-op for `flat`. */\n\treindex: () => void;\n\t/**\n\t * Reactive top-K search. Re-derives whenever entries / query / k change.\n\t * Lazy. Use `firstValueFrom(searchNode(...))` for one-shot reads.\n\t */\n\tsearchNode: (\n\t\tquery: Node<readonly number[]>,\n\t\tk?: NodeOrValue<number>,\n\t) => Node<readonly VectorSearchResult<TMeta>[]>;\n};\n\n/**\n * Reactive vector store with optional HNSW backend.\n *\n * **Storage on `reactiveMap`.** `entries` is a `reactiveMap<id, VectorRecord<TMeta>>`\n * with optional score-based retention (`maxSize` + LRU-by-`upsertedAtNs` by\n * default; user can supply a custom `retentionScore`). On retention eviction,\n * the HNSW adapter (if configured) is also notified via `adapter.remove(id)`.\n *\n * **Reactive search.** `searchNode(queryNode, k)` returns a `Node<readonly\n * VectorSearchResult<TMeta>[]>` that re-derives on entries / query / k change.\n * Lazy — only computes when subscribed. Imperative `search()` is intentionally\n * not exposed (no-imperative-reads policy). Use `firstValueFrom(searchNode(...))`\n * for one-shot reads.\n *\n * **Strict dimension.** Default `strictDimension: true` — if `dimension` is\n * unset and an upsert produces a vector of a different length than the first\n * upserted, throws `RangeError`. Pass `strictDimension: false` to opt into\n * the lenient zero-padding fallback (the previous default).\n *\n * **Adapter lifecycle.** When the HNSW adapter exposes a `dispose()` method,\n * it is bound to the graph's teardown via `addDisposer`. When retention\n * evicts an entry, `adapter.remove(id)` is invoked synchronously inside the\n * retention `onArchive` callback.\n *\n * **Cosine zero-pad.** The flat backend uses cosine similarity over the\n * pairwise max-length zero-pad. Mixing dimensions silently degrades scores\n * unless strict mode catches it at upsert time. For embedding-model vectors,\n * L2-normalize at the source — `vectorIndex` does not normalize.\n *\n * @category memory\n */\nexport function vectorIndex<TMeta>(opts: VectorIndexOptions<TMeta> = {}): VectorIndexGraph<TMeta> {\n\tconst backend = opts.backend ?? \"flat\";\n\tconst dimension = opts.dimension;\n\tconst strictDimension = opts.strictDimension ?? true;\n\tconst maxSize = opts.maxSize;\n\tconst userRetentionScore = opts.retentionScore;\n\n\tlet hnsw: HnswAdapter<TMeta> | undefined;\n\tif (backend === \"hnsw\") {\n\t\thnsw = opts.hnswFactory?.();\n\t\tif (!hnsw) {\n\t\t\tthrow new Error(\n\t\t\t\t'vectorIndex backend \"hnsw\" requires an optional dependency adapter; install your HNSW package and provide `hnswFactory`.',\n\t\t\t);\n\t\t}\n\t}\n\n\tconst graph = new Graph(opts.name ?? \"vector_index\");\n\n\t// Track an inferred dimension when the user didn't lock it but strict mode\n\t// is on — first upsert sets it; subsequent mismatches throw.\n\tlet inferredDimension: number | undefined;\n\tfunction assertDimension(vector: readonly number[]): void {\n\t\tif (dimension !== undefined) {\n\t\t\tif (vector.length !== dimension) {\n\t\t\t\tthrow new RangeError(\n\t\t\t\t\t`vector dimension mismatch: expected ${dimension}, got ${vector.length}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (!strictDimension) return;\n\t\tif (inferredDimension === undefined) {\n\t\t\tinferredDimension = vector.length;\n\t\t\treturn;\n\t\t}\n\t\tif (vector.length !== inferredDimension) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`vector dimension mismatch: inferred ${inferredDimension} from first upsert, got ${vector.length}. ` +\n\t\t\t\t\t`Pass \\`strictDimension: false\\` to opt into zero-pad behavior, or set an explicit \\`dimension\\`.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tconst baseRetentionScore = userRetentionScore ?? ((r: VectorRecord<TMeta>) => r.upsertedAtNs);\n\t// `clearInProgress` lets us short-circuit the per-entry `onArchive` →\n\t// `hnsw.remove(id)` cascade when the user calls `clearImpl()`. Retention\n\t// fires `onArchive` for every evicted entry; followed by an explicit\n\t// `hnsw.clear()` we'd double-touch the adapter. Inside `clearImpl` we\n\t// flip this flag, then call `hnsw.clear()` once at the end. (G fix.)\n\tlet clearInProgress = false;\n\n\t// `clearAuditPending` defers the per-entry `evict` audit emission when a\n\t// `clear()` is in flight — those evictions are reported as a single\n\t// `clear` action, not a flurry of `evict` records.\n\tconst events = createAuditLog<VectorIndexAuditRecord>({\n\t\tname: \"events\",\n\t\tretainedLimit: 1024,\n\t\tgraph,\n\t});\n\tconst seqCursor = registerCursor(graph, \"seq\", 0);\n\n\tconst entries = reactiveMap<string, VectorRecord<TMeta>>({\n\t\tname: \"entries\",\n\t\t...(maxSize !== undefined\n\t\t\t? {\n\t\t\t\t\tretention: {\n\t\t\t\t\t\tscore: (_k, v) => baseRetentionScore(v),\n\t\t\t\t\t\tmaxSize,\n\t\t\t\t\t\tonArchive: (key) => {\n\t\t\t\t\t\t\tif (clearInProgress) return;\n\t\t\t\t\t\t\tif (backend === \"hnsw\") hnsw!.remove(key);\n\t\t\t\t\t\t\t// E1: surface retention-driven evictions in the audit log\n\t\t\t\t\t\t\t// so replay consumers can reconstruct the live snapshot\n\t\t\t\t\t\t\t// from `events` alone. `seq` is bumped via the cursor;\n\t\t\t\t\t\t\t// the `t_ns` matches `wallClockNs()` for consistency\n\t\t\t\t\t\t\t// with `lightMutation`'s record stamping.\n\t\t\t\t\t\t\tevents.append({\n\t\t\t\t\t\t\t\taction: \"evict\" as const,\n\t\t\t\t\t\t\t\tid: key,\n\t\t\t\t\t\t\t\tt_ns: wallClockNs(),\n\t\t\t\t\t\t\t\tseq: bumpCursor(seqCursor),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t});\n\tgraph.add(entries.entries, { name: \"entries\" });\n\t// F1: keep `entries` warm so downstream consumers reading\n\t// `vectors.entries.cache` (e.g. `patterns/ai/memory/runRetrieval`) don't\n\t// rely on an external subscriber to activate the node. State nodes are\n\t// ROM and retain `.cache` regardless of subscribers — this `keepalive`\n\t// is defense-in-depth and matches the kg's adjacency keepalive pattern.\n\tgraph.addDisposer(keepalive(entries.entries));\n\n\t// HNSW dispose runs BEFORE state-node teardown via standard disposer\n\t// ordering (disposers drain first, then `[[TEARDOWN]]` propagates per\n\t// `Graph.destroy()`). This is the right ordering: free the adapter's\n\t// native resources before the reactive layer tears down.\n\tif (hnsw?.dispose) {\n\t\tconst disposeAdapter = hnsw.dispose.bind(hnsw);\n\t\tgraph.addDisposer(() => disposeAdapter());\n\t}\n\n\tconst upsertImpl = (id: string, vector: readonly number[], meta?: TMeta): void => {\n\t\tassertDimension(vector);\n\t\t// B1: mutate HNSW first so a throw aborts the reactive write. With\n\t\t// the prior order (entries.set then hnsw.upsert), an adapter throw\n\t\t// would leave entries holding a row HNSW didn't index. Now: HNSW\n\t\t// commits first; if it throws, entries is untouched and audit log\n\t\t// records the failure.\n\t\tif (backend === \"hnsw\") hnsw!.upsert(id, vector, meta);\n\t\t// Defensive copies: vector via `[...vector]`; meta via shallow spread\n\t\t// when it's a non-null object (Array.isArray covered first since arrays\n\t\t// are objects). Primitives, `null`, functions etc. pass through\n\t\t// unchanged. Documented depth limitation: nested objects in `meta` are\n\t\t// shared by reference.\n\t\tconst copiedMeta: TMeta | undefined = (() => {\n\t\t\tif (meta === undefined) return undefined;\n\t\t\tif (meta === null || typeof meta !== \"object\") return meta;\n\t\t\treturn Array.isArray(meta) ? ([...meta] as unknown as TMeta) : ({ ...meta } as TMeta);\n\t\t})();\n\t\tconst record: VectorRecord<TMeta> = {\n\t\t\tid,\n\t\t\tvector: [...vector],\n\t\t\t...(copiedMeta !== undefined ? { meta: copiedMeta } : {}),\n\t\t\tupsertedAtNs: monotonicNs(),\n\t\t};\n\t\tentries.set(id, record);\n\t};\n\tconst removeImpl = (id: string): void => {\n\t\tif (!entries.has(id)) return;\n\t\t// B1: HNSW first, then entries.\n\t\tif (backend === \"hnsw\") hnsw!.remove(id);\n\t\tentries.delete(id);\n\t};\n\tconst clearImpl = (): void => {\n\t\tif (entries.size === 0) return;\n\t\t// B1 + G: mark the clear-in-progress flag so retention `onArchive`\n\t\t// suppresses per-entry HNSW removes AND per-entry `evict` audit\n\t\t// records. Then call `entries.clear()` (drains the backend through\n\t\t// retention archival without side effects), and finally call\n\t\t// `hnsw.clear()` once. Reset `inferredDimension` so a fresh start\n\t\t// re-infers from the next upsert.\n\t\tclearInProgress = true;\n\t\ttry {\n\t\t\tentries.clear();\n\t\t\tif (backend === \"hnsw\") hnsw!.clear();\n\t\t} finally {\n\t\t\tclearInProgress = false;\n\t\t}\n\t\tinferredDimension = undefined;\n\t};\n\tconst reindexImpl = (): void => {\n\t\tif (backend !== \"hnsw\") return;\n\t\tconst snapshot = entries.entries.cache as ReadonlyMap<string, VectorRecord<TMeta>> | undefined;\n\t\tif (!snapshot) return;\n\t\thnsw!.clear();\n\t\tfor (const r of snapshot.values()) {\n\t\t\thnsw!.upsert(r.id, r.vector, r.meta);\n\t\t}\n\t};\n\n\t// `freeze: false` for `upsert` — deep-freezing a 768-dim vector is a\n\t// measurable hot-path tax, and the wrapper does its own defensive copy\n\t// (`vector: [...vector]`) before persisting. See §B.2 of the audit lock.\n\tconst upsert = mutate(upsertImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tfreeze: false,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({ action: \"upsert\" as const, id, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst remove = mutate(removeImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({ action: \"remove\" as const, id, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst clear = mutate(clearImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: (_args, _r, m) => ({ action: \"clear\" as const, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst reindex = mutate(reindexImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: (_args, _r, m) => ({ action: \"reindex\" as const, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\n\tfunction searchNode(\n\t\tquery: Node<readonly number[]>,\n\t\tk: NodeOrValue<number> = 5,\n\t): Node<readonly VectorSearchResult<TMeta>[]> {\n\t\tconst kN = toNode<number>(k, \"k\");\n\t\treturn node(\n\t\t\t[entries.entries, query, kN],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst values = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst snapshot = values[0] as ReadonlyMap<string, VectorRecord<TMeta>> | undefined;\n\t\t\t\tconst q = values[1] as readonly number[] | undefined;\n\t\t\t\tconst kRaw = values[2] as number;\n\t\t\t\t// Auto-fix: `Math.max(0, Math.floor(k))` — `| 0` is a 32-bit\n\t\t\t\t// signed truncation that collapses Infinity to 0 and wraps\n\t\t\t\t// values > 2^31. Use a proper floor with a non-negative floor.\n\t\t\t\tconst kVal = Number.isFinite(kRaw) ? Math.max(0, Math.floor(kRaw)) : 0;\n\t\t\t\tif (!snapshot || snapshot.size === 0 || kVal <= 0) {\n\t\t\t\t\tactions.emit([] as readonly VectorSearchResult<TMeta>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Auto-fix: defensive guard for unset / empty query — earlier\n\t\t\t\t// the fn would TypeError on `q.length` reading `undefined`,\n\t\t\t\t// or compute meaningless all-zero scores against an empty\n\t\t\t\t// vector. With strict-dimension OR an explicit `dimension`,\n\t\t\t\t// also reject mismatched-length queries (the imperative path\n\t\t\t\t// used to throw; reactive deriveds shouldn't throw, so\n\t\t\t\t// degrade to empty results).\n\t\t\t\tif (q == null || q.length === 0) {\n\t\t\t\t\tactions.emit([] as readonly VectorSearchResult<TMeta>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst expectedDim = dimension ?? (strictDimension ? inferredDimension : undefined);\n\t\t\t\tif (expectedDim !== undefined && q.length !== expectedDim) {\n\t\t\t\t\tactions.emit([] as readonly VectorSearchResult<TMeta>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (backend === \"hnsw\") {\n\t\t\t\t\t// Defensive copy of the adapter's return — HNSW libs\n\t\t\t\t\t// sometimes hand back internal buffers; downstream\n\t\t\t\t\t// subscribers must not be able to corrupt adapter state.\n\t\t\t\t\tconst adapterResults = hnsw!.search(q, kVal);\n\t\t\t\t\tactions.emit([...adapterResults] as readonly VectorSearchResult<TMeta>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst ranked = [...snapshot.values()]\n\t\t\t\t\t.map((row) => {\n\t\t\t\t\t\tconst result: VectorSearchResult<TMeta> = {\n\t\t\t\t\t\t\tid: row.id,\n\t\t\t\t\t\t\tscore: cosineSimilarity(q, row.vector),\n\t\t\t\t\t\t\t...(row.meta !== undefined ? { meta: row.meta } : {}),\n\t\t\t\t\t\t};\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t})\n\t\t\t\t\t.sort((a, b) => b.score - a.score)\n\t\t\t\t\t.slice(0, kVal);\n\t\t\t\tactions.emit(ranked as readonly VectorSearchResult<TMeta>[]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\t// A1: include `score` in equality. The previous id-only\n\t\t\t\t// comparator suppressed re-emissions when the same set of\n\t\t\t\t// IDs/order had different scores (re-upsert with new\n\t\t\t\t// vector; query change preserving ranking order).\n\t\t\t\tequals: (a, b) => searchResultsEqual(a, b),\n\t\t\t\tmeta: memoryMeta(\"vector_search\"),\n\t\t\t},\n\t\t) as Node<readonly VectorSearchResult<TMeta>[]>;\n\t}\n\n\tconst out = Object.assign(graph, {\n\t\tbackend,\n\t\tevents,\n\t\tentries: entries.entries,\n\t\tupsert,\n\t\tremove,\n\t\tclear,\n\t\treindex,\n\t\tsearchNode,\n\t}) as VectorIndexGraph<TMeta>;\n\treturn out;\n}\n\n// ── Unit 5: knowledgeGraph ───────────────────────────────────────────────\n\nexport type KnowledgeEdge<TRelation extends string = string> = {\n\treadonly from: string;\n\treadonly to: string;\n\treadonly relation: TRelation;\n\treadonly weight: number;\n};\n\nexport type KnowledgeGraphOptions = {\n\t/** Cap on entity count (LRU-by-upsert-time when set). */\n\tentitiesMaxSize?: number;\n\t/** Cap on edge count (LRU-by-upsert-time when set). */\n\tedgesMaxSize?: number;\n\t/**\n\t * Orphan-entity garbage collection. `\"keep\"` (default) leaves entities\n\t * untouched when their last edge is unlinked; `\"remove\"` deletes the\n\t * entity post-`unlink` if no edges reference it.\n\t */\n\torphanGC?: \"keep\" | \"remove\";\n};\n\nexport interface KnowledgeGraphAuditRecord extends BaseAuditRecord {\n\treadonly action: \"upsertEntity\" | \"removeEntity\" | \"link\" | \"unlink\" | \"orphanRemove\";\n\treadonly id?: string;\n\treadonly from?: string;\n\treadonly to?: string;\n\treadonly relation?: string;\n\t/** Edge weight at the time of the `link`. Omitted for non-edge actions. */\n\treadonly weight?: number;\n}\n\nexport type KnowledgeGraph<TEntity, TRelation extends string = string> = Graph & {\n\treadonly events: ReactiveLogBundle<KnowledgeGraphAuditRecord>;\n\treadonly entities: Node<ReadonlyMap<string, TEntity>>;\n\treadonly edges: Node<ReadonlyMap<string, KnowledgeEdge<TRelation>>>;\n\treadonly adjacencyOut: Node<ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>>;\n\treadonly adjacencyIn: Node<ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>>;\n\treadonly entityCount: Node<number>;\n\treadonly edgeCount: Node<number>;\n\tupsertEntity: (id: string, value: TEntity) => void;\n\tremoveEntity: (id: string) => void;\n\tlink: (from: string, to: string, relation: TRelation, weight?: number) => void;\n\tunlink: (from: string, to: string, relation?: TRelation) => void;\n\trelatedNode: (\n\t\tid: NodeOrValue<string>,\n\t\trelation?: NodeOrValue<TRelation>,\n\t) => Node<readonly KnowledgeEdge<TRelation>[]>;\n};\n\nconst TRIPLE_SEP = \"\u0000\";\nfunction tripleKey(from: string, to: string, relation: string): string {\n\treturn `${from}${TRIPLE_SEP}${to}${TRIPLE_SEP}${relation}`;\n}\n\nfunction buildAdjacency<TRelation extends string>(\n\tedges: ReadonlyMap<string, KnowledgeEdge<TRelation>> | undefined,\n\tside: \"from\" | \"to\",\n): ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]> {\n\tif (!edges || edges.size === 0) return new Map();\n\tconst buckets = new Map<string, KnowledgeEdge<TRelation>[]>();\n\tfor (const edge of edges.values()) {\n\t\tconst key = side === \"from\" ? edge.from : edge.to;\n\t\tlet bucket = buckets.get(key);\n\t\tif (!bucket) {\n\t\t\tbucket = [];\n\t\t\tbuckets.set(key, bucket);\n\t\t}\n\t\tbucket.push(edge);\n\t}\n\tconst out = new Map<string, readonly KnowledgeEdge<TRelation>[]>();\n\tfor (const [key, bucket] of buckets) out.set(key, Object.freeze(bucket));\n\treturn out;\n}\n\nfunction adjacencyEqual<TRelation extends string>(\n\ta: ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]> | undefined,\n\tb: ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]> | undefined,\n): boolean {\n\tif (a === b) return true;\n\tif (a == null || b == null) return false;\n\tif (a.size !== b.size) return false;\n\tfor (const [k, av] of a) {\n\t\tconst bv = b.get(k);\n\t\tif (!bv || av.length !== bv.length) return false;\n\t\tfor (let i = 0; i < av.length; i += 1) {\n\t\t\tconst ae = av[i]!;\n\t\t\tconst be = bv[i]!;\n\t\t\tif (\n\t\t\t\tae.from !== be.from ||\n\t\t\t\tae.to !== be.to ||\n\t\t\t\tae.relation !== be.relation ||\n\t\t\t\tae.weight !== be.weight\n\t\t\t)\n\t\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\n/**\n * Reactive knowledge graph: entities + typed edges + symmetric adjacency.\n *\n * Topology (mounted on the returned graph):\n * - `entities` — `reactiveMap<id, TEntity>` (optional `entitiesMaxSize` LRU).\n * - `edges` — `reactiveMap<tripleKey, KnowledgeEdge<TRelation>>` keyed by\n * `${from}\u0000${to}\u0000${relation}` (optional `edgesMaxSize` LRU).\n * Entity IDs / relations must NOT contain `\u0000`.\n * - `adjacencyOut` — `Node<ReadonlyMap<from, readonly edge[]>>`. **Full O(E)\n * rebuild on every `link` / `unlink` mutation.** (Prior JSDoc claim of\n * \"O(E) build\" referred to a single rebuild — the per-mutation cost is\n * O(E), not O(1) amortized. For very large graphs with frequent edge\n * churn, consider batching via `reactiveMap.setMany`.)\n * - `adjacencyIn` — `Node<ReadonlyMap<to, readonly edge[]>>`. Same O(E) per\n * mutation rebuild characteristic.\n * - `entityCount` / `edgeCount` — observability deriveds.\n * - `events` — bounded reactive audit log.\n *\n * **`link()` semantics.** Calling `link(a, b, rel, w)` twice with different\n * weights replaces the weight on the existing edge (keyed by the triple).\n * `unlink` then `link` re-creates the edge (and bumps `lastUpsertNs` for\n * retention purposes).\n *\n * **Edge weight convention.** Higher weight = stronger relation. Default `1`.\n *\n * **Orphan GC.** `orphanGC: \"remove\"` deletes an entity from `entities` after\n * an `unlink` that empties its adjacency on both sides. Default `\"keep\"`.\n *\n * **No imperative reads.** Use `relatedNode(id, relation?)` for reactive reads.\n *\n * @category memory\n */\nexport function knowledgeGraph<TEntity, TRelation extends string = string>(\n\tname: string,\n\topts: KnowledgeGraphOptions = {},\n): KnowledgeGraph<TEntity, TRelation> {\n\tconst orphanGC = opts.orphanGC ?? \"keep\";\n\tif (opts.entitiesMaxSize !== undefined && opts.entitiesMaxSize < 1) {\n\t\tthrow new RangeError(\"knowledgeGraph: entitiesMaxSize must be >= 1\");\n\t}\n\tif (opts.edgesMaxSize !== undefined && opts.edgesMaxSize < 1) {\n\t\tthrow new RangeError(\"knowledgeGraph: edgesMaxSize must be >= 1\");\n\t}\n\n\tconst graph = new Graph(name);\n\n\tconst entitiesMap = reactiveMap<string, TEntity>({\n\t\tname: \"entities\",\n\t\t...(opts.entitiesMaxSize !== undefined ? { maxSize: opts.entitiesMaxSize } : {}),\n\t});\n\tconst edgesMap = reactiveMap<string, KnowledgeEdge<TRelation>>({\n\t\tname: \"edges\",\n\t\t...(opts.edgesMaxSize !== undefined ? { maxSize: opts.edgesMaxSize } : {}),\n\t});\n\tgraph.add(entitiesMap.entries, { name: \"entities\" });\n\tgraph.add(edgesMap.entries, { name: \"edges\" });\n\n\tconst adjacencyOut = node(\n\t\t[edgesMap.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0] as ReadonlyMap<string, KnowledgeEdge<TRelation>> | undefined;\n\t\t\tactions.emit(buildAdjacency<TRelation>(snapshot, \"from\"));\n\t\t},\n\t\t{\n\t\t\tname: \"adjacencyOut\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: new Map() as ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>,\n\t\t\tequals: adjacencyEqual,\n\t\t\tmeta: memoryMeta(\"adjacency_out\"),\n\t\t},\n\t) as Node<ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>>;\n\tconst adjacencyIn = node(\n\t\t[edgesMap.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0] as ReadonlyMap<string, KnowledgeEdge<TRelation>> | undefined;\n\t\t\tactions.emit(buildAdjacency<TRelation>(snapshot, \"to\"));\n\t\t},\n\t\t{\n\t\t\tname: \"adjacencyIn\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: new Map() as ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>,\n\t\t\tequals: adjacencyEqual,\n\t\t\tmeta: memoryMeta(\"adjacency_in\"),\n\t\t},\n\t) as Node<ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>>;\n\tgraph.add(adjacencyOut, { name: \"adjacencyOut\" });\n\tgraph.add(adjacencyIn, { name: \"adjacencyIn\" });\n\tgraph.addDisposer(keepalive(adjacencyOut));\n\tgraph.addDisposer(keepalive(adjacencyIn));\n\n\tconst entityCount = node(\n\t\t[entitiesMap.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst m = data[0] as ReadonlyMap<string, TEntity> | undefined;\n\t\t\tactions.emit(((m ?? new Map()) as ReadonlyMap<string, TEntity>).size);\n\t\t},\n\t\t{ name: \"entityCount\", describeKind: \"derived\", initial: 0, meta: memoryMeta(\"entity_count\") },\n\t);\n\tconst edgeCount = node(\n\t\t[edgesMap.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst m = data[0] as ReadonlyMap<string, KnowledgeEdge<TRelation>> | undefined;\n\t\t\tactions.emit(((m ?? new Map()) as ReadonlyMap<string, KnowledgeEdge<TRelation>>).size);\n\t\t},\n\t\t{ name: \"edgeCount\", describeKind: \"derived\", initial: 0, meta: memoryMeta(\"edge_count\") },\n\t);\n\tgraph.add(entityCount, { name: \"entityCount\" });\n\tgraph.add(edgeCount, { name: \"edgeCount\" });\n\tgraph.addDisposer(keepalive(entityCount));\n\tgraph.addDisposer(keepalive(edgeCount));\n\n\tconst events = createAuditLog<KnowledgeGraphAuditRecord>({\n\t\tname: \"events\",\n\t\tretainedLimit: 1024,\n\t\tgraph,\n\t});\n\tconst seqCursor = registerCursor(graph, \"seq\", 0);\n\n\t/**\n\t * O(1) orphan check via the kept-warm `adjacency*` deriveds. Reading\n\t * `adjacencyOut.cache` / `adjacencyIn.cache` is safe here because both\n\t * are activated via `addDisposer(keepalive(...))` at construction time\n\t * (a derived's RAM cache only persists with at least one subscriber, and\n\t * the keepalive registers exactly that). The previous implementation\n\t * scanned `edgesMap.entries.cache` post-`deleteMany`, which depended on\n\t * the (sync) snapshot-emit timing of `reactiveMap` — fragile. The\n\t * `adjacency*.cache` approach is both faster (O(1) vs O(E) per check)\n\t * and timing-robust because the reactiveMap snapshot has already\n\t * propagated through the derived chain by the time we read.\n\t */\n\tfunction entityHasReferences(id: string): boolean {\n\t\tconst out = adjacencyOut.cache as\n\t\t\t| ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>\n\t\t\t| undefined;\n\t\tconst inb = adjacencyIn.cache as\n\t\t\t| ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>\n\t\t\t| undefined;\n\t\tif ((out?.get(id)?.length ?? 0) > 0) return true;\n\t\tif ((inb?.get(id)?.length ?? 0) > 0) return true;\n\t\treturn false;\n\t}\n\n\t/**\n\t * Apply orphan GC to a list of candidate entity ids. Used by both\n\t * {@link unlinkImpl} (post-edge-removal) and {@link removeEntityImpl}\n\t * (post-cascade) so semantics are consistent. Each removed entity\n\t * records a separate `orphanRemove` audit entry with its own monotonic\n\t * `seq` value (D1 fix — the previous bare `events.append(...)` skipped\n\t * the cursor advance, leaving gaps in the audit replay sequence).\n\t */\n\tfunction applyOrphanGC(candidates: readonly string[]): void {\n\t\tif (orphanGC !== \"remove\") return;\n\t\tfor (const candidate of candidates) {\n\t\t\tif (!entitiesMap.has(candidate)) continue;\n\t\t\tif (entityHasReferences(candidate)) continue;\n\t\t\tentitiesMap.delete(candidate);\n\t\t\tevents.append({\n\t\t\t\taction: \"orphanRemove\" as const,\n\t\t\t\tid: candidate,\n\t\t\t\tt_ns: wallClockNs(),\n\t\t\t\tseq: bumpCursor(seqCursor),\n\t\t\t});\n\t\t}\n\t}\n\n\tconst upsertEntityImpl = (id: string, value: TEntity): void => {\n\t\tentitiesMap.set(id, value);\n\t};\n\tconst removeEntityImpl = (id: string): void => {\n\t\tconst snapshot = edgesMap.entries.cache as\n\t\t\t| ReadonlyMap<string, KnowledgeEdge<TRelation>>\n\t\t\t| undefined;\n\t\t// Collect both the edge-keys to drop AND the entity ids those edges\n\t\t// reference (other than `id` itself) — the latter become orphan-GC\n\t\t// candidates after the cascade. (C1 fix — the previous impl only\n\t\t// applied orphan GC inside `unlink`, so cascading entity removal\n\t\t// could leave dangling orphans.)\n\t\tconst cascadedNeighbors = new Set<string>();\n\t\tif (snapshot) {\n\t\t\tconst toDrop: string[] = [];\n\t\t\tfor (const [key, edge] of snapshot) {\n\t\t\t\tif (edge.from === id || edge.to === id) {\n\t\t\t\t\ttoDrop.push(key);\n\t\t\t\t\tif (edge.from !== id) cascadedNeighbors.add(edge.from);\n\t\t\t\t\tif (edge.to !== id) cascadedNeighbors.add(edge.to);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (toDrop.length > 0) edgesMap.deleteMany(toDrop);\n\t\t}\n\t\tif (entitiesMap.has(id)) entitiesMap.delete(id);\n\t\tapplyOrphanGC([...cascadedNeighbors]);\n\t};\n\tconst linkImpl = (from: string, to: string, relation: TRelation, weight = 1): void => {\n\t\tedgesMap.set(tripleKey(from, to, relation), { from, to, relation, weight });\n\t};\n\tconst unlinkImpl = (from: string, to: string, relation?: TRelation): void => {\n\t\tif (relation !== undefined) {\n\t\t\tedgesMap.delete(tripleKey(from, to, relation));\n\t\t} else {\n\t\t\tconst snapshot = edgesMap.entries.cache as\n\t\t\t\t| ReadonlyMap<string, KnowledgeEdge<TRelation>>\n\t\t\t\t| undefined;\n\t\t\tif (!snapshot) return;\n\t\t\tconst toDrop: string[] = [];\n\t\t\tfor (const [key, edge] of snapshot) {\n\t\t\t\tif (edge.from === from && edge.to === to) toDrop.push(key);\n\t\t\t}\n\t\t\tif (toDrop.length > 0) edgesMap.deleteMany(toDrop);\n\t\t}\n\t\tapplyOrphanGC([from, to]);\n\t};\n\n\tconst upsertEntity = mutate(upsertEntityImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({\n\t\t\taction: \"upsertEntity\" as const,\n\t\t\tid,\n\t\t\tt_ns: m.t_ns,\n\t\t\tseq: m.seq,\n\t\t}),\n\t});\n\tconst removeEntity = mutate(removeEntityImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({\n\t\t\taction: \"removeEntity\" as const,\n\t\t\tid,\n\t\t\tt_ns: m.t_ns,\n\t\t\tseq: m.seq,\n\t\t}),\n\t});\n\tconst link = mutate(linkImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([from, to, relation, weight], _r, m) => ({\n\t\t\taction: \"link\" as const,\n\t\t\tfrom,\n\t\t\tto,\n\t\t\trelation: relation as string,\n\t\t\tweight: weight ?? 1,\n\t\t\tt_ns: m.t_ns,\n\t\t\tseq: m.seq,\n\t\t}),\n\t});\n\tconst unlink = mutate(unlinkImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([from, to, relation], _r, m) => ({\n\t\t\taction: \"unlink\" as const,\n\t\t\tfrom,\n\t\t\tto,\n\t\t\t...(relation !== undefined ? { relation: relation as string } : {}),\n\t\t\tt_ns: m.t_ns,\n\t\t\tseq: m.seq,\n\t\t}),\n\t});\n\n\tfunction relatedNode(\n\t\tid: NodeOrValue<string>,\n\t\trelation?: NodeOrValue<TRelation>,\n\t): Node<readonly KnowledgeEdge<TRelation>[]> {\n\t\tconst idN = toNode(id, \"id\");\n\t\t// `relation` is OPTIONAL. We deliberately do NOT include it as a dep\n\t\t// when omitted — `state(undefined)` would be a SENTINEL and the\n\t\t// derived's first-run gate would never open. Callers pass a Node\n\t\t// when they want reactive filtering; pass a value to lock the\n\t\t// filter; omit to disable filtering.\n\t\tconst relN = relation !== undefined ? toNode(relation, \"relation\") : undefined;\n\t\tconst deps: Node<unknown>[] = relN\n\t\t\t? [adjacencyOut, adjacencyIn, idN, relN]\n\t\t\t: [adjacencyOut, adjacencyIn, idN];\n\t\treturn node(\n\t\t\tdeps,\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst values = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst out = values[0] as ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>;\n\t\t\t\tconst inb = values[1] as ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>;\n\t\t\t\tconst key = values[2] as string;\n\t\t\t\tconst rel = relN ? (values[3] as TRelation | undefined) : undefined;\n\t\t\t\tconst outE = out?.get(key) ?? [];\n\t\t\t\tconst inE = inb?.get(key) ?? [];\n\t\t\t\t// Concatenate, then dedupe by triple key (a self-loop would appear in both).\n\t\t\t\tconst seen = new Set<string>();\n\t\t\t\tconst acc: KnowledgeEdge<TRelation>[] = [];\n\t\t\t\tfor (const edge of outE) {\n\t\t\t\t\tconst k = tripleKey(edge.from, edge.to, edge.relation);\n\t\t\t\t\tif (seen.has(k)) continue;\n\t\t\t\t\tif (rel !== undefined && edge.relation !== rel) continue;\n\t\t\t\t\tseen.add(k);\n\t\t\t\t\tacc.push(edge);\n\t\t\t\t}\n\t\t\t\tfor (const edge of inE) {\n\t\t\t\t\tconst k = tripleKey(edge.from, edge.to, edge.relation);\n\t\t\t\t\tif (seen.has(k)) continue;\n\t\t\t\t\tif (rel !== undefined && edge.relation !== rel) continue;\n\t\t\t\t\tseen.add(k);\n\t\t\t\t\tacc.push(edge);\n\t\t\t\t}\n\t\t\t\tactions.emit(acc as readonly KnowledgeEdge<TRelation>[]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tequals: (a, b) => {\n\t\t\t\t\tconst av = a as readonly KnowledgeEdge<TRelation>[] | undefined;\n\t\t\t\t\tconst bv = b as readonly KnowledgeEdge<TRelation>[] | undefined;\n\t\t\t\t\tif (av === bv) return true;\n\t\t\t\t\tif (av == null || bv == null) return false;\n\t\t\t\t\tif (av.length !== bv.length) return false;\n\t\t\t\t\tfor (let i = 0; i < av.length; i += 1) {\n\t\t\t\t\t\tconst x = av[i]!;\n\t\t\t\t\t\tconst y = bv[i]!;\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tx.from !== y.from ||\n\t\t\t\t\t\t\tx.to !== y.to ||\n\t\t\t\t\t\t\tx.relation !== y.relation ||\n\t\t\t\t\t\t\tx.weight !== y.weight\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t},\n\t\t\t\tmeta: memoryMeta(\"related\"),\n\t\t\t},\n\t\t) as Node<readonly KnowledgeEdge<TRelation>[]>;\n\t}\n\n\tconst out = Object.assign(graph, {\n\t\tevents,\n\t\tentities: entitiesMap.entries,\n\t\tedges: edgesMap.entries,\n\t\tadjacencyOut,\n\t\tadjacencyIn,\n\t\tentityCount,\n\t\tedgeCount,\n\t\tupsertEntity,\n\t\tremoveEntity,\n\t\tlink,\n\t\tunlink,\n\t\trelatedNode,\n\t}) as KnowledgeGraph<TEntity, TRelation>;\n\treturn out;\n}\n\n// ── DS-14.7: reactiveFactStore (static-topology MEME L2/L3 substrate) ─────\n// Lives in its own file (`fact-store.ts`) — re-exported here so the\n// `utils/memory` barrel stays the single import surface alongside\n// collection / vectorIndex / knowledgeGraph.\nexport {\n\ttype AdmissionFilter,\n\ttype CascadeEvent,\n\ttype CascadeOverflow,\n\ttype CascadeReason,\n\ttype DecayPolicy,\n\ttype DependentsIndex,\n\ttype FactId,\n\ttype FactStore,\n\ttype FactStoreAuditRecord,\n\ttype MemoryAnswer,\n\ttype MemoryFragment,\n\ttype MemoryQuery,\n\ttype OutcomeSignal,\n\ttype ReactiveFactStoreConfig,\n\ttype ReactiveFactStoreGraph,\n\ttype ReviewRequest,\n\treactiveFactStore,\n\ttype ScoringPolicy,\n\ttype ShardKey,\n\ttype StoreReadHandle,\n} from \"./fact-store.js\";\n","// ---------------------------------------------------------------------------\n// gaugesAsContext\n// ---------------------------------------------------------------------------\n\nimport type { Actor } from \"@graphrefly/pure-ts/core\";\nimport type { Graph } from \"@graphrefly/pure-ts/graph\";\n\nexport type GaugesAsContextOptions = {\n\t/** Group gauges by `meta.tags` (default true). */\n\tgroupByTags?: boolean;\n\t/** Separator between gauge lines (default \"\\n\"). */\n\tseparator?: string;\n\t/**\n\t * V0 delta mode (§6.0b): only include nodes whose `v.version` exceeds\n\t * the corresponding entry in this map. Nodes without V0 or not in the\n\t * map are always included. Callers maintain this map across calls.\n\t *\n\t * The `id` field guards against node replacement: if a node is removed\n\t * and re-added under the same name (new id), it is always included.\n\t */\n\tsinceVersion?: ReadonlyMap<string, { id: string; version: number }>;\n};\n\n/**\n * Format a graph's readable (gauge) nodes as a context string for LLM\n * system prompts.\n *\n * Gauges are nodes with `meta.description` or `meta.format`. Values are\n * formatted using `meta.format` and `meta.unit` hints.\n *\n * @param graph - The graph to introspect.\n * @param actor - Optional actor for guard-scoped describe.\n * @param options - Formatting options.\n * @returns A formatted string ready for system prompt injection.\n */\nexport function gaugesAsContext(\n\tgraph: Graph,\n\tactor?: Actor,\n\toptions?: GaugesAsContextOptions,\n): string {\n\tconst described = graph.describe({ actor, detail: \"full\" });\n\tconst groupByTags = options?.groupByTags ?? true;\n\tconst separator = options?.separator ?? \"\\n\";\n\n\ttype GaugeEntry = { path: string; description: string; formatted: string };\n\tconst entries: GaugeEntry[] = [];\n\n\tconst sinceVersion = options?.sinceVersion;\n\tfor (const [path, node] of Object.entries(described.nodes)) {\n\t\tconst meta = node.meta ?? {};\n\t\tconst desc = meta.description as string | undefined;\n\t\tconst format = meta.format as string | undefined;\n\t\t// Must have description or format to be a gauge\n\t\tif (!desc && !format) continue;\n\t\t// V0 delta filter: skip nodes unchanged since last seen version (§6.0b).\n\t\tif (sinceVersion != null && node.v != null) {\n\t\t\tconst lastSeen = sinceVersion.get(path);\n\t\t\tif (lastSeen != null && lastSeen.id === node.v.id && node.v.version <= lastSeen.version)\n\t\t\t\tcontinue;\n\t\t}\n\n\t\tconst label = desc ?? path;\n\t\tconst value = node.value;\n\t\tconst unit = meta.unit as string | undefined;\n\n\t\tlet formatted: string;\n\t\tif (format === \"currency\" && typeof value === \"number\") {\n\t\t\tformatted = `$${value.toFixed(2)}`;\n\t\t} else if (format === \"percentage\" && typeof value === \"number\") {\n\t\t\tformatted = `${(value * 100).toFixed(1)}%`;\n\t\t} else if (value === undefined || value === null) {\n\t\t\tformatted = \"(no value)\";\n\t\t} else {\n\t\t\tformatted = String(value);\n\t\t}\n\n\t\tif (unit && format !== \"currency\" && format !== \"percentage\") {\n\t\t\tformatted = `${formatted} ${unit}`;\n\t\t}\n\n\t\tentries.push({ path, description: label, formatted });\n\t}\n\n\tif (entries.length === 0) return \"\";\n\n\tif (groupByTags) {\n\t\tconst tagGroups = new Map<string, GaugeEntry[]>();\n\t\tconst ungrouped: GaugeEntry[] = [];\n\n\t\tfor (const entry of entries) {\n\t\t\tconst node = described.nodes[entry.path]!;\n\t\t\tconst tags = node.meta?.tags as string[] | undefined;\n\t\t\tif (tags && tags.length > 0) {\n\t\t\t\t// Use first tag for grouping to avoid duplicating entries across groups\n\t\t\t\tconst tag = tags[0]!;\n\t\t\t\tlet group = tagGroups.get(tag);\n\t\t\t\tif (!group) {\n\t\t\t\t\tgroup = [];\n\t\t\t\t\ttagGroups.set(tag, group);\n\t\t\t\t}\n\t\t\t\tgroup.push(entry);\n\t\t\t} else {\n\t\t\t\tungrouped.push(entry);\n\t\t\t}\n\t\t}\n\n\t\tif (tagGroups.size === 0) {\n\t\t\treturn entries.map((e) => `- ${e.description}: ${e.formatted}`).join(separator);\n\t\t}\n\n\t\tconst sections: string[] = [];\n\t\tfor (const [tag, group] of [...tagGroups.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {\n\t\t\tsections.push(\n\t\t\t\t`[${tag}]${separator}${group.map((e) => `- ${e.description}: ${e.formatted}`).join(separator)}`,\n\t\t\t);\n\t\t}\n\t\tif (ungrouped.length > 0) {\n\t\t\tsections.push(ungrouped.map((e) => `- ${e.description}: ${e.formatted}`).join(separator));\n\t\t}\n\t\treturn sections.join(separator + separator);\n\t}\n\n\treturn entries.map((e) => `- ${e.description}: ${e.formatted}`).join(separator);\n}\n","// ---------------------------------------------------------------------------\n// graphFromSpec\n// ---------------------------------------------------------------------------\n\nimport { COMPLETE, ERROR, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { fromAny, type NodeInput, switchMap } from \"@graphrefly/pure-ts/extra\";\nimport type { Graph } from \"@graphrefly/pure-ts/graph\";\nimport { compileSpec, type GraphSpec, type GraphSpecCatalog } from \"../../graphspec/index.js\";\nimport { resolveToolHandlerResult, stripFences } from \"../_internal.js\";\nimport type { ChatMessage, LLMAdapter, LLMResponse } from \"../adapters/core/types.js\";\n\nexport type GraphFromSpecOptions = {\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\t/** Fn/source catalog for resolving named node factories from the LLM-generated spec. */\n\tcatalog?: GraphSpecCatalog;\n\t/** Extra instructions appended to the system prompt. */\n\tsystemPromptExtra?: string;\n\t/**\n\t * Optional AbortSignal forwarded to `adapter.invoke({ signal })`. Lets\n\t * callers cancel the in-flight LLM call (e.g. when the reactive variant\n\t * supersedes mid-flight). When the signal aborts, the underlying call\n\t * propagates the abort and `graphFromSpec` rejects with the abort reason.\n\t */\n\tsignal?: AbortSignal;\n};\n\nconst GRAPH_FROM_SPEC_SYSTEM_PROMPT = `You are a graph architect for GraphReFly, a reactive graph protocol.\n\nGiven a natural-language description, produce a JSON graph specification with this structure:\n\n{\n \"name\": \"<graph_name>\",\n \"nodes\": {\n \"<node_name>\": {\n \"type\": \"state\" | \"derived\" | \"producer\" | \"effect\" | \"operator\",\n \"initial\": <initial_value_for_state_nodes>,\n \"deps\": [\"<dep_node_name>\", ...],\n \"meta\": {\n \"description\": \"<human-readable purpose>\",\n \"type\": \"string\" | \"number\" | \"boolean\" | \"integer\" | \"enum\",\n \"range\": [min, max],\n \"values\": [\"a\", \"b\"],\n \"format\": \"currency\" | \"percentage\" | \"status\",\n \"access\": \"human\" | \"llm\" | \"both\" | \"system\",\n \"unit\": \"<unit>\",\n \"tags\": [\"<tag>\"]\n }\n }\n }\n}\n\nRules:\n- \"state\" nodes have no deps and hold user/LLM-writable values (knobs). Use \"initial\" for the starting value.\n- \"derived\" nodes have deps and compute from them (pure, no side effects).\n- \"effect\" nodes have deps but produce side effects (no return value).\n- \"producer\" nodes have no deps but generate values asynchronously.\n- \"operator\" nodes are parameterized transformations with deps.\n- Use \"deps\" inside each node to declare dependencies — no separate \"edges\" array.\n- meta.description is required for every node.\n- Return ONLY valid JSON, no markdown fences or commentary.`;\n\n/**\n * Ask an LLM to compose a Graph from a natural-language description.\n *\n * The LLM returns a JSON {@link GraphSpec} which is validated, catalog-expanded,\n * and instantiated via {@link compileSpec} (gains catalog validation, template\n * expansion, and feedback wiring that `Graph.fromSnapshot` bypasses).\n *\n * @param naturalLanguage - The problem/use-case description.\n * @param adapter - LLM adapter for the generation call.\n * @param opts - Model options and optional catalog for named node factories.\n * @returns A constructed Graph.\n * @throws On invalid LLM output, validation failure, or unresolvable deps.\n */\nexport async function graphFromSpec(\n\tnaturalLanguage: string,\n\tadapter: LLMAdapter,\n\topts?: GraphFromSpecOptions,\n): Promise<Graph> {\n\tconst systemPrompt = opts?.systemPromptExtra\n\t\t? `${GRAPH_FROM_SPEC_SYSTEM_PROMPT}\\n\\n${opts.systemPromptExtra}`\n\t\t: GRAPH_FROM_SPEC_SYSTEM_PROMPT;\n\n\tconst messages: ChatMessage[] = [\n\t\t{ role: \"system\", content: systemPrompt },\n\t\t{ role: \"user\", content: naturalLanguage },\n\t];\n\n\tconst rawResult = adapter.invoke(messages, {\n\t\tmodel: opts?.model,\n\t\ttemperature: opts?.temperature ?? 0,\n\t\tmaxTokens: opts?.maxTokens,\n\t\tsignal: opts?.signal,\n\t});\n\n\tconst response = (await resolveToolHandlerResult(rawResult)) as LLMResponse;\n\tlet content = response.content.trim();\n\n\t// Strip markdown fences if present (handles trailing commentary after ```)\n\tif (content.startsWith(\"```\")) {\n\t\tcontent = stripFences(content);\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(content);\n\t} catch {\n\t\tthrow new Error(`graphFromSpec: LLM response is not valid JSON: ${content.slice(0, 200)}`);\n\t}\n\n\treturn compileSpec(parsed as GraphSpec, { catalog: opts?.catalog });\n}\n\n/**\n * Reactive variant of {@link graphFromSpec}: re-invokes the LLM and\n * recompiles the graph whenever `input` emits a new natural-language\n * description. Useful inside the harness or refine loop when the spec text\n * itself is a reactive value (e.g. fed by a `node([], { initial: ... })` knob, a memory\n * snapshot, or an upstream `promptNode` output).\n *\n * **Supersede:** when the input changes mid-flight, switchMap tears the\n * inner producer down. The producer's cleanup aborts the in-flight LLM\n * call via an internal `AbortController` (threaded into `graphFromSpec`'s\n * new `signal` option) AND destroys any Graph that lands after cancel —\n * no token leak, no unreferenced compiled graphs. If the user's input\n * already changed by the time the LLM responds, the about-to-be-discarded\n * Graph is freed instead of orphaned.\n *\n * **Lifetime of the latest emitted Graph:** the caller owns each Graph\n * that actually reaches them. If you keep multiple historical values, call\n * `prev?.destroy()` before storing the new one.\n *\n * @param input - Reactive source of natural-language descriptions.\n * @param adapter - LLM adapter for the generation call.\n * @param opts - Model options and optional catalog for named node factories.\n * @returns `Node<Graph | null>` — emits the latest compiled graph, or `null`\n * while the input is empty / unsettled.\n */\nexport function graphFromSpecReactive(\n\tinput: NodeInput<string>,\n\tadapter: LLMAdapter,\n\topts?: GraphFromSpecOptions,\n): Node<Graph | null> {\n\tconst inputNode = fromAny(input);\n\treturn switchMap<string, Graph | null>(inputNode, (nl) => {\n\t\tif (!nl || typeof nl !== \"string\" || nl.trim().length === 0) {\n\t\t\treturn node<Graph | null>([], { initial: null });\n\t\t}\n\t\t// Producer guarantees a single DATA + COMPLETE per upstream wave —\n\t\t// matches the `promptNode` shape (see Unit 1 review). On supersede,\n\t\t// switchMap tears down the producer; cleanup aborts the in-flight LLM\n\t\t// call AND destroys any Graph that lands post-abort (would otherwise\n\t\t// leak its mounted state nodes / storage handles until GC).\n\t\treturn node<Graph | null>(\n\t\t\t(_data, actions) => {\n\t\t\t\tconst controller = new AbortController();\n\t\t\t\tlet cancelled = false;\n\t\t\t\tgraphFromSpec(nl, adapter, { ...opts, signal: controller.signal })\n\t\t\t\t\t.then((g) => {\n\t\t\t\t\t\tif (cancelled) {\n\t\t\t\t\t\t\tg.destroy();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tactions.emit(g);\n\t\t\t\t\t\tactions.down([[COMPLETE]]);\n\t\t\t\t\t})\n\t\t\t\t\t.catch((err) => {\n\t\t\t\t\t\tif (cancelled) return;\n\t\t\t\t\t\tactions.down([[ERROR, err]]);\n\t\t\t\t\t});\n\t\t\t\treturn () => {\n\t\t\t\t\tcancelled = true;\n\t\t\t\t\tcontroller.abort();\n\t\t\t\t};\n\t\t\t},\n\t\t\t{ describeKind: \"producer\", ...{ name: \"graphFromSpec::call\" } },\n\t\t);\n\t});\n}\n","/**\n * LLM graph composition (roadmap §8.3).\n *\n * Declarative GraphSpec schema + compiler/decompiler for graph topology.\n * The LLM designs graphs as JSON; `compileSpec` instantiates them;\n * `decompileSpec` extracts them back. Templates support reusable subgraph\n * patterns. Feedback edges express bounded cycles via §8.1 feedback().\n *\n * **Tier 1.5.3 Phase 3 (2026-04-27):** `GraphSpec` is a structural alias of\n * {@link GraphDescribeOutput} with two LLM-author-friendly extras\n * (`templates?` / `feedback?`). Per-node factory references are encoded in\n * `meta.factory` + `meta.factoryArgs` (no more `fn` / `source` / `config` /\n * `initial` fields). State node initial values live in\n * `meta.factoryArgs.initial` (state self-tags with\n * `factoryTag(\"state\", { initial })`).\n *\n * @module\n */\n\nimport type { DescribeNodeOutput } from \"@graphrefly/pure-ts/core\";\nimport { type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { GRAPH_META_SEGMENT, Graph, type GraphDescribeOutput } from \"@graphrefly/pure-ts/graph\";\nimport type { ChatMessage, LLMAdapter, LLMResponse } from \"../ai/index.js\";\nimport { feedback as feedbackPrimitive } from \"../reduction/index.js\";\n\n// ---------------------------------------------------------------------------\n// GraphSpec types — structural alias of GraphDescribeOutput\n// ---------------------------------------------------------------------------\n\n/**\n * A single node declaration in a GraphSpec — structural alias of\n * {@link DescribeNodeOutput}.\n *\n * Per-node factory provenance lives in `meta.factory` + `meta.factoryArgs`\n * (use {@link factoryTag} to stamp them at construction time). State node\n * initial values come through `meta.factoryArgs.initial` for tagged states,\n * with fallback to `value` (since spec projection retains state values).\n */\nexport type GraphSpecNode = DescribeNodeOutput;\n\n/** Template instantiation node — expanded at compile time. */\nexport type GraphSpecTemplateRef = {\n\ttype: \"template\";\n\t/** Name of the template to instantiate. */\n\ttemplate: string;\n\t/** Parameter bindings: template param name → node name. */\n\tbind: Record<string, string>;\n};\n\n/** A reusable subgraph pattern with parameter substitution. */\nexport type GraphSpecTemplate = {\n\t/** Parameter names (prefixed with $ in node refs). */\n\tparams: string[];\n\t/** Node declarations within the template. */\n\tnodes: Record<string, GraphSpecNode>;\n\t/** Which node's output is the template's output. */\n\toutput: string;\n};\n\n/** A feedback edge: bounded cycle from condition to reentry. */\nexport type GraphSpecFeedbackEdge = {\n\t/** Node whose DATA triggers the feedback. */\n\tfrom: string;\n\t/** State node that receives the feedback value. */\n\tto: string;\n\t/** Max iterations before stopping (default: 10). */\n\tmaxIterations?: number;\n};\n\n/**\n * Declarative graph topology for LLM composition (§8.3).\n *\n * Tier 1.5.3 Phase 3 (2026-04-27): structural alias of\n * {@link GraphDescribeOutput} extended with optional `templates` /\n * `feedback` fields for LLM-author convenience. Top-level `factory` /\n * `factoryArgs` (Phase 2.5 carry) ride along on every describe output.\n *\n * Round-trip property: `decompileSpec(g) === g.describe({ detail: \"spec\" })`\n * (modulo the small feedback-edge extraction sugar).\n */\nexport type GraphSpec = Omit<GraphDescribeOutput, \"nodes\" | \"expand\"> & {\n\t/** Node declarations (keyed by node name). Either a structural describe entry or a template ref. */\n\tnodes: Record<string, GraphSpecNode | GraphSpecTemplateRef>;\n\t/** Reusable subgraph templates (LLM-author extra; not present in `describe()` output). */\n\ttemplates?: Record<string, GraphSpecTemplate>;\n\t/** Feedback edges (bounded cycles, LLM-author extra). */\n\tfeedback?: GraphSpecFeedbackEdge[];\n};\n\n/**\n * Extract `meta.factory` from a node, if any. Pure read — no normalization.\n */\nfunction readFactory(node: GraphSpecNode): string | undefined {\n\tconst f = (node.meta as Record<string, unknown> | undefined)?.factory;\n\treturn typeof f === \"string\" ? f : undefined;\n}\n\n/**\n * Extract `meta.factoryArgs` from a node as a plain Record. Pure read.\n */\nfunction readFactoryArgs(node: GraphSpecNode): Record<string, unknown> {\n\tconst a = (node.meta as Record<string, unknown> | undefined)?.factoryArgs;\n\treturn a != null && typeof a === \"object\" ? (a as Record<string, unknown>) : {};\n}\n\n/**\n * Resolve the initial value for a state node. Prefers\n * `meta.factoryArgs.initial` (the path the `state()` factory itself stamps)\n * and falls back to `value` (in case the spec carries the resolved value\n * without a factory tag, e.g. from a hand-written spec).\n */\nfunction readStateInitial(node: GraphSpecNode): unknown {\n\tconst args = readFactoryArgs(node);\n\tif (\"initial\" in args) return args.initial;\n\treturn node.value;\n}\n\n// ---------------------------------------------------------------------------\n// Catalog types\n// ---------------------------------------------------------------------------\n\n/**\n * Factory for creating a derived/effect/operator node from catalog.\n * Receives resolved dep nodes and the config from the spec.\n */\nexport type FnFactory = (deps: Node<unknown>[], config: Record<string, unknown>) => Node<unknown>;\n\n/**\n * Factory for creating a producer node from catalog.\n * Receives the config from the spec.\n */\nexport type SourceFactory = (config: Record<string, unknown>) => Node<unknown>;\n\n// ---------------------------------------------------------------------------\n// Rich catalog entries (§9.1b — auto-prompt, catalog-aware validation)\n// ---------------------------------------------------------------------------\n\n/** Simple config field descriptor for LLM prompt generation and validation. */\nexport type ConfigFieldSchema = {\n\t/** Human-readable type: \"string\", \"number\", \"boolean\", \"string[]\", etc. */\n\ttype: string;\n\t/** Whether this field is required (default: true). */\n\trequired?: boolean;\n\t/** Allowed values (enum constraint). */\n\tenum?: readonly (string | number | boolean)[];\n\t/** Human-readable description for LLM context. */\n\tdescription?: string;\n\t/** Default value if omitted. */\n\tdefault?: unknown;\n};\n\n/**\n * Rich catalog entry: bundles a runtime factory with LLM-facing metadata.\n *\n * The metadata is used to:\n * 1. Auto-generate prompt text for {@link llmCompose} (replaces manual `catalogDescription`)\n * 2. Validate LLM output in {@link validateSpec} (catch wrong fn names, invalid config)\n * 3. Provide actionable error messages for {@link llmRefine} feedback loops\n *\n * Developers register ONE object; the library handles prompt generation and validation.\n */\nexport type CatalogFnEntry = {\n\t/** Runtime factory. */\n\tfactory: FnFactory;\n\t/** One-line description for LLM prompt (what it does, not how). */\n\tdescription: string;\n\t/** Config field schemas. Keys are config field names. */\n\tconfigSchema?: Record<string, ConfigFieldSchema>;\n\t/** Example config objects (shown in prompt for complex fns). */\n\texamples?: Record<string, unknown>[];\n\t/** Category tags for grouping in prompt (e.g., \"resilience\", \"reduction\", \"ai\"). */\n\ttags?: string[];\n};\n\n/** Rich catalog entry for producer sources. */\nexport type CatalogSourceEntry = {\n\t/** Runtime factory. */\n\tfactory: SourceFactory;\n\t/** One-line description for LLM prompt. */\n\tdescription: string;\n\t/** Config field schemas. */\n\tconfigSchema?: Record<string, ConfigFieldSchema>;\n\t/** Example config objects. */\n\texamples?: Record<string, unknown>[];\n\t/** Category tags. */\n\ttags?: string[];\n};\n\n/**\n * Top-level Graph factory — used when a spec was produced from a graph that\n * called `Graph.prototype.tagFactory(name, args)`. The catalog supplies a\n * function that takes the recorded `factoryArgs` (JSON-serializable subset)\n * and returns a fully-wired Graph. Runtime context (LLMAdapter instances,\n * callbacks, embedders) is captured by the closure — the args themselves are\n * a documentation fragment, not a complete construction recipe.\n *\n * Tier 1.5.3 Phase 2.5 (DG1=B, 2026-04-27).\n */\nexport type GraphSpecFactory = (factoryArgs: unknown) => Graph;\n\n/**\n * Fn/source lookup table passed to compileSpec and llmCompose.\n *\n * Accepts both bare factories (backward-compatible) and rich {@link CatalogFnEntry}\n * / {@link CatalogSourceEntry} objects. When rich entries are provided, the library\n * auto-generates LLM prompts and validates LLM output against the catalog.\n *\n * `graphFactories` (Tier 1.5.3 Phase 2.5) handles top-level Graph-returning\n * factories — when `spec.factory` matches a key, `compileSpec` delegates the\n * entire reconstruction to that factory.\n */\nexport type GraphSpecCatalog = {\n\tfns?: Record<string, FnFactory | CatalogFnEntry>;\n\tsources?: Record<string, SourceFactory | CatalogSourceEntry>;\n\tgraphFactories?: Record<string, GraphSpecFactory>;\n};\n\n// ---------------------------------------------------------------------------\n// Catalog helpers\n// ---------------------------------------------------------------------------\n\n/** Type guard: is this a rich catalog fn entry (vs bare factory)? */\nexport function isRichFnEntry(entry: FnFactory | CatalogFnEntry): entry is CatalogFnEntry {\n\treturn typeof entry === \"object\" && entry !== null && \"factory\" in entry;\n}\n\n/** Type guard: is this a rich catalog source entry (vs bare factory)? */\nexport function isRichSourceEntry(\n\tentry: SourceFactory | CatalogSourceEntry,\n): entry is CatalogSourceEntry {\n\treturn typeof entry === \"object\" && entry !== null && \"factory\" in entry;\n}\n\n/** Extract the runtime factory from a catalog entry (rich or bare). */\nexport function extractFnFactory(entry: FnFactory | CatalogFnEntry): FnFactory {\n\treturn isRichFnEntry(entry) ? entry.factory : entry;\n}\n\n/** Extract the runtime factory from a catalog source entry (rich or bare). */\nexport function extractSourceFactory(entry: SourceFactory | CatalogSourceEntry): SourceFactory {\n\treturn isRichSourceEntry(entry) ? entry.factory : entry;\n}\n\n/**\n * Auto-generate catalog prompt text from rich catalog entries.\n *\n * Groups fns by tag, formats each as `- name: description. Config: { ... }`.\n * Falls back to listing names only for bare factories.\n */\nexport function generateCatalogPrompt(catalog: GraphSpecCatalog): string {\n\tconst sections: string[] = [];\n\n\tif (catalog.fns) {\n\t\t// Group by first tag (or \"Other\")\n\t\tconst groups = new Map<string, string[]>();\n\t\tfor (const [name, entry] of Object.entries(catalog.fns)) {\n\t\t\tconst tag = isRichFnEntry(entry) ? (entry.tags?.[0] ?? \"Other\") : \"Other\";\n\t\t\tif (!groups.has(tag)) groups.set(tag, []);\n\t\t\tgroups.get(tag)!.push(formatFnEntry(name, entry));\n\t\t}\n\t\tfor (const [tag, lines] of groups) {\n\t\t\tsections.push(`${tag}:\\n${lines.join(\"\\n\")}`);\n\t\t}\n\t}\n\n\tif (catalog.sources) {\n\t\tconst lines: string[] = [];\n\t\tfor (const [name, entry] of Object.entries(catalog.sources)) {\n\t\t\tlines.push(formatSourceEntry(name, entry));\n\t\t}\n\t\tif (lines.length > 0) {\n\t\t\tsections.push(`Sources:\\n${lines.join(\"\\n\")}`);\n\t\t}\n\t}\n\n\treturn sections.join(\"\\n\\n\");\n}\n\nfunction formatFnEntry(name: string, entry: FnFactory | CatalogFnEntry): string {\n\tif (!isRichFnEntry(entry)) return `- ${name}`;\n\tlet line = `- ${name}: ${entry.description}`;\n\tif (entry.configSchema) {\n\t\tconst fields = Object.entries(entry.configSchema).map(([k, v]) => {\n\t\t\tlet desc = `${k}: ${v.type}`;\n\t\t\tif (v.enum) desc += ` (${v.enum.join(\"|\")})`;\n\t\t\tif (v.required === false) desc += \"?\";\n\t\t\treturn desc;\n\t\t});\n\t\tline += `. Config: { ${fields.join(\", \")} }`;\n\t}\n\treturn line;\n}\n\nfunction formatSourceEntry(name: string, entry: SourceFactory | CatalogSourceEntry): string {\n\tif (!isRichSourceEntry(entry)) return `- ${name}`;\n\tlet line = `- ${name}: ${entry.description}`;\n\tif (entry.configSchema) {\n\t\tconst fields = Object.entries(entry.configSchema).map(([k, v]) => {\n\t\t\tlet desc = `${k}: ${v.type}`;\n\t\t\tif (v.required === false) desc += \"?\";\n\t\t\treturn desc;\n\t\t});\n\t\tline += `. Config: { ${fields.join(\", \")} }`;\n\t}\n\treturn line;\n}\n\n/**\n * Validate a GraphSpec against a catalog.\n *\n * Checks that fn/source names reference actual catalog entries, and validates\n * config fields against configSchema when rich entries are available.\n * Returns additional errors beyond structural {@link validateSpec} checks.\n */\nexport function validateSpecAgainstCatalog(\n\tspec: GraphSpec,\n\tcatalog: GraphSpecCatalog,\n): GraphSpecValidation {\n\tconst errors: string[] = [];\n\tconst fnNames = new Set(Object.keys(catalog.fns ?? {}));\n\tconst sourceNames = new Set(Object.keys(catalog.sources ?? {}));\n\n\tfor (const [nodeName, nodeRaw] of Object.entries(spec.nodes)) {\n\t\tif (nodeRaw.type === \"template\") continue;\n\t\tconst node = nodeRaw as GraphSpecNode;\n\t\tconst factoryName = readFactory(node);\n\t\tif (factoryName == null) continue;\n\n\t\tconst isProducer = node.type === \"producer\";\n\t\t// State nodes self-tag with `factory: \"state\"` — never expected to live\n\t\t// in the catalog. Skip.\n\t\tif (node.type === \"state\" && factoryName === \"state\") continue;\n\n\t\t// Producers may resolve via either sources (preferred) or fns; non-\n\t\t// producers only resolve via fns. Mismatched-side suggestions (e.g.\n\t\t// using a source name on a derived node) match the legacy diagnostic.\n\t\tif (isProducer) {\n\t\t\tconst inSources = sourceNames.has(factoryName);\n\t\t\tconst inFns = fnNames.has(factoryName);\n\t\t\tif (!inSources && !inFns && (sourceNames.size > 0 || fnNames.size > 0)) {\n\t\t\t\tconst suggestion =\n\t\t\t\t\tfindClosest(factoryName, sourceNames) ?? findClosest(factoryName, fnNames);\n\t\t\t\terrors.push(\n\t\t\t\t\t`Node \"${nodeName}\": source \"${factoryName}\" not found in catalog` +\n\t\t\t\t\t\t(suggestion ? `. Did you mean \"${suggestion}\"?` : \"\"),\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\tif (fnNames.size > 0 && !fnNames.has(factoryName)) {\n\t\t\t\tif (sourceNames.has(factoryName)) {\n\t\t\t\t\terrors.push(\n\t\t\t\t\t\t`Node \"${nodeName}\": fn \"${factoryName}\" is a source, not a function. ` +\n\t\t\t\t\t\t\t`Use it as a producer source instead, or use a function from: ${[...fnNames].join(\", \")}`,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tconst suggestion = findClosest(factoryName, fnNames);\n\t\t\t\t\terrors.push(\n\t\t\t\t\t\t`Node \"${nodeName}\": fn \"${factoryName}\" not found in catalog` +\n\t\t\t\t\t\t\t(suggestion ? `. Did you mean \"${suggestion}\"?` : \"\"),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Validate config (`meta.factoryArgs`) against schema (if rich entry).\n\t\tconst factoryArgs = readFactoryArgs(node);\n\t\tif (!isProducer && catalog.fns?.[factoryName]) {\n\t\t\tconst entry = catalog.fns[factoryName];\n\t\t\tif (isRichFnEntry(entry) && entry.configSchema) {\n\t\t\t\tfor (const [field, schema] of Object.entries(entry.configSchema)) {\n\t\t\t\t\tif (schema.required !== false && !(field in factoryArgs)) {\n\t\t\t\t\t\terrors.push(`Node \"${nodeName}\": config missing required field \"${field}\"`);\n\t\t\t\t\t}\n\t\t\t\t\tif (field in factoryArgs && schema.enum) {\n\t\t\t\t\t\tconst val = factoryArgs[field];\n\t\t\t\t\t\tif (!schema.enum.includes(val as string | number | boolean)) {\n\t\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t\t`Node \"${nodeName}\": config.${field} = ${JSON.stringify(val)}, ` +\n\t\t\t\t\t\t\t\t\t`expected one of: ${schema.enum.join(\", \")}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (isProducer && catalog.sources?.[factoryName]) {\n\t\t\tconst entry = catalog.sources[factoryName];\n\t\t\tif (isRichSourceEntry(entry) && entry.configSchema) {\n\t\t\t\tfor (const [field, schema] of Object.entries(entry.configSchema)) {\n\t\t\t\t\tif (schema.required !== false && !(field in factoryArgs)) {\n\t\t\t\t\t\terrors.push(`Node \"${nodeName}\": config missing required field \"${field}\"`);\n\t\t\t\t\t}\n\t\t\t\t\tif (field in factoryArgs && schema.enum) {\n\t\t\t\t\t\tconst val = factoryArgs[field];\n\t\t\t\t\t\tif (!schema.enum.includes(val as string | number | boolean)) {\n\t\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t\t`Node \"${nodeName}\": config.${field} = ${JSON.stringify(val)}, ` +\n\t\t\t\t\t\t\t\t\t`expected one of: ${schema.enum.join(\", \")}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Also check template inner nodes\n\tif (spec.templates) {\n\t\tfor (const [tName, template] of Object.entries(spec.templates)) {\n\t\t\tfor (const [nodeName, node] of Object.entries(template.nodes)) {\n\t\t\t\tconst factoryName = readFactory(node);\n\t\t\t\tif (factoryName == null) continue;\n\t\t\t\tif (node.type === \"state\" && factoryName === \"state\") continue;\n\t\t\t\tif (node.type === \"producer\") continue; // template producer/source skipped (parity with legacy)\n\t\t\t\tif (fnNames.size > 0 && !fnNames.has(factoryName)) {\n\t\t\t\t\tconst suggestion = findClosest(factoryName, fnNames);\n\t\t\t\t\terrors.push(\n\t\t\t\t\t\t`Template \"${tName}\" node \"${nodeName}\": fn \"${factoryName}\" not found in catalog` +\n\t\t\t\t\t\t\t(suggestion ? `. Did you mean \"${suggestion}\"?` : \"\"),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { valid: errors.length === 0, errors, warnings: [] };\n}\n\n/** Simple Levenshtein-based closest match for \"did you mean?\" suggestions. */\nfunction findClosest(input: string, candidates: Set<string>): string | null {\n\tlet best: string | null = null;\n\tlet bestDist = Infinity;\n\tconst lower = input.toLowerCase();\n\tfor (const c of candidates) {\n\t\tconst dist = levenshtein(lower, c.toLowerCase());\n\t\tif (dist < bestDist && dist <= Math.max(3, Math.floor(input.length / 2))) {\n\t\t\tbestDist = dist;\n\t\t\tbest = c;\n\t\t}\n\t}\n\treturn best;\n}\n\nfunction levenshtein(a: string, b: string): number {\n\tconst m = a.length;\n\tconst n = b.length;\n\tconst dp: number[][] = Array.from({ length: m + 1 }, (_, i) =>\n\t\tArray.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)),\n\t);\n\tfor (let i = 1; i <= m; i++) {\n\t\tfor (let j = 1; j <= n; j++) {\n\t\t\tdp[i][j] =\n\t\t\t\ta[i - 1] === b[j - 1]\n\t\t\t\t\t? dp[i - 1][j - 1]\n\t\t\t\t\t: 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);\n\t\t}\n\t}\n\treturn dp[m][n];\n}\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\n/** Validation result from {@link validateSpec}. */\nexport type GraphSpecValidation = {\n\tvalid: boolean;\n\terrors: string[];\n\t/**\n\t * Non-fatal advisories. Currently includes feedback edges whose `from`\n\t * refers to an `effect` node (effects produce no DATA — the feedback\n\t * counter will never advance). Always present (empty array when nothing\n\t * is flagged) — symmetry with `errors` so callers can read\n\t * `result.warnings.length` without a null check.\n\t */\n\twarnings: string[];\n};\n\nconst VALID_NODE_TYPES = new Set([\n\t\"state\",\n\t\"producer\",\n\t\"derived\",\n\t\"effect\",\n\t\"operator\",\n\t\"template\",\n]);\n\nconst INNER_NODE_TYPES = new Set([\"state\", \"producer\", \"derived\", \"effect\", \"operator\"]);\n\n/**\n * Validate a GraphSpec JSON object.\n *\n * Checks structural validity: required fields, node types, dep references,\n * template references, feedback edge targets, self-cycles, and bind completeness.\n *\n * **Effect-node feedback advisory (C24-3).** When a feedback edge's `from`\n * refers to an `effect` node, the validator flags it via `warnings` (not\n * `errors`) — effect nodes produce no DATA emission, so a feedback counter\n * targeting one will never advance. The spec compiles either way; the\n * advisory exists because the misconfiguration is silent at runtime\n * (counter at 0 forever) without it.\n */\nexport function validateSpec(spec: unknown): GraphSpecValidation {\n\tconst errors: string[] = [];\n\tconst warnings: string[] = [];\n\n\tif (spec == null || typeof spec !== \"object\") {\n\t\treturn { valid: false, errors: [\"GraphSpec must be a non-null object\"], warnings };\n\t}\n\n\tconst s = spec as Record<string, unknown>;\n\n\tif (typeof s.name !== \"string\" || s.name.length === 0) {\n\t\terrors.push(\"Missing or empty 'name' field\");\n\t}\n\n\tif (s.nodes == null || typeof s.nodes !== \"object\" || Array.isArray(s.nodes)) {\n\t\terrors.push(\"Missing or invalid 'nodes' field (must be an object)\");\n\t\treturn { valid: false, errors, warnings };\n\t}\n\n\tconst nodeNames = new Set(Object.keys(s.nodes as object));\n\tconst nodeTypes = new Map<string, string>();\n\tconst templateDefs = new Map<string, { params: string[] }>();\n\n\t// Pre-scan template definitions for param validation\n\tif (s.templates != null && typeof s.templates === \"object\" && !Array.isArray(s.templates)) {\n\t\tfor (const [tName, tRaw] of Object.entries(s.templates as Record<string, unknown>)) {\n\t\t\tif (tRaw != null && typeof tRaw === \"object\") {\n\t\t\t\tconst t = tRaw as Record<string, unknown>;\n\t\t\t\ttemplateDefs.set(tName, {\n\t\t\t\t\tparams: Array.isArray(t.params) ? (t.params as string[]) : [],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// Validate templates\n\tif (s.templates != null) {\n\t\tif (typeof s.templates !== \"object\" || Array.isArray(s.templates)) {\n\t\t\terrors.push(\"'templates' must be an object\");\n\t\t} else {\n\t\t\tfor (const [tName, tRaw] of Object.entries(s.templates as Record<string, unknown>)) {\n\t\t\t\tif (tRaw == null || typeof tRaw !== \"object\") {\n\t\t\t\t\terrors.push(`Template \"${tName}\": must be an object`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst t = tRaw as Record<string, unknown>;\n\t\t\t\tif (!Array.isArray(t.params)) {\n\t\t\t\t\terrors.push(`Template \"${tName}\": missing 'params' array`);\n\t\t\t\t}\n\t\t\t\tif (t.nodes == null || typeof t.nodes !== \"object\" || Array.isArray(t.nodes)) {\n\t\t\t\t\terrors.push(`Template \"${tName}\": missing or invalid 'nodes' object`);\n\t\t\t\t} else {\n\t\t\t\t\tconst paramSet = new Set(Array.isArray(t.params) ? (t.params as string[]) : []);\n\t\t\t\t\tconst innerNames = new Set(Object.keys(t.nodes as object));\n\t\t\t\t\tfor (const [nName, nRaw] of Object.entries(t.nodes as Record<string, unknown>)) {\n\t\t\t\t\t\tif (nRaw == null || typeof nRaw !== \"object\") {\n\t\t\t\t\t\t\terrors.push(`Template \"${tName}\" node \"${nName}\": must be an object`);\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst n = nRaw as Record<string, unknown>;\n\t\t\t\t\t\tif (typeof n.type !== \"string\" || !INNER_NODE_TYPES.has(n.type)) {\n\t\t\t\t\t\t\terrors.push(`Template \"${tName}\" node \"${nName}\": invalid type`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (Array.isArray(n.deps)) {\n\t\t\t\t\t\t\tfor (const dep of n.deps as string[]) {\n\t\t\t\t\t\t\t\tif (!innerNames.has(dep) && !paramSet.has(dep)) {\n\t\t\t\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t\t\t\t`Template \"${tName}\" node \"${nName}\": dep \"${dep}\" is not an inner node or param`,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (typeof t.output !== \"string\") {\n\t\t\t\t\t\terrors.push(`Template \"${tName}\": missing 'output' string`);\n\t\t\t\t\t} else if (!(t.nodes as Record<string, unknown>)[t.output as string]) {\n\t\t\t\t\t\terrors.push(`Template \"${tName}\": output \"${t.output}\" is not a declared node`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Validate nodes\n\tfor (const [name, raw] of Object.entries(s.nodes as Record<string, unknown>)) {\n\t\tif (raw == null || typeof raw !== \"object\") {\n\t\t\terrors.push(`Node \"${name}\": must be an object`);\n\t\t\tcontinue;\n\t\t}\n\t\tconst n = raw as Record<string, unknown>;\n\t\tif (typeof n.type !== \"string\" || !VALID_NODE_TYPES.has(n.type)) {\n\t\t\terrors.push(\n\t\t\t\t`Node \"${name}\": invalid type \"${String(n.type)}\" (expected: ${[...VALID_NODE_TYPES].join(\", \")})`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\t\tnodeTypes.set(name, n.type);\n\n\t\tif (n.type === \"template\") {\n\t\t\tif (typeof n.template !== \"string\" || !templateDefs.has(n.template)) {\n\t\t\t\terrors.push(`Node \"${name}\": template \"${String(n.template)}\" not found in templates`);\n\t\t\t} else {\n\t\t\t\t// Check bind completeness: all template params must be bound\n\t\t\t\tif (n.bind == null || typeof n.bind !== \"object\" || Array.isArray(n.bind)) {\n\t\t\t\t\terrors.push(`Node \"${name}\": template ref requires 'bind' object`);\n\t\t\t\t} else {\n\t\t\t\t\tconst tmpl = templateDefs.get(n.template as string)!;\n\t\t\t\t\tconst bind = n.bind as Record<string, string>;\n\t\t\t\t\tfor (const param of tmpl.params) {\n\t\t\t\t\t\tif (!(param in bind)) {\n\t\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t\t`Node \"${name}\": template param \"${param}\" is not bound (template \"${n.template}\")`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfor (const [, target] of Object.entries(bind)) {\n\t\t\t\t\t\tif (typeof target === \"string\" && !nodeNames.has(target)) {\n\t\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t\t`Node \"${name}\": bind target \"${target}\" does not reference an existing node`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif (Array.isArray(n.deps)) {\n\t\t\t\tfor (const dep of n.deps as string[]) {\n\t\t\t\t\t// Self-referencing dep\n\t\t\t\t\tif (dep === name) {\n\t\t\t\t\t\terrors.push(`Node \"${name}\": self-referencing dep`);\n\t\t\t\t\t} else if (!nodeNames.has(dep)) {\n\t\t\t\t\t\terrors.push(`Node \"${name}\": dep \"${dep}\" does not reference an existing node`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Warn: derived/effect/operator without deps\n\t\t\tif (\n\t\t\t\t(n.type === \"derived\" || n.type === \"effect\" || n.type === \"operator\") &&\n\t\t\t\t!Array.isArray(n.deps)\n\t\t\t) {\n\t\t\t\terrors.push(`Node \"${name}\": ${n.type} node should have a 'deps' array`);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Validate feedback edges\n\tif (s.feedback != null) {\n\t\tif (!Array.isArray(s.feedback)) {\n\t\t\terrors.push(\"'feedback' must be an array\");\n\t\t} else {\n\t\t\tfor (let i = 0; i < (s.feedback as unknown[]).length; i++) {\n\t\t\t\tconst edge = (s.feedback as unknown[])[i];\n\t\t\t\tif (edge == null || typeof edge !== \"object\") {\n\t\t\t\t\terrors.push(`Feedback [${i}]: must be an object`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst e = edge as Record<string, unknown>;\n\t\t\t\tif (typeof e.from !== \"string\" || !nodeNames.has(e.from)) {\n\t\t\t\t\terrors.push(\n\t\t\t\t\t\t`Feedback [${i}]: 'from' \"${String(e.from)}\" does not reference an existing node`,\n\t\t\t\t\t);\n\t\t\t\t} else if (nodeTypes.get(e.from) === \"effect\") {\n\t\t\t\t\t// Effect nodes produce no DATA — a feedback edge from one will\n\t\t\t\t\t// never trigger the counter / re-entry. Almost certainly a\n\t\t\t\t\t// modelling mistake (caller probably meant the upstream\n\t\t\t\t\t// derived/state node). Warn but don't reject — the spec is\n\t\t\t\t\t// structurally valid; some advanced uses might still be ok.\n\t\t\t\t\twarnings.push(\n\t\t\t\t\t\t`Feedback [${i}]: 'from' \"${e.from}\" is an effect node — effects emit no DATA, so the feedback edge will never fire. Did you mean a derived/state node upstream?`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (typeof e.from === \"string\" && e.from === e.to) {\n\t\t\t\t\terrors.push(`Feedback [${i}]: 'from' and 'to' must be different nodes`);\n\t\t\t\t}\n\t\t\t\tif (typeof e.to !== \"string\" || !nodeNames.has(e.to)) {\n\t\t\t\t\terrors.push(\n\t\t\t\t\t\t`Feedback [${i}]: 'to' \"${String(e.to)}\" does not reference an existing node`,\n\t\t\t\t\t);\n\t\t\t\t} else if (typeof e.to === \"string\" && nodeTypes.get(e.to) !== \"state\") {\n\t\t\t\t\terrors.push(\n\t\t\t\t\t\t`Feedback [${i}]: 'to' node \"${e.to}\" must be a state node (got \"${nodeTypes.get(e.to) ?? \"unknown\"}\")`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tvalid: errors.length === 0,\n\t\terrors,\n\t\twarnings,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// validateOwnership — multi-agent subgraph ownership PR lint (DS-14.5.A #5)\n// ---------------------------------------------------------------------------\n\n/**\n * Read `meta.owner` from a spec node. Pure read — no normalization.\n * Empty / non-string is treated as \"no annotation\" (silent, INV-OWNER-2).\n */\nfunction readOwner(node: GraphSpecNode): string | undefined {\n\tconst o = (node.meta as Record<string, unknown> | undefined)?.owner;\n\treturn typeof o === \"string\" && o.length > 0 ? o : undefined;\n}\n\n/**\n * The change-set fed to {@link validateOwnership}. Mirrors the minimal slice\n * of a PR diff the lint needs: the set of factory identifiers whose\n * implementation the diff touches, plus the PR author and (optionally) the\n * raw commit-message text so the `Override-Owner:` trailer can be detected.\n *\n * **Why factory-keyed (not path-keyed) — locked decision (DS-14.5.A Q5\n * sub-flag).** PR-diff → spec-node mapping resolves through `meta.factory`\n * provenance, NOT a `meta.ownerPath` glob. A diff that edits the\n * implementation of factory `\"rateLimiter\"` maps to *every* spec node whose\n * `meta.factory === \"rateLimiter\"`. This reuses the existing\n * `factoryTag` / `decompileSpec` round-trip (the same `meta.factory` field\n * `compileSpec` consumes) — no parallel ownership-path indexing scheme.\n */\nexport type OwnershipPrDiff = {\n\t/**\n\t * Factory identifiers (the `meta.factory` value) whose source the PR\n\t * modifies. A spec node is \"edited by this PR\" iff its `meta.factory` is\n\t * in this set. Nodes without `meta.factory` cannot be mapped from a code\n\t * diff and are therefore never flagged (silent — consistent with the\n\t * un-annotated rule).\n\t */\n\treadonly editedFactories: readonly string[];\n\t/** PR author's `Actor.id`. Compared against each edited node's `meta.owner`. */\n\treadonly author: string;\n\t/**\n\t * Raw commit message(s) text. If any line is an `Override-Owner: <reason>`\n\t * trailer (case-insensitive key, non-empty reason) the lint hard-fail is\n\t * bypassed and recorded as an audit-trail override (Q5 sub-lock i — any\n\t * committer may use it; it is recorded, never silently granted).\n\t */\n\treadonly commitMessage?: string;\n};\n\n/** One cross-owner violation surfaced by {@link validateOwnership}. */\nexport type OwnershipViolation = {\n\t/** Spec node path that carries `meta.owner` and was edited by a non-owner. */\n\treadonly node: string;\n\t/** The `meta.owner` value on that node. */\n\treadonly owner: string;\n\t/** The PR author who edited it. */\n\treadonly author: string;\n\t/** The `meta.factory` that mapped the diff onto this node. */\n\treadonly factory: string;\n};\n\n/** Result of {@link validateOwnership}. */\nexport type OwnershipValidation = {\n\t/**\n\t * `true` when no hard-fail applies — either no cross-owner edit, or every\n\t * cross-owner edit is bypassed by a valid `Override-Owner:` trailer.\n\t */\n\treadonly ok: boolean;\n\t/** Cross-owner edits that hard-fail (empty when `ok`). */\n\treadonly violations: readonly OwnershipViolation[];\n\t/**\n\t * Cross-owner edits that WOULD have failed but were bypassed by an\n\t * `Override-Owner:` commit trailer. Pure audit trail — CI / reviewers\n\t * grep this to surface override abuse. Present (possibly empty) so callers\n\t * can read `.overridden.length` without a null check.\n\t */\n\treadonly overridden: readonly OwnershipViolation[];\n\t/**\n\t * The override reason parsed from the `Override-Owner:` trailer, when one\n\t * was present and applied. `undefined` when no trailer was used.\n\t */\n\treadonly overrideReason?: string;\n};\n\nconst OVERRIDE_OWNER_TRAILER = /^\\s*override-owner\\s*:\\s*(.+?)\\s*$/im;\n\n/**\n * Detect an `Override-Owner: <reason>` commit trailer (case-insensitive key;\n * reason must be non-empty after trim). Returns the trimmed reason, or\n * `undefined` when absent.\n */\nfunction parseOverrideOwner(commitMessage: string | undefined): string | undefined {\n\tif (commitMessage == null) return undefined;\n\tconst m = OVERRIDE_OWNER_TRAILER.exec(commitMessage);\n\tconst reason = m?.[1]?.trim();\n\treturn reason != null && reason.length > 0 ? reason : undefined;\n}\n\n/**\n * Multi-agent subgraph ownership PR lint (DS-14.5.A delta #5, L0 rung;\n * spec §2.3a INV-OWNER-2).\n *\n * Hard-fails a pull request whose code diff edits a spec node carrying\n * `meta.owner` when the PR author is not that owner. Nodes **without**\n * `meta.owner` are silent (no advisory, no failure) — \"shared infrastructure\"\n * is exactly the un-annotated case; no separate allow-list is maintained.\n *\n * **Rules (Q5 lock):**\n * - Edited node has no `meta.owner` → silent.\n * - Edited node has `meta.owner` AND `author === meta.owner` → OK.\n * - Edited node has `meta.owner` AND `author !== meta.owner` → **violation**\n * (hard-fail) unless an `Override-Owner: <reason>` commit trailer is present,\n * in which case the violation is moved to `overridden` (audit trail) and\n * `ok` stays `true`.\n *\n * **PR-diff → spec-node mapping (Q5 sub-flag lock):** `meta.factory`\n * resolution. A node is \"edited\" iff its `meta.factory` appears in\n * `prDiff.editedFactories`. This reuses the `factoryTag` / `decompileSpec`\n * round-trip rather than introducing a `meta.ownerPath` glob. Nodes without\n * `meta.factory` can't be mapped from a code diff and are never flagged.\n *\n * Pure function — no `Node` / `Graph` returned, no side effects. Designed to\n * be called from a `graphrefly check-spec`-adjacent CI step (delta #6, Phase\n * 16) or any host PR gate.\n *\n * @param spec - The committed GraphSpec (or any `describe({ detail: \"spec\" })`\n * projection / structural superset).\n * @param prDiff - The factory-keyed diff slice + author + commit text.\n */\nexport function validateOwnership(spec: unknown, prDiff: OwnershipPrDiff): OwnershipValidation {\n\tconst violations: OwnershipViolation[] = [];\n\tconst overridden: OwnershipViolation[] = [];\n\n\tif (spec == null || typeof spec !== \"object\") {\n\t\treturn { ok: true, violations, overridden };\n\t}\n\tconst s = spec as Record<string, unknown>;\n\tconst nodes = s.nodes;\n\tif (nodes == null || typeof nodes !== \"object\" || Array.isArray(nodes)) {\n\t\treturn { ok: true, violations, overridden };\n\t}\n\n\tconst edited = new Set(prDiff.editedFactories);\n\tif (edited.size > 0) {\n\t\tfor (const [path, nRaw] of Object.entries(nodes as Record<string, unknown>)) {\n\t\t\tif (nRaw == null || typeof nRaw !== \"object\") continue;\n\t\t\tconst n = nRaw as GraphSpecNode;\n\t\t\tconst factory = readFactory(n);\n\t\t\t// Unmappable from a code diff (no factory provenance) → silent.\n\t\t\tif (factory == null || !edited.has(factory)) continue;\n\t\t\tconst owner = readOwner(n);\n\t\t\t// No annotation → silent (INV-OWNER-2: un-annotated == shared).\n\t\t\tif (owner == null) continue;\n\t\t\t// Author IS the owner → OK.\n\t\t\tif (owner === prDiff.author) continue;\n\t\t\tviolations.push({ node: path, owner, author: prDiff.author, factory });\n\t\t}\n\t}\n\n\tconst overrideReason = parseOverrideOwner(prDiff.commitMessage);\n\tif (violations.length > 0 && overrideReason != null) {\n\t\t// Trailer bypasses ALL cross-owner violations in this PR (the trailer\n\t\t// is PR-scoped and a pure audit-trail record per Q5 sub-lock i).\n\t\toverridden.push(...violations);\n\t\treturn { ok: true, violations: [], overridden, overrideReason };\n\t}\n\n\treturn {\n\t\tok: violations.length === 0,\n\t\tviolations,\n\t\toverridden,\n\t\t...(overrideReason != null ? { overrideReason } : {}),\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// compileSpec\n// ---------------------------------------------------------------------------\n\n/** Options for {@link compileSpec}. */\nexport type CompileSpecOptions = {\n\t/** Fn/source catalog for resolving named factories. */\n\tcatalog?: GraphSpecCatalog;\n\t/**\n\t * How to handle nodes whose `fn` / `source` is missing from the catalog.\n\t * - `\"placeholder\"` (default): silently substitute identity passthroughs\n\t * (`node([], () => {})` / `node(deps, (bd, a, ctx) => a.emit(bd[0]?.at(-1)))`). Backward-\n\t * compatible — preserves the historical \"soft compile\" behavior.\n\t * - `\"warn\"`: substitute placeholders AND log each missing entry via\n\t * `console.warn`, or via the `onWarn` callback if supplied.\n\t * - `\"error\"`: collect every missing entry across the whole spec, then\n\t * throw an `Error` listing them all (no partial graph returned).\n\t */\n\tonMissing?: \"error\" | \"warn\" | \"placeholder\";\n\t/** Custom warning sink. Used only when `onMissing === \"warn\"`. Defaults to `console.warn`. */\n\tonWarn?: (message: string) => void;\n};\n\ninterface MissingCatalogEntry {\n\t/** Node path (template-prefixed where applicable, e.g. `myMount.inner`). */\n\tpath: string;\n\t/** The catalog kind (`\"fn\"` or `\"source\"`) that was looked up. */\n\tkind: \"fn\" | \"source\";\n\t/** The catalog name string supplied in the spec. */\n\tname: string;\n}\n\n/**\n * Instantiate a Graph from a GraphSpec.\n *\n * Handles template expansion (mounted subgraphs), feedback wiring via §8.1\n * feedback(), node factory lookup from the catalog, and topology validation.\n *\n * @param spec - Declarative graph topology.\n * @param opts - Catalog and compile options.\n * @returns A running Graph.\n * @throws On validation failure, missing catalog entries, or unresolvable deps.\n *\n * @category patterns\n */\nexport function compileSpec(spec: GraphSpec, opts?: CompileSpecOptions): Graph {\n\t// QA F4: validate FIRST, even when the early-dispatch path will delegate to\n\t// a Graph-level factory. The early-dispatch is a *constructor* short-circuit,\n\t// not a *validation* short-circuit — we still want malformed specs to throw\n\t// so a catalog-tagged spec with bogus nodes/templates surfaces the error.\n\tconst validation = validateSpec(spec);\n\tif (!validation.valid) {\n\t\tthrow new Error(`compileSpec: invalid GraphSpec:\\n${validation.errors.join(\"\\n\")}`);\n\t}\n\n\t// Tier 1.5.3 Phase 2.5 (DG1=B): if the spec carries a top-level `factory`\n\t// tag and the catalog has a matching `graphFactories` entry, delegate the\n\t// full reconstruction. This lets Graph-returning factories\n\t// (`agentMemory`, `harnessLoop`, etc.) own their own rebuild path with\n\t// access to user-supplied runtime ctx (LLMAdapter, callbacks).\n\tconst specFactory = spec.factory;\n\tconst specFactoryArgs = spec.factoryArgs;\n\tif (typeof specFactory === \"string\") {\n\t\tconst graphFactory = opts?.catalog?.graphFactories?.[specFactory];\n\t\tif (graphFactory) return graphFactory(specFactoryArgs);\n\t\t// No catalog entry for the named factory — fall through to per-node\n\t\t// compile so the per-node-tagged paths still work.\n\t}\n\n\tconst catalog = opts?.catalog ?? {};\n\tconst onMissing = opts?.onMissing ?? \"placeholder\";\n\tconst g = new Graph(spec.name);\n\tconst templates = spec.templates ?? {};\n\n\t// Catalog-aware validation (when rich entries are available)\n\tconst catalogValidation = validateSpecAgainstCatalog(spec, catalog);\n\tif (!catalogValidation.valid) {\n\t\tthrow new Error(\n\t\t\t`compileSpec: catalog validation errors:\\n${catalogValidation.errors.join(\"\\n\")}`,\n\t\t);\n\t}\n\n\t// Track missing catalog entries across both top-level and template passes;\n\t// the chosen `onMissing` policy is applied once after compile so callers see\n\t// every miss in a single error / warn batch instead of one-at-a-time.\n\tconst missingEntries: MissingCatalogEntry[] = [];\n\n\tconst recordMissing = (nodePath: string, kind: \"fn\" | \"source\", name: string): void => {\n\t\tmissingEntries.push({ path: nodePath, kind, name });\n\t};\n\n\t// Helper: resolve fn/source factories from catalog (handles rich + bare entries)\n\tconst resolveFn = (fnName: string): FnFactory | undefined => {\n\t\tconst entry = catalog.fns?.[fnName];\n\t\treturn entry ? extractFnFactory(entry) : undefined;\n\t};\n\tconst resolveSource = (sourceName: string): SourceFactory | undefined => {\n\t\tconst entry = catalog.sources?.[sourceName];\n\t\treturn entry ? extractSourceFactory(entry) : undefined;\n\t};\n\n\t/**\n\t * Strip the `factory` / `factoryArgs` keys from a spec node's `meta`\n\t * before forwarding to the construction factory. The factory itself\n\t * re-stamps its own `factoryTag(...)` (so the rebuilt node carries the\n\t * canonical factoryArgs); leaving the spec's pre-stamped meta in place\n\t * would shadow that with stale args (esp. after `placeholderArgs`\n\t * scrubbed non-JSON fields).\n\t */\n\tconst stripFactoryMeta = (\n\t\tmeta: Record<string, unknown> | undefined,\n\t): Record<string, unknown> | undefined => {\n\t\tif (!meta) return undefined;\n\t\tconst out: Record<string, unknown> = {};\n\t\tfor (const [k, v] of Object.entries(meta)) {\n\t\t\tif (k === \"factory\" || k === \"factoryArgs\") continue;\n\t\t\tout[k] = v;\n\t\t}\n\t\treturn Object.keys(out).length > 0 ? out : undefined;\n\t};\n\n\t// Phase 1: Create non-template nodes (state/producer first, then derived/effect/operator)\n\tconst created = new Map<string, Node<unknown>>();\n\tconst deferred: [string, GraphSpecNode][] = [];\n\n\tfor (const [name, raw] of Object.entries(spec.nodes)) {\n\t\tif (raw.type === \"template\") continue; // handled in Phase 2\n\n\t\tconst n = raw as GraphSpecNode;\n\t\tconst factoryName = readFactory(n);\n\t\tconst factoryArgs = readFactoryArgs(n);\n\n\t\tif (n.type === \"state\") {\n\t\t\tconst initial = readStateInitial(n);\n\t\t\tconst nd = node([], {\n\t\t\t\tname,\n\t\t\t\tinitial,\n\t\t\t\tmeta: stripFactoryMeta(n.meta),\n\t\t\t});\n\t\t\tg.add(nd, { name: name });\n\t\t\tcreated.set(name, nd);\n\t\t} else if (n.type === \"producer\") {\n\t\t\t// Producer: try sources first (matching the legacy precedence) then fns.\n\t\t\tconst sourceFactory = factoryName ? resolveSource(factoryName) : undefined;\n\t\t\tconst fnFactory = factoryName ? resolveFn(factoryName) : undefined;\n\t\t\tif (sourceFactory) {\n\t\t\t\tconst nd = sourceFactory(factoryArgs);\n\t\t\t\tg.add(nd, { name: name });\n\t\t\t\tcreated.set(name, nd);\n\t\t\t} else if (fnFactory) {\n\t\t\t\tconst nd = fnFactory([], factoryArgs);\n\t\t\t\tg.add(nd, { name: name });\n\t\t\t\tcreated.set(name, nd);\n\t\t\t} else {\n\t\t\t\t// No catalog entry — create a bare producer placeholder.\n\t\t\t\tif (factoryName) recordMissing(name, \"source\", factoryName);\n\t\t\t\tconst nd = node([], () => {}, {\n\t\t\t\t\tname,\n\t\t\t\t\tdescribeKind: \"producer\",\n\t\t\t\t\tmeta: { ...stripFactoryMeta(n.meta), _specSource: factoryName },\n\t\t\t\t});\n\t\t\t\tg.add(nd, { name: name });\n\t\t\t\tcreated.set(name, nd);\n\t\t\t}\n\t\t} else {\n\t\t\tdeferred.push([name, n]);\n\t\t}\n\t}\n\n\t// Resolve deferred nodes (derived/effect/operator) in dependency order\n\tlet progressed = true;\n\tconst pending = new Map(deferred);\n\twhile (pending.size > 0 && progressed) {\n\t\tprogressed = false;\n\t\tfor (const [name, n] of [...pending.entries()]) {\n\t\t\tconst deps = n.deps ?? [];\n\t\t\tif (!deps.every((dep) => created.has(dep))) continue;\n\n\t\t\tconst resolvedDeps = deps.map((dep) => created.get(dep)!);\n\t\t\tconst factoryName = readFactory(n);\n\t\t\tconst factoryArgs = readFactoryArgs(n);\n\t\t\tconst fnFactory = factoryName ? resolveFn(factoryName) : undefined;\n\n\t\t\tlet nd: Node<unknown>;\n\t\t\tif (fnFactory) {\n\t\t\t\tnd = fnFactory(resolvedDeps, factoryArgs);\n\t\t\t} else if (n.type === \"effect\") {\n\t\t\t\tif (factoryName) recordMissing(name, \"fn\", factoryName);\n\t\t\t\tnd = node(resolvedDeps, () => {}, { describeKind: \"effect\" });\n\t\t\t} else {\n\t\t\t\t// derived without catalog fn — identity passthrough\n\t\t\t\tif (factoryName) recordMissing(name, \"fn\", factoryName);\n\t\t\t\tnd = node(\n\t\t\t\t\tresolvedDeps,\n\t\t\t\t\t(batchData, actions, ctx) => {\n\t\t\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t\t\t);\n\t\t\t\t\t\tactions.emit(data[0]);\n\t\t\t\t\t},\n\t\t\t\t\t{ describeKind: \"derived\" },\n\t\t\t\t);\n\t\t\t}\n\t\t\tg.add(nd, { name: name });\n\t\t\tcreated.set(name, nd);\n\t\t\tpending.delete(name);\n\t\t\tprogressed = true;\n\t\t}\n\t}\n\tif (pending.size > 0) {\n\t\tconst unresolved = [...pending.keys()].sort().join(\", \");\n\t\tthrow new Error(`compileSpec: unresolvable deps for nodes: ${unresolved}`);\n\t}\n\n\t// Phase 2: Expand template instantiations as mounted subgraphs\n\tfor (const [name, raw] of Object.entries(spec.nodes)) {\n\t\tif (raw.type !== \"template\") continue;\n\t\tconst ref = raw as GraphSpecTemplateRef;\n\t\tconst tmpl = templates[ref.template]!;\n\n\t\tconst sub = new Graph(name);\n\t\tconst subCreated = new Map<string, Node<unknown>>();\n\t\tconst subDeferred: [string, GraphSpecNode][] = [];\n\n\t\t// Create inner nodes, resolving $params to bound nodes\n\t\tfor (const [nName, nSpec] of Object.entries(tmpl.nodes)) {\n\t\t\tconst resolvedDeps = (nSpec.deps ?? []).map((dep) => {\n\t\t\t\tif (dep.startsWith(\"$\") && ref.bind[dep]) {\n\t\t\t\t\treturn ref.bind[dep];\n\t\t\t\t}\n\t\t\t\treturn dep;\n\t\t\t});\n\t\t\tconst specWithResolvedDeps: GraphSpecNode = { ...nSpec, deps: resolvedDeps };\n\t\t\tconst factoryName = readFactory(nSpec);\n\t\t\tconst factoryArgs = readFactoryArgs(nSpec);\n\n\t\t\tif (nSpec.type === \"state\") {\n\t\t\t\tconst initial = readStateInitial(nSpec);\n\t\t\t\tconst nd = node([], {\n\t\t\t\t\tname: nName,\n\t\t\t\t\tinitial,\n\t\t\t\t\tmeta: stripFactoryMeta(nSpec.meta),\n\t\t\t\t});\n\t\t\t\tsub.add(nd, { name: nName });\n\t\t\t\tsubCreated.set(nName, nd);\n\t\t\t} else if (nSpec.type === \"producer\") {\n\t\t\t\tconst sourceFactory = factoryName ? resolveSource(factoryName) : undefined;\n\t\t\t\tconst fnFactory = factoryName ? resolveFn(factoryName) : undefined;\n\t\t\t\tif (sourceFactory) {\n\t\t\t\t\tconst nd = sourceFactory(factoryArgs);\n\t\t\t\t\tsub.add(nd, { name: nName });\n\t\t\t\t\tsubCreated.set(nName, nd);\n\t\t\t\t} else if (fnFactory) {\n\t\t\t\t\tconst nd = fnFactory([], factoryArgs);\n\t\t\t\t\tsub.add(nd, { name: nName });\n\t\t\t\t\tsubCreated.set(nName, nd);\n\t\t\t\t} else {\n\t\t\t\t\tif (factoryName) recordMissing(`${name}.${nName}`, \"source\", factoryName);\n\t\t\t\t\tconst nd = node([], () => {}, {\n\t\t\t\t\t\tname: nName,\n\t\t\t\t\t\tdescribeKind: \"producer\",\n\t\t\t\t\t\tmeta: { ...stripFactoryMeta(nSpec.meta), _specSource: factoryName },\n\t\t\t\t\t});\n\t\t\t\t\tsub.add(nd, { name: nName });\n\t\t\t\t\tsubCreated.set(nName, nd);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tsubDeferred.push([nName, specWithResolvedDeps]);\n\t\t\t}\n\t\t}\n\n\t\t// Resolve deferred inner nodes\n\t\tlet subProgressed = true;\n\t\tconst subPending = new Map(subDeferred);\n\t\twhile (subPending.size > 0 && subProgressed) {\n\t\t\tsubProgressed = false;\n\t\t\tfor (const [nName, nSpec] of [...subPending.entries()]) {\n\t\t\t\tconst deps = nSpec.deps ?? [];\n\t\t\t\tconst allReady = deps.every((dep) => subCreated.has(dep) || created.has(dep));\n\t\t\t\tif (!allReady) continue;\n\n\t\t\t\tconst resolvedDeps = deps.map((dep) => subCreated.get(dep) ?? created.get(dep)!);\n\t\t\t\tconst factoryName = readFactory(nSpec);\n\t\t\t\tconst factoryArgs = readFactoryArgs(nSpec);\n\t\t\t\tconst fnFactory = factoryName ? resolveFn(factoryName) : undefined;\n\n\t\t\t\tlet nd: Node<unknown>;\n\t\t\t\tif (fnFactory) {\n\t\t\t\t\tnd = fnFactory(resolvedDeps, factoryArgs);\n\t\t\t\t} else if (nSpec.type === \"effect\") {\n\t\t\t\t\tif (factoryName) recordMissing(`${name}.${nName}`, \"fn\", factoryName);\n\t\t\t\t\tnd = node(resolvedDeps, () => {}, { describeKind: \"effect\" });\n\t\t\t\t} else {\n\t\t\t\t\tif (factoryName) recordMissing(`${name}.${nName}`, \"fn\", factoryName);\n\t\t\t\t\tnd = node(\n\t\t\t\t\t\tresolvedDeps,\n\t\t\t\t\t\t(batchData, actions, ctx) => {\n\t\t\t\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tactions.emit(data[0]);\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{ describeKind: \"derived\" },\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tsub.add(nd, { name: nName });\n\t\t\t\tsubCreated.set(nName, nd);\n\t\t\t\tsubPending.delete(nName);\n\t\t\t\tsubProgressed = true;\n\t\t\t}\n\t\t}\n\t\tif (subPending.size > 0) {\n\t\t\tconst unresolved = [...subPending.keys()].sort().join(\", \");\n\t\t\tthrow new Error(\n\t\t\t\t`compileSpec: template \"${ref.template}\" has unresolvable deps: ${unresolved}`,\n\t\t\t);\n\t\t}\n\n\t\tg.mount(name, sub);\n\t\t// Register template output as a reachable node path\n\t\tconst outputPath = `${name}::${tmpl.output}`;\n\t\tcreated.set(name, g.resolve(outputPath));\n\n\t\t// Store template origin meta on the mounted subgraph's output node\n\t\t// so decompile-style introspection can recover the template name.\n\t\ttry {\n\t\t\tconst outputNode = g.resolve(outputPath);\n\t\t\toutputNode.meta._templateName?.emit(ref.template);\n\t\t\toutputNode.meta._templateBind?.emit(ref.bind);\n\t\t} catch {\n\t\t\t/* meta nodes may not exist; template origin is best-effort */\n\t\t}\n\t}\n\n\t// Edges are derived from node `_deps` (Unit 7) — no explicit edge wiring step.\n\n\t// Phase 4: Wire feedback edges via §8.1 feedback()\n\tfor (const fb of spec.feedback ?? []) {\n\t\tfeedbackPrimitive(g, fb.from, fb.to, {\n\t\t\tmaxIterations: fb.maxIterations,\n\t\t});\n\t}\n\n\t// Apply onMissing policy. We always finish compilation first (for \"warn\"\n\t// + \"placeholder\") so the caller still gets a usable graph in non-strict\n\t// modes. In \"error\" mode we throw before returning.\n\tif (missingEntries.length > 0) {\n\t\tif (onMissing === \"error\") {\n\t\t\tconst lines = missingEntries.map((e) => ` - ${e.path}: missing ${e.kind} \"${e.name}\"`);\n\t\t\tthrow new Error(\n\t\t\t\t`compileSpec: ${missingEntries.length} catalog entr${\n\t\t\t\t\tmissingEntries.length === 1 ? \"y\" : \"ies\"\n\t\t\t\t} missing — pass them via opts.catalog or set opts.onMissing to \"warn\"/\"placeholder\":\\n${lines.join(\"\\n\")}`,\n\t\t\t);\n\t\t}\n\t\tif (onMissing === \"warn\") {\n\t\t\tconst warn = opts?.onWarn ?? ((m: string): void => console.warn(m));\n\t\t\tfor (const e of missingEntries) {\n\t\t\t\twarn(\n\t\t\t\t\t`compileSpec: ${e.path} references missing ${e.kind} \"${e.name}\" — substituted placeholder`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn g;\n}\n\n// ---------------------------------------------------------------------------\n// decompileGraph\n// ---------------------------------------------------------------------------\n\n/** Internal meta keys used by compileSpec/feedback — stripped from output. */\nconst INTERNAL_META_KEYS = new Set([\n\t\"reduction\",\n\t\"reduction_type\",\n\t\"_specFn\",\n\t\"_specSource\",\n\t\"_templateName\",\n\t\"_templateBind\",\n\t\"feedbackFrom\",\n\t\"feedbackTo\",\n\t\"_internal\",\n]);\n\n/**\n * Extract a {@link GraphSpec} from a running graph.\n *\n * Tier 1.5.3 Phase 3 (2026-04-27): thin projection over\n * `graph.describe({ detail: \"spec\" })`. The describe-output already carries\n * structural fields (`type`, `deps`, optional `value`) plus per-node\n * `meta.factory` / `meta.factoryArgs` for tagged factories and top-level\n * `factory` / `factoryArgs` for graph-level tags. The only sugar this helper\n * adds is a feedback-edge recovery scan over `meta.feedbackFrom` /\n * `meta.feedbackTo` companion fields stamped by the §8.1 `feedback()`\n * primitive.\n *\n * **Removed in Phase 3:** template fingerprinting / `_templateName` /\n * `_templateBind` recovery. Mounted subgraphs surface as nested `subname::*`\n * paths in `desc.nodes`; if you need the template-instantiation form, build\n * the spec by hand or read the meta companions directly.\n *\n * @param graph - Running graph to decompile.\n * @returns A GraphSpec representation.\n *\n * @category patterns\n */\nexport function decompileSpec(graph: Graph): GraphSpec {\n\tconst desc = graph.describe({ detail: \"spec\" }) as GraphDescribeOutput;\n\tconst metaSegment = `::${GRAPH_META_SEGMENT}::`;\n\tconst feedbackCounterPattern = /^__feedback_(?!effect_)(.+)$/;\n\tconst feedbackEdges: GraphSpecFeedbackEdge[] = [];\n\n\t// qa D1 — Pre-pass: collect paths whose own node carries `meta.factory`.\n\t// These are \"factory parents\" (e.g. `prompt_node` for the `promptNode`\n\t// compound factory). Their `::`-prefixed sibling paths (`prompt_node::messages`,\n\t// `prompt_node::output`, etc.) are factory-internal and SHOULD NOT round-trip\n\t// as separate spec nodes — `compileSpec` will recreate them when the factory\n\t// runs against the parent's `meta.factory` / `meta.factoryArgs` tag. Without\n\t// this filter, every compound-factory internal would be emitted as a top-level\n\t// spec node, then `compileSpec` would try to re-add them via `g.add(nd, {name})`\n\t// alongside the factory's own outputs — duplicate-name failures or split topology.\n\tconst compoundFactoryPrefixes = new Set<string>();\n\tfor (const [path, nodeDesc] of Object.entries(desc.nodes)) {\n\t\tconst meta = nodeDesc.meta as Record<string, unknown> | undefined;\n\t\tif (meta?.factory != null && !path.includes(\"::\")) {\n\t\t\t// A12 (QA fix 2026-05-01): skip the `proxy` factoryTag — proxies\n\t\t\t// are local wrappers around foreign-source Nodes (used by\n\t\t\t// `pipelineGraph.approvalGate`, `gatedStream`, `stratify` after\n\t\t\t// the C3 ownership migration). They're regenerated by their\n\t\t\t// parent factory and don't have their own catalog entry; treating\n\t\t\t// them as compound-factory roots would cause `compileSpec` to\n\t\t\t// look up \"proxy\" as a registered factory name and fail.\n\t\t\tif (meta.factory === \"proxy\") continue;\n\t\t\tcompoundFactoryPrefixes.add(path);\n\t\t}\n\t}\n\n\t// 5.6 (b) — DF1 hard-require (Tier 5, 2026-04-29). Locked: any `::`-path\n\t// whose parent prefix exists in the graph but does NOT carry\n\t// `meta.factory` is an untagged compound factory. `compileSpec` cannot\n\t// reconstruct it, so the spec round-trip would silently break. Fail\n\t// loud at decompile time so the offending factory author tags the\n\t// parent. Skip well-known internal prefixes that are not factory output\n\t// (meta companions, feedback / bridge infrastructure).\n\tconst allPaths = new Set(Object.keys(desc.nodes));\n\tfor (const path of allPaths) {\n\t\tconst sepIdx = path.indexOf(\"::\");\n\t\tif (sepIdx <= 0) continue;\n\t\tconst parent = path.slice(0, sepIdx);\n\t\t// Skip internal infrastructure prefixes (handled below in the main loop).\n\t\tif (path.includes(metaSegment)) continue;\n\t\tif (path.startsWith(\"__feedback_effect_\") || path.startsWith(\"__bridge_\")) continue;\n\t\t// Parent is a tagged compound factory → covered by the existing pre-pass.\n\t\tif (compoundFactoryPrefixes.has(parent)) continue;\n\t\t// Parent doesn't appear in the graph (untagged child path with no\n\t\t// matching parent) — treat as a regular `::`-named node, not a\n\t\t// compound factory. Allowed.\n\t\tif (!allPaths.has(parent)) continue;\n\t\t// Parent IS in the graph but lacks `meta.factory` — untagged compound\n\t\t// factory. Refuse to round-trip.\n\t\tthrow new Error(\n\t\t\t`decompileSpec: untagged compound factory at \"${parent}\" (child: \"${path}\"). ` +\n\t\t\t\t\"Compound factories that ship `parent::child` topology MUST set `meta.factory` \" +\n\t\t\t\t\"on the parent so `compileSpec` can reconstruct the internals via the catalog. \" +\n\t\t\t\t\"Either tag the parent (`{ meta: factoryTag('myFactory', args) }`) OR rename the \" +\n\t\t\t\t\"child to use `/` instead of `::` if it's not a compound-factory internal \" +\n\t\t\t\t\"(see COMPOSITION-GUIDE §38).\",\n\t\t);\n\t}\n\n\t// Build the spec-shaped node map by walking describe's output. Strip\n\t// meta-companion paths, bridge / feedback-effect internals, AND compound-\n\t// factory `::` internals (per pre-pass above); preserve everything else verbatim.\n\tconst nodes: Record<string, GraphSpecNode | GraphSpecTemplateRef> = {};\n\tfor (const [path, nodeDesc] of Object.entries(desc.nodes)) {\n\t\tif (path.includes(metaSegment)) continue;\n\n\t\t// qa D1 — skip compound-factory `::` internals (e.g. `prompt_node::messages`)\n\t\t// when their parent is a tagged factory. The factory recreates them.\n\t\tconst sepIdx = path.indexOf(\"::\");\n\t\tif (sepIdx > 0 && compoundFactoryPrefixes.has(path.slice(0, sepIdx))) continue;\n\n\t\tconst match = feedbackCounterPattern.exec(path);\n\t\tif (match) {\n\t\t\tconst meta = nodeDesc.meta as Record<string, unknown> | undefined;\n\t\t\tif (meta?.feedbackFrom && meta?.feedbackTo) {\n\t\t\t\tfeedbackEdges.push({\n\t\t\t\t\tfrom: meta.feedbackFrom as string,\n\t\t\t\t\tto: meta.feedbackTo as string,\n\t\t\t\t\t...(meta.maxIterations ? { maxIterations: meta.maxIterations as number } : {}),\n\t\t\t\t});\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\t// Skip internal infrastructure nodes (feedback-effect, bridge).\n\t\tif (nodeDesc.meta?._internal) continue;\n\t\tif (path.startsWith(\"__feedback_effect_\")) continue;\n\t\tif (path.startsWith(\"__bridge_\")) continue;\n\n\t\t// QA F5 carry: strip runtime-state sibling keys for known stateful factory\n\t\t// tags so the spec doesn't carry transient runtime state into round-trips.\n\t\tconst meta = nodeDesc.meta as Record<string, unknown> | undefined;\n\t\tlet cleanedMeta: Record<string, unknown> | undefined = meta;\n\t\tif (meta && Object.keys(meta).length > 0) {\n\t\t\tconst out: Record<string, unknown> = {};\n\t\t\tfor (const [k, v] of Object.entries(meta)) {\n\t\t\t\tif (INTERNAL_META_KEYS.has(k)) continue;\n\t\t\t\tout[k] = v;\n\t\t\t}\n\t\t\tif (out.factory === \"withStatus\") {\n\t\t\t\tdelete out.status;\n\t\t\t\tdelete out.error;\n\t\t\t} else if (out.factory === \"withBreaker\") {\n\t\t\t\tdelete out.breakerState;\n\t\t\t} else if (out.factory === \"verifiable\") {\n\t\t\t\tdelete out.sourceVersion;\n\t\t\t}\n\t\t\tcleanedMeta = Object.keys(out).length > 0 ? out : undefined;\n\t\t}\n\n\t\tconst cleaned: GraphSpecNode = { ...nodeDesc };\n\t\tif (cleanedMeta === undefined) delete cleaned.meta;\n\t\telse cleaned.meta = cleanedMeta;\n\t\tnodes[path] = cleaned;\n\t}\n\n\tconst result: GraphSpec = { ...desc, nodes };\n\t// `expand` (a closure injected onto live describe outputs) is not part of\n\t// the GraphSpec wire shape — it leaks function refs into JSON-stringified\n\t// specs. Drop it.\n\tdelete (result as { expand?: unknown }).expand;\n\tif (feedbackEdges.length > 0) result.feedback = feedbackEdges;\n\treturn result;\n}\n\n// ---------------------------------------------------------------------------\n// specDiff\n// ---------------------------------------------------------------------------\n\n/** A single change in a spec diff. */\nexport type SpecDiffEntry = {\n\ttype: \"added\" | \"removed\" | \"changed\";\n\tpath: string;\n\tdetail?: string;\n};\n\n/** Structural diff between two GraphSpecs. */\nexport type SpecDiffResult = {\n\tentries: SpecDiffEntry[];\n\tsummary: string;\n};\n\n/**\n * Compute a structural diff between two GraphSpecs.\n *\n * Template-aware: reports \"changed template definition\" vs \"changed\n * instantiation bindings.\" No runtime needed — pure JSON comparison.\n *\n * @param specA - The \"before\" spec.\n * @param specB - The \"after\" spec.\n * @returns Diff entries and a human-readable summary.\n *\n * @category patterns\n */\nexport function specDiff(specA: GraphSpec, specB: GraphSpec): SpecDiffResult {\n\tconst entries: SpecDiffEntry[] = [];\n\n\t// Diff name\n\tif (specA.name !== specB.name) {\n\t\tentries.push({\n\t\t\ttype: \"changed\",\n\t\t\tpath: \"name\",\n\t\t\tdetail: `\"${specA.name}\" → \"${specB.name}\"`,\n\t\t});\n\t}\n\n\t// Diff nodes\n\tconst nodesA = new Set(Object.keys(specA.nodes));\n\tconst nodesB = new Set(Object.keys(specB.nodes));\n\n\tfor (const name of nodesB) {\n\t\tif (!nodesA.has(name)) {\n\t\t\tconst n = specB.nodes[name]!;\n\t\t\tentries.push({\n\t\t\t\ttype: \"added\",\n\t\t\t\tpath: `nodes.${name}`,\n\t\t\t\tdetail: `type: ${n.type}`,\n\t\t\t});\n\t\t}\n\t}\n\tfor (const name of nodesA) {\n\t\tif (!nodesB.has(name)) {\n\t\t\tentries.push({ type: \"removed\", path: `nodes.${name}` });\n\t\t}\n\t}\n\tfor (const name of nodesA) {\n\t\tif (!nodesB.has(name)) continue;\n\t\tconst a = specA.nodes[name]!;\n\t\tconst b = specB.nodes[name]!;\n\t\tif (JSON.stringify(a) !== JSON.stringify(b)) {\n\t\t\tconst details: string[] = [];\n\t\t\tif (a.type !== b.type) details.push(`type: ${a.type} → ${b.type}`);\n\t\t\tif (JSON.stringify((a as GraphSpecNode).deps) !== JSON.stringify((b as GraphSpecNode).deps)) {\n\t\t\t\tdetails.push(\"deps changed\");\n\t\t\t}\n\t\t\tconst aFactory = a.type === \"template\" ? undefined : readFactory(a as GraphSpecNode);\n\t\t\tconst bFactory = b.type === \"template\" ? undefined : readFactory(b as GraphSpecNode);\n\t\t\tif (aFactory !== bFactory) {\n\t\t\t\tdetails.push(`fn: ${aFactory} → ${bFactory}`);\n\t\t\t}\n\t\t\tconst aArgs = a.type === \"template\" ? undefined : readFactoryArgs(a as GraphSpecNode);\n\t\t\tconst bArgs = b.type === \"template\" ? undefined : readFactoryArgs(b as GraphSpecNode);\n\t\t\tif (JSON.stringify(aArgs) !== JSON.stringify(bArgs)) {\n\t\t\t\tdetails.push(\"config changed\");\n\t\t\t}\n\t\t\tentries.push({\n\t\t\t\ttype: \"changed\",\n\t\t\t\tpath: `nodes.${name}`,\n\t\t\t\tdetail: details.join(\"; \") || \"modified\",\n\t\t\t});\n\t\t}\n\t}\n\n\t// Diff templates\n\tconst tmplA = specA.templates ?? {};\n\tconst tmplB = specB.templates ?? {};\n\tconst tmplNamesA = new Set(Object.keys(tmplA));\n\tconst tmplNamesB = new Set(Object.keys(tmplB));\n\n\tfor (const name of tmplNamesB) {\n\t\tif (!tmplNamesA.has(name)) {\n\t\t\tentries.push({ type: \"added\", path: `templates.${name}` });\n\t\t}\n\t}\n\tfor (const name of tmplNamesA) {\n\t\tif (!tmplNamesB.has(name)) {\n\t\t\tentries.push({ type: \"removed\", path: `templates.${name}` });\n\t\t}\n\t}\n\tfor (const name of tmplNamesA) {\n\t\tif (!tmplNamesB.has(name)) continue;\n\t\tif (JSON.stringify(tmplA[name]) !== JSON.stringify(tmplB[name])) {\n\t\t\tentries.push({\n\t\t\t\ttype: \"changed\",\n\t\t\t\tpath: `templates.${name}`,\n\t\t\t\tdetail: \"template definition changed\",\n\t\t\t});\n\t\t}\n\t}\n\n\t// Diff feedback\n\tconst fbA = specA.feedback ?? [];\n\tconst fbB = specB.feedback ?? [];\n\tconst fbKeyA = new Set(fbA.map((e) => `${e.from}->${e.to}`));\n\tconst fbKeyB = new Set(fbB.map((e) => `${e.from}->${e.to}`));\n\n\tfor (const fb of fbB) {\n\t\tconst key = `${fb.from}->${fb.to}`;\n\t\tif (!fbKeyA.has(key)) {\n\t\t\tentries.push({\n\t\t\t\ttype: \"added\",\n\t\t\t\tpath: `feedback.${key}`,\n\t\t\t\tdetail: `maxIterations: ${fb.maxIterations ?? 10}`,\n\t\t\t});\n\t\t}\n\t}\n\tfor (const fb of fbA) {\n\t\tconst key = `${fb.from}->${fb.to}`;\n\t\tif (!fbKeyB.has(key)) {\n\t\t\tentries.push({ type: \"removed\", path: `feedback.${key}` });\n\t\t}\n\t}\n\tfor (const fb of fbA) {\n\t\tconst key = `${fb.from}->${fb.to}`;\n\t\tconst counterpart = fbB.find((b) => b.from === fb.from && b.to === fb.to);\n\t\tif (counterpart && JSON.stringify(fb) !== JSON.stringify(counterpart)) {\n\t\t\tentries.push({\n\t\t\t\ttype: \"changed\",\n\t\t\t\tpath: `feedback.${key}`,\n\t\t\t\tdetail: `maxIterations: ${fb.maxIterations ?? 10} → ${counterpart.maxIterations ?? 10}`,\n\t\t\t});\n\t\t}\n\t}\n\n\t// Build summary\n\tconst added = entries.filter((e) => e.type === \"added\").length;\n\tconst removed = entries.filter((e) => e.type === \"removed\").length;\n\tconst changed = entries.filter((e) => e.type === \"changed\").length;\n\tconst parts: string[] = [];\n\tif (added) parts.push(`${added} added`);\n\tif (removed) parts.push(`${removed} removed`);\n\tif (changed) parts.push(`${changed} changed`);\n\tconst summary = parts.length > 0 ? parts.join(\", \") : \"no changes\";\n\n\treturn { entries, summary };\n}\n\n// ---------------------------------------------------------------------------\n// llmCompose\n// ---------------------------------------------------------------------------\n\n/** Options for {@link llmCompose}. */\nexport type LLMComposeOptions = {\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\t/** Extra instructions appended to the system prompt. */\n\tsystemPromptExtra?: string;\n\t/**\n\t * Available fn/source catalog names for the LLM to reference.\n\t * When omitted and `catalog` contains rich {@link CatalogFnEntry} entries,\n\t * the prompt is auto-generated via {@link generateCatalogPrompt}.\n\t */\n\tcatalogDescription?: string;\n\t/**\n\t * Catalog for auto-prompt generation and catalog-aware validation.\n\t * When rich entries are provided, the catalog prompt is auto-generated\n\t * and LLM output is validated against fn/source names and config schemas.\n\t */\n\tcatalog?: GraphSpecCatalog;\n\t/**\n\t * Max auto-refine attempts when the LLM output fails catalog validation.\n\t * Each attempt feeds the validation errors back to the LLM via llmRefine.\n\t * Default: 0 (no auto-refine). Set to 2-3 for production use.\n\t */\n\tmaxAutoRefine?: number;\n};\n\nconst LLM_COMPOSE_SYSTEM_PROMPT = `You are a graph architect for GraphReFly, a reactive graph protocol.\n\nGiven a natural-language description, produce a JSON GraphSpec with this structure:\n\n{\n \"name\": \"<graph_name>\",\n \"nodes\": {\n \"<node_name>\": {\n \"type\": \"state\" | \"derived\" | \"producer\" | \"effect\",\n \"deps\": [\"<dep_node_name>\", ...],\n \"value\": <initial_value>,\n \"meta\": {\n \"factory\": \"<catalog_factory_name>\",\n \"factoryArgs\": { ... },\n \"description\": \"<purpose>\"\n }\n },\n \"<template_instance>\": {\n \"type\": \"template\",\n \"template\": \"<template_name>\",\n \"bind\": { \"$param\": \"node_name\" }\n }\n },\n \"templates\": {\n \"<template_name>\": {\n \"params\": [\"$param1\", \"$param2\"],\n \"nodes\": { ... },\n \"output\": \"<output_node>\"\n }\n },\n \"feedback\": [\n { \"from\": \"<condition_node>\", \"to\": \"<state_node>\", \"maxIterations\": 10 }\n ]\n}\n\nRules:\n- \"state\" nodes hold user/LLM-writable values (knobs). Stamp the initial value\n in \"meta.factoryArgs.initial\" (or as the top-level \"value\" field — both work).\n- \"derived\" nodes compute from deps using a catalog function named in\n \"meta.factory\"; pass any config via \"meta.factoryArgs\".\n- \"effect\" nodes produce side effects from deps; same meta.factory shape as derived.\n- \"producer\" nodes generate values from a catalog source named in \"meta.factory\";\n pass any config via \"meta.factoryArgs\".\n- Use \"templates\" when the same subgraph pattern repeats (e.g., per-source resilience).\n- Use \"feedback\" for bounded cycles where a derived value writes back to a state node.\n- meta.description is required for every node.\n- Return ONLY valid JSON, no markdown fences or commentary.`;\n\n/** Strip markdown code fences. */\nfunction stripFences(text: string): string {\n\tconst match = text.match(/^```(?:json)?\\s*([\\s\\S]*?)\\s*```[\\s\\S]*$/);\n\treturn match ? match[1]! : text;\n}\n\n/**\n * Ask an LLM to compose a GraphSpec from a natural-language problem description.\n *\n * The LLM generates a GraphSpec (with templates + feedback), validated before\n * returning. The spec is for human review before compilation via compileSpec().\n *\n * @param problem - Natural language problem description.\n * @param adapter - LLM adapter for the generation call.\n * @param opts - Model options and catalog description.\n * @returns A validated GraphSpec.\n * @throws On invalid LLM output or validation failure.\n *\n * @category patterns\n */\nexport async function llmCompose(\n\tproblem: string,\n\tadapter: LLMAdapter,\n\topts?: LLMComposeOptions,\n): Promise<GraphSpec> {\n\tlet systemPrompt = LLM_COMPOSE_SYSTEM_PROMPT;\n\n\t// Auto-generate catalog prompt from rich entries, or use manual description\n\tconst catalogPrompt =\n\t\topts?.catalogDescription ?? (opts?.catalog ? generateCatalogPrompt(opts.catalog) : undefined);\n\tif (catalogPrompt) {\n\t\tsystemPrompt += `\\n\\nAvailable catalog (use ONLY these names):\\n${catalogPrompt}`;\n\t}\n\tif (opts?.systemPromptExtra) {\n\t\tsystemPrompt += `\\n\\n${opts.systemPromptExtra}`;\n\t}\n\n\tconst messages: ChatMessage[] = [\n\t\t{ role: \"system\", content: systemPrompt },\n\t\t{ role: \"user\", content: problem },\n\t];\n\n\tconst rawResult = adapter.invoke(messages, {\n\t\tmodel: opts?.model,\n\t\ttemperature: opts?.temperature ?? 0,\n\t\tmaxTokens: opts?.maxTokens,\n\t});\n\n\t// System boundary: await the adapter's response (Promise, plain value).\n\tconst response = (await rawResult) as LLMResponse;\n\tlet content = response.content.trim();\n\n\tif (content.startsWith(\"```\")) {\n\t\tcontent = stripFences(content);\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(content);\n\t} catch {\n\t\tthrow new Error(`llmCompose: LLM response is not valid JSON: ${content.slice(0, 200)}`);\n\t}\n\n\tconst validation = validateSpec(parsed);\n\tif (!validation.valid) {\n\t\tthrow new Error(`llmCompose: invalid GraphSpec:\\n${validation.errors.join(\"\\n\")}`);\n\t}\n\n\tlet spec = parsed as GraphSpec;\n\n\t// Catalog-aware validation + auto-refine loop\n\tif (opts?.catalog) {\n\t\tconst maxRefine = opts.maxAutoRefine ?? 0;\n\t\tfor (let attempt = 0; attempt <= maxRefine; attempt++) {\n\t\t\tconst catalogValidation = validateSpecAgainstCatalog(spec, opts.catalog);\n\t\t\tif (catalogValidation.valid) break;\n\n\t\t\tif (attempt === maxRefine) {\n\t\t\t\t// Last attempt failed — return with errors attached as meta\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`llmCompose: catalog validation failed after ${maxRefine} refine attempts:\\n${catalogValidation.errors.join(\"\\n\")}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Auto-refine: feed catalog errors back to LLM\n\t\t\tspec = await llmRefine(\n\t\t\t\tspec,\n\t\t\t\t`Fix these catalog errors:\\n${catalogValidation.errors.join(\"\\n\")}\\n\\nUse ONLY functions and sources from the catalog.`,\n\t\t\t\tadapter,\n\t\t\t\t{ ...opts, catalogDescription: catalogPrompt },\n\t\t\t);\n\t\t}\n\t}\n\n\treturn spec;\n}\n\n// ---------------------------------------------------------------------------\n// llmRefine\n// ---------------------------------------------------------------------------\n\n/** Options for {@link llmRefine}. */\nexport type LLMRefineOptions = LLMComposeOptions;\n\n/**\n * Ask an LLM to modify an existing GraphSpec based on feedback or changed requirements.\n *\n * @param currentSpec - The current GraphSpec to modify.\n * @param feedback - Natural language feedback or changed requirements.\n * @param adapter - LLM adapter for the generation call.\n * @param opts - Model options.\n * @returns A new GraphSpec incorporating the feedback.\n * @throws On invalid LLM output or validation failure.\n *\n * @category patterns\n */\nexport async function llmRefine(\n\tcurrentSpec: GraphSpec,\n\tfeedback: string,\n\tadapter: LLMAdapter,\n\topts?: LLMRefineOptions,\n): Promise<GraphSpec> {\n\tlet systemPrompt = LLM_COMPOSE_SYSTEM_PROMPT;\n\tif (opts?.catalogDescription) {\n\t\tsystemPrompt += `\\n\\nAvailable catalog:\\n${opts.catalogDescription}`;\n\t}\n\tif (opts?.systemPromptExtra) {\n\t\tsystemPrompt += `\\n\\n${opts.systemPromptExtra}`;\n\t}\n\n\tconst messages: ChatMessage[] = [\n\t\t{ role: \"system\", content: systemPrompt },\n\t\t{\n\t\t\trole: \"user\",\n\t\t\tcontent: `Current GraphSpec:\\n${JSON.stringify(currentSpec, null, 2)}\\n\\nModification request: ${feedback}\\n\\nReturn the complete modified GraphSpec as JSON.`,\n\t\t},\n\t];\n\n\tconst rawResult = adapter.invoke(messages, {\n\t\tmodel: opts?.model,\n\t\ttemperature: opts?.temperature ?? 0,\n\t\tmaxTokens: opts?.maxTokens,\n\t});\n\n\t// System boundary: await the adapter's response.\n\tconst response = (await rawResult) as LLMResponse;\n\tlet content = response.content.trim();\n\n\tif (content.startsWith(\"```\")) {\n\t\tcontent = stripFences(content);\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(content);\n\t} catch {\n\t\tthrow new Error(`llmRefine: LLM response is not valid JSON: ${content.slice(0, 200)}`);\n\t}\n\n\tconst validation = validateSpec(parsed);\n\tif (!validation.valid) {\n\t\tthrow new Error(`llmRefine: invalid GraphSpec:\\n${validation.errors.join(\"\\n\")}`);\n\t}\n\n\treturn parsed as GraphSpec;\n}\n","/**\n * Reduction primitives (roadmap §8.1).\n *\n * Composable building blocks for taking heterogeneous massive inputs and producing\n * prioritized, auditable, human-actionable output. Each primitive is either a Graph\n * factory or a Node factory, built on top of core + extra primitives.\n *\n * @module\n */\n\nimport {\n\tbatch,\n\tCOMPLETE,\n\tDATA,\n\tERROR,\n\ttype Message,\n\ttype Node,\n\ttype NodeOptions,\n\tnode,\n} from \"@graphrefly/pure-ts/core\";\n\nimport { merge } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\n\n// ---------------------------------------------------------------------------\n// Shared helpers (same pattern as orchestration.ts)\n// ---------------------------------------------------------------------------\n\nexport type { StepRef } from \"../orchestration/pipeline-graph.js\";\n\nimport { keepalive } from \"@graphrefly/pure-ts/extra\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport { tryIncrementBounded } from \"../../base/mutation/index.js\";\nimport type { StepRef } from \"../orchestration/pipeline-graph.js\";\n\nfunction baseMeta(kind: string, meta?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"reduction\", kind, meta);\n}\n\n// stratify moved to `src/extra/stratify.ts` (protocol-level primitive).\n\n// ---------------------------------------------------------------------------\n// funnel\n// ---------------------------------------------------------------------------\n\n/** A named stage for {@link funnel}. */\nexport type FunnelStage = {\n\t/** Stage name (mounted as subgraph). */\n\tname: string;\n\t/** Builder: receives a sub-graph, should add an `\"input\"` and `\"output\"` node. */\n\tbuild: (sub: Graph) => void;\n};\n\n/** Options for {@link funnel}. */\nexport type FunnelOptions = GraphOptions & {\n\tmeta?: Record<string, unknown>;\n};\n\n/**\n * Multi-source merge with sequential reduction stages.\n *\n * Sources are merged into a single stream. Each stage is a named subgraph\n * (mounted via `graph.mount()`). Stages connect linearly:\n * `merged → stage[0].input → stage[0].output → stage[1].input → ...`\n *\n * @param name - Graph name.\n * @param sources - Input nodes to merge.\n * @param stages - Sequential reduction stages.\n * @param opts - Optional graph/meta options.\n * @returns Graph with `\"merged\"` and mounted stage subgraphs.\n *\n * @category patterns\n */\nexport function funnel<T>(\n\tname: string,\n\tsources: ReadonlyArray<Node<T>>,\n\tstages: ReadonlyArray<FunnelStage>,\n\topts?: FunnelOptions,\n): Graph {\n\tif (sources.length === 0) throw new RangeError(\"funnel requires at least one source\");\n\tif (stages.length === 0) throw new RangeError(\"funnel requires at least one stage\");\n\n\tconst g = new Graph(name, opts);\n\n\t// Merge all sources\n\tconst merged = sources.length === 1 ? sources[0] : merge(...(sources as unknown as Node<T>[]));\n\tg.add(merged as Node<unknown>, { name: \"merged\" });\n\n\t// Build and mount each stage linearly.\n\t// Stage inputs are standalone state nodes, so we bridge via subscribe\n\t// (connect() requires constructor deps). Bridge effects forward DATA\n\t// from the previous output to the next stage's input.\n\tlet prevOutputPath = \"merged\";\n\tfor (let i = 0; i < stages.length; i++) {\n\t\tconst stage = stages[i];\n\t\tconst sub = new Graph(stage.name);\n\t\tstage.build(sub);\n\n\t\t// Validate that the stage has input and output nodes\n\t\ttry {\n\t\t\tsub.resolve(\"input\");\n\t\t} catch {\n\t\t\tthrow new Error(`funnel stage \"${stage.name}\" must define an \"input\" node`);\n\t\t}\n\t\ttry {\n\t\t\tsub.resolve(\"output\");\n\t\t} catch {\n\t\t\tthrow new Error(`funnel stage \"${stage.name}\" must define an \"output\" node`);\n\t\t}\n\n\t\tg.mount(stage.name, sub);\n\n\t\t// Bridge replacement: effect that forwards DATA from previous output\n\t\t// to the next stage's input. TEARDOWN excluded because stage lifecycle\n\t\t// is managed by the parent graph. Shows up in describe().\n\t\tconst prevNode = g.resolve(prevOutputPath);\n\t\tconst stageInputPath = `${stage.name}::input`;\n\t\tconst stageInput = g.resolve(stageInputPath);\n\t\tconst bridgeName = `__bridge_${prevOutputPath}→${stage.name}_input`;\n\t\tconst br = node(\n\t\t\t[prevNode],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tstageInput.emit(data[0]);\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t\t{ describeKind: \"effect\", name: bridgeName },\n\t\t);\n\t\tg.add(br as Node<unknown>, { name: bridgeName });\n\t\tg.addDisposer(keepalive(br));\n\n\t\tprevOutputPath = `${stage.name}::output`;\n\t}\n\n\treturn g;\n}\n\n// ---------------------------------------------------------------------------\n// feedback\n// ---------------------------------------------------------------------------\n\n/** Options for {@link feedback}. */\nexport type FeedbackOptions = {\n\t/** Maximum feedback iterations before stopping (default: 10). */\n\tmaxIterations?: number;\n\t/** Optional budget gate node path for cost-bounded iteration. */\n\tbudgetNode?: StepRef;\n\tmeta?: Record<string, unknown>;\n};\n\n/**\n * Introduce a bounded reactive cycle into an existing graph.\n *\n * When `condition` emits a non-null DATA value, the feedback effect routes it\n * back to the `reentry` state node — creating a cycle. Bounded by\n * `maxIterations` (default 10). The counter node (`__feedback_<condition>`)\n * is the source of truth — reset it to 0 to allow more iterations.\n *\n * To remove the feedback cycle, call `graph.remove(\"__feedback_<condition>\")`.\n *\n * @param graph - Existing graph to augment with a feedback cycle.\n * @param condition - Path to a node whose DATA triggers feedback.\n * @param reentry - Path to a state node that receives the feedback value.\n * @param opts - Iteration bounds and metadata.\n * @returns The same graph (mutated with feedback nodes added).\n *\n * @category patterns\n */\nexport function feedback(\n\tgraph: Graph,\n\tcondition: string,\n\treentry: string,\n\topts?: FeedbackOptions,\n): Graph {\n\tconst maxIter = opts?.maxIterations ?? 10;\n\n\t// Internal counter node — source of truth for iteration bound.\n\t// Reset to 0 to allow more iterations.\n\tconst counterName = `__feedback_${condition}`;\n\tconst counter = node<number>([], {\n\t\t...{\n\t\t\tmeta: baseMeta(\"feedback_counter\", {\n\t\t\t\tmaxIterations: maxIter,\n\t\t\t\tfeedbackFrom: condition,\n\t\t\t\tfeedbackTo: reentry,\n\t\t\t}),\n\t\t},\n\t\tinitial: 0,\n\t});\n\tgraph.add(counter as Node<unknown>, { name: counterName });\n\n\t// Resolve the condition and reentry nodes\n\tconst condNode = graph.resolve(condition);\n\tconst reentryNode = graph.resolve(reentry);\n\n\t// Graph-visible feedback effect: intercepts condition DATA, routes back to\n\t// reentry with iteration counting. Registered in the graph so it shows up\n\t// in describe() and cleans up on graph.destroy().\n\t// Feedback effect: subscribe to condition node for per-message interception\n\t// (onMessage removed in v5 — use producer+subscribe instead)\n\tconst feedbackEffectName = `__feedback_effect_${condition}`;\n\tconst feedbackEffect = node(\n\t\t[],\n\t\t(_data, _feedbackActions) => {\n\t\t\tconst unsub = condNode.subscribe((msgs) => {\n\t\t\t\tfor (const msg of msgs) {\n\t\t\t\t\tconst t = msg[0];\n\t\t\t\t\tif (t === DATA) {\n\t\t\t\t\t\tconst condValue = msg[1];\n\t\t\t\t\t\tif (condValue == null) return;\n\t\t\t\t\t\tbatch(() => {\n\t\t\t\t\t\t\tif (tryIncrementBounded(counter, maxIter)) {\n\t\t\t\t\t\t\t\treentryNode.emit(condValue);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (t === COMPLETE || t === ERROR) {\n\t\t\t\t\t\tconst terminal: Message = t === ERROR && msg.length > 1 ? [ERROR, msg[1]] : [t];\n\t\t\t\t\t\tcounter.down([terminal]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn () => unsub();\n\t\t},\n\t\t{\n\t\t\tname: feedbackEffectName,\n\t\t\tdescribeKind: \"effect\",\n\t\t\tmeta: {\n\t\t\t\t...baseMeta(\"feedback_effect\", {\n\t\t\t\t\tfeedbackFrom: condition,\n\t\t\t\t\tfeedbackTo: reentry,\n\t\t\t\t}),\n\t\t\t\t_internal: true,\n\t\t\t},\n\t\t},\n\t);\n\tgraph.add(feedbackEffect as Node<unknown>, { name: feedbackEffectName });\n\tgraph.addDisposer(keepalive(feedbackEffect));\n\n\treturn graph;\n}\n\n// `budgetGate` was promoted to `extra/resilience/budget-gate.ts` per Tier 2.2.\n// Import from `@graphrefly/graphrefly/extra` (or `../../extra/resilience/budget-gate.js`\n// internally) instead. See the resilience family for sibling primitives:\n// `retry`, `circuitBreaker`, `rateLimiter`, `tokenBucket`, `fallback`, `withStatus`.\n\n// ---------------------------------------------------------------------------\n// scorer\n// ---------------------------------------------------------------------------\n\n/** A scored item with full breakdown. */\nexport type ScoredItem<T = unknown> = {\n\t/** Original value. */\n\tvalue: T;\n\t/** Final weighted score. */\n\tscore: number;\n\t/** Per-signal breakdown: signal index → weighted contribution. */\n\tbreakdown: number[];\n};\n\n/** Options for {@link scorer}. */\nexport type ScorerOptions = Omit<NodeOptions<unknown>, \"describeKind\" | \"name\" | \"meta\"> & {\n\tmeta?: Record<string, unknown>;\n\t/** Custom scoring function per signal. Default: identity (signal value IS the score). */\n\tscoreFns?: ReadonlyArray<(value: unknown) => number>;\n};\n\n/**\n * Reactive multi-signal scoring with live weights.\n *\n * Each source emits items to score. Weights are reactive state nodes that\n * LLM or human can adjust live. Output is sorted scored items with full\n * breakdown.\n *\n * @param sources - Signal nodes (each emits a numeric score dimension).\n * @param weights - Reactive weight nodes (one per source).\n * @param opts - Optional node/meta options.\n * @returns Node emitting scored output.\n *\n * @category patterns\n */\nexport function scorer(\n\tsources: ReadonlyArray<Node<number>>,\n\tweights: ReadonlyArray<Node<number>>,\n\topts?: ScorerOptions,\n): Node<ScoredItem<number[]>> {\n\tif (sources.length === 0) throw new RangeError(\"scorer requires at least one source\");\n\tif (sources.length !== weights.length) {\n\t\tthrow new RangeError(\"scorer requires the same number of sources and weights\");\n\t}\n\n\tconst allDeps = [...(sources as unknown as Node[]), ...(weights as unknown as Node[])];\n\tconst n = sources.length;\n\tconst scoreFns = opts?.scoreFns;\n\n\treturn node<ScoredItem<number[]>>(\n\t\tallDeps,\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst vals = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst signals = vals.slice(0, n) as number[];\n\t\t\tconst weightValues = vals.slice(n) as number[];\n\n\t\t\tconst breakdown: number[] = [];\n\t\t\tlet totalScore = 0;\n\n\t\t\tfor (let i = 0; i < n; i++) {\n\t\t\t\tconst sig = signals[i] ?? 0;\n\t\t\t\tconst wt = weightValues[i] ?? 0;\n\t\t\t\tconst rawScore = scoreFns?.[i] ? scoreFns[i](sig) : sig;\n\t\t\t\tconst weighted = (rawScore as number) * wt;\n\t\t\t\tbreakdown.push(weighted);\n\t\t\t\ttotalScore += weighted;\n\t\t\t}\n\n\t\t\tactions.emit({\n\t\t\t\tvalue: signals,\n\t\t\t\tscore: totalScore,\n\t\t\t\tbreakdown,\n\t\t\t});\n\t\t},\n\t\t{\n\t\t\t...(opts\n\t\t\t\t? {\n\t\t\t\t\t\tequals: opts.equals,\n\t\t\t\t\t\tresubscribable: opts.resubscribable,\n\t\t\t\t\t\tresetOnTeardown: opts.resetOnTeardown,\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\tdescribeKind: \"derived\",\n\t\t\tmeta: baseMeta(\"scorer\", opts?.meta),\n\t\t},\n\t);\n}\n\n// `effectivenessTracker` was deleted per Class B audit Alt E (2026-04-30).\n// The shared substrate now lives in `extra/composition/audited-success-tracker.ts`\n// — re-exported via `@graphrefly/graphrefly-ts/extra` for general use.\n","// ---------------------------------------------------------------------------\n// 5.4 — LLM tool integration\n// ---------------------------------------------------------------------------\n\nimport type { Actor } from \"@graphrefly/pure-ts/core\";\nimport type { Graph } from \"@graphrefly/pure-ts/graph\";\nimport type { ToolDefinition } from \"../adapters/core/types.js\";\n\n/** OpenAI function-calling tool schema. */\nexport type OpenAIToolSchema = {\n\treadonly type: \"function\";\n\treadonly function: {\n\t\treadonly name: string;\n\t\treadonly description: string;\n\t\treadonly parameters: Record<string, unknown>;\n\t};\n};\n\n/** MCP (Model Context Protocol) tool schema. */\nexport type McpToolSchema = {\n\treadonly name: string;\n\treadonly description: string;\n\treadonly inputSchema: Record<string, unknown>;\n};\n\n/** Result of {@link knobsAsTools}. */\nexport type KnobsAsToolsResult = {\n\t/** OpenAI function-calling tool schemas. */\n\treadonly openai: readonly OpenAIToolSchema[];\n\t/** MCP tool schemas. */\n\treadonly mcp: readonly McpToolSchema[];\n\t/** GraphReFly ToolDefinitions with handlers that call `graph.set()`. */\n\treadonly definitions: readonly ToolDefinition[];\n};\n\n/**\n * Build a JSON Schema `properties.value` descriptor from a node's meta fields.\n *\n * Maps `meta.type`, `meta.range`, `meta.values`, `meta.format`, and `meta.unit`\n * to a JSON Schema property definition.\n */\nfunction metaToJsonSchema(meta: Record<string, unknown>): Record<string, unknown> {\n\tconst schema: Record<string, unknown> = {};\n\n\tconst metaType = meta.type as string | undefined;\n\tif (metaType === \"enum\" && Array.isArray(meta.values)) {\n\t\tschema.type = \"string\";\n\t\tschema.enum = meta.values;\n\t} else if (metaType === \"integer\") {\n\t\tschema.type = \"integer\";\n\t} else if (metaType === \"number\") {\n\t\tschema.type = \"number\";\n\t} else if (metaType === \"boolean\") {\n\t\tschema.type = \"boolean\";\n\t} else if (metaType === \"string\") {\n\t\tschema.type = \"string\";\n\t} else {\n\t\t// Unknown or unspecified — accept anything\n\t\tschema.type = [\"string\", \"number\", \"boolean\"];\n\t}\n\n\tif (Array.isArray(meta.range) && meta.range.length === 2) {\n\t\tschema.minimum = meta.range[0];\n\t\tschema.maximum = meta.range[1];\n\t}\n\n\tif (typeof meta.format === \"string\") {\n\t\tschema.description = `Format: ${meta.format}`;\n\t}\n\n\tif (typeof meta.unit === \"string\") {\n\t\tif (schema.description) {\n\t\t\tschema.description += ` (${meta.unit})`;\n\t\t} else {\n\t\t\tschema.description = `Unit: ${meta.unit}`;\n\t\t}\n\t}\n\n\treturn schema;\n}\n\n/**\n * Derive tool schemas from a graph's writable (knob) nodes.\n *\n * Knobs are state nodes whose `meta.access` is `\"llm\"`, `\"both\"`, or absent\n * (default: writable). Each knob becomes a tool that calls `graph.set()`.\n *\n * Speaks **domain language** (spec §5.4): the returned schemas use node names\n * and meta descriptions — no protocol internals exposed.\n *\n * @param graph - The graph to introspect.\n * @param actor - Optional actor for guard-scoped describe.\n * @returns OpenAI, MCP, and GraphReFly tool schemas.\n */\nexport function knobsAsTools(graph: Graph, actor?: Actor): KnobsAsToolsResult {\n\tconst described = graph.describe({ actor, detail: \"full\" });\n\tconst openai: OpenAIToolSchema[] = [];\n\tconst mcp: McpToolSchema[] = [];\n\tconst definitions: ToolDefinition[] = [];\n\n\tfor (const [path, node] of Object.entries(described.nodes)) {\n\t\t// Only state nodes are writable knobs\n\t\tif (node.type !== \"state\") continue;\n\n\t\t// Skip meta companion nodes (§2.3)\n\t\tif (path.includes(\"::__meta__::\")) continue;\n\n\t\t// Skip terminal-state nodes (§1.3.4 — no further messages after COMPLETE/ERROR)\n\t\tif (node.status === \"completed\" || node.status === \"errored\") continue;\n\n\t\t// Skip if access explicitly excludes LLM\n\t\tconst meta = node.meta ?? {};\n\t\tconst access = meta.access as string | undefined;\n\t\tif (access === \"human\" || access === \"system\") continue;\n\n\t\tconst description = (meta.description as string) ?? `Set the value of ${path}`;\n\t\tconst valueSchema = metaToJsonSchema(meta);\n\n\t\tconst parameterSchema: Record<string, unknown> = {\n\t\t\ttype: \"object\",\n\t\t\trequired: [\"value\"],\n\t\t\tproperties: {\n\t\t\t\tvalue: valueSchema,\n\t\t\t},\n\t\t\tadditionalProperties: false,\n\t\t};\n\n\t\t// OpenAI requires [a-zA-Z0-9_-] in function names; sanitize :: separators\n\t\tconst sanitizedName = path.replace(/::/g, \"__\");\n\n\t\topenai.push({\n\t\t\ttype: \"function\",\n\t\t\tfunction: {\n\t\t\t\tname: sanitizedName,\n\t\t\t\tdescription,\n\t\t\t\tparameters: parameterSchema,\n\t\t\t},\n\t\t});\n\n\t\tmcp.push({\n\t\t\tname: path,\n\t\t\tdescription,\n\t\t\tinputSchema: parameterSchema,\n\t\t});\n\n\t\tconst graphRef = graph;\n\t\tconst actorRef = actor;\n\t\tconst nv = node.v;\n\t\tdefinitions.push({\n\t\t\tname: path,\n\t\t\tdescription,\n\t\t\tparameters: parameterSchema,\n\t\t\thandler(args: Record<string, unknown>) {\n\t\t\t\tgraphRef.set(path, args.value, actorRef ? { actor: actorRef } : undefined);\n\t\t\t\treturn args.value;\n\t\t\t},\n\t\t\t...(nv != null ? { version: { id: nv.id, version: nv.version } } : {}),\n\t\t});\n\t}\n\n\treturn { openai, mcp, definitions };\n}\n","// ---------------------------------------------------------------------------\n// suggestStrategy\n// ---------------------------------------------------------------------------\n\nimport type { Actor, Node } from \"@graphrefly/pure-ts/core\";\nimport { COMPLETE, ERROR, node } from \"@graphrefly/pure-ts/core\";\nimport { fromAny, type NodeInput, switchMap, withLatestFrom } from \"@graphrefly/pure-ts/extra\";\nimport type { Graph } from \"@graphrefly/pure-ts/graph\";\nimport { resolveToolHandlerResult } from \"../_internal.js\";\nimport type { ChatMessage, LLMAdapter, LLMResponse } from \"../adapters/core/types.js\";\n\n/** A single operation in a strategy plan. */\nexport type StrategyOperation =\n\t| {\n\t\t\treadonly type: \"add_node\";\n\t\t\treadonly name: string;\n\t\t\treadonly nodeType: string;\n\t\t\treadonly meta?: Record<string, unknown>;\n\t\t\treadonly initial?: unknown;\n\t }\n\t| { readonly type: \"remove_node\"; readonly name: string }\n\t| { readonly type: \"connect\"; readonly from: string; readonly to: string }\n\t| { readonly type: \"disconnect\"; readonly from: string; readonly to: string }\n\t| { readonly type: \"set_value\"; readonly name: string; readonly value: unknown }\n\t| {\n\t\t\treadonly type: \"update_meta\";\n\t\t\treadonly name: string;\n\t\t\treadonly key: string;\n\t\t\treadonly value: unknown;\n\t };\n\n/** Structured strategy plan returned by {@link suggestStrategy}. */\nexport type StrategyPlan = {\n\treadonly summary: string;\n\treadonly operations: readonly StrategyOperation[];\n\treadonly reasoning: string;\n};\n\nexport type SuggestStrategyOptions = {\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\tactor?: Actor;\n\t/**\n\t * Optional AbortSignal forwarded to `adapter.invoke({ signal })`. Lets\n\t * callers cancel the in-flight LLM call (e.g. when the reactive variant\n\t * supersedes mid-flight). When the signal aborts, the underlying call\n\t * propagates the abort and `suggestStrategy` rejects with the abort reason.\n\t */\n\tsignal?: AbortSignal;\n};\n\nconst SUGGEST_STRATEGY_SYSTEM_PROMPT = `You are a reactive graph optimizer for GraphReFly.\n\nGiven a graph's current structure (from describe()) and a problem statement, suggest topology and parameter changes to solve the problem.\n\nReturn ONLY valid JSON with this structure:\n{\n \"summary\": \"<one-line summary of the strategy>\",\n \"reasoning\": \"<explanation of why these changes help>\",\n \"operations\": [\n { \"type\": \"add_node\", \"name\": \"<name>\", \"nodeType\": \"state|derived|effect|producer|operator\", \"meta\": {...}, \"initial\": <value> },\n { \"type\": \"remove_node\", \"name\": \"<name>\" },\n { \"type\": \"connect\", \"from\": \"<source>\", \"to\": \"<target>\" },\n { \"type\": \"disconnect\", \"from\": \"<source>\", \"to\": \"<target>\" },\n { \"type\": \"set_value\", \"name\": \"<name>\", \"value\": <new_value> },\n { \"type\": \"update_meta\", \"name\": \"<name>\", \"key\": \"<meta_key>\", \"value\": <new_value> }\n ]\n}\n\nRules:\n- Only suggest operations that reference existing nodes (for remove/disconnect/set_value/update_meta) or new nodes you define (for add_node).\n- Keep changes minimal — prefer the smallest set of operations that solves the problem.\n- Return ONLY valid JSON, no markdown fences or commentary.`;\n\n/**\n * Ask an LLM to analyze a graph and suggest topology/parameter changes\n * to solve a stated problem.\n *\n * Returns a structured plan — does NOT auto-apply. The caller reviews\n * and selectively applies operations.\n *\n * @param graph - The graph to analyze.\n * @param problem - Natural-language problem statement.\n * @param adapter - LLM adapter for the analysis call.\n * @param opts - Model and actor options.\n * @returns A structured strategy plan.\n * @throws On invalid LLM output.\n */\nexport async function suggestStrategy(\n\tgraph: Graph,\n\tproblem: string,\n\tadapter: LLMAdapter,\n\topts?: SuggestStrategyOptions,\n): Promise<StrategyPlan> {\n\tconst { expand: _, ...described } = graph.describe({ actor: opts?.actor, detail: \"standard\" });\n\n\tconst messages: ChatMessage[] = [\n\t\t{ role: \"system\", content: SUGGEST_STRATEGY_SYSTEM_PROMPT },\n\t\t{\n\t\t\trole: \"user\",\n\t\t\tcontent: JSON.stringify({\n\t\t\t\tgraph: described,\n\t\t\t\tproblem,\n\t\t\t}),\n\t\t},\n\t];\n\n\tconst rawResult = adapter.invoke(messages, {\n\t\tmodel: opts?.model,\n\t\ttemperature: opts?.temperature ?? 0,\n\t\tmaxTokens: opts?.maxTokens,\n\t\tsignal: opts?.signal,\n\t});\n\n\tconst response = (await resolveToolHandlerResult(rawResult)) as LLMResponse;\n\tlet content = response.content.trim();\n\n\tif (content.startsWith(\"```\")) {\n\t\tcontent = content.replace(/^```(?:json)?\\s*/, \"\").replace(/\\s*```$/, \"\");\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(content);\n\t} catch {\n\t\tthrow new Error(`suggestStrategy: LLM response is not valid JSON: ${content.slice(0, 200)}`);\n\t}\n\n\tconst plan = parsed as Record<string, unknown>;\n\n\tif (typeof plan.summary !== \"string\") {\n\t\tthrow new Error(\"suggestStrategy: missing 'summary' in response\");\n\t}\n\tif (typeof plan.reasoning !== \"string\") {\n\t\tthrow new Error(\"suggestStrategy: missing 'reasoning' in response\");\n\t}\n\tif (!Array.isArray(plan.operations)) {\n\t\tthrow new Error(\"suggestStrategy: missing 'operations' array in response\");\n\t}\n\n\treturn {\n\t\tsummary: plan.summary,\n\t\treasoning: plan.reasoning,\n\t\toperations: plan.operations as readonly StrategyOperation[],\n\t};\n}\n\n/**\n * Reactive variant of {@link suggestStrategy}: re-invokes the LLM whenever\n * the `problem` source emits, sampling the latest `graph` value (via\n * `withLatestFrom`) to describe. The graph is the *secondary* dep — only\n * problem changes re-trigger analysis. This breaks the feedback cycle that\n * would otherwise arise if downstream consumers wired `apply(plan)` back\n * into the same graph node (graph mutation must not auto-fire a re-analysis).\n *\n * @param graph - Reactive source of graphs to analyze.\n * @param problem - Reactive source of natural-language problem statements.\n * @param adapter - LLM adapter for the analysis call.\n * @param opts - Model and actor options.\n * @returns `Node<StrategyPlan | null>` — emits the latest plan, or `null`\n * while inputs are unsettled.\n */\nexport function suggestStrategyReactive(\n\tgraph: Node<Graph | null>,\n\tproblem: NodeInput<string>,\n\tadapter: LLMAdapter,\n\topts?: SuggestStrategyOptions,\n): Node<StrategyPlan | null> {\n\tconst problemNode = fromAny(problem);\n\t// problem is primary (re-triggers on change); graph is sampled — no\n\t// graph-edit-feedback loop to suggestStrategy when callers apply ops.\n\tconst paired = withLatestFrom(problemNode as Node<unknown>, graph as Node<unknown>);\n\treturn switchMap<unknown, StrategyPlan | null>(paired, (pair) => {\n\t\tif (pair == null) return node<StrategyPlan | null>([], { initial: null });\n\t\tconst [pText, g] = pair as [string | null, Graph | null];\n\t\tif (!g || !pText || typeof pText !== \"string\" || pText.trim().length === 0) {\n\t\t\treturn node<StrategyPlan | null>([], { initial: null });\n\t\t}\n\t\t// QA-fix: skip rather than ERROR if the sampled Graph was destroyed\n\t\t// between the `withLatestFrom` sample and this project fn. Common when\n\t\t// a caller's reactive `graph: Node<Graph | null>` cycles graphs faster\n\t\t// than `suggestStrategy` resolves; the supersede was the user's intent,\n\t\t// so emitting null here matches \"input not ready\" semantics rather\n\t\t// than surfacing a spurious ERROR on the StrategyPlan stream.\n\t\tif (g.destroyed) return node<StrategyPlan | null>([], { initial: null });\n\t\treturn node<StrategyPlan | null>(\n\t\t\t(_data, actions) => {\n\t\t\t\tconst controller = new AbortController();\n\t\t\t\tlet cancelled = false;\n\t\t\t\tsuggestStrategy(g, pText, adapter, { ...opts, signal: controller.signal })\n\t\t\t\t\t.then((plan) => {\n\t\t\t\t\t\tif (cancelled) return;\n\t\t\t\t\t\tactions.emit(plan);\n\t\t\t\t\t\tactions.down([[COMPLETE]]);\n\t\t\t\t\t})\n\t\t\t\t\t.catch((err) => {\n\t\t\t\t\t\tif (cancelled) return;\n\t\t\t\t\t\tactions.down([[ERROR, err]]);\n\t\t\t\t\t});\n\t\t\t\treturn () => {\n\t\t\t\t\tcancelled = true;\n\t\t\t\t\tcontroller.abort();\n\t\t\t\t};\n\t\t\t},\n\t\t\t{ describeKind: \"producer\", ...{ name: \"suggestStrategy::call\" } },\n\t\t);\n\t});\n}\n","// ---------------------------------------------------------------------------\n// validateGraphDef\n// ---------------------------------------------------------------------------\n\n/** Validation result from {@link validateGraphDef}. */\nexport type GraphDefValidation = {\n\treadonly valid: boolean;\n\treadonly errors: readonly string[];\n};\n\nconst VALID_NODE_TYPES = new Set([\"state\", \"derived\", \"producer\", \"operator\", \"effect\"]);\n\n/**\n * Validate an LLM-generated graph definition before passing to\n * `Graph.fromSnapshot()`.\n *\n * Checks:\n * - Required fields: `name`, `nodes`, `edges`\n * - Node types are valid enum values\n * - Edge `from`/`to` reference existing nodes\n * - No duplicate edge entries\n *\n * @param def - The graph definition to validate (parsed JSON).\n * @returns Validation result with errors array.\n */\nexport function validateGraphDef(def: unknown): GraphDefValidation {\n\tconst errors: string[] = [];\n\n\tif (def == null || typeof def !== \"object\") {\n\t\treturn { valid: false, errors: [\"Definition must be a non-null object\"] };\n\t}\n\n\tconst d = def as Record<string, unknown>;\n\n\tif (typeof d.name !== \"string\" || d.name.length === 0) {\n\t\terrors.push(\"Missing or empty 'name' field\");\n\t}\n\n\tif (d.nodes == null || typeof d.nodes !== \"object\" || Array.isArray(d.nodes)) {\n\t\terrors.push(\"Missing or invalid 'nodes' field (must be an object)\");\n\t\treturn { valid: false, errors };\n\t}\n\n\tconst nodeNames = new Set(Object.keys(d.nodes as object));\n\n\tfor (const [name, raw] of Object.entries(d.nodes as Record<string, unknown>)) {\n\t\tif (raw == null || typeof raw !== \"object\") {\n\t\t\terrors.push(`Node \"${name}\": must be an object`);\n\t\t\tcontinue;\n\t\t}\n\t\tconst node = raw as Record<string, unknown>;\n\t\tif (typeof node.type !== \"string\" || !VALID_NODE_TYPES.has(node.type)) {\n\t\t\terrors.push(\n\t\t\t\t`Node \"${name}\": invalid type \"${String(node.type)}\" (expected: ${[...VALID_NODE_TYPES].join(\", \")})`,\n\t\t\t);\n\t\t}\n\t\tif (Array.isArray(node.deps)) {\n\t\t\tfor (const dep of node.deps) {\n\t\t\t\tif (typeof dep === \"string\" && !nodeNames.has(dep)) {\n\t\t\t\t\terrors.push(`Node \"${name}\": dep \"${dep}\" does not reference an existing node`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!Array.isArray(d.edges)) {\n\t\tif (d.edges !== undefined) {\n\t\t\terrors.push(\"'edges' must be an array\");\n\t\t}\n\t\t// edges are optional — no error if absent\n\t} else {\n\t\tconst seen = new Set<string>();\n\t\tfor (let i = 0; i < (d.edges as unknown[]).length; i++) {\n\t\t\tconst edge = (d.edges as unknown[])[i];\n\t\t\tif (edge == null || typeof edge !== \"object\") {\n\t\t\t\terrors.push(`Edge [${i}]: must be an object`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst e = edge as Record<string, unknown>;\n\t\t\tif (typeof e.from !== \"string\" || !nodeNames.has(e.from)) {\n\t\t\t\terrors.push(`Edge [${i}]: 'from' \"${String(e.from)}\" does not reference an existing node`);\n\t\t\t}\n\t\t\tif (typeof e.to !== \"string\" || !nodeNames.has(e.to)) {\n\t\t\t\terrors.push(`Edge [${i}]: 'to' \"${String(e.to)}\" does not reference an existing node`);\n\t\t\t}\n\t\t\tconst key = `${e.from}->${e.to}`;\n\t\t\tif (seen.has(key)) {\n\t\t\t\terrors.push(`Edge [${i}]: duplicate edge ${key}`);\n\t\t\t}\n\t\t\tseen.add(key);\n\t\t}\n\t}\n\n\treturn { valid: errors.length === 0, errors };\n}\n"],"mappings":"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","names":["import_core","clampNonNegative","batch","import_core","import_core","import_core","import_core","import_extra","import_core","import_extra","import_core","import_extra","import_core","import_extra","raw","import_core","import_extra","batch","tier","import_core","mapUsage","toLLMResponse","import_core","mapUsage","toLLMResponse","import_core","import_extra","batch","tier","import_extra","import_core","import_core","import_core","import_core","import_extra","makeAbortError","batch","import_core","import_extra","batch","meta","import_extra","import_extra","import_extra","import_core","import_extra","makeAbortError","sleep","import_core","import_extra","import_core","import_extra","import_core","import_extra","nodeFactory","import_core","import_core","import_extra","batch","import_core","import_extra","import_core","import_extra","import_graph","import_core","import_extra","meta","batch","import_core","import_graph","batch","store","batch","import_core","import_extra","batch","import_core","store","batch","import_core","batch","import_core","batch","import_core","batch","i","import_core","batch","import_core","batch","import_core","import_extra","import_graph","batch","import_core","import_extra","batch","import_core","import_extra","batch","import_core","import_extra","import_graph","batch","import_core","import_extra","batch","import_core","import_extra","import_graph","import_core","import_extra","import_core","import_extra","isNodeLike","keepalive","node","batch","ageSeconds","import_core","import_extra","import_graph","NS_PER_SEC","batch","out","meta","ageSeconds","node","meta","import_core","import_extra","import_core","import_graph","import_core","import_extra","import_graph","meta","node","node","_","meta","batch","meta","node","import_core","import_extra","VALID_NODE_TYPES","node"]}