@graphrefly/graphrefly 0.45.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 (714) hide show
  1. package/README.md +1 -2
  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/base/render/index.d.cts +227 -0
  47. package/dist/base/render/index.d.ts +227 -0
  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/base/sources/index.d.cts +357 -0
  65. package/dist/base/sources/index.d.ts +357 -0
  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/base/sources/node/index.d.cts +185 -0
  71. package/dist/base/sources/node/index.d.ts +185 -0
  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-CSSbKGrJ.d.ts +199 -0
  89. package/dist/cascading-baGkiihI.d.cts +199 -0
  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 +3083 -2
  239. package/dist/compat/index.cjs.map +1 -1
  240. package/dist/compat/index.d.cts +116 -1
  241. package/dist/compat/index.d.ts +116 -1
  242. package/dist/compat/index.js +175 -2
  243. package/dist/compat/index.js.map +1 -1
  244. package/dist/compat/jotai/index.cjs +130 -2
  245. package/dist/compat/jotai/index.cjs.map +1 -1
  246. package/dist/compat/jotai/index.d.cts +2 -1
  247. package/dist/compat/jotai/index.d.ts +2 -1
  248. package/dist/compat/jotai/index.js +7 -2
  249. package/dist/compat/jotai/index.js.map +1 -1
  250. package/dist/compat/nanostores/index.cjs +186 -2
  251. package/dist/compat/nanostores/index.cjs.map +1 -1
  252. package/dist/compat/nanostores/index.d.cts +2 -1
  253. package/dist/compat/nanostores/index.d.ts +2 -1
  254. package/dist/compat/nanostores/index.js +21 -2
  255. package/dist/compat/nanostores/index.js.map +1 -1
  256. package/dist/compat/nestjs/index.cjs +2224 -2
  257. package/dist/compat/nestjs/index.cjs.map +1 -1
  258. package/dist/compat/nestjs/index.d.cts +10 -1
  259. package/dist/compat/nestjs/index.d.ts +10 -1
  260. package/dist/compat/nestjs/index.js +77 -2
  261. package/dist/compat/nestjs/index.js.map +1 -1
  262. package/dist/compat/react/index.cjs +95 -2
  263. package/dist/compat/react/index.cjs.map +1 -1
  264. package/dist/compat/react/index.d.cts +2 -1
  265. package/dist/compat/react/index.d.ts +2 -1
  266. package/dist/compat/react/index.js +11 -2
  267. package/dist/compat/react/index.js.map +1 -1
  268. package/dist/compat/solid/index.cjs +82 -2
  269. package/dist/compat/solid/index.cjs.map +1 -1
  270. package/dist/compat/solid/index.d.cts +2 -1
  271. package/dist/compat/solid/index.d.ts +2 -1
  272. package/dist/compat/solid/index.js +11 -2
  273. package/dist/compat/solid/index.js.map +1 -1
  274. package/dist/compat/svelte/index.cjs +85 -2
  275. package/dist/compat/svelte/index.cjs.map +1 -1
  276. package/dist/compat/svelte/index.d.cts +2 -1
  277. package/dist/compat/svelte/index.d.ts +2 -1
  278. package/dist/compat/svelte/index.js +11 -2
  279. package/dist/compat/svelte/index.js.map +1 -1
  280. package/dist/compat/vue/index.cjs +100 -2
  281. package/dist/compat/vue/index.cjs.map +1 -1
  282. package/dist/compat/vue/index.d.cts +3 -1
  283. package/dist/compat/vue/index.d.ts +3 -1
  284. package/dist/compat/vue/index.js +11 -2
  285. package/dist/compat/vue/index.js.map +1 -1
  286. package/dist/compat/zustand/index.cjs +50 -2
  287. package/dist/compat/zustand/index.cjs.map +1 -1
  288. package/dist/compat/zustand/index.d.cts +2 -1
  289. package/dist/compat/zustand/index.d.ts +2 -1
  290. package/dist/compat/zustand/index.js +7 -2
  291. package/dist/compat/zustand/index.js.map +1 -1
  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-Bx46zqky.d.cts +243 -0
  297. package/dist/fallback-pIWW8A2d.d.ts +243 -0
  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-5SU_O78r.d.cts +754 -0
  301. package/dist/index-B6pxYJzO.d.cts +36 -0
  302. package/dist/index-B6pxYJzO.d.ts +36 -0
  303. package/dist/index-BFsng6v1.d.cts +44 -0
  304. package/dist/index-BFsng6v1.d.ts +44 -0
  305. package/dist/index-Bg-LwEt-.d.cts +45 -0
  306. package/dist/index-Bg-LwEt-.d.ts +45 -0
  307. package/dist/index-Brp888t0.d.cts +127 -0
  308. package/dist/index-Brp888t0.d.ts +127 -0
  309. package/dist/index-CDfk6jHN.d.cts +37 -0
  310. package/dist/index-CDfk6jHN.d.ts +37 -0
  311. package/dist/index-CEXCtYYJ.d.ts +754 -0
  312. package/dist/index-DLAxYaN5.d.cts +169 -0
  313. package/dist/index-DLAxYaN5.d.ts +169 -0
  314. package/dist/index-DeWbQzMe.d.cts +34 -0
  315. package/dist/index-DeWbQzMe.d.ts +34 -0
  316. package/dist/index-dX9IzPqj.d.cts +86 -0
  317. package/dist/index-dX9IzPqj.d.ts +86 -0
  318. package/dist/index.cjs +25950 -0
  319. package/dist/index.cjs.map +1 -1
  320. package/dist/index.d.cts +56 -42
  321. package/dist/index.d.ts +56 -42
  322. package/dist/index.js +849 -0
  323. package/dist/index.js.map +1 -1
  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-BXQoW1P-.d.cts +36 -0
  329. package/dist/observable-BXQoW1P-.d.ts +36 -0
  330. package/dist/pipeline-graph-Ce47CB6Y.d.cts +145 -0
  331. package/dist/pipeline-graph-DXCwY9vG.d.ts +145 -0
  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-fswlBUvX.d.cts +195 -0
  365. package/dist/reactive-layout-fswlBUvX.d.ts +195 -0
  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-BB5Lw-pB.d.cts +442 -0
  381. package/dist/types-BB5Lw-pB.d.ts +442 -0
  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/utils/ai/browser.d.cts +129 -0
  387. package/dist/utils/ai/browser.d.ts +129 -0
  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/utils/ai/index.d.cts +1777 -0
  393. package/dist/utils/ai/index.d.ts +1777 -0
  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/utils/ai/node.d.cts +57 -0
  399. package/dist/utils/ai/node.d.ts +57 -0
  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/utils/cqrs/index.d.cts +438 -0
  405. package/dist/utils/cqrs/index.d.ts +438 -0
  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/utils/demo-shell/index.d.cts +90 -0
  411. package/dist/utils/demo-shell/index.d.ts +90 -0
  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/utils/domain-templates/index.d.cts +214 -0
  417. package/dist/utils/domain-templates/index.d.ts +214 -0
  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/utils/graphspec/index.d.cts +449 -0
  423. package/dist/utils/graphspec/index.d.ts +449 -0
  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/utils/job-queue/index.d.cts +200 -0
  447. package/dist/utils/job-queue/index.d.ts +200 -0
  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/utils/memory/index.d.cts +582 -0
  453. package/dist/utils/memory/index.d.ts +582 -0
  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/utils/process/index.d.cts +411 -0
  471. package/dist/utils/process/index.d.ts +411 -0
  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/utils/reactive-layout/index.d.cts +492 -0
  477. package/dist/utils/reactive-layout/index.d.ts +492 -0
  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/utils/reduction/index.d.cts +102 -0
  483. package/dist/utils/reduction/index.d.ts +102 -0
  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/utils/surface/index.d.cts +240 -0
  495. package/dist/utils/surface/index.d.ts +240 -0
  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 +293 -237
  505. package/dist/core/index.cjs +0 -21
  506. package/dist/core/index.cjs.map +0 -1
  507. package/dist/core/index.d.cts +0 -1
  508. package/dist/core/index.d.ts +0 -1
  509. package/dist/core/index.js +0 -3
  510. package/dist/core/index.js.map +0 -1
  511. package/dist/extra/browser.cjs +0 -21
  512. package/dist/extra/browser.cjs.map +0 -1
  513. package/dist/extra/browser.d.cts +0 -1
  514. package/dist/extra/browser.d.ts +0 -1
  515. package/dist/extra/browser.js +0 -3
  516. package/dist/extra/browser.js.map +0 -1
  517. package/dist/extra/index.cjs +0 -21
  518. package/dist/extra/index.cjs.map +0 -1
  519. package/dist/extra/index.d.cts +0 -1
  520. package/dist/extra/index.d.ts +0 -1
  521. package/dist/extra/index.js +0 -3
  522. package/dist/extra/index.js.map +0 -1
  523. package/dist/extra/node.cjs +0 -21
  524. package/dist/extra/node.cjs.map +0 -1
  525. package/dist/extra/node.d.cts +0 -1
  526. package/dist/extra/node.d.ts +0 -1
  527. package/dist/extra/node.js +0 -3
  528. package/dist/extra/node.js.map +0 -1
  529. package/dist/extra/operators.cjs +0 -21
  530. package/dist/extra/operators.cjs.map +0 -1
  531. package/dist/extra/operators.d.cts +0 -1
  532. package/dist/extra/operators.d.ts +0 -1
  533. package/dist/extra/operators.js +0 -3
  534. package/dist/extra/operators.js.map +0 -1
  535. package/dist/extra/reactive.cjs +0 -21
  536. package/dist/extra/reactive.cjs.map +0 -1
  537. package/dist/extra/reactive.d.cts +0 -1
  538. package/dist/extra/reactive.d.ts +0 -1
  539. package/dist/extra/reactive.js +0 -3
  540. package/dist/extra/reactive.js.map +0 -1
  541. package/dist/extra/render/index.cjs +0 -21
  542. package/dist/extra/render/index.cjs.map +0 -1
  543. package/dist/extra/render/index.d.cts +0 -1
  544. package/dist/extra/render/index.d.ts +0 -1
  545. package/dist/extra/render/index.js +0 -3
  546. package/dist/extra/render/index.js.map +0 -1
  547. package/dist/extra/sources.cjs +0 -21
  548. package/dist/extra/sources.cjs.map +0 -1
  549. package/dist/extra/sources.d.cts +0 -1
  550. package/dist/extra/sources.d.ts +0 -1
  551. package/dist/extra/sources.js +0 -3
  552. package/dist/extra/sources.js.map +0 -1
  553. package/dist/extra/storage-browser.cjs +0 -21
  554. package/dist/extra/storage-browser.cjs.map +0 -1
  555. package/dist/extra/storage-browser.d.cts +0 -1
  556. package/dist/extra/storage-browser.d.ts +0 -1
  557. package/dist/extra/storage-browser.js +0 -3
  558. package/dist/extra/storage-browser.js.map +0 -1
  559. package/dist/extra/storage-core.cjs +0 -21
  560. package/dist/extra/storage-core.cjs.map +0 -1
  561. package/dist/extra/storage-core.d.cts +0 -1
  562. package/dist/extra/storage-core.d.ts +0 -1
  563. package/dist/extra/storage-core.js +0 -3
  564. package/dist/extra/storage-core.js.map +0 -1
  565. package/dist/extra/storage-node.cjs +0 -21
  566. package/dist/extra/storage-node.cjs.map +0 -1
  567. package/dist/extra/storage-node.d.cts +0 -1
  568. package/dist/extra/storage-node.d.ts +0 -1
  569. package/dist/extra/storage-node.js +0 -3
  570. package/dist/extra/storage-node.js.map +0 -1
  571. package/dist/extra/storage-tiers-browser.cjs +0 -21
  572. package/dist/extra/storage-tiers-browser.cjs.map +0 -1
  573. package/dist/extra/storage-tiers-browser.d.cts +0 -1
  574. package/dist/extra/storage-tiers-browser.d.ts +0 -1
  575. package/dist/extra/storage-tiers-browser.js +0 -3
  576. package/dist/extra/storage-tiers-browser.js.map +0 -1
  577. package/dist/extra/storage-tiers-node.cjs +0 -21
  578. package/dist/extra/storage-tiers-node.cjs.map +0 -1
  579. package/dist/extra/storage-tiers-node.d.cts +0 -1
  580. package/dist/extra/storage-tiers-node.d.ts +0 -1
  581. package/dist/extra/storage-tiers-node.js +0 -3
  582. package/dist/extra/storage-tiers-node.js.map +0 -1
  583. package/dist/extra/storage-tiers.cjs +0 -21
  584. package/dist/extra/storage-tiers.cjs.map +0 -1
  585. package/dist/extra/storage-tiers.d.cts +0 -1
  586. package/dist/extra/storage-tiers.d.ts +0 -1
  587. package/dist/extra/storage-tiers.js +0 -3
  588. package/dist/extra/storage-tiers.js.map +0 -1
  589. package/dist/extra/storage-wal.cjs +0 -21
  590. package/dist/extra/storage-wal.cjs.map +0 -1
  591. package/dist/extra/storage-wal.d.cts +0 -1
  592. package/dist/extra/storage-wal.d.ts +0 -1
  593. package/dist/extra/storage-wal.js +0 -3
  594. package/dist/extra/storage-wal.js.map +0 -1
  595. package/dist/graph/index.cjs +0 -21
  596. package/dist/graph/index.cjs.map +0 -1
  597. package/dist/graph/index.d.cts +0 -1
  598. package/dist/graph/index.d.ts +0 -1
  599. package/dist/graph/index.js +0 -3
  600. package/dist/graph/index.js.map +0 -1
  601. package/dist/patterns/ai/browser.cjs +0 -21
  602. package/dist/patterns/ai/browser.cjs.map +0 -1
  603. package/dist/patterns/ai/browser.d.cts +0 -1
  604. package/dist/patterns/ai/browser.d.ts +0 -1
  605. package/dist/patterns/ai/browser.js +0 -3
  606. package/dist/patterns/ai/browser.js.map +0 -1
  607. package/dist/patterns/ai/index.cjs +0 -21
  608. package/dist/patterns/ai/index.cjs.map +0 -1
  609. package/dist/patterns/ai/index.d.cts +0 -1
  610. package/dist/patterns/ai/index.d.ts +0 -1
  611. package/dist/patterns/ai/index.js +0 -3
  612. package/dist/patterns/ai/index.js.map +0 -1
  613. package/dist/patterns/ai/node.cjs +0 -21
  614. package/dist/patterns/ai/node.cjs.map +0 -1
  615. package/dist/patterns/ai/node.d.cts +0 -1
  616. package/dist/patterns/ai/node.d.ts +0 -1
  617. package/dist/patterns/ai/node.js +0 -3
  618. package/dist/patterns/ai/node.js.map +0 -1
  619. package/dist/patterns/cqrs/index.cjs +0 -21
  620. package/dist/patterns/cqrs/index.cjs.map +0 -1
  621. package/dist/patterns/cqrs/index.d.cts +0 -1
  622. package/dist/patterns/cqrs/index.d.ts +0 -1
  623. package/dist/patterns/cqrs/index.js +0 -3
  624. package/dist/patterns/cqrs/index.js.map +0 -1
  625. package/dist/patterns/demo-shell/index.cjs +0 -21
  626. package/dist/patterns/demo-shell/index.cjs.map +0 -1
  627. package/dist/patterns/demo-shell/index.d.cts +0 -1
  628. package/dist/patterns/demo-shell/index.d.ts +0 -1
  629. package/dist/patterns/demo-shell/index.js +0 -3
  630. package/dist/patterns/demo-shell/index.js.map +0 -1
  631. package/dist/patterns/domain-templates/index.cjs +0 -21
  632. package/dist/patterns/domain-templates/index.cjs.map +0 -1
  633. package/dist/patterns/domain-templates/index.d.cts +0 -1
  634. package/dist/patterns/domain-templates/index.d.ts +0 -1
  635. package/dist/patterns/domain-templates/index.js +0 -3
  636. package/dist/patterns/domain-templates/index.js.map +0 -1
  637. package/dist/patterns/graphspec/index.cjs +0 -21
  638. package/dist/patterns/graphspec/index.cjs.map +0 -1
  639. package/dist/patterns/graphspec/index.d.cts +0 -1
  640. package/dist/patterns/graphspec/index.d.ts +0 -1
  641. package/dist/patterns/graphspec/index.js +0 -3
  642. package/dist/patterns/graphspec/index.js.map +0 -1
  643. package/dist/patterns/harness/index.cjs +0 -21
  644. package/dist/patterns/harness/index.cjs.map +0 -1
  645. package/dist/patterns/harness/index.d.cts +0 -1
  646. package/dist/patterns/harness/index.d.ts +0 -1
  647. package/dist/patterns/harness/index.js +0 -3
  648. package/dist/patterns/harness/index.js.map +0 -1
  649. package/dist/patterns/inspect/index.cjs +0 -21
  650. package/dist/patterns/inspect/index.cjs.map +0 -1
  651. package/dist/patterns/inspect/index.d.cts +0 -1
  652. package/dist/patterns/inspect/index.d.ts +0 -1
  653. package/dist/patterns/inspect/index.js +0 -3
  654. package/dist/patterns/inspect/index.js.map +0 -1
  655. package/dist/patterns/job-queue/index.cjs +0 -21
  656. package/dist/patterns/job-queue/index.cjs.map +0 -1
  657. package/dist/patterns/job-queue/index.d.cts +0 -1
  658. package/dist/patterns/job-queue/index.d.ts +0 -1
  659. package/dist/patterns/job-queue/index.js +0 -3
  660. package/dist/patterns/job-queue/index.js.map +0 -1
  661. package/dist/patterns/memory/index.cjs +0 -21
  662. package/dist/patterns/memory/index.cjs.map +0 -1
  663. package/dist/patterns/memory/index.d.cts +0 -1
  664. package/dist/patterns/memory/index.d.ts +0 -1
  665. package/dist/patterns/memory/index.js +0 -3
  666. package/dist/patterns/memory/index.js.map +0 -1
  667. package/dist/patterns/messaging/index.cjs +0 -21
  668. package/dist/patterns/messaging/index.cjs.map +0 -1
  669. package/dist/patterns/messaging/index.d.cts +0 -1
  670. package/dist/patterns/messaging/index.d.ts +0 -1
  671. package/dist/patterns/messaging/index.js +0 -3
  672. package/dist/patterns/messaging/index.js.map +0 -1
  673. package/dist/patterns/orchestration/index.cjs +0 -21
  674. package/dist/patterns/orchestration/index.cjs.map +0 -1
  675. package/dist/patterns/orchestration/index.d.cts +0 -1
  676. package/dist/patterns/orchestration/index.d.ts +0 -1
  677. package/dist/patterns/orchestration/index.js +0 -3
  678. package/dist/patterns/orchestration/index.js.map +0 -1
  679. package/dist/patterns/process/index.cjs +0 -21
  680. package/dist/patterns/process/index.cjs.map +0 -1
  681. package/dist/patterns/process/index.d.cts +0 -1
  682. package/dist/patterns/process/index.d.ts +0 -1
  683. package/dist/patterns/process/index.js +0 -3
  684. package/dist/patterns/process/index.js.map +0 -1
  685. package/dist/patterns/reactive-layout/index.cjs +0 -21
  686. package/dist/patterns/reactive-layout/index.cjs.map +0 -1
  687. package/dist/patterns/reactive-layout/index.d.cts +0 -1
  688. package/dist/patterns/reactive-layout/index.d.ts +0 -1
  689. package/dist/patterns/reactive-layout/index.js +0 -3
  690. package/dist/patterns/reactive-layout/index.js.map +0 -1
  691. package/dist/patterns/reduction/index.cjs +0 -21
  692. package/dist/patterns/reduction/index.cjs.map +0 -1
  693. package/dist/patterns/reduction/index.d.cts +0 -1
  694. package/dist/patterns/reduction/index.d.ts +0 -1
  695. package/dist/patterns/reduction/index.js +0 -3
  696. package/dist/patterns/reduction/index.js.map +0 -1
  697. package/dist/patterns/surface/index.cjs +0 -21
  698. package/dist/patterns/surface/index.cjs.map +0 -1
  699. package/dist/patterns/surface/index.d.cts +0 -1
  700. package/dist/patterns/surface/index.d.ts +0 -1
  701. package/dist/patterns/surface/index.js +0 -3
  702. package/dist/patterns/surface/index.js.map +0 -1
  703. package/dist/patterns/topology-view/index.cjs +0 -21
  704. package/dist/patterns/topology-view/index.cjs.map +0 -1
  705. package/dist/patterns/topology-view/index.d.cts +0 -1
  706. package/dist/patterns/topology-view/index.d.ts +0 -1
  707. package/dist/patterns/topology-view/index.js +0 -3
  708. package/dist/patterns/topology-view/index.js.map +0 -1
  709. package/dist/testing/index.cjs +0 -21
  710. package/dist/testing/index.cjs.map +0 -1
  711. package/dist/testing/index.d.cts +0 -1
  712. package/dist/testing/index.d.ts +0 -1
  713. package/dist/testing/index.js +0 -3
  714. package/dist/testing/index.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/presets/ai/agent-loop.ts","../src/presets/ai/agent.ts","../src/presets/ai/agents.ts"],"sourcesContent":["/**\n * Reactive agent loop — autonomous multi-turn LLM agent with tool execution.\n */\n\nexport type AgentLoopStatus = \"idle\" | \"thinking\" | \"acting\" | \"done\" | \"error\";\n\nimport {\n\tbatch,\n\tDATA,\n\tERROR,\n\tINVALIDATE,\n\ttype Node,\n\tnode,\n\tnode as nodeFactory,\n\tplaceholderArgs,\n\tRESOLVED,\n} from \"@graphrefly/pure-ts/core\";\nimport { fromAny, keepalive, switchMap } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { awaitSettled } from \"../../base/sources/settled.js\";\nimport { aiMeta } from \"../../utils/ai/_internal.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMResponse,\n\tToolCall,\n\tToolDefinition,\n} from \"../../utils/ai/adapters/core/types.js\";\nimport { type ChatStreamGraph, chatStream } from \"../../utils/ai/agents/chat-stream.js\";\nimport { type ToolResult, toolExecution } from \"../../utils/ai/agents/tool-execution.js\";\nimport { type ToolRegistryGraph, toolRegistry } from \"../../utils/ai/agents/tool-registry.js\";\n\nexport type { ToolResult } from \"../../utils/ai/agents/tool-execution.js\";\n\n// ---------------------------------------------------------------------------\n// agentLoop\n// ---------------------------------------------------------------------------\n\nexport type AgentLoopOptions = {\n\tgraph?: GraphOptions;\n\tadapter: LLMAdapter;\n\ttools?: readonly ToolDefinition[];\n\tsystemPrompt?: string;\n\tmaxTurns?: number;\n\tstopWhen?: (response: LLMResponse) => boolean;\n\tonToolCall?: (call: ToolCall) => void;\n\tmaxMessages?: number;\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\t/**\n\t * Reactive tool-call splice (COMPOSITION-GUIDE §31 \"interception is security\").\n\t * When set, the raw `toolCalls` node is piped through this transform before\n\t * reaching the executor. The transform is a pure reactive composition —\n\t * `(calls: Node<readonly ToolCall[]>) => Node<readonly ToolCall[]>` — so the\n\t * gate is visible in `describe()` / `explain()` as a real edge (no hidden\n\t * imperative wraps; §24).\n\t *\n\t * Typical uses:\n\t * - **Filter / block** — `derived([calls, policy], ([raw, p]) => raw.filter(p))`\n\t * - **Throttle / debounce** — `throttle(calls, windowMs)`\n\t * - **Human-in-the-loop approval** — pipe through a `gate` controller so\n\t * calls wait for human approval before reaching the executor.\n\t *\n\t * The public `agent.toolCalls` node surfaces the POST-intercept stream, so\n\t * audit / telemetry consumers see what the executor actually runs. The raw\n\t * pre-intercept stream is not exposed — tests that need it should run\n\t * without `interceptToolCalls` set (the identity case).\n\t */\n\tinterceptToolCalls?: (calls: Node<readonly ToolCall[]>) => Node<readonly ToolCall[]>;\n};\n\n/**\n * Reactive agent loop.\n *\n * The loop is a reactive state machine wired entirely from graph primitives:\n * `chat.messages` + `tools.schemas` + gating state feed a `promptInput`\n * derived; `switchMap` turns non-null inputs into an LLM invocation via\n * `fromAny(adapter.invoke(...))`. The LLM response drives chat writes and\n * status transitions via effects. Tool calls flow through a reactive\n * executor (`retrySource` + `rescue`) that retries once on error and\n * surfaces terminal errors as JSON-shaped `ToolResult` payloads for the\n * LLM to react to.\n *\n * **No imperative control flow inside the reactive layer** (spec §5.8-5.12):\n * no `while` loops, no manual `await adapter.invoke`, no polling.\n * `agent.run()` is a thin `awaitSettled` bridge so callers can still `await`\n * the loop if they want a Promise.\n *\n * Public surface:\n * - `chat` / `tools` — subgraphs (imperative `append` at boundary, reactive `executeReactive` for tool invocation)\n * - `status` / `turn` / `aborted` — state nodes with explicit initials\n * - `lastResponse` / `toolCalls` / `toolResults` — reactive outputs (SENTINEL until first emission; callers use `awaitSettled` / `subscribe`)\n * - `run(userMessage?, signal?)` — optional user append + Promise bridge\n * - `abort()` — imperative abort shim; flips `aborted` state\n *\n * **Lifecycle: single-mount.** `AgentLoopGraph` instances expect to be\n * constructed once and used until `destroy()`. The internal closure mirrors\n * (`latestTurn` / `latestAborted` / `latestStatus`) are wired by\n * subscribe-and-capture at construction time; their `addDisposer`-registered\n * subscriptions are torn down on subgraph unmount or `destroy()`. After\n * teardown the mirrors freeze at their last value, so re-using a destroyed\n * instance — calling `run()` again, or remounting under a new parent —\n * would silently feed stale mirror data into reactive fn bodies. If you\n * need to \"reset\" an agent, build a fresh `AgentLoopGraph` instance instead\n * of recycling.\n */\nexport class AgentLoopGraph extends Graph {\n\treadonly chat: ChatStreamGraph;\n\treadonly tools: ToolRegistryGraph;\n\n\t/** Current agent status. `initial: \"idle\"` — always has a real value. */\n\treadonly status: Node<AgentLoopStatus>;\n\t/** Turn count (completed LLM invocations this run). `initial: 0`. */\n\treadonly turn: Node<number>;\n\t/** Aborted flag; flipped by `abort()` or external `AbortSignal`. `initial: false`. */\n\treadonly aborted: Node<boolean>;\n\n\t/**\n\t * Most recent LLM response. State-backed mirror driven by the response\n\t * effect. **Stays SENTINEL** (`cache === undefined`, no DATA emitted)\n\t * until the first real response — bridge subscribers see no spurious\n\t * push-on-subscribe DATA. After a real response, holds the latest\n\t * `LLMResponse`. Reset between `run()` calls via `[[INVALIDATE]]` (clears\n\t * cache back to SENTINEL) so a second run with a pre-aborted signal\n\t * cannot leak the prior run's response. Bridge with\n\t * `awaitSettled(lastResponse)` for the first DATA as a Promise; consumers\n\t * inside reactive fns gate on `ctx.prevData[i] === undefined`.\n\t */\n\treadonly lastResponse: Node<LLMResponse>;\n\t/** Tool-call batch emitted by the most recent LLM response. SENTINEL. */\n\treadonly toolCalls: Node<readonly ToolCall[]>;\n\t/** Tool-result batch (one entry per call) after reactive execution. SENTINEL. */\n\treadonly toolResults: Node<readonly ToolResult[]>;\n\n\tprivate readonly _terminalResult: Node<LLMResponse>;\n\tprivate readonly _disposeRunWiring: () => void;\n\t/** Guards against overlapping `run()` calls. */\n\tprivate _running = false;\n\t/**\n\t * Abort controller for the currently-running `adapter.invoke`. Minted per\n\t * switchMap project; aborted when the reactive `aborted` node flips true\n\t * OR when the caller's external `AbortSignal` fires. Threaded into\n\t * `adapter.invoke({ signal })` AND `fromAny(promise, { signal })`, so the\n\t * reactive layer sees ERROR when the wire call is cancelled.\n\t */\n\tprivate _currentAbortController: AbortController | null = null;\n\n\tconstructor(name: string, opts: AgentLoopOptions) {\n\t\tsuper(name, opts.graph);\n\n\t\t// Mount chat subgraph\n\t\tthis.chat = chatStream(`${name}-chat`, { maxMessages: opts.maxMessages });\n\t\tthis.mount(\"chat\", this.chat);\n\n\t\t// Mount tool registry subgraph\n\t\tthis.tools = toolRegistry(`${name}-tools`);\n\t\tthis.mount(\"tools\", this.tools);\n\n\t\tif (opts.tools) {\n\t\t\tfor (const tool of opts.tools) {\n\t\t\t\tthis.tools.register(tool);\n\t\t\t}\n\t\t}\n\n\t\t// --- State nodes (always have a real value; explicit initials) ---\n\t\tthis.status = node<AgentLoopStatus>([], {\n\t\t\t...{\n\t\t\t\tname: \"status\",\n\t\t\t\tdescribeKind: \"state\",\n\t\t\t\tmeta: aiMeta(\"agent_status\"),\n\t\t\t},\n\t\t\tinitial: \"idle\",\n\t\t});\n\t\tthis.add(this.status, { name: \"status\" });\n\n\t\tthis.turn = node<number>([], {\n\t\t\t...{\n\t\t\t\tname: \"turn\",\n\t\t\t\tdescribeKind: \"state\",\n\t\t\t\tmeta: aiMeta(\"agent_turn_count\"),\n\t\t\t},\n\t\t\tinitial: 0,\n\t\t});\n\t\tthis.add(this.turn, { name: \"turn\" });\n\n\t\tthis.aborted = node<boolean>([], {\n\t\t\t...{\n\t\t\t\tname: \"aborted\",\n\t\t\t\tdescribeKind: \"state\",\n\t\t\t\tmeta: aiMeta(\"agent_aborted\"),\n\t\t\t},\n\t\t\tinitial: false,\n\t\t});\n\t\tthis.add(this.aborted, { name: \"aborted\" });\n\n\t\t// --- Reactive pipeline ---\n\t\t//\n\t\t// **Read pattern (Phase 12 D1 lock + F2 fix 2026-05-01).** State\n\t\t// scratchpad held on this `AgentLoopGraph` (turn / aborted / chat /\n\t\t// tools) is read inside reactive fn bodies via either:\n\t\t// (a) `data[i]` / `ctx.prevData[i]` for declared deps, OR\n\t\t// (b) sole-owner `.cache` reads on subgraph-mounted state Nodes\n\t\t// (chat / tools mounted as subgraphs of this Graph; the agent\n\t\t// is the sole owner; promptInput / effResponse / effResults\n\t\t// live in the same enclosing constructor scope — sanctioned\n\t\t// form per Phase 12 D1 read-pattern lock).\n\t\t//\n\t\t// Closure mirrors (`latestTurn` / `latestAborted` / `latestStatus`)\n\t\t// are kept ONLY for fields where (b) doesn't simplify the call site\n\t\t// — turn / aborted / status are state Nodes registered on `this`\n\t\t// directly (not subgraphs), and the closure form keeps\n\t\t// effResponse's batch logic readable. They are CORRECT but are NOT\n\t\t// safe under nested drains (the subscribe handler may not have run\n\t\t// yet when a downstream fn reads the closure). For nested-drain-\n\t\t// reachable reads (promptInput, called via `agentLoop.run` from\n\t\t// inside another graph's reactive subscribe handler), prefer (a) or\n\t\t// (b) over the closure mirror. F2 root cause: chat.messages.cache\n\t\t// is updated DURING the DATA-settle phase (before subscribers\n\t\t// run), so `.cache` reads are always at least as fresh as closure\n\t\t// mirrors. See `optimizations.md` \"Phase 13 design-session inputs\n\t\t// from §13.M lock-test\" F2.\n\t\t//\n\t\t// **Pattern note on `latestTurn` staleness under in-batch reads.**\n\t\t// Effect 1 emits `turnNode.emit(next)` inside its batch; Effect 2\n\t\t// reads `latestTurn` on the following wave (after toolResults\n\t\t// settle). Because batch drain is FIFO, `turnSub`'s handler runs\n\t\t// before Effect 2's next wave fires, so `latestTurn` is up-to-date\n\t\t// by the time Effect 2 reads it. This invariant is stable as long\n\t\t// as `turnNode.emit` remains inside Effect 1's batch — a future\n\t\t// refactor that un-batches the emit would regress silently.\n\t\tlet latestTurn = 0;\n\t\tconst turnSub = this.turn.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) if (m[0] === DATA) latestTurn = m[1] as number;\n\t\t});\n\t\tlet latestAborted = false;\n\t\tconst abortedSub = this.aborted.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) if (m[0] === DATA) latestAborted = m[1] as boolean;\n\t\t});\n\n\t\tconst adapter = opts.adapter;\n\t\tconst systemPrompt = opts.systemPrompt;\n\t\tconst model = opts.model;\n\t\tconst temperature = opts.temperature;\n\t\tconst maxTokens = opts.maxTokens;\n\t\tconst maxTurns = opts.maxTurns ?? 10;\n\t\tconst stopWhen = opts.stopWhen;\n\n\t\t// Capture `this` for closures that don't bind `this`.\n\t\tconst chat = this.chat;\n\t\tconst tools = this.tools;\n\t\tconst statusNode = this.status;\n\t\tconst turnNode = this.turn;\n\t\tconst abortedNode = this.aborted;\n\n\t\t// promptInput: STATUS is the only reactive trigger — chat.messages,\n\t\t// tools.schemas, turn, aborted are sampled via closure-held mirrors\n\t\t// (all populated by subscribe-and-capture above). This prevents the\n\t\t// classic feedback cycle (COMPOSITION-GUIDE §7): if chat.messageCount\n\t\t// were a reactive dep here, effect 1's `chat.append` would trigger a\n\t\t// promptInput wave, which under effect-1's batch would see status\n\t\t// STILL \"thinking\" (pre-drain) and fire a spurious LLM invocation.\n\t\t// By gating only on status, chat writes don't re-trigger — only\n\t\t// explicit status transitions do.\n\t\tconst promptInput: Node<InvokeInput> = nodeFactory<InvokeInput>(\n\t\t\t[statusNode],\n\t\t\t(data, actions, ctx) => {\n\t\t\t\tconst stat = readLatest<AgentLoopStatus>(data, ctx.prevData, 0, \"idle\");\n\t\t\t\tif (stat !== \"thinking\" || latestAborted || latestTurn >= maxTurns) {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// F2 fix (2026-05-01): under nested drains, the closure mirrors\n\t\t\t\t// `latestMessages` / `latestSchemas` lag the actual node state —\n\t\t\t\t// messagesSub / schemasSub subscribers may not have run yet when\n\t\t\t\t// promptInput fires (the drain processes status's downstream\n\t\t\t\t// before chat.messages's subscribers fire, even though\n\t\t\t\t// chat.messages.cache is already settled). Read `.cache`\n\t\t\t\t// directly per Phase 12 D1 read-pattern lock: chat / tools are\n\t\t\t\t// mounted as subgraphs of this AgentLoopGraph (sole owner) and\n\t\t\t\t// promptInput is a reactive reader in the same enclosing\n\t\t\t\t// constructor scope — sanctioned `.cache` form. See\n\t\t\t\t// `optimizations.md` \"Phase 13 design-session inputs from §13.M\n\t\t\t\t// lock-test\" F2.\n\t\t\t\tconst messages = (this.chat.messages.cache as readonly ChatMessage[] | undefined) ?? [];\n\t\t\t\tif (messages.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\tconst schemas = (this.tools.schemas.cache as readonly ToolDefinition[] | undefined) ?? [];\n\t\t\t\tactions.emit({ messages, tools: schemas });\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"promptInput\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"agent_prompt_input\", {\n\t\t\t\t\t// State this fn body samples beyond its declared `statusNode`\n\t\t\t\t\t// dep. `aborted` / `turn` come from §28 closure mirrors\n\t\t\t\t\t// (`latestAborted` / `latestTurn`); `chat.messages` /\n\t\t\t\t\t// `tools.schemas` come from sole-owner `.cache` reads\n\t\t\t\t\t// (Phase 12 D1 lock + F2 fix; see comment block above).\n\t\t\t\t\t// Listed here so inspection tooling can surface fold-in\n\t\t\t\t\t// state without grepping source.\n\t\t\t\t\tclosureReads: [\"aborted\", \"turn\", \"chat.messages\", \"tools.schemas\"],\n\t\t\t\t}),\n\t\t\t},\n\t\t);\n\n\t\tconst llmResponse: Node<LLMResponse> = switchMap(\n\t\t\tpromptInput,\n\t\t\t(input) => {\n\t\t\t\tconst controller = new AbortController();\n\t\t\t\tthis._currentAbortController = controller;\n\t\t\t\tif (latestAborted) {\n\t\t\t\t\tcontroller.abort(new Error(\"agentLoop: aborted\"));\n\t\t\t\t}\n\t\t\t\t// Wave A Unit B-CC fix: drop the `Promise.resolve(adapter.invoke(...))`\n\t\t\t\t// wrapper. `adapter.invoke` returns a `NodeInput<LLMResponse>`\n\t\t\t\t// (Promise | Node | raw). `fromAny` already handles all three\n\t\t\t\t// shapes; the manual `Promise.resolve` wrapper would force a\n\t\t\t\t// Node-returning adapter into an extra microtask hop and lose\n\t\t\t\t// reactivity (see Unit 11 + Unit 1 for the parallel cleanup).\n\t\t\t\treturn fromAny(\n\t\t\t\t\tadapter.invoke(input.messages, {\n\t\t\t\t\t\ttools: input.tools.length > 0 ? input.tools : undefined,\n\t\t\t\t\t\tsystemPrompt,\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\ttemperature,\n\t\t\t\t\t\tmaxTokens,\n\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t}),\n\t\t\t\t\t{ signal: controller.signal },\n\t\t\t\t);\n\t\t\t},\n\t\t\t{ equals: () => false },\n\t\t);\n\n\t\t// State mirror for `lastResponse` — exists for **cross-run reset\n\t\t// semantics**, NOT the §32 mid-wave hazard.\n\t\t//\n\t\t// Why: `llmResponse` is a switchMap output; its cache persists across\n\t\t// `run()` calls (switchMap's output node has no built-in reset path —\n\t\t// the cache stays at the last DATA the inner emitted). A second\n\t\t// `run()` with a pre-aborted signal would otherwise have\n\t\t// `_terminalResult` evaluate `stat=done` (driven by `effAbort`) +\n\t\t// `resp=<prior run's response>` (cached on `llmResponse`) and resolve\n\t\t// the Promise with stale data instead of rejecting with AbortError.\n\t\t// The mirror is **reset via `[[INVALIDATE]]`** in `run()`'s reset\n\t\t// batch — INVALIDATE clears `_cached` back to `undefined` (SENTINEL)\n\t\t// AND clears the `prevData` slot on every dependent (`_terminalResult`,\n\t\t// `toolCallsRaw`), so the abort path correctly emits\n\t\t// `[[ERROR, AbortError]]` from terminalResult's `stat=\"done\" &&\n\t\t// prevData[lastResponse] === undefined → ERROR` guard.\n\t\t//\n\t\t// **No `T | null` placeholder.** Per `feedback_use_prevdata_for_sentinel`\n\t\t// + COMPOSITION-GUIDE §1a, the SENTINEL state IS the \"never sent\n\t\t// real DATA yet\" signal. An eager `initial: null` would push `[null]`\n\t\t// to every fresh subscriber — a footgun for bridge subscribers that\n\t\t// would otherwise need `if (resp == null) continue` guards. Stay\n\t\t// SENTINEL; consumers detect \"no response yet\" via\n\t\t// `ctx.prevData[i] === undefined` (or `cache === undefined` outside\n\t\t// reactive fns). F9 lock-test (`multi-agent-example.test.ts` test 5)\n\t\t// pins this invariant.\n\t\t//\n\t\t// What this does NOT solve: the §32 mid-wave \"stale peer-read\"\n\t\t// hazard. Investigation (2026-04-25) confirmed `_dirtyDepCount`\n\t\t// gating in `_maybeRunFnOnSettlement` already prevents that — when\n\t\t// `effResponse`'s nested batch fires `status=\"done\"` mid-iteration,\n\t\t// terminal's status dep settles but its `llmResponse` (or mirror)\n\t\t// dep is still DIRTY from Phase 1, so the fn does not run until\n\t\t// Phase 2 visits both deps. Verified by fast-check invariant `#12b\n\t\t// nested-drain-peer-consistency-compound` and by the multi-turn\n\t\t// `executes tool calls and loops` test passing under either dep\n\t\t// shape (`[statusNode, llmResponse]` or `[statusNode, lastResponseState]`).\n\t\t//\n\t\t// Verified by: QA C3 regression tests (`run() with pre-aborted\n\t\t// signal rejects AbortError` and `second run() with pre-aborted\n\t\t// signal rejects AbortError (no stale response leak)`) — both\n\t\t// fail when `_terminalResult` is rewired to depend on `llmResponse`\n\t\t// directly. See COMPOSITION-GUIDE §32 (cross-wave reset reframe).\n\t\tconst lastResponseState = node<LLMResponse>([], {\n\t\t\tname: \"lastResponse\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"agent_last_response\"),\n\t\t});\n\t\tthis.lastResponse = lastResponseState;\n\n\t\t// toolCalls: raw node that emits DATA only when status === \"acting\" and\n\t\t// the current response has tool calls. Otherwise emits RESOLVED. Using\n\t\t// DATA([]) for the idle case would cause switchMap(toolCalls) to\n\t\t// re-dispatch its inner (creating a fresh node([], { initial: [] }) source whose\n\t\t// emissions re-trigger effects downstream). RESOLVED keeps the inner\n\t\t// alive and lets upstream waves pass through without re-dispatch.\n\t\t// Inner raw tool-call stream — name `toolCallsRaw` so the post-intercept\n\t\t// public surface (`this.toolCalls`) is unambiguous in `describe()`.\n\t\t// QA-fix: previously the inner was named `\"toolCalls\"`, which collided\n\t\t// with `this.toolCalls` if the user-supplied interceptor returned a\n\t\t// wrapper that internally retained a reference to this raw node —\n\t\t// `describe()` would render two distinct nodes both labeled `\"toolCalls\"`.\n\t\tconst toolCallsRaw = nodeFactory<readonly ToolCall[]>(\n\t\t\t[lastResponseState, statusNode],\n\t\t\t(data, actions, ctx) => {\n\t\t\t\t// SENTINEL guard: `lastResponseState` stays `undefined` (cache\n\t\t\t\t// + prevData) until the first real response. `readLatest`'s\n\t\t\t\t// fallback returns `undefined` here so the no-DATA branch is\n\t\t\t\t// indistinguishable from the protocol SENTINEL — both gate to\n\t\t\t\t// RESOLVED. Per `feedback_use_prevdata_for_sentinel`.\n\t\t\t\tconst resp = readLatest<LLMResponse | undefined>(data, ctx.prevData, 0, undefined);\n\t\t\t\tconst stat = readLatest<AgentLoopStatus>(data, ctx.prevData, 1, \"idle\");\n\t\t\t\tif (stat !== \"acting\") {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst calls = resp?.toolCalls;\n\t\t\t\tif (calls == null || calls.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(calls);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"toolCallsRaw\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"agent_tool_calls_raw\"),\n\t\t\t},\n\t\t);\n\t\t// Reactive splice (D9 / COMPOSITION-GUIDE §31). When `interceptToolCalls`\n\t\t// is set, the raw tool-call stream is transformed in the graph — the\n\t\t// executor sees the gated stream, and `agent.toolCalls` surfaces the\n\t\t// post-intercept view so audit / telemetry match reality.\n\t\tconst gatedToolCallsNode = opts.interceptToolCalls\n\t\t\t? opts.interceptToolCalls(toolCallsRaw)\n\t\t\t: toolCallsRaw;\n\t\tthis.toolCalls = gatedToolCallsNode;\n\n\t\t// Delegate per-call fan-out + retry + rescue to the `toolExecution`\n\t\t// primitive. `toolCallsRaw` already gates empty batches to RESOLVED,\n\t\t// so `toolExecution`'s \"non-empty batch only\" contract is satisfied\n\t\t// upstream. `retryCount: 1` matches the pre-extraction behaviour\n\t\t// (one retry after first failure = 2 attempts total).\n\t\tconst toolResultsNode: Node<readonly ToolResult[]> = toolExecution({\n\t\t\ttoolCalls: gatedToolCallsNode,\n\t\t\ttools,\n\t\t\tretryCount: 1,\n\t\t});\n\t\tthis.toolResults = toolResultsNode;\n\n\t\t// --- State-machine effects ---\n\t\t// Effect 1: LLM response landed → write lastResponse mirror + chat,\n\t\t// transition status, increment turn. Emission ORDER inside the batch\n\t\t// matters (drain is FIFO under any outer-batch depth):\n\t\t// 1. `lastResponseState.emit(response)` FIRST — so when the drain\n\t\t// fires the status=done wave later in the queue, `_terminalResult`'s\n\t\t// dep on `lastResponseState` has already been updated.\n\t\t// 2. `statusNode.emit(nextStatus)` — drives state machine.\n\t\t// 3. `turnNode.emit(next)` — counter.\n\t\t// 4. `chat.append(...)` LAST — chat.messageCount wave now sees the\n\t\t// new status (so `promptInput` gates correctly).\n\t\t// Without (1) first, `_terminalResult` reads stale `prevData` for\n\t\t// lastResponse when status transitions synchronously during drain.\n\t\t//\n\t\t// **Invariant independence from outer batch depth.** `downWithBatch`\n\t\t// preserves FIFO drain order regardless of nesting — whether the\n\t\t// outer batch is at depth 0 (common: Promise microtask) or depth >0\n\t\t// (user-composed `batch()` scope around `agent.run()`), the emissions\n\t\t// above drain in the order they were enqueued. The state-mirror\n\t\t// pattern holds in both cases.\n\t\t//\n\t\t// **Abort guard (C2 defense-in-depth).** If the `aborted` state has\n\t\t// flipped true between `adapter.invoke`'s Promise resolution and this\n\t\t// effect firing (micro-race), bail out so we don't append to chat or\n\t\t// execute tool calls for an abandoned run. The controller.abort() in\n\t\t// effAbort also fires the signal, which causes `fromAny` to emit\n\t\t// ERROR — but that ERROR propagation arrives in a separate wave, so\n\t\t// this guard covers the \"Promise already resolved before abort hit\n\t\t// the controller\" case.\n\t\tconst effResponse = node(\n\t\t\t[llmResponse],\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\tif (latestAborted) return;\n\t\t\t\tconst response = data[0] as LLMResponse;\n\t\t\t\tconst next = latestTurn + 1;\n\t\t\t\tconst hasToolCalls = response.toolCalls != null && response.toolCalls.length > 0;\n\t\t\t\tconst naturalStop =\n\t\t\t\t\tresponse.finishReason === \"end_turn\" &&\n\t\t\t\t\t(!response.toolCalls || response.toolCalls.length === 0);\n\t\t\t\tconst customStop = stopWhen?.(response) === true;\n\t\t\t\tconst capReached = next >= maxTurns;\n\t\t\t\tconst nextStatus: AgentLoopStatus =\n\t\t\t\t\tcustomStop || naturalStop || !hasToolCalls || capReached ? \"done\" : \"acting\";\n\t\t\t\tbatch(() => {\n\t\t\t\t\tlastResponseState.emit(response);\n\t\t\t\t\tstatusNode.emit(nextStatus);\n\t\t\t\t\tturnNode.emit(next);\n\t\t\t\t\tchat.append(\"assistant\", response.content, {\n\t\t\t\t\t\ttoolCalls: response.toolCalls,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ describeKind: \"effect\" },\n\t\t);\n\n\t\t// Effect 2: Tool results landed → append to chat, transition to\n\t\t// thinking (or done if turn cap reached). Same ordering discipline —\n\t\t// status emits before chat mutations. Abort guard mirrors effResponse.\n\t\tconst effResults = node(\n\t\t\t[toolResultsNode],\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\tif (latestAborted) return;\n\t\t\t\tconst arr = data[0] as readonly ToolResult[];\n\t\t\t\tif (arr.length === 0) return;\n\t\t\t\tconst nextStatus: AgentLoopStatus = latestTurn >= maxTurns ? \"done\" : \"thinking\";\n\t\t\t\tbatch(() => {\n\t\t\t\t\tstatusNode.emit(nextStatus);\n\t\t\t\t\tfor (const r of arr) chat.appendToolResult(r.id, r.content);\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ describeKind: \"effect\" },\n\t\t);\n\n\t\t// Effect 3: external abort → cancel in-flight wire call + terminal status.\n\t\t// Aborting the controller causes the switchMap inner's `fromAny` to\n\t\t// emit ERROR (signal-bound), which tears down the subscription. The\n\t\t// `status=\"done\"` emit drives `_terminalResult` to resolve `run()`'s\n\t\t// Promise (via AbortError when `resp == null`, see C3).\n\t\t//\n\t\t// Unit 4 Q5: status guard — if status is already \"done\" (the natural-\n\t\t// completion path raced the abort), skip the redundant emit so the\n\t\t// status-node event log isn't polluted with a trailing duplicate.\n\t\t// Closure-mirror `latestStatus` keeps the comparison synchronous and\n\t\t// P3-compliant (closure read, not `.cache` read — see §28). Seeded\n\t\t// from `statusNode.cache` to match the §28 factory-time-seed pattern\n\t\t// that `latestTurn` / `latestAborted` use — the literal `\"idle\"` would\n\t\t// silently drift if the constructor initial value ever changed.\n\t\tlet latestStatus: AgentLoopStatus = (statusNode.cache as AgentLoopStatus | undefined) ?? \"idle\";\n\t\tconst statusSub = statusNode.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) if (m[0] === DATA) latestStatus = m[1] as AgentLoopStatus;\n\t\t});\n\t\tconst effAbort = node(\n\t\t\t[abortedNode],\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\tif (data[0] === true) {\n\t\t\t\t\tthis._currentAbortController?.abort(new Error(\"agentLoop: aborted\"));\n\t\t\t\t\tif (latestStatus !== \"done\") statusNode.emit(\"done\");\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ describeKind: \"effect\" },\n\t\t);\n\n\t\t// Keepalive so the pipeline stays activated even without external\n\t\t// subscribers. Callers don't need to subscribe to `llmResponse` /\n\t\t// `toolResults` for the loop to run.\n\t\tconst kaResponse = keepalive(effResponse);\n\t\tconst kaResults = keepalive(effResults);\n\t\tconst kaAbort = keepalive(effAbort);\n\n\t\t// terminalResult emits the final `LLMResponse` on each \"done\"\n\t\t// transition. The old compound `{response, runVersion}` shape existed\n\t\t// to let a re-entrant caller's `awaitSettled` predicate filter out\n\t\t// the PREVIOUS run's cached DATA; that job now belongs to\n\t\t// `awaitSettled({skipCurrent: true})` (extra/sources.ts) which\n\t\t// ignores the initial push-on-subscribe DATA and resolves only on\n\t\t// fresh post-subscribe emissions. Retiring the stamp removes a\n\t\t// closure-held counter and a per-emission object allocation from\n\t\t// the hot path.\n\t\t//\n\t\t// C3 (abort-before-response) post-SENTINEL: when `stat === \"done\"` but\n\t\t// `lastResponseState` is SENTINEL (no DATA ever delivered for this\n\t\t// run — `prevData[1] === undefined`, equivalently `resp === undefined`\n\t\t// after `readLatest`'s fallback), emit `ERROR(AbortError)` so the\n\t\t// awaiting Promise rejects instead of hanging on a RESOLVED. The\n\t\t// SENTINEL state is restored at every `run()` boundary by\n\t\t// `lastResponse.down([[INVALIDATE]])` (clears `_cached` AND clears\n\t\t// each dependent's `prevData` slot for this dep), so a second run\n\t\t// after a successful first run still detects the abort cleanly —\n\t\t// no stale `prevData` leak.\n\t\tthis._terminalResult = nodeFactory<LLMResponse>(\n\t\t\t[statusNode, lastResponseState],\n\t\t\t(data, actions, ctx) => {\n\t\t\t\tconst stat = readLatest<AgentLoopStatus>(data, ctx.prevData, 0, \"idle\");\n\t\t\t\tconst resp = readLatest<LLMResponse | undefined>(data, ctx.prevData, 1, undefined);\n\t\t\t\tif (stat === \"done\") {\n\t\t\t\t\tif (resp !== undefined) {\n\t\t\t\t\t\tactions.emit(resp);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst err = new Error(\"agentLoop: aborted\") as Error & { name: string };\n\t\t\t\t\terr.name = \"AbortError\";\n\t\t\t\t\tactions.down([[ERROR, err]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (stat === \"error\") {\n\t\t\t\t\tactions.down([[ERROR, new Error(\"agentLoop: errored\")]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"terminalResult\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"agent_terminal_result\"),\n\t\t\t\t// `lastResponseState` is SENTINEL until the first real response\n\t\t\t\t// arrives — without `partial: true`, the spec §2.7 first-run\n\t\t\t\t// gate would block this fn from ever firing on the abort-\n\t\t\t\t// before-response path (`status → \"done\"` while `lastResponse`\n\t\t\t\t// has never delivered DATA). The fn explicitly handles the\n\t\t\t\t// SENTINEL case (`resp === undefined → ERROR(AbortError)`),\n\t\t\t\t// so partial-fire is safe by design.\n\t\t\t\tpartial: true,\n\t\t\t},\n\t\t);\n\t\t// Wave B-CC Q2/C: register intermediate pipeline nodes so consumers\n\t\t// can `observe(path)` them by name (e.g. `agent.observe(\"promptInput\")`).\n\t\t// They were already visible in `describe()` via dep traversal, but not\n\t\t// path-addressable. Tools using the `observe`-by-path API now work.\n\t\t//\n\t\t// QA-fix (#5 stability): registrations live AFTER ALL dependent nodes\n\t\t// are constructed (`promptInput → llmResponse → effResponse →\n\t\t// lastResponseState → toolCallsRaw → toolResultsNode → effResults →\n\t\t// effAbort → _terminalResult`). Topology event-stream consumers\n\t\t// subscribed at construction time now see registrations in an order\n\t\t// where every edge between two registered nodes is already valid —\n\t\t// no transient partial graph slipping through to live mermaid / d2\n\t\t// renderers.\n\t\tthis.add(promptInput as Node<unknown>, { name: \"promptInput\" });\n\t\tthis.add(llmResponse as Node<unknown>, { name: \"llmResponse\" });\n\t\tthis.add(this.lastResponse as Node<unknown>, { name: \"lastResponse\" });\n\t\t// When no interceptor is configured, `this.toolCalls === toolCallsRaw` —\n\t\t// registering the same instance under two names trips the per-graph\n\t\t// `_nodeToName` collision check. Register the raw under `toolCalls`\n\t\t// directly in that case; otherwise register both (raw + post-intercept).\n\t\tif (this.toolCalls === toolCallsRaw) {\n\t\t\tthis.add(this.toolCalls as Node<unknown>, { name: \"toolCalls\" });\n\t\t} else {\n\t\t\tthis.add(toolCallsRaw as Node<unknown>, { name: \"toolCallsRaw\" });\n\t\t\tthis.add(this.toolCalls as Node<unknown>, { name: \"toolCalls\" });\n\t\t}\n\t\tthis.add(toolResultsNode as Node<unknown>, { name: \"toolResults\" });\n\t\tthis.add(this._terminalResult as Node<unknown>, { name: \"terminalResult\" });\n\n\t\t// Register subscriptions via `addDisposer` so they tear down on\n\t\t// subgraph unmount (not just explicit `destroy()`). A caller that\n\t\t// unmounts the AgentLoopGraph from its parent via `graph.remove(...)`\n\t\t// would otherwise keep `turnSub` / `abortedSub` live against dead state.\n\t\tthis.addDisposer(turnSub);\n\t\tthis.addDisposer(abortedSub);\n\t\tthis.addDisposer(statusSub);\n\t\tthis.addDisposer(kaResponse);\n\t\tthis.addDisposer(kaResults);\n\t\tthis.addDisposer(kaAbort);\n\t\tthis._disposeRunWiring = (): void => {\n\t\t\t// addDisposer takes care of teardown; this shim stays for the\n\t\t\t// `destroy()` override's idempotency contract (safe no-op if the\n\t\t\t// disposers already fired).\n\t\t};\n\t}\n\n\t/**\n\t * Bridge to `Promise<LLMResponse>` over the reactive pipeline.\n\t *\n\t * - If `userMessage` is provided, appends it as a user message and\n\t * transitions status to `\"thinking\"` to kick the loop.\n\t * - If `signal` is provided, binds it to the reactive `aborted` node\n\t * AND threads into `adapter.invoke({ signal })` so the wire call can\n\t * cancel mid-flight. The reactive `aborted` state + effect 3 guarantee\n\t * that even an adapter that ignores `signal` will stop emitting into\n\t * the agent graph.\n\t * - Resolves when `status === \"done\"` with the final LLM response.\n\t * Rejects with `AbortError` when the abort signal fires pre-response.\n\t * Rejects with the stage error when `status === \"error\"`.\n\t *\n\t * **Concurrency:** `run()` refuses to overlap with a pending call on the\n\t * same agent. Attempting to call `run()` while a previous `run()` is\n\t * still in-flight throws a `RangeError` immediately. Stale-resolution\n\t * safety is provided by `awaitSettled({skipCurrent: true})`, which\n\t * ignores the cached initial DATA from any previous run and resolves\n\t * only on a fresh post-subscribe emission of `_terminalResult`.\n\t */\n\tasync run(userMessage?: string, signal?: AbortSignal): Promise<LLMResponse | null> {\n\t\tif (this._running) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`agentLoop \"${this.name}\": run() called while a previous run() is still pending — await the previous run before starting another, or call abort() first`,\n\t\t\t);\n\t\t}\n\t\tthis._running = true;\n\n\t\tlet offAbort: (() => void) | undefined;\n\t\ttry {\n\t\t\t// Reset per-run state. `lastResponse` MUST be cleared here —\n\t\t\t// without it, `_terminalResult` would read the prior run's\n\t\t\t// cached response during a second `run()` with a pre-aborted\n\t\t\t// signal: `effAbort` drives `status → \"done\"`, `_terminalResult`\n\t\t\t// evaluates `stat=\"done\"` + `resp=<prior respA>` and emits DATA\n\t\t\t// as a fresh post-subscribe signal → `awaitSettled` resolves\n\t\t\t// with the stale response instead of rejecting with AbortError.\n\t\t\t// The C3 `stat=done && resp===undefined → ERROR` guard in\n\t\t\t// `_terminalResult` is only correct once the reset clears the\n\t\t\t// cache.\n\t\t\t//\n\t\t\t// **SENTINEL reset via plain `[[INVALIDATE]]`** (DS-13.5.A,\n\t\t\t// 2026-05-01). Pre-DS-13.5.A this required a paired\n\t\t\t// `[[INVALIDATE], [RESOLVED]]` because INVALIDATE alone left\n\t\t\t// dependents wedged in DIRTY. With INVALIDATE settling the wave\n\t\t\t// (decrementing `_dirtyDepCount` like RESOLVED) and clearing\n\t\t\t// `_cached` + each dependent's `prevData[lastResponse]` slot\n\t\t\t// back to `undefined`, a single emission restores SENTINEL state\n\t\t\t// AND lets dependents fire on the next status transition.\n\t\t\t// `lastResponse` is a `Node<LLMResponse>` with no `initial` —\n\t\t\t// it stays SENTINEL until the first real response; resetting\n\t\t\t// via `emit(null)` would push a `null` DATA placeholder (the\n\t\t\t// F9 trap), which is why INVALIDATE rather than emit is used.\n\t\t\tbatch(() => {\n\t\t\t\tthis.lastResponse.down([[INVALIDATE]]);\n\t\t\t\tthis.turn.emit(0);\n\t\t\t\tthis.aborted.emit(false);\n\t\t\t\tthis.status.emit(\"idle\");\n\t\t\t});\n\t\t\tif (userMessage != null) this.chat.append(\"user\", userMessage);\n\n\t\t\t// Subscribe to `_terminalResult` BEFORE transitioning to\n\t\t\t// \"thinking\" — otherwise a synchronous adapter (mock tests,\n\t\t\t// offline stubs) would drain status → done → DATA on\n\t\t\t// `_terminalResult` before `awaitSettled` had a chance to\n\t\t\t// subscribe, and `skipCurrent: true` would swallow the only\n\t\t\t// DATA this run will produce. `awaitSettled` / `firstWhere`\n\t\t\t// subscribes synchronously during the `async` function's\n\t\t\t// initial execution slice, so calling it before the kick\n\t\t\t// guarantees the subscription is in place when the pipeline\n\t\t\t// starts draining.\n\t\t\t//\n\t\t\t// `skipCurrent: true` still matters: on the second `run()`\n\t\t\t// call `_terminalResult` holds cached DATA from the prior run,\n\t\t\t// and push-on-subscribe would resolve immediately with that\n\t\t\t// stale value without the skip.\n\t\t\tconst resultPromise = awaitSettled(this._terminalResult, { skipCurrent: true });\n\n\t\t\tif (signal != null) {\n\t\t\t\tif (signal.aborted) {\n\t\t\t\t\tthis.aborted.emit(true);\n\t\t\t\t} else {\n\t\t\t\t\tconst listener = (): void => this.aborted.emit(true);\n\t\t\t\t\tsignal.addEventListener(\"abort\", listener, { once: true });\n\t\t\t\t\toffAbort = (): void => signal.removeEventListener(\"abort\", listener);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Kick — transition to \"thinking\" fires promptInput → llmResponse.\n\t\t\t// Skip the kick when the signal was already aborted: `effAbort`\n\t\t\t// has driven `status → \"done\"` above, and a trailing\n\t\t\t// `thinking` emit would produce a non-monotonic `idle → done →\n\t\t\t// thinking` sequence in the status-event log for no reactive\n\t\t\t// benefit (promptInput gates on `!latestAborted` anyway).\n\t\t\tif (signal?.aborted !== true) {\n\t\t\t\tthis.status.emit(\"thinking\");\n\t\t\t}\n\n\t\t\treturn await resultPromise;\n\t\t} finally {\n\t\t\toffAbort?.();\n\t\t\tthis._running = false;\n\t\t\tthis._currentAbortController = null;\n\t\t}\n\t}\n\n\t/**\n\t * Flip the reactive `aborted` state. Equivalent to setting an external\n\t * `AbortSignal` — the pipeline observes and transitions to `\"done\"`.\n\t */\n\tabort(): void {\n\t\tthis.aborted.emit(true);\n\t}\n\n\toverride destroy(): void {\n\t\ttry {\n\t\t\tthis._disposeRunWiring();\n\t\t} catch {\n\t\t\t/* best-effort: disposing keepalives shouldn't block destroy */\n\t\t}\n\t\tsuper.destroy();\n\t}\n}\n\n/**\n * Read the latest value for dep `i` inside a raw-`node()` fn body.\n *\n * Checks `batchData[i]` first (this-wave DATA from the dep), falls back to\n * `ctx.prevData[i]` (last DATA from prior waves), and finally to `fallback`\n * when the dep has never emitted (SENTINEL). Matches the unwrap semantics\n * `derived`'s sugar applies, so raw nodes can read deps uniformly.\n *\n * @internal\n */\nfunction readLatest<T>(\n\tbatchData: readonly (readonly unknown[] | undefined)[],\n\tprevData: readonly unknown[],\n\tindex: number,\n\tfallback: T,\n): T {\n\tconst batch = batchData[index];\n\tif (batch != null && batch.length > 0) return batch[batch.length - 1] as T;\n\tconst prev = prevData[index];\n\treturn (prev !== undefined ? prev : fallback) as T;\n}\n\n/** @internal Shape of the LLM invocation input — constructed inside `promptInput`. */\ninterface InvokeInput {\n\treadonly messages: readonly ChatMessage[];\n\treadonly tools: readonly ToolDefinition[];\n}\n\nexport function agentLoop(name: string, opts: AgentLoopOptions): AgentLoopGraph {\n\tconst g = new AgentLoopGraph(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. Opts include non-JSON\n\t// fields (`adapter`, `tools`, `stopWhen`, `onToolCall`,\n\t// `interceptToolCalls`, etc.) so route through `placeholderArgs`\n\t// (DG2=ii).\n\tg.tagFactory(\"agentLoop\", placeholderArgs(opts as unknown as Record<string, unknown>));\n\treturn g;\n}\n","/**\n * Phase 13.G — `AgentBundle<TIn, TOut>` interface + `class AgentGraph extends Graph`.\n *\n * Source: `archive/docs/SESSION-multi-agent-gap-analysis.md` G1 lock B.\n *\n * Composes the existing substrate (`agentLoop`, `toolRegistry`,\n * `agentMemory`) into a typed inbox/outbox subgraph that other parts of a\n * multi-agent system can wire to. Sibling preset `agent()` (in\n * `./agents.ts`) is the ergonomic factory; this file is the contract.\n *\n * **Cross-cut #1 lock (no `agent.run()`):** caller-side runtime entry is\n * `bundle.in.emit(input)` + `awaitSettled(bundle.out)`. The legacy\n * `agentLoop.run()` is still available on `bundle.graph.loop` for\n * single-shot Promise-bridge use cases, but `agent()` does NOT expose a\n * `run()` method on the bundle.\n *\n * **Memory partition default:** private memory per agent (each `agent(...)`\n * call creates its own `AgentMemoryGraph` if none passed). Pass an explicit\n * shared instance for §29 handoff context-transfer.\n */\n\nimport { batch, DATA, INVALIDATE, type Node, node, RESOLVED } from \"@graphrefly/pure-ts/core\";\nimport { keepalive } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { aiMeta } from \"../../utils/ai/_internal.js\";\nimport type {\n\tInputTokens,\n\tLLMAdapter,\n\tLLMResponse,\n\tOutputTokens,\n\tTokenUsage,\n\tToolDefinition,\n} from \"../../utils/ai/adapters/core/types.js\";\nimport {\n\ttype SubscriptionGraph,\n\tsubscription,\n\ttype TopicGraph,\n\ttopic,\n} from \"../../utils/messaging/index.js\";\nimport { type AgentLoopGraph, agentLoop } from \"./agent-loop.js\";\nimport type { AgentMemoryGraph } from \"./agent-memory.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Lifecycle status of an {@link AgentGraph}.\n *\n * - `idle` — no input has been received since construction or last reset.\n * - `running` — inputs are flowing through the underlying agentLoop\n * (collapses the loop's `thinking` + `acting` substates so consumers\n * don't have to model the tool-call inner loop).\n * - `verifying` — verifier subgraph is in flight (reserved; lights up when\n * the verifier slot is added in a future wave per G7 recipe).\n * - `done` — the most recent input has settled with a verified response.\n * - `error` — the loop or verifier produced a terminal error.\n *\n * **Note (Phase 13.G, 2026-05-01):** v1 of `agent()` has no built-in\n * verifier slot — `verifying` is reserved but never produced. When a\n * verifier consumer surfaces, this enum widens (non-breaking type\n * widening; existing consumers see the same `idle | running | done | error`\n * subset).\n */\nexport type AgentStatus = \"idle\" | \"running\" | \"verifying\" | \"done\" | \"error\";\n\n/**\n * Aggregated cost for an agent's run, surfaced as a `Node<CostState>` on\n * the bundle. **Wraps the canonical {@link TokenUsage}** so consumers get\n * the full provider-disaggregated token classes (cache-read /\n * cache-write-5m / cache-write-1h / audio / image / video / tool-use /\n * reasoning / prediction-accepted / prediction-rejected / extensions /\n * auxiliary non-token costs / raw escape-hatch) without losing fidelity\n * for downstream pricing. USD conversion is a downstream `derived` over\n * `usage`.\n *\n * - `usage` — accumulated {@link TokenUsage} across all turns of the\n * current input.\n * - `turns` — number of completed agentLoop iterations (LLM invocations).\n *\n * **Counter scope:** resets to {@link ZERO_COST} on each new `bundle.in`\n * emit (per-input cost rather than per-agent-lifetime). Sum across multiple\n * inputs by snapshotting `cost` at `done` and accumulating externally —\n * a per-lifetime cost is a downstream `scan` over this.\n *\n * **Helpers.** Use `sumInputTokens(usage)` / `sumOutputTokens(usage)` from\n * `@graphrefly/graphrefly-ts` to flatten to scalars when the caller wants\n * a single number.\n */\nexport interface CostState {\n\treadonly usage: TokenUsage;\n\treadonly turns: number;\n}\n\nconst EMPTY_INPUT: InputTokens = Object.freeze({ regular: 0 });\nconst EMPTY_OUTPUT: OutputTokens = Object.freeze({ regular: 0 });\nconst EMPTY_USAGE: TokenUsage = Object.freeze({ input: EMPTY_INPUT, output: EMPTY_OUTPUT });\n\n/** Empty cost. Used as the initial value and the per-input reset baseline. */\nexport const ZERO_COST: CostState = Object.freeze({ usage: EMPTY_USAGE, turns: 0 });\n\n// ---------------------------------------------------------------------------\n// TokenUsage accumulator\n// ---------------------------------------------------------------------------\n\nfunction addOptional(a: number | undefined, b: number | undefined): number | undefined {\n\tif (a == null && b == null) return undefined;\n\treturn (a ?? 0) + (b ?? 0);\n}\n\nfunction addExtensions(\n\ta: Record<string, number> | undefined,\n\tb: Record<string, number> | undefined,\n): Record<string, number> | undefined {\n\tif (a == null && b == null) return undefined;\n\tconst out: Record<string, number> = { ...(a ?? {}) };\n\tfor (const [k, v] of Object.entries(b ?? {})) {\n\t\tout[k] = (out[k] ?? 0) + v;\n\t}\n\treturn out;\n}\n\n/**\n * Accumulates two {@link TokenUsage} snapshots. All field classes are\n * summed; optional fields propagate as `undefined` when absent from both\n * sides, otherwise treated as 0 for the missing side. `auxiliary` and\n * `extensions` merge by key. `raw` is dropped — it's a per-call escape\n * hatch, not summable.\n *\n * @category extra\n */\nexport function addUsage(a: TokenUsage, b: TokenUsage): TokenUsage {\n\tconst out: TokenUsage = {\n\t\tinput: {\n\t\t\tregular: a.input.regular + b.input.regular,\n\t\t\t...(addOptional(a.input.cacheRead, b.input.cacheRead) !== undefined && {\n\t\t\t\tcacheRead: addOptional(a.input.cacheRead, b.input.cacheRead) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.cacheWrite5m, b.input.cacheWrite5m) !== undefined && {\n\t\t\t\tcacheWrite5m: addOptional(a.input.cacheWrite5m, b.input.cacheWrite5m) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.cacheWrite1h, b.input.cacheWrite1h) !== undefined && {\n\t\t\t\tcacheWrite1h: addOptional(a.input.cacheWrite1h, b.input.cacheWrite1h) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.cacheWriteOther, b.input.cacheWriteOther) !== undefined && {\n\t\t\t\tcacheWriteOther: addOptional(a.input.cacheWriteOther, b.input.cacheWriteOther) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.audio, b.input.audio) !== undefined && {\n\t\t\t\taudio: addOptional(a.input.audio, b.input.audio) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.image, b.input.image) !== undefined && {\n\t\t\t\timage: addOptional(a.input.image, b.input.image) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.video, b.input.video) !== undefined && {\n\t\t\t\tvideo: addOptional(a.input.video, b.input.video) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.toolUse, b.input.toolUse) !== undefined && {\n\t\t\t\ttoolUse: addOptional(a.input.toolUse, b.input.toolUse) as number,\n\t\t\t}),\n\t\t\t...(addExtensions(a.input.extensions, b.input.extensions) !== undefined && {\n\t\t\t\textensions: addExtensions(a.input.extensions, b.input.extensions) as Record<string, number>,\n\t\t\t}),\n\t\t},\n\t\toutput: {\n\t\t\tregular: a.output.regular + b.output.regular,\n\t\t\t...(addOptional(a.output.reasoning, b.output.reasoning) !== undefined && {\n\t\t\t\treasoning: addOptional(a.output.reasoning, b.output.reasoning) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.output.audio, b.output.audio) !== undefined && {\n\t\t\t\taudio: addOptional(a.output.audio, b.output.audio) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.output.predictionAccepted, b.output.predictionAccepted) !== undefined && {\n\t\t\t\tpredictionAccepted: addOptional(\n\t\t\t\t\ta.output.predictionAccepted,\n\t\t\t\t\tb.output.predictionAccepted,\n\t\t\t\t) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.output.predictionRejected, b.output.predictionRejected) !== undefined && {\n\t\t\t\tpredictionRejected: addOptional(\n\t\t\t\t\ta.output.predictionRejected,\n\t\t\t\t\tb.output.predictionRejected,\n\t\t\t\t) as number,\n\t\t\t}),\n\t\t\t...(addExtensions(a.output.extensions, b.output.extensions) !== undefined && {\n\t\t\t\textensions: addExtensions(a.output.extensions, b.output.extensions) as Record<\n\t\t\t\t\tstring,\n\t\t\t\t\tnumber\n\t\t\t\t>,\n\t\t\t}),\n\t\t},\n\t\t...(addExtensions(a.auxiliary, b.auxiliary) !== undefined && {\n\t\t\tauxiliary: addExtensions(a.auxiliary, b.auxiliary) as Record<string, number>,\n\t\t}),\n\t};\n\treturn out;\n}\n\n/**\n * Spec for {@link agent} (in `./agents.ts`). Required fields are minimal —\n * `name` and `adapter` cover the common case where the input is a string\n * and the output is the raw `LLMResponse`. Optional fields shape the\n * agent's behavior:\n *\n * - **Mappers** (`inMapper` / `outMapper`) translate between caller-typed\n * `TIn` / `TOut` and the loop's internal `string` / `LLMResponse`. Default\n * identity mappers are wired automatically when `TIn` extends `string`\n * and `TOut` extends `LLMResponse`.\n * - **`tools`** is a reactive `NodeInput<readonly ToolDefinition[]>` —\n * `agent()` subscribes and reconciles the underlying `toolRegistry`'s\n * registrations on each emit. Static-array form is also accepted.\n * - **`memory`** is an explicit `AgentMemoryGraph` instance for shared\n * memory across agents (§29 handoff context transfer). Default: private\n * memory per agent (each `agent()` call mints its own).\n * - **`maxIterations`** caps the underlying agentLoop's tool-call inner\n * loop. Default 10 (matches `agentLoop`).\n * - **Verifier slot** is intentionally not in v1 — G7 reframe locks it as\n * a caller-composed recipe. When a real consumer surfaces, a\n * `verifier?: (out: Node<TOut>) => NodeInput<VerifierResult>` field\n * lands here additively.\n */\nexport interface AgentSpec<TIn, TOut> {\n\t/** Local mount name when wired to a parent graph. Required. */\n\treadonly name: string;\n\t/** LLM adapter for the underlying agentLoop. Required. */\n\treadonly adapter: LLMAdapter;\n\t/** Optional system prompt. Static today; reactive widening pending. */\n\treadonly systemPrompt?: string;\n\t/**\n\t * Optional reactive tool list. When a Node, the agent subscribes and\n\t * reconciles the underlying `toolRegistry` registrations on each emit\n\t * (additions registered, removals unregistered). When a static array,\n\t * tools are registered once at construction.\n\t */\n\treadonly tools?: Node<readonly ToolDefinition[]> | readonly ToolDefinition[];\n\t/**\n\t * Optional shared memory. Default: private (agent mints its own\n\t * `AgentMemoryGraph` if needed; not yet wired into the loop's chat —\n\t * that wiring is a separate follow-up). Pass an explicit instance to\n\t * share memory across agents for §29 handoff context transfer.\n\t */\n\treadonly memory?: AgentMemoryGraph<unknown>;\n\t/**\n\t * Maps caller-typed input → string for the underlying chat. Defaults to\n\t * identity when `TIn extends string`; required otherwise.\n\t */\n\treadonly inMapper?: (input: TIn) => string;\n\t/**\n\t * Maps the agentLoop's `LLMResponse` → caller-typed output. Defaults to\n\t * identity when `TOut extends LLMResponse`; required otherwise.\n\t */\n\treadonly outMapper?: (response: LLMResponse) => TOut;\n\t/** Caps tool-call inner-loop iterations. Default 10. */\n\treadonly maxIterations?: number;\n\t/** Escape hatch for non-core fields. Surfaced in `describe()` via meta. */\n\treadonly meta?: Record<string, unknown>;\n}\n\n/**\n * Public contract for an agent — typed inbox/outbox + lifecycle / cost\n * observables + the underlying graph for inspection / mounting.\n *\n * **Reactive entry:** caller writes to `in` (e.g. `bundle.in.emit(input)`).\n * The agent reactively kicks the underlying loop and produces `out`.\n *\n * **Reactive exit:** caller reads `out` via `subscribe` (continuous) or\n * `awaitSettled(out)` (single-shot). Both `in` and `out` stay SENTINEL\n * (`cache === undefined`) until the first real emission — no `null`\n * push-on-subscribe trap (per `feedback_use_prevdata_for_sentinel`).\n *\n * **Cross-graph wiring:** the bundle's `graph` is mountable under any\n * parent via `parent.mount(name, bundle.graph)`. After mount, the bundle's\n * Nodes are reachable through both the bundle reference (direct) and via\n * `parent.node(\"<name>::out\")` etc. (qualified path).\n */\nexport interface AgentBundle<TIn, TOut> {\n\treadonly in: Node<TIn>;\n\treadonly out: Node<TOut>;\n\treadonly status: Node<AgentStatus>;\n\treadonly cost: Node<CostState>;\n\treadonly graph: AgentGraph<TIn, TOut>;\n}\n\n// ---------------------------------------------------------------------------\n// AgentGraph\n// ---------------------------------------------------------------------------\n\nconst TERMINAL_STATUSES = new Set<AgentStatus>([\"done\", \"error\"]);\n\n/**\n * Graph subclass implementing {@link AgentBundle}. Mounts an inner\n * {@link AgentLoopGraph} at `loop/`; `in` / `out` / `status` / `cost`\n * surface the bundle contract as top-level nodes.\n *\n * Construction is internal — use the {@link agent} factory in\n * `./agents.ts` for normal use. Direct `new AgentGraph(name, spec)` is\n * supported for callers that want full control over mount order.\n *\n * **Topology:**\n * ```\n * <name>\n * ├── loop (AgentLoopGraph subgraph)\n * │ ├── chat\n * │ ├── tools\n * │ ├── status / turn / aborted / lastResponse / ...\n * ├── in (Node<TIn>, SENTINEL until first emit)\n * ├── out (Node<TOut>, SENTINEL until first response)\n * ├── status (Node<AgentStatus>, mirror of loop.status)\n * └── cost (Node<CostState>)\n * ```\n *\n * **Lifecycle:**\n * - On `in` emit: `inMapper` projects to `string`; appended to\n * `loop.chat`; loop status reset (`turn=0`, `aborted=false`,\n * `status=\"thinking\"`); per-input cost counters reset to zero.\n * - On `loop.lastResponse` emit: cost rolls forward; `out` emits\n * `outMapper(response)`.\n * - On `loop.status=\"done\"`: agent's status emits `\"done\"`.\n * - On `loop.status=\"error\"` (or any ERROR propagation): agent's status\n * emits `\"error\"`.\n */\nexport class AgentGraph<TIn, TOut> extends Graph {\n\t/** The agent's typed inbox. Writable; `in.emit(value)` kicks the loop. */\n\treadonly in: Node<TIn>;\n\t/** The agent's typed outbox. SENTINEL until first response. */\n\treadonly out: Node<TOut>;\n\t/** Lifecycle status (translated from the underlying loop's substates). */\n\treadonly status: Node<AgentStatus>;\n\t/** Cumulative cost for the current / most-recent input. */\n\treadonly cost: Node<CostState>;\n\t/** The underlying agentLoop — exposed for inspection / advanced wiring. */\n\treadonly loop: AgentLoopGraph;\n\t/** Optional shared memory subgraph (mounted at `memory/` if provided). */\n\treadonly memory: AgentMemoryGraph<unknown> | null;\n\n\tconstructor(spec: AgentSpec<TIn, TOut>, opts?: GraphOptions) {\n\t\tsuper(spec.name, opts);\n\n\t\t// --- 1. Mount the agentLoop subgraph. ------------------------------\n\t\tconst initialTools = Array.isArray(spec.tools)\n\t\t\t? (spec.tools as readonly ToolDefinition[])\n\t\t\t: undefined;\n\t\tthis.loop = agentLoop(`${spec.name}-loop`, {\n\t\t\tadapter: spec.adapter,\n\t\t\t...(spec.systemPrompt != null ? { systemPrompt: spec.systemPrompt } : {}),\n\t\t\t...(initialTools != null ? { tools: initialTools } : {}),\n\t\t\t...(spec.maxIterations != null ? { maxTurns: spec.maxIterations } : {}),\n\t\t});\n\t\tthis.mount(\"loop\", this.loop);\n\n\t\t// --- 2. Reactive tools subscription (if Node-form). ----------------\n\t\t// agentLoop's tools are static-array at construction; we reconcile\n\t\t// dynamically by subscribing to the user's reactive Node and\n\t\t// register/unregister against the inner toolRegistry.\n\t\tif (spec.tools != null && !Array.isArray(spec.tools)) {\n\t\t\tconst toolsNode = spec.tools as Node<readonly ToolDefinition[]>;\n\t\t\tconst registered = new Set<string>();\n\t\t\tconst unsubTools = toolsNode.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 next = m[1] as readonly ToolDefinition[];\n\t\t\t\t\tconst nextNames = new Set(next.map((t) => t.name));\n\t\t\t\t\t// Unregister missing.\n\t\t\t\t\tfor (const name of registered) {\n\t\t\t\t\t\tif (!nextNames.has(name)) {\n\t\t\t\t\t\t\tthis.loop.tools.unregister(name);\n\t\t\t\t\t\t\tregistered.delete(name);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Register new (idempotent guard via local tracking).\n\t\t\t\t\tfor (const tool of next) {\n\t\t\t\t\t\tif (!registered.has(tool.name)) {\n\t\t\t\t\t\t\tthis.loop.tools.register(tool);\n\t\t\t\t\t\t\tregistered.add(tool.name);\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(unsubTools);\n\t\t}\n\n\t\t// --- 3. Optional shared memory subgraph (passed through). ----------\n\t\t// v1: memory is mounted but NOT yet wired into the loop's chat — the\n\t\t// chat-context-from-memory glue is a separate follow-up. Mounting it\n\t\t// here gives the bundle a stable surface for §29 handoff (callers\n\t\t// can pass the SAME instance to multiple agents for shared memory).\n\t\tthis.memory = spec.memory ?? null;\n\t\tif (this.memory != null) {\n\t\t\tthis.mount(\"memory\", this.memory);\n\t\t}\n\n\t\t// --- 4. `in` — the typed inbox. ------------------------------------\n\t\t// SENTINEL until first emit; `equals: () => false` so re-emitting the\n\t\t// same value still kicks (no spurious dedup of repeat inputs).\n\t\tthis.in = node<TIn>([], {\n\t\t\tname: \"in\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"agent_in\"),\n\t\t\tequals: () => false,\n\t\t});\n\t\tthis.add(this.in, { name: \"in\" });\n\n\t\t// --- 5. `cost` — per-input token counters. -------------------------\n\t\tconst costNode = node<CostState>([], {\n\t\t\tname: \"cost\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"agent_cost\"),\n\t\t\tinitial: ZERO_COST,\n\t\t});\n\t\tthis.add(costNode, { name: \"cost\" });\n\t\tthis.cost = costNode;\n\n\t\t// --- 6. `out` — the typed outbox. ----------------------------------\n\t\t// Derived from `loop.lastResponse`. SENTINEL while `loop.lastResponse`\n\t\t// has never emitted a real response (F9 fix: the loop now stays\n\t\t// SENTINEL too — no more eager `null` placeholder), so the SENTINEL\n\t\t// detector inside the fn is `prevData[0] === undefined`. Between\n\t\t// runs, `loop.lastResponse.down([[INVALIDATE]])` clears that\n\t\t// `prevData` slot back to undefined, so this derived correctly gates\n\t\t// to RESOLVED on the next status=\"idle\" wave.\n\t\tconst outMapper = spec.outMapper ?? defaultOutMapper<TOut>();\n\t\tconst outNode = node<TOut>(\n\t\t\t[this.loop.lastResponse],\n\t\t\t(data, a, ctx) => {\n\t\t\t\tconst batch0 = data[0];\n\t\t\t\tconst resp =\n\t\t\t\t\tbatch0 != null && batch0.length > 0\n\t\t\t\t\t\t? (batch0.at(-1) as LLMResponse | undefined)\n\t\t\t\t\t\t: (ctx.prevData[0] as LLMResponse | undefined);\n\t\t\t\tif (resp === undefined) {\n\t\t\t\t\ta.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ta.emit(outMapper(resp));\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"out\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"agent_out\"),\n\t\t\t\t// Each in.emit may produce a structurally-equal response (e.g.\n\t\t\t\t// from a deterministic adapter) — disable framework dedup so\n\t\t\t\t// repeat emits propagate and `awaitSettled({skipCurrent:true})`\n\t\t\t\t// sees them. Callers can wrap with `distinctUntilChanged` if\n\t\t\t\t// they want change-only semantics.\n\t\t\t\tequals: () => false,\n\t\t\t},\n\t\t);\n\t\tthis.add(outNode, { name: \"out\" });\n\t\tthis.out = outNode;\n\n\t\t// --- 7. `status` — translated from loop.status. --------------------\n\t\t// Mirror via §32 pattern: a state node downstream consumers depend on,\n\t\t// reset and updated by an effect listening to loop.status.\n\t\tconst statusNode = node<AgentStatus>([], {\n\t\t\tname: \"status\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"agent_status\"),\n\t\t\tinitial: \"idle\",\n\t\t});\n\t\tthis.add(statusNode, { name: \"status\" });\n\t\tthis.status = statusNode;\n\n\t\tconst statusMirrorEff = node(\n\t\t\t[this.loop.status],\n\t\t\t(data, _a, ctx) => {\n\t\t\t\tconst batch0 = data[0];\n\t\t\t\tconst loopStatus =\n\t\t\t\t\tbatch0 != null && batch0.length > 0\n\t\t\t\t\t\t? (batch0.at(-1) as string)\n\t\t\t\t\t\t: ((ctx.prevData[0] as string | undefined) ?? \"idle\");\n\t\t\t\tconst next: AgentStatus =\n\t\t\t\t\tloopStatus === \"idle\"\n\t\t\t\t\t\t? \"idle\"\n\t\t\t\t\t\t: loopStatus === \"thinking\" || loopStatus === \"acting\"\n\t\t\t\t\t\t\t? \"running\"\n\t\t\t\t\t\t\t: loopStatus === \"done\"\n\t\t\t\t\t\t\t\t? \"done\"\n\t\t\t\t\t\t\t\t: loopStatus === \"error\"\n\t\t\t\t\t\t\t\t\t? \"error\"\n\t\t\t\t\t\t\t\t\t: \"idle\";\n\t\t\t\tif (statusNode.cache !== next) statusNode.emit(next);\n\t\t\t},\n\t\t\t{ describeKind: \"effect\", meta: aiMeta(\"agent_status_mirror\") },\n\t\t);\n\t\tthis.addDisposer(keepalive(statusMirrorEff));\n\n\t\t// --- 8. Cost-rollup effect. ---------------------------------------\n\t\t// Rolls forward on each loop.lastResponse emission. Reads\n\t\t// loop.turn.cache for the iteration count (sole-owner-reactive-reader\n\t\t// per Phase 12 D1 lock — loop is mounted as a subgraph of this Graph).\n\t\t// SENTINEL gate: `prevData[0] === undefined` means no response has\n\t\t// ever been delivered for this run (post-INVALIDATE reset between\n\t\t// runs), so the rollup short-circuits.\n\t\tconst costEff = node(\n\t\t\t[this.loop.lastResponse],\n\t\t\t(data, _a, ctx) => {\n\t\t\t\tconst batch0 = data[0];\n\t\t\t\tconst resp =\n\t\t\t\t\tbatch0 != null && batch0.length > 0\n\t\t\t\t\t\t? (batch0.at(-1) as LLMResponse | undefined)\n\t\t\t\t\t\t: (ctx.prevData[0] as LLMResponse | undefined);\n\t\t\t\tif (resp === undefined) return;\n\t\t\t\tconst prev = (costNode.cache as CostState | undefined) ?? ZERO_COST;\n\t\t\t\tconst turns = (this.loop.turn.cache as number | undefined) ?? prev.turns;\n\t\t\t\tconst next: CostState = {\n\t\t\t\t\tusage: resp.usage != null ? addUsage(prev.usage, resp.usage) : prev.usage,\n\t\t\t\t\tturns,\n\t\t\t\t};\n\t\t\t\tcostNode.emit(next);\n\t\t\t},\n\t\t\t{ describeKind: \"effect\", meta: aiMeta(\"agent_cost_rollup\") },\n\t\t);\n\t\tthis.addDisposer(keepalive(costEff));\n\n\t\t// --- 9. `in` → input queue → drain → kick the loop. ----------------\n\t\t// Phase 13.G/H + /qa N1(b) lock (2026-05-01): bundle.in is a\n\t\t// writable surface, but kicks are queued through an internal\n\t\t// hub-style topic + cursor subscription. Out-of-the-box queueing —\n\t\t// caller fires `in.emit(x)` while the agent is mid-run; the input\n\t\t// is parked on the queue and picked up when the loop returns to\n\t\t// `idle` / `done` / `error`. No mid-run reset / cost-leak hazard\n\t\t// (which the prior raw `in.subscribe → kick` path had).\n\t\t//\n\t\t// Topology:\n\t\t// `in` (state Node, writable) → `inputBridge` (subscribe →\n\t\t// publish) → `inputTopic` (TopicGraph<TIn>) → `inputSub`\n\t\t// (SubscriptionGraph<TIn>) → `drainEffect` (effect on\n\t\t// [inputSub.available, loop.status]) → loop kick.\n\t\tconst inMapper = spec.inMapper ?? defaultInMapper<TIn>();\n\t\tconst inputTopic: TopicGraph<TIn> = topic<TIn>(\"input-topic\");\n\t\tthis.mount(\"input-topic\", inputTopic);\n\t\tconst inputSub: SubscriptionGraph<TIn> = subscription<TIn>(\"input-sub\", inputTopic, {\n\t\t\tfrom: \"now\",\n\t\t});\n\t\tthis.mount(\"input-sub\", inputSub);\n\n\t\t// Bridge: `in.emit(x)` publishes to the topic. Validates the\n\t\t// caller-supplied input via `inMapper` at the boundary so the\n\t\t// type error surfaces in the caller's stack frame (not later\n\t\t// during drain). Per the F9 SENTINEL trap, `in` cache is\n\t\t// `undefined` until the first emit; push-on-subscribe delivers\n\t\t// nothing.\n\t\tconst inputBridge = this.in.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] !== DATA) continue;\n\t\t\t\tconst input = m[1] as TIn;\n\t\t\t\t// Boundary type-check: throws if TIn is not string and no\n\t\t\t\t// inMapper supplied. Better here than at drain time so the\n\t\t\t\t// caller's `in.emit(...)` raises synchronously.\n\t\t\t\tinMapper(input);\n\t\t\t\tinputTopic.publish(input);\n\t\t\t}\n\t\t});\n\t\tthis.addDisposer(inputBridge);\n\n\t\t// Drain effect: when an input is pending AND the loop is ready\n\t\t// (`idle` / `done` / `error`), pull one and kick. Re-entrancy\n\t\t// guard via `loop.status` — `thinking` / `acting` skip.\n\t\tconst drainEffect = node(\n\t\t\t[inputSub.available, this.loop.status],\n\t\t\t(data, _a, ctx) => {\n\t\t\t\tconst availBatch = data[0];\n\t\t\t\tconst statusBatch = data[1];\n\t\t\t\tconst avail =\n\t\t\t\t\t(availBatch != null && availBatch.length > 0\n\t\t\t\t\t\t? (availBatch.at(-1) as readonly TIn[])\n\t\t\t\t\t\t: ((ctx.prevData[0] as readonly TIn[] | undefined) ?? [])) ?? [];\n\t\t\t\tconst stat =\n\t\t\t\t\t(statusBatch != null && statusBatch.length > 0\n\t\t\t\t\t\t? (statusBatch.at(-1) as string)\n\t\t\t\t\t\t: ((ctx.prevData[1] as string | undefined) ?? \"idle\")) ?? \"idle\";\n\t\t\t\tif (avail.length === 0) return;\n\t\t\t\tif (stat === \"thinking\" || stat === \"acting\") return;\n\t\t\t\tconst result = inputSub.pullAndAck(1);\n\t\t\t\tif (result.items.length === 0) return;\n\t\t\t\tconst input = result.items[0] as TIn;\n\t\t\t\tconst userMsg = inMapper(input);\n\t\t\t\tbatch(() => {\n\t\t\t\t\t// Reset per-input accumulators so cost/turns don't include\n\t\t\t\t\t// the previous input. `lastResponse` is reset via plain\n\t\t\t\t\t// `[[INVALIDATE]]` — under DS-13.5.A INVALIDATE both clears\n\t\t\t\t\t// `_cached` AND settles the consuming wave (decrements\n\t\t\t\t\t// `_dirtyDepCount` like RESOLVED), so dependents like\n\t\t\t\t\t// `out` / `costEff` fire on the next status transition\n\t\t\t\t\t// without staying wedged in DIRTY. Pre-DS-13.5.A this used\n\t\t\t\t\t// the `[[INVALIDATE], [RESOLVED]]` paired-reset workaround.\n\t\t\t\t\tthis.loop.lastResponse.down([[INVALIDATE]]);\n\t\t\t\t\tthis.loop.turn.emit(0);\n\t\t\t\t\tthis.loop.aborted.emit(false);\n\t\t\t\t\tcostNode.emit(ZERO_COST);\n\t\t\t\t\tthis.loop.chat.append(\"user\", userMsg);\n\t\t\t\t\tthis.loop.status.emit(\"thinking\");\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ describeKind: \"effect\", meta: aiMeta(\"agent_input_drain\") },\n\t\t);\n\t\tthis.addDisposer(keepalive(drainEffect));\n\n\t\t// `out` and `status` keepalives are unnecessary because the cost /\n\t\t// status effects above already activate `loop.lastResponse` and\n\t\t// `loop.status` — the derived `out` reads from a kept-alive source.\n\t\t// We do keep `out` alive explicitly so `awaitSettled(bundle.out,\n\t\t// { skipCurrent: true })` works even when no other consumer\n\t\t// subscribes between input and response.\n\t\tthis.addDisposer(keepalive(this.out));\n\n\t\t// Surface in describe.\n\t\tvoid TERMINAL_STATUSES;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Default mappers\n// ---------------------------------------------------------------------------\n\n/**\n * Default `inMapper` for `TIn extends string`. Asserts the runtime type at\n * the boundary so callers who omit `inMapper` for a non-string `TIn` get a\n * clear error rather than a silent passthrough.\n */\nfunction defaultInMapper<TIn>(): (input: TIn) => string {\n\treturn (input) => {\n\t\tif (typeof input !== \"string\") {\n\t\t\tthrow new TypeError(\n\t\t\t\t`agent: inMapper is required when TIn is not a string (got ${typeof input}). Pass spec.inMapper.`,\n\t\t\t);\n\t\t}\n\t\treturn input;\n\t};\n}\n\n/**\n * Default `outMapper` for `TOut extends LLMResponse`. Asserts the response\n * shape at the boundary; callers with a non-LLMResponse `TOut` must\n * provide `outMapper`.\n */\nfunction defaultOutMapper<TOut>(): (response: LLMResponse) => TOut {\n\treturn (response) => response as unknown as TOut;\n}\n","/**\n * Phase 13.H — `agent(spec)` preset + `presetRegistry` sugar.\n *\n * Source: `archive/docs/SESSION-multi-agent-gap-analysis.md` G1 + G2.\n *\n * `agent()` is the ergonomic factory — given a parent Graph and an\n * `AgentSpec`, mints an `AgentGraph`, mounts it under the parent at\n * `spec.name`, and returns the `AgentBundle` contract.\n *\n * `presetRegistry()` is thin sugar over `reactiveMap` — a typed reactive\n * map of `<id, preset>`. Pairs with `materialize` (Phase 13.C) for\n * dynamic preset selection: callers store specs / factories / configs in\n * the registry and `materialize` mounts the matching one based on a\n * routing key.\n *\n * **Cross-cut #1 lock:** no `agent.run()` imperative sugar — caller-side\n * runtime is `bundle.in.emit(input)` + `awaitSettled(bundle.out)`.\n */\n\nimport { type ReactiveMapBundle, reactiveMap } from \"@graphrefly/pure-ts/extra\";\nimport type { Graph } from \"@graphrefly/pure-ts/graph\";\nimport type { LLMResponse } from \"../../utils/ai/adapters/core/types.js\";\nimport { type AgentBundle, AgentGraph, type AgentSpec } from \"./agent.js\";\n\n// ---------------------------------------------------------------------------\n// agent() factory\n// ---------------------------------------------------------------------------\n\n/**\n * Mints an {@link AgentGraph} from `spec`, mounts it under `parent` at\n * `spec.name`, and returns the {@link AgentBundle} contract.\n *\n * **Default type parameters.** When called without explicit type params,\n * `TIn` defaults to `string` and `TOut` to `LLMResponse` — the common\n * case where the caller writes a user message and reads the raw response.\n * Custom types require both `inMapper` and `outMapper` in the spec; the\n * default mappers throw at runtime if `TIn` / `TOut` aren't string /\n * LLMResponse.\n *\n * **Memory partition default.** Each `agent()` call mints its own\n * `AgentMemoryGraph` if `spec.memory` is omitted (private memory; the\n * common case). Pass an explicit shared instance — e.g.\n * `agent(parent, { ..., memory: sharedMemory })` for two agents — to\n * implement §29 handoff context transfer.\n *\n * **Reactive entry / exit:**\n * - `bundle.in.emit(input)` kicks the loop reactively (no imperative\n * `.run()` per cross-cut #1 lock).\n * - `awaitSettled(bundle.out, { skipCurrent: true })` resolves on the\n * first response after the kick. `skipCurrent` matters for the second\n * call onward — `out` caches the prior response.\n *\n * **Mounting.** The factory mounts under `parent.mount(spec.name, ...)`.\n * The slot name must be free on `parent` at construction time. To keep\n * the agent unmounted, construct `new AgentGraph(spec)` directly.\n *\n * @example\n * ```ts\n * import { agent, awaitSettled, Graph } from \"@graphrefly/graphrefly-ts\";\n *\n * const parent = new Graph(\"parent\");\n * const a = agent(parent, {\n * name: \"researcher\",\n * adapter: openaiAdapter,\n * systemPrompt: \"Research the user's question carefully.\",\n * });\n * a.in.emit(\"What's the capital of France?\");\n * const resp = await awaitSettled(a.out, { skipCurrent: true });\n * ```\n *\n * @category patterns\n */\nexport function agent<TIn = string, TOut = LLMResponse>(\n\tparent: Graph,\n\tspec: AgentSpec<TIn, TOut>,\n): AgentBundle<TIn, TOut> {\n\tconst graph = new AgentGraph<TIn, TOut>(spec);\n\tparent.mount(spec.name, graph);\n\treturn {\n\t\tin: graph.in,\n\t\tout: graph.out,\n\t\tstatus: graph.status,\n\t\tcost: graph.cost,\n\t\tgraph,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// presetRegistry()\n// ---------------------------------------------------------------------------\n\n/**\n * The bundle returned by {@link presetRegistry}. Wraps a `reactiveMap`\n * with imperative `put` / `remove` shortcuts and exposes the underlying\n * `registry` for direct reactive consumption (`.entries` is a\n * `Node<ReadonlyMap<string, TPreset>>`).\n *\n * Use the `registry.entries` Node directly with {@link materialize} (Phase\n * 13.C) — pass it as the `factories` argument when `TPreset` is itself\n * a `() => Graph` factory thunk, or transform via `derived` when\n * `TPreset` is a richer spec type that needs a `spec → factory` adapter.\n */\nexport interface PresetRegistryBundle<TPreset> {\n\t/**\n\t * The underlying reactive map. `registry.entries` is the\n\t * `Node<ReadonlyMap<string, TPreset>>` — pass directly to\n\t * {@link materialize} when preset shape matches the factories arg.\n\t */\n\treadonly registry: ReactiveMapBundle<string, TPreset>;\n\t/** Imperative add / replace. Always emits a fresh snapshot. */\n\tput(id: string, preset: TPreset): void;\n\t/** Imperative remove. Returns `true` if the id was present. */\n\tremove(id: string): boolean;\n}\n\n/**\n * Thin sugar over `reactiveMap` — a typed registry of `<id, preset>` for\n * agent / strategy / persona / skill catalogs.\n *\n * **Generic over preset shape.** `TPreset` is open — could be an\n * {@link AgentSpec}, a `() => Graph` factory thunk, a static config\n * object, or anything else. Decoupled from `agent()` so the same primitive\n * powers harnessLoop strategy registries, pipelineGraph stage catalogs,\n * etc.\n *\n * **Composes with `materialize`.** When `TPreset` is a `() => Graph`\n * factory, pass `registry.entries` directly to\n * {@link materialize} as the `factories` argument. When `TPreset` is a\n * spec, transform via `derived` to build a `Map<id, () => Graph>` adapter:\n *\n * ```ts\n * const presets = presetRegistry<AgentSpec<string, LLMResponse>>();\n * presets.put(\"researcher\", { name: \"researcher\", adapter, systemPrompt: \"...\" });\n *\n * // Adapter: spec → factory.\n * const factories = derived(\n * [presets.registry.entries],\n * ([m]) => new Map(\n * [...m].map(([id, spec]) => [id, () => new AgentGraph(spec)]),\n * ),\n * );\n * const slot = materialize(activeKey, factories, parent);\n * ```\n *\n * @param initial - Optional initial entries.\n * @returns {@link PresetRegistryBundle}.\n *\n * @category patterns\n */\nexport function presetRegistry<TPreset>(\n\tinitial?: ReadonlyMap<string, TPreset>,\n): PresetRegistryBundle<TPreset> {\n\tconst registry = reactiveMap<string, TPreset>({ name: \"presetRegistry\" });\n\tif (initial != null) {\n\t\tfor (const [id, preset] of initial) {\n\t\t\tregistry.set(id, preset);\n\t\t}\n\t}\n\treturn {\n\t\tregistry,\n\t\tput(id, preset) {\n\t\t\tregistry.set(id, preset);\n\t\t},\n\t\tremove(id) {\n\t\t\tif (!registry.has(id)) return false;\n\t\t\tregistry.delete(id);\n\t\t\treturn true;\n\t\t},\n\t};\n}\n"],"mappings":"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","names":["batch","batch","DATA","INVALIDATE","node","RESOLVED","keepalive","Graph","Graph","DATA","node","RESOLVED","keepalive","batch","INVALIDATE"]}
