@graphrefly/graphrefly 0.44.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -19
- package/dist/_internal-B23BagFd.d.cts +33 -0
- package/dist/_internal-B23BagFd.d.ts +33 -0
- package/dist/adaptive-rate-limiter-Dch_xYIi.d.cts +111 -0
- package/dist/adaptive-rate-limiter-Dch_xYIi.d.ts +111 -0
- package/dist/agents-C0Ji9ldU.d.cts +629 -0
- package/dist/agents-C9zexT7I.d.ts +629 -0
- package/dist/audit-BAXb3VOg.d.ts +246 -0
- package/dist/audit-C_bPfkqS.d.cts +246 -0
- package/dist/backoff-7KIK3WQW.js +24 -0
- package/dist/backoff-7KIK3WQW.js.map +1 -0
- package/dist/backoff-Bnb9OoPh.d.cts +6 -0
- package/dist/backoff-Bnb9OoPh.d.ts +6 -0
- package/dist/base/composition/index.cjs +811 -0
- package/dist/base/composition/index.cjs.map +1 -0
- package/dist/base/composition/index.d.cts +469 -0
- package/dist/base/composition/index.d.ts +469 -0
- package/dist/base/composition/index.js +40 -0
- package/dist/base/composition/index.js.map +1 -0
- package/dist/base/index.cjs +6336 -0
- package/dist/base/index.cjs.map +1 -0
- package/dist/base/index.d.cts +22 -0
- package/dist/base/index.d.ts +22 -0
- package/dist/base/index.js +259 -0
- package/dist/base/index.js.map +1 -0
- package/dist/base/io/index.cjs +3270 -0
- package/dist/base/io/index.cjs.map +1 -0
- package/dist/base/io/index.d.cts +2245 -0
- package/dist/base/io/index.d.ts +2245 -0
- package/dist/base/io/index.js +117 -0
- package/dist/base/io/index.js.map +1 -0
- package/dist/base/meta/index.cjs +43 -0
- package/dist/base/meta/index.cjs.map +1 -0
- package/dist/base/meta/index.d.cts +45 -0
- package/dist/base/meta/index.d.ts +45 -0
- package/dist/base/meta/index.js +13 -0
- package/dist/base/meta/index.js.map +1 -0
- package/dist/base/mutation/index.cjs +200 -0
- package/dist/base/mutation/index.cjs.map +1 -0
- package/dist/base/mutation/index.d.cts +177 -0
- package/dist/base/mutation/index.d.ts +177 -0
- package/dist/base/mutation/index.js +22 -0
- package/dist/base/mutation/index.js.map +1 -0
- package/dist/base/render/index.cjs +1120 -0
- package/dist/base/render/index.cjs.map +1 -0
- package/dist/{extra/render/index.d.ts → base/render/index.d.cts} +75 -31
- package/dist/{extra/render/index.d.cts → base/render/index.d.ts} +75 -31
- package/dist/base/render/index.js +24 -0
- package/dist/base/render/index.js.map +1 -0
- package/dist/base/sources/browser/index.cjs +172 -0
- package/dist/base/sources/browser/index.cjs.map +1 -0
- package/dist/base/sources/browser/index.d.cts +84 -0
- package/dist/base/sources/browser/index.d.ts +84 -0
- package/dist/base/sources/browser/index.js +151 -0
- package/dist/base/sources/browser/index.js.map +1 -0
- package/dist/base/sources/event/index.cjs +98 -0
- package/dist/base/sources/event/index.cjs.map +1 -0
- package/dist/base/sources/event/index.d.cts +91 -0
- package/dist/base/sources/event/index.d.ts +91 -0
- package/dist/base/sources/event/index.js +13 -0
- package/dist/base/sources/event/index.js.map +1 -0
- package/dist/base/sources/index.cjs +755 -0
- package/dist/base/sources/index.cjs.map +1 -0
- package/dist/{extra/sources.d.ts → base/sources/index.d.cts} +74 -301
- package/dist/{extra/sources.d.cts → base/sources/index.d.ts} +74 -301
- package/dist/base/sources/index.js +42 -0
- package/dist/base/sources/index.js.map +1 -0
- package/dist/base/sources/node/index.cjs +320 -0
- package/dist/base/sources/node/index.cjs.map +1 -0
- package/dist/{extra/node.d.ts → base/sources/node/index.d.cts} +35 -37
- package/dist/{extra/node.d.cts → base/sources/node/index.d.ts} +35 -37
- package/dist/base/sources/node/index.js +306 -0
- package/dist/base/sources/node/index.js.map +1 -0
- package/dist/base/utils/index.cjs +37 -0
- package/dist/base/utils/index.cjs.map +1 -0
- package/dist/base/utils/index.d.cts +37 -0
- package/dist/base/utils/index.d.ts +37 -0
- package/dist/base/utils/index.js +11 -0
- package/dist/base/utils/index.js.map +1 -0
- package/dist/base/worker/index.cjs +548 -0
- package/dist/base/worker/index.cjs.map +1 -0
- package/dist/base/worker/index.d.cts +207 -0
- package/dist/base/worker/index.d.ts +207 -0
- package/dist/base/worker/index.js +20 -0
- package/dist/base/worker/index.js.map +1 -0
- package/dist/breaker-C9skL3d8.d.ts +175 -0
- package/dist/breaker-ugSdq54q.d.cts +175 -0
- package/dist/{cascading-BglDkMdX.d.cts → cascading-CSSbKGrJ.d.ts} +3 -3
- package/dist/{cascading-MFgxu7Yo.d.ts → cascading-baGkiihI.d.cts} +3 -3
- package/dist/chunk-255UCBG4.js +58 -0
- package/dist/chunk-255UCBG4.js.map +1 -0
- package/dist/chunk-2LO3EL4W.js +1 -0
- package/dist/chunk-2LO3EL4W.js.map +1 -0
- package/dist/chunk-2OB3CEJS.js +1065 -0
- package/dist/chunk-2OB3CEJS.js.map +1 -0
- package/dist/chunk-36NMM65U.js +144 -0
- package/dist/chunk-36NMM65U.js.map +1 -0
- package/dist/chunk-3CEXCBN6.js +1 -0
- package/dist/chunk-3CEXCBN6.js.map +1 -0
- package/dist/chunk-3MUSLI6E.js +105 -0
- package/dist/chunk-3MUSLI6E.js.map +1 -0
- package/dist/chunk-3PSLNJDU.js +884 -0
- package/dist/chunk-3PSLNJDU.js.map +1 -0
- package/dist/chunk-3QZY5BI7.js +92 -0
- package/dist/chunk-3QZY5BI7.js.map +1 -0
- package/dist/chunk-42FQ27MQ.js +594 -0
- package/dist/chunk-42FQ27MQ.js.map +1 -0
- package/dist/chunk-4GYMCUDZ.js +1085 -0
- package/dist/chunk-4GYMCUDZ.js.map +1 -0
- package/dist/chunk-4S53H2KR.js +382 -0
- package/dist/chunk-4S53H2KR.js.map +1 -0
- package/dist/chunk-4XCHZRUJ.js +128 -0
- package/dist/chunk-4XCHZRUJ.js.map +1 -0
- package/dist/chunk-5THCXDWY.js +725 -0
- package/dist/chunk-5THCXDWY.js.map +1 -0
- package/dist/chunk-6XZYT4SW.js +256 -0
- package/dist/chunk-6XZYT4SW.js.map +1 -0
- package/dist/chunk-7EGRP2VX.js +76 -0
- package/dist/chunk-7EGRP2VX.js.map +1 -0
- package/dist/chunk-A7KV5UK4.js +150 -0
- package/dist/chunk-A7KV5UK4.js.map +1 -0
- package/dist/chunk-APY2SS5X.js +156 -0
- package/dist/chunk-APY2SS5X.js.map +1 -0
- package/dist/chunk-AZDQPQ3V.js +66 -0
- package/dist/chunk-AZDQPQ3V.js.map +1 -0
- package/dist/chunk-BU3SEFA5.js +90 -0
- package/dist/chunk-BU3SEFA5.js.map +1 -0
- package/dist/chunk-BXGZFGZ4.js +189 -0
- package/dist/chunk-BXGZFGZ4.js.map +1 -0
- package/dist/chunk-CGHORL6G.js +579 -0
- package/dist/chunk-CGHORL6G.js.map +1 -0
- package/dist/chunk-CXANAIZU.js +530 -0
- package/dist/chunk-CXANAIZU.js.map +1 -0
- package/dist/chunk-CZQHCKKG.js +1 -0
- package/dist/chunk-CZQHCKKG.js.map +1 -0
- package/dist/chunk-DKNHAICT.js +133 -0
- package/dist/chunk-DKNHAICT.js.map +1 -0
- package/dist/chunk-DM4OMPWK.js +584 -0
- package/dist/chunk-DM4OMPWK.js.map +1 -0
- package/dist/chunk-DMSNO6ZB.js +452 -0
- package/dist/chunk-DMSNO6ZB.js.map +1 -0
- package/dist/chunk-E5OZPDIW.js +229 -0
- package/dist/chunk-E5OZPDIW.js.map +1 -0
- package/dist/chunk-EVYY4X5A.js +509 -0
- package/dist/chunk-EVYY4X5A.js.map +1 -0
- package/dist/chunk-FDFD67UO.js +1 -0
- package/dist/chunk-FDFD67UO.js.map +1 -0
- package/dist/chunk-FMPF42Q4.js +13 -0
- package/dist/chunk-FMPF42Q4.js.map +1 -0
- package/dist/chunk-FR6RGA3B.js +1277 -0
- package/dist/chunk-FR6RGA3B.js.map +1 -0
- package/dist/chunk-FW23JYNQ.js +454 -0
- package/dist/chunk-FW23JYNQ.js.map +1 -0
- package/dist/chunk-GBCENOLN.js +1575 -0
- package/dist/chunk-GBCENOLN.js.map +1 -0
- package/dist/chunk-HL7HUJIX.js +1 -0
- package/dist/chunk-HL7HUJIX.js.map +1 -0
- package/dist/chunk-HULCUY35.js +2508 -0
- package/dist/chunk-HULCUY35.js.map +1 -0
- package/dist/chunk-IHTWQEDR.js +169 -0
- package/dist/chunk-IHTWQEDR.js.map +1 -0
- package/dist/chunk-IJRR6YAI.js +128 -0
- package/dist/chunk-IJRR6YAI.js.map +1 -0
- package/dist/chunk-JGFRAFDL.js +221 -0
- package/dist/chunk-JGFRAFDL.js.map +1 -0
- package/dist/chunk-KIIXR252.js +211 -0
- package/dist/chunk-KIIXR252.js.map +1 -0
- package/dist/chunk-KN3H5CNT.js +11 -0
- package/dist/chunk-KN3H5CNT.js.map +1 -0
- package/dist/chunk-KPG3DGLA.js +1 -0
- package/dist/chunk-KPG3DGLA.js.map +1 -0
- package/dist/chunk-KRNQ6RGQ.js +1 -0
- package/dist/chunk-KRNQ6RGQ.js.map +1 -0
- package/dist/chunk-LBAJK24K.js +1071 -0
- package/dist/chunk-LBAJK24K.js.map +1 -0
- package/dist/chunk-MLTPJMH6.js +417 -0
- package/dist/chunk-MLTPJMH6.js.map +1 -0
- package/dist/chunk-N3SZ7BMH.js +95 -0
- package/dist/chunk-N3SZ7BMH.js.map +1 -0
- package/dist/chunk-NDUD3IMO.js +540 -0
- package/dist/chunk-NDUD3IMO.js.map +1 -0
- package/dist/chunk-NY2PYHNC.js +873 -0
- package/dist/chunk-NY2PYHNC.js.map +1 -0
- package/dist/chunk-O3MT7DYI.js +225 -0
- package/dist/chunk-O3MT7DYI.js.map +1 -0
- package/dist/chunk-OCUDSN63.js +2386 -0
- package/dist/chunk-OCUDSN63.js.map +1 -0
- package/dist/chunk-OIWU3NYV.js +199 -0
- package/dist/chunk-OIWU3NYV.js.map +1 -0
- package/dist/chunk-OO5BM6CJ.js +1153 -0
- package/dist/chunk-OO5BM6CJ.js.map +1 -0
- package/dist/chunk-OQUIJT7A.js +1 -0
- package/dist/chunk-OQUIJT7A.js.map +1 -0
- package/dist/chunk-P5LBT622.js +105 -0
- package/dist/chunk-P5LBT622.js.map +1 -0
- package/dist/chunk-PKGQG5QQ.js +519 -0
- package/dist/chunk-PKGQG5QQ.js.map +1 -0
- package/dist/chunk-PKPO3JTZ.js +561 -0
- package/dist/chunk-PKPO3JTZ.js.map +1 -0
- package/dist/chunk-PL5UDIQ5.js +118 -0
- package/dist/chunk-PL5UDIQ5.js.map +1 -0
- package/dist/chunk-PZWISPIQ.js +432 -0
- package/dist/chunk-PZWISPIQ.js.map +1 -0
- package/dist/chunk-Q3EYOCZB.js +510 -0
- package/dist/chunk-Q3EYOCZB.js.map +1 -0
- package/dist/chunk-QMBYUVRL.js +15 -0
- package/dist/chunk-QMBYUVRL.js.map +1 -0
- package/dist/chunk-RAGGHLCV.js +200 -0
- package/dist/chunk-RAGGHLCV.js.map +1 -0
- package/dist/chunk-RGL53X5G.js +574 -0
- package/dist/chunk-RGL53X5G.js.map +1 -0
- package/dist/chunk-RJOG4IJU.js +1039 -0
- package/dist/chunk-RJOG4IJU.js.map +1 -0
- package/dist/chunk-SOOKUYVM.js +403 -0
- package/dist/chunk-SOOKUYVM.js.map +1 -0
- package/dist/chunk-T5BN5KG7.js +1 -0
- package/dist/chunk-T5BN5KG7.js.map +1 -0
- package/dist/chunk-TP7244Y6.js +207 -0
- package/dist/chunk-TP7244Y6.js.map +1 -0
- package/dist/chunk-TSBFTJKM.js +57 -0
- package/dist/chunk-TSBFTJKM.js.map +1 -0
- package/dist/chunk-URQ2CBBF.js +143 -0
- package/dist/chunk-URQ2CBBF.js.map +1 -0
- package/dist/chunk-W2BOPXTI.js +1 -0
- package/dist/chunk-W2BOPXTI.js.map +1 -0
- package/dist/chunk-WKSWLSCX.js +207 -0
- package/dist/chunk-WKSWLSCX.js.map +1 -0
- package/dist/chunk-Y52CS6YA.js +88 -0
- package/dist/chunk-Y52CS6YA.js.map +1 -0
- package/dist/chunk-YCBUWK77.js +92 -0
- package/dist/chunk-YCBUWK77.js.map +1 -0
- package/dist/chunk-YJ4U2D2C.js +314 -0
- package/dist/chunk-YJ4U2D2C.js.map +1 -0
- package/dist/chunk-Z4YXAUDN.js +239 -0
- package/dist/chunk-Z4YXAUDN.js.map +1 -0
- package/dist/chunk-Z6EGP5D7.js +92 -0
- package/dist/chunk-Z6EGP5D7.js.map +1 -0
- package/dist/compat/index.cjs +3100 -9
- package/dist/compat/index.cjs.map +1 -0
- package/dist/compat/index.d.cts +112 -18
- package/dist/compat/index.d.ts +112 -18
- package/dist/compat/index.js +176 -1
- package/dist/compat/index.js.map +1 -0
- package/dist/compat/jotai/index.cjs +149 -1
- package/dist/compat/jotai/index.cjs.map +1 -0
- package/dist/compat/jotai/index.d.cts +2 -2
- package/dist/compat/jotai/index.d.ts +2 -2
- package/dist/compat/jotai/index.js +8 -1
- package/dist/compat/jotai/index.js.map +1 -0
- package/dist/compat/nanostores/index.cjs +205 -1
- package/dist/compat/nanostores/index.cjs.map +1 -0
- package/dist/compat/nanostores/index.d.cts +2 -2
- package/dist/compat/nanostores/index.d.ts +2 -2
- package/dist/compat/nanostores/index.js +22 -1
- package/dist/compat/nanostores/index.js.map +1 -0
- package/dist/compat/nestjs/index.cjs +2241 -9
- package/dist/compat/nestjs/index.cjs.map +1 -0
- package/dist/compat/nestjs/index.d.cts +7 -10
- package/dist/compat/nestjs/index.d.ts +7 -10
- package/dist/compat/nestjs/index.js +78 -1
- package/dist/compat/nestjs/index.js.map +1 -0
- package/dist/compat/react/index.cjs +114 -1
- package/dist/compat/react/index.cjs.map +1 -0
- package/dist/compat/react/index.d.cts +2 -2
- package/dist/compat/react/index.d.ts +2 -2
- package/dist/compat/react/index.js +12 -1
- package/dist/compat/react/index.js.map +1 -0
- package/dist/compat/solid/index.cjs +101 -1
- package/dist/compat/solid/index.cjs.map +1 -0
- package/dist/compat/solid/index.d.cts +2 -2
- package/dist/compat/solid/index.d.ts +2 -2
- package/dist/compat/solid/index.js +12 -1
- package/dist/compat/solid/index.js.map +1 -0
- package/dist/compat/svelte/index.cjs +104 -1
- package/dist/compat/svelte/index.cjs.map +1 -0
- package/dist/compat/svelte/index.d.cts +2 -2
- package/dist/compat/svelte/index.d.ts +2 -2
- package/dist/compat/svelte/index.js +12 -1
- package/dist/compat/svelte/index.js.map +1 -0
- package/dist/compat/vue/index.cjs +119 -1
- package/dist/compat/vue/index.cjs.map +1 -0
- package/dist/compat/vue/index.d.cts +2 -2
- package/dist/compat/vue/index.d.ts +2 -2
- package/dist/compat/vue/index.js +12 -1
- package/dist/compat/vue/index.js.map +1 -0
- package/dist/compat/zustand/index.cjs +69 -3
- package/dist/compat/zustand/index.cjs.map +1 -0
- package/dist/compat/zustand/index.d.cts +2 -6
- package/dist/compat/zustand/index.d.ts +2 -6
- package/dist/compat/zustand/index.js +8 -1
- package/dist/compat/zustand/index.js.map +1 -0
- package/dist/distill-De6Rnn15.d.cts +48 -0
- package/dist/distill-De6Rnn15.d.ts +48 -0
- package/dist/external-register-CWyroXb_.d.cts +138 -0
- package/dist/external-register-CWyroXb_.d.ts +138 -0
- package/dist/{fallback-74oxi34l.d.cts → fallback-Bx46zqky.d.cts} +3 -10
- package/dist/{fallback-DUyyBTBK.d.ts → fallback-pIWW8A2d.d.ts} +3 -10
- package/dist/guarded-execution-BcdtxeBk.d.ts +207 -0
- package/dist/guarded-execution-C-3hnP6A.d.cts +207 -0
- package/dist/{index-CBGUK09R.d.ts → index-5SU_O78r.d.cts} +5 -5
- package/dist/{index-BmZXHqkE.d.ts → index-B6pxYJzO.d.cts} +1 -1
- package/dist/{index-hcDJ8PSI.d.cts → index-B6pxYJzO.d.ts} +1 -1
- package/dist/{index-C5stwKcw.d.cts → index-BFsng6v1.d.cts} +1 -1
- package/dist/{index-CdAlHFEt.d.ts → index-BFsng6v1.d.ts} +1 -1
- package/dist/{index-_6ODbuOu.d.cts → index-Bg-LwEt-.d.cts} +1 -1
- package/dist/{index-CviRnE4K.d.ts → index-Bg-LwEt-.d.ts} +1 -1
- package/dist/{index-CBBLl_rc.d.ts → index-Brp888t0.d.cts} +1 -1
- package/dist/{index-BQSKmbuG.d.cts → index-Brp888t0.d.ts} +1 -1
- package/dist/{index-sqkqlb1p.d.ts → index-CDfk6jHN.d.cts} +1 -1
- package/dist/{index-ZVQhLa2i.d.cts → index-CDfk6jHN.d.ts} +1 -1
- package/dist/{index-Climxqsu.d.cts → index-CEXCtYYJ.d.ts} +5 -5
- package/dist/index-DLAxYaN5.d.cts +169 -0
- package/dist/index-DLAxYaN5.d.ts +169 -0
- package/dist/{index-CK29LV56.d.cts → index-DeWbQzMe.d.cts} +1 -1
- package/dist/{index-CPQlGA29.d.ts → index-DeWbQzMe.d.ts} +1 -1
- package/dist/{index-BrPrLl4e.d.cts → index-dX9IzPqj.d.cts} +1 -1
- package/dist/{index-Dgl1HpPn.d.ts → index-dX9IzPqj.d.ts} +1 -1
- package/dist/index.cjs +25934 -191
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +58 -94
- package/dist/index.d.ts +58 -94
- package/dist/index.js +852 -1
- package/dist/index.js.map +1 -0
- package/dist/layout-types-B5aiHYgk.d.cts +72 -0
- package/dist/layout-types-B5aiHYgk.d.ts +72 -0
- package/dist/memory-composers-BryDrRBX.d.cts +529 -0
- package/dist/memory-composers-CVQqPYEV.d.ts +529 -0
- package/dist/{observable-DWjNfLvC.d.ts → observable-BXQoW1P-.d.cts} +1 -1
- package/dist/{observable-e3eiPPFy.d.cts → observable-BXQoW1P-.d.ts} +1 -1
- package/dist/{pipeline-graph-Sgj0gCwn.d.ts → pipeline-graph-Ce47CB6Y.d.cts} +13 -10
- package/dist/{pipeline-graph-CIKhynsF.d.cts → pipeline-graph-DXCwY9vG.d.ts} +13 -10
- package/dist/presets/ai/index.cjs +4377 -0
- package/dist/presets/ai/index.cjs.map +1 -0
- package/dist/presets/ai/index.d.cts +98 -0
- package/dist/presets/ai/index.d.ts +98 -0
- package/dist/presets/ai/index.js +54 -0
- package/dist/presets/ai/index.js.map +1 -0
- package/dist/presets/harness/index.cjs +5929 -0
- package/dist/presets/harness/index.cjs.map +1 -0
- package/dist/presets/harness/index.d.cts +566 -0
- package/dist/presets/harness/index.d.ts +566 -0
- package/dist/presets/harness/index.js +71 -0
- package/dist/presets/harness/index.js.map +1 -0
- package/dist/presets/index.cjs +9782 -0
- package/dist/presets/index.cjs.map +1 -0
- package/dist/presets/index.d.cts +28 -0
- package/dist/presets/index.d.ts +28 -0
- package/dist/presets/index.js +129 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/presets/inspect/index.cjs +1087 -0
- package/dist/presets/inspect/index.cjs.map +1 -0
- package/dist/presets/inspect/index.d.cts +172 -0
- package/dist/presets/inspect/index.d.ts +172 -0
- package/dist/presets/inspect/index.js +21 -0
- package/dist/presets/inspect/index.js.map +1 -0
- package/dist/presets/resilience/index.cjs +1593 -0
- package/dist/presets/resilience/index.cjs.map +1 -0
- package/dist/presets/resilience/index.d.cts +205 -0
- package/dist/presets/resilience/index.d.ts +205 -0
- package/dist/presets/resilience/index.js +18 -0
- package/dist/presets/resilience/index.js.map +1 -0
- package/dist/rate-limiter-CEALq4N1.d.ts +559 -0
- package/dist/rate-limiter-DpVbSYdH.d.cts +559 -0
- package/dist/{reactive-layout-DOTs9P3X.d.ts → reactive-layout-fswlBUvX.d.cts} +19 -7
- package/dist/{reactive-layout-DgctbqZo.d.cts → reactive-layout-fswlBUvX.d.ts} +19 -7
- package/dist/retry-BDbRZ_gx.d.ts +125 -0
- package/dist/retry-DWuhjvsA.d.cts +125 -0
- package/dist/solutions/index.cjs +8200 -0
- package/dist/solutions/index.cjs.map +1 -0
- package/dist/solutions/index.d.cts +23 -0
- package/dist/solutions/index.d.ts +23 -0
- package/dist/solutions/index.js +55 -0
- package/dist/solutions/index.js.map +1 -0
- package/dist/spawnable-5mDY501F.d.cts +746 -0
- package/dist/spawnable-D3lR0oQu.d.ts +746 -0
- package/dist/status-U-rUI79b.d.cts +84 -0
- package/dist/status-U-rUI79b.d.ts +84 -0
- package/dist/timeout-U5O4ESK3.js +12 -0
- package/dist/timeout-U5O4ESK3.js.map +1 -0
- package/dist/{types-CWFysE9E.d.ts → types-BB5Lw-pB.d.cts} +3 -3
- package/dist/{types-C0_yquda.d.cts → types-BB5Lw-pB.d.ts} +3 -3
- package/dist/types-CJWIMJiZ.d.ts +548 -0
- package/dist/types-vCq7ShIm.d.cts +548 -0
- package/dist/utils/ai/browser.cjs +2169 -0
- package/dist/utils/ai/browser.cjs.map +1 -0
- package/dist/{patterns → utils}/ai/browser.d.cts +7 -5
- package/dist/{patterns → utils}/ai/browser.d.ts +7 -5
- package/dist/utils/ai/browser.js +255 -0
- package/dist/utils/ai/browser.js.map +1 -0
- package/dist/utils/ai/index.cjs +8468 -0
- package/dist/utils/ai/index.cjs.map +1 -0
- package/dist/{index-CR8QpwX8.d.ts → utils/ai/index.d.cts} +73 -976
- package/dist/{index-UPSiS-X7.d.cts → utils/ai/index.d.ts} +73 -976
- package/dist/utils/ai/index.js +173 -0
- package/dist/utils/ai/index.js.map +1 -0
- package/dist/utils/ai/node.cjs +648 -0
- package/dist/utils/ai/node.cjs.map +1 -0
- package/dist/{patterns → utils}/ai/node.d.cts +5 -7
- package/dist/{patterns → utils}/ai/node.d.ts +5 -7
- package/dist/utils/ai/node.js +84 -0
- package/dist/utils/ai/node.js.map +1 -0
- package/dist/utils/cqrs/index.cjs +1036 -0
- package/dist/utils/cqrs/index.cjs.map +1 -0
- package/dist/{index-CeFiHtAg.d.ts → utils/cqrs/index.d.cts} +7 -37
- package/dist/{index-B-_tFaqV.d.cts → utils/cqrs/index.d.ts} +7 -37
- package/dist/utils/cqrs/index.js +18 -0
- package/dist/utils/cqrs/index.js.map +1 -0
- package/dist/utils/demo-shell/index.cjs +865 -0
- package/dist/utils/demo-shell/index.cjs.map +1 -0
- package/dist/{index-B8YnZpIR.d.ts → utils/demo-shell/index.d.cts} +4 -16
- package/dist/{index-Cwv0KWcU.d.cts → utils/demo-shell/index.d.ts} +4 -16
- package/dist/utils/demo-shell/index.js +13 -0
- package/dist/utils/demo-shell/index.js.map +1 -0
- package/dist/utils/domain-templates/index.cjs +732 -0
- package/dist/utils/domain-templates/index.cjs.map +1 -0
- package/dist/{index-CzLVrjxn.d.ts → utils/domain-templates/index.d.cts} +3 -20
- package/dist/{index-BaQaY_IQ.d.cts → utils/domain-templates/index.d.ts} +3 -20
- package/dist/utils/domain-templates/index.js +17 -0
- package/dist/utils/domain-templates/index.js.map +1 -0
- package/dist/utils/graphspec/index.cjs +1174 -0
- package/dist/utils/graphspec/index.cjs.map +1 -0
- package/dist/{index-CMh5Rz1y.d.ts → utils/graphspec/index.d.cts} +106 -42
- package/dist/{index-CS0LTlB8.d.cts → utils/graphspec/index.d.ts} +106 -42
- package/dist/utils/graphspec/index.js +35 -0
- package/dist/utils/graphspec/index.js.map +1 -0
- package/dist/utils/harness/index.cjs +656 -0
- package/dist/utils/harness/index.cjs.map +1 -0
- package/dist/utils/harness/index.d.cts +542 -0
- package/dist/utils/harness/index.d.ts +542 -0
- package/dist/utils/harness/index.js +56 -0
- package/dist/utils/harness/index.js.map +1 -0
- package/dist/utils/index.cjs +17609 -0
- package/dist/utils/index.cjs.map +1 -0
- package/dist/utils/index.d.cts +96 -0
- package/dist/utils/index.d.ts +96 -0
- package/dist/utils/index.js +514 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/inspect/index.cjs +807 -0
- package/dist/utils/inspect/index.cjs.map +1 -0
- package/dist/utils/inspect/index.d.cts +123 -0
- package/dist/utils/inspect/index.d.ts +123 -0
- package/dist/utils/inspect/index.js +30 -0
- package/dist/utils/inspect/index.js.map +1 -0
- package/dist/utils/job-queue/index.cjs +717 -0
- package/dist/utils/job-queue/index.cjs.map +1 -0
- package/dist/{index-DisjX8a-.d.ts → utils/job-queue/index.d.cts} +5 -26
- package/dist/{index-DV_1YuVk.d.cts → utils/job-queue/index.d.ts} +5 -26
- package/dist/utils/job-queue/index.js +18 -0
- package/dist/utils/job-queue/index.js.map +1 -0
- package/dist/utils/memory/index.cjs +1451 -0
- package/dist/utils/memory/index.cjs.map +1 -0
- package/dist/{index-CZ3r5Rxp.d.ts → utils/memory/index.d.cts} +242 -34
- package/dist/{index-B17QddL1.d.cts → utils/memory/index.d.ts} +242 -34
- package/dist/utils/memory/index.js +19 -0
- package/dist/utils/memory/index.js.map +1 -0
- package/dist/utils/messaging/index.cjs +666 -0
- package/dist/utils/messaging/index.cjs.map +1 -0
- package/dist/utils/messaging/index.d.cts +562 -0
- package/dist/utils/messaging/index.d.ts +562 -0
- package/dist/utils/messaging/index.js +50 -0
- package/dist/utils/messaging/index.js.map +1 -0
- package/dist/utils/orchestration/index.cjs +876 -0
- package/dist/utils/orchestration/index.cjs.map +1 -0
- package/dist/utils/orchestration/index.d.cts +233 -0
- package/dist/utils/orchestration/index.d.ts +233 -0
- package/dist/utils/orchestration/index.js +19 -0
- package/dist/utils/orchestration/index.js.map +1 -0
- package/dist/utils/process/index.cjs +743 -0
- package/dist/utils/process/index.cjs.map +1 -0
- package/dist/{index-p09KSrTN.d.ts → utils/process/index.d.cts} +97 -44
- package/dist/{index-CasX6Pfq.d.cts → utils/process/index.d.ts} +97 -44
- package/dist/utils/process/index.js +14 -0
- package/dist/utils/process/index.js.map +1 -0
- package/dist/utils/reactive-layout/index.cjs +1607 -0
- package/dist/utils/reactive-layout/index.cjs.map +1 -0
- package/dist/{index-B5S8ULbU.d.ts → utils/reactive-layout/index.d.cts} +58 -81
- package/dist/{index-Dc4AYqrJ.d.cts → utils/reactive-layout/index.d.ts} +58 -81
- package/dist/utils/reactive-layout/index.js +52 -0
- package/dist/utils/reactive-layout/index.js.map +1 -0
- package/dist/utils/reduction/index.cjs +203 -0
- package/dist/utils/reduction/index.cjs.map +1 -0
- package/dist/{index-Byu-OpX_.d.ts → utils/reduction/index.d.cts} +6 -17
- package/dist/{index-tRCxuAXF.d.cts → utils/reduction/index.d.ts} +6 -17
- package/dist/utils/reduction/index.js +14 -0
- package/dist/utils/reduction/index.js.map +1 -0
- package/dist/utils/resilience/index.cjs +1617 -0
- package/dist/utils/resilience/index.cjs.map +1 -0
- package/dist/utils/resilience/index.d.cts +9 -0
- package/dist/utils/resilience/index.d.ts +9 -0
- package/dist/utils/resilience/index.js +44 -0
- package/dist/utils/resilience/index.js.map +1 -0
- package/dist/utils/surface/index.cjs +1070 -0
- package/dist/utils/surface/index.cjs.map +1 -0
- package/dist/{index-CYq8vAyV.d.ts → utils/surface/index.d.cts} +7 -58
- package/dist/{index-CSOmP7xT.d.cts → utils/surface/index.d.ts} +7 -58
- package/dist/utils/surface/index.js +30 -0
- package/dist/utils/surface/index.js.map +1 -0
- package/dist/utils/topology-view/index.cjs +620 -0
- package/dist/utils/topology-view/index.cjs.map +1 -0
- package/dist/utils/topology-view/index.d.cts +68 -0
- package/dist/utils/topology-view/index.d.ts +68 -0
- package/dist/utils/topology-view/index.js +11 -0
- package/dist/utils/topology-view/index.js.map +1 -0
- package/package.json +664 -584
- package/dist/backoff-HPZMEZNF.js +0 -1
- package/dist/chunk-2T7U5EU6.js +0 -1
- package/dist/chunk-3G5U5QNE.js +0 -5
- package/dist/chunk-4VVTGLXJ.js +0 -1
- package/dist/chunk-5M4CCMMD.js +0 -45
- package/dist/chunk-5QDBSZBV.js +0 -1
- package/dist/chunk-5XJ6B66J.js +0 -1
- package/dist/chunk-6QZNQS5B.js +0 -1
- package/dist/chunk-6X7AFUJV.js +0 -9
- package/dist/chunk-7K6PWTDQ.js +0 -1
- package/dist/chunk-7LIAPXJB.js +0 -1
- package/dist/chunk-7WPU3UHQ.js +0 -1
- package/dist/chunk-A5WCQ5NO.js +0 -1
- package/dist/chunk-APPIWSGD.js +0 -84
- package/dist/chunk-BEZWM2SY.js +0 -1
- package/dist/chunk-C72GO4IZ.js +0 -1
- package/dist/chunk-CB676TKJ.js +0 -1
- package/dist/chunk-CE6TI2TL.js +0 -1
- package/dist/chunk-CE72X3WO.js +0 -1
- package/dist/chunk-CK2E7BTU.js +0 -1
- package/dist/chunk-CLVB32RD.js +0 -1
- package/dist/chunk-CRVT7D2P.js +0 -1
- package/dist/chunk-D5RFJOZ2.js +0 -1
- package/dist/chunk-D7GPHKFH.js +0 -1
- package/dist/chunk-DHRX7JX4.js +0 -2
- package/dist/chunk-ESMPEKEV.js +0 -1
- package/dist/chunk-F672GV32.js +0 -1
- package/dist/chunk-FZMYDOWV.js +0 -1
- package/dist/chunk-GHBWHMRZ.js +0 -1
- package/dist/chunk-GLERH466.js +0 -1
- package/dist/chunk-GPW2V3RE.js +0 -1
- package/dist/chunk-HIDYF36O.js +0 -1
- package/dist/chunk-HITNVN6B.js +0 -3
- package/dist/chunk-HY4DJBA7.js +0 -5
- package/dist/chunk-KZIEYVXN.js +0 -1
- package/dist/chunk-L6NSJVJZ.js +0 -1
- package/dist/chunk-N4MQX6JU.js +0 -18
- package/dist/chunk-N7FHEL4D.js +0 -1
- package/dist/chunk-NTEURFZH.js +0 -1
- package/dist/chunk-OIVP6KFV.js +0 -1
- package/dist/chunk-OPHBU3LG.js +0 -1
- package/dist/chunk-OYQOZP2F.js +0 -5
- package/dist/chunk-PTZK576G.js +0 -1
- package/dist/chunk-QYADASLV.js +0 -1
- package/dist/chunk-ST7UXLWR.js +0 -1
- package/dist/chunk-SVY7VUYU.js +0 -1
- package/dist/chunk-TK3NWWD4.js +0 -1
- package/dist/chunk-TSOYJ743.js +0 -1
- package/dist/chunk-UNGSTR4X.js +0 -61
- package/dist/chunk-VIMF6LGM.js +0 -1
- package/dist/chunk-VJLMUKOI.js +0 -1
- package/dist/chunk-VN6RDSK2.js +0 -1
- package/dist/chunk-VV4N5P64.js +0 -1
- package/dist/chunk-W3I423PS.js +0 -1
- package/dist/chunk-WJR24TAG.js +0 -1
- package/dist/chunk-XTGKMHSW.js +0 -1
- package/dist/chunk-YBB7ZGTY.js +0 -1
- package/dist/chunk-Z4NPUARF.js +0 -1
- package/dist/chunk-ZGNQRPDT.js +0 -1
- package/dist/chunk-ZKPSFFKU.js +0 -1
- package/dist/chunk-ZLV5SQSX.js +0 -1
- package/dist/content-addressed-storage-4-ST1tYk.d.cts +0 -124
- package/dist/content-addressed-storage-DuYMjV7o.d.ts +0 -124
- package/dist/core/index.cjs +0 -1
- package/dist/core/index.d.cts +0 -3
- package/dist/core/index.d.ts +0 -3
- package/dist/core/index.js +0 -1
- package/dist/decay-BvOWTZ00.d.ts +0 -112
- package/dist/decay-CFlLvXUT.d.cts +0 -112
- package/dist/extra/browser.cjs +0 -1
- package/dist/extra/browser.d.cts +0 -4
- package/dist/extra/browser.d.ts +0 -4
- package/dist/extra/browser.js +0 -1
- package/dist/extra/index.cjs +0 -20
- package/dist/extra/index.d.cts +0 -17
- package/dist/extra/index.d.ts +0 -17
- package/dist/extra/index.js +0 -1
- package/dist/extra/node.cjs +0 -2
- package/dist/extra/node.js +0 -2
- package/dist/extra/operators.cjs +0 -1
- package/dist/extra/operators.d.cts +0 -958
- package/dist/extra/operators.d.ts +0 -958
- package/dist/extra/operators.js +0 -1
- package/dist/extra/reactive.cjs +0 -1
- package/dist/extra/reactive.d.cts +0 -353
- package/dist/extra/reactive.d.ts +0 -353
- package/dist/extra/reactive.js +0 -1
- package/dist/extra/render/index.cjs +0 -5
- package/dist/extra/render/index.js +0 -1
- package/dist/extra/sources.cjs +0 -3
- package/dist/extra/sources.js +0 -1
- package/dist/extra/storage-browser.cjs +0 -1
- package/dist/extra/storage-browser.d.cts +0 -37
- package/dist/extra/storage-browser.d.ts +0 -37
- package/dist/extra/storage-browser.js +0 -1
- package/dist/extra/storage-core.cjs +0 -1
- package/dist/extra/storage-core.d.cts +0 -28
- package/dist/extra/storage-core.d.ts +0 -28
- package/dist/extra/storage-core.js +0 -1
- package/dist/extra/storage-node.cjs +0 -1
- package/dist/extra/storage-node.d.cts +0 -2
- package/dist/extra/storage-node.d.ts +0 -2
- package/dist/extra/storage-node.js +0 -0
- package/dist/extra/storage-tiers-browser.cjs +0 -1
- package/dist/extra/storage-tiers-browser.d.cts +0 -120
- package/dist/extra/storage-tiers-browser.d.ts +0 -120
- package/dist/extra/storage-tiers-browser.js +0 -1
- package/dist/extra/storage-tiers-node.cjs +0 -1
- package/dist/extra/storage-tiers-node.d.cts +0 -210
- package/dist/extra/storage-tiers-node.d.ts +0 -210
- package/dist/extra/storage-tiers-node.js +0 -1
- package/dist/extra/storage-tiers.cjs +0 -1
- package/dist/extra/storage-tiers.d.cts +0 -412
- package/dist/extra/storage-tiers.d.ts +0 -412
- package/dist/extra/storage-tiers.js +0 -1
- package/dist/graph/index.cjs +0 -7
- package/dist/graph/index.d.cts +0 -7
- package/dist/graph/index.d.ts +0 -7
- package/dist/graph/index.js +0 -1
- package/dist/graph-CWvEUQAq.d.cts +0 -1861
- package/dist/graph-D9LFnda9.d.ts +0 -1861
- package/dist/index-5k1T6jl0.d.cts +0 -121
- package/dist/index-9770hRuQ.d.cts +0 -779
- package/dist/index-B1F8Enjf.d.ts +0 -704
- package/dist/index-BHskSB8v.d.ts +0 -3413
- package/dist/index-BIYAkbAi.d.cts +0 -26
- package/dist/index-BoJ5JHxI.d.ts +0 -557
- package/dist/index-BocU7pqs.d.ts +0 -779
- package/dist/index-BxNs2HB9.d.cts +0 -1858
- package/dist/index-C1T3d7V-.d.cts +0 -704
- package/dist/index-C5ri2Axc.d.cts +0 -301
- package/dist/index-C9l6OEBL.d.ts +0 -26
- package/dist/index-CC-AvFTy.d.cts +0 -557
- package/dist/index-CJF1URuX.d.ts +0 -121
- package/dist/index-CdTelp1M.d.ts +0 -202
- package/dist/index-Cj3WohTd.d.cts +0 -202
- package/dist/index-Co7uli2l.d.cts +0 -3413
- package/dist/index-D0aciIex.d.cts +0 -209
- package/dist/index-DHen9Klo.d.ts +0 -1858
- package/dist/index-Yq60JP3s.d.ts +0 -209
- package/dist/index-nozs3fFC.d.ts +0 -301
- package/dist/node-kK3CvTrR.d.cts +0 -1347
- package/dist/node-kK3CvTrR.d.ts +0 -1347
- package/dist/patterns/ai/browser.cjs +0 -8
- package/dist/patterns/ai/browser.js +0 -3
- package/dist/patterns/ai/index.cjs +0 -74
- package/dist/patterns/ai/index.d.cts +0 -20
- package/dist/patterns/ai/index.d.ts +0 -20
- package/dist/patterns/ai/index.js +0 -1
- package/dist/patterns/ai/node.cjs +0 -1
- package/dist/patterns/ai/node.js +0 -1
- package/dist/patterns/cqrs/index.cjs +0 -3
- package/dist/patterns/cqrs/index.d.cts +0 -8
- package/dist/patterns/cqrs/index.d.ts +0 -8
- package/dist/patterns/cqrs/index.js +0 -1
- package/dist/patterns/demo-shell/index.cjs +0 -5
- package/dist/patterns/demo-shell/index.d.cts +0 -7
- package/dist/patterns/demo-shell/index.d.ts +0 -7
- package/dist/patterns/demo-shell/index.js +0 -1
- package/dist/patterns/domain-templates/index.cjs +0 -3
- package/dist/patterns/domain-templates/index.d.cts +0 -6
- package/dist/patterns/domain-templates/index.d.ts +0 -6
- package/dist/patterns/domain-templates/index.js +0 -1
- package/dist/patterns/graphspec/index.cjs +0 -86
- package/dist/patterns/graphspec/index.d.cts +0 -8
- package/dist/patterns/graphspec/index.d.ts +0 -8
- package/dist/patterns/graphspec/index.js +0 -1
- package/dist/patterns/harness/index.cjs +0 -48
- package/dist/patterns/harness/index.d.cts +0 -13
- package/dist/patterns/harness/index.d.ts +0 -13
- package/dist/patterns/harness/index.js +0 -1
- package/dist/patterns/inspect/index.cjs +0 -3
- package/dist/patterns/inspect/index.d.cts +0 -9
- package/dist/patterns/inspect/index.d.ts +0 -9
- package/dist/patterns/inspect/index.js +0 -1
- package/dist/patterns/job-queue/index.cjs +0 -3
- package/dist/patterns/job-queue/index.d.cts +0 -9
- package/dist/patterns/job-queue/index.d.ts +0 -9
- package/dist/patterns/job-queue/index.js +0 -1
- package/dist/patterns/memory/index.cjs +0 -3
- package/dist/patterns/memory/index.d.cts +0 -8
- package/dist/patterns/memory/index.d.ts +0 -8
- package/dist/patterns/memory/index.js +0 -1
- package/dist/patterns/messaging/index.cjs +0 -3
- package/dist/patterns/messaging/index.d.cts +0 -7
- package/dist/patterns/messaging/index.d.ts +0 -7
- package/dist/patterns/messaging/index.js +0 -1
- package/dist/patterns/orchestration/index.cjs +0 -3
- package/dist/patterns/orchestration/index.d.cts +0 -8
- package/dist/patterns/orchestration/index.d.ts +0 -8
- package/dist/patterns/orchestration/index.js +0 -1
- package/dist/patterns/process/index.cjs +0 -3
- package/dist/patterns/process/index.d.cts +0 -10
- package/dist/patterns/process/index.d.ts +0 -10
- package/dist/patterns/process/index.js +0 -1
- package/dist/patterns/reactive-layout/index.cjs +0 -4
- package/dist/patterns/reactive-layout/index.d.cts +0 -7
- package/dist/patterns/reactive-layout/index.d.ts +0 -7
- package/dist/patterns/reactive-layout/index.js +0 -1
- package/dist/patterns/reduction/index.cjs +0 -3
- package/dist/patterns/reduction/index.d.cts +0 -6
- package/dist/patterns/reduction/index.d.ts +0 -6
- package/dist/patterns/reduction/index.js +0 -1
- package/dist/patterns/surface/index.cjs +0 -13
- package/dist/patterns/surface/index.d.cts +0 -9
- package/dist/patterns/surface/index.d.ts +0 -9
- package/dist/patterns/surface/index.js +0 -1
- package/dist/reactive-log-BKALbfal.d.ts +0 -223
- package/dist/reactive-log-DIGdYqQ6.d.cts +0 -223
- package/dist/reactive-map-CEFGp8TK.d.cts +0 -296
- package/dist/reactive-map-DS_SIAxv.d.ts +0 -296
- package/dist/resilience-6LYQJAC5.js +0 -1
- package/dist/sugar-DQjFmVqb.d.cts +0 -399
- package/dist/sugar-fhLIE7TT.d.ts +0 -399
- package/dist/topology-tree-Bcz27hpF.d.cts +0 -25
- package/dist/topology-tree-xvaD0fOX.d.ts +0 -25
|
@@ -0,0 +1,4377 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __esm = (fn, res) => function __init() {
|
|
7
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
8
|
+
};
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
22
|
+
|
|
23
|
+
// src/base/resilience/_internal.ts
|
|
24
|
+
function operatorOpts(opts) {
|
|
25
|
+
return { describeKind: "derived", ...opts };
|
|
26
|
+
}
|
|
27
|
+
function msgVal(m) {
|
|
28
|
+
return m[1];
|
|
29
|
+
}
|
|
30
|
+
function coerceDelayNs(raw) {
|
|
31
|
+
if (typeof raw !== "number" || !Number.isFinite(raw)) {
|
|
32
|
+
throw new TypeError("backoff strategy must return a finite number");
|
|
33
|
+
}
|
|
34
|
+
return raw < 0 ? 0 : raw;
|
|
35
|
+
}
|
|
36
|
+
function isNode(x) {
|
|
37
|
+
return x != null && typeof x === "object" && "cache" in x && typeof x.subscribe === "function";
|
|
38
|
+
}
|
|
39
|
+
var import_core4;
|
|
40
|
+
var init_internal = __esm({
|
|
41
|
+
"src/base/resilience/_internal.ts"() {
|
|
42
|
+
"use strict";
|
|
43
|
+
import_core4 = require("@graphrefly/pure-ts/core");
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// src/base/resilience/backoff.ts
|
|
48
|
+
var backoff_exports = {};
|
|
49
|
+
__export(backoff_exports, {
|
|
50
|
+
NS_PER_MS: () => NS_PER_MS,
|
|
51
|
+
NS_PER_SEC: () => NS_PER_SEC,
|
|
52
|
+
constant: () => constant,
|
|
53
|
+
decorrelatedJitter: () => decorrelatedJitter,
|
|
54
|
+
exponential: () => exponential,
|
|
55
|
+
fibonacci: () => fibonacci,
|
|
56
|
+
linear: () => linear,
|
|
57
|
+
resolveBackoffPreset: () => resolveBackoffPreset,
|
|
58
|
+
withMaxAttempts: () => withMaxAttempts
|
|
59
|
+
});
|
|
60
|
+
function clampNonNegative(value) {
|
|
61
|
+
return value < 0 ? 0 : value;
|
|
62
|
+
}
|
|
63
|
+
function applyJitter(delay, jitter) {
|
|
64
|
+
if (jitter === "none") return delay;
|
|
65
|
+
if (jitter === "full") return Math.random() * delay;
|
|
66
|
+
return delay / 2 + Math.random() * (delay / 2);
|
|
67
|
+
}
|
|
68
|
+
function randomBetween(min, max) {
|
|
69
|
+
return min + Math.random() * (max - min);
|
|
70
|
+
}
|
|
71
|
+
function constant(delayNs) {
|
|
72
|
+
const safe = clampNonNegative(delayNs);
|
|
73
|
+
return () => safe;
|
|
74
|
+
}
|
|
75
|
+
function linear(baseNs, stepNs) {
|
|
76
|
+
const safeBase = clampNonNegative(baseNs);
|
|
77
|
+
const safeStep = stepNs === void 0 ? safeBase : clampNonNegative(stepNs);
|
|
78
|
+
return (attempt) => safeBase + safeStep * Math.max(0, attempt);
|
|
79
|
+
}
|
|
80
|
+
function exponential(options) {
|
|
81
|
+
const baseNs = clampNonNegative(options?.baseNs ?? 100 * NS_PER_MS);
|
|
82
|
+
const factor = options?.factor !== void 0 && options.factor < 1 ? 1 : options?.factor ?? 2;
|
|
83
|
+
const maxDelayNs = clampNonNegative(options?.maxDelayNs ?? 30 * NS_PER_SEC);
|
|
84
|
+
const jitter = options?.jitter ?? "none";
|
|
85
|
+
return (attempt) => {
|
|
86
|
+
let delay;
|
|
87
|
+
if (baseNs === 0) {
|
|
88
|
+
delay = 0;
|
|
89
|
+
} else if (factor === 1) {
|
|
90
|
+
delay = baseNs;
|
|
91
|
+
} else {
|
|
92
|
+
const capRatio = maxDelayNs / baseNs;
|
|
93
|
+
let growth = 1;
|
|
94
|
+
for (let i = 0; i < Math.max(0, attempt); i++) {
|
|
95
|
+
if (growth >= capRatio) {
|
|
96
|
+
growth = capRatio;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
growth *= factor;
|
|
100
|
+
}
|
|
101
|
+
delay = baseNs * growth;
|
|
102
|
+
if (delay > maxDelayNs) delay = maxDelayNs;
|
|
103
|
+
}
|
|
104
|
+
return applyJitter(delay, jitter);
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function fibonacci(baseNs = 100 * NS_PER_MS, maxDelayNs = 30 * NS_PER_SEC) {
|
|
108
|
+
const safeBase = clampNonNegative(baseNs);
|
|
109
|
+
const safeMax = clampNonNegative(maxDelayNs);
|
|
110
|
+
function fibUnit(attempt) {
|
|
111
|
+
if (attempt <= 0) return 1;
|
|
112
|
+
let prev = 1;
|
|
113
|
+
let cur = 2;
|
|
114
|
+
for (let i = 1; i < attempt; i++) {
|
|
115
|
+
const next = prev + cur;
|
|
116
|
+
prev = cur;
|
|
117
|
+
cur = next;
|
|
118
|
+
}
|
|
119
|
+
return cur;
|
|
120
|
+
}
|
|
121
|
+
return (attempt) => {
|
|
122
|
+
const raw = fibUnit(attempt) * safeBase;
|
|
123
|
+
return raw <= safeMax ? raw : safeMax;
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function decorrelatedJitter(baseNs = 100 * NS_PER_MS, maxNs = 30 * NS_PER_SEC) {
|
|
127
|
+
return (_attempt, _error, prevDelayNs) => {
|
|
128
|
+
const last = prevDelayNs ?? baseNs;
|
|
129
|
+
const ceiling = Math.min(maxNs, last * 3);
|
|
130
|
+
return randomBetween(baseNs, ceiling);
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function withMaxAttempts(strategy, maxAttempts) {
|
|
134
|
+
return (attempt, error, prevDelayNs) => {
|
|
135
|
+
if (attempt >= maxAttempts) return null;
|
|
136
|
+
return strategy(attempt, error, prevDelayNs);
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function resolveBackoffPreset(name) {
|
|
140
|
+
if (name === "constant") return constant(1 * NS_PER_SEC);
|
|
141
|
+
if (name === "linear") return linear(1 * NS_PER_SEC);
|
|
142
|
+
if (name === "exponential") return exponential();
|
|
143
|
+
if (name === "fibonacci") return fibonacci();
|
|
144
|
+
if (name === "decorrelatedJitter") return decorrelatedJitter();
|
|
145
|
+
throw new Error(
|
|
146
|
+
`Unknown backoff preset: "${String(name)}". Use one of: constant, linear, exponential, fibonacci, decorrelatedJitter`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
var NS_PER_MS, NS_PER_SEC;
|
|
150
|
+
var init_backoff = __esm({
|
|
151
|
+
"src/base/resilience/backoff.ts"() {
|
|
152
|
+
"use strict";
|
|
153
|
+
NS_PER_MS = 1e6;
|
|
154
|
+
NS_PER_SEC = 1e9;
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// src/base/resilience/timeout.ts
|
|
159
|
+
var timeout_exports = {};
|
|
160
|
+
__export(timeout_exports, {
|
|
161
|
+
TimeoutError: () => TimeoutError,
|
|
162
|
+
withTimeout: () => withTimeout
|
|
163
|
+
});
|
|
164
|
+
function withTimeout(source, opts, extraOpts) {
|
|
165
|
+
const isReactive = isNode(opts);
|
|
166
|
+
let latestOpts = null;
|
|
167
|
+
if (!isReactive) {
|
|
168
|
+
const staticOpts = opts;
|
|
169
|
+
if (staticOpts.ns === void 0 || typeof staticOpts.ns !== "number" || !Number.isFinite(staticOpts.ns) || staticOpts.ns <= 0) {
|
|
170
|
+
throw new RangeError("withTimeout: opts.ns must be a positive finite number");
|
|
171
|
+
}
|
|
172
|
+
latestOpts = {
|
|
173
|
+
ns: staticOpts.ns,
|
|
174
|
+
...staticOpts.meta != null ? { meta: staticOpts.meta } : {}
|
|
175
|
+
};
|
|
176
|
+
} else {
|
|
177
|
+
const cached = opts.cache;
|
|
178
|
+
if (cached !== void 0) {
|
|
179
|
+
if (cached.ns === void 0 || typeof cached.ns !== "number" || !Number.isFinite(cached.ns) || cached.ns <= 0) {
|
|
180
|
+
throw new RangeError(
|
|
181
|
+
"withTimeout: opts.ns must be a positive finite number on first settle"
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
latestOpts = {
|
|
185
|
+
ns: cached.ns,
|
|
186
|
+
...cached.meta != null ? { meta: cached.meta } : {}
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const callerMeta = extraOpts?.meta;
|
|
191
|
+
const factoryArgs = isReactive ? { ns: "Node<Partial<TimeoutOptions>>" } : { ns: latestOpts.ns };
|
|
192
|
+
const timeoutState = (0, import_core5.node)([], {
|
|
193
|
+
name: "timeoutState",
|
|
194
|
+
describeKind: "state",
|
|
195
|
+
initial: { status: "pending" },
|
|
196
|
+
equals: (a, b) => a === b || a != null && b != null && typeof a === "object" && typeof b === "object" && a.status === b.status && JSON.stringify(a) === JSON.stringify(b)
|
|
197
|
+
});
|
|
198
|
+
const out = (0, import_core5.node)(
|
|
199
|
+
(_data, a) => {
|
|
200
|
+
let stopped = false;
|
|
201
|
+
let lastDeadlineNs = 0;
|
|
202
|
+
const timer = new import_core5.ResettableTimer();
|
|
203
|
+
let optsUnsub = null;
|
|
204
|
+
let srcUnsub = null;
|
|
205
|
+
function emitState(next) {
|
|
206
|
+
timeoutState.down([[import_core5.DIRTY], [import_core5.DATA, next]]);
|
|
207
|
+
}
|
|
208
|
+
function startTimer() {
|
|
209
|
+
if (stopped) return;
|
|
210
|
+
if (latestOpts == null || typeof latestOpts.ns !== "number" || !Number.isFinite(latestOpts.ns) || latestOpts.ns <= 0) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const ns = latestOpts.ns;
|
|
214
|
+
lastDeadlineNs = ns;
|
|
215
|
+
const startedAt = (0, import_core5.monotonicNs)();
|
|
216
|
+
const delayMs = ns / NS_PER_MS;
|
|
217
|
+
emitState({
|
|
218
|
+
status: "running",
|
|
219
|
+
startedAt_ns: startedAt,
|
|
220
|
+
deadline_ns: ns
|
|
221
|
+
});
|
|
222
|
+
timer.start(delayMs, () => {
|
|
223
|
+
if (stopped) return;
|
|
224
|
+
stopped = true;
|
|
225
|
+
srcUnsub?.();
|
|
226
|
+
emitState({
|
|
227
|
+
status: "errored",
|
|
228
|
+
firedAt_ns: (0, import_core5.monotonicNs)(),
|
|
229
|
+
deadline_ns: ns
|
|
230
|
+
});
|
|
231
|
+
a.down([[import_core5.ERROR, new TimeoutError(ns)]]);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
function attachSource() {
|
|
235
|
+
if (srcUnsub != null || stopped) return;
|
|
236
|
+
srcUnsub = source.subscribe((msgs) => {
|
|
237
|
+
for (const m of msgs) {
|
|
238
|
+
if (stopped) return;
|
|
239
|
+
const t = m[0];
|
|
240
|
+
if (t === import_core5.DIRTY) a.down([[import_core5.DIRTY]]);
|
|
241
|
+
else if (t === import_core5.DATA) {
|
|
242
|
+
startTimer();
|
|
243
|
+
a.emit(m[1]);
|
|
244
|
+
} else if (t === import_core5.RESOLVED) a.down([[import_core5.RESOLVED]]);
|
|
245
|
+
else if (t === import_core5.COMPLETE) {
|
|
246
|
+
timer.cancel();
|
|
247
|
+
stopped = true;
|
|
248
|
+
emitState({
|
|
249
|
+
status: "completed",
|
|
250
|
+
settledAt_ns: (0, import_core5.monotonicNs)()
|
|
251
|
+
});
|
|
252
|
+
a.down([[import_core5.COMPLETE]]);
|
|
253
|
+
return;
|
|
254
|
+
} else if (t === import_core5.ERROR) {
|
|
255
|
+
timer.cancel();
|
|
256
|
+
stopped = true;
|
|
257
|
+
emitState({
|
|
258
|
+
status: "errored",
|
|
259
|
+
firedAt_ns: (0, import_core5.monotonicNs)(),
|
|
260
|
+
deadline_ns: lastDeadlineNs
|
|
261
|
+
});
|
|
262
|
+
a.down([m]);
|
|
263
|
+
return;
|
|
264
|
+
} else if (t === import_core5.TEARDOWN) {
|
|
265
|
+
timer.cancel();
|
|
266
|
+
stopped = true;
|
|
267
|
+
a.down([m]);
|
|
268
|
+
return;
|
|
269
|
+
} else a.down([m]);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
if (latestOpts != null && latestOpts.ns > 0) {
|
|
273
|
+
startTimer();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (isReactive) {
|
|
277
|
+
const optsNode = opts;
|
|
278
|
+
optsUnsub = optsNode.subscribe((msgs) => {
|
|
279
|
+
for (const m of msgs) {
|
|
280
|
+
if (m[0] !== import_core5.DATA) continue;
|
|
281
|
+
const next = m[1];
|
|
282
|
+
if (next == null || typeof next !== "object") continue;
|
|
283
|
+
const keys = Object.keys(next);
|
|
284
|
+
if (keys.length === 0) continue;
|
|
285
|
+
if ("ns" in next) {
|
|
286
|
+
if (typeof next.ns !== "number" || !Number.isFinite(next.ns) || next.ns <= 0) {
|
|
287
|
+
if (latestOpts == null) {
|
|
288
|
+
stopped = true;
|
|
289
|
+
a.down([
|
|
290
|
+
[
|
|
291
|
+
import_core5.ERROR,
|
|
292
|
+
new RangeError(
|
|
293
|
+
"withTimeout: opts.ns must be a positive finite number on first settle"
|
|
294
|
+
)
|
|
295
|
+
]
|
|
296
|
+
]);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
const wasNull = latestOpts == null;
|
|
303
|
+
latestOpts = {
|
|
304
|
+
...latestOpts ?? { ns: 0 },
|
|
305
|
+
...next
|
|
306
|
+
};
|
|
307
|
+
if (wasNull && latestOpts.ns > 0) {
|
|
308
|
+
attachSource();
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
if (latestOpts != null) {
|
|
314
|
+
attachSource();
|
|
315
|
+
}
|
|
316
|
+
return () => {
|
|
317
|
+
stopped = true;
|
|
318
|
+
timer.cancel();
|
|
319
|
+
if (srcUnsub) srcUnsub();
|
|
320
|
+
if (optsUnsub) optsUnsub();
|
|
321
|
+
};
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
...operatorOpts(),
|
|
325
|
+
initial: source.cache,
|
|
326
|
+
meta: { ...callerMeta ?? {}, ...(0, import_core5.factoryTag)("withTimeout", factoryArgs) }
|
|
327
|
+
}
|
|
328
|
+
);
|
|
329
|
+
return { node: out, timeoutState };
|
|
330
|
+
}
|
|
331
|
+
var import_core5, TimeoutError;
|
|
332
|
+
var init_timeout = __esm({
|
|
333
|
+
"src/base/resilience/timeout.ts"() {
|
|
334
|
+
"use strict";
|
|
335
|
+
import_core5 = require("@graphrefly/pure-ts/core");
|
|
336
|
+
init_internal();
|
|
337
|
+
init_backoff();
|
|
338
|
+
TimeoutError = class extends Error {
|
|
339
|
+
name = "TimeoutError";
|
|
340
|
+
constructor(ns) {
|
|
341
|
+
super(`Timed out after ${ns / NS_PER_MS}ms`);
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// src/presets/ai/index.ts
|
|
348
|
+
var ai_exports = {};
|
|
349
|
+
__export(ai_exports, {
|
|
350
|
+
AgentGraph: () => AgentGraph,
|
|
351
|
+
AgentLoopGraph: () => AgentLoopGraph,
|
|
352
|
+
AgentMemoryGraph: () => AgentMemoryGraph,
|
|
353
|
+
CompressionCache: () => CompressionCache,
|
|
354
|
+
DebateGraph: () => DebateGraph,
|
|
355
|
+
ZERO_COST: () => ZERO_COST,
|
|
356
|
+
addUsage: () => addUsage,
|
|
357
|
+
agent: () => agent,
|
|
358
|
+
agentLoop: () => agentLoop,
|
|
359
|
+
agentMemory: () => agentMemory,
|
|
360
|
+
heterogeneousDebate: () => heterogeneousDebate,
|
|
361
|
+
presetRegistry: () => presetRegistry,
|
|
362
|
+
renderContextView: () => renderContextView,
|
|
363
|
+
taggedContextPool: () => taggedContextPool,
|
|
364
|
+
tierCompress: () => tierCompress
|
|
365
|
+
});
|
|
366
|
+
module.exports = __toCommonJS(ai_exports);
|
|
367
|
+
|
|
368
|
+
// src/presets/ai/agent.ts
|
|
369
|
+
var import_core12 = require("@graphrefly/pure-ts/core");
|
|
370
|
+
var import_extra8 = require("@graphrefly/pure-ts/extra");
|
|
371
|
+
var import_graph6 = require("@graphrefly/pure-ts/graph");
|
|
372
|
+
|
|
373
|
+
// src/utils/ai/_internal.ts
|
|
374
|
+
var import_core = require("@graphrefly/pure-ts/core");
|
|
375
|
+
var import_extra = require("@graphrefly/pure-ts/extra");
|
|
376
|
+
|
|
377
|
+
// src/base/meta/domain-meta.ts
|
|
378
|
+
function domainMeta(domain, kind, extra) {
|
|
379
|
+
return {
|
|
380
|
+
[domain]: true,
|
|
381
|
+
[`${domain}_type`]: kind,
|
|
382
|
+
...extra ?? {}
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// src/utils/ai/_internal.ts
|
|
387
|
+
function aiMeta(kind, extra) {
|
|
388
|
+
return domainMeta("ai", kind, extra);
|
|
389
|
+
}
|
|
390
|
+
function isNodeLike(x) {
|
|
391
|
+
return typeof x === "object" && x !== null && "subscribe" in x && typeof x.subscribe === "function" && "cache" in x;
|
|
392
|
+
}
|
|
393
|
+
function stripFences(text) {
|
|
394
|
+
const match = text.match(/^```(?:json)?\s*([\s\S]*?)\s*```[\s\S]*$/);
|
|
395
|
+
return match ? match[1] : text;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// src/utils/messaging/index.ts
|
|
399
|
+
var import_core3 = require("@graphrefly/pure-ts/core");
|
|
400
|
+
var import_extra3 = require("@graphrefly/pure-ts/extra");
|
|
401
|
+
var import_graph2 = require("@graphrefly/pure-ts/graph");
|
|
402
|
+
|
|
403
|
+
// src/base/mutation/index.ts
|
|
404
|
+
var import_core2 = require("@graphrefly/pure-ts/core");
|
|
405
|
+
var import_extra2 = require("@graphrefly/pure-ts/extra");
|
|
406
|
+
var import_graph = require("@graphrefly/pure-ts/graph");
|
|
407
|
+
var DEFAULT_AUDIT_GUARD = (0, import_core2.policy)((allow, deny) => {
|
|
408
|
+
allow("observe");
|
|
409
|
+
allow("signal");
|
|
410
|
+
deny("write");
|
|
411
|
+
});
|
|
412
|
+
function createAuditLog(opts) {
|
|
413
|
+
const log = (0, import_extra2.reactiveLog)([], {
|
|
414
|
+
name: opts.name,
|
|
415
|
+
maxSize: opts.retainedLimit ?? 1024,
|
|
416
|
+
guard: opts.guard ?? DEFAULT_AUDIT_GUARD,
|
|
417
|
+
...opts.versioning != null ? { versioning: opts.versioning } : {}
|
|
418
|
+
});
|
|
419
|
+
log.withLatest();
|
|
420
|
+
if (opts.graph) {
|
|
421
|
+
opts.graph.add(log.entries, { name: opts.name });
|
|
422
|
+
}
|
|
423
|
+
return log;
|
|
424
|
+
}
|
|
425
|
+
function deepFreeze(value) {
|
|
426
|
+
if (value === null || typeof value !== "object" || Object.isFrozen(value)) return value;
|
|
427
|
+
for (const k of Object.keys(value)) {
|
|
428
|
+
deepFreeze(value[k]);
|
|
429
|
+
}
|
|
430
|
+
return Object.freeze(value);
|
|
431
|
+
}
|
|
432
|
+
function mutate(act, opts) {
|
|
433
|
+
const { up, down } = typeof act === "function" ? { up: act, down: void 0 } : act;
|
|
434
|
+
const freeze = opts.freeze ?? true;
|
|
435
|
+
if (opts.frame === "inline") {
|
|
436
|
+
return function wrapped(...args) {
|
|
437
|
+
const sealed = freeze ? args.map(deepFreeze) : args;
|
|
438
|
+
const t_ns = (0, import_core2.wallClockNs)();
|
|
439
|
+
const seq = opts.seq ? bumpCursor(opts.seq) : void 0;
|
|
440
|
+
try {
|
|
441
|
+
const result = up(...sealed);
|
|
442
|
+
if (opts.log && opts.onSuccessRecord) {
|
|
443
|
+
appendAudit(
|
|
444
|
+
opts.log,
|
|
445
|
+
opts.onSuccessRecord,
|
|
446
|
+
sealed,
|
|
447
|
+
result,
|
|
448
|
+
{ t_ns, seq },
|
|
449
|
+
opts.handlerVersion
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
return result;
|
|
453
|
+
} catch (err) {
|
|
454
|
+
if (opts.log && opts.onFailureRecord) {
|
|
455
|
+
const errorType = err instanceof Error ? err.name : typeof err;
|
|
456
|
+
appendAudit(
|
|
457
|
+
opts.log,
|
|
458
|
+
opts.onFailureRecord,
|
|
459
|
+
sealed,
|
|
460
|
+
err,
|
|
461
|
+
{ t_ns, seq, errorType },
|
|
462
|
+
opts.handlerVersion
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
throw err;
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
return function wrapped(...args) {
|
|
470
|
+
const sealed = freeze ? args.map(deepFreeze) : args;
|
|
471
|
+
const t_ns = (0, import_core2.wallClockNs)();
|
|
472
|
+
let result;
|
|
473
|
+
let captured;
|
|
474
|
+
let captureSet = false;
|
|
475
|
+
let seq;
|
|
476
|
+
try {
|
|
477
|
+
(0, import_core2.batch)(() => {
|
|
478
|
+
if (opts.seq) seq = bumpCursor(opts.seq);
|
|
479
|
+
try {
|
|
480
|
+
result = up(...sealed);
|
|
481
|
+
if (opts.log && opts.onSuccessRecord) {
|
|
482
|
+
appendAudit(
|
|
483
|
+
opts.log,
|
|
484
|
+
opts.onSuccessRecord,
|
|
485
|
+
sealed,
|
|
486
|
+
result,
|
|
487
|
+
{ t_ns, seq },
|
|
488
|
+
opts.handlerVersion
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
} catch (err) {
|
|
492
|
+
captured = err;
|
|
493
|
+
captureSet = true;
|
|
494
|
+
throw err;
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
} catch (outerErr) {
|
|
498
|
+
if (captureSet && down) {
|
|
499
|
+
try {
|
|
500
|
+
down(...sealed);
|
|
501
|
+
} catch (downErr) {
|
|
502
|
+
console.error(
|
|
503
|
+
`mutate: down hook threw \u2014 original action error preserved (${captured instanceof Error ? captured.name : typeof captured}). Down error:`,
|
|
504
|
+
downErr
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
if (captureSet && opts.log && opts.onFailureRecord) {
|
|
509
|
+
const errorType = captured instanceof Error ? captured.name : typeof captured;
|
|
510
|
+
appendAudit(
|
|
511
|
+
opts.log,
|
|
512
|
+
opts.onFailureRecord,
|
|
513
|
+
sealed,
|
|
514
|
+
captured,
|
|
515
|
+
{ t_ns, seq, errorType },
|
|
516
|
+
opts.handlerVersion
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
throw captureSet ? captured : outerErr;
|
|
520
|
+
}
|
|
521
|
+
return result;
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
var _bumpCursorWarned = /* @__PURE__ */ new WeakSet();
|
|
525
|
+
function bumpCursor(seq) {
|
|
526
|
+
const raw = seq.cache;
|
|
527
|
+
const valid = typeof raw === "number" && Number.isFinite(raw);
|
|
528
|
+
if (!valid && raw !== void 0 && !_bumpCursorWarned.has(seq)) {
|
|
529
|
+
_bumpCursorWarned.add(seq);
|
|
530
|
+
console.warn(
|
|
531
|
+
`bumpCursor: cursor cache held a non-numeric value (${String(raw)}); resetting to 0. Causes include: a snapshot codec round-tripping the cursor as a string / null / NaN, OR a malformed initial seed (e.g. state<number>(NaN)). Audit consumers may see colliding seq values after this point.`
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
const cur = valid ? raw : 0;
|
|
535
|
+
const next = cur + 1;
|
|
536
|
+
seq.down([[import_core2.DIRTY], [import_core2.DATA, next]]);
|
|
537
|
+
return next;
|
|
538
|
+
}
|
|
539
|
+
function appendAudit(audit, builder, args, value, meta, handlerVersion) {
|
|
540
|
+
const record = builder(args, value, meta);
|
|
541
|
+
if (record === void 0) return;
|
|
542
|
+
const stamped = handlerVersion != null ? { ...record, handlerVersion } : record;
|
|
543
|
+
audit.append(stamped);
|
|
544
|
+
}
|
|
545
|
+
function registerCursor(graph, name, initial = 0) {
|
|
546
|
+
const cursor = (0, import_core2.node)([], { initial, name, describeKind: "state" });
|
|
547
|
+
graph.add(cursor, { name });
|
|
548
|
+
return cursor;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// src/utils/messaging/index.ts
|
|
552
|
+
function requireNonNegativeInt(value, label) {
|
|
553
|
+
if (!Number.isFinite(value) || !Number.isInteger(value) || value < 0) {
|
|
554
|
+
throw new Error(`${label} must be a non-negative integer`);
|
|
555
|
+
}
|
|
556
|
+
return value;
|
|
557
|
+
}
|
|
558
|
+
function messagingMeta(kind, extra) {
|
|
559
|
+
return domainMeta("messaging", kind, extra);
|
|
560
|
+
}
|
|
561
|
+
var DEFAULT_TOPIC_RETAINED_LIMIT = 1024;
|
|
562
|
+
var TopicGraph = class extends import_graph2.Graph {
|
|
563
|
+
_log;
|
|
564
|
+
_publishImpl;
|
|
565
|
+
events;
|
|
566
|
+
/**
|
|
567
|
+
* Most recently published value. Stays in the protocol SENTINEL state
|
|
568
|
+
* (`cache === undefined`, no DATA emitted) until the first publish, then
|
|
569
|
+
* tracks the latest entry. Spec §5.12 reserves `undefined` as the
|
|
570
|
+
* "never sent DATA" sentinel — and `TopicGraph.publish(undefined)` is
|
|
571
|
+
* rejected — so `cache === undefined` unambiguously signals "empty topic"
|
|
572
|
+
* even when `T` itself includes `null` (i.e., `topic<number | null>`).
|
|
573
|
+
*
|
|
574
|
+
* **Within a reactive fn:** detect the empty-topic case via
|
|
575
|
+
* `ctx.prevData[i] === undefined` for the dep slot holding `topic.latest`,
|
|
576
|
+
* or check `latest.cache === undefined` outside reactive code. No
|
|
577
|
+
* separate `hasLatest` companion needed — the SENTINEL is the answer.
|
|
578
|
+
*/
|
|
579
|
+
latest;
|
|
580
|
+
constructor(name, opts = {}) {
|
|
581
|
+
super(name, opts.graph);
|
|
582
|
+
this._log = (0, import_extra3.reactiveLog)([], {
|
|
583
|
+
name: "events",
|
|
584
|
+
maxSize: opts.retainedLimit ?? DEFAULT_TOPIC_RETAINED_LIMIT
|
|
585
|
+
});
|
|
586
|
+
this.events = this._log.entries;
|
|
587
|
+
this.add(this.events, { name: "events" });
|
|
588
|
+
this.latest = this.derived(
|
|
589
|
+
"latest",
|
|
590
|
+
["events"],
|
|
591
|
+
(batchData, ctx) => {
|
|
592
|
+
const data = batchData.map(
|
|
593
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
594
|
+
);
|
|
595
|
+
const entries = data[0];
|
|
596
|
+
return entries.length === 0 ? [] : [entries[entries.length - 1]];
|
|
597
|
+
},
|
|
598
|
+
{ meta: messagingMeta("topic_latest") }
|
|
599
|
+
);
|
|
600
|
+
this.addDisposer((0, import_extra3.keepalive)(this.latest));
|
|
601
|
+
this.addDisposer(() => {
|
|
602
|
+
this.events.down([[import_core3.COMPLETE]]);
|
|
603
|
+
});
|
|
604
|
+
this.addDisposer(() => this._log.disposeAllViews());
|
|
605
|
+
this._publishImpl = mutate(
|
|
606
|
+
(value) => {
|
|
607
|
+
this._log.append(value);
|
|
608
|
+
},
|
|
609
|
+
{ frame: "inline", freeze: false }
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
publish(value) {
|
|
613
|
+
if (value === void 0) {
|
|
614
|
+
throw new TypeError(
|
|
615
|
+
`TopicGraph "${this.name}": publish(undefined) is not allowed (spec \xA75.12 SENTINEL).`
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
this._publishImpl(value);
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Wire one or more append-log storage tiers (Audit 4). Each tier receives
|
|
622
|
+
* appended events per wave; rollback honors the wave-as-transaction model.
|
|
623
|
+
*
|
|
624
|
+
* Named `attachEventStorage` (not `attachStorage`) to avoid colliding with
|
|
625
|
+
* the inherited {@link Graph.attachSnapshotStorage} which takes the
|
|
626
|
+
* paired `AttachSnapshotTierPair[]` shape (Phase 14.6) — distinct
|
|
627
|
+
* concerns, distinct surfaces.
|
|
628
|
+
*
|
|
629
|
+
* @returns Disposer.
|
|
630
|
+
*/
|
|
631
|
+
attachEventStorage(tiers) {
|
|
632
|
+
return this._log.attachStorage(tiers);
|
|
633
|
+
}
|
|
634
|
+
retained() {
|
|
635
|
+
return this.events.cache;
|
|
636
|
+
}
|
|
637
|
+
/** Internal log bundle — used by TopicBridgeGraph for `attach`. */
|
|
638
|
+
get _logBundle() {
|
|
639
|
+
return this._log;
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
var SubscriptionGraph = class extends import_graph2.Graph {
|
|
643
|
+
cursor;
|
|
644
|
+
available;
|
|
645
|
+
/**
|
|
646
|
+
* Reference to the upstream topic graph. Intentionally NOT mounted
|
|
647
|
+
* under this subscription: a subscription is a VIEW over an
|
|
648
|
+
* externally-owned topic. Double-mounting (e.g. hub-owned topic +
|
|
649
|
+
* sub-mount here) would make either-side teardown leave the other
|
|
650
|
+
* holding a dead reference. Node-level `derived([topicEvents], …)`
|
|
651
|
+
* still wires the data dependency across graph boundaries. D1(e).
|
|
652
|
+
*/
|
|
653
|
+
topic;
|
|
654
|
+
_disposed = false;
|
|
655
|
+
_ackImpl;
|
|
656
|
+
_pullAndAckImpl;
|
|
657
|
+
constructor(name, topicGraph, opts = {}) {
|
|
658
|
+
super(name, opts.graph);
|
|
659
|
+
this.topic = topicGraph;
|
|
660
|
+
let initialCursor;
|
|
661
|
+
if (opts.from !== void 0) {
|
|
662
|
+
if (opts.from === "retained") {
|
|
663
|
+
initialCursor = 0;
|
|
664
|
+
} else if (opts.from === "now") {
|
|
665
|
+
initialCursor = topicGraph.events.cache.length;
|
|
666
|
+
} else {
|
|
667
|
+
initialCursor = requireNonNegativeInt(opts.from, "subscription from");
|
|
668
|
+
}
|
|
669
|
+
} else {
|
|
670
|
+
initialCursor = requireNonNegativeInt(opts.cursor ?? 0, "subscription cursor");
|
|
671
|
+
}
|
|
672
|
+
this.cursor = this.state("cursor", initialCursor, {
|
|
673
|
+
meta: messagingMeta("subscription_cursor")
|
|
674
|
+
});
|
|
675
|
+
this.available = topicGraph._logBundle.view({ kind: "fromCursor", cursor: this.cursor });
|
|
676
|
+
this.add(this.available, { name: "available" });
|
|
677
|
+
this.addDisposer((0, import_extra3.keepalive)(this.available));
|
|
678
|
+
if (opts.advanceOn !== void 0) {
|
|
679
|
+
const advanceOn = opts.advanceOn;
|
|
680
|
+
let advanceInitialized = false;
|
|
681
|
+
const advancePump = (0, import_core3.node)(
|
|
682
|
+
[advanceOn],
|
|
683
|
+
() => {
|
|
684
|
+
if (!advanceInitialized) {
|
|
685
|
+
advanceInitialized = true;
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
if (this._disposed) return;
|
|
689
|
+
const avail = this.available.cache;
|
|
690
|
+
if (avail.length === 0) return;
|
|
691
|
+
const next = this.cursor.cache + avail.length;
|
|
692
|
+
this.cursor.emit(next);
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
name: "advancePump",
|
|
696
|
+
describeKind: "effect",
|
|
697
|
+
meta: messagingMeta("subscription_advance_pump")
|
|
698
|
+
}
|
|
699
|
+
);
|
|
700
|
+
this.add(advancePump, { name: "advancePump" });
|
|
701
|
+
this.addDisposer((0, import_extra3.keepalive)(advancePump));
|
|
702
|
+
}
|
|
703
|
+
this._ackImpl = mutate(
|
|
704
|
+
(count) => {
|
|
705
|
+
const available = this.available.cache;
|
|
706
|
+
const requested = count === void 0 ? available.length : requireNonNegativeInt(count, "subscription ack count");
|
|
707
|
+
const step = Math.min(requested, available.length);
|
|
708
|
+
if (step <= 0) return this.cursor.cache;
|
|
709
|
+
const next = this.cursor.cache + step;
|
|
710
|
+
this.cursor.emit(next);
|
|
711
|
+
return next;
|
|
712
|
+
},
|
|
713
|
+
{ frame: "inline", freeze: false }
|
|
714
|
+
);
|
|
715
|
+
this._pullAndAckImpl = mutate(
|
|
716
|
+
(limit) => {
|
|
717
|
+
const available = this.available.cache;
|
|
718
|
+
const max = limit === void 0 ? available.length : requireNonNegativeInt(limit, "subscription pullAndAck limit");
|
|
719
|
+
const items = available.slice(0, max);
|
|
720
|
+
if (items.length === 0) return { items, cursor: this.cursor.cache };
|
|
721
|
+
const next = this.cursor.cache + items.length;
|
|
722
|
+
this.cursor.emit(next);
|
|
723
|
+
return { items, cursor: next };
|
|
724
|
+
},
|
|
725
|
+
{ frame: "inline", freeze: false }
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
ack(count) {
|
|
729
|
+
if (this._disposed) return this.cursor.cache;
|
|
730
|
+
return this._ackImpl(count);
|
|
731
|
+
}
|
|
732
|
+
pull(limit) {
|
|
733
|
+
if (this._disposed) return [];
|
|
734
|
+
const available = this.available.cache;
|
|
735
|
+
const max = limit === void 0 ? available.length : requireNonNegativeInt(limit, "subscription pull limit");
|
|
736
|
+
return available.slice(0, max);
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Atomic pull-and-acknowledge. Returns `{ items, cursor }` where `cursor`
|
|
740
|
+
* is the new cursor position after advancing. Under single-threaded JS the
|
|
741
|
+
* snapshot and advance are atomic; PY callers use a per-subscription Lock.
|
|
742
|
+
*
|
|
743
|
+
* Replaces `pull(limit, { ack: true })`.
|
|
744
|
+
*/
|
|
745
|
+
pullAndAck(limit) {
|
|
746
|
+
if (this._disposed) return { items: [], cursor: this.cursor.cache };
|
|
747
|
+
return this._pullAndAckImpl(limit);
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* Release internal subscriptions and mark the subscription torn-down.
|
|
751
|
+
* Subsequent `pull`, `pullAndAck`, `ack` return empty / current cursor.
|
|
752
|
+
* Emits COMPLETE on `cursor` so derived consumers (e.g. `available`) see
|
|
753
|
+
* the termination signal. Also drains `addDisposer` callbacks (including
|
|
754
|
+
* the `keepalive(advancePump)` subscription) so no keepalive leak occurs.
|
|
755
|
+
*/
|
|
756
|
+
dispose() {
|
|
757
|
+
if (this._disposed) return;
|
|
758
|
+
this._disposed = true;
|
|
759
|
+
this.cursor.down([[import_core3.COMPLETE]]);
|
|
760
|
+
this.destroy();
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
function topic(name, opts) {
|
|
764
|
+
return new TopicGraph(name, opts);
|
|
765
|
+
}
|
|
766
|
+
function subscription(name, topicGraph, opts) {
|
|
767
|
+
return new SubscriptionGraph(name, topicGraph, opts);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// src/presets/ai/agent-loop.ts
|
|
771
|
+
var import_core11 = require("@graphrefly/pure-ts/core");
|
|
772
|
+
var import_extra7 = require("@graphrefly/pure-ts/extra");
|
|
773
|
+
var import_graph5 = require("@graphrefly/pure-ts/graph");
|
|
774
|
+
|
|
775
|
+
// src/base/sources/settled.ts
|
|
776
|
+
var import_core6 = require("@graphrefly/pure-ts/core");
|
|
777
|
+
function firstValueFrom(source) {
|
|
778
|
+
return new Promise((resolve, reject) => {
|
|
779
|
+
let settled = false;
|
|
780
|
+
let shouldUnsub = false;
|
|
781
|
+
let unsub;
|
|
782
|
+
unsub = source.subscribe((msgs) => {
|
|
783
|
+
for (const m of msgs) {
|
|
784
|
+
if (settled) return;
|
|
785
|
+
if (m[0] === import_core6.DATA) {
|
|
786
|
+
settled = true;
|
|
787
|
+
resolve(m[1]);
|
|
788
|
+
if (unsub) {
|
|
789
|
+
unsub();
|
|
790
|
+
unsub = void 0;
|
|
791
|
+
} else shouldUnsub = true;
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
if (m[0] === import_core6.ERROR) {
|
|
795
|
+
settled = true;
|
|
796
|
+
reject(m[1]);
|
|
797
|
+
if (unsub) {
|
|
798
|
+
unsub();
|
|
799
|
+
unsub = void 0;
|
|
800
|
+
} else shouldUnsub = true;
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
if (m[0] === import_core6.COMPLETE) {
|
|
804
|
+
settled = true;
|
|
805
|
+
reject(new Error("completed without DATA"));
|
|
806
|
+
if (unsub) {
|
|
807
|
+
unsub();
|
|
808
|
+
unsub = void 0;
|
|
809
|
+
} else shouldUnsub = true;
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
});
|
|
814
|
+
if (shouldUnsub) {
|
|
815
|
+
unsub?.();
|
|
816
|
+
unsub = void 0;
|
|
817
|
+
}
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
function firstWhere(source, predicate, opts) {
|
|
821
|
+
let pending;
|
|
822
|
+
let resolveFn;
|
|
823
|
+
let rejectFn;
|
|
824
|
+
let settled = false;
|
|
825
|
+
let shouldUnsub = false;
|
|
826
|
+
let unsub;
|
|
827
|
+
let inInitialSyncPhase = opts?.skipCurrent === true;
|
|
828
|
+
const settleData = (v) => {
|
|
829
|
+
if (settled) return;
|
|
830
|
+
settled = true;
|
|
831
|
+
if (resolveFn != null) resolveFn(v);
|
|
832
|
+
else pending = { kind: "data", value: v };
|
|
833
|
+
};
|
|
834
|
+
const settleError = (err) => {
|
|
835
|
+
if (settled) return;
|
|
836
|
+
settled = true;
|
|
837
|
+
if (rejectFn != null) rejectFn(err);
|
|
838
|
+
else pending = { kind: "error", err };
|
|
839
|
+
};
|
|
840
|
+
const settleComplete = () => {
|
|
841
|
+
if (settled) return;
|
|
842
|
+
settled = true;
|
|
843
|
+
const err = new Error("completed without matching value");
|
|
844
|
+
if (rejectFn != null) rejectFn(err);
|
|
845
|
+
else pending = { kind: "complete" };
|
|
846
|
+
};
|
|
847
|
+
const detach = () => {
|
|
848
|
+
if (unsub) {
|
|
849
|
+
unsub();
|
|
850
|
+
unsub = void 0;
|
|
851
|
+
} else shouldUnsub = true;
|
|
852
|
+
};
|
|
853
|
+
const sink = (msgs) => {
|
|
854
|
+
if (settled) return;
|
|
855
|
+
for (const m of msgs) {
|
|
856
|
+
if (settled) return;
|
|
857
|
+
if (inInitialSyncPhase && m[0] === import_core6.DATA) continue;
|
|
858
|
+
if (m[0] === import_core6.DATA) {
|
|
859
|
+
const v = m[1];
|
|
860
|
+
if (predicate(v)) {
|
|
861
|
+
settleData(v);
|
|
862
|
+
detach();
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
if (m[0] === import_core6.ERROR) {
|
|
867
|
+
settleError(m[1]);
|
|
868
|
+
detach();
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
if (m[0] === import_core6.COMPLETE) {
|
|
872
|
+
settleComplete();
|
|
873
|
+
detach();
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
};
|
|
878
|
+
unsub = source.subscribe(sink);
|
|
879
|
+
inInitialSyncPhase = false;
|
|
880
|
+
if (opts?.kick != null && !settled) {
|
|
881
|
+
try {
|
|
882
|
+
opts.kick();
|
|
883
|
+
} catch (err) {
|
|
884
|
+
settleError(err);
|
|
885
|
+
detach();
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
if (shouldUnsub) {
|
|
889
|
+
unsub?.();
|
|
890
|
+
unsub = void 0;
|
|
891
|
+
}
|
|
892
|
+
return new Promise((resolve, reject) => {
|
|
893
|
+
if (pending != null) {
|
|
894
|
+
if (pending.kind === "data") resolve(pending.value);
|
|
895
|
+
else if (pending.kind === "error") reject(pending.err);
|
|
896
|
+
else reject(new Error("completed without matching value"));
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
resolveFn = resolve;
|
|
900
|
+
rejectFn = reject;
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
var _timeoutOp;
|
|
904
|
+
var _nsPerMs;
|
|
905
|
+
async function awaitSettled(source, opts) {
|
|
906
|
+
const predicate = opts?.predicate ?? ((v) => v != null);
|
|
907
|
+
const skipCurrent = opts?.skipCurrent;
|
|
908
|
+
const kick = opts?.kick;
|
|
909
|
+
if (opts?.timeoutMs == null || opts.timeoutMs <= 0) {
|
|
910
|
+
return await firstWhere(source, predicate, { skipCurrent, kick });
|
|
911
|
+
}
|
|
912
|
+
if (_timeoutOp === void 0) {
|
|
913
|
+
const [timeoutMod, backoff] = await Promise.all([
|
|
914
|
+
Promise.resolve().then(() => (init_timeout(), timeout_exports)),
|
|
915
|
+
Promise.resolve().then(() => (init_backoff(), backoff_exports))
|
|
916
|
+
]);
|
|
917
|
+
_timeoutOp = timeoutMod.withTimeout;
|
|
918
|
+
_nsPerMs = backoff.NS_PER_MS;
|
|
919
|
+
}
|
|
920
|
+
const guarded = _timeoutOp(source, { ns: opts.timeoutMs * _nsPerMs }).node;
|
|
921
|
+
return await firstWhere(guarded, predicate, { skipCurrent, kick });
|
|
922
|
+
}
|
|
923
|
+
function nodeSignal(source, opts) {
|
|
924
|
+
const ctrl = new AbortController();
|
|
925
|
+
const reason = opts?.reason ?? new Error("cancelled via nodeSignal");
|
|
926
|
+
let unsub;
|
|
927
|
+
let shouldUnsub = false;
|
|
928
|
+
const done = () => {
|
|
929
|
+
if (unsub) {
|
|
930
|
+
unsub();
|
|
931
|
+
unsub = void 0;
|
|
932
|
+
} else shouldUnsub = true;
|
|
933
|
+
};
|
|
934
|
+
unsub = source.subscribe((msgs) => {
|
|
935
|
+
if (ctrl.signal.aborted) return;
|
|
936
|
+
for (const m of msgs) {
|
|
937
|
+
if (m[0] === import_core6.DATA && m[1] === true) {
|
|
938
|
+
ctrl.abort(reason);
|
|
939
|
+
done();
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
if (m[0] === import_core6.ERROR) {
|
|
943
|
+
ctrl.abort(m[1]);
|
|
944
|
+
done();
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
if (m[0] === import_core6.COMPLETE) {
|
|
948
|
+
done();
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
});
|
|
953
|
+
if (shouldUnsub) {
|
|
954
|
+
unsub?.();
|
|
955
|
+
unsub = void 0;
|
|
956
|
+
}
|
|
957
|
+
return {
|
|
958
|
+
signal: ctrl.signal,
|
|
959
|
+
dispose: () => {
|
|
960
|
+
if (unsub) {
|
|
961
|
+
unsub();
|
|
962
|
+
unsub = void 0;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// src/utils/ai/agents/chat-stream.ts
|
|
969
|
+
var import_core7 = require("@graphrefly/pure-ts/core");
|
|
970
|
+
var import_extra4 = require("@graphrefly/pure-ts/extra");
|
|
971
|
+
var import_graph3 = require("@graphrefly/pure-ts/graph");
|
|
972
|
+
var ChatStreamGraph = class extends import_graph3.Graph {
|
|
973
|
+
_log;
|
|
974
|
+
messages;
|
|
975
|
+
/**
|
|
976
|
+
* Most recently appended message. Stays in the protocol SENTINEL state
|
|
977
|
+
* (`cache === undefined`, no DATA emitted) until the first append, then
|
|
978
|
+
* tracks the latest entry. Per COMPOSITION-GUIDE §1a, the SENTINEL is
|
|
979
|
+
* the canonical "no value yet" signal — consumers detect empty via
|
|
980
|
+
* `data[i] === undefined` inside reactive fns or `latest.cache === undefined`
|
|
981
|
+
* outside. No `T | null` placeholder, no `hasLatest` companion.
|
|
982
|
+
*/
|
|
983
|
+
latest;
|
|
984
|
+
messageCount;
|
|
985
|
+
constructor(name, opts = {}) {
|
|
986
|
+
super(name, opts.graph);
|
|
987
|
+
this._log = (0, import_extra4.reactiveLog)([], {
|
|
988
|
+
name: "messages",
|
|
989
|
+
maxSize: opts.maxMessages
|
|
990
|
+
});
|
|
991
|
+
this.messages = this._log.entries;
|
|
992
|
+
this.add(this.messages, { name: "messages" });
|
|
993
|
+
this.latest = (0, import_core7.node)(
|
|
994
|
+
[this.messages],
|
|
995
|
+
(batchData, actions, ctx) => {
|
|
996
|
+
const data = batchData.map(
|
|
997
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
998
|
+
);
|
|
999
|
+
const entries = data[0];
|
|
1000
|
+
if (entries.length === 0) {
|
|
1001
|
+
actions.down([[import_core7.RESOLVED]]);
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
actions.emit(entries[entries.length - 1]);
|
|
1005
|
+
},
|
|
1006
|
+
{
|
|
1007
|
+
name: "latest",
|
|
1008
|
+
describeKind: "derived",
|
|
1009
|
+
meta: aiMeta("chat_latest")
|
|
1010
|
+
}
|
|
1011
|
+
);
|
|
1012
|
+
this.add(this.latest, { name: "latest" });
|
|
1013
|
+
this.addDisposer((0, import_extra4.keepalive)(this.latest));
|
|
1014
|
+
this.messageCount = (0, import_core7.node)(
|
|
1015
|
+
[this.messages],
|
|
1016
|
+
(batchData, actions, ctx) => {
|
|
1017
|
+
const data = batchData.map(
|
|
1018
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
1019
|
+
);
|
|
1020
|
+
actions.emit(data[0].length);
|
|
1021
|
+
},
|
|
1022
|
+
{
|
|
1023
|
+
name: "messageCount",
|
|
1024
|
+
describeKind: "derived",
|
|
1025
|
+
meta: aiMeta("chat_message_count"),
|
|
1026
|
+
initial: 0
|
|
1027
|
+
}
|
|
1028
|
+
);
|
|
1029
|
+
this.add(this.messageCount, { name: "messageCount" });
|
|
1030
|
+
this.addDisposer((0, import_extra4.keepalive)(this.messageCount));
|
|
1031
|
+
}
|
|
1032
|
+
append(role, content, extra) {
|
|
1033
|
+
this._log.append({ role, content, ...extra });
|
|
1034
|
+
}
|
|
1035
|
+
appendToolResult(callId, content) {
|
|
1036
|
+
this._log.append({ role: "tool", content, toolCallId: callId });
|
|
1037
|
+
}
|
|
1038
|
+
clear() {
|
|
1039
|
+
this._log.clear();
|
|
1040
|
+
}
|
|
1041
|
+
allMessages() {
|
|
1042
|
+
return this.messages.cache;
|
|
1043
|
+
}
|
|
1044
|
+
};
|
|
1045
|
+
function chatStream(name, opts) {
|
|
1046
|
+
return new ChatStreamGraph(name, opts);
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// src/utils/ai/agents/tool-execution.ts
|
|
1050
|
+
var import_core9 = require("@graphrefly/pure-ts/core");
|
|
1051
|
+
var import_extra5 = require("@graphrefly/pure-ts/extra");
|
|
1052
|
+
|
|
1053
|
+
// src/base/resilience/retry.ts
|
|
1054
|
+
var import_core8 = require("@graphrefly/pure-ts/core");
|
|
1055
|
+
init_internal();
|
|
1056
|
+
init_backoff();
|
|
1057
|
+
function resolveRetryConfig(opts) {
|
|
1058
|
+
const count = opts?.count;
|
|
1059
|
+
const backoffOpt = opts?.backoff;
|
|
1060
|
+
if (backoffOpt !== void 0 && count === void 0) {
|
|
1061
|
+
throw new RangeError(
|
|
1062
|
+
"retry({ backoff }) requires explicit count to prevent unbounded retries; pass { count: <n>, backoff: ... }"
|
|
1063
|
+
);
|
|
1064
|
+
}
|
|
1065
|
+
const maxRetries = count !== void 0 ? count : 0;
|
|
1066
|
+
if (maxRetries < 0) throw new RangeError("retry count must be >= 0");
|
|
1067
|
+
const strategy = backoffOpt === void 0 ? null : typeof backoffOpt === "string" ? resolveBackoffPreset(backoffOpt) : backoffOpt;
|
|
1068
|
+
return { maxRetries, strategy };
|
|
1069
|
+
}
|
|
1070
|
+
function retryFactoryArgs(opts) {
|
|
1071
|
+
const args = {};
|
|
1072
|
+
if (opts?.count !== void 0) args.count = opts.count;
|
|
1073
|
+
if (typeof opts?.backoff === "string") args.backoff = opts.backoff;
|
|
1074
|
+
return Object.keys(args).length > 0 ? args : void 0;
|
|
1075
|
+
}
|
|
1076
|
+
function _runRetryStateMachine(getCfg, acquireSource, a, emitState) {
|
|
1077
|
+
let attempt = 0;
|
|
1078
|
+
let stopped = false;
|
|
1079
|
+
let prevDelay = null;
|
|
1080
|
+
let unsub;
|
|
1081
|
+
const timer = new import_core8.ResettableTimer();
|
|
1082
|
+
const publish = (status) => {
|
|
1083
|
+
emitState?.({ status, attempt, lastDelay_ns: prevDelay });
|
|
1084
|
+
};
|
|
1085
|
+
publish("pending");
|
|
1086
|
+
function disconnectUpstream() {
|
|
1087
|
+
unsub?.();
|
|
1088
|
+
unsub = void 0;
|
|
1089
|
+
}
|
|
1090
|
+
function scheduleRetryOrFinish(err) {
|
|
1091
|
+
if (stopped) return;
|
|
1092
|
+
const cfg = getCfg();
|
|
1093
|
+
if (attempt >= cfg.maxRetries) {
|
|
1094
|
+
disconnectUpstream();
|
|
1095
|
+
publish("errored");
|
|
1096
|
+
a.down([[import_core8.ERROR, err]]);
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
const raw = cfg.strategy === null ? 0 : cfg.strategy(attempt, err, prevDelay);
|
|
1100
|
+
if (raw === null || raw === void 0) {
|
|
1101
|
+
disconnectUpstream();
|
|
1102
|
+
publish("errored");
|
|
1103
|
+
a.down([[import_core8.ERROR, err]]);
|
|
1104
|
+
return;
|
|
1105
|
+
}
|
|
1106
|
+
let delayNs;
|
|
1107
|
+
try {
|
|
1108
|
+
delayNs = coerceDelayNs(raw);
|
|
1109
|
+
} catch {
|
|
1110
|
+
disconnectUpstream();
|
|
1111
|
+
publish("errored");
|
|
1112
|
+
a.down([[import_core8.ERROR, err]]);
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
prevDelay = delayNs;
|
|
1116
|
+
attempt += 1;
|
|
1117
|
+
disconnectUpstream();
|
|
1118
|
+
publish("paused");
|
|
1119
|
+
const delayMs = delayNs > 0 ? delayNs / NS_PER_MS : 1;
|
|
1120
|
+
timer.start(delayMs, () => {
|
|
1121
|
+
if (stopped) return;
|
|
1122
|
+
connect();
|
|
1123
|
+
});
|
|
1124
|
+
}
|
|
1125
|
+
function connect() {
|
|
1126
|
+
timer.cancel();
|
|
1127
|
+
disconnectUpstream();
|
|
1128
|
+
let src;
|
|
1129
|
+
try {
|
|
1130
|
+
src = acquireSource();
|
|
1131
|
+
} catch (err) {
|
|
1132
|
+
scheduleRetryOrFinish(err);
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
1135
|
+
publish("running");
|
|
1136
|
+
unsub = src.subscribe((msgs) => {
|
|
1137
|
+
if (stopped) return;
|
|
1138
|
+
for (const m of msgs) {
|
|
1139
|
+
const t = m[0];
|
|
1140
|
+
if (t === import_core8.DIRTY) a.down([[import_core8.DIRTY]]);
|
|
1141
|
+
else if (t === import_core8.DATA) {
|
|
1142
|
+
attempt = 0;
|
|
1143
|
+
prevDelay = null;
|
|
1144
|
+
a.emit(m[1]);
|
|
1145
|
+
publish("running");
|
|
1146
|
+
} else if (t === import_core8.RESOLVED) a.down([[import_core8.RESOLVED]]);
|
|
1147
|
+
else if (t === import_core8.COMPLETE) {
|
|
1148
|
+
stopped = true;
|
|
1149
|
+
disconnectUpstream();
|
|
1150
|
+
publish("completed");
|
|
1151
|
+
a.down([[import_core8.COMPLETE]]);
|
|
1152
|
+
} else if (t === import_core8.ERROR) {
|
|
1153
|
+
scheduleRetryOrFinish(msgVal(m));
|
|
1154
|
+
return;
|
|
1155
|
+
} else a.down([m]);
|
|
1156
|
+
}
|
|
1157
|
+
});
|
|
1158
|
+
}
|
|
1159
|
+
connect();
|
|
1160
|
+
return () => {
|
|
1161
|
+
const wasStopped = stopped;
|
|
1162
|
+
stopped = true;
|
|
1163
|
+
timer.cancel();
|
|
1164
|
+
disconnectUpstream();
|
|
1165
|
+
if (!wasStopped) publish("cancelled");
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
function retry(input, opts) {
|
|
1169
|
+
const retryState = (0, import_core8.node)([], {
|
|
1170
|
+
name: "retryState",
|
|
1171
|
+
describeKind: "state",
|
|
1172
|
+
initial: { status: "pending", attempt: 0, lastDelay_ns: null },
|
|
1173
|
+
equals: (a, b) => a === b || a != null && b != null && typeof a === "object" && typeof b === "object" && JSON.stringify(a) === JSON.stringify(b)
|
|
1174
|
+
});
|
|
1175
|
+
const emit = (s) => {
|
|
1176
|
+
retryState.down([[import_core8.DIRTY], [import_core8.DATA, s]]);
|
|
1177
|
+
};
|
|
1178
|
+
if (typeof input === "function") {
|
|
1179
|
+
return {
|
|
1180
|
+
node: _retryFactory(input, opts, emit),
|
|
1181
|
+
retryState
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
return {
|
|
1185
|
+
node: _retrySource(input, opts, emit),
|
|
1186
|
+
retryState
|
|
1187
|
+
};
|
|
1188
|
+
}
|
|
1189
|
+
function makeMergedOptsMirror(arg) {
|
|
1190
|
+
if (arg === void 0) {
|
|
1191
|
+
return { current: () => void 0, unsub: () => void 0 };
|
|
1192
|
+
}
|
|
1193
|
+
if (!isNode(arg)) {
|
|
1194
|
+
return { current: () => arg, unsub: () => void 0 };
|
|
1195
|
+
}
|
|
1196
|
+
const optsNode = arg;
|
|
1197
|
+
let merged = optsNode.cache ?? void 0;
|
|
1198
|
+
const unsub = optsNode.subscribe((msgs) => {
|
|
1199
|
+
for (const m of msgs) {
|
|
1200
|
+
if (m[0] !== import_core8.DATA) continue;
|
|
1201
|
+
const next = m[1];
|
|
1202
|
+
if (next == null || typeof next !== "object") continue;
|
|
1203
|
+
if (Object.keys(next).length === 0) continue;
|
|
1204
|
+
merged = { ...merged ?? {}, ...next };
|
|
1205
|
+
}
|
|
1206
|
+
});
|
|
1207
|
+
return { current: () => merged, unsub };
|
|
1208
|
+
}
|
|
1209
|
+
var _retrySourceNonResubscribableWarned = /* @__PURE__ */ new WeakSet();
|
|
1210
|
+
function _retrySource(source, opts, emitState) {
|
|
1211
|
+
const sourceWithFlag = source;
|
|
1212
|
+
if (sourceWithFlag._resubscribable === false && !_retrySourceNonResubscribableWarned.has(source)) {
|
|
1213
|
+
_retrySourceNonResubscribableWarned.add(source);
|
|
1214
|
+
console.warn(
|
|
1215
|
+
"retry(source, opts): source-mode requires `resubscribable: true` on the upstream node. Retries will be silent no-ops after the first ERROR. Either pass `resubscribable: true` to the source factory, OR use factory-mode retry `retry(() => buildSource(), opts)` so each attempt builds a fresh node."
|
|
1216
|
+
);
|
|
1217
|
+
}
|
|
1218
|
+
const staticOpts = isNode(opts) ? void 0 : opts;
|
|
1219
|
+
if (!isNode(opts)) resolveRetryConfig(staticOpts);
|
|
1220
|
+
return (0, import_core8.node)(
|
|
1221
|
+
(_data, a) => {
|
|
1222
|
+
const merged = makeMergedOptsMirror(opts);
|
|
1223
|
+
const getCfg = () => resolveRetryConfig(merged.current());
|
|
1224
|
+
const inner = _runRetryStateMachine(getCfg, () => source, a, emitState);
|
|
1225
|
+
return () => {
|
|
1226
|
+
inner();
|
|
1227
|
+
merged.unsub();
|
|
1228
|
+
};
|
|
1229
|
+
},
|
|
1230
|
+
{
|
|
1231
|
+
...operatorOpts(),
|
|
1232
|
+
initial: source.cache,
|
|
1233
|
+
meta: {
|
|
1234
|
+
...staticOpts?.meta ?? {},
|
|
1235
|
+
...(0, import_core8.factoryTag)(
|
|
1236
|
+
"retry",
|
|
1237
|
+
isNode(opts) ? { reactiveOpts: true } : retryFactoryArgs(staticOpts)
|
|
1238
|
+
)
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
);
|
|
1242
|
+
}
|
|
1243
|
+
function _retryFactory(factory, opts, emitState) {
|
|
1244
|
+
const staticOpts = isNode(opts) ? void 0 : opts;
|
|
1245
|
+
if (!isNode(opts)) resolveRetryConfig(staticOpts);
|
|
1246
|
+
return (0, import_core8.node)(
|
|
1247
|
+
(_data, a) => {
|
|
1248
|
+
const merged = makeMergedOptsMirror(opts);
|
|
1249
|
+
const getCfg = () => resolveRetryConfig(merged.current());
|
|
1250
|
+
const inner = _runRetryStateMachine(getCfg, factory, a, emitState);
|
|
1251
|
+
return () => {
|
|
1252
|
+
inner();
|
|
1253
|
+
merged.unsub();
|
|
1254
|
+
};
|
|
1255
|
+
},
|
|
1256
|
+
{
|
|
1257
|
+
...operatorOpts(),
|
|
1258
|
+
initial: staticOpts?.initial,
|
|
1259
|
+
meta: {
|
|
1260
|
+
...staticOpts?.meta ?? {},
|
|
1261
|
+
...(0, import_core8.factoryTag)(
|
|
1262
|
+
"retry",
|
|
1263
|
+
isNode(opts) ? { reactiveOpts: true } : retryFactoryArgs(staticOpts)
|
|
1264
|
+
)
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
// src/utils/ai/agents/tool-execution.ts
|
|
1271
|
+
function toolExecution(opts) {
|
|
1272
|
+
const { toolCalls, tools } = opts;
|
|
1273
|
+
const retryCount = opts.retryCount ?? 1;
|
|
1274
|
+
const onError = opts.onError ?? "rescue";
|
|
1275
|
+
const batchEquals = (a, b) => {
|
|
1276
|
+
if (a === b) return true;
|
|
1277
|
+
if (a.length !== b.length) return false;
|
|
1278
|
+
for (let i = 0; i < a.length; i++) {
|
|
1279
|
+
const ai = a[i];
|
|
1280
|
+
const bi = b[i];
|
|
1281
|
+
if (ai?.id !== bi?.id) return false;
|
|
1282
|
+
if (ai?.content !== bi?.content) return false;
|
|
1283
|
+
}
|
|
1284
|
+
return true;
|
|
1285
|
+
};
|
|
1286
|
+
return (0, import_extra5.switchMap)(toolCalls, (calls) => {
|
|
1287
|
+
if (calls == null || calls.length === 0) {
|
|
1288
|
+
throw new Error(
|
|
1289
|
+
"toolExecution: received an empty tool-call batch as DATA \u2014 callers must upstream-filter empty batches (emit RESOLVED) so switchMap is only dispatched for non-empty batches."
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
const perCall = calls.map((call) => executeOne(call, tools, retryCount, onError));
|
|
1293
|
+
return (0, import_core9.node)(
|
|
1294
|
+
perCall,
|
|
1295
|
+
(batchData, actions, ctx) => {
|
|
1296
|
+
const data = batchData.map(
|
|
1297
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
1298
|
+
);
|
|
1299
|
+
actions.emit(data);
|
|
1300
|
+
},
|
|
1301
|
+
{ describeKind: "derived", name: "toolExecution::batch", equals: batchEquals }
|
|
1302
|
+
);
|
|
1303
|
+
});
|
|
1304
|
+
}
|
|
1305
|
+
function executeOne(call, tools, retryCount, onError) {
|
|
1306
|
+
const attempted = retry(() => tools.executeReactive(call.name, call.arguments), {
|
|
1307
|
+
count: retryCount
|
|
1308
|
+
}).node;
|
|
1309
|
+
const onSuccess = (0, import_core9.node)(
|
|
1310
|
+
[attempted],
|
|
1311
|
+
(batchData, actions, ctx) => {
|
|
1312
|
+
const data = batchData.map(
|
|
1313
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
1314
|
+
);
|
|
1315
|
+
const val = data[0];
|
|
1316
|
+
actions.emit({
|
|
1317
|
+
id: call.id,
|
|
1318
|
+
content: typeof val === "string" ? val : JSON.stringify(val)
|
|
1319
|
+
});
|
|
1320
|
+
},
|
|
1321
|
+
{ describeKind: "derived" }
|
|
1322
|
+
);
|
|
1323
|
+
if (onError === "propagate") return onSuccess;
|
|
1324
|
+
return (0, import_extra5.rescue)(onSuccess, (err) => ({
|
|
1325
|
+
id: call.id,
|
|
1326
|
+
content: JSON.stringify({ error: String(err) })
|
|
1327
|
+
}));
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
// src/utils/ai/agents/tool-registry.ts
|
|
1331
|
+
var import_core10 = require("@graphrefly/pure-ts/core");
|
|
1332
|
+
var import_extra6 = require("@graphrefly/pure-ts/extra");
|
|
1333
|
+
var import_graph4 = require("@graphrefly/pure-ts/graph");
|
|
1334
|
+
var ToolRegistryGraph = class extends import_graph4.Graph {
|
|
1335
|
+
definitions;
|
|
1336
|
+
schemas;
|
|
1337
|
+
_bundle;
|
|
1338
|
+
constructor(name, opts = {}) {
|
|
1339
|
+
super(name, opts.graph);
|
|
1340
|
+
this._bundle = (0, import_extra6.reactiveMap)({
|
|
1341
|
+
name: "definitions"
|
|
1342
|
+
});
|
|
1343
|
+
this.definitions = this._bundle.entries;
|
|
1344
|
+
this.add(this.definitions, { name: "definitions" });
|
|
1345
|
+
this.schemas = (0, import_core10.node)(
|
|
1346
|
+
[this.definitions],
|
|
1347
|
+
(batchData, actions, ctx) => {
|
|
1348
|
+
const data = batchData.map(
|
|
1349
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
1350
|
+
);
|
|
1351
|
+
const defs = data[0];
|
|
1352
|
+
actions.emit([...(defs ?? /* @__PURE__ */ new Map()).values()]);
|
|
1353
|
+
},
|
|
1354
|
+
{
|
|
1355
|
+
name: "schemas",
|
|
1356
|
+
describeKind: "derived",
|
|
1357
|
+
meta: aiMeta("tool_schemas"),
|
|
1358
|
+
initial: []
|
|
1359
|
+
}
|
|
1360
|
+
);
|
|
1361
|
+
this.add(this.schemas, { name: "schemas" });
|
|
1362
|
+
this.addDisposer((0, import_extra6.keepalive)(this.schemas));
|
|
1363
|
+
}
|
|
1364
|
+
register(tool) {
|
|
1365
|
+
this._bundle.set(tool.name, tool);
|
|
1366
|
+
}
|
|
1367
|
+
unregister(name) {
|
|
1368
|
+
this._bundle.delete(name);
|
|
1369
|
+
}
|
|
1370
|
+
/**
|
|
1371
|
+
* Reactive execution — returns a `Node<unknown>` that emits the handler
|
|
1372
|
+
* result. The returned node is a `producer` that:
|
|
1373
|
+
*
|
|
1374
|
+
* 1. Mints a per-call `AbortController` whose `signal` is threaded into
|
|
1375
|
+
* the handler call AND into `fromAny` (so a `fromPromise` /
|
|
1376
|
+
* `fromAsyncIter` inner abandons cleanly when the consumer
|
|
1377
|
+
* unsubscribes).
|
|
1378
|
+
* 2. Runs `tool.handler(args, {signal})` inside a try/catch — a
|
|
1379
|
+
* synchronous throw surfaces as `[[ERROR, err]]` downstream instead
|
|
1380
|
+
* of escaping the producer.
|
|
1381
|
+
* 3. Forwards every message from the inner `fromAny` chain to the
|
|
1382
|
+
* producer's outputs.
|
|
1383
|
+
* 4. On teardown (subscriber count drops to zero, e.g. `switchMap`
|
|
1384
|
+
* supersede) calls `ac.abort()` and unsubscribes the inner.
|
|
1385
|
+
* Signal-aware handlers (e.g. `fetch(url, {signal})`) actually stop.
|
|
1386
|
+
*
|
|
1387
|
+
* Each call mints a fresh node tied to a fresh `handler(args, ...)`
|
|
1388
|
+
* invocation — call `executeReactive` again for repeated invocations.
|
|
1389
|
+
*
|
|
1390
|
+
* @throws `Error` synchronously when `name` is not registered (no node is
|
|
1391
|
+
* constructed — the caller gets a pre-wiring failure rather than a
|
|
1392
|
+
* silent ERROR wave on an empty graph).
|
|
1393
|
+
*/
|
|
1394
|
+
executeReactive(name, args) {
|
|
1395
|
+
const tool = this._bundle.get(name);
|
|
1396
|
+
if (!tool) throw new Error(`toolRegistry: unknown tool "${name}"`);
|
|
1397
|
+
return (0, import_core10.node)(
|
|
1398
|
+
[],
|
|
1399
|
+
(_data, actions) => {
|
|
1400
|
+
const ac = new AbortController();
|
|
1401
|
+
let inner;
|
|
1402
|
+
try {
|
|
1403
|
+
const raw = tool.handler(args, { signal: ac.signal });
|
|
1404
|
+
inner = handlerResultToNode(raw, ac.signal);
|
|
1405
|
+
} catch (err) {
|
|
1406
|
+
actions.down([[import_core10.ERROR, err]]);
|
|
1407
|
+
return () => {
|
|
1408
|
+
ac.abort();
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1411
|
+
const unsub = inner.subscribe((batch8) => {
|
|
1412
|
+
actions.down(batch8);
|
|
1413
|
+
});
|
|
1414
|
+
return () => {
|
|
1415
|
+
ac.abort();
|
|
1416
|
+
unsub();
|
|
1417
|
+
};
|
|
1418
|
+
},
|
|
1419
|
+
{
|
|
1420
|
+
name: `executeReactive::${name}`,
|
|
1421
|
+
describeKind: "producer",
|
|
1422
|
+
meta: aiMeta("tool_execute_reactive")
|
|
1423
|
+
}
|
|
1424
|
+
);
|
|
1425
|
+
}
|
|
1426
|
+
getDefinition(name) {
|
|
1427
|
+
return this._bundle.entries.cache?.get(name);
|
|
1428
|
+
}
|
|
1429
|
+
};
|
|
1430
|
+
function toolRegistry(name, opts) {
|
|
1431
|
+
return new ToolRegistryGraph(name, opts);
|
|
1432
|
+
}
|
|
1433
|
+
function handlerResultToNode(raw, signal) {
|
|
1434
|
+
if (isNodeLike(raw)) {
|
|
1435
|
+
return raw;
|
|
1436
|
+
}
|
|
1437
|
+
if (raw != null && typeof raw.then === "function") {
|
|
1438
|
+
return (0, import_extra6.fromPromise)(raw, { signal });
|
|
1439
|
+
}
|
|
1440
|
+
if (raw != null && typeof raw === "object" && Symbol.asyncIterator in raw) {
|
|
1441
|
+
return (0, import_extra6.fromAsyncIter)(raw, { signal });
|
|
1442
|
+
}
|
|
1443
|
+
return (0, import_extra6.fromPromise)(Promise.resolve(raw), { signal });
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
// src/presets/ai/agent-loop.ts
|
|
1447
|
+
var AgentLoopGraph = class extends import_graph5.Graph {
|
|
1448
|
+
chat;
|
|
1449
|
+
tools;
|
|
1450
|
+
/** Current agent status. `initial: "idle"` — always has a real value. */
|
|
1451
|
+
status;
|
|
1452
|
+
/** Turn count (completed LLM invocations this run). `initial: 0`. */
|
|
1453
|
+
turn;
|
|
1454
|
+
/** Aborted flag; flipped by `abort()` or external `AbortSignal`. `initial: false`. */
|
|
1455
|
+
aborted;
|
|
1456
|
+
/**
|
|
1457
|
+
* Most recent LLM response. State-backed mirror driven by the response
|
|
1458
|
+
* effect. **Stays SENTINEL** (`cache === undefined`, no DATA emitted)
|
|
1459
|
+
* until the first real response — bridge subscribers see no spurious
|
|
1460
|
+
* push-on-subscribe DATA. After a real response, holds the latest
|
|
1461
|
+
* `LLMResponse`. Reset between `run()` calls via `[[INVALIDATE]]` (clears
|
|
1462
|
+
* cache back to SENTINEL) so a second run with a pre-aborted signal
|
|
1463
|
+
* cannot leak the prior run's response. Bridge with
|
|
1464
|
+
* `awaitSettled(lastResponse)` for the first DATA as a Promise; consumers
|
|
1465
|
+
* inside reactive fns gate on `ctx.prevData[i] === undefined`.
|
|
1466
|
+
*/
|
|
1467
|
+
lastResponse;
|
|
1468
|
+
/** Tool-call batch emitted by the most recent LLM response. SENTINEL. */
|
|
1469
|
+
toolCalls;
|
|
1470
|
+
/** Tool-result batch (one entry per call) after reactive execution. SENTINEL. */
|
|
1471
|
+
toolResults;
|
|
1472
|
+
_terminalResult;
|
|
1473
|
+
_disposeRunWiring;
|
|
1474
|
+
/** Guards against overlapping `run()` calls. */
|
|
1475
|
+
_running = false;
|
|
1476
|
+
/**
|
|
1477
|
+
* Abort controller for the currently-running `adapter.invoke`. Minted per
|
|
1478
|
+
* switchMap project; aborted when the reactive `aborted` node flips true
|
|
1479
|
+
* OR when the caller's external `AbortSignal` fires. Threaded into
|
|
1480
|
+
* `adapter.invoke({ signal })` AND `fromAny(promise, { signal })`, so the
|
|
1481
|
+
* reactive layer sees ERROR when the wire call is cancelled.
|
|
1482
|
+
*/
|
|
1483
|
+
_currentAbortController = null;
|
|
1484
|
+
constructor(name, opts) {
|
|
1485
|
+
super(name, opts.graph);
|
|
1486
|
+
this.chat = chatStream(`${name}-chat`, { maxMessages: opts.maxMessages });
|
|
1487
|
+
this.mount("chat", this.chat);
|
|
1488
|
+
this.tools = toolRegistry(`${name}-tools`);
|
|
1489
|
+
this.mount("tools", this.tools);
|
|
1490
|
+
if (opts.tools) {
|
|
1491
|
+
for (const tool of opts.tools) {
|
|
1492
|
+
this.tools.register(tool);
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
this.status = (0, import_core11.node)([], {
|
|
1496
|
+
...{
|
|
1497
|
+
name: "status",
|
|
1498
|
+
describeKind: "state",
|
|
1499
|
+
meta: aiMeta("agent_status")
|
|
1500
|
+
},
|
|
1501
|
+
initial: "idle"
|
|
1502
|
+
});
|
|
1503
|
+
this.add(this.status, { name: "status" });
|
|
1504
|
+
this.turn = (0, import_core11.node)([], {
|
|
1505
|
+
...{
|
|
1506
|
+
name: "turn",
|
|
1507
|
+
describeKind: "state",
|
|
1508
|
+
meta: aiMeta("agent_turn_count")
|
|
1509
|
+
},
|
|
1510
|
+
initial: 0
|
|
1511
|
+
});
|
|
1512
|
+
this.add(this.turn, { name: "turn" });
|
|
1513
|
+
this.aborted = (0, import_core11.node)([], {
|
|
1514
|
+
...{
|
|
1515
|
+
name: "aborted",
|
|
1516
|
+
describeKind: "state",
|
|
1517
|
+
meta: aiMeta("agent_aborted")
|
|
1518
|
+
},
|
|
1519
|
+
initial: false
|
|
1520
|
+
});
|
|
1521
|
+
this.add(this.aborted, { name: "aborted" });
|
|
1522
|
+
let latestTurn = 0;
|
|
1523
|
+
const turnSub = this.turn.subscribe((msgs) => {
|
|
1524
|
+
for (const m of msgs) if (m[0] === import_core11.DATA) latestTurn = m[1];
|
|
1525
|
+
});
|
|
1526
|
+
let latestAborted = false;
|
|
1527
|
+
const abortedSub = this.aborted.subscribe((msgs) => {
|
|
1528
|
+
for (const m of msgs) if (m[0] === import_core11.DATA) latestAborted = m[1];
|
|
1529
|
+
});
|
|
1530
|
+
const adapter = opts.adapter;
|
|
1531
|
+
const systemPrompt = opts.systemPrompt;
|
|
1532
|
+
const model = opts.model;
|
|
1533
|
+
const temperature = opts.temperature;
|
|
1534
|
+
const maxTokens = opts.maxTokens;
|
|
1535
|
+
const maxTurns = opts.maxTurns ?? 10;
|
|
1536
|
+
const stopWhen = opts.stopWhen;
|
|
1537
|
+
const chat = this.chat;
|
|
1538
|
+
const tools = this.tools;
|
|
1539
|
+
const statusNode = this.status;
|
|
1540
|
+
const turnNode = this.turn;
|
|
1541
|
+
const abortedNode = this.aborted;
|
|
1542
|
+
const promptInput = (0, import_core11.node)(
|
|
1543
|
+
[statusNode],
|
|
1544
|
+
(data, actions, ctx) => {
|
|
1545
|
+
const stat = readLatest(data, ctx.prevData, 0, "idle");
|
|
1546
|
+
if (stat !== "thinking" || latestAborted || latestTurn >= maxTurns) {
|
|
1547
|
+
actions.down([[import_core11.RESOLVED]]);
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1550
|
+
const messages = this.chat.messages.cache ?? [];
|
|
1551
|
+
if (messages.length === 0) {
|
|
1552
|
+
actions.down([[import_core11.RESOLVED]]);
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
const schemas = this.tools.schemas.cache ?? [];
|
|
1556
|
+
actions.emit({ messages, tools: schemas });
|
|
1557
|
+
},
|
|
1558
|
+
{
|
|
1559
|
+
name: "promptInput",
|
|
1560
|
+
describeKind: "derived",
|
|
1561
|
+
meta: aiMeta("agent_prompt_input", {
|
|
1562
|
+
// State this fn body samples beyond its declared `statusNode`
|
|
1563
|
+
// dep. `aborted` / `turn` come from §28 closure mirrors
|
|
1564
|
+
// (`latestAborted` / `latestTurn`); `chat.messages` /
|
|
1565
|
+
// `tools.schemas` come from sole-owner `.cache` reads
|
|
1566
|
+
// (Phase 12 D1 lock + F2 fix; see comment block above).
|
|
1567
|
+
// Listed here so inspection tooling can surface fold-in
|
|
1568
|
+
// state without grepping source.
|
|
1569
|
+
closureReads: ["aborted", "turn", "chat.messages", "tools.schemas"]
|
|
1570
|
+
})
|
|
1571
|
+
}
|
|
1572
|
+
);
|
|
1573
|
+
const llmResponse = (0, import_extra7.switchMap)(
|
|
1574
|
+
promptInput,
|
|
1575
|
+
(input) => {
|
|
1576
|
+
const controller = new AbortController();
|
|
1577
|
+
this._currentAbortController = controller;
|
|
1578
|
+
if (latestAborted) {
|
|
1579
|
+
controller.abort(new Error("agentLoop: aborted"));
|
|
1580
|
+
}
|
|
1581
|
+
return (0, import_extra7.fromAny)(
|
|
1582
|
+
adapter.invoke(input.messages, {
|
|
1583
|
+
tools: input.tools.length > 0 ? input.tools : void 0,
|
|
1584
|
+
systemPrompt,
|
|
1585
|
+
model,
|
|
1586
|
+
temperature,
|
|
1587
|
+
maxTokens,
|
|
1588
|
+
signal: controller.signal
|
|
1589
|
+
}),
|
|
1590
|
+
{ signal: controller.signal }
|
|
1591
|
+
);
|
|
1592
|
+
},
|
|
1593
|
+
{ equals: () => false }
|
|
1594
|
+
);
|
|
1595
|
+
const lastResponseState = (0, import_core11.node)([], {
|
|
1596
|
+
name: "lastResponse",
|
|
1597
|
+
describeKind: "state",
|
|
1598
|
+
meta: aiMeta("agent_last_response")
|
|
1599
|
+
});
|
|
1600
|
+
this.lastResponse = lastResponseState;
|
|
1601
|
+
const toolCallsRaw = (0, import_core11.node)(
|
|
1602
|
+
[lastResponseState, statusNode],
|
|
1603
|
+
(data, actions, ctx) => {
|
|
1604
|
+
const resp = readLatest(data, ctx.prevData, 0, void 0);
|
|
1605
|
+
const stat = readLatest(data, ctx.prevData, 1, "idle");
|
|
1606
|
+
if (stat !== "acting") {
|
|
1607
|
+
actions.down([[import_core11.RESOLVED]]);
|
|
1608
|
+
return;
|
|
1609
|
+
}
|
|
1610
|
+
const calls = resp?.toolCalls;
|
|
1611
|
+
if (calls == null || calls.length === 0) {
|
|
1612
|
+
actions.down([[import_core11.RESOLVED]]);
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
1615
|
+
actions.emit(calls);
|
|
1616
|
+
},
|
|
1617
|
+
{
|
|
1618
|
+
name: "toolCallsRaw",
|
|
1619
|
+
describeKind: "derived",
|
|
1620
|
+
meta: aiMeta("agent_tool_calls_raw")
|
|
1621
|
+
}
|
|
1622
|
+
);
|
|
1623
|
+
const gatedToolCallsNode = opts.interceptToolCalls ? opts.interceptToolCalls(toolCallsRaw) : toolCallsRaw;
|
|
1624
|
+
this.toolCalls = gatedToolCallsNode;
|
|
1625
|
+
const toolResultsNode = toolExecution({
|
|
1626
|
+
toolCalls: gatedToolCallsNode,
|
|
1627
|
+
tools,
|
|
1628
|
+
retryCount: 1
|
|
1629
|
+
});
|
|
1630
|
+
this.toolResults = toolResultsNode;
|
|
1631
|
+
const effResponse = (0, import_core11.node)(
|
|
1632
|
+
[llmResponse],
|
|
1633
|
+
(batchData, _actions, ctx) => {
|
|
1634
|
+
const data = batchData.map(
|
|
1635
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
1636
|
+
);
|
|
1637
|
+
if (latestAborted) return;
|
|
1638
|
+
const response = data[0];
|
|
1639
|
+
const next = latestTurn + 1;
|
|
1640
|
+
const hasToolCalls = response.toolCalls != null && response.toolCalls.length > 0;
|
|
1641
|
+
const naturalStop = response.finishReason === "end_turn" && (!response.toolCalls || response.toolCalls.length === 0);
|
|
1642
|
+
const customStop = stopWhen?.(response) === true;
|
|
1643
|
+
const capReached = next >= maxTurns;
|
|
1644
|
+
const nextStatus = customStop || naturalStop || !hasToolCalls || capReached ? "done" : "acting";
|
|
1645
|
+
(0, import_core11.batch)(() => {
|
|
1646
|
+
lastResponseState.emit(response);
|
|
1647
|
+
statusNode.emit(nextStatus);
|
|
1648
|
+
turnNode.emit(next);
|
|
1649
|
+
chat.append("assistant", response.content, {
|
|
1650
|
+
toolCalls: response.toolCalls
|
|
1651
|
+
});
|
|
1652
|
+
});
|
|
1653
|
+
},
|
|
1654
|
+
{ describeKind: "effect" }
|
|
1655
|
+
);
|
|
1656
|
+
const effResults = (0, import_core11.node)(
|
|
1657
|
+
[toolResultsNode],
|
|
1658
|
+
(batchData, _actions, ctx) => {
|
|
1659
|
+
const data = batchData.map(
|
|
1660
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
1661
|
+
);
|
|
1662
|
+
if (latestAborted) return;
|
|
1663
|
+
const arr = data[0];
|
|
1664
|
+
if (arr.length === 0) return;
|
|
1665
|
+
const nextStatus = latestTurn >= maxTurns ? "done" : "thinking";
|
|
1666
|
+
(0, import_core11.batch)(() => {
|
|
1667
|
+
statusNode.emit(nextStatus);
|
|
1668
|
+
for (const r of arr) chat.appendToolResult(r.id, r.content);
|
|
1669
|
+
});
|
|
1670
|
+
},
|
|
1671
|
+
{ describeKind: "effect" }
|
|
1672
|
+
);
|
|
1673
|
+
let latestStatus = statusNode.cache ?? "idle";
|
|
1674
|
+
const statusSub = statusNode.subscribe((msgs) => {
|
|
1675
|
+
for (const m of msgs) if (m[0] === import_core11.DATA) latestStatus = m[1];
|
|
1676
|
+
});
|
|
1677
|
+
const effAbort = (0, import_core11.node)(
|
|
1678
|
+
[abortedNode],
|
|
1679
|
+
(batchData, _actions, ctx) => {
|
|
1680
|
+
const data = batchData.map(
|
|
1681
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
1682
|
+
);
|
|
1683
|
+
if (data[0] === true) {
|
|
1684
|
+
this._currentAbortController?.abort(new Error("agentLoop: aborted"));
|
|
1685
|
+
if (latestStatus !== "done") statusNode.emit("done");
|
|
1686
|
+
}
|
|
1687
|
+
},
|
|
1688
|
+
{ describeKind: "effect" }
|
|
1689
|
+
);
|
|
1690
|
+
const kaResponse = (0, import_extra7.keepalive)(effResponse);
|
|
1691
|
+
const kaResults = (0, import_extra7.keepalive)(effResults);
|
|
1692
|
+
const kaAbort = (0, import_extra7.keepalive)(effAbort);
|
|
1693
|
+
this._terminalResult = (0, import_core11.node)(
|
|
1694
|
+
[statusNode, lastResponseState],
|
|
1695
|
+
(data, actions, ctx) => {
|
|
1696
|
+
const stat = readLatest(data, ctx.prevData, 0, "idle");
|
|
1697
|
+
const resp = readLatest(data, ctx.prevData, 1, void 0);
|
|
1698
|
+
if (stat === "done") {
|
|
1699
|
+
if (resp !== void 0) {
|
|
1700
|
+
actions.emit(resp);
|
|
1701
|
+
return;
|
|
1702
|
+
}
|
|
1703
|
+
const err = new Error("agentLoop: aborted");
|
|
1704
|
+
err.name = "AbortError";
|
|
1705
|
+
actions.down([[import_core11.ERROR, err]]);
|
|
1706
|
+
return;
|
|
1707
|
+
}
|
|
1708
|
+
if (stat === "error") {
|
|
1709
|
+
actions.down([[import_core11.ERROR, new Error("agentLoop: errored")]]);
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1712
|
+
actions.down([[import_core11.RESOLVED]]);
|
|
1713
|
+
},
|
|
1714
|
+
{
|
|
1715
|
+
name: "terminalResult",
|
|
1716
|
+
describeKind: "derived",
|
|
1717
|
+
meta: aiMeta("agent_terminal_result"),
|
|
1718
|
+
// `lastResponseState` is SENTINEL until the first real response
|
|
1719
|
+
// arrives — without `partial: true`, the spec §2.7 first-run
|
|
1720
|
+
// gate would block this fn from ever firing on the abort-
|
|
1721
|
+
// before-response path (`status → "done"` while `lastResponse`
|
|
1722
|
+
// has never delivered DATA). The fn explicitly handles the
|
|
1723
|
+
// SENTINEL case (`resp === undefined → ERROR(AbortError)`),
|
|
1724
|
+
// so partial-fire is safe by design.
|
|
1725
|
+
partial: true
|
|
1726
|
+
}
|
|
1727
|
+
);
|
|
1728
|
+
this.add(promptInput, { name: "promptInput" });
|
|
1729
|
+
this.add(llmResponse, { name: "llmResponse" });
|
|
1730
|
+
this.add(this.lastResponse, { name: "lastResponse" });
|
|
1731
|
+
if (this.toolCalls === toolCallsRaw) {
|
|
1732
|
+
this.add(this.toolCalls, { name: "toolCalls" });
|
|
1733
|
+
} else {
|
|
1734
|
+
this.add(toolCallsRaw, { name: "toolCallsRaw" });
|
|
1735
|
+
this.add(this.toolCalls, { name: "toolCalls" });
|
|
1736
|
+
}
|
|
1737
|
+
this.add(toolResultsNode, { name: "toolResults" });
|
|
1738
|
+
this.add(this._terminalResult, { name: "terminalResult" });
|
|
1739
|
+
this.addDisposer(turnSub);
|
|
1740
|
+
this.addDisposer(abortedSub);
|
|
1741
|
+
this.addDisposer(statusSub);
|
|
1742
|
+
this.addDisposer(kaResponse);
|
|
1743
|
+
this.addDisposer(kaResults);
|
|
1744
|
+
this.addDisposer(kaAbort);
|
|
1745
|
+
this._disposeRunWiring = () => {
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
/**
|
|
1749
|
+
* Bridge to `Promise<LLMResponse>` over the reactive pipeline.
|
|
1750
|
+
*
|
|
1751
|
+
* - If `userMessage` is provided, appends it as a user message and
|
|
1752
|
+
* transitions status to `"thinking"` to kick the loop.
|
|
1753
|
+
* - If `signal` is provided, binds it to the reactive `aborted` node
|
|
1754
|
+
* AND threads into `adapter.invoke({ signal })` so the wire call can
|
|
1755
|
+
* cancel mid-flight. The reactive `aborted` state + effect 3 guarantee
|
|
1756
|
+
* that even an adapter that ignores `signal` will stop emitting into
|
|
1757
|
+
* the agent graph.
|
|
1758
|
+
* - Resolves when `status === "done"` with the final LLM response.
|
|
1759
|
+
* Rejects with `AbortError` when the abort signal fires pre-response.
|
|
1760
|
+
* Rejects with the stage error when `status === "error"`.
|
|
1761
|
+
*
|
|
1762
|
+
* **Concurrency:** `run()` refuses to overlap with a pending call on the
|
|
1763
|
+
* same agent. Attempting to call `run()` while a previous `run()` is
|
|
1764
|
+
* still in-flight throws a `RangeError` immediately. Stale-resolution
|
|
1765
|
+
* safety is provided by `awaitSettled({skipCurrent: true})`, which
|
|
1766
|
+
* ignores the cached initial DATA from any previous run and resolves
|
|
1767
|
+
* only on a fresh post-subscribe emission of `_terminalResult`.
|
|
1768
|
+
*/
|
|
1769
|
+
async run(userMessage, signal) {
|
|
1770
|
+
if (this._running) {
|
|
1771
|
+
throw new RangeError(
|
|
1772
|
+
`agentLoop "${this.name}": run() called while a previous run() is still pending \u2014 await the previous run before starting another, or call abort() first`
|
|
1773
|
+
);
|
|
1774
|
+
}
|
|
1775
|
+
this._running = true;
|
|
1776
|
+
let offAbort;
|
|
1777
|
+
try {
|
|
1778
|
+
(0, import_core11.batch)(() => {
|
|
1779
|
+
this.lastResponse.down([[import_core11.INVALIDATE]]);
|
|
1780
|
+
this.turn.emit(0);
|
|
1781
|
+
this.aborted.emit(false);
|
|
1782
|
+
this.status.emit("idle");
|
|
1783
|
+
});
|
|
1784
|
+
if (userMessage != null) this.chat.append("user", userMessage);
|
|
1785
|
+
const resultPromise = awaitSettled(this._terminalResult, { skipCurrent: true });
|
|
1786
|
+
if (signal != null) {
|
|
1787
|
+
if (signal.aborted) {
|
|
1788
|
+
this.aborted.emit(true);
|
|
1789
|
+
} else {
|
|
1790
|
+
const listener = () => this.aborted.emit(true);
|
|
1791
|
+
signal.addEventListener("abort", listener, { once: true });
|
|
1792
|
+
offAbort = () => signal.removeEventListener("abort", listener);
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
if (signal?.aborted !== true) {
|
|
1796
|
+
this.status.emit("thinking");
|
|
1797
|
+
}
|
|
1798
|
+
return await resultPromise;
|
|
1799
|
+
} finally {
|
|
1800
|
+
offAbort?.();
|
|
1801
|
+
this._running = false;
|
|
1802
|
+
this._currentAbortController = null;
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
/**
|
|
1806
|
+
* Flip the reactive `aborted` state. Equivalent to setting an external
|
|
1807
|
+
* `AbortSignal` — the pipeline observes and transitions to `"done"`.
|
|
1808
|
+
*/
|
|
1809
|
+
abort() {
|
|
1810
|
+
this.aborted.emit(true);
|
|
1811
|
+
}
|
|
1812
|
+
destroy() {
|
|
1813
|
+
try {
|
|
1814
|
+
this._disposeRunWiring();
|
|
1815
|
+
} catch {
|
|
1816
|
+
}
|
|
1817
|
+
super.destroy();
|
|
1818
|
+
}
|
|
1819
|
+
};
|
|
1820
|
+
function readLatest(batchData, prevData, index, fallback) {
|
|
1821
|
+
const batch8 = batchData[index];
|
|
1822
|
+
if (batch8 != null && batch8.length > 0) return batch8[batch8.length - 1];
|
|
1823
|
+
const prev = prevData[index];
|
|
1824
|
+
return prev !== void 0 ? prev : fallback;
|
|
1825
|
+
}
|
|
1826
|
+
function agentLoop(name, opts) {
|
|
1827
|
+
const g = new AgentLoopGraph(name, opts);
|
|
1828
|
+
g.tagFactory("agentLoop", (0, import_core11.placeholderArgs)(opts));
|
|
1829
|
+
return g;
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
// src/presets/ai/agent.ts
|
|
1833
|
+
var EMPTY_INPUT = Object.freeze({ regular: 0 });
|
|
1834
|
+
var EMPTY_OUTPUT = Object.freeze({ regular: 0 });
|
|
1835
|
+
var EMPTY_USAGE = Object.freeze({ input: EMPTY_INPUT, output: EMPTY_OUTPUT });
|
|
1836
|
+
var ZERO_COST = Object.freeze({ usage: EMPTY_USAGE, turns: 0 });
|
|
1837
|
+
function addOptional(a, b) {
|
|
1838
|
+
if (a == null && b == null) return void 0;
|
|
1839
|
+
return (a ?? 0) + (b ?? 0);
|
|
1840
|
+
}
|
|
1841
|
+
function addExtensions(a, b) {
|
|
1842
|
+
if (a == null && b == null) return void 0;
|
|
1843
|
+
const out = { ...a ?? {} };
|
|
1844
|
+
for (const [k, v] of Object.entries(b ?? {})) {
|
|
1845
|
+
out[k] = (out[k] ?? 0) + v;
|
|
1846
|
+
}
|
|
1847
|
+
return out;
|
|
1848
|
+
}
|
|
1849
|
+
function addUsage(a, b) {
|
|
1850
|
+
const out = {
|
|
1851
|
+
input: {
|
|
1852
|
+
regular: a.input.regular + b.input.regular,
|
|
1853
|
+
...addOptional(a.input.cacheRead, b.input.cacheRead) !== void 0 && {
|
|
1854
|
+
cacheRead: addOptional(a.input.cacheRead, b.input.cacheRead)
|
|
1855
|
+
},
|
|
1856
|
+
...addOptional(a.input.cacheWrite5m, b.input.cacheWrite5m) !== void 0 && {
|
|
1857
|
+
cacheWrite5m: addOptional(a.input.cacheWrite5m, b.input.cacheWrite5m)
|
|
1858
|
+
},
|
|
1859
|
+
...addOptional(a.input.cacheWrite1h, b.input.cacheWrite1h) !== void 0 && {
|
|
1860
|
+
cacheWrite1h: addOptional(a.input.cacheWrite1h, b.input.cacheWrite1h)
|
|
1861
|
+
},
|
|
1862
|
+
...addOptional(a.input.cacheWriteOther, b.input.cacheWriteOther) !== void 0 && {
|
|
1863
|
+
cacheWriteOther: addOptional(a.input.cacheWriteOther, b.input.cacheWriteOther)
|
|
1864
|
+
},
|
|
1865
|
+
...addOptional(a.input.audio, b.input.audio) !== void 0 && {
|
|
1866
|
+
audio: addOptional(a.input.audio, b.input.audio)
|
|
1867
|
+
},
|
|
1868
|
+
...addOptional(a.input.image, b.input.image) !== void 0 && {
|
|
1869
|
+
image: addOptional(a.input.image, b.input.image)
|
|
1870
|
+
},
|
|
1871
|
+
...addOptional(a.input.video, b.input.video) !== void 0 && {
|
|
1872
|
+
video: addOptional(a.input.video, b.input.video)
|
|
1873
|
+
},
|
|
1874
|
+
...addOptional(a.input.toolUse, b.input.toolUse) !== void 0 && {
|
|
1875
|
+
toolUse: addOptional(a.input.toolUse, b.input.toolUse)
|
|
1876
|
+
},
|
|
1877
|
+
...addExtensions(a.input.extensions, b.input.extensions) !== void 0 && {
|
|
1878
|
+
extensions: addExtensions(a.input.extensions, b.input.extensions)
|
|
1879
|
+
}
|
|
1880
|
+
},
|
|
1881
|
+
output: {
|
|
1882
|
+
regular: a.output.regular + b.output.regular,
|
|
1883
|
+
...addOptional(a.output.reasoning, b.output.reasoning) !== void 0 && {
|
|
1884
|
+
reasoning: addOptional(a.output.reasoning, b.output.reasoning)
|
|
1885
|
+
},
|
|
1886
|
+
...addOptional(a.output.audio, b.output.audio) !== void 0 && {
|
|
1887
|
+
audio: addOptional(a.output.audio, b.output.audio)
|
|
1888
|
+
},
|
|
1889
|
+
...addOptional(a.output.predictionAccepted, b.output.predictionAccepted) !== void 0 && {
|
|
1890
|
+
predictionAccepted: addOptional(
|
|
1891
|
+
a.output.predictionAccepted,
|
|
1892
|
+
b.output.predictionAccepted
|
|
1893
|
+
)
|
|
1894
|
+
},
|
|
1895
|
+
...addOptional(a.output.predictionRejected, b.output.predictionRejected) !== void 0 && {
|
|
1896
|
+
predictionRejected: addOptional(
|
|
1897
|
+
a.output.predictionRejected,
|
|
1898
|
+
b.output.predictionRejected
|
|
1899
|
+
)
|
|
1900
|
+
},
|
|
1901
|
+
...addExtensions(a.output.extensions, b.output.extensions) !== void 0 && {
|
|
1902
|
+
extensions: addExtensions(a.output.extensions, b.output.extensions)
|
|
1903
|
+
}
|
|
1904
|
+
},
|
|
1905
|
+
...addExtensions(a.auxiliary, b.auxiliary) !== void 0 && {
|
|
1906
|
+
auxiliary: addExtensions(a.auxiliary, b.auxiliary)
|
|
1907
|
+
}
|
|
1908
|
+
};
|
|
1909
|
+
return out;
|
|
1910
|
+
}
|
|
1911
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["done", "error"]);
|
|
1912
|
+
var AgentGraph = class extends import_graph6.Graph {
|
|
1913
|
+
/** The agent's typed inbox. Writable; `in.emit(value)` kicks the loop. */
|
|
1914
|
+
in;
|
|
1915
|
+
/** The agent's typed outbox. SENTINEL until first response. */
|
|
1916
|
+
out;
|
|
1917
|
+
/** Lifecycle status (translated from the underlying loop's substates). */
|
|
1918
|
+
status;
|
|
1919
|
+
/** Cumulative cost for the current / most-recent input. */
|
|
1920
|
+
cost;
|
|
1921
|
+
/** The underlying agentLoop — exposed for inspection / advanced wiring. */
|
|
1922
|
+
loop;
|
|
1923
|
+
/** Optional shared memory subgraph (mounted at `memory/` if provided). */
|
|
1924
|
+
memory;
|
|
1925
|
+
constructor(spec, opts) {
|
|
1926
|
+
super(spec.name, opts);
|
|
1927
|
+
const initialTools = Array.isArray(spec.tools) ? spec.tools : void 0;
|
|
1928
|
+
this.loop = agentLoop(`${spec.name}-loop`, {
|
|
1929
|
+
adapter: spec.adapter,
|
|
1930
|
+
...spec.systemPrompt != null ? { systemPrompt: spec.systemPrompt } : {},
|
|
1931
|
+
...initialTools != null ? { tools: initialTools } : {},
|
|
1932
|
+
...spec.maxIterations != null ? { maxTurns: spec.maxIterations } : {}
|
|
1933
|
+
});
|
|
1934
|
+
this.mount("loop", this.loop);
|
|
1935
|
+
if (spec.tools != null && !Array.isArray(spec.tools)) {
|
|
1936
|
+
const toolsNode = spec.tools;
|
|
1937
|
+
const registered = /* @__PURE__ */ new Set();
|
|
1938
|
+
const unsubTools = toolsNode.subscribe((msgs) => {
|
|
1939
|
+
for (const m of msgs) {
|
|
1940
|
+
if (m[0] !== import_core12.DATA) continue;
|
|
1941
|
+
const next = m[1];
|
|
1942
|
+
const nextNames = new Set(next.map((t) => t.name));
|
|
1943
|
+
for (const name of registered) {
|
|
1944
|
+
if (!nextNames.has(name)) {
|
|
1945
|
+
this.loop.tools.unregister(name);
|
|
1946
|
+
registered.delete(name);
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
for (const tool of next) {
|
|
1950
|
+
if (!registered.has(tool.name)) {
|
|
1951
|
+
this.loop.tools.register(tool);
|
|
1952
|
+
registered.add(tool.name);
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
});
|
|
1957
|
+
this.addDisposer(unsubTools);
|
|
1958
|
+
}
|
|
1959
|
+
this.memory = spec.memory ?? null;
|
|
1960
|
+
if (this.memory != null) {
|
|
1961
|
+
this.mount("memory", this.memory);
|
|
1962
|
+
}
|
|
1963
|
+
this.in = (0, import_core12.node)([], {
|
|
1964
|
+
name: "in",
|
|
1965
|
+
describeKind: "state",
|
|
1966
|
+
meta: aiMeta("agent_in"),
|
|
1967
|
+
equals: () => false
|
|
1968
|
+
});
|
|
1969
|
+
this.add(this.in, { name: "in" });
|
|
1970
|
+
const costNode = (0, import_core12.node)([], {
|
|
1971
|
+
name: "cost",
|
|
1972
|
+
describeKind: "state",
|
|
1973
|
+
meta: aiMeta("agent_cost"),
|
|
1974
|
+
initial: ZERO_COST
|
|
1975
|
+
});
|
|
1976
|
+
this.add(costNode, { name: "cost" });
|
|
1977
|
+
this.cost = costNode;
|
|
1978
|
+
const outMapper = spec.outMapper ?? defaultOutMapper();
|
|
1979
|
+
const outNode = (0, import_core12.node)(
|
|
1980
|
+
[this.loop.lastResponse],
|
|
1981
|
+
(data, a, ctx) => {
|
|
1982
|
+
const batch0 = data[0];
|
|
1983
|
+
const resp = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0];
|
|
1984
|
+
if (resp === void 0) {
|
|
1985
|
+
a.down([[import_core12.RESOLVED]]);
|
|
1986
|
+
return;
|
|
1987
|
+
}
|
|
1988
|
+
a.emit(outMapper(resp));
|
|
1989
|
+
},
|
|
1990
|
+
{
|
|
1991
|
+
name: "out",
|
|
1992
|
+
describeKind: "derived",
|
|
1993
|
+
meta: aiMeta("agent_out"),
|
|
1994
|
+
// Each in.emit may produce a structurally-equal response (e.g.
|
|
1995
|
+
// from a deterministic adapter) — disable framework dedup so
|
|
1996
|
+
// repeat emits propagate and `awaitSettled({skipCurrent:true})`
|
|
1997
|
+
// sees them. Callers can wrap with `distinctUntilChanged` if
|
|
1998
|
+
// they want change-only semantics.
|
|
1999
|
+
equals: () => false
|
|
2000
|
+
}
|
|
2001
|
+
);
|
|
2002
|
+
this.add(outNode, { name: "out" });
|
|
2003
|
+
this.out = outNode;
|
|
2004
|
+
const statusNode = (0, import_core12.node)([], {
|
|
2005
|
+
name: "status",
|
|
2006
|
+
describeKind: "state",
|
|
2007
|
+
meta: aiMeta("agent_status"),
|
|
2008
|
+
initial: "idle"
|
|
2009
|
+
});
|
|
2010
|
+
this.add(statusNode, { name: "status" });
|
|
2011
|
+
this.status = statusNode;
|
|
2012
|
+
const statusMirrorEff = (0, import_core12.node)(
|
|
2013
|
+
[this.loop.status],
|
|
2014
|
+
(data, _a, ctx) => {
|
|
2015
|
+
const batch0 = data[0];
|
|
2016
|
+
const loopStatus = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0] ?? "idle";
|
|
2017
|
+
const next = loopStatus === "idle" ? "idle" : loopStatus === "thinking" || loopStatus === "acting" ? "running" : loopStatus === "done" ? "done" : loopStatus === "error" ? "error" : "idle";
|
|
2018
|
+
if (statusNode.cache !== next) statusNode.emit(next);
|
|
2019
|
+
},
|
|
2020
|
+
{ describeKind: "effect", meta: aiMeta("agent_status_mirror") }
|
|
2021
|
+
);
|
|
2022
|
+
this.addDisposer((0, import_extra8.keepalive)(statusMirrorEff));
|
|
2023
|
+
const costEff = (0, import_core12.node)(
|
|
2024
|
+
[this.loop.lastResponse],
|
|
2025
|
+
(data, _a, ctx) => {
|
|
2026
|
+
const batch0 = data[0];
|
|
2027
|
+
const resp = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0];
|
|
2028
|
+
if (resp === void 0) return;
|
|
2029
|
+
const prev = costNode.cache ?? ZERO_COST;
|
|
2030
|
+
const turns = this.loop.turn.cache ?? prev.turns;
|
|
2031
|
+
const next = {
|
|
2032
|
+
usage: resp.usage != null ? addUsage(prev.usage, resp.usage) : prev.usage,
|
|
2033
|
+
turns
|
|
2034
|
+
};
|
|
2035
|
+
costNode.emit(next);
|
|
2036
|
+
},
|
|
2037
|
+
{ describeKind: "effect", meta: aiMeta("agent_cost_rollup") }
|
|
2038
|
+
);
|
|
2039
|
+
this.addDisposer((0, import_extra8.keepalive)(costEff));
|
|
2040
|
+
const inMapper = spec.inMapper ?? defaultInMapper();
|
|
2041
|
+
const inputTopic = topic("input-topic");
|
|
2042
|
+
this.mount("input-topic", inputTopic);
|
|
2043
|
+
const inputSub = subscription("input-sub", inputTopic, {
|
|
2044
|
+
from: "now"
|
|
2045
|
+
});
|
|
2046
|
+
this.mount("input-sub", inputSub);
|
|
2047
|
+
const inputBridge = this.in.subscribe((msgs) => {
|
|
2048
|
+
for (const m of msgs) {
|
|
2049
|
+
if (m[0] !== import_core12.DATA) continue;
|
|
2050
|
+
const input = m[1];
|
|
2051
|
+
inMapper(input);
|
|
2052
|
+
inputTopic.publish(input);
|
|
2053
|
+
}
|
|
2054
|
+
});
|
|
2055
|
+
this.addDisposer(inputBridge);
|
|
2056
|
+
const drainEffect = (0, import_core12.node)(
|
|
2057
|
+
[inputSub.available, this.loop.status],
|
|
2058
|
+
(data, _a, ctx) => {
|
|
2059
|
+
const availBatch = data[0];
|
|
2060
|
+
const statusBatch = data[1];
|
|
2061
|
+
const avail = (availBatch != null && availBatch.length > 0 ? availBatch.at(-1) : ctx.prevData[0] ?? []) ?? [];
|
|
2062
|
+
const stat = (statusBatch != null && statusBatch.length > 0 ? statusBatch.at(-1) : ctx.prevData[1] ?? "idle") ?? "idle";
|
|
2063
|
+
if (avail.length === 0) return;
|
|
2064
|
+
if (stat === "thinking" || stat === "acting") return;
|
|
2065
|
+
const result = inputSub.pullAndAck(1);
|
|
2066
|
+
if (result.items.length === 0) return;
|
|
2067
|
+
const input = result.items[0];
|
|
2068
|
+
const userMsg = inMapper(input);
|
|
2069
|
+
(0, import_core12.batch)(() => {
|
|
2070
|
+
this.loop.lastResponse.down([[import_core12.INVALIDATE]]);
|
|
2071
|
+
this.loop.turn.emit(0);
|
|
2072
|
+
this.loop.aborted.emit(false);
|
|
2073
|
+
costNode.emit(ZERO_COST);
|
|
2074
|
+
this.loop.chat.append("user", userMsg);
|
|
2075
|
+
this.loop.status.emit("thinking");
|
|
2076
|
+
});
|
|
2077
|
+
},
|
|
2078
|
+
{ describeKind: "effect", meta: aiMeta("agent_input_drain") }
|
|
2079
|
+
);
|
|
2080
|
+
this.addDisposer((0, import_extra8.keepalive)(drainEffect));
|
|
2081
|
+
this.addDisposer((0, import_extra8.keepalive)(this.out));
|
|
2082
|
+
void TERMINAL_STATUSES;
|
|
2083
|
+
}
|
|
2084
|
+
};
|
|
2085
|
+
function defaultInMapper() {
|
|
2086
|
+
return (input) => {
|
|
2087
|
+
if (typeof input !== "string") {
|
|
2088
|
+
throw new TypeError(
|
|
2089
|
+
`agent: inMapper is required when TIn is not a string (got ${typeof input}). Pass spec.inMapper.`
|
|
2090
|
+
);
|
|
2091
|
+
}
|
|
2092
|
+
return input;
|
|
2093
|
+
};
|
|
2094
|
+
}
|
|
2095
|
+
function defaultOutMapper() {
|
|
2096
|
+
return (response) => response;
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
// src/presets/ai/agent-memory.ts
|
|
2100
|
+
var import_core19 = require("@graphrefly/pure-ts/core");
|
|
2101
|
+
var import_extra15 = require("@graphrefly/pure-ts/extra");
|
|
2102
|
+
var import_graph9 = require("@graphrefly/pure-ts/graph");
|
|
2103
|
+
|
|
2104
|
+
// src/base/composition/distill.ts
|
|
2105
|
+
var import_core14 = require("@graphrefly/pure-ts/core");
|
|
2106
|
+
var import_extra11 = require("@graphrefly/pure-ts/extra");
|
|
2107
|
+
|
|
2108
|
+
// src/base/sources/async.ts
|
|
2109
|
+
var import_core13 = require("@graphrefly/pure-ts/core");
|
|
2110
|
+
var import_extra9 = require("@graphrefly/pure-ts/extra");
|
|
2111
|
+
var import_extra10 = require("@graphrefly/pure-ts/extra");
|
|
2112
|
+
function forEach(source, fn, opts) {
|
|
2113
|
+
const inner = (0, import_core13.node)(
|
|
2114
|
+
[source],
|
|
2115
|
+
(data, _actions) => {
|
|
2116
|
+
const batch0 = data[0];
|
|
2117
|
+
if (batch0 != null && batch0.length > 0) {
|
|
2118
|
+
for (const v of batch0) fn(v);
|
|
2119
|
+
}
|
|
2120
|
+
},
|
|
2121
|
+
{ describeKind: "effect", ...opts }
|
|
2122
|
+
);
|
|
2123
|
+
return inner.subscribe(() => {
|
|
2124
|
+
});
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
// src/base/composition/distill.ts
|
|
2128
|
+
function isNodeLike2(value) {
|
|
2129
|
+
return typeof value === "object" && value !== null && "cache" in value && typeof value.subscribe === "function";
|
|
2130
|
+
}
|
|
2131
|
+
function keepalive6(node20) {
|
|
2132
|
+
node20.subscribe(() => void 0);
|
|
2133
|
+
}
|
|
2134
|
+
function mapFromSnapshot(snapshot) {
|
|
2135
|
+
if (snapshot instanceof Map) return snapshot;
|
|
2136
|
+
return /* @__PURE__ */ new Map();
|
|
2137
|
+
}
|
|
2138
|
+
function applyExtraction(store, extraction) {
|
|
2139
|
+
if (!Array.isArray(extraction.upsert)) {
|
|
2140
|
+
throw new TypeError("distill extraction requires upsert: Array<{ key, value }>");
|
|
2141
|
+
}
|
|
2142
|
+
(0, import_core14.batch)(() => {
|
|
2143
|
+
for (const { key, value } of extraction.upsert) {
|
|
2144
|
+
store.set(key, value);
|
|
2145
|
+
}
|
|
2146
|
+
for (const key of extraction.remove ?? []) {
|
|
2147
|
+
store.delete(key);
|
|
2148
|
+
}
|
|
2149
|
+
});
|
|
2150
|
+
}
|
|
2151
|
+
function distill(source, extractFn, opts) {
|
|
2152
|
+
const sourceNode = (0, import_extra11.fromAny)(source);
|
|
2153
|
+
const store = (0, import_extra11.reactiveMap)(opts.mapOptions ?? {});
|
|
2154
|
+
const budget = opts.budget ?? 2e3;
|
|
2155
|
+
const hasContext = opts.context !== void 0 && opts.context !== null;
|
|
2156
|
+
const contextNode = hasContext ? (0, import_extra11.fromAny)(opts.context) : (0, import_core14.node)([], { initial: null });
|
|
2157
|
+
const extractionStream = (0, import_extra11.fromAny)(
|
|
2158
|
+
extractFn(sourceNode, store.entries)
|
|
2159
|
+
);
|
|
2160
|
+
forEach(extractionStream, (extraction) => {
|
|
2161
|
+
applyExtraction(store, extraction);
|
|
2162
|
+
});
|
|
2163
|
+
if (opts.evict) {
|
|
2164
|
+
const verdictUnsubs = /* @__PURE__ */ new Map();
|
|
2165
|
+
const evictionKeys = (0, import_core14.node)(
|
|
2166
|
+
[store.entries],
|
|
2167
|
+
(batchData, actions, ctx) => {
|
|
2168
|
+
const batch0 = batchData[0];
|
|
2169
|
+
const snapshot = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0];
|
|
2170
|
+
const out = [];
|
|
2171
|
+
const entries = mapFromSnapshot(snapshot);
|
|
2172
|
+
for (const key of verdictUnsubs.keys()) {
|
|
2173
|
+
if (!entries.has(key)) {
|
|
2174
|
+
verdictUnsubs.get(key)();
|
|
2175
|
+
verdictUnsubs.delete(key);
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
for (const [key, mem] of entries) {
|
|
2179
|
+
const verdict = opts.evict(key, mem);
|
|
2180
|
+
if (isNodeLike2(verdict)) {
|
|
2181
|
+
if (!verdictUnsubs.has(key)) {
|
|
2182
|
+
const unsub = forEach(verdict, (val) => {
|
|
2183
|
+
if (val === true && store.has(key)) {
|
|
2184
|
+
store.delete(key);
|
|
2185
|
+
}
|
|
2186
|
+
});
|
|
2187
|
+
verdictUnsubs.set(key, unsub);
|
|
2188
|
+
}
|
|
2189
|
+
continue;
|
|
2190
|
+
}
|
|
2191
|
+
if (typeof verdict === "boolean") {
|
|
2192
|
+
if (verdict) out.push(key);
|
|
2193
|
+
continue;
|
|
2194
|
+
}
|
|
2195
|
+
throw new TypeError("distill evict() must return boolean or Node<boolean>");
|
|
2196
|
+
}
|
|
2197
|
+
actions.emit(out);
|
|
2198
|
+
},
|
|
2199
|
+
{ describeKind: "derived" }
|
|
2200
|
+
);
|
|
2201
|
+
forEach(evictionKeys, (keys) => {
|
|
2202
|
+
for (const key of keys) store.delete(key);
|
|
2203
|
+
});
|
|
2204
|
+
}
|
|
2205
|
+
const hasConsolidateTrigger = opts.consolidateTrigger !== void 0 && opts.consolidateTrigger !== null;
|
|
2206
|
+
if (opts.consolidate && hasConsolidateTrigger) {
|
|
2207
|
+
const consolidateTriggerNode = (0, import_extra11.fromAny)(opts.consolidateTrigger);
|
|
2208
|
+
const consolidatePaired = (0, import_extra11.withLatestFrom)(
|
|
2209
|
+
consolidateTriggerNode,
|
|
2210
|
+
store.entries
|
|
2211
|
+
);
|
|
2212
|
+
const consolidationStream = (0, import_extra11.switchMap)(
|
|
2213
|
+
consolidatePaired,
|
|
2214
|
+
([, entries]) => opts.consolidate(mapFromSnapshot(entries))
|
|
2215
|
+
);
|
|
2216
|
+
forEach(consolidationStream, (extraction) => {
|
|
2217
|
+
applyExtraction(store, extraction);
|
|
2218
|
+
});
|
|
2219
|
+
}
|
|
2220
|
+
const compact = (0, import_core14.node)(
|
|
2221
|
+
[store.entries, contextNode],
|
|
2222
|
+
(batchData, actions, ctx) => {
|
|
2223
|
+
const data = batchData.map(
|
|
2224
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
2225
|
+
);
|
|
2226
|
+
const snapshot = data[0];
|
|
2227
|
+
const context = data[1];
|
|
2228
|
+
const map = mapFromSnapshot(snapshot);
|
|
2229
|
+
const entries = [...map.entries()].map(([key, value]) => ({
|
|
2230
|
+
key,
|
|
2231
|
+
value,
|
|
2232
|
+
score: opts.score(value, context),
|
|
2233
|
+
cost: opts.cost(value)
|
|
2234
|
+
}));
|
|
2235
|
+
entries.sort((a, b) => b.score - a.score);
|
|
2236
|
+
const packed = [];
|
|
2237
|
+
let remaining = budget;
|
|
2238
|
+
for (const item of entries) {
|
|
2239
|
+
if (item.cost <= remaining) {
|
|
2240
|
+
packed.push({ key: item.key, value: item.value, score: item.score });
|
|
2241
|
+
remaining -= item.cost;
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
actions.emit(packed);
|
|
2245
|
+
},
|
|
2246
|
+
{ describeKind: "derived", meta: { ...(0, import_core14.factoryTag)("distill", { budget }) } }
|
|
2247
|
+
);
|
|
2248
|
+
const size = (0, import_core14.node)(
|
|
2249
|
+
[store.entries],
|
|
2250
|
+
(batchData, actions, ctx) => {
|
|
2251
|
+
const batch0 = batchData[0];
|
|
2252
|
+
const snapshot = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0];
|
|
2253
|
+
actions.emit(mapFromSnapshot(snapshot).size);
|
|
2254
|
+
},
|
|
2255
|
+
{ describeKind: "derived" }
|
|
2256
|
+
);
|
|
2257
|
+
keepalive6(compact);
|
|
2258
|
+
keepalive6(size);
|
|
2259
|
+
return { store, compact, size };
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
// src/utils/ai/memory/memory-composers.ts
|
|
2263
|
+
var import_core16 = require("@graphrefly/pure-ts/core");
|
|
2264
|
+
var import_extra13 = require("@graphrefly/pure-ts/extra");
|
|
2265
|
+
var import_graph8 = require("@graphrefly/pure-ts/graph");
|
|
2266
|
+
|
|
2267
|
+
// src/base/utils/decay.ts
|
|
2268
|
+
var DEFAULT_DECAY_RATE = Math.LN2 / (7 * 86400);
|
|
2269
|
+
function decay(baseScore, ageSeconds2, ratePerSecond, minScore = 0) {
|
|
2270
|
+
if (!Number.isFinite(baseScore)) return minScore;
|
|
2271
|
+
if (!Number.isFinite(ageSeconds2) || ageSeconds2 <= 0) return Math.max(minScore, baseScore);
|
|
2272
|
+
if (!Number.isFinite(ratePerSecond) || ratePerSecond <= 0) return Math.max(minScore, baseScore);
|
|
2273
|
+
const decayed = baseScore * Math.exp(-ratePerSecond * ageSeconds2);
|
|
2274
|
+
return Math.max(minScore, decayed);
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2277
|
+
// src/utils/memory/index.ts
|
|
2278
|
+
var import_core15 = require("@graphrefly/pure-ts/core");
|
|
2279
|
+
var import_extra12 = require("@graphrefly/pure-ts/extra");
|
|
2280
|
+
var import_graph7 = require("@graphrefly/pure-ts/graph");
|
|
2281
|
+
var NS_PER_SEC2 = 1e9;
|
|
2282
|
+
function memoryMeta(kind, extra) {
|
|
2283
|
+
return domainMeta("memory", kind, extra);
|
|
2284
|
+
}
|
|
2285
|
+
function toNode(v, name) {
|
|
2286
|
+
if (v instanceof import_core15.NodeImpl) return v;
|
|
2287
|
+
return (0, import_core15.node)([], { initial: v, ...name ? { name } : void 0 });
|
|
2288
|
+
}
|
|
2289
|
+
function ageSeconds(now, lastNs) {
|
|
2290
|
+
return (now - lastNs) / NS_PER_SEC2;
|
|
2291
|
+
}
|
|
2292
|
+
function cosineSimilarity(a, b) {
|
|
2293
|
+
const n = Math.max(a.length, b.length);
|
|
2294
|
+
let dot = 0;
|
|
2295
|
+
let na = 0;
|
|
2296
|
+
let nb = 0;
|
|
2297
|
+
for (let i = 0; i < n; i += 1) {
|
|
2298
|
+
const av = a[i] ?? 0;
|
|
2299
|
+
const bv = b[i] ?? 0;
|
|
2300
|
+
dot += av * bv;
|
|
2301
|
+
na += av * av;
|
|
2302
|
+
nb += bv * bv;
|
|
2303
|
+
}
|
|
2304
|
+
if (na === 0 || nb === 0) return 0;
|
|
2305
|
+
const score = dot / Math.sqrt(na * nb);
|
|
2306
|
+
return Number.isFinite(score) ? score : 0;
|
|
2307
|
+
}
|
|
2308
|
+
function searchResultsEqual(a, b) {
|
|
2309
|
+
if (a === b) return true;
|
|
2310
|
+
if (a == null || b == null) return false;
|
|
2311
|
+
if (a.length !== b.length) return false;
|
|
2312
|
+
for (let i = 0; i < a.length; i += 1) {
|
|
2313
|
+
const x = a[i];
|
|
2314
|
+
const y = b[i];
|
|
2315
|
+
if (x.id !== y.id || x.score !== y.score || x.meta !== y.meta) return false;
|
|
2316
|
+
}
|
|
2317
|
+
return true;
|
|
2318
|
+
}
|
|
2319
|
+
function rankedEqual(a, b) {
|
|
2320
|
+
if (a === b) return true;
|
|
2321
|
+
if (a == null || b == null) return false;
|
|
2322
|
+
if (a.length !== b.length) return false;
|
|
2323
|
+
for (let i = 0; i < a.length; i += 1) {
|
|
2324
|
+
const x = a[i];
|
|
2325
|
+
const y = b[i];
|
|
2326
|
+
if (x.id !== y.id || x.score !== y.score || x.lastAccessNs !== y.lastAccessNs || x.value !== y.value)
|
|
2327
|
+
return false;
|
|
2328
|
+
}
|
|
2329
|
+
return true;
|
|
2330
|
+
}
|
|
2331
|
+
function collection(name, opts = {}) {
|
|
2332
|
+
const maxSize = opts.maxSize;
|
|
2333
|
+
const ranked = opts.ranked ?? true;
|
|
2334
|
+
const decayRate = ranked ? opts.decayRate ?? 0 : 0;
|
|
2335
|
+
const minScore = opts.minScore ?? 0;
|
|
2336
|
+
if (maxSize !== void 0 && maxSize < 1) {
|
|
2337
|
+
throw new RangeError("collection: maxSize must be >= 1");
|
|
2338
|
+
}
|
|
2339
|
+
const scoreFnDefault = () => ranked ? 1 : 0;
|
|
2340
|
+
const scoreInput = opts.score ?? scoreFnDefault;
|
|
2341
|
+
const scoreNode = ranked && scoreInput instanceof import_core15.NodeImpl ? scoreInput : void 0;
|
|
2342
|
+
const readScoreFn = () => {
|
|
2343
|
+
if (scoreNode) return scoreNode.cache ?? scoreFnDefault;
|
|
2344
|
+
return scoreInput;
|
|
2345
|
+
};
|
|
2346
|
+
const graph = new import_graph7.Graph(name);
|
|
2347
|
+
const retentionScore = (_k, v) => ranked ? decay(v.baseScore, ageSeconds((0, import_core15.monotonicNs)(), v.lastAccessNs), decayRate, minScore) : v.lastAccessNs;
|
|
2348
|
+
const items = (0, import_extra12.reactiveMap)({
|
|
2349
|
+
name: "items",
|
|
2350
|
+
...maxSize !== void 0 ? { retention: { score: retentionScore, maxSize } } : {}
|
|
2351
|
+
});
|
|
2352
|
+
graph.add(items.entries, { name: "items" });
|
|
2353
|
+
let refreshTick;
|
|
2354
|
+
if (ranked && decayRate > 0) {
|
|
2355
|
+
const intervalMs = opts.refreshIntervalMs ?? Math.max(1, 1e3 * Math.LN2 / (10 * decayRate));
|
|
2356
|
+
const tickCounter = (0, import_extra12.fromTimer)(intervalMs, { period: intervalMs });
|
|
2357
|
+
refreshTick = (0, import_core15.node)(
|
|
2358
|
+
[tickCounter],
|
|
2359
|
+
(_batchData, actions) => {
|
|
2360
|
+
actions.emit((0, import_core15.monotonicNs)());
|
|
2361
|
+
},
|
|
2362
|
+
{
|
|
2363
|
+
name: "refresh_tick_ns",
|
|
2364
|
+
describeKind: "derived",
|
|
2365
|
+
initial: (0, import_core15.monotonicNs)(),
|
|
2366
|
+
meta: memoryMeta("clock")
|
|
2367
|
+
}
|
|
2368
|
+
);
|
|
2369
|
+
graph.add(refreshTick, { name: "refresh_tick_ns" });
|
|
2370
|
+
}
|
|
2371
|
+
let rankedNode;
|
|
2372
|
+
if (ranked) {
|
|
2373
|
+
const rankedDeps = [items.entries];
|
|
2374
|
+
if (refreshTick) rankedDeps.push(refreshTick);
|
|
2375
|
+
if (scoreNode) rankedDeps.push(scoreNode);
|
|
2376
|
+
rankedNode = (0, import_core15.node)(
|
|
2377
|
+
rankedDeps,
|
|
2378
|
+
(batchData, actions, ctx) => {
|
|
2379
|
+
const values = batchData.map(
|
|
2380
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
2381
|
+
);
|
|
2382
|
+
const snapshot = values[0];
|
|
2383
|
+
let now;
|
|
2384
|
+
if (refreshTick) {
|
|
2385
|
+
const tickValue = values[1];
|
|
2386
|
+
now = typeof tickValue === "number" ? tickValue : (0, import_core15.monotonicNs)();
|
|
2387
|
+
} else {
|
|
2388
|
+
now = (0, import_core15.monotonicNs)();
|
|
2389
|
+
}
|
|
2390
|
+
if (!snapshot || snapshot.size === 0) {
|
|
2391
|
+
actions.emit([]);
|
|
2392
|
+
return;
|
|
2393
|
+
}
|
|
2394
|
+
const out2 = [];
|
|
2395
|
+
for (const entry of snapshot.values()) {
|
|
2396
|
+
out2.push({
|
|
2397
|
+
...entry,
|
|
2398
|
+
score: decay(entry.baseScore, ageSeconds(now, entry.lastAccessNs), decayRate, minScore)
|
|
2399
|
+
});
|
|
2400
|
+
}
|
|
2401
|
+
out2.sort((a, b) => b.score - a.score || b.lastAccessNs - a.lastAccessNs);
|
|
2402
|
+
actions.emit(out2);
|
|
2403
|
+
},
|
|
2404
|
+
{
|
|
2405
|
+
name: "ranked",
|
|
2406
|
+
describeKind: "derived",
|
|
2407
|
+
equals: rankedEqual,
|
|
2408
|
+
meta: memoryMeta("ranked")
|
|
2409
|
+
}
|
|
2410
|
+
);
|
|
2411
|
+
graph.add(rankedNode, { name: "ranked" });
|
|
2412
|
+
} else {
|
|
2413
|
+
rankedNode = (0, import_core15.node)([], {
|
|
2414
|
+
initial: [],
|
|
2415
|
+
name: "ranked",
|
|
2416
|
+
describeKind: "state",
|
|
2417
|
+
meta: memoryMeta("ranked_disabled")
|
|
2418
|
+
});
|
|
2419
|
+
graph.add(rankedNode, { name: "ranked" });
|
|
2420
|
+
}
|
|
2421
|
+
const size = (0, import_core15.node)(
|
|
2422
|
+
[items.entries],
|
|
2423
|
+
(batchData, actions, ctx) => {
|
|
2424
|
+
const data = batchData.map(
|
|
2425
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
2426
|
+
);
|
|
2427
|
+
const snapshot = data[0];
|
|
2428
|
+
actions.emit((snapshot ?? /* @__PURE__ */ new Map()).size);
|
|
2429
|
+
},
|
|
2430
|
+
{
|
|
2431
|
+
name: "size",
|
|
2432
|
+
describeKind: "derived",
|
|
2433
|
+
initial: 0,
|
|
2434
|
+
meta: memoryMeta("size")
|
|
2435
|
+
}
|
|
2436
|
+
);
|
|
2437
|
+
graph.add(size, { name: "size" });
|
|
2438
|
+
graph.addDisposer((0, import_extra12.keepalive)(size));
|
|
2439
|
+
const events = createAuditLog({
|
|
2440
|
+
name: "events",
|
|
2441
|
+
retainedLimit: 1024,
|
|
2442
|
+
graph
|
|
2443
|
+
});
|
|
2444
|
+
const seqCursor = registerCursor(graph, "seq", 0);
|
|
2445
|
+
const upsertImpl = (id, value, _opts) => {
|
|
2446
|
+
const now = (0, import_core15.monotonicNs)();
|
|
2447
|
+
const prev = items.get(id);
|
|
2448
|
+
const baseScore = _opts?.score ?? readScoreFn()(value);
|
|
2449
|
+
items.set(id, {
|
|
2450
|
+
id,
|
|
2451
|
+
value,
|
|
2452
|
+
baseScore,
|
|
2453
|
+
createdAtNs: prev?.createdAtNs ?? now,
|
|
2454
|
+
lastAccessNs: now
|
|
2455
|
+
});
|
|
2456
|
+
};
|
|
2457
|
+
const removeImpl = (id) => {
|
|
2458
|
+
if (!items.has(id)) return;
|
|
2459
|
+
items.delete(id);
|
|
2460
|
+
};
|
|
2461
|
+
const clearImpl = () => {
|
|
2462
|
+
if (items.size === 0) return;
|
|
2463
|
+
items.clear();
|
|
2464
|
+
};
|
|
2465
|
+
const rescoreImpl = () => {
|
|
2466
|
+
if (!ranked) return;
|
|
2467
|
+
const fn = readScoreFn();
|
|
2468
|
+
const snapshot = items.entries.cache;
|
|
2469
|
+
if (!snapshot || snapshot.size === 0) return;
|
|
2470
|
+
const updates = [];
|
|
2471
|
+
for (const entry of snapshot.values()) {
|
|
2472
|
+
updates.push([entry.id, { ...entry, baseScore: fn(entry.value) }]);
|
|
2473
|
+
}
|
|
2474
|
+
items.setMany(updates);
|
|
2475
|
+
};
|
|
2476
|
+
const upsert = mutate(upsertImpl, {
|
|
2477
|
+
frame: "inline",
|
|
2478
|
+
log: events,
|
|
2479
|
+
seq: seqCursor,
|
|
2480
|
+
onSuccessRecord: ([id], _r, m) => ({ action: "upsert", id, t_ns: m.t_ns, seq: m.seq })
|
|
2481
|
+
});
|
|
2482
|
+
const remove = mutate(removeImpl, {
|
|
2483
|
+
frame: "inline",
|
|
2484
|
+
log: events,
|
|
2485
|
+
seq: seqCursor,
|
|
2486
|
+
onSuccessRecord: ([id], _r, m) => ({ action: "remove", id, t_ns: m.t_ns, seq: m.seq })
|
|
2487
|
+
});
|
|
2488
|
+
const clear = mutate(clearImpl, {
|
|
2489
|
+
frame: "inline",
|
|
2490
|
+
log: events,
|
|
2491
|
+
seq: seqCursor,
|
|
2492
|
+
onSuccessRecord: (_args, _r, m) => ({ action: "clear", t_ns: m.t_ns, seq: m.seq })
|
|
2493
|
+
});
|
|
2494
|
+
const rescore = mutate(rescoreImpl, {
|
|
2495
|
+
frame: "inline",
|
|
2496
|
+
log: events,
|
|
2497
|
+
seq: seqCursor,
|
|
2498
|
+
onSuccessRecord: (_args, _r, m) => ({ action: "rescore", t_ns: m.t_ns, seq: m.seq })
|
|
2499
|
+
});
|
|
2500
|
+
function itemNode(id) {
|
|
2501
|
+
const idN = toNode(id, "id");
|
|
2502
|
+
return (0, import_core15.node)(
|
|
2503
|
+
[items.entries, idN],
|
|
2504
|
+
(batchData, actions, ctx) => {
|
|
2505
|
+
const data = batchData.map(
|
|
2506
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
2507
|
+
);
|
|
2508
|
+
const map = data[0];
|
|
2509
|
+
const key = data[1];
|
|
2510
|
+
actions.emit(map?.get(key));
|
|
2511
|
+
},
|
|
2512
|
+
{
|
|
2513
|
+
describeKind: "derived",
|
|
2514
|
+
meta: memoryMeta("collection_item")
|
|
2515
|
+
}
|
|
2516
|
+
);
|
|
2517
|
+
}
|
|
2518
|
+
function hasNode(id) {
|
|
2519
|
+
const idN = toNode(id, "id");
|
|
2520
|
+
return (0, import_core15.node)(
|
|
2521
|
+
[items.entries, idN],
|
|
2522
|
+
(batchData, actions, ctx) => {
|
|
2523
|
+
const data = batchData.map(
|
|
2524
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
2525
|
+
);
|
|
2526
|
+
const map = data[0];
|
|
2527
|
+
const key = data[1];
|
|
2528
|
+
actions.emit(map?.has(key) ?? false);
|
|
2529
|
+
},
|
|
2530
|
+
{
|
|
2531
|
+
describeKind: "derived",
|
|
2532
|
+
meta: memoryMeta("collection_has")
|
|
2533
|
+
}
|
|
2534
|
+
);
|
|
2535
|
+
}
|
|
2536
|
+
const out = Object.assign(graph, {
|
|
2537
|
+
events,
|
|
2538
|
+
items: items.entries,
|
|
2539
|
+
ranked: rankedNode,
|
|
2540
|
+
size,
|
|
2541
|
+
upsert,
|
|
2542
|
+
remove,
|
|
2543
|
+
clear,
|
|
2544
|
+
rescore,
|
|
2545
|
+
itemNode,
|
|
2546
|
+
hasNode
|
|
2547
|
+
});
|
|
2548
|
+
return out;
|
|
2549
|
+
}
|
|
2550
|
+
function vectorIndex(opts = {}) {
|
|
2551
|
+
const backend = opts.backend ?? "flat";
|
|
2552
|
+
const dimension = opts.dimension;
|
|
2553
|
+
const strictDimension = opts.strictDimension ?? true;
|
|
2554
|
+
const maxSize = opts.maxSize;
|
|
2555
|
+
const userRetentionScore = opts.retentionScore;
|
|
2556
|
+
let hnsw;
|
|
2557
|
+
if (backend === "hnsw") {
|
|
2558
|
+
hnsw = opts.hnswFactory?.();
|
|
2559
|
+
if (!hnsw) {
|
|
2560
|
+
throw new Error(
|
|
2561
|
+
'vectorIndex backend "hnsw" requires an optional dependency adapter; install your HNSW package and provide `hnswFactory`.'
|
|
2562
|
+
);
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
const graph = new import_graph7.Graph(opts.name ?? "vector_index");
|
|
2566
|
+
let inferredDimension;
|
|
2567
|
+
function assertDimension(vector) {
|
|
2568
|
+
if (dimension !== void 0) {
|
|
2569
|
+
if (vector.length !== dimension) {
|
|
2570
|
+
throw new RangeError(
|
|
2571
|
+
`vector dimension mismatch: expected ${dimension}, got ${vector.length}`
|
|
2572
|
+
);
|
|
2573
|
+
}
|
|
2574
|
+
return;
|
|
2575
|
+
}
|
|
2576
|
+
if (!strictDimension) return;
|
|
2577
|
+
if (inferredDimension === void 0) {
|
|
2578
|
+
inferredDimension = vector.length;
|
|
2579
|
+
return;
|
|
2580
|
+
}
|
|
2581
|
+
if (vector.length !== inferredDimension) {
|
|
2582
|
+
throw new RangeError(
|
|
2583
|
+
`vector dimension mismatch: inferred ${inferredDimension} from first upsert, got ${vector.length}. Pass \`strictDimension: false\` to opt into zero-pad behavior, or set an explicit \`dimension\`.`
|
|
2584
|
+
);
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
const baseRetentionScore = userRetentionScore ?? ((r) => r.upsertedAtNs);
|
|
2588
|
+
let clearInProgress = false;
|
|
2589
|
+
const events = createAuditLog({
|
|
2590
|
+
name: "events",
|
|
2591
|
+
retainedLimit: 1024,
|
|
2592
|
+
graph
|
|
2593
|
+
});
|
|
2594
|
+
const seqCursor = registerCursor(graph, "seq", 0);
|
|
2595
|
+
const entries = (0, import_extra12.reactiveMap)({
|
|
2596
|
+
name: "entries",
|
|
2597
|
+
...maxSize !== void 0 ? {
|
|
2598
|
+
retention: {
|
|
2599
|
+
score: (_k, v) => baseRetentionScore(v),
|
|
2600
|
+
maxSize,
|
|
2601
|
+
onArchive: (key) => {
|
|
2602
|
+
if (clearInProgress) return;
|
|
2603
|
+
if (backend === "hnsw") hnsw.remove(key);
|
|
2604
|
+
events.append({
|
|
2605
|
+
action: "evict",
|
|
2606
|
+
id: key,
|
|
2607
|
+
t_ns: (0, import_core15.wallClockNs)(),
|
|
2608
|
+
seq: bumpCursor(seqCursor)
|
|
2609
|
+
});
|
|
2610
|
+
}
|
|
2611
|
+
}
|
|
2612
|
+
} : {}
|
|
2613
|
+
});
|
|
2614
|
+
graph.add(entries.entries, { name: "entries" });
|
|
2615
|
+
graph.addDisposer((0, import_extra12.keepalive)(entries.entries));
|
|
2616
|
+
if (hnsw?.dispose) {
|
|
2617
|
+
const disposeAdapter = hnsw.dispose.bind(hnsw);
|
|
2618
|
+
graph.addDisposer(() => disposeAdapter());
|
|
2619
|
+
}
|
|
2620
|
+
const upsertImpl = (id, vector, meta) => {
|
|
2621
|
+
assertDimension(vector);
|
|
2622
|
+
if (backend === "hnsw") hnsw.upsert(id, vector, meta);
|
|
2623
|
+
const copiedMeta = (() => {
|
|
2624
|
+
if (meta === void 0) return void 0;
|
|
2625
|
+
if (meta === null || typeof meta !== "object") return meta;
|
|
2626
|
+
return Array.isArray(meta) ? [...meta] : { ...meta };
|
|
2627
|
+
})();
|
|
2628
|
+
const record = {
|
|
2629
|
+
id,
|
|
2630
|
+
vector: [...vector],
|
|
2631
|
+
...copiedMeta !== void 0 ? { meta: copiedMeta } : {},
|
|
2632
|
+
upsertedAtNs: (0, import_core15.monotonicNs)()
|
|
2633
|
+
};
|
|
2634
|
+
entries.set(id, record);
|
|
2635
|
+
};
|
|
2636
|
+
const removeImpl = (id) => {
|
|
2637
|
+
if (!entries.has(id)) return;
|
|
2638
|
+
if (backend === "hnsw") hnsw.remove(id);
|
|
2639
|
+
entries.delete(id);
|
|
2640
|
+
};
|
|
2641
|
+
const clearImpl = () => {
|
|
2642
|
+
if (entries.size === 0) return;
|
|
2643
|
+
clearInProgress = true;
|
|
2644
|
+
try {
|
|
2645
|
+
entries.clear();
|
|
2646
|
+
if (backend === "hnsw") hnsw.clear();
|
|
2647
|
+
} finally {
|
|
2648
|
+
clearInProgress = false;
|
|
2649
|
+
}
|
|
2650
|
+
inferredDimension = void 0;
|
|
2651
|
+
};
|
|
2652
|
+
const reindexImpl = () => {
|
|
2653
|
+
if (backend !== "hnsw") return;
|
|
2654
|
+
const snapshot = entries.entries.cache;
|
|
2655
|
+
if (!snapshot) return;
|
|
2656
|
+
hnsw.clear();
|
|
2657
|
+
for (const r of snapshot.values()) {
|
|
2658
|
+
hnsw.upsert(r.id, r.vector, r.meta);
|
|
2659
|
+
}
|
|
2660
|
+
};
|
|
2661
|
+
const upsert = mutate(upsertImpl, {
|
|
2662
|
+
frame: "inline",
|
|
2663
|
+
log: events,
|
|
2664
|
+
freeze: false,
|
|
2665
|
+
seq: seqCursor,
|
|
2666
|
+
onSuccessRecord: ([id], _r, m) => ({ action: "upsert", id, t_ns: m.t_ns, seq: m.seq })
|
|
2667
|
+
});
|
|
2668
|
+
const remove = mutate(removeImpl, {
|
|
2669
|
+
frame: "inline",
|
|
2670
|
+
log: events,
|
|
2671
|
+
seq: seqCursor,
|
|
2672
|
+
onSuccessRecord: ([id], _r, m) => ({ action: "remove", id, t_ns: m.t_ns, seq: m.seq })
|
|
2673
|
+
});
|
|
2674
|
+
const clear = mutate(clearImpl, {
|
|
2675
|
+
frame: "inline",
|
|
2676
|
+
log: events,
|
|
2677
|
+
seq: seqCursor,
|
|
2678
|
+
onSuccessRecord: (_args, _r, m) => ({ action: "clear", t_ns: m.t_ns, seq: m.seq })
|
|
2679
|
+
});
|
|
2680
|
+
const reindex = mutate(reindexImpl, {
|
|
2681
|
+
frame: "inline",
|
|
2682
|
+
log: events,
|
|
2683
|
+
seq: seqCursor,
|
|
2684
|
+
onSuccessRecord: (_args, _r, m) => ({ action: "reindex", t_ns: m.t_ns, seq: m.seq })
|
|
2685
|
+
});
|
|
2686
|
+
function searchNode(query, k = 5) {
|
|
2687
|
+
const kN = toNode(k, "k");
|
|
2688
|
+
return (0, import_core15.node)(
|
|
2689
|
+
[entries.entries, query, kN],
|
|
2690
|
+
(batchData, actions, ctx) => {
|
|
2691
|
+
const values = batchData.map(
|
|
2692
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
2693
|
+
);
|
|
2694
|
+
const snapshot = values[0];
|
|
2695
|
+
const q = values[1];
|
|
2696
|
+
const kRaw = values[2];
|
|
2697
|
+
const kVal = Number.isFinite(kRaw) ? Math.max(0, Math.floor(kRaw)) : 0;
|
|
2698
|
+
if (!snapshot || snapshot.size === 0 || kVal <= 0) {
|
|
2699
|
+
actions.emit([]);
|
|
2700
|
+
return;
|
|
2701
|
+
}
|
|
2702
|
+
if (q == null || q.length === 0) {
|
|
2703
|
+
actions.emit([]);
|
|
2704
|
+
return;
|
|
2705
|
+
}
|
|
2706
|
+
const expectedDim = dimension ?? (strictDimension ? inferredDimension : void 0);
|
|
2707
|
+
if (expectedDim !== void 0 && q.length !== expectedDim) {
|
|
2708
|
+
actions.emit([]);
|
|
2709
|
+
return;
|
|
2710
|
+
}
|
|
2711
|
+
if (backend === "hnsw") {
|
|
2712
|
+
const adapterResults = hnsw.search(q, kVal);
|
|
2713
|
+
actions.emit([...adapterResults]);
|
|
2714
|
+
return;
|
|
2715
|
+
}
|
|
2716
|
+
const ranked = [...snapshot.values()].map((row) => {
|
|
2717
|
+
const result = {
|
|
2718
|
+
id: row.id,
|
|
2719
|
+
score: cosineSimilarity(q, row.vector),
|
|
2720
|
+
...row.meta !== void 0 ? { meta: row.meta } : {}
|
|
2721
|
+
};
|
|
2722
|
+
return result;
|
|
2723
|
+
}).sort((a, b) => b.score - a.score).slice(0, kVal);
|
|
2724
|
+
actions.emit(ranked);
|
|
2725
|
+
},
|
|
2726
|
+
{
|
|
2727
|
+
describeKind: "derived",
|
|
2728
|
+
// A1: include `score` in equality. The previous id-only
|
|
2729
|
+
// comparator suppressed re-emissions when the same set of
|
|
2730
|
+
// IDs/order had different scores (re-upsert with new
|
|
2731
|
+
// vector; query change preserving ranking order).
|
|
2732
|
+
equals: (a, b) => searchResultsEqual(a, b),
|
|
2733
|
+
meta: memoryMeta("vector_search")
|
|
2734
|
+
}
|
|
2735
|
+
);
|
|
2736
|
+
}
|
|
2737
|
+
const out = Object.assign(graph, {
|
|
2738
|
+
backend,
|
|
2739
|
+
events,
|
|
2740
|
+
entries: entries.entries,
|
|
2741
|
+
upsert,
|
|
2742
|
+
remove,
|
|
2743
|
+
clear,
|
|
2744
|
+
reindex,
|
|
2745
|
+
searchNode
|
|
2746
|
+
});
|
|
2747
|
+
return out;
|
|
2748
|
+
}
|
|
2749
|
+
var TRIPLE_SEP = "\0";
|
|
2750
|
+
function tripleKey(from, to, relation) {
|
|
2751
|
+
return `${from}${TRIPLE_SEP}${to}${TRIPLE_SEP}${relation}`;
|
|
2752
|
+
}
|
|
2753
|
+
function buildAdjacency(edges, side) {
|
|
2754
|
+
if (!edges || edges.size === 0) return /* @__PURE__ */ new Map();
|
|
2755
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
2756
|
+
for (const edge of edges.values()) {
|
|
2757
|
+
const key = side === "from" ? edge.from : edge.to;
|
|
2758
|
+
let bucket = buckets.get(key);
|
|
2759
|
+
if (!bucket) {
|
|
2760
|
+
bucket = [];
|
|
2761
|
+
buckets.set(key, bucket);
|
|
2762
|
+
}
|
|
2763
|
+
bucket.push(edge);
|
|
2764
|
+
}
|
|
2765
|
+
const out = /* @__PURE__ */ new Map();
|
|
2766
|
+
for (const [key, bucket] of buckets) out.set(key, Object.freeze(bucket));
|
|
2767
|
+
return out;
|
|
2768
|
+
}
|
|
2769
|
+
function adjacencyEqual(a, b) {
|
|
2770
|
+
if (a === b) return true;
|
|
2771
|
+
if (a == null || b == null) return false;
|
|
2772
|
+
if (a.size !== b.size) return false;
|
|
2773
|
+
for (const [k, av] of a) {
|
|
2774
|
+
const bv = b.get(k);
|
|
2775
|
+
if (!bv || av.length !== bv.length) return false;
|
|
2776
|
+
for (let i = 0; i < av.length; i += 1) {
|
|
2777
|
+
const ae = av[i];
|
|
2778
|
+
const be = bv[i];
|
|
2779
|
+
if (ae.from !== be.from || ae.to !== be.to || ae.relation !== be.relation || ae.weight !== be.weight)
|
|
2780
|
+
return false;
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
return true;
|
|
2784
|
+
}
|
|
2785
|
+
function knowledgeGraph(name, opts = {}) {
|
|
2786
|
+
const orphanGC = opts.orphanGC ?? "keep";
|
|
2787
|
+
if (opts.entitiesMaxSize !== void 0 && opts.entitiesMaxSize < 1) {
|
|
2788
|
+
throw new RangeError("knowledgeGraph: entitiesMaxSize must be >= 1");
|
|
2789
|
+
}
|
|
2790
|
+
if (opts.edgesMaxSize !== void 0 && opts.edgesMaxSize < 1) {
|
|
2791
|
+
throw new RangeError("knowledgeGraph: edgesMaxSize must be >= 1");
|
|
2792
|
+
}
|
|
2793
|
+
const graph = new import_graph7.Graph(name);
|
|
2794
|
+
const entitiesMap = (0, import_extra12.reactiveMap)({
|
|
2795
|
+
name: "entities",
|
|
2796
|
+
...opts.entitiesMaxSize !== void 0 ? { maxSize: opts.entitiesMaxSize } : {}
|
|
2797
|
+
});
|
|
2798
|
+
const edgesMap = (0, import_extra12.reactiveMap)({
|
|
2799
|
+
name: "edges",
|
|
2800
|
+
...opts.edgesMaxSize !== void 0 ? { maxSize: opts.edgesMaxSize } : {}
|
|
2801
|
+
});
|
|
2802
|
+
graph.add(entitiesMap.entries, { name: "entities" });
|
|
2803
|
+
graph.add(edgesMap.entries, { name: "edges" });
|
|
2804
|
+
const adjacencyOut = (0, import_core15.node)(
|
|
2805
|
+
[edgesMap.entries],
|
|
2806
|
+
(batchData, actions, ctx) => {
|
|
2807
|
+
const data = batchData.map(
|
|
2808
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
2809
|
+
);
|
|
2810
|
+
const snapshot = data[0];
|
|
2811
|
+
actions.emit(buildAdjacency(snapshot, "from"));
|
|
2812
|
+
},
|
|
2813
|
+
{
|
|
2814
|
+
name: "adjacencyOut",
|
|
2815
|
+
describeKind: "derived",
|
|
2816
|
+
initial: /* @__PURE__ */ new Map(),
|
|
2817
|
+
equals: adjacencyEqual,
|
|
2818
|
+
meta: memoryMeta("adjacency_out")
|
|
2819
|
+
}
|
|
2820
|
+
);
|
|
2821
|
+
const adjacencyIn = (0, import_core15.node)(
|
|
2822
|
+
[edgesMap.entries],
|
|
2823
|
+
(batchData, actions, ctx) => {
|
|
2824
|
+
const data = batchData.map(
|
|
2825
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
2826
|
+
);
|
|
2827
|
+
const snapshot = data[0];
|
|
2828
|
+
actions.emit(buildAdjacency(snapshot, "to"));
|
|
2829
|
+
},
|
|
2830
|
+
{
|
|
2831
|
+
name: "adjacencyIn",
|
|
2832
|
+
describeKind: "derived",
|
|
2833
|
+
initial: /* @__PURE__ */ new Map(),
|
|
2834
|
+
equals: adjacencyEqual,
|
|
2835
|
+
meta: memoryMeta("adjacency_in")
|
|
2836
|
+
}
|
|
2837
|
+
);
|
|
2838
|
+
graph.add(adjacencyOut, { name: "adjacencyOut" });
|
|
2839
|
+
graph.add(adjacencyIn, { name: "adjacencyIn" });
|
|
2840
|
+
graph.addDisposer((0, import_extra12.keepalive)(adjacencyOut));
|
|
2841
|
+
graph.addDisposer((0, import_extra12.keepalive)(adjacencyIn));
|
|
2842
|
+
const entityCount = (0, import_core15.node)(
|
|
2843
|
+
[entitiesMap.entries],
|
|
2844
|
+
(batchData, actions, ctx) => {
|
|
2845
|
+
const data = batchData.map(
|
|
2846
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
2847
|
+
);
|
|
2848
|
+
const m = data[0];
|
|
2849
|
+
actions.emit((m ?? /* @__PURE__ */ new Map()).size);
|
|
2850
|
+
},
|
|
2851
|
+
{ name: "entityCount", describeKind: "derived", initial: 0, meta: memoryMeta("entity_count") }
|
|
2852
|
+
);
|
|
2853
|
+
const edgeCount = (0, import_core15.node)(
|
|
2854
|
+
[edgesMap.entries],
|
|
2855
|
+
(batchData, actions, ctx) => {
|
|
2856
|
+
const data = batchData.map(
|
|
2857
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
2858
|
+
);
|
|
2859
|
+
const m = data[0];
|
|
2860
|
+
actions.emit((m ?? /* @__PURE__ */ new Map()).size);
|
|
2861
|
+
},
|
|
2862
|
+
{ name: "edgeCount", describeKind: "derived", initial: 0, meta: memoryMeta("edge_count") }
|
|
2863
|
+
);
|
|
2864
|
+
graph.add(entityCount, { name: "entityCount" });
|
|
2865
|
+
graph.add(edgeCount, { name: "edgeCount" });
|
|
2866
|
+
graph.addDisposer((0, import_extra12.keepalive)(entityCount));
|
|
2867
|
+
graph.addDisposer((0, import_extra12.keepalive)(edgeCount));
|
|
2868
|
+
const events = createAuditLog({
|
|
2869
|
+
name: "events",
|
|
2870
|
+
retainedLimit: 1024,
|
|
2871
|
+
graph
|
|
2872
|
+
});
|
|
2873
|
+
const seqCursor = registerCursor(graph, "seq", 0);
|
|
2874
|
+
function entityHasReferences(id) {
|
|
2875
|
+
const out2 = adjacencyOut.cache;
|
|
2876
|
+
const inb = adjacencyIn.cache;
|
|
2877
|
+
if ((out2?.get(id)?.length ?? 0) > 0) return true;
|
|
2878
|
+
if ((inb?.get(id)?.length ?? 0) > 0) return true;
|
|
2879
|
+
return false;
|
|
2880
|
+
}
|
|
2881
|
+
function applyOrphanGC(candidates) {
|
|
2882
|
+
if (orphanGC !== "remove") return;
|
|
2883
|
+
for (const candidate of candidates) {
|
|
2884
|
+
if (!entitiesMap.has(candidate)) continue;
|
|
2885
|
+
if (entityHasReferences(candidate)) continue;
|
|
2886
|
+
entitiesMap.delete(candidate);
|
|
2887
|
+
events.append({
|
|
2888
|
+
action: "orphanRemove",
|
|
2889
|
+
id: candidate,
|
|
2890
|
+
t_ns: (0, import_core15.wallClockNs)(),
|
|
2891
|
+
seq: bumpCursor(seqCursor)
|
|
2892
|
+
});
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2895
|
+
const upsertEntityImpl = (id, value) => {
|
|
2896
|
+
entitiesMap.set(id, value);
|
|
2897
|
+
};
|
|
2898
|
+
const removeEntityImpl = (id) => {
|
|
2899
|
+
const snapshot = edgesMap.entries.cache;
|
|
2900
|
+
const cascadedNeighbors = /* @__PURE__ */ new Set();
|
|
2901
|
+
if (snapshot) {
|
|
2902
|
+
const toDrop = [];
|
|
2903
|
+
for (const [key, edge] of snapshot) {
|
|
2904
|
+
if (edge.from === id || edge.to === id) {
|
|
2905
|
+
toDrop.push(key);
|
|
2906
|
+
if (edge.from !== id) cascadedNeighbors.add(edge.from);
|
|
2907
|
+
if (edge.to !== id) cascadedNeighbors.add(edge.to);
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
if (toDrop.length > 0) edgesMap.deleteMany(toDrop);
|
|
2911
|
+
}
|
|
2912
|
+
if (entitiesMap.has(id)) entitiesMap.delete(id);
|
|
2913
|
+
applyOrphanGC([...cascadedNeighbors]);
|
|
2914
|
+
};
|
|
2915
|
+
const linkImpl = (from, to, relation, weight = 1) => {
|
|
2916
|
+
edgesMap.set(tripleKey(from, to, relation), { from, to, relation, weight });
|
|
2917
|
+
};
|
|
2918
|
+
const unlinkImpl = (from, to, relation) => {
|
|
2919
|
+
if (relation !== void 0) {
|
|
2920
|
+
edgesMap.delete(tripleKey(from, to, relation));
|
|
2921
|
+
} else {
|
|
2922
|
+
const snapshot = edgesMap.entries.cache;
|
|
2923
|
+
if (!snapshot) return;
|
|
2924
|
+
const toDrop = [];
|
|
2925
|
+
for (const [key, edge] of snapshot) {
|
|
2926
|
+
if (edge.from === from && edge.to === to) toDrop.push(key);
|
|
2927
|
+
}
|
|
2928
|
+
if (toDrop.length > 0) edgesMap.deleteMany(toDrop);
|
|
2929
|
+
}
|
|
2930
|
+
applyOrphanGC([from, to]);
|
|
2931
|
+
};
|
|
2932
|
+
const upsertEntity = mutate(upsertEntityImpl, {
|
|
2933
|
+
frame: "inline",
|
|
2934
|
+
log: events,
|
|
2935
|
+
seq: seqCursor,
|
|
2936
|
+
onSuccessRecord: ([id], _r, m) => ({
|
|
2937
|
+
action: "upsertEntity",
|
|
2938
|
+
id,
|
|
2939
|
+
t_ns: m.t_ns,
|
|
2940
|
+
seq: m.seq
|
|
2941
|
+
})
|
|
2942
|
+
});
|
|
2943
|
+
const removeEntity = mutate(removeEntityImpl, {
|
|
2944
|
+
frame: "inline",
|
|
2945
|
+
log: events,
|
|
2946
|
+
seq: seqCursor,
|
|
2947
|
+
onSuccessRecord: ([id], _r, m) => ({
|
|
2948
|
+
action: "removeEntity",
|
|
2949
|
+
id,
|
|
2950
|
+
t_ns: m.t_ns,
|
|
2951
|
+
seq: m.seq
|
|
2952
|
+
})
|
|
2953
|
+
});
|
|
2954
|
+
const link = mutate(linkImpl, {
|
|
2955
|
+
frame: "inline",
|
|
2956
|
+
log: events,
|
|
2957
|
+
seq: seqCursor,
|
|
2958
|
+
onSuccessRecord: ([from, to, relation, weight], _r, m) => ({
|
|
2959
|
+
action: "link",
|
|
2960
|
+
from,
|
|
2961
|
+
to,
|
|
2962
|
+
relation,
|
|
2963
|
+
weight: weight ?? 1,
|
|
2964
|
+
t_ns: m.t_ns,
|
|
2965
|
+
seq: m.seq
|
|
2966
|
+
})
|
|
2967
|
+
});
|
|
2968
|
+
const unlink = mutate(unlinkImpl, {
|
|
2969
|
+
frame: "inline",
|
|
2970
|
+
log: events,
|
|
2971
|
+
seq: seqCursor,
|
|
2972
|
+
onSuccessRecord: ([from, to, relation], _r, m) => ({
|
|
2973
|
+
action: "unlink",
|
|
2974
|
+
from,
|
|
2975
|
+
to,
|
|
2976
|
+
...relation !== void 0 ? { relation } : {},
|
|
2977
|
+
t_ns: m.t_ns,
|
|
2978
|
+
seq: m.seq
|
|
2979
|
+
})
|
|
2980
|
+
});
|
|
2981
|
+
function relatedNode(id, relation) {
|
|
2982
|
+
const idN = toNode(id, "id");
|
|
2983
|
+
const relN = relation !== void 0 ? toNode(relation, "relation") : void 0;
|
|
2984
|
+
const deps = relN ? [adjacencyOut, adjacencyIn, idN, relN] : [adjacencyOut, adjacencyIn, idN];
|
|
2985
|
+
return (0, import_core15.node)(
|
|
2986
|
+
deps,
|
|
2987
|
+
(batchData, actions, ctx) => {
|
|
2988
|
+
const values = batchData.map(
|
|
2989
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
2990
|
+
);
|
|
2991
|
+
const out2 = values[0];
|
|
2992
|
+
const inb = values[1];
|
|
2993
|
+
const key = values[2];
|
|
2994
|
+
const rel = relN ? values[3] : void 0;
|
|
2995
|
+
const outE = out2?.get(key) ?? [];
|
|
2996
|
+
const inE = inb?.get(key) ?? [];
|
|
2997
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2998
|
+
const acc = [];
|
|
2999
|
+
for (const edge of outE) {
|
|
3000
|
+
const k = tripleKey(edge.from, edge.to, edge.relation);
|
|
3001
|
+
if (seen.has(k)) continue;
|
|
3002
|
+
if (rel !== void 0 && edge.relation !== rel) continue;
|
|
3003
|
+
seen.add(k);
|
|
3004
|
+
acc.push(edge);
|
|
3005
|
+
}
|
|
3006
|
+
for (const edge of inE) {
|
|
3007
|
+
const k = tripleKey(edge.from, edge.to, edge.relation);
|
|
3008
|
+
if (seen.has(k)) continue;
|
|
3009
|
+
if (rel !== void 0 && edge.relation !== rel) continue;
|
|
3010
|
+
seen.add(k);
|
|
3011
|
+
acc.push(edge);
|
|
3012
|
+
}
|
|
3013
|
+
actions.emit(acc);
|
|
3014
|
+
},
|
|
3015
|
+
{
|
|
3016
|
+
describeKind: "derived",
|
|
3017
|
+
equals: (a, b) => {
|
|
3018
|
+
const av = a;
|
|
3019
|
+
const bv = b;
|
|
3020
|
+
if (av === bv) return true;
|
|
3021
|
+
if (av == null || bv == null) return false;
|
|
3022
|
+
if (av.length !== bv.length) return false;
|
|
3023
|
+
for (let i = 0; i < av.length; i += 1) {
|
|
3024
|
+
const x = av[i];
|
|
3025
|
+
const y = bv[i];
|
|
3026
|
+
if (x.from !== y.from || x.to !== y.to || x.relation !== y.relation || x.weight !== y.weight)
|
|
3027
|
+
return false;
|
|
3028
|
+
}
|
|
3029
|
+
return true;
|
|
3030
|
+
},
|
|
3031
|
+
meta: memoryMeta("related")
|
|
3032
|
+
}
|
|
3033
|
+
);
|
|
3034
|
+
}
|
|
3035
|
+
const out = Object.assign(graph, {
|
|
3036
|
+
events,
|
|
3037
|
+
entities: entitiesMap.entries,
|
|
3038
|
+
edges: edgesMap.entries,
|
|
3039
|
+
adjacencyOut,
|
|
3040
|
+
adjacencyIn,
|
|
3041
|
+
entityCount,
|
|
3042
|
+
edgeCount,
|
|
3043
|
+
upsertEntity,
|
|
3044
|
+
removeEntity,
|
|
3045
|
+
link,
|
|
3046
|
+
unlink,
|
|
3047
|
+
relatedNode
|
|
3048
|
+
});
|
|
3049
|
+
return out;
|
|
3050
|
+
}
|
|
3051
|
+
|
|
3052
|
+
// src/utils/ai/memory/memory-composers.ts
|
|
3053
|
+
var MemoryWithVectorsGraph = class extends import_graph8.Graph {
|
|
3054
|
+
vectors;
|
|
3055
|
+
constructor(opts) {
|
|
3056
|
+
super(opts.name ?? "memory-vectors", opts.graph);
|
|
3057
|
+
this.vectors = vectorIndex({ dimension: opts.dimension });
|
|
3058
|
+
this.mount("vectorIndex", this.vectors);
|
|
3059
|
+
const embedFn = opts.embedFn;
|
|
3060
|
+
const vectorsRef = this.vectors;
|
|
3061
|
+
const indexer = (0, import_core16.node)(
|
|
3062
|
+
[opts.store.store.entries],
|
|
3063
|
+
(batchData, _actions, ctx) => {
|
|
3064
|
+
const data = batchData.map(
|
|
3065
|
+
(b, i) => b != null && b.length > 0 ? b.at(-1) : ctx.prevData[i]
|
|
3066
|
+
);
|
|
3067
|
+
const storeMap = data[0] ?? /* @__PURE__ */ new Map();
|
|
3068
|
+
for (const [key, mem] of storeMap) {
|
|
3069
|
+
const vec = embedFn(mem);
|
|
3070
|
+
if (vec) vectorsRef.upsert(key, vec, mem);
|
|
3071
|
+
}
|
|
3072
|
+
},
|
|
3073
|
+
{ name: "indexer", describeKind: "effect" }
|
|
3074
|
+
);
|
|
3075
|
+
this.add(indexer, { name: "indexer" });
|
|
3076
|
+
this.addDisposer((0, import_extra13.keepalive)(indexer));
|
|
3077
|
+
}
|
|
3078
|
+
};
|
|
3079
|
+
function memoryWithVectors(opts) {
|
|
3080
|
+
return new MemoryWithVectorsGraph(opts);
|
|
3081
|
+
}
|
|
3082
|
+
var MemoryWithKGGraph = class extends import_graph8.Graph {
|
|
3083
|
+
kg;
|
|
3084
|
+
constructor(opts) {
|
|
3085
|
+
const name = opts.name ?? "memory-kg";
|
|
3086
|
+
super(name, opts.graph);
|
|
3087
|
+
const kgName = opts.kgName ?? `${name}-kg`;
|
|
3088
|
+
const mountPath = opts.mountPath ?? "knowledge-kg";
|
|
3089
|
+
this.kg = knowledgeGraph(kgName);
|
|
3090
|
+
this.mount(mountPath, this.kg);
|
|
3091
|
+
if (!opts.entityFn) return;
|
|
3092
|
+
const entityFn = opts.entityFn;
|
|
3093
|
+
const kgRef = this.kg;
|
|
3094
|
+
const indexer = (0, import_core16.node)(
|
|
3095
|
+
[opts.store.store.entries],
|
|
3096
|
+
(batchData, _actions, ctx) => {
|
|
3097
|
+
const data = batchData.map(
|
|
3098
|
+
(b, i) => b != null && b.length > 0 ? b.at(-1) : ctx.prevData[i]
|
|
3099
|
+
);
|
|
3100
|
+
const storeMap = data[0] ?? /* @__PURE__ */ new Map();
|
|
3101
|
+
for (const [key, mem] of storeMap) {
|
|
3102
|
+
const extracted = entityFn(key, mem);
|
|
3103
|
+
if (!extracted) continue;
|
|
3104
|
+
for (const ent of extracted.entities ?? []) {
|
|
3105
|
+
kgRef.upsertEntity(ent.id, ent.value);
|
|
3106
|
+
}
|
|
3107
|
+
for (const rel of extracted.relations ?? []) {
|
|
3108
|
+
kgRef.link(rel.from, rel.to, rel.relation, rel.weight);
|
|
3109
|
+
}
|
|
3110
|
+
}
|
|
3111
|
+
},
|
|
3112
|
+
{ name: "indexer", describeKind: "effect" }
|
|
3113
|
+
);
|
|
3114
|
+
this.add(indexer, { name: "indexer" });
|
|
3115
|
+
this.addDisposer((0, import_extra13.keepalive)(indexer));
|
|
3116
|
+
}
|
|
3117
|
+
};
|
|
3118
|
+
function memoryWithKG(opts) {
|
|
3119
|
+
return new MemoryWithKGGraph(opts);
|
|
3120
|
+
}
|
|
3121
|
+
var MemoryWithTiersGraph = class extends import_graph8.Graph {
|
|
3122
|
+
store;
|
|
3123
|
+
tiers;
|
|
3124
|
+
compact;
|
|
3125
|
+
size;
|
|
3126
|
+
permanent;
|
|
3127
|
+
permanentKeys;
|
|
3128
|
+
entryCreatedAtNs;
|
|
3129
|
+
constructor(opts) {
|
|
3130
|
+
super(opts.name ?? "memory-tiers", opts.graph);
|
|
3131
|
+
const decayRate = opts.decayRate ?? DEFAULT_DECAY_RATE;
|
|
3132
|
+
const maxActive = opts.maxActive ?? 1e3;
|
|
3133
|
+
const archiveThreshold = opts.archiveThreshold ?? 0.1;
|
|
3134
|
+
const permanentFilter = opts.permanentFilter ?? (() => false);
|
|
3135
|
+
this.permanent = collection("permanent", { ranked: false });
|
|
3136
|
+
this.mount("permanent", this.permanent);
|
|
3137
|
+
this.permanentKeys = (0, import_extra13.reactiveMap)({ name: "permanentKeys" });
|
|
3138
|
+
this.add(this.permanentKeys.entries, { name: "permanentKeys" });
|
|
3139
|
+
this.entryCreatedAtNs = (0, import_extra13.reactiveMap)({ name: "entryCreatedAtNs" });
|
|
3140
|
+
this.add(this.entryCreatedAtNs.entries, { name: "entryCreatedAtNs" });
|
|
3141
|
+
let contextNode;
|
|
3142
|
+
if (opts.context) {
|
|
3143
|
+
contextNode = (0, import_extra13.fromAny)(opts.context);
|
|
3144
|
+
} else {
|
|
3145
|
+
contextNode = (0, import_core16.node)([], { initial: null });
|
|
3146
|
+
this.add(contextNode, { name: "context" });
|
|
3147
|
+
}
|
|
3148
|
+
let latestCtx = contextNode.cache;
|
|
3149
|
+
const ctxUnsub = contextNode.subscribe((msgs) => {
|
|
3150
|
+
for (const m of msgs) if (m[0] === import_core16.DATA) latestCtx = m[1];
|
|
3151
|
+
});
|
|
3152
|
+
this.addDisposer(ctxUnsub);
|
|
3153
|
+
const permanentKeysRef = this.permanentKeys;
|
|
3154
|
+
const entryCreatedAtNsRef = this.entryCreatedAtNs;
|
|
3155
|
+
const score = opts.score;
|
|
3156
|
+
const retention = {
|
|
3157
|
+
score: (key, value) => {
|
|
3158
|
+
if (permanentFilter(key, value)) return Number.POSITIVE_INFINITY;
|
|
3159
|
+
if (permanentKeysRef.has(key)) return Number.POSITIVE_INFINITY;
|
|
3160
|
+
const nowNs = (0, import_core16.monotonicNs)();
|
|
3161
|
+
const createdNs = entryCreatedAtNsRef.get(key) ?? nowNs;
|
|
3162
|
+
const ageSeconds2 = Number(nowNs - createdNs) / 1e9;
|
|
3163
|
+
return decay(score(value, latestCtx), ageSeconds2, decayRate);
|
|
3164
|
+
},
|
|
3165
|
+
archiveThreshold,
|
|
3166
|
+
maxSize: maxActive
|
|
3167
|
+
};
|
|
3168
|
+
this.store = distill(opts.source, opts.extractFn, {
|
|
3169
|
+
score: opts.score,
|
|
3170
|
+
cost: opts.cost,
|
|
3171
|
+
...opts.budget !== void 0 ? { budget: opts.budget } : {},
|
|
3172
|
+
...opts.evict !== void 0 ? { evict: opts.evict } : {},
|
|
3173
|
+
...opts.consolidate !== void 0 ? { consolidate: opts.consolidate } : {},
|
|
3174
|
+
...opts.consolidateTrigger !== void 0 ? { consolidateTrigger: opts.consolidateTrigger } : {},
|
|
3175
|
+
...opts.context !== void 0 ? { context: opts.context } : {},
|
|
3176
|
+
mapOptions: { retention }
|
|
3177
|
+
});
|
|
3178
|
+
this.add(this.store.store.entries, { name: "store" });
|
|
3179
|
+
this.compact = this.store.compact;
|
|
3180
|
+
this.add(this.compact, { name: "compact" });
|
|
3181
|
+
this.size = this.store.size;
|
|
3182
|
+
this.add(this.size, { name: "size" });
|
|
3183
|
+
const storeRef = this.store;
|
|
3184
|
+
const tierOf = (key) => {
|
|
3185
|
+
if (permanentKeysRef.has(key)) return "permanent";
|
|
3186
|
+
const m = storeRef.store.entries.cache ?? /* @__PURE__ */ new Map();
|
|
3187
|
+
if (m.has(key)) return "active";
|
|
3188
|
+
return "archived";
|
|
3189
|
+
};
|
|
3190
|
+
const permanentRef = this.permanent;
|
|
3191
|
+
const markPermanent = (key, value) => {
|
|
3192
|
+
permanentKeysRef.set(key, true);
|
|
3193
|
+
permanentRef.upsert(key, value);
|
|
3194
|
+
};
|
|
3195
|
+
const syncCreatedAt = (0, import_core16.node)(
|
|
3196
|
+
[this.store.store.entries],
|
|
3197
|
+
(batchData, _actions, ctx) => {
|
|
3198
|
+
const data = batchData.map(
|
|
3199
|
+
(b, i) => b != null && b.length > 0 ? b.at(-1) : ctx.prevData[i]
|
|
3200
|
+
);
|
|
3201
|
+
const map = data[0] ?? /* @__PURE__ */ new Map();
|
|
3202
|
+
const nowNs = (0, import_core16.monotonicNs)();
|
|
3203
|
+
const toAdd = [];
|
|
3204
|
+
for (const key of map.keys()) {
|
|
3205
|
+
if (!entryCreatedAtNsRef.has(key)) toAdd.push(key);
|
|
3206
|
+
}
|
|
3207
|
+
if (toAdd.length > 0) {
|
|
3208
|
+
(0, import_core16.batch)(() => {
|
|
3209
|
+
for (const key of toAdd) entryCreatedAtNsRef.set(key, nowNs);
|
|
3210
|
+
});
|
|
3211
|
+
}
|
|
3212
|
+
},
|
|
3213
|
+
{ name: "entryCreatedAtNs/sync", describeKind: "effect" }
|
|
3214
|
+
);
|
|
3215
|
+
this.add(syncCreatedAt, { name: "entryCreatedAtNs/sync" });
|
|
3216
|
+
this.addDisposer((0, import_extra13.keepalive)(syncCreatedAt));
|
|
3217
|
+
const entriesUnsub = this.store.store.entries.subscribe((msgs) => {
|
|
3218
|
+
for (const m of msgs) {
|
|
3219
|
+
if (m[0] !== import_core16.DATA) continue;
|
|
3220
|
+
const map = m[1];
|
|
3221
|
+
const created = entryCreatedAtNsRef.entries.cache;
|
|
3222
|
+
if (created == null) continue;
|
|
3223
|
+
const toDelete = [];
|
|
3224
|
+
for (const key of created.keys()) {
|
|
3225
|
+
if (!map.has(key)) toDelete.push(key);
|
|
3226
|
+
}
|
|
3227
|
+
if (toDelete.length > 0) {
|
|
3228
|
+
(0, import_core16.batch)(() => {
|
|
3229
|
+
for (const key of toDelete) entryCreatedAtNsRef.delete(key);
|
|
3230
|
+
});
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
});
|
|
3234
|
+
this.addDisposer(entriesUnsub);
|
|
3235
|
+
const promoter = (0, import_core16.node)(
|
|
3236
|
+
[this.store.store.entries],
|
|
3237
|
+
(batchData, _actions, ctx) => {
|
|
3238
|
+
const data = batchData.map(
|
|
3239
|
+
(b, i) => b != null && b.length > 0 ? b.at(-1) : ctx.prevData[i]
|
|
3240
|
+
);
|
|
3241
|
+
const map = data[0] ?? /* @__PURE__ */ new Map();
|
|
3242
|
+
for (const [key, mem] of map) {
|
|
3243
|
+
if (permanentKeysRef.has(key)) continue;
|
|
3244
|
+
if (permanentFilter(key, mem)) {
|
|
3245
|
+
(0, import_core16.batch)(() => {
|
|
3246
|
+
markPermanent(key, mem);
|
|
3247
|
+
});
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
},
|
|
3251
|
+
{ name: "promoter", describeKind: "effect" }
|
|
3252
|
+
);
|
|
3253
|
+
this.add(promoter, { name: "promoter" });
|
|
3254
|
+
this.addDisposer((0, import_extra13.keepalive)(promoter));
|
|
3255
|
+
let archiveHandle = null;
|
|
3256
|
+
if (opts.archiveTier) {
|
|
3257
|
+
archiveHandle = this.attachSnapshotStorage(
|
|
3258
|
+
[{ snapshot: opts.archiveTier }],
|
|
3259
|
+
opts.archiveStorageOptions ?? {}
|
|
3260
|
+
);
|
|
3261
|
+
this.addDisposer(() => archiveHandle?.dispose());
|
|
3262
|
+
}
|
|
3263
|
+
this.tiers = {
|
|
3264
|
+
permanent: this.permanent,
|
|
3265
|
+
activeEntries: this.store.store.entries,
|
|
3266
|
+
archiveHandle,
|
|
3267
|
+
tierOf,
|
|
3268
|
+
markPermanent
|
|
3269
|
+
};
|
|
3270
|
+
}
|
|
3271
|
+
};
|
|
3272
|
+
function memoryWithTiers(opts) {
|
|
3273
|
+
return new MemoryWithTiersGraph(opts);
|
|
3274
|
+
}
|
|
3275
|
+
function sharedPrefixDepth(q, e) {
|
|
3276
|
+
if (!q || !e) return 0;
|
|
3277
|
+
const n = Math.min(q.length, e.length);
|
|
3278
|
+
let i = 0;
|
|
3279
|
+
while (i < n && q[i] === e[i]) i++;
|
|
3280
|
+
return i;
|
|
3281
|
+
}
|
|
3282
|
+
var packedEquals = (a, b) => {
|
|
3283
|
+
if (a === b) return true;
|
|
3284
|
+
if (a.length !== b.length) return false;
|
|
3285
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
3286
|
+
return true;
|
|
3287
|
+
};
|
|
3288
|
+
var MemoryRetrievalGraph = class extends import_graph8.Graph {
|
|
3289
|
+
_store;
|
|
3290
|
+
_vectors;
|
|
3291
|
+
_kg;
|
|
3292
|
+
_opts;
|
|
3293
|
+
_contextNode;
|
|
3294
|
+
_topK;
|
|
3295
|
+
_graphDepth;
|
|
3296
|
+
_budget;
|
|
3297
|
+
_contextWeight;
|
|
3298
|
+
_retrieveSeq = 0;
|
|
3299
|
+
constructor(opts) {
|
|
3300
|
+
super(opts.name ?? "memory-retrieval", opts.graph);
|
|
3301
|
+
this._store = opts.store;
|
|
3302
|
+
this._vectors = opts.vectors ?? null;
|
|
3303
|
+
this._kg = opts.kg ?? null;
|
|
3304
|
+
this._opts = opts;
|
|
3305
|
+
this._topK = opts.topK ?? 20;
|
|
3306
|
+
this._graphDepth = opts.graphDepth ?? 1;
|
|
3307
|
+
this._budget = opts.budget ?? 2e3;
|
|
3308
|
+
this._contextWeight = opts.contextWeight ?? 0;
|
|
3309
|
+
if (opts.context) {
|
|
3310
|
+
this._contextNode = (0, import_extra13.fromAny)(opts.context);
|
|
3311
|
+
} else {
|
|
3312
|
+
this._contextNode = this.state("_context", null);
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
_runRetrieval(storeMap, ctx, query) {
|
|
3316
|
+
const opts = this._opts;
|
|
3317
|
+
const candidateMap = /* @__PURE__ */ new Map();
|
|
3318
|
+
let vectorCandidates = [];
|
|
3319
|
+
if (this._vectors && query.vector) {
|
|
3320
|
+
const q = query.vector;
|
|
3321
|
+
const snapshot = this._vectors.entries.cache;
|
|
3322
|
+
if (snapshot && snapshot.size > 0 && this._topK > 0) {
|
|
3323
|
+
const scored = [...snapshot.values()].map(
|
|
3324
|
+
(row) => ({
|
|
3325
|
+
id: row.id,
|
|
3326
|
+
score: cosineSimilarity(q, row.vector),
|
|
3327
|
+
...row.meta !== void 0 ? { meta: row.meta } : {}
|
|
3328
|
+
})
|
|
3329
|
+
).sort((a, b) => b.score - a.score).slice(0, this._topK);
|
|
3330
|
+
vectorCandidates = scored;
|
|
3331
|
+
for (const vc of vectorCandidates) {
|
|
3332
|
+
const mem = storeMap.get(vc.id);
|
|
3333
|
+
if (mem) candidateMap.set(vc.id, { value: mem, sources: /* @__PURE__ */ new Set(["vector"]) });
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3337
|
+
const graphExpanded = [];
|
|
3338
|
+
if (this._kg) {
|
|
3339
|
+
const adjOut = this._kg.adjacencyOut.cache;
|
|
3340
|
+
const adjIn = this._kg.adjacencyIn.cache;
|
|
3341
|
+
const seedIds = [...query.entityIds ?? [], ...[...candidateMap.keys()]];
|
|
3342
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3343
|
+
let frontier = seedIds;
|
|
3344
|
+
for (let depth = 0; depth < this._graphDepth; depth++) {
|
|
3345
|
+
const nextFrontier = [];
|
|
3346
|
+
for (const id of frontier) {
|
|
3347
|
+
if (visited.has(id)) continue;
|
|
3348
|
+
visited.add(id);
|
|
3349
|
+
const outEdges = adjOut?.get(id) ?? [];
|
|
3350
|
+
const inEdges = adjIn?.get(id) ?? [];
|
|
3351
|
+
for (const edge of outEdges) {
|
|
3352
|
+
const targetId = edge.to;
|
|
3353
|
+
if (!visited.has(targetId)) {
|
|
3354
|
+
nextFrontier.push(targetId);
|
|
3355
|
+
const mem = storeMap.get(targetId);
|
|
3356
|
+
if (mem) {
|
|
3357
|
+
const existing = candidateMap.get(targetId);
|
|
3358
|
+
if (existing) existing.sources.add("graph");
|
|
3359
|
+
else candidateMap.set(targetId, { value: mem, sources: /* @__PURE__ */ new Set(["graph"]) });
|
|
3360
|
+
graphExpanded.push(targetId);
|
|
3361
|
+
}
|
|
3362
|
+
}
|
|
3363
|
+
}
|
|
3364
|
+
for (const edge of inEdges) {
|
|
3365
|
+
const targetId = edge.from;
|
|
3366
|
+
if (!visited.has(targetId)) {
|
|
3367
|
+
nextFrontier.push(targetId);
|
|
3368
|
+
const mem = storeMap.get(targetId);
|
|
3369
|
+
if (mem) {
|
|
3370
|
+
const existing = candidateMap.get(targetId);
|
|
3371
|
+
if (existing) existing.sources.add("graph");
|
|
3372
|
+
else candidateMap.set(targetId, { value: mem, sources: /* @__PURE__ */ new Set(["graph"]) });
|
|
3373
|
+
graphExpanded.push(targetId);
|
|
3374
|
+
}
|
|
3375
|
+
}
|
|
3376
|
+
}
|
|
3377
|
+
}
|
|
3378
|
+
frontier = nextFrontier;
|
|
3379
|
+
}
|
|
3380
|
+
}
|
|
3381
|
+
for (const [key, mem] of storeMap) {
|
|
3382
|
+
if (!candidateMap.has(key)) {
|
|
3383
|
+
candidateMap.set(key, { value: mem, sources: /* @__PURE__ */ new Set(["store"]) });
|
|
3384
|
+
}
|
|
3385
|
+
}
|
|
3386
|
+
const qDepth = query.context?.length ?? 0;
|
|
3387
|
+
const ranked = [];
|
|
3388
|
+
for (const [key, { value, sources }] of candidateMap) {
|
|
3389
|
+
const entryContext = opts.contextOf ? opts.contextOf(value) : void 0;
|
|
3390
|
+
let score = opts.score(value, ctx);
|
|
3391
|
+
if (this._contextWeight > 0 && qDepth > 0) {
|
|
3392
|
+
const shared = sharedPrefixDepth(query.context, entryContext);
|
|
3393
|
+
if (shared > 0) score = score * (1 + this._contextWeight * shared / qDepth);
|
|
3394
|
+
}
|
|
3395
|
+
const entry = entryContext ? { key, value, score, sources: [...sources], context: entryContext } : { key, value, score, sources: [...sources] };
|
|
3396
|
+
ranked.push(entry);
|
|
3397
|
+
}
|
|
3398
|
+
ranked.sort((a, b) => b.score - a.score);
|
|
3399
|
+
const packed = [];
|
|
3400
|
+
let usedBudget = 0;
|
|
3401
|
+
for (const entry of ranked) {
|
|
3402
|
+
const c = opts.cost(entry.value);
|
|
3403
|
+
if (usedBudget + c > this._budget && packed.length > 0) break;
|
|
3404
|
+
packed.push(entry);
|
|
3405
|
+
usedBudget += c;
|
|
3406
|
+
}
|
|
3407
|
+
return { packed, trace: { vectorCandidates, graphExpanded, ranked, packed } };
|
|
3408
|
+
}
|
|
3409
|
+
/**
|
|
3410
|
+
* Reactive consumer API — chain into the graph.
|
|
3411
|
+
*
|
|
3412
|
+
* Each call constructs its own per-input subgraph mounted at
|
|
3413
|
+
* `retrieve_${id}` (auto-incrementing within this MemoryRetrievalGraph
|
|
3414
|
+
* instance) with named nodes:
|
|
3415
|
+
*
|
|
3416
|
+
* - `context` — `fromAny(queryInput)` projection (so the input node is
|
|
3417
|
+
* visible to `describe()` even when callers pass a raw value).
|
|
3418
|
+
* - `result` — pure derived `{ packed, trace }`.
|
|
3419
|
+
* - `projection` — the packed-array node returned to the caller.
|
|
3420
|
+
*
|
|
3421
|
+
* `result` declares the substrate's `store.entries`, the optional
|
|
3422
|
+
* `context` Node, the local `context` projection, and (when configured)
|
|
3423
|
+
* `vectors.entries` / `kg.adjacencyOut` / `kg.adjacencyIn` as deps —
|
|
3424
|
+
* so vector upserts and KG mutations re-trigger retrieval even when
|
|
3425
|
+
* the input is unchanged.
|
|
3426
|
+
*
|
|
3427
|
+
* **Lifecycle contract (DS-13.5.C, 2026-05-01).** The per-call subgraph
|
|
3428
|
+
* stays mounted while the returned `projection` has at least one
|
|
3429
|
+
* subscriber. When the last subscriber unsubscribes, projection's
|
|
3430
|
+
* `deactivate` cleanup hook fires (canonical "last unsubscribe" signal
|
|
3431
|
+
* via the existing `NodeFnCleanup.onDeactivation` protocol), which calls
|
|
3432
|
+
* `parent.remove(retrieve_${id})` and tears the per-call topology
|
|
3433
|
+
* down via TEARDOWN cascade (post-DS-13.5.A Q16, COMPLETE auto-precedes).
|
|
3434
|
+
*
|
|
3435
|
+
* **Single-shot lifecycle.** This auto-unmount is keyed to the FIRST
|
|
3436
|
+
* last-unsubscribe event — projection is non-resubscribable from the
|
|
3437
|
+
* caller's perspective. Callers who need to subscribe / unsubscribe /
|
|
3438
|
+
* re-subscribe should hold a long-lived subscription externally (e.g.
|
|
3439
|
+
* `keepalive(projection)`) or call `retrieveReactive(...)` again to
|
|
3440
|
+
* mount a fresh per-call subgraph.
|
|
3441
|
+
*
|
|
3442
|
+
* **Caller obligation.** Either subscribe to `projection` (and
|
|
3443
|
+
* eventually unsubscribe to trigger cleanup) OR drop the returned
|
|
3444
|
+
* reference without subscribing — in the no-subscribe case the
|
|
3445
|
+
* subgraph is dormant (no compute fires) and a parent `destroy()`
|
|
3446
|
+
* cascade reclaims it. Holding `projection` without subscribing AND
|
|
3447
|
+
* without ever destroying the parent is the leak case the JSDoc above
|
|
3448
|
+
* the C1 rework covers.
|
|
3449
|
+
*
|
|
3450
|
+
* One-shot callers use `awaitSettled(retrieveReactive(input))`.
|
|
3451
|
+
*/
|
|
3452
|
+
retrieveReactive(queryInput) {
|
|
3453
|
+
const id = ++this._retrieveSeq;
|
|
3454
|
+
const segment = `retrieve_${id}`;
|
|
3455
|
+
const sub = new import_graph8.Graph(segment);
|
|
3456
|
+
const inputNode = (0, import_extra13.fromAny)(queryInput);
|
|
3457
|
+
const localContext = sub.derived(
|
|
3458
|
+
"context",
|
|
3459
|
+
[inputNode],
|
|
3460
|
+
(batchData, ctx) => {
|
|
3461
|
+
const data = batchData.map(
|
|
3462
|
+
(b, i) => b != null && b.length > 0 ? b.at(-1) : ctx.prevData[i]
|
|
3463
|
+
);
|
|
3464
|
+
return [data[0] ?? null];
|
|
3465
|
+
},
|
|
3466
|
+
{
|
|
3467
|
+
meta: aiMeta("retrieval_query_input"),
|
|
3468
|
+
initial: null
|
|
3469
|
+
}
|
|
3470
|
+
);
|
|
3471
|
+
const resultDeps = [
|
|
3472
|
+
this._store.store.entries,
|
|
3473
|
+
this._contextNode,
|
|
3474
|
+
localContext
|
|
3475
|
+
];
|
|
3476
|
+
if (this._vectors) resultDeps.push(this._vectors.entries);
|
|
3477
|
+
if (this._kg) {
|
|
3478
|
+
resultDeps.push(this._kg.adjacencyOut);
|
|
3479
|
+
resultDeps.push(this._kg.adjacencyIn);
|
|
3480
|
+
}
|
|
3481
|
+
const result = sub.derived(
|
|
3482
|
+
"result",
|
|
3483
|
+
resultDeps,
|
|
3484
|
+
(batchData, ctx) => {
|
|
3485
|
+
const data = batchData.map(
|
|
3486
|
+
(b, i) => b != null && b.length > 0 ? b.at(-1) : ctx.prevData[i]
|
|
3487
|
+
);
|
|
3488
|
+
const query = data[2];
|
|
3489
|
+
if (query == null) {
|
|
3490
|
+
return [{ packed: [], trace: null }];
|
|
3491
|
+
}
|
|
3492
|
+
const storeMap = data[0] ?? /* @__PURE__ */ new Map();
|
|
3493
|
+
const { packed, trace } = this._runRetrieval(storeMap, data[1], query);
|
|
3494
|
+
return [{ packed, trace }];
|
|
3495
|
+
},
|
|
3496
|
+
{
|
|
3497
|
+
meta: aiMeta("retrieval_reactive_result"),
|
|
3498
|
+
initial: { packed: [], trace: null }
|
|
3499
|
+
}
|
|
3500
|
+
);
|
|
3501
|
+
const projection = (0, import_core16.node)(
|
|
3502
|
+
[result],
|
|
3503
|
+
(batchData, actions, ctx) => {
|
|
3504
|
+
const data = batchData.map(
|
|
3505
|
+
(b, i) => b != null && b.length > 0 ? b.at(-1) : ctx.prevData[i]
|
|
3506
|
+
);
|
|
3507
|
+
actions.emit(data[0].packed);
|
|
3508
|
+
return {
|
|
3509
|
+
onDeactivation: () => {
|
|
3510
|
+
try {
|
|
3511
|
+
this.remove(segment);
|
|
3512
|
+
} catch {
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
};
|
|
3516
|
+
},
|
|
3517
|
+
{
|
|
3518
|
+
name: "projection",
|
|
3519
|
+
describeKind: "derived",
|
|
3520
|
+
meta: aiMeta("retrieval_reactive"),
|
|
3521
|
+
initial: [],
|
|
3522
|
+
equals: packedEquals
|
|
3523
|
+
}
|
|
3524
|
+
);
|
|
3525
|
+
sub.add(projection, { name: "projection" });
|
|
3526
|
+
this.mount(segment, sub);
|
|
3527
|
+
return projection;
|
|
3528
|
+
}
|
|
3529
|
+
};
|
|
3530
|
+
function memoryRetrieval(opts) {
|
|
3531
|
+
return new MemoryRetrievalGraph(opts);
|
|
3532
|
+
}
|
|
3533
|
+
|
|
3534
|
+
// src/utils/ai/prompts/prompt-call.ts
|
|
3535
|
+
var import_core18 = require("@graphrefly/pure-ts/core");
|
|
3536
|
+
|
|
3537
|
+
// src/utils/ai/prompts/prompt-node.ts
|
|
3538
|
+
var import_core17 = require("@graphrefly/pure-ts/core");
|
|
3539
|
+
var import_extra14 = require("@graphrefly/pure-ts/extra");
|
|
3540
|
+
function extractContent(resp) {
|
|
3541
|
+
if (resp != null && typeof resp === "object" && "content" in resp) {
|
|
3542
|
+
return String(resp.content);
|
|
3543
|
+
}
|
|
3544
|
+
if (typeof resp === "string") return resp;
|
|
3545
|
+
return String(resp);
|
|
3546
|
+
}
|
|
3547
|
+
function previewContent(text, max = 200) {
|
|
3548
|
+
if (text.length <= max) return text;
|
|
3549
|
+
return `${text.slice(0, max)}\u2026`;
|
|
3550
|
+
}
|
|
3551
|
+
function promptNode(adapter, deps, prompt, opts) {
|
|
3552
|
+
const format = opts?.format ?? "text";
|
|
3553
|
+
const baseName = opts?.name ?? "prompt_node";
|
|
3554
|
+
if (opts?.tools !== void 0 && format !== "raw") {
|
|
3555
|
+
console.warn(
|
|
3556
|
+
"promptNode: `tools` is set but `format !== 'raw'`. Tool calls in the response will be silently dropped \u2014 set `format: 'raw'` to receive the full LLMResponse with `toolCalls`."
|
|
3557
|
+
);
|
|
3558
|
+
}
|
|
3559
|
+
const userDepsLength = deps.length;
|
|
3560
|
+
const allDeps = opts?.tools !== void 0 ? [...deps, opts.tools] : deps;
|
|
3561
|
+
const messagesNode = (0, import_core17.node)(
|
|
3562
|
+
allDeps,
|
|
3563
|
+
(batchData, actions, ctx) => {
|
|
3564
|
+
const data = batchData.map(
|
|
3565
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
3566
|
+
);
|
|
3567
|
+
const userValues = data.slice(0, userDepsLength);
|
|
3568
|
+
const toolsValue = opts?.tools !== void 0 ? data[userDepsLength] : void 0;
|
|
3569
|
+
if (userValues.some((v) => v == null)) {
|
|
3570
|
+
actions.emit({ messages: [], tools: toolsValue });
|
|
3571
|
+
return;
|
|
3572
|
+
}
|
|
3573
|
+
const text = typeof prompt === "string" ? prompt : prompt(...userValues);
|
|
3574
|
+
if (!text) {
|
|
3575
|
+
actions.emit({ messages: [], tools: toolsValue });
|
|
3576
|
+
return;
|
|
3577
|
+
}
|
|
3578
|
+
actions.emit({
|
|
3579
|
+
messages: [{ role: "user", content: text }],
|
|
3580
|
+
tools: toolsValue
|
|
3581
|
+
});
|
|
3582
|
+
},
|
|
3583
|
+
{
|
|
3584
|
+
name: `${baseName}::messages`,
|
|
3585
|
+
meta: aiMeta("prompt_node::messages")
|
|
3586
|
+
}
|
|
3587
|
+
);
|
|
3588
|
+
const result = (0, import_extra14.switchMap)(
|
|
3589
|
+
messagesNode,
|
|
3590
|
+
(envelope) => {
|
|
3591
|
+
const { messages: msgs, tools } = envelope;
|
|
3592
|
+
if (!msgs || msgs.length === 0) {
|
|
3593
|
+
return (0, import_core17.node)([], { initial: null });
|
|
3594
|
+
}
|
|
3595
|
+
return (0, import_core17.node)(
|
|
3596
|
+
(_data, actions) => {
|
|
3597
|
+
let done = false;
|
|
3598
|
+
let cancelled = false;
|
|
3599
|
+
let abortDispose;
|
|
3600
|
+
const invokeOpts = {
|
|
3601
|
+
model: opts?.model,
|
|
3602
|
+
temperature: opts?.temperature,
|
|
3603
|
+
maxTokens: opts?.maxTokens,
|
|
3604
|
+
systemPrompt: opts?.systemPrompt,
|
|
3605
|
+
...tools !== void 0 ? { tools } : {}
|
|
3606
|
+
};
|
|
3607
|
+
if (opts?.abort) {
|
|
3608
|
+
const sig = nodeSignal(opts.abort);
|
|
3609
|
+
invokeOpts.signal = sig.signal;
|
|
3610
|
+
abortDispose = sig.dispose;
|
|
3611
|
+
}
|
|
3612
|
+
let invokeResult;
|
|
3613
|
+
try {
|
|
3614
|
+
invokeResult = adapter.invoke(msgs, invokeOpts);
|
|
3615
|
+
} catch (err) {
|
|
3616
|
+
done = true;
|
|
3617
|
+
actions.down([[import_core17.ERROR, err]]);
|
|
3618
|
+
return () => {
|
|
3619
|
+
abortDispose?.();
|
|
3620
|
+
};
|
|
3621
|
+
}
|
|
3622
|
+
const callNode = (0, import_extra14.fromAny)(invokeResult);
|
|
3623
|
+
const sub = callNode.subscribe((batch8) => {
|
|
3624
|
+
if (cancelled || done) return;
|
|
3625
|
+
for (const msg of batch8) {
|
|
3626
|
+
if (cancelled || done) return;
|
|
3627
|
+
if (msg[0] === import_core17.DATA) {
|
|
3628
|
+
const resp = msg[1];
|
|
3629
|
+
if (format === "raw") {
|
|
3630
|
+
actions.emit(resp);
|
|
3631
|
+
} else {
|
|
3632
|
+
let content;
|
|
3633
|
+
try {
|
|
3634
|
+
content = extractContent(resp);
|
|
3635
|
+
} catch (err) {
|
|
3636
|
+
const wrapped = new Error(
|
|
3637
|
+
`promptNode: failed to extract content from LLM response: ${err.message}`
|
|
3638
|
+
);
|
|
3639
|
+
abortDispose?.();
|
|
3640
|
+
abortDispose = void 0;
|
|
3641
|
+
done = true;
|
|
3642
|
+
actions.down([[import_core17.ERROR, wrapped]]);
|
|
3643
|
+
return;
|
|
3644
|
+
}
|
|
3645
|
+
try {
|
|
3646
|
+
const parsed = format === "json" ? JSON.parse(stripFences(content)) : content;
|
|
3647
|
+
actions.emit(parsed);
|
|
3648
|
+
} catch (err) {
|
|
3649
|
+
const wrapped = new Error(
|
|
3650
|
+
`promptNode: failed to parse LLM response as JSON: ${err.message}
|
|
3651
|
+
Raw content (first 200 chars): ${previewContent(content)}`
|
|
3652
|
+
);
|
|
3653
|
+
abortDispose?.();
|
|
3654
|
+
abortDispose = void 0;
|
|
3655
|
+
done = true;
|
|
3656
|
+
actions.down([[import_core17.ERROR, wrapped]]);
|
|
3657
|
+
return;
|
|
3658
|
+
}
|
|
3659
|
+
}
|
|
3660
|
+
} else if (msg[0] === import_core17.ERROR) {
|
|
3661
|
+
abortDispose?.();
|
|
3662
|
+
abortDispose = void 0;
|
|
3663
|
+
done = true;
|
|
3664
|
+
actions.down([[import_core17.ERROR, msg[1]]]);
|
|
3665
|
+
return;
|
|
3666
|
+
} else if (msg[0] === import_core17.COMPLETE) {
|
|
3667
|
+
abortDispose?.();
|
|
3668
|
+
abortDispose = void 0;
|
|
3669
|
+
done = true;
|
|
3670
|
+
actions.down([[import_core17.COMPLETE]]);
|
|
3671
|
+
return;
|
|
3672
|
+
} else {
|
|
3673
|
+
actions.down([msg]);
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
});
|
|
3677
|
+
return () => {
|
|
3678
|
+
cancelled = true;
|
|
3679
|
+
sub();
|
|
3680
|
+
abortDispose?.();
|
|
3681
|
+
abortDispose = void 0;
|
|
3682
|
+
};
|
|
3683
|
+
},
|
|
3684
|
+
{
|
|
3685
|
+
describeKind: "producer",
|
|
3686
|
+
name: `${baseName}::response`,
|
|
3687
|
+
meta: aiMeta("prompt_node::response")
|
|
3688
|
+
}
|
|
3689
|
+
);
|
|
3690
|
+
},
|
|
3691
|
+
{
|
|
3692
|
+
name: `${baseName}::output`,
|
|
3693
|
+
meta: opts?.meta ? { ...aiMeta("prompt_node::output"), ...opts.meta } : aiMeta("prompt_node::output")
|
|
3694
|
+
}
|
|
3695
|
+
);
|
|
3696
|
+
return result;
|
|
3697
|
+
}
|
|
3698
|
+
|
|
3699
|
+
// src/utils/ai/prompts/prompt-call.ts
|
|
3700
|
+
function promptCall(systemPrompt, buildUserContent, opts, defaultName) {
|
|
3701
|
+
const name = opts.name ?? defaultName;
|
|
3702
|
+
return (input) => {
|
|
3703
|
+
const inputState = (0, import_core18.node)([], { initial: input });
|
|
3704
|
+
return promptNode(
|
|
3705
|
+
opts.adapter,
|
|
3706
|
+
[inputState],
|
|
3707
|
+
(value) => buildUserContent(value),
|
|
3708
|
+
{
|
|
3709
|
+
name,
|
|
3710
|
+
format: "json",
|
|
3711
|
+
systemPrompt,
|
|
3712
|
+
model: opts.model,
|
|
3713
|
+
temperature: opts.temperature ?? 0,
|
|
3714
|
+
maxTokens: opts.maxTokens
|
|
3715
|
+
}
|
|
3716
|
+
);
|
|
3717
|
+
};
|
|
3718
|
+
}
|
|
3719
|
+
function llmExtractor(systemPrompt, opts) {
|
|
3720
|
+
const cap = opts.maxExistingKeys ?? 100;
|
|
3721
|
+
const call = promptCall(
|
|
3722
|
+
systemPrompt,
|
|
3723
|
+
(input) => JSON.stringify({ input: input.raw, existingKeys: input.existingKeys }),
|
|
3724
|
+
opts,
|
|
3725
|
+
"llmExtractor"
|
|
3726
|
+
);
|
|
3727
|
+
return (raw, existing) => {
|
|
3728
|
+
const existingKeys = cap === Number.POSITIVE_INFINITY ? [...existing.keys()] : [...existing.keys()].slice(0, cap);
|
|
3729
|
+
return call({ raw, existingKeys });
|
|
3730
|
+
};
|
|
3731
|
+
}
|
|
3732
|
+
function llmConsolidator(systemPrompt, opts) {
|
|
3733
|
+
const call = promptCall(
|
|
3734
|
+
systemPrompt,
|
|
3735
|
+
(memories) => JSON.stringify({ memories }),
|
|
3736
|
+
opts,
|
|
3737
|
+
"llmConsolidator"
|
|
3738
|
+
);
|
|
3739
|
+
return (entries) => {
|
|
3740
|
+
const memories = [...entries.entries()].map(([key, value]) => ({ key, value }));
|
|
3741
|
+
return call(memories);
|
|
3742
|
+
};
|
|
3743
|
+
}
|
|
3744
|
+
|
|
3745
|
+
// src/presets/ai/agent-memory.ts
|
|
3746
|
+
var AgentMemoryGraph = class extends import_graph9.Graph {
|
|
3747
|
+
distillBundle;
|
|
3748
|
+
compact;
|
|
3749
|
+
size;
|
|
3750
|
+
/** Vector index bundle (null if not enabled). */
|
|
3751
|
+
vectors;
|
|
3752
|
+
/** Knowledge graph (null if not enabled). */
|
|
3753
|
+
kg;
|
|
3754
|
+
/** Memory tiers bundle (null if not configured). */
|
|
3755
|
+
memoryTiers;
|
|
3756
|
+
/**
|
|
3757
|
+
* The mounted `MemoryWithTiersGraph` subgraph (null when `opts.tiers` was
|
|
3758
|
+
* omitted). Surfaces the inner graph for `describe()` / `explain()` walks
|
|
3759
|
+
* and for callers that need direct access to the tiers subgraph (e.g.
|
|
3760
|
+
* to register additional disposers or attach storage). Companion to
|
|
3761
|
+
* `memoryTiers`, which carries only the bundle's reactive surface (B5e).
|
|
3762
|
+
*/
|
|
3763
|
+
tiers;
|
|
3764
|
+
/**
|
|
3765
|
+
* Reactive consumer API. Given a reactive `RetrievalQuery | null` source,
|
|
3766
|
+
* returns a `Node` emitting the packed retrieval results. Composable with
|
|
3767
|
+
* graph topology — subscribe it, chain it into `promptNode`, or switchMap
|
|
3768
|
+
* over a user-input node.
|
|
3769
|
+
*
|
|
3770
|
+
* Each call mounts its own per-input subgraph at
|
|
3771
|
+
* `retrieval::retrieve_${id}` (via `MemoryRetrievalGraph`); concurrent
|
|
3772
|
+
* calls don't share state mirrors. One-shot consumers wrap with
|
|
3773
|
+
* `awaitSettled(retrieveReactive(query))`.
|
|
3774
|
+
*
|
|
3775
|
+
* Null when no retrieval pipeline is configured.
|
|
3776
|
+
*
|
|
3777
|
+
* **QA F-9 (2026-04-30):** the prior `retrieval` / `retrievalTrace`
|
|
3778
|
+
* shared state-node mirrors have been dropped. Use `retrieveReactive`
|
|
3779
|
+
* for per-call reactive results; one-shot trace consumers should
|
|
3780
|
+
* subscribe to the projection's upstream `result` derived directly
|
|
3781
|
+
* via `view.target.resolve("retrieval::retrieve_${id}::result")`.
|
|
3782
|
+
*/
|
|
3783
|
+
retrieveReactive;
|
|
3784
|
+
constructor(name, source, opts) {
|
|
3785
|
+
super(name, opts.graph);
|
|
3786
|
+
let rawExtractFn;
|
|
3787
|
+
if (opts.extractFn) {
|
|
3788
|
+
rawExtractFn = opts.extractFn;
|
|
3789
|
+
} else if (opts.adapter && opts.extractPrompt) {
|
|
3790
|
+
rawExtractFn = llmExtractor(opts.extractPrompt, { adapter: opts.adapter });
|
|
3791
|
+
} else {
|
|
3792
|
+
throw new Error("agentMemory: provide either extractFn or adapter + extractPrompt");
|
|
3793
|
+
}
|
|
3794
|
+
this.tagFactory("agentMemory", (0, import_core19.placeholderArgs)(opts));
|
|
3795
|
+
const extractFn = (rawNode, existingNode) => {
|
|
3796
|
+
let latestExisting = existingNode.cache ?? /* @__PURE__ */ new Map();
|
|
3797
|
+
const unsubExisting = existingNode.subscribe((msgs) => {
|
|
3798
|
+
for (const m of msgs) {
|
|
3799
|
+
if (m[0] === import_core19.DATA) latestExisting = m[1];
|
|
3800
|
+
}
|
|
3801
|
+
});
|
|
3802
|
+
this.addDisposer(unsubExisting);
|
|
3803
|
+
return (0, import_extra15.switchMap)(rawNode, (raw) => {
|
|
3804
|
+
if (raw == null) return { upsert: [] };
|
|
3805
|
+
return rawExtractFn(raw, latestExisting);
|
|
3806
|
+
});
|
|
3807
|
+
};
|
|
3808
|
+
let filteredSource = source;
|
|
3809
|
+
if (opts.admissionFilter) {
|
|
3810
|
+
const srcNode = (0, import_extra15.fromAny)(source);
|
|
3811
|
+
const filter = opts.admissionFilter;
|
|
3812
|
+
filteredSource = (0, import_core19.node)(
|
|
3813
|
+
[srcNode],
|
|
3814
|
+
(batchData, actions, ctx) => {
|
|
3815
|
+
const data = batchData.map(
|
|
3816
|
+
(batch8, i) => batch8 != null && batch8.length > 0 ? batch8.at(-1) : ctx.prevData[i]
|
|
3817
|
+
);
|
|
3818
|
+
const raw = data[0];
|
|
3819
|
+
if (filter(raw)) {
|
|
3820
|
+
actions.emit(raw);
|
|
3821
|
+
} else {
|
|
3822
|
+
actions.down([[import_core19.RESOLVED]]);
|
|
3823
|
+
}
|
|
3824
|
+
},
|
|
3825
|
+
{ name: "admissionFilter", describeKind: "derived" }
|
|
3826
|
+
);
|
|
3827
|
+
}
|
|
3828
|
+
let consolidateFn;
|
|
3829
|
+
if (opts.consolidateFn) {
|
|
3830
|
+
consolidateFn = opts.consolidateFn;
|
|
3831
|
+
} else if (opts.adapter && opts.consolidatePrompt) {
|
|
3832
|
+
consolidateFn = llmConsolidator(opts.consolidatePrompt, { adapter: opts.adapter });
|
|
3833
|
+
}
|
|
3834
|
+
let consolidateTrigger = opts.consolidateTrigger;
|
|
3835
|
+
if (!consolidateTrigger && consolidateFn && opts.reflection?.enabled !== false) {
|
|
3836
|
+
const interval = opts.reflection?.interval ?? 3e5;
|
|
3837
|
+
consolidateTrigger = (0, import_extra15.fromTimer)(interval, { period: interval });
|
|
3838
|
+
}
|
|
3839
|
+
const distillOpts = {
|
|
3840
|
+
score: opts.score,
|
|
3841
|
+
cost: opts.cost,
|
|
3842
|
+
budget: opts.budget ?? 2e3,
|
|
3843
|
+
context: opts.context,
|
|
3844
|
+
consolidate: consolidateFn,
|
|
3845
|
+
consolidateTrigger
|
|
3846
|
+
};
|
|
3847
|
+
let distillBundle;
|
|
3848
|
+
let memoryTiersBundle = null;
|
|
3849
|
+
let tiersSubgraph = null;
|
|
3850
|
+
if (opts.tiers) {
|
|
3851
|
+
const tiersGraph = memoryWithTiers({
|
|
3852
|
+
// User customization first; canonical agent-memory-level overrides
|
|
3853
|
+
// last so they always win even if `MemoryTiersOptions` later adds
|
|
3854
|
+
// any of the same keys.
|
|
3855
|
+
...opts.tiers,
|
|
3856
|
+
name: "tiers",
|
|
3857
|
+
source: filteredSource,
|
|
3858
|
+
extractFn,
|
|
3859
|
+
score: opts.score,
|
|
3860
|
+
cost: opts.cost,
|
|
3861
|
+
...opts.budget !== void 0 ? { budget: opts.budget } : { budget: 2e3 },
|
|
3862
|
+
...opts.context !== void 0 ? { context: opts.context } : {},
|
|
3863
|
+
...consolidateFn !== void 0 ? { consolidate: consolidateFn } : {},
|
|
3864
|
+
...consolidateTrigger !== void 0 ? { consolidateTrigger } : {}
|
|
3865
|
+
});
|
|
3866
|
+
this.mount("tiers", tiersGraph);
|
|
3867
|
+
distillBundle = tiersGraph.store;
|
|
3868
|
+
memoryTiersBundle = tiersGraph.tiers;
|
|
3869
|
+
tiersSubgraph = tiersGraph;
|
|
3870
|
+
} else {
|
|
3871
|
+
distillBundle = distill(filteredSource, extractFn, distillOpts);
|
|
3872
|
+
this.add(distillBundle.store.entries, { name: "store" });
|
|
3873
|
+
this.add(distillBundle.compact, { name: "compact" });
|
|
3874
|
+
this.add(distillBundle.size, { name: "size" });
|
|
3875
|
+
}
|
|
3876
|
+
let vectors = null;
|
|
3877
|
+
if (opts.vectorDimensions && opts.vectorDimensions > 0 && opts.embedFn) {
|
|
3878
|
+
const vectorsGraph = memoryWithVectors({
|
|
3879
|
+
name: "vectors",
|
|
3880
|
+
store: distillBundle,
|
|
3881
|
+
dimension: opts.vectorDimensions,
|
|
3882
|
+
embedFn: opts.embedFn
|
|
3883
|
+
});
|
|
3884
|
+
this.mount("vectors", vectorsGraph);
|
|
3885
|
+
vectors = vectorsGraph.vectors;
|
|
3886
|
+
}
|
|
3887
|
+
let kg = null;
|
|
3888
|
+
if (opts.enableKnowledgeGraph) {
|
|
3889
|
+
const kgGraph = memoryWithKG({
|
|
3890
|
+
name: "knowledge",
|
|
3891
|
+
store: distillBundle,
|
|
3892
|
+
kgName: `${name}-kg`,
|
|
3893
|
+
mountPath: "knowledge-kg",
|
|
3894
|
+
...opts.entityFn !== void 0 ? { entityFn: opts.entityFn } : {}
|
|
3895
|
+
});
|
|
3896
|
+
this.mount("knowledge", kgGraph);
|
|
3897
|
+
kg = kgGraph.kg;
|
|
3898
|
+
}
|
|
3899
|
+
let retrieveReactive = null;
|
|
3900
|
+
if (vectors || kg) {
|
|
3901
|
+
const retrievalGraph = memoryRetrieval({
|
|
3902
|
+
name: "retrieval",
|
|
3903
|
+
store: distillBundle,
|
|
3904
|
+
vectors,
|
|
3905
|
+
kg,
|
|
3906
|
+
score: opts.score,
|
|
3907
|
+
cost: opts.cost,
|
|
3908
|
+
...opts.budget !== void 0 ? { budget: opts.budget } : {},
|
|
3909
|
+
...opts.retrieval?.topK !== void 0 ? { topK: opts.retrieval.topK } : {},
|
|
3910
|
+
...opts.retrieval?.graphDepth !== void 0 ? { graphDepth: opts.retrieval.graphDepth } : {},
|
|
3911
|
+
...opts.contextOf !== void 0 ? { contextOf: opts.contextOf } : {},
|
|
3912
|
+
...opts.contextWeight !== void 0 ? { contextWeight: opts.contextWeight } : {},
|
|
3913
|
+
...opts.context !== void 0 ? { context: opts.context } : {}
|
|
3914
|
+
});
|
|
3915
|
+
this.mount("retrieval", retrievalGraph);
|
|
3916
|
+
retrieveReactive = retrievalGraph.retrieveReactive.bind(retrievalGraph);
|
|
3917
|
+
}
|
|
3918
|
+
this.distillBundle = distillBundle;
|
|
3919
|
+
this.compact = distillBundle.compact;
|
|
3920
|
+
this.size = distillBundle.size;
|
|
3921
|
+
this.vectors = vectors;
|
|
3922
|
+
this.kg = kg;
|
|
3923
|
+
this.memoryTiers = memoryTiersBundle;
|
|
3924
|
+
this.tiers = tiersSubgraph;
|
|
3925
|
+
this.retrieveReactive = retrieveReactive;
|
|
3926
|
+
}
|
|
3927
|
+
};
|
|
3928
|
+
function agentMemory(name, source, opts) {
|
|
3929
|
+
return new AgentMemoryGraph(name, source, opts);
|
|
3930
|
+
}
|
|
3931
|
+
|
|
3932
|
+
// src/presets/ai/agents.ts
|
|
3933
|
+
var import_extra16 = require("@graphrefly/pure-ts/extra");
|
|
3934
|
+
function agent(parent, spec) {
|
|
3935
|
+
const graph = new AgentGraph(spec);
|
|
3936
|
+
parent.mount(spec.name, graph);
|
|
3937
|
+
return {
|
|
3938
|
+
in: graph.in,
|
|
3939
|
+
out: graph.out,
|
|
3940
|
+
status: graph.status,
|
|
3941
|
+
cost: graph.cost,
|
|
3942
|
+
graph
|
|
3943
|
+
};
|
|
3944
|
+
}
|
|
3945
|
+
function presetRegistry(initial) {
|
|
3946
|
+
const registry = (0, import_extra16.reactiveMap)({ name: "presetRegistry" });
|
|
3947
|
+
if (initial != null) {
|
|
3948
|
+
for (const [id, preset] of initial) {
|
|
3949
|
+
registry.set(id, preset);
|
|
3950
|
+
}
|
|
3951
|
+
}
|
|
3952
|
+
return {
|
|
3953
|
+
registry,
|
|
3954
|
+
put(id, preset) {
|
|
3955
|
+
registry.set(id, preset);
|
|
3956
|
+
},
|
|
3957
|
+
remove(id) {
|
|
3958
|
+
if (!registry.has(id)) return false;
|
|
3959
|
+
registry.delete(id);
|
|
3960
|
+
return true;
|
|
3961
|
+
}
|
|
3962
|
+
};
|
|
3963
|
+
}
|
|
3964
|
+
|
|
3965
|
+
// src/presets/ai/context/index.ts
|
|
3966
|
+
var import_core20 = require("@graphrefly/pure-ts/core");
|
|
3967
|
+
var import_extra17 = require("@graphrefly/pure-ts/extra");
|
|
3968
|
+
var import_graph10 = require("@graphrefly/pure-ts/graph");
|
|
3969
|
+
var CompressionCache = class {
|
|
3970
|
+
constructor(_max) {
|
|
3971
|
+
this._max = _max;
|
|
3972
|
+
}
|
|
3973
|
+
_m = /* @__PURE__ */ new Map();
|
|
3974
|
+
/** Insertion-order list of `id` keys for LRU eviction at the id granularity. */
|
|
3975
|
+
_order = [];
|
|
3976
|
+
get(id, tier) {
|
|
3977
|
+
const inner = this._m.get(id);
|
|
3978
|
+
const v = inner?.get(tier);
|
|
3979
|
+
if (v !== void 0) {
|
|
3980
|
+
const i = this._order.indexOf(id);
|
|
3981
|
+
if (i >= 0) this._order.splice(i, 1);
|
|
3982
|
+
this._order.push(id);
|
|
3983
|
+
}
|
|
3984
|
+
return v;
|
|
3985
|
+
}
|
|
3986
|
+
set(id, tier, value) {
|
|
3987
|
+
let inner = this._m.get(id);
|
|
3988
|
+
if (inner === void 0) {
|
|
3989
|
+
inner = /* @__PURE__ */ new Map();
|
|
3990
|
+
this._m.set(id, inner);
|
|
3991
|
+
}
|
|
3992
|
+
inner.set(tier, value);
|
|
3993
|
+
const i = this._order.indexOf(id);
|
|
3994
|
+
if (i >= 0) this._order.splice(i, 1);
|
|
3995
|
+
this._order.push(id);
|
|
3996
|
+
while (this._m.size > this._max) {
|
|
3997
|
+
const evict = this._order.shift();
|
|
3998
|
+
if (evict === void 0) break;
|
|
3999
|
+
this._m.delete(evict);
|
|
4000
|
+
}
|
|
4001
|
+
}
|
|
4002
|
+
};
|
|
4003
|
+
var _poolSeq = 0;
|
|
4004
|
+
function taggedContextPool(parent, opts) {
|
|
4005
|
+
const mountName = opts.name ?? `ctxpool-${opts.topic}-${++_poolSeq}`;
|
|
4006
|
+
const graph = new import_graph10.Graph(mountName);
|
|
4007
|
+
parent.mount(mountName, graph);
|
|
4008
|
+
const log = (0, import_extra17.reactiveLog)(void 0, {
|
|
4009
|
+
name: `${mountName}.log`,
|
|
4010
|
+
maxSize: opts.maxEntries
|
|
4011
|
+
});
|
|
4012
|
+
const cache = new CompressionCache(opts.cacheMax ?? 512);
|
|
4013
|
+
let autoId = 0;
|
|
4014
|
+
const entries = log.entries;
|
|
4015
|
+
function add(e) {
|
|
4016
|
+
const id = e.id ?? `ctx-${++autoId}`;
|
|
4017
|
+
log.append({
|
|
4018
|
+
id,
|
|
4019
|
+
payload: e.payload,
|
|
4020
|
+
tags: e.tags,
|
|
4021
|
+
importance: e.importance,
|
|
4022
|
+
compressible: e.compressible,
|
|
4023
|
+
topic: e.topic,
|
|
4024
|
+
t_ns: (0, import_core20.wallClockNs)()
|
|
4025
|
+
// QA P2 — clock.ts invariant (was Date.now()*1e6)
|
|
4026
|
+
});
|
|
4027
|
+
return id;
|
|
4028
|
+
}
|
|
4029
|
+
function byTag(tag) {
|
|
4030
|
+
return (0, import_core20.node)(
|
|
4031
|
+
[entries],
|
|
4032
|
+
(data, actions, ctx) => {
|
|
4033
|
+
const cur = data[0] != null && data[0].length > 0 ? data[0].at(-1) : ctx.prevData[0];
|
|
4034
|
+
actions.emit((cur ?? []).filter((x) => x.tags.includes(tag)));
|
|
4035
|
+
},
|
|
4036
|
+
{ describeKind: "derived", meta: aiMeta("contextPool.byTag", { tag }) }
|
|
4037
|
+
);
|
|
4038
|
+
}
|
|
4039
|
+
function poolGC(policy2) {
|
|
4040
|
+
const all = log.entries.cache ?? [];
|
|
4041
|
+
const nowNs = (0, import_core20.wallClockNs)();
|
|
4042
|
+
let survivors = all.filter((e) => {
|
|
4043
|
+
if (policy2.topic != null && e.topic !== policy2.topic) return true;
|
|
4044
|
+
if (policy2.olderThanNs != null && nowNs - e.t_ns >= policy2.olderThanNs) return false;
|
|
4045
|
+
if (policy2.importanceBelow != null && e.importance < policy2.importanceBelow) return false;
|
|
4046
|
+
return true;
|
|
4047
|
+
});
|
|
4048
|
+
if (policy2.max != null && survivors.length > policy2.max) {
|
|
4049
|
+
survivors = survivors.slice(survivors.length - policy2.max);
|
|
4050
|
+
}
|
|
4051
|
+
const removed = all.length - survivors.length;
|
|
4052
|
+
if (removed > 0) {
|
|
4053
|
+
log.clear();
|
|
4054
|
+
log.appendMany(survivors);
|
|
4055
|
+
}
|
|
4056
|
+
return removed;
|
|
4057
|
+
}
|
|
4058
|
+
return {
|
|
4059
|
+
add,
|
|
4060
|
+
entries,
|
|
4061
|
+
byTag,
|
|
4062
|
+
poolGC,
|
|
4063
|
+
graph,
|
|
4064
|
+
_cache: cache,
|
|
4065
|
+
_opts: opts,
|
|
4066
|
+
dispose() {
|
|
4067
|
+
log.dispose();
|
|
4068
|
+
}
|
|
4069
|
+
};
|
|
4070
|
+
}
|
|
4071
|
+
var DEFAULT_TOKENIZER = (s) => Math.ceil(s.length / 4);
|
|
4072
|
+
function matches(e, m) {
|
|
4073
|
+
if (m.topic != null) {
|
|
4074
|
+
if (typeof m.topic === "string" ? e.topic !== m.topic : !m.topic.test(e.topic)) return false;
|
|
4075
|
+
}
|
|
4076
|
+
if (m.tagsAny != null && !m.tagsAny.some((t) => e.tags.includes(t))) return false;
|
|
4077
|
+
if (m.importanceMin != null && e.importance < m.importanceMin) return false;
|
|
4078
|
+
if (m.importanceMax != null && e.importance > m.importanceMax) return false;
|
|
4079
|
+
if (m.compressible != null && e.compressible !== m.compressible) return false;
|
|
4080
|
+
return true;
|
|
4081
|
+
}
|
|
4082
|
+
function tierCompress(e, rules, pressure, cache, llmCompress) {
|
|
4083
|
+
const base = {
|
|
4084
|
+
id: e.id,
|
|
4085
|
+
topic: e.topic,
|
|
4086
|
+
tags: e.tags,
|
|
4087
|
+
tier: 0,
|
|
4088
|
+
payload: e.payload,
|
|
4089
|
+
compressed: false
|
|
4090
|
+
};
|
|
4091
|
+
if (pressure <= 0) return base;
|
|
4092
|
+
for (const rule of rules) {
|
|
4093
|
+
if (!matches(e, rule.match)) continue;
|
|
4094
|
+
switch (rule.action) {
|
|
4095
|
+
case "evict":
|
|
4096
|
+
return void 0;
|
|
4097
|
+
case "reference":
|
|
4098
|
+
return { ...base, tier: 1, payload: `[ref:${e.id}]`, compressed: true };
|
|
4099
|
+
case "truncate": {
|
|
4100
|
+
const s = typeof e.payload === "string" ? e.payload : JSON.stringify(e.payload);
|
|
4101
|
+
return {
|
|
4102
|
+
...base,
|
|
4103
|
+
tier: 1,
|
|
4104
|
+
payload: s.length > rule.maxChars ? s.slice(0, rule.maxChars) : s,
|
|
4105
|
+
compressed: s.length > rule.maxChars
|
|
4106
|
+
};
|
|
4107
|
+
}
|
|
4108
|
+
case "llm-summary": {
|
|
4109
|
+
if (!llmCompress) {
|
|
4110
|
+
throw new Error("tierCompress: 'llm-summary' rule requires `llmCompress`");
|
|
4111
|
+
}
|
|
4112
|
+
const cached = cache.get(e.id, rule.toTier);
|
|
4113
|
+
const text = cached ?? llmCompress(e, rule.toTier);
|
|
4114
|
+
if (cached === void 0) cache.set(e.id, rule.toTier, text);
|
|
4115
|
+
return { ...base, tier: rule.toTier, payload: text, compressed: true };
|
|
4116
|
+
}
|
|
4117
|
+
}
|
|
4118
|
+
}
|
|
4119
|
+
return base;
|
|
4120
|
+
}
|
|
4121
|
+
function renderContextView(pool, view) {
|
|
4122
|
+
const usesLlm = view.rules.some((r) => r.action === "llm-summary");
|
|
4123
|
+
if (usesLlm && !pool._opts.llmCompress) {
|
|
4124
|
+
throw new Error(
|
|
4125
|
+
"renderContextView: view has an 'llm-summary' rule but the pool was created without `llmCompress` (DS-14.6.A D-A3)."
|
|
4126
|
+
);
|
|
4127
|
+
}
|
|
4128
|
+
const tokenize = view.tokenizer ?? DEFAULT_TOKENIZER;
|
|
4129
|
+
const llmCompress = pool._opts.llmCompress;
|
|
4130
|
+
return (0, import_core20.node)(
|
|
4131
|
+
[pool.entries, view.pressure],
|
|
4132
|
+
(data, actions, ctx) => {
|
|
4133
|
+
const entries = data[0] != null && data[0].length > 0 ? data[0].at(-1) : ctx.prevData[0];
|
|
4134
|
+
const pressure = data[1] != null && data[1].length > 0 ? data[1].at(-1) : ctx.prevData[1];
|
|
4135
|
+
if (entries === void 0) {
|
|
4136
|
+
actions.emit([]);
|
|
4137
|
+
return;
|
|
4138
|
+
}
|
|
4139
|
+
const p = pressure ?? 0;
|
|
4140
|
+
const rendered = [];
|
|
4141
|
+
for (const e of entries) {
|
|
4142
|
+
if (!view.filter(e)) continue;
|
|
4143
|
+
const r = tierCompress(e, view.rules, p, pool._cache, llmCompress);
|
|
4144
|
+
if (r !== void 0) rendered.push(r);
|
|
4145
|
+
}
|
|
4146
|
+
const cost = (r) => tokenize(typeof r.payload === "string" ? r.payload : JSON.stringify(r.payload));
|
|
4147
|
+
let total = 0;
|
|
4148
|
+
for (const r of rendered) total += cost(r);
|
|
4149
|
+
if (total > view.budgetTokens) {
|
|
4150
|
+
const byImp = entries.reduce(
|
|
4151
|
+
(acc, e) => acc.set(e.id, e.importance),
|
|
4152
|
+
/* @__PURE__ */ new Map()
|
|
4153
|
+
);
|
|
4154
|
+
rendered.sort((a, b) => (byImp.get(a.id) ?? 0) - (byImp.get(b.id) ?? 0));
|
|
4155
|
+
while (total > view.budgetTokens && rendered.length > 0) {
|
|
4156
|
+
total -= cost(rendered.shift());
|
|
4157
|
+
}
|
|
4158
|
+
}
|
|
4159
|
+
actions.emit(rendered);
|
|
4160
|
+
},
|
|
4161
|
+
{ describeKind: "derived", meta: aiMeta("contextView", { topic: pool._opts.topic }) }
|
|
4162
|
+
);
|
|
4163
|
+
}
|
|
4164
|
+
|
|
4165
|
+
// src/presets/ai/debate/index.ts
|
|
4166
|
+
var import_core21 = require("@graphrefly/pure-ts/core");
|
|
4167
|
+
var import_extra18 = require("@graphrefly/pure-ts/extra");
|
|
4168
|
+
var import_graph11 = require("@graphrefly/pure-ts/graph");
|
|
4169
|
+
var DebateGraph = class extends import_graph11.Graph {
|
|
4170
|
+
};
|
|
4171
|
+
var SYNTH_RE = /synth/i;
|
|
4172
|
+
function defaultConverge(transcript) {
|
|
4173
|
+
const rounds = transcript.reduce((m, t) => Math.max(m, t.round), 0);
|
|
4174
|
+
if (rounds < 2) return false;
|
|
4175
|
+
const at = (r) => {
|
|
4176
|
+
const m = /* @__PURE__ */ new Map();
|
|
4177
|
+
for (const t of transcript) if (t.round === r) m.set(t.role, t.content);
|
|
4178
|
+
return m;
|
|
4179
|
+
};
|
|
4180
|
+
const prev = at(rounds - 1);
|
|
4181
|
+
const cur = at(rounds);
|
|
4182
|
+
if (prev.size === 0 || prev.size !== cur.size) return false;
|
|
4183
|
+
for (const [role, content] of cur) if (prev.get(role) !== content) return false;
|
|
4184
|
+
return true;
|
|
4185
|
+
}
|
|
4186
|
+
var _debateSeq = 0;
|
|
4187
|
+
function heterogeneousDebate(parent, opts) {
|
|
4188
|
+
const output = opts.output ?? "transcript";
|
|
4189
|
+
if (output === "synthesizer-final" && !opts.participants.some((p) => SYNTH_RE.test(p.role))) {
|
|
4190
|
+
throw new Error(
|
|
4191
|
+
"heterogeneousDebate: output 'synthesizer-final' requires a participant whose role matches /synth/i (DS-14.6.A D-C2)."
|
|
4192
|
+
);
|
|
4193
|
+
}
|
|
4194
|
+
if (opts.participants.length === 0) {
|
|
4195
|
+
throw new Error("heterogeneousDebate: at least one participant is required");
|
|
4196
|
+
}
|
|
4197
|
+
const name = opts.name ?? `debate-${++_debateSeq}`;
|
|
4198
|
+
const graph = new DebateGraph(name);
|
|
4199
|
+
parent.mount(name, graph);
|
|
4200
|
+
const term = opts.rounds ?? 3;
|
|
4201
|
+
const maxRounds = opts.maxRounds ?? 12;
|
|
4202
|
+
const converge = opts.converge ?? defaultConverge;
|
|
4203
|
+
const untilNode = typeof term === "object" ? term.until : (0, import_core21.node)([], { initial: false });
|
|
4204
|
+
const roundTrigger = (0, import_core21.node)([], { name: `${name}.round`, initial: 0 });
|
|
4205
|
+
const statusState = (0, import_core21.node)([], { name: `${name}.status`, initial: "running" });
|
|
4206
|
+
const resultState = (0, import_core21.node)([], { name: `${name}.result`, initial: void 0 });
|
|
4207
|
+
let history = [];
|
|
4208
|
+
function buildMessages(p) {
|
|
4209
|
+
const msgs = [
|
|
4210
|
+
{ role: "system", content: p.systemPrompt },
|
|
4211
|
+
{ role: "user", content: opts.question }
|
|
4212
|
+
];
|
|
4213
|
+
for (const t of history) {
|
|
4214
|
+
msgs.push({ role: "assistant", content: `[${t.role} r${t.round}] ${t.content}` });
|
|
4215
|
+
}
|
|
4216
|
+
return msgs;
|
|
4217
|
+
}
|
|
4218
|
+
const roundWork = (0, import_extra18.switchMap)(
|
|
4219
|
+
roundTrigger,
|
|
4220
|
+
(r) => (0, import_core21.node)(
|
|
4221
|
+
[],
|
|
4222
|
+
(_data, actions) => {
|
|
4223
|
+
if (r < 1) {
|
|
4224
|
+
actions.down([[import_core21.RESOLVED]]);
|
|
4225
|
+
return void 0;
|
|
4226
|
+
}
|
|
4227
|
+
const ac = new AbortController();
|
|
4228
|
+
let cancelled = false;
|
|
4229
|
+
(async () => {
|
|
4230
|
+
const turns = [];
|
|
4231
|
+
try {
|
|
4232
|
+
for (const p of opts.participants) {
|
|
4233
|
+
const res = await firstValueFrom(
|
|
4234
|
+
(0, import_extra18.fromAny)(
|
|
4235
|
+
p.adapter.invoke(buildMessages(p), {
|
|
4236
|
+
signal: ac.signal
|
|
4237
|
+
})
|
|
4238
|
+
)
|
|
4239
|
+
);
|
|
4240
|
+
if (cancelled) return;
|
|
4241
|
+
turns.push({ round: r, role: p.role, content: res.content });
|
|
4242
|
+
}
|
|
4243
|
+
if (!cancelled) actions.emit({ round: r, turns });
|
|
4244
|
+
} catch (err) {
|
|
4245
|
+
if (!cancelled) actions.down([[import_core21.ERROR, err]]);
|
|
4246
|
+
}
|
|
4247
|
+
})();
|
|
4248
|
+
return () => {
|
|
4249
|
+
cancelled = true;
|
|
4250
|
+
ac.abort();
|
|
4251
|
+
};
|
|
4252
|
+
},
|
|
4253
|
+
{ describeKind: "producer", name: `${name}.round-work` }
|
|
4254
|
+
),
|
|
4255
|
+
{ name: `${name}.rounds` }
|
|
4256
|
+
);
|
|
4257
|
+
graph.add(roundWork, { name: "rounds" });
|
|
4258
|
+
const transcript = (0, import_core21.node)(
|
|
4259
|
+
[roundWork],
|
|
4260
|
+
(batchData, actions, ctx) => {
|
|
4261
|
+
const env = batchData[0] != null && batchData[0].length > 0 ? batchData[0].at(-1) : ctx.prevData[0];
|
|
4262
|
+
if (env === void 0) {
|
|
4263
|
+
actions.down([[import_core21.RESOLVED]]);
|
|
4264
|
+
return;
|
|
4265
|
+
}
|
|
4266
|
+
actions.emit(history.slice());
|
|
4267
|
+
},
|
|
4268
|
+
{ name: `${name}.transcript`, describeKind: "derived" }
|
|
4269
|
+
);
|
|
4270
|
+
graph.add(transcript, { name: "transcript" });
|
|
4271
|
+
const converged = (0, import_core21.node)(
|
|
4272
|
+
[transcript, untilNode],
|
|
4273
|
+
(batchData, actions, ctx) => {
|
|
4274
|
+
const tr = batchData[0] != null && batchData[0].length > 0 ? batchData[0].at(-1) : ctx.prevData[0];
|
|
4275
|
+
const untilV = batchData[1] != null && batchData[1].length > 0 ? batchData[1].at(-1) : ctx.prevData[1];
|
|
4276
|
+
const rounds = (tr ?? []).reduce((m, t) => Math.max(m, t.round), 0);
|
|
4277
|
+
if (typeof term === "number") {
|
|
4278
|
+
actions.emit({ done: rounds >= term, reason: "max-rounds" });
|
|
4279
|
+
return;
|
|
4280
|
+
}
|
|
4281
|
+
if (term === "until-converge") {
|
|
4282
|
+
if (converge(tr ?? [])) actions.emit({ done: true, reason: "converged" });
|
|
4283
|
+
else actions.emit({ done: rounds >= maxRounds, reason: "max-rounds" });
|
|
4284
|
+
return;
|
|
4285
|
+
}
|
|
4286
|
+
actions.emit({ done: untilV === true || rounds >= maxRounds, reason: "max-rounds" });
|
|
4287
|
+
},
|
|
4288
|
+
{ name: `${name}.converged`, describeKind: "derived" }
|
|
4289
|
+
);
|
|
4290
|
+
graph.add(converged, { name: "converged" });
|
|
4291
|
+
const decideEffect = (0, import_core21.node)(
|
|
4292
|
+
[roundWork, untilNode],
|
|
4293
|
+
(batchData, _actions, ctx) => {
|
|
4294
|
+
const env = batchData[0] != null && batchData[0].length > 0 ? batchData[0].at(-1) : void 0;
|
|
4295
|
+
const untilV = batchData[1] != null && batchData[1].length > 0 ? batchData[1].at(-1) : ctx.prevData[1];
|
|
4296
|
+
if (env === void 0) {
|
|
4297
|
+
if (typeof term === "object" && untilV === true && statusState.cache === "running") {
|
|
4298
|
+
finalize("max-rounds");
|
|
4299
|
+
}
|
|
4300
|
+
return;
|
|
4301
|
+
}
|
|
4302
|
+
history = [...history, ...env.turns];
|
|
4303
|
+
const r = env.round;
|
|
4304
|
+
let done = false;
|
|
4305
|
+
let reason = "max-rounds";
|
|
4306
|
+
if (typeof term === "number") done = r >= term;
|
|
4307
|
+
else if (term === "until-converge") {
|
|
4308
|
+
if (converge(history)) {
|
|
4309
|
+
done = true;
|
|
4310
|
+
reason = "converged";
|
|
4311
|
+
} else done = r >= maxRounds;
|
|
4312
|
+
} else done = untilV === true || r >= maxRounds;
|
|
4313
|
+
if (done) finalize(reason);
|
|
4314
|
+
else roundTrigger.emit(r + 1);
|
|
4315
|
+
},
|
|
4316
|
+
{ name: `${name}.decide`, describeKind: "effect", errorWhenDepsError: false }
|
|
4317
|
+
);
|
|
4318
|
+
graph.add(decideEffect, { name: "decide" });
|
|
4319
|
+
function finalize(reason) {
|
|
4320
|
+
let out;
|
|
4321
|
+
if (output === "transcript") out = history.slice();
|
|
4322
|
+
else if (output === "synthesizer-final") {
|
|
4323
|
+
const synth = [...history].reverse().find((t) => SYNTH_RE.test(t.role));
|
|
4324
|
+
out = synth?.content ?? null;
|
|
4325
|
+
} else out = output.project(history.slice());
|
|
4326
|
+
(0, import_core21.batch)(() => {
|
|
4327
|
+
statusState.emit(reason);
|
|
4328
|
+
resultState.emit(out);
|
|
4329
|
+
});
|
|
4330
|
+
}
|
|
4331
|
+
const errorWatcher = (0, import_core21.node)(
|
|
4332
|
+
[roundWork],
|
|
4333
|
+
(_b, _a, ec) => {
|
|
4334
|
+
const t = ec.terminalDeps[0];
|
|
4335
|
+
if (t !== void 0 && t !== true && statusState.cache === "running") {
|
|
4336
|
+
(0, import_core21.batch)(() => {
|
|
4337
|
+
statusState.emit("error");
|
|
4338
|
+
resultState.emit(new Error("heterogeneousDebate: a participant adapter errored"));
|
|
4339
|
+
});
|
|
4340
|
+
}
|
|
4341
|
+
},
|
|
4342
|
+
{ name: `${name}.error-watcher`, describeKind: "effect", errorWhenDepsError: false }
|
|
4343
|
+
);
|
|
4344
|
+
graph.add(errorWatcher, { name: "error-watcher" });
|
|
4345
|
+
decideEffect.subscribe(() => void 0);
|
|
4346
|
+
errorWatcher.subscribe(() => void 0);
|
|
4347
|
+
transcript.subscribe(() => void 0);
|
|
4348
|
+
converged.subscribe(() => void 0);
|
|
4349
|
+
let running = false;
|
|
4350
|
+
return {
|
|
4351
|
+
transcript,
|
|
4352
|
+
result: resultState,
|
|
4353
|
+
status: statusState,
|
|
4354
|
+
graph,
|
|
4355
|
+
async run() {
|
|
4356
|
+
if (running) {
|
|
4357
|
+
throw new RangeError(
|
|
4358
|
+
`heterogeneousDebate "${name}": run() called while a previous run() is still pending`
|
|
4359
|
+
);
|
|
4360
|
+
}
|
|
4361
|
+
running = true;
|
|
4362
|
+
try {
|
|
4363
|
+
history = [];
|
|
4364
|
+
(0, import_core21.batch)(() => {
|
|
4365
|
+
statusState.emit("running");
|
|
4366
|
+
resultState.down([[import_core21.INVALIDATE]]);
|
|
4367
|
+
});
|
|
4368
|
+
const settled = awaitSettled(resultState, { skipCurrent: true });
|
|
4369
|
+
roundTrigger.emit(1);
|
|
4370
|
+
return await settled;
|
|
4371
|
+
} finally {
|
|
4372
|
+
running = false;
|
|
4373
|
+
}
|
|
4374
|
+
}
|
|
4375
|
+
};
|
|
4376
|
+
}
|
|
4377
|
+
//# sourceMappingURL=index.cjs.map
|