@@ -0,0 +1,256 @@
1
+ import {
2
+ budgetGate,
3
+ circuitBreaker,
4
+ fallback,
5
+ rateLimiter,
6
+ withBreaker
7
+ } from "./chunk-RJOG4IJU.js";
8
+ import {
9
+ withTimeout
10
+ } from "./chunk-RAGGHLCV.js";
11
+ import {
12
+ domainMeta
13
+ } from "./chunk-FMPF42Q4.js";
14
+ import {
15
+ withStatus
16
+ } from "./chunk-Y52CS6YA.js";
17
+ import {
18
+ retry
19
+ } from "./chunk-Z4YXAUDN.js";
20
+ import {
21
+ NS_PER_MS
22
+ } from "./chunk-P5LBT622.js";
23
+
24
+ // src/presets/resilience/resilient-pipeline.ts
25
+ import { ERROR, node, placeholderArgs } from "@graphrefly/pure-ts/core";
26
+ import { switchMap } from "@graphrefly/pure-ts/extra";
27
+ import { Graph } from "@graphrefly/pure-ts/graph";
28
+ function isNode(x) {
29
+ return typeof x === "object" && x !== null && "subscribe" in x && "down" in x;
30
+ }
31
+ function assertTimeoutMsValid(ms) {
32
+ if (ms <= 0) throw new RangeError("timeoutMs must be > 0");
33
+ if (ms > 9e6) {
34
+ throw new RangeError(
35
+ "timeoutMs must be <= 9_000_000 (\u22482.5h) to stay within safe ns arithmetic"
36
+ );
37
+ }
38
+ }
39
+ var ResilientPipelineGraph = class extends Graph {
40
+ /**
41
+ * Final resilient node — subscribe to this for `DATA` emissions.
42
+ *
43
+ * Named `output` (not `node`) because `Graph.node(name)` already names the
44
+ * path-resolution method on the base class; a `readonly node` field would
45
+ * shadow it.
46
+ */
47
+ output;
48
+ /** Live status: `"pending" | "running" | "completed" | "errored"`. */
49
+ status;
50
+ /**
51
+ * Last error payload, or `null` when not errored.
52
+ *
53
+ * Named `lastError` (not `error`) because `Graph.error(name, err)` already
54
+ * names a method on the base class.
55
+ */
56
+ lastError;
57
+ /** Breaker state when `opts.breaker` is provided; `undefined` otherwise. */
58
+ breakerState;
59
+ /**
60
+ * Timeout state companion when `opts.timeoutMs` is supplied as a
61
+ * `Node<Partial<TimeoutOptions>>`-like form; `undefined` otherwise
62
+ * (DS-13.5.B forwarding contract — Node-form opts skip the switchMap
63
+ * rebuild and lift the primitive's lifecycle companion onto the
64
+ * pipeline bundle).
65
+ */
66
+ timeoutState;
67
+ /**
68
+ * Retry state companion when `opts.retry` is supplied as a
69
+ * `Node<RetryOptions>`-like form; `undefined` otherwise
70
+ * (DS-13.5.B forwarding contract).
71
+ */
72
+ retryState;
73
+ /**
74
+ * Drop-counter when `opts.rateLimit` is provided; `undefined` otherwise.
75
+ *
76
+ * **Lifetime note:** `droppedCount` retains its final value through
77
+ * terminal (`COMPLETE` / `ERROR` / `TEARDOWN`); the underlying counter
78
+ * resets to `0` only at the next subscription cycle.
79
+ */
80
+ droppedCount;
81
+ /**
82
+ * Combined rate-limit state when `opts.rateLimit` is provided; `undefined`
83
+ * otherwise. Same lifecycle as {@link droppedCount} but exposes
84
+ * `pendingCount` and `paused` alongside the drop counter for richer
85
+ * backpressure observability (Tier 5.2 D7).
86
+ */
87
+ rateLimitState;
88
+ constructor(source, opts = {}) {
89
+ super(opts.name ?? "resilient_pipeline", opts.graph);
90
+ let current = source;
91
+ let droppedCount;
92
+ let rateLimitState;
93
+ let breakerState;
94
+ let timeoutState;
95
+ let retryState;
96
+ if (opts.rateLimit != null) {
97
+ if (isNode(opts.rateLimit)) {
98
+ const bundle = rateLimiter(current, opts.rateLimit);
99
+ current = bundle.node;
100
+ droppedCount = bundle.droppedCount;
101
+ rateLimitState = bundle.rateLimitState;
102
+ this.add(current, { name: "rateLimited" });
103
+ this.add(droppedCount, { name: "droppedCount" });
104
+ this.add(rateLimitState, { name: "rateLimitState" });
105
+ } else {
106
+ const rateOpts = {
107
+ ...opts.rateLimit,
108
+ maxBuffer: opts.rateLimit.maxBuffer ?? Infinity,
109
+ meta: domainMeta("resilient", "rate-limit")
110
+ };
111
+ const bundle = rateLimiter(current, rateOpts);
112
+ current = bundle.node;
113
+ droppedCount = bundle.droppedCount;
114
+ rateLimitState = bundle.rateLimitState;
115
+ this.add(current, { name: "rateLimited" });
116
+ this.add(droppedCount, { name: "droppedCount" });
117
+ this.add(rateLimitState, { name: "rateLimitState" });
118
+ }
119
+ }
120
+ if (opts.budget != null) {
121
+ if (isNode(opts.budget)) {
122
+ const inputForLayer = current;
123
+ const reactiveBudget = opts.budget;
124
+ current = switchMap(
125
+ reactiveBudget,
126
+ (constraints) => constraints.length > 0 ? budgetGate(inputForLayer, constraints, {
127
+ meta: domainMeta("resilient", "budget")
128
+ }).node : inputForLayer
129
+ );
130
+ this.add(current, { name: "budgetGated" });
131
+ } else if (opts.budget.length > 0) {
132
+ current = budgetGate(current, opts.budget, {
133
+ meta: domainMeta("resilient", "budget")
134
+ }).node;
135
+ this.add(current, { name: "budgetGated" });
136
+ }
137
+ }
138
+ if (opts.breaker != null) {
139
+ const breaker = circuitBreaker(opts.breaker);
140
+ const onOpen = opts.breakerOnOpen ?? "skip";
141
+ const wrapped = withBreaker(breaker, {
142
+ onOpen,
143
+ meta: domainMeta("resilient", "breaker")
144
+ })(current);
145
+ current = wrapped.node;
146
+ breakerState = wrapped.breakerState;
147
+ this.add(current, { name: "breakerWrapped" });
148
+ this.add(breakerState, { name: "breakerState" });
149
+ }
150
+ if (opts.timeoutMs != null) {
151
+ if (isNode(opts.timeoutMs)) {
152
+ const reactiveTimeoutMs = opts.timeoutMs;
153
+ const initialMs = reactiveTimeoutMs.cache;
154
+ if (initialMs !== void 0) assertTimeoutMsValid(initialMs);
155
+ const optsBridge = node(
156
+ [reactiveTimeoutMs],
157
+ (batchData, actions, ctx) => {
158
+ const data = batchData.map(
159
+ (b, i) => b != null && b.length > 0 ? b.at(-1) : ctx.prevData[i]
160
+ );
161
+ const ms = data[0];
162
+ if (ms === void 0) return;
163
+ if (typeof ms !== "number" || !Number.isFinite(ms) || ms <= 0 || ms > 9e6) {
164
+ actions.down([
165
+ [
166
+ ERROR,
167
+ new RangeError(
168
+ `resilientPipeline: timeoutMs reactive emit invalid (${ms}); must be > 0 and <= 9_000_000.`
169
+ )
170
+ ]
171
+ ]);
172
+ return;
173
+ }
174
+ actions.emit({ ns: ms * NS_PER_MS });
175
+ },
176
+ {
177
+ describeKind: "derived",
178
+ name: "timeoutOptsBridge",
179
+ ...initialMs !== void 0 ? { initial: { ns: initialMs * NS_PER_MS } } : {}
180
+ }
181
+ );
182
+ this.add(optsBridge, { name: "timeoutOptsBridge" });
183
+ const bundle = withTimeout(current, optsBridge, {
184
+ meta: domainMeta("resilient", "timeout")
185
+ });
186
+ current = bundle.node;
187
+ timeoutState = bundle.timeoutState;
188
+ this.add(current, { name: "timeoutWrapped" });
189
+ this.add(timeoutState, { name: "timeoutState" });
190
+ } else {
191
+ assertTimeoutMsValid(opts.timeoutMs);
192
+ const bundle = withTimeout(
193
+ current,
194
+ { ns: opts.timeoutMs * NS_PER_MS },
195
+ {
196
+ meta: domainMeta("resilient", "timeout")
197
+ }
198
+ );
199
+ current = bundle.node;
200
+ timeoutState = bundle.timeoutState;
201
+ this.add(current, { name: "timeoutWrapped" });
202
+ this.add(timeoutState, { name: "timeoutState" });
203
+ }
204
+ }
205
+ if (opts.retry != null) {
206
+ if (isNode(opts.retry)) {
207
+ const bundle = retry(current, opts.retry);
208
+ current = bundle.node;
209
+ retryState = bundle.retryState;
210
+ this.add(current, { name: "retryWrapped" });
211
+ this.add(retryState, { name: "retryState" });
212
+ } else {
213
+ const bundle = retry(current, {
214
+ ...opts.retry,
215
+ meta: domainMeta("resilient", "retry")
216
+ });
217
+ current = bundle.node;
218
+ retryState = bundle.retryState;
219
+ this.add(current, { name: "retryWrapped" });
220
+ this.add(retryState, { name: "retryState" });
221
+ }
222
+ }
223
+ if (opts.fallback !== void 0) {
224
+ current = fallback(current, opts.fallback, {
225
+ meta: domainMeta("resilient", "fallback")
226
+ });
227
+ this.add(current, { name: "fallbackWrapped" });
228
+ }
229
+ const statusBundle = withStatus(current, {
230
+ initialStatus: opts.initialStatus ?? "pending",
231
+ meta: domainMeta("resilient", "status")
232
+ });
233
+ this.output = statusBundle.node;
234
+ this.status = statusBundle.status;
235
+ this.lastError = statusBundle.error;
236
+ this.breakerState = breakerState;
237
+ this.droppedCount = droppedCount;
238
+ this.rateLimitState = rateLimitState;
239
+ this.timeoutState = timeoutState;
240
+ this.retryState = retryState;
241
+ this.add(this.output, { name: "output" });
242
+ this.add(this.status, { name: "status" });
243
+ this.add(this.lastError, { name: "lastError" });
244
+ }
245
+ };
246
+ function resilientPipeline(source, opts = {}) {
247
+ const g = new ResilientPipelineGraph(source, opts);
248
+ g.tagFactory("resilientPipeline", placeholderArgs(opts));
249
+ return g;
250
+ }
251
+
252
+ export {
253
+ ResilientPipelineGraph,
254
+ resilientPipeline
255
+ };
256
+ //# sourceMappingURL=chunk-6XZYT4SW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/presets/resilience/resilient-pipeline.ts"],"sourcesContent":["/**\n * Resilience composition with correct nesting order (roadmap §9.0b — Tier 5.2 Wave-B rebuild).\n *\n * {@link resilientPipeline} composes the resilience primitives from\n * `extra/resilience/` in the canonical nesting order:\n *\n * ```text\n * rateLimit → budget → breaker → timeout → retry → fallback → status\n * ```\n *\n * Returns a {@link ResilientPipelineGraph} (Graph subclass) with mounted\n * intermediate nodes and per-layer status companions, replacing the prior\n * bundle return. Each intermediate is mounted under a stable name so\n * `pipeline.describe()` shows the resilience chain in topology snapshots,\n * mermaid renders, and `lens.health` aggregations.\n *\n * **Per-attempt timeout vs. retry ordering.** `timeout` is applied BEFORE\n * `retry` so each retry attempt resubscribes to a fresh deadline (per-attempt\n * semantics). If `timeout` wrapped `retry`, a single deadline would apply to\n * the entire retry chain — not what callers expect.\n *\n * **`breakerOnOpen` + `retry` interaction.** With `breakerOnOpen: \"error\"` AND\n * `retry`, retry sees `CircuitOpenError` and resubscribes; the next attempt\n * very likely also breaker-open → another error → retry burns its budget\n * against an open circuit. Either set retry's `backoff` long enough for the\n * breaker reset window OR keep the default `breakerOnOpen: \"skip\"` (emits\n * RESOLVED when open; downstream drops the beat without retry firing).\n *\n * **Reactive options (switchMap rebuild).** Every primitive option accepts a\n * `T | Node<T>` (precedent-aligned with `FallbackInput<T>`). When the caller\n * supplies a static value, the layer is built once at construction. When the\n * caller supplies a `Node<T>`, the pipeline subscribes via `switchMap` and\n * **rebuilds the layer on every option emission** — the chain stalls until\n * the option Node emits its first DATA. Each rebuild creates a fresh\n * primitive instance, so internal state is lost (rate-limiter pending buffer,\n * breaker failure count, retry attempt count, in-flight timeout). Per-layer\n * **companion Nodes** (`droppedCount`, `rateLimitState`, `breakerState`) are\n * therefore exposed ONLY for the static-options path. Primitive-side widening\n * (filed in `docs/optimizations.md` under \"Tier 5.2 follow-up — primitive-side\n * reactive-options widening\") will preserve internal state once it lands and\n * the pipeline will trivially forward Node-form options to the primitive.\n *\n * @module\n */\nimport { ERROR, type Node, node, placeholderArgs } from \"@graphrefly/pure-ts/core\";\nimport { switchMap } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport { NS_PER_MS } from \"../../base/resilience/backoff.js\";\nimport {\n\ttype BreakerState,\n\ttype BudgetConstraint,\n\tbudgetGate,\n\ttype CircuitBreakerOptions,\n\tcircuitBreaker,\n\ttype FallbackInput,\n\tfallback,\n\ttype NodeOrValue,\n\ttype RateLimiterOptions,\n\ttype RateLimiterState,\n\ttype RetryOptions,\n\ttype RetryState,\n\trateLimiter,\n\tretry,\n\ttype StatusValue,\n\ttype TimeoutOptions,\n\ttype TimeoutState,\n\twithBreaker,\n\twithStatus,\n\twithTimeout,\n} from \"../../utils/resilience/index.js\";\n\n// ---------------------------------------------------------------------------\n// Reactive-option helpers\n// ---------------------------------------------------------------------------\n\n/**\n * `T | Node<T>` for primitive options — precedent-aligned with\n * {@link FallbackInput} and `policyGate.policies`. When the caller supplies a\n * static value, the layer is built once at construction. When the caller\n * supplies a `Node<T>`, the pipeline subscribes via {@link switchMap}: the\n * layer is rebuilt on every option emission. **State-loss caveat:** each\n * rebuild creates a fresh primitive instance — `rateLimiter` loses its pending\n * buffer, `circuitBreaker` resets failure count, `retry` resets attempt\n * count, `timeout` cancels in-flight deadline. This is the documented\n * switchMap-pattern semantics; primitive-side widening (filed in\n * `docs/optimizations.md`) will preserve internal state once it lands and the\n * pipeline can forward Node-form options directly.\n *\n * Per-layer **companion Nodes** (`droppedCount`, `rateLimitState`,\n * `breakerState`) are exposed only for the static-options path — Node-form\n * leaves them as `undefined` because each rebuild creates new companion\n * instances and a switchMap-mirrored companion would track only the latest\n * bundle. Callers needing both reactive options AND companions wait for\n * primitive-side widening.\n */\n// NodeOrValue re-imported from utils/resilience (same type, avoid barrel duplicate).\n\nfunction isNode<T>(x: unknown): x is Node<T> {\n\treturn (\n\t\ttypeof x === \"object\" && x !== null && \"subscribe\" in (x as object) && \"down\" in (x as object)\n\t);\n}\n\n/**\n * Validation shared by the static and reactive timeout paths. The reactive\n * path runs this inside the `switchMap` projection so an emitted bad value\n * surfaces as a thrown error at projection time (the consuming subscribe\n * routes it through the reactive ERROR channel rather than crashing\n * construction).\n */\nfunction assertTimeoutMsValid(ms: number): void {\n\tif (ms <= 0) throw new RangeError(\"timeoutMs must be > 0\");\n\t// Guard against `timeoutMs * NS_PER_MS` overflowing\n\t// `Number.MAX_SAFE_INTEGER` (~9.007e15). 9_000_000 ms ≈ 2.5 hours is a\n\t// sane upper bound; callers needing longer deadlines should express them\n\t// at the primitive level.\n\tif (ms > 9_000_000) {\n\t\tthrow new RangeError(\n\t\t\t\"timeoutMs must be <= 9_000_000 (≈2.5h) to stay within safe ns arithmetic\",\n\t\t);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/**\n * Options for {@link resilientPipeline}. Every layer is optional — omit a\n * field and that layer is skipped.\n *\n * Reactive (`Node<T>`) forms are accepted everywhere a primitive value would\n * fit; the pipeline subscribes via `switchMap` and rebuilds the layer on each\n * emission. See module JSDoc for the rebuild semantics + state-loss caveat.\n */\nexport interface ResilientPipelineOptions<T> {\n\t/**\n\t * Admission control — at most `maxEvents` `DATA` per `windowNs`. See\n\t * {@link rateLimiter}.\n\t *\n\t * `maxBuffer` is optional at the pipeline layer (defaults to `Infinity`,\n\t * preserving the historical unbounded behavior). Pass an explicit positive\n\t * integer to opt in to a bounded queue.\n\t */\n\trateLimit?: NodeOrValue<Omit<RateLimiterOptions, \"maxBuffer\"> & { maxBuffer?: number }>;\n\t/** Cost/constraint gate. See {@link budgetGate}. */\n\tbudget?: NodeOrValue<ReadonlyArray<BudgetConstraint>>;\n\t/** Circuit breaker — fail-fast when the downstream resource is unhealthy. See {@link circuitBreaker}. */\n\tbreaker?: NodeOrValue<CircuitBreakerOptions>;\n\t/**\n\t * Behavior when the breaker is open:\n\t * - `\"skip\"` (default) — emit `RESOLVED` (lets downstream drop the beat).\n\t * - `\"error\"` — emit a `CircuitOpenError` so `retry` / `fallback` can react.\n\t * See module JSDoc for the retry-budget burn caveat.\n\t *\n\t * Static (configuration-only — no reactive form).\n\t */\n\tbreakerOnOpen?: \"skip\" | \"error\";\n\t/** Retry policy on terminal `ERROR`. See {@link retry}. */\n\tretry?: NodeOrValue<RetryOptions>;\n\t/**\n\t * Per-attempt deadline in milliseconds. Converted to ns internally. Omit\n\t * to skip the timeout wrap.\n\t *\n\t * Specified in ms (not ns) because callers consistently think in\n\t * millisecond deadlines; the underlying {@link timeout} primitive takes ns\n\t * internally.\n\t */\n\ttimeoutMs?: NodeOrValue<number>;\n\t/** Final fallback value emitted on terminal `ERROR` after retry exhausts. See {@link fallback}. */\n\tfallback?: FallbackInput<T>;\n\t/**\n\t * Initial status reported by the status node. Default `\"pending\"`. Static.\n\t */\n\tinitialStatus?: StatusValue;\n\t/** Wrapper graph name. Default `\"resilient_pipeline\"`. */\n\tname?: string;\n\t/** Wrapper graph options. */\n\tgraph?: GraphOptions;\n}\n\n// ---------------------------------------------------------------------------\n// ResilientPipelineGraph\n// ---------------------------------------------------------------------------\n\n/**\n * Graph subclass returned by {@link resilientPipeline}. Mounts each\n * configured intermediate under a stable name and exposes per-layer status\n * companions.\n *\n * @category patterns\n */\nexport class ResilientPipelineGraph<T> extends Graph {\n\t/**\n\t * Final resilient node — subscribe to this for `DATA` emissions.\n\t *\n\t * Named `output` (not `node`) because `Graph.node(name)` already names the\n\t * path-resolution method on the base class; a `readonly node` field would\n\t * shadow it.\n\t */\n\treadonly output: Node<T>;\n\t/** Live status: `\"pending\" | \"running\" | \"completed\" | \"errored\"`. */\n\treadonly status: Node<StatusValue>;\n\t/**\n\t * Last error payload, or `null` when not errored.\n\t *\n\t * Named `lastError` (not `error`) because `Graph.error(name, err)` already\n\t * names a method on the base class.\n\t */\n\treadonly lastError: Node<unknown | null>;\n\t/** Breaker state when `opts.breaker` is provided; `undefined` otherwise. */\n\treadonly breakerState: Node<BreakerState> | undefined;\n\t/**\n\t * Timeout state companion when `opts.timeoutMs` is supplied as a\n\t * `Node<Partial<TimeoutOptions>>`-like form; `undefined` otherwise\n\t * (DS-13.5.B forwarding contract — Node-form opts skip the switchMap\n\t * rebuild and lift the primitive's lifecycle companion onto the\n\t * pipeline bundle).\n\t */\n\treadonly timeoutState: Node<TimeoutState> | undefined;\n\t/**\n\t * Retry state companion when `opts.retry` is supplied as a\n\t * `Node<RetryOptions>`-like form; `undefined` otherwise\n\t * (DS-13.5.B forwarding contract).\n\t */\n\treadonly retryState: Node<RetryState> | undefined;\n\t/**\n\t * Drop-counter when `opts.rateLimit` is provided; `undefined` otherwise.\n\t *\n\t * **Lifetime note:** `droppedCount` retains its final value through\n\t * terminal (`COMPLETE` / `ERROR` / `TEARDOWN`); the underlying counter\n\t * resets to `0` only at the next subscription cycle.\n\t */\n\treadonly droppedCount: Node<number> | undefined;\n\t/**\n\t * Combined rate-limit state when `opts.rateLimit` is provided; `undefined`\n\t * otherwise. Same lifecycle as {@link droppedCount} but exposes\n\t * `pendingCount` and `paused` alongside the drop counter for richer\n\t * backpressure observability (Tier 5.2 D7).\n\t */\n\treadonly rateLimitState: Node<RateLimiterState> | undefined;\n\n\tconstructor(source: Node<T>, opts: ResilientPipelineOptions<T> = {}) {\n\t\tsuper(opts.name ?? \"resilient_pipeline\", opts.graph);\n\n\t\tlet current: Node<T> = source;\n\t\tlet droppedCount: Node<number> | undefined;\n\t\tlet rateLimitState: Node<RateLimiterState> | undefined;\n\t\tlet breakerState: Node<BreakerState> | undefined;\n\t\tlet timeoutState: Node<TimeoutState> | undefined;\n\t\tlet retryState: Node<RetryState> | undefined;\n\n\t\t// 1. Admission control — cheapest to drop / queue before any other work.\n\t\tif (opts.rateLimit != null) {\n\t\t\tif (isNode<Omit<RateLimiterOptions, \"maxBuffer\"> & { maxBuffer?: number }>(opts.rateLimit)) {\n\t\t\t\t// DS-13.5.B forwarding: rateLimiter primitive is widened to\n\t\t\t\t// accept `NodeOrValue<RateLimiterOptions>` directly. Forward\n\t\t\t\t// the Node form to preserve internal state (pending buffer,\n\t\t\t\t// dropped counter) across opts swaps. Companion nodes\n\t\t\t\t// (droppedCount / rateLimitState) lift onto the pipeline\n\t\t\t\t// bundle. The pre-DS-13.5.B switchMap-rebuild path is gone.\n\t\t\t\tconst bundle = rateLimiter(current, opts.rateLimit as NodeOrValue<RateLimiterOptions>);\n\t\t\t\tcurrent = bundle.node;\n\t\t\t\tdroppedCount = bundle.droppedCount;\n\t\t\t\trateLimitState = bundle.rateLimitState;\n\t\t\t\tthis.add(current, { name: \"rateLimited\" });\n\t\t\t\tthis.add(droppedCount, { name: \"droppedCount\" });\n\t\t\t\tthis.add(rateLimitState, { name: \"rateLimitState\" });\n\t\t\t} else {\n\t\t\t\tconst rateOpts: RateLimiterOptions = {\n\t\t\t\t\t...opts.rateLimit,\n\t\t\t\t\tmaxBuffer: opts.rateLimit.maxBuffer ?? Infinity,\n\t\t\t\t\tmeta: domainMeta(\"resilient\", \"rate-limit\"),\n\t\t\t\t};\n\t\t\t\tconst bundle = rateLimiter(current, rateOpts);\n\t\t\t\tcurrent = bundle.node;\n\t\t\t\tdroppedCount = bundle.droppedCount;\n\t\t\t\trateLimitState = bundle.rateLimitState;\n\t\t\t\tthis.add(current, { name: \"rateLimited\" });\n\t\t\t\tthis.add(droppedCount, { name: \"droppedCount\" });\n\t\t\t\tthis.add(rateLimitState, { name: \"rateLimitState\" });\n\t\t\t}\n\t\t}\n\n\t\t// 2. Budget — block when constraints are exhausted. Also cheap (no I/O).\n\t\tif (opts.budget != null) {\n\t\t\tif (isNode<ReadonlyArray<BudgetConstraint>>(opts.budget)) {\n\t\t\t\tconst inputForLayer = current;\n\t\t\t\tconst reactiveBudget = opts.budget;\n\t\t\t\tcurrent = switchMap(reactiveBudget, (constraints) =>\n\t\t\t\t\tconstraints.length > 0\n\t\t\t\t\t\t? budgetGate(inputForLayer, constraints, {\n\t\t\t\t\t\t\t\tmeta: domainMeta(\"resilient\", \"budget\"),\n\t\t\t\t\t\t\t}).node\n\t\t\t\t\t\t: inputForLayer,\n\t\t\t\t);\n\t\t\t\tthis.add(current, { name: \"budgetGated\" });\n\t\t\t} else if (opts.budget.length > 0) {\n\t\t\t\tcurrent = budgetGate(current, opts.budget, {\n\t\t\t\t\tmeta: domainMeta(\"resilient\", \"budget\"),\n\t\t\t\t}).node;\n\t\t\t\tthis.add(current, { name: \"budgetGated\" });\n\t\t\t}\n\t\t}\n\n\t\t// 3. Breaker — skip the resource when unhealthy (fail-fast before retry wastes time).\n\t\tif (opts.breaker != null) {\n\t\t\t// DS-13.5.B forwarding: circuitBreaker primitive accepts\n\t\t\t// `NodeOrValue<CircuitBreakerOptions>` directly. Pass the Node\n\t\t\t// form straight through so internal state (`_state`,\n\t\t\t// `_failureCount`, `_openCycle`, …) is preserved across opts\n\t\t\t// swaps. Companion `breakerState` lifts onto the pipeline\n\t\t\t// bundle in both static and Node-form paths.\n\t\t\tconst breaker = circuitBreaker(opts.breaker as NodeOrValue<CircuitBreakerOptions>);\n\t\t\tconst onOpen = opts.breakerOnOpen ?? \"skip\";\n\t\t\tconst wrapped = withBreaker<T>(breaker, {\n\t\t\t\tonOpen,\n\t\t\t\tmeta: domainMeta(\"resilient\", \"breaker\"),\n\t\t\t})(current);\n\t\t\tcurrent = wrapped.node;\n\t\t\tbreakerState = wrapped.breakerState;\n\t\t\tthis.add(current, { name: \"breakerWrapped\" });\n\t\t\tthis.add(breakerState, { name: \"breakerState\" });\n\t\t}\n\n\t\t// 4. Timeout — per-attempt deadline. Applied BEFORE retry so each retry\n\t\t// resubscribes to a fresh timeout. Swapping the order (timeout\n\t\t// OUTSIDE retry) would apply one global deadline to the entire\n\t\t// retry chain — not what callers expect for \"per-attempt timeout.\"\n\t\tif (opts.timeoutMs != null) {\n\t\t\tif (isNode<number>(opts.timeoutMs)) {\n\t\t\t\t// DS-13.5.B forwarding: build a derived `Node<{ns}>` from\n\t\t\t\t// the caller's `Node<number>` (ms) and pass directly to the\n\t\t\t\t// widened timeout primitive. State preservation (in-flight\n\t\t\t\t// deadline) is handled inside timeout's reactive opts path.\n\t\t\t\t// Companion `timeoutState` lifts onto the pipeline bundle.\n\t\t\t\tconst reactiveTimeoutMs = opts.timeoutMs;\n\t\t\t\tconst initialMs = reactiveTimeoutMs.cache as number | undefined;\n\t\t\t\t// QA A5 (2026-05-03): assert validity of the cached initial\n\t\t\t\t// value at construction so a bad cache fails loud at wire\n\t\t\t\t// time, not silently at first emit. Reactive emits with\n\t\t\t\t// invalid values flow through the producer body's ERROR\n\t\t\t\t// channel rather than throwing into the host scheduler.\n\t\t\t\tif (initialMs !== undefined) assertTimeoutMsValid(initialMs);\n\t\t\t\tconst optsBridge = node<Partial<TimeoutOptions>>(\n\t\t\t\t\t[reactiveTimeoutMs as Node<unknown>],\n\t\t\t\t\t(batchData, actions, ctx) => {\n\t\t\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst ms = data[0] as number | undefined;\n\t\t\t\t\t\tif (ms === undefined) return;\n\t\t\t\t\t\t// QA A5: route validation failures through the\n\t\t\t\t\t\t// reactive ERROR channel — sync `throw` inside a\n\t\t\t\t\t\t// producer body corrupts the host scheduler's\n\t\t\t\t\t\t// wave dispatch (mirrors timeout primitive's\n\t\t\t\t\t\t// \"sync throw would corrupt the host scheduler\"\n\t\t\t\t\t\t// rationale).\n\t\t\t\t\t\tif (typeof ms !== \"number\" || !Number.isFinite(ms) || ms <= 0 || ms > 9_000_000) {\n\t\t\t\t\t\t\tactions.down([\n\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\tERROR,\n\t\t\t\t\t\t\t\t\tnew RangeError(\n\t\t\t\t\t\t\t\t\t\t`resilientPipeline: timeoutMs reactive emit invalid (${ms}); must be > 0 and <= 9_000_000.`,\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\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tactions.emit({ ns: ms * NS_PER_MS });\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\t\t\tname: \"timeoutOptsBridge\",\n\t\t\t\t\t\t...(initialMs !== undefined\n\t\t\t\t\t\t\t? { initial: { ns: initialMs * NS_PER_MS } as Partial<TimeoutOptions> }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\t// QA A5: register the bridge on the pipeline graph so\n\t\t\t\t// describe() walks see the full topology (dry-run /\n\t\t\t\t// real-run equivalence per CLAUDE.md).\n\t\t\t\tthis.add(optsBridge, { name: \"timeoutOptsBridge\" });\n\t\t\t\tconst bundle = withTimeout(current, optsBridge, {\n\t\t\t\t\tmeta: domainMeta(\"resilient\", \"timeout\"),\n\t\t\t\t});\n\t\t\t\tcurrent = bundle.node;\n\t\t\t\ttimeoutState = bundle.timeoutState;\n\t\t\t\tthis.add(current, { name: \"timeoutWrapped\" });\n\t\t\t\tthis.add(timeoutState, { name: \"timeoutState\" });\n\t\t\t} else {\n\t\t\t\tassertTimeoutMsValid(opts.timeoutMs);\n\t\t\t\tconst bundle = withTimeout(\n\t\t\t\t\tcurrent,\n\t\t\t\t\t{ ns: opts.timeoutMs * NS_PER_MS },\n\t\t\t\t\t{\n\t\t\t\t\t\tmeta: domainMeta(\"resilient\", \"timeout\"),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tcurrent = bundle.node;\n\t\t\t\ttimeoutState = bundle.timeoutState;\n\t\t\t\tthis.add(current, { name: \"timeoutWrapped\" });\n\t\t\t\tthis.add(timeoutState, { name: \"timeoutState\" });\n\t\t\t}\n\t\t}\n\n\t\t// 5. Retry — resubscribe on `ERROR` up to `count` times. Wraps timeout\n\t\t// so each retry gets its own fresh deadline.\n\t\tif (opts.retry != null) {\n\t\t\t// DS-13.5.B forwarding: retry primitive accepts\n\t\t\t// `NodeOrValue<RetryOptions>` directly. Forward Node form so\n\t\t\t// `attempt` / `prevDelay` / in-flight timer survive opts swaps.\n\t\t\t// Companion `retryState` lifts onto the pipeline bundle.\n\t\t\tif (isNode<RetryOptions>(opts.retry)) {\n\t\t\t\tconst bundle = retry(current, opts.retry as NodeOrValue<RetryOptions>);\n\t\t\t\tcurrent = bundle.node;\n\t\t\t\tretryState = bundle.retryState;\n\t\t\t\tthis.add(current, { name: \"retryWrapped\" });\n\t\t\t\tthis.add(retryState, { name: \"retryState\" });\n\t\t\t} else {\n\t\t\t\tconst bundle = retry(current, {\n\t\t\t\t\t...opts.retry,\n\t\t\t\t\tmeta: domainMeta(\"resilient\", \"retry\"),\n\t\t\t\t});\n\t\t\t\tcurrent = bundle.node;\n\t\t\t\tretryState = bundle.retryState;\n\t\t\t\tthis.add(current, { name: \"retryWrapped\" });\n\t\t\t\tthis.add(retryState, { name: \"retryState\" });\n\t\t\t}\n\t\t}\n\n\t\t// 6. Fallback — last resort after retry+timeout exhaust. Guard\n\t\t// `opts.fallback !== undefined` so `null` is a valid fallback.\n\t\tif (opts.fallback !== undefined) {\n\t\t\tcurrent = fallback(current, opts.fallback, {\n\t\t\t\tmeta: domainMeta(\"resilient\", \"fallback\"),\n\t\t\t});\n\t\t\tthis.add(current, { name: \"fallbackWrapped\" });\n\t\t}\n\n\t\t// 7. Status wrapping — observability. Always last so it sees the final shape.\n\t\tconst statusBundle = withStatus(current, {\n\t\t\tinitialStatus: opts.initialStatus ?? \"pending\",\n\t\t\tmeta: domainMeta(\"resilient\", \"status\"),\n\t\t});\n\n\t\tthis.output = statusBundle.node;\n\t\tthis.status = statusBundle.status;\n\t\tthis.lastError = statusBundle.error;\n\t\tthis.breakerState = breakerState;\n\t\tthis.droppedCount = droppedCount;\n\t\tthis.rateLimitState = rateLimitState;\n\t\tthis.timeoutState = timeoutState;\n\t\tthis.retryState = retryState;\n\n\t\t// Mount the externally-visible top-level entries by name. Each carries\n\t\t// its own factoryTag meta from the underlying primitive (`withStatus`\n\t\t// for `output`/`status`/`lastError`); domain-level provenance lives on\n\t\t// the Graph itself via the `tagFactory(\"resilientPipeline\", ...)` call\n\t\t// in the public factory below. The mount names use `output` /\n\t\t// `lastError` to match the property names — the previous `node` /\n\t\t// `error` clashed with `Graph.node(name)` / `Graph.error(name, err)`.\n\t\tthis.add(this.output, { name: \"output\" });\n\t\tthis.add(this.status, { name: \"status\" });\n\t\tthis.add(this.lastError, { name: \"lastError\" });\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Compose a resilient pipeline around `source` in the canonical nesting\n * order — `rateLimit → budget → breaker → timeout → retry → fallback → status`.\n * Omit any option to skip that layer.\n *\n * Returns a {@link ResilientPipelineGraph} (Graph subclass) —\n * `pipeline.output` is the externally visible final node; `pipeline.status`\n * / `pipeline.lastError` / `pipeline.breakerState` / `pipeline.droppedCount`\n * are the per-layer companions. Call `pipeline.describe()` to see the\n * mounted intermediates; compose with {@link graphLens}'s `health` for\n * aggregate status.\n *\n * **Naming note:** `output` and `lastError` (not `node` / `error`) avoid\n * clashes with `Graph.node(name)` and `Graph.error(name, err)` on the base\n * class.\n *\n * @param source - Upstream node to wrap.\n * @param opts - See {@link ResilientPipelineOptions}. All fields optional.\n *\n * @example\n * ```ts\n * const safeFetch = resilientPipeline(fetchNode, {\n * rateLimit: { maxEvents: 10, windowNs: NS_PER_SEC },\n * breaker: { failureThreshold: 5 },\n * retry: { count: 3, backoff: \"exponential\" },\n * timeoutMs: 10_000,\n * fallback: null,\n * });\n * safeFetch.output.subscribe(msgs => console.log(msgs));\n * safeFetch.status.subscribe(msgs => console.log(msgs));\n * graphSpecToAscii(safeFetch.describe()); // visualize the chain\n * ```\n *\n * @category patterns\n */\nexport function resilientPipeline<T>(\n\tsource: Node<T>,\n\topts: ResilientPipelineOptions<T> = {},\n): ResilientPipelineGraph<T> {\n\tconst g = new ResilientPipelineGraph<T>(source, opts);\n\t// Self-tag for `graph.describe()` factory provenance (Phase 2.5 DG1=B).\n\t// `placeholderArgs` substitutes Node-typed and function-typed fields with\n\t// `\"<Node>\"` / `\"<function>\"` so `factoryArgs` stays JSON-serializable.\n\tg.tagFactory(\"resilientPipeline\", placeholderArgs(opts as unknown as Record<string, unknown>));\n\treturn g;\n}\n\n// Tag the underlying status / error / breaker / dropped companions with a\n// best-effort factoryTag too via the wrapper class's meta — already covered\n// by `domainMeta(\"resilient\", kind)` on the mounted nodes.\n\n// Tier 9.1 γ-form: this module now lives inside `extra/resilience/`, so the\n// underlying primitive option types are already exported from the same barrel\n// (`./index.js`). The previous re-exports of `factoryTag` / `placeholderArgs` /\n// `NS_PER_MS` / `NS_PER_SEC` / option types were a workaround for the prior\n// `patterns/resilient-pipeline/` folder location and are now redundant.\n"],"mappings":"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","names":[]}
@@ -0,0 +1,76 @@
1
+ // src/base/sources/event/cron.ts
2
+ import { node, wallClockNs } from "@graphrefly/pure-ts/core";
3
+ function sourceOpts(opts) {
4
+ return { describeKind: "producer", ...opts };
5
+ }
6
+ function parseField(field, min, max) {
7
+ const result = /* @__PURE__ */ new Set();
8
+ for (const part of field.split(",")) {
9
+ const [range, stepStr] = part.split("/");
10
+ const step = stepStr ? Number.parseInt(stepStr, 10) : 1;
11
+ if (Number.isNaN(step) || step < 1) throw new Error(`Invalid cron step: ${part}`);
12
+ let start;
13
+ let end;
14
+ if (range === "*") {
15
+ start = min;
16
+ end = max;
17
+ } else if (range.includes("-")) {
18
+ const [a, b] = range.split("-");
19
+ start = Number.parseInt(a, 10);
20
+ end = Number.parseInt(b, 10);
21
+ } else {
22
+ start = Number.parseInt(range, 10);
23
+ end = start;
24
+ }
25
+ if (Number.isNaN(start) || Number.isNaN(end)) throw new Error(`Invalid cron field: ${field}`);
26
+ if (start < min || end > max)
27
+ throw new Error(`Cron field out of range: ${field} (${min}-${max})`);
28
+ if (start > end) throw new Error(`Invalid cron range: ${start}-${end} in ${field}`);
29
+ for (let i = start; i <= end; i += step) result.add(i);
30
+ }
31
+ return result;
32
+ }
33
+ function parseCron(expr) {
34
+ const parts = expr.trim().split(/\s+/);
35
+ if (parts.length !== 5) throw new Error(`Invalid cron: expected 5 fields, got ${parts.length}`);
36
+ return {
37
+ minutes: parseField(parts[0], 0, 59),
38
+ hours: parseField(parts[1], 0, 23),
39
+ daysOfMonth: parseField(parts[2], 1, 31),
40
+ months: parseField(parts[3], 1, 12),
41
+ daysOfWeek: parseField(parts[4], 0, 6)
42
+ };
43
+ }
44
+ function matchesCron(schedule, date) {
45
+ return schedule.minutes.has(date.getMinutes()) && schedule.hours.has(date.getHours()) && schedule.daysOfMonth.has(date.getDate()) && schedule.months.has(date.getMonth() + 1) && schedule.daysOfWeek.has(date.getDay());
46
+ }
47
+ function fromCron(expr, opts) {
48
+ const schedule = parseCron(expr);
49
+ const { tickMs: tickOpt, output, ...rest } = opts ?? {};
50
+ const tickMs = tickOpt ?? 6e4;
51
+ const emitDate = output === "date";
52
+ return node(
53
+ (_data, a) => {
54
+ let lastFiredKey = -1;
55
+ const check = () => {
56
+ const now = /* @__PURE__ */ new Date();
57
+ const key = now.getFullYear() * 1e8 + (now.getMonth() + 1) * 1e6 + now.getDate() * 1e4 + now.getHours() * 100 + now.getMinutes();
58
+ if (key !== lastFiredKey && matchesCron(schedule, now)) {
59
+ lastFiredKey = key;
60
+ a.emit(emitDate ? now : wallClockNs());
61
+ }
62
+ };
63
+ check();
64
+ const id = setInterval(check, tickMs);
65
+ return () => clearInterval(id);
66
+ },
67
+ { ...sourceOpts(rest), name: rest.name ?? `cron:${expr}` }
68
+ );
69
+ }
70
+
71
+ export {
72
+ parseCron,
73
+ matchesCron,
74
+ fromCron
75
+ };
76
+ //# sourceMappingURL=chunk-7EGRP2VX.js.map