@graphrefly/graphrefly 0.45.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- 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/base/render/index.d.cts +227 -0
- package/dist/base/render/index.d.ts +227 -0
- 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/base/sources/index.d.cts +357 -0
- package/dist/base/sources/index.d.ts +357 -0
- 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/base/sources/node/index.d.cts +185 -0
- package/dist/base/sources/node/index.d.ts +185 -0
- 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-CSSbKGrJ.d.ts +199 -0
- package/dist/cascading-baGkiihI.d.cts +199 -0
- 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 +3083 -2
- package/dist/compat/index.cjs.map +1 -1
- package/dist/compat/index.d.cts +116 -1
- package/dist/compat/index.d.ts +116 -1
- package/dist/compat/index.js +175 -2
- package/dist/compat/index.js.map +1 -1
- package/dist/compat/jotai/index.cjs +130 -2
- package/dist/compat/jotai/index.cjs.map +1 -1
- package/dist/compat/jotai/index.d.cts +2 -1
- package/dist/compat/jotai/index.d.ts +2 -1
- package/dist/compat/jotai/index.js +7 -2
- package/dist/compat/jotai/index.js.map +1 -1
- package/dist/compat/nanostores/index.cjs +186 -2
- package/dist/compat/nanostores/index.cjs.map +1 -1
- package/dist/compat/nanostores/index.d.cts +2 -1
- package/dist/compat/nanostores/index.d.ts +2 -1
- package/dist/compat/nanostores/index.js +21 -2
- package/dist/compat/nanostores/index.js.map +1 -1
- package/dist/compat/nestjs/index.cjs +2224 -2
- package/dist/compat/nestjs/index.cjs.map +1 -1
- package/dist/compat/nestjs/index.d.cts +10 -1
- package/dist/compat/nestjs/index.d.ts +10 -1
- package/dist/compat/nestjs/index.js +77 -2
- package/dist/compat/nestjs/index.js.map +1 -1
- package/dist/compat/react/index.cjs +95 -2
- package/dist/compat/react/index.cjs.map +1 -1
- package/dist/compat/react/index.d.cts +2 -1
- package/dist/compat/react/index.d.ts +2 -1
- package/dist/compat/react/index.js +11 -2
- package/dist/compat/react/index.js.map +1 -1
- package/dist/compat/solid/index.cjs +82 -2
- package/dist/compat/solid/index.cjs.map +1 -1
- package/dist/compat/solid/index.d.cts +2 -1
- package/dist/compat/solid/index.d.ts +2 -1
- package/dist/compat/solid/index.js +11 -2
- package/dist/compat/solid/index.js.map +1 -1
- package/dist/compat/svelte/index.cjs +85 -2
- package/dist/compat/svelte/index.cjs.map +1 -1
- package/dist/compat/svelte/index.d.cts +2 -1
- package/dist/compat/svelte/index.d.ts +2 -1
- package/dist/compat/svelte/index.js +11 -2
- package/dist/compat/svelte/index.js.map +1 -1
- package/dist/compat/vue/index.cjs +100 -2
- package/dist/compat/vue/index.cjs.map +1 -1
- package/dist/compat/vue/index.d.cts +3 -1
- package/dist/compat/vue/index.d.ts +3 -1
- package/dist/compat/vue/index.js +11 -2
- package/dist/compat/vue/index.js.map +1 -1
- package/dist/compat/zustand/index.cjs +50 -2
- package/dist/compat/zustand/index.cjs.map +1 -1
- package/dist/compat/zustand/index.d.cts +2 -1
- package/dist/compat/zustand/index.d.ts +2 -1
- package/dist/compat/zustand/index.js +7 -2
- package/dist/compat/zustand/index.js.map +1 -1
- 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-Bx46zqky.d.cts +243 -0
- package/dist/fallback-pIWW8A2d.d.ts +243 -0
- package/dist/guarded-execution-BcdtxeBk.d.ts +207 -0
- package/dist/guarded-execution-C-3hnP6A.d.cts +207 -0
- package/dist/index-5SU_O78r.d.cts +754 -0
- package/dist/index-B6pxYJzO.d.cts +36 -0
- package/dist/index-B6pxYJzO.d.ts +36 -0
- package/dist/index-BFsng6v1.d.cts +44 -0
- package/dist/index-BFsng6v1.d.ts +44 -0
- package/dist/index-Bg-LwEt-.d.cts +45 -0
- package/dist/index-Bg-LwEt-.d.ts +45 -0
- package/dist/index-Brp888t0.d.cts +127 -0
- package/dist/index-Brp888t0.d.ts +127 -0
- package/dist/index-CDfk6jHN.d.cts +37 -0
- package/dist/index-CDfk6jHN.d.ts +37 -0
- package/dist/index-CEXCtYYJ.d.ts +754 -0
- package/dist/index-DLAxYaN5.d.cts +169 -0
- package/dist/index-DLAxYaN5.d.ts +169 -0
- package/dist/index-DeWbQzMe.d.cts +34 -0
- package/dist/index-DeWbQzMe.d.ts +34 -0
- package/dist/index-dX9IzPqj.d.cts +86 -0
- package/dist/index-dX9IzPqj.d.ts +86 -0
- package/dist/index.cjs +25950 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -42
- package/dist/index.d.ts +56 -42
- package/dist/index.js +849 -0
- package/dist/index.js.map +1 -1
- 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-BXQoW1P-.d.cts +36 -0
- package/dist/observable-BXQoW1P-.d.ts +36 -0
- package/dist/pipeline-graph-Ce47CB6Y.d.cts +145 -0
- package/dist/pipeline-graph-DXCwY9vG.d.ts +145 -0
- 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-fswlBUvX.d.cts +195 -0
- package/dist/reactive-layout-fswlBUvX.d.ts +195 -0
- 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-BB5Lw-pB.d.cts +442 -0
- package/dist/types-BB5Lw-pB.d.ts +442 -0
- 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/utils/ai/browser.d.cts +129 -0
- package/dist/utils/ai/browser.d.ts +129 -0
- 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/utils/ai/index.d.cts +1777 -0
- package/dist/utils/ai/index.d.ts +1777 -0
- 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/utils/ai/node.d.cts +57 -0
- package/dist/utils/ai/node.d.ts +57 -0
- 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/utils/cqrs/index.d.cts +438 -0
- package/dist/utils/cqrs/index.d.ts +438 -0
- 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/utils/demo-shell/index.d.cts +90 -0
- package/dist/utils/demo-shell/index.d.ts +90 -0
- 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/utils/domain-templates/index.d.cts +214 -0
- package/dist/utils/domain-templates/index.d.ts +214 -0
- 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/utils/graphspec/index.d.cts +449 -0
- package/dist/utils/graphspec/index.d.ts +449 -0
- 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/utils/job-queue/index.d.cts +200 -0
- package/dist/utils/job-queue/index.d.ts +200 -0
- 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/utils/memory/index.d.cts +582 -0
- package/dist/utils/memory/index.d.ts +582 -0
- 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/utils/process/index.d.cts +411 -0
- package/dist/utils/process/index.d.ts +411 -0
- 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/utils/reactive-layout/index.d.cts +492 -0
- package/dist/utils/reactive-layout/index.d.ts +492 -0
- 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/utils/reduction/index.d.cts +102 -0
- package/dist/utils/reduction/index.d.ts +102 -0
- 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/utils/surface/index.d.cts +240 -0
- package/dist/utils/surface/index.d.ts +240 -0
- 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 +293 -237
- package/dist/core/index.cjs +0 -21
- package/dist/core/index.cjs.map +0 -1
- package/dist/core/index.d.cts +0 -1
- package/dist/core/index.d.ts +0 -1
- package/dist/core/index.js +0 -3
- package/dist/core/index.js.map +0 -1
- package/dist/extra/browser.cjs +0 -21
- package/dist/extra/browser.cjs.map +0 -1
- package/dist/extra/browser.d.cts +0 -1
- package/dist/extra/browser.d.ts +0 -1
- package/dist/extra/browser.js +0 -3
- package/dist/extra/browser.js.map +0 -1
- package/dist/extra/index.cjs +0 -21
- package/dist/extra/index.cjs.map +0 -1
- package/dist/extra/index.d.cts +0 -1
- package/dist/extra/index.d.ts +0 -1
- package/dist/extra/index.js +0 -3
- package/dist/extra/index.js.map +0 -1
- package/dist/extra/node.cjs +0 -21
- package/dist/extra/node.cjs.map +0 -1
- package/dist/extra/node.d.cts +0 -1
- package/dist/extra/node.d.ts +0 -1
- package/dist/extra/node.js +0 -3
- package/dist/extra/node.js.map +0 -1
- package/dist/extra/operators.cjs +0 -21
- package/dist/extra/operators.cjs.map +0 -1
- package/dist/extra/operators.d.cts +0 -1
- package/dist/extra/operators.d.ts +0 -1
- package/dist/extra/operators.js +0 -3
- package/dist/extra/operators.js.map +0 -1
- package/dist/extra/reactive.cjs +0 -21
- package/dist/extra/reactive.cjs.map +0 -1
- package/dist/extra/reactive.d.cts +0 -1
- package/dist/extra/reactive.d.ts +0 -1
- package/dist/extra/reactive.js +0 -3
- package/dist/extra/reactive.js.map +0 -1
- package/dist/extra/render/index.cjs +0 -21
- package/dist/extra/render/index.cjs.map +0 -1
- package/dist/extra/render/index.d.cts +0 -1
- package/dist/extra/render/index.d.ts +0 -1
- package/dist/extra/render/index.js +0 -3
- package/dist/extra/render/index.js.map +0 -1
- package/dist/extra/sources.cjs +0 -21
- package/dist/extra/sources.cjs.map +0 -1
- package/dist/extra/sources.d.cts +0 -1
- package/dist/extra/sources.d.ts +0 -1
- package/dist/extra/sources.js +0 -3
- package/dist/extra/sources.js.map +0 -1
- package/dist/extra/storage-browser.cjs +0 -21
- package/dist/extra/storage-browser.cjs.map +0 -1
- package/dist/extra/storage-browser.d.cts +0 -1
- package/dist/extra/storage-browser.d.ts +0 -1
- package/dist/extra/storage-browser.js +0 -3
- package/dist/extra/storage-browser.js.map +0 -1
- package/dist/extra/storage-core.cjs +0 -21
- package/dist/extra/storage-core.cjs.map +0 -1
- package/dist/extra/storage-core.d.cts +0 -1
- package/dist/extra/storage-core.d.ts +0 -1
- package/dist/extra/storage-core.js +0 -3
- package/dist/extra/storage-core.js.map +0 -1
- package/dist/extra/storage-node.cjs +0 -21
- package/dist/extra/storage-node.cjs.map +0 -1
- package/dist/extra/storage-node.d.cts +0 -1
- package/dist/extra/storage-node.d.ts +0 -1
- package/dist/extra/storage-node.js +0 -3
- package/dist/extra/storage-node.js.map +0 -1
- package/dist/extra/storage-tiers-browser.cjs +0 -21
- package/dist/extra/storage-tiers-browser.cjs.map +0 -1
- package/dist/extra/storage-tiers-browser.d.cts +0 -1
- package/dist/extra/storage-tiers-browser.d.ts +0 -1
- package/dist/extra/storage-tiers-browser.js +0 -3
- package/dist/extra/storage-tiers-browser.js.map +0 -1
- package/dist/extra/storage-tiers-node.cjs +0 -21
- package/dist/extra/storage-tiers-node.cjs.map +0 -1
- package/dist/extra/storage-tiers-node.d.cts +0 -1
- package/dist/extra/storage-tiers-node.d.ts +0 -1
- package/dist/extra/storage-tiers-node.js +0 -3
- package/dist/extra/storage-tiers-node.js.map +0 -1
- package/dist/extra/storage-tiers.cjs +0 -21
- package/dist/extra/storage-tiers.cjs.map +0 -1
- package/dist/extra/storage-tiers.d.cts +0 -1
- package/dist/extra/storage-tiers.d.ts +0 -1
- package/dist/extra/storage-tiers.js +0 -3
- package/dist/extra/storage-tiers.js.map +0 -1
- package/dist/extra/storage-wal.cjs +0 -21
- package/dist/extra/storage-wal.cjs.map +0 -1
- package/dist/extra/storage-wal.d.cts +0 -1
- package/dist/extra/storage-wal.d.ts +0 -1
- package/dist/extra/storage-wal.js +0 -3
- package/dist/extra/storage-wal.js.map +0 -1
- package/dist/graph/index.cjs +0 -21
- package/dist/graph/index.cjs.map +0 -1
- package/dist/graph/index.d.cts +0 -1
- package/dist/graph/index.d.ts +0 -1
- package/dist/graph/index.js +0 -3
- package/dist/graph/index.js.map +0 -1
- package/dist/patterns/ai/browser.cjs +0 -21
- package/dist/patterns/ai/browser.cjs.map +0 -1
- package/dist/patterns/ai/browser.d.cts +0 -1
- package/dist/patterns/ai/browser.d.ts +0 -1
- package/dist/patterns/ai/browser.js +0 -3
- package/dist/patterns/ai/browser.js.map +0 -1
- package/dist/patterns/ai/index.cjs +0 -21
- package/dist/patterns/ai/index.cjs.map +0 -1
- package/dist/patterns/ai/index.d.cts +0 -1
- package/dist/patterns/ai/index.d.ts +0 -1
- package/dist/patterns/ai/index.js +0 -3
- package/dist/patterns/ai/index.js.map +0 -1
- package/dist/patterns/ai/node.cjs +0 -21
- package/dist/patterns/ai/node.cjs.map +0 -1
- package/dist/patterns/ai/node.d.cts +0 -1
- package/dist/patterns/ai/node.d.ts +0 -1
- package/dist/patterns/ai/node.js +0 -3
- package/dist/patterns/ai/node.js.map +0 -1
- package/dist/patterns/cqrs/index.cjs +0 -21
- package/dist/patterns/cqrs/index.cjs.map +0 -1
- package/dist/patterns/cqrs/index.d.cts +0 -1
- package/dist/patterns/cqrs/index.d.ts +0 -1
- package/dist/patterns/cqrs/index.js +0 -3
- package/dist/patterns/cqrs/index.js.map +0 -1
- package/dist/patterns/demo-shell/index.cjs +0 -21
- package/dist/patterns/demo-shell/index.cjs.map +0 -1
- package/dist/patterns/demo-shell/index.d.cts +0 -1
- package/dist/patterns/demo-shell/index.d.ts +0 -1
- package/dist/patterns/demo-shell/index.js +0 -3
- package/dist/patterns/demo-shell/index.js.map +0 -1
- package/dist/patterns/domain-templates/index.cjs +0 -21
- package/dist/patterns/domain-templates/index.cjs.map +0 -1
- package/dist/patterns/domain-templates/index.d.cts +0 -1
- package/dist/patterns/domain-templates/index.d.ts +0 -1
- package/dist/patterns/domain-templates/index.js +0 -3
- package/dist/patterns/domain-templates/index.js.map +0 -1
- package/dist/patterns/graphspec/index.cjs +0 -21
- package/dist/patterns/graphspec/index.cjs.map +0 -1
- package/dist/patterns/graphspec/index.d.cts +0 -1
- package/dist/patterns/graphspec/index.d.ts +0 -1
- package/dist/patterns/graphspec/index.js +0 -3
- package/dist/patterns/graphspec/index.js.map +0 -1
- package/dist/patterns/harness/index.cjs +0 -21
- package/dist/patterns/harness/index.cjs.map +0 -1
- package/dist/patterns/harness/index.d.cts +0 -1
- package/dist/patterns/harness/index.d.ts +0 -1
- package/dist/patterns/harness/index.js +0 -3
- package/dist/patterns/harness/index.js.map +0 -1
- package/dist/patterns/inspect/index.cjs +0 -21
- package/dist/patterns/inspect/index.cjs.map +0 -1
- package/dist/patterns/inspect/index.d.cts +0 -1
- package/dist/patterns/inspect/index.d.ts +0 -1
- package/dist/patterns/inspect/index.js +0 -3
- package/dist/patterns/inspect/index.js.map +0 -1
- package/dist/patterns/job-queue/index.cjs +0 -21
- package/dist/patterns/job-queue/index.cjs.map +0 -1
- package/dist/patterns/job-queue/index.d.cts +0 -1
- package/dist/patterns/job-queue/index.d.ts +0 -1
- package/dist/patterns/job-queue/index.js +0 -3
- package/dist/patterns/job-queue/index.js.map +0 -1
- package/dist/patterns/memory/index.cjs +0 -21
- package/dist/patterns/memory/index.cjs.map +0 -1
- package/dist/patterns/memory/index.d.cts +0 -1
- package/dist/patterns/memory/index.d.ts +0 -1
- package/dist/patterns/memory/index.js +0 -3
- package/dist/patterns/memory/index.js.map +0 -1
- package/dist/patterns/messaging/index.cjs +0 -21
- package/dist/patterns/messaging/index.cjs.map +0 -1
- package/dist/patterns/messaging/index.d.cts +0 -1
- package/dist/patterns/messaging/index.d.ts +0 -1
- package/dist/patterns/messaging/index.js +0 -3
- package/dist/patterns/messaging/index.js.map +0 -1
- package/dist/patterns/orchestration/index.cjs +0 -21
- package/dist/patterns/orchestration/index.cjs.map +0 -1
- package/dist/patterns/orchestration/index.d.cts +0 -1
- package/dist/patterns/orchestration/index.d.ts +0 -1
- package/dist/patterns/orchestration/index.js +0 -3
- package/dist/patterns/orchestration/index.js.map +0 -1
- package/dist/patterns/process/index.cjs +0 -21
- package/dist/patterns/process/index.cjs.map +0 -1
- package/dist/patterns/process/index.d.cts +0 -1
- package/dist/patterns/process/index.d.ts +0 -1
- package/dist/patterns/process/index.js +0 -3
- package/dist/patterns/process/index.js.map +0 -1
- package/dist/patterns/reactive-layout/index.cjs +0 -21
- package/dist/patterns/reactive-layout/index.cjs.map +0 -1
- package/dist/patterns/reactive-layout/index.d.cts +0 -1
- package/dist/patterns/reactive-layout/index.d.ts +0 -1
- package/dist/patterns/reactive-layout/index.js +0 -3
- package/dist/patterns/reactive-layout/index.js.map +0 -1
- package/dist/patterns/reduction/index.cjs +0 -21
- package/dist/patterns/reduction/index.cjs.map +0 -1
- package/dist/patterns/reduction/index.d.cts +0 -1
- package/dist/patterns/reduction/index.d.ts +0 -1
- package/dist/patterns/reduction/index.js +0 -3
- package/dist/patterns/reduction/index.js.map +0 -1
- package/dist/patterns/surface/index.cjs +0 -21
- package/dist/patterns/surface/index.cjs.map +0 -1
- package/dist/patterns/surface/index.d.cts +0 -1
- package/dist/patterns/surface/index.d.ts +0 -1
- package/dist/patterns/surface/index.js +0 -3
- package/dist/patterns/surface/index.js.map +0 -1
- package/dist/patterns/topology-view/index.cjs +0 -21
- package/dist/patterns/topology-view/index.cjs.map +0 -1
- package/dist/patterns/topology-view/index.d.cts +0 -1
- package/dist/patterns/topology-view/index.d.ts +0 -1
- package/dist/patterns/topology-view/index.js +0 -3
- package/dist/patterns/topology-view/index.js.map +0 -1
- package/dist/testing/index.cjs +0 -21
- package/dist/testing/index.cjs.map +0 -1
- package/dist/testing/index.d.cts +0 -1
- package/dist/testing/index.d.ts +0 -1
- package/dist/testing/index.js +0 -3
- package/dist/testing/index.js.map +0 -1
|
@@ -0,0 +1,2508 @@
|
|
|
1
|
+
import {
|
|
2
|
+
compileSpec
|
|
3
|
+
} from "./chunk-2OB3CEJS.js";
|
|
4
|
+
import {
|
|
5
|
+
pipelineGraph
|
|
6
|
+
} from "./chunk-CGHORL6G.js";
|
|
7
|
+
import {
|
|
8
|
+
cascadingLlmAdapter
|
|
9
|
+
} from "./chunk-4GYMCUDZ.js";
|
|
10
|
+
import {
|
|
11
|
+
CircuitOpenError,
|
|
12
|
+
adaptiveRateLimiter,
|
|
13
|
+
circuitBreaker
|
|
14
|
+
} from "./chunk-RJOG4IJU.js";
|
|
15
|
+
import {
|
|
16
|
+
adaptInvokeResult,
|
|
17
|
+
adapterWrapper,
|
|
18
|
+
buildCallStats,
|
|
19
|
+
dryRunAdapter,
|
|
20
|
+
emptyUsageStub,
|
|
21
|
+
withLayer,
|
|
22
|
+
withReplayCache
|
|
23
|
+
} from "./chunk-CXANAIZU.js";
|
|
24
|
+
import {
|
|
25
|
+
aiMeta,
|
|
26
|
+
resolveToolHandlerResult,
|
|
27
|
+
stripFences
|
|
28
|
+
} from "./chunk-OO5BM6CJ.js";
|
|
29
|
+
import {
|
|
30
|
+
topic
|
|
31
|
+
} from "./chunk-Q3EYOCZB.js";
|
|
32
|
+
import {
|
|
33
|
+
firstValueFrom
|
|
34
|
+
} from "./chunk-O3MT7DYI.js";
|
|
35
|
+
|
|
36
|
+
// src/utils/ai/adapters/core/capabilities.ts
|
|
37
|
+
import { node } from "@graphrefly/pure-ts/core";
|
|
38
|
+
import { reactiveMap } from "@graphrefly/pure-ts/extra";
|
|
39
|
+
function capKey(provider, model) {
|
|
40
|
+
return `${provider}::${model}`;
|
|
41
|
+
}
|
|
42
|
+
function createCapabilitiesRegistry(initial) {
|
|
43
|
+
const bundle = reactiveMap({
|
|
44
|
+
name: "capabilitiesRegistry"
|
|
45
|
+
});
|
|
46
|
+
const register = (cap) => {
|
|
47
|
+
bundle.set(capKey(cap.provider, cap.id), cap);
|
|
48
|
+
};
|
|
49
|
+
if (initial) for (const cap of initial) register(cap);
|
|
50
|
+
const lookupSync = (provider, model) => {
|
|
51
|
+
const exact = bundle.get(capKey(provider, model));
|
|
52
|
+
if (exact) return exact;
|
|
53
|
+
const snapshot = bundle.entries.cache;
|
|
54
|
+
if (!snapshot) return void 0;
|
|
55
|
+
let best;
|
|
56
|
+
for (const [, cap] of snapshot) {
|
|
57
|
+
if (cap.provider !== provider) continue;
|
|
58
|
+
const candidate = cap.id;
|
|
59
|
+
if (model.startsWith(candidate)) {
|
|
60
|
+
if (!best || candidate.length > best.id.length) {
|
|
61
|
+
best = cap;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return best;
|
|
66
|
+
};
|
|
67
|
+
const LOOKUP_CACHE_MAX = 128;
|
|
68
|
+
const lookupCache = /* @__PURE__ */ new Map();
|
|
69
|
+
const byProviderCache = /* @__PURE__ */ new Map();
|
|
70
|
+
const lruTouch = (cache, key, value, max) => {
|
|
71
|
+
if (cache.has(key)) cache.delete(key);
|
|
72
|
+
cache.set(key, value);
|
|
73
|
+
while (cache.size > max) {
|
|
74
|
+
const oldest = cache.keys().next().value;
|
|
75
|
+
if (oldest === void 0) break;
|
|
76
|
+
cache.delete(oldest);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const entriesNode = node(
|
|
80
|
+
[bundle.entries],
|
|
81
|
+
(batchData, actions, ctx) => {
|
|
82
|
+
const data = batchData.map(
|
|
83
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
84
|
+
);
|
|
85
|
+
const snapshot = data[0];
|
|
86
|
+
actions.emit(
|
|
87
|
+
snapshot instanceof Map ? Array.from(snapshot.values()) : []
|
|
88
|
+
);
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
describeKind: "derived",
|
|
92
|
+
name: "capabilitiesRegistry/entries",
|
|
93
|
+
initial: []
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
return {
|
|
97
|
+
register,
|
|
98
|
+
lookup: lookupSync,
|
|
99
|
+
remove(provider, model) {
|
|
100
|
+
const existed = bundle.has(capKey(provider, model));
|
|
101
|
+
if (existed) bundle.delete(capKey(provider, model));
|
|
102
|
+
return existed;
|
|
103
|
+
},
|
|
104
|
+
entries() {
|
|
105
|
+
const snapshot = bundle.entries.cache;
|
|
106
|
+
return (function* () {
|
|
107
|
+
if (!snapshot) return;
|
|
108
|
+
for (const cap of snapshot.values()) yield cap;
|
|
109
|
+
})();
|
|
110
|
+
},
|
|
111
|
+
lookupNode(provider, model) {
|
|
112
|
+
const cacheKey = capKey(provider, model);
|
|
113
|
+
const cached = lookupCache.get(cacheKey);
|
|
114
|
+
if (cached) {
|
|
115
|
+
lookupCache.delete(cacheKey);
|
|
116
|
+
lookupCache.set(cacheKey, cached);
|
|
117
|
+
return cached;
|
|
118
|
+
}
|
|
119
|
+
const lookupNode = node(
|
|
120
|
+
[bundle.entries],
|
|
121
|
+
(_batchData, actions) => {
|
|
122
|
+
actions.emit(lookupSync(provider, model));
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
describeKind: "derived",
|
|
126
|
+
name: `capabilitiesRegistry/lookup/${provider}::${model}`,
|
|
127
|
+
initial: void 0
|
|
128
|
+
}
|
|
129
|
+
);
|
|
130
|
+
lruTouch(lookupCache, cacheKey, lookupNode, LOOKUP_CACHE_MAX);
|
|
131
|
+
return lookupNode;
|
|
132
|
+
},
|
|
133
|
+
entriesNode,
|
|
134
|
+
byProvider(provider) {
|
|
135
|
+
const cached = byProviderCache.get(provider);
|
|
136
|
+
if (cached) {
|
|
137
|
+
byProviderCache.delete(provider);
|
|
138
|
+
byProviderCache.set(provider, cached);
|
|
139
|
+
return cached;
|
|
140
|
+
}
|
|
141
|
+
const providerNode = node(
|
|
142
|
+
[entriesNode],
|
|
143
|
+
(batchData, actions, ctx) => {
|
|
144
|
+
const data = batchData.map(
|
|
145
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
146
|
+
);
|
|
147
|
+
const entries = data[0];
|
|
148
|
+
actions.emit(entries.filter((c) => c.provider === provider));
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
describeKind: "derived",
|
|
152
|
+
name: `capabilitiesRegistry/byProvider/${provider}`,
|
|
153
|
+
initial: []
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
lruTouch(byProviderCache, provider, providerNode, LOOKUP_CACHE_MAX);
|
|
157
|
+
return providerNode;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// src/utils/ai/adapters/core/observable.ts
|
|
163
|
+
import { monotonicNs, node as node2, wallClockNs } from "@graphrefly/pure-ts/core";
|
|
164
|
+
import { keepalive, reactiveLog } from "@graphrefly/pure-ts/extra";
|
|
165
|
+
|
|
166
|
+
// src/utils/ai/adapters/core/types.ts
|
|
167
|
+
function sumInputTokens(u) {
|
|
168
|
+
const i = u.input;
|
|
169
|
+
const base = i.regular + (i.cacheRead ?? 0) + (i.cacheWrite5m ?? 0) + (i.cacheWrite1h ?? 0) + (i.cacheWriteOther ?? 0) + (i.audio ?? 0) + (i.image ?? 0) + (i.video ?? 0) + (i.toolUse ?? 0);
|
|
170
|
+
if (!i.extensions) return base;
|
|
171
|
+
let ext = 0;
|
|
172
|
+
for (const v of Object.values(i.extensions)) ext += v;
|
|
173
|
+
return base + ext;
|
|
174
|
+
}
|
|
175
|
+
function sumOutputTokens(u) {
|
|
176
|
+
const o = u.output;
|
|
177
|
+
const base = o.regular + (o.reasoning ?? 0) + (o.audio ?? 0) + (o.predictionAccepted ?? 0) + (o.predictionRejected ?? 0);
|
|
178
|
+
if (!o.extensions) return base;
|
|
179
|
+
let ext = 0;
|
|
180
|
+
for (const v of Object.values(o.extensions)) ext += v;
|
|
181
|
+
return base + ext;
|
|
182
|
+
}
|
|
183
|
+
function emptyUsage() {
|
|
184
|
+
return { input: { regular: 0 }, output: { regular: 0 } };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/utils/ai/adapters/core/observable.ts
|
|
188
|
+
function observableAdapter(inner, opts) {
|
|
189
|
+
const logMax = opts?.logMax ?? 1e3;
|
|
190
|
+
const allCalls = reactiveLog(void 0, {
|
|
191
|
+
name: opts?.name ? `${opts.name}/stats` : "adapterStats",
|
|
192
|
+
maxSize: logMax
|
|
193
|
+
});
|
|
194
|
+
const lastCall = node2([], {
|
|
195
|
+
name: "adapterStats/lastCall",
|
|
196
|
+
initial: null
|
|
197
|
+
});
|
|
198
|
+
const totalCalls = node2(
|
|
199
|
+
[allCalls.entries],
|
|
200
|
+
(batchData, actions, ctx) => {
|
|
201
|
+
const data = batchData.map(
|
|
202
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
203
|
+
);
|
|
204
|
+
const entries = data[0];
|
|
205
|
+
actions.emit(entries.length);
|
|
206
|
+
},
|
|
207
|
+
{ describeKind: "derived", name: "adapterStats/totalCalls", initial: 0 }
|
|
208
|
+
);
|
|
209
|
+
const totalInputTokens = node2(
|
|
210
|
+
[allCalls.entries],
|
|
211
|
+
(batchData, actions, ctx) => {
|
|
212
|
+
const data = batchData.map(
|
|
213
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
214
|
+
);
|
|
215
|
+
const entries = data[0];
|
|
216
|
+
actions.emit(entries.reduce((acc, ev) => acc + sumInputTokens(ev.usage), 0));
|
|
217
|
+
},
|
|
218
|
+
{ describeKind: "derived", name: "adapterStats/totalInputTokens", initial: 0 }
|
|
219
|
+
);
|
|
220
|
+
const totalOutputTokens = node2(
|
|
221
|
+
[allCalls.entries],
|
|
222
|
+
(batchData, actions, ctx) => {
|
|
223
|
+
const data = batchData.map(
|
|
224
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
225
|
+
);
|
|
226
|
+
const entries = data[0];
|
|
227
|
+
actions.emit(entries.reduce((acc, ev) => acc + sumOutputTokens(ev.usage), 0));
|
|
228
|
+
},
|
|
229
|
+
{ describeKind: "derived", name: "adapterStats/totalOutputTokens", initial: 0 }
|
|
230
|
+
);
|
|
231
|
+
const unsubKeepalives = [
|
|
232
|
+
keepalive(totalCalls),
|
|
233
|
+
keepalive(totalInputTokens),
|
|
234
|
+
keepalive(totalOutputTokens)
|
|
235
|
+
];
|
|
236
|
+
const record = (ev) => {
|
|
237
|
+
allCalls.append(ev);
|
|
238
|
+
lastCall.emit(ev);
|
|
239
|
+
};
|
|
240
|
+
const reset = () => {
|
|
241
|
+
allCalls.clear();
|
|
242
|
+
lastCall.emit(null);
|
|
243
|
+
};
|
|
244
|
+
const wrap = adapterWrapper(inner, {
|
|
245
|
+
invoke(messages, invokeOpts) {
|
|
246
|
+
const startNs = monotonicNs();
|
|
247
|
+
const startWallClockNs = wallClockNs();
|
|
248
|
+
const model = inner.model ?? invokeOpts?.model ?? "";
|
|
249
|
+
const recordResp = (resp) => {
|
|
250
|
+
record(
|
|
251
|
+
buildCallStats({
|
|
252
|
+
provider: inner.provider,
|
|
253
|
+
model: inner.model ?? invokeOpts?.model ?? resp.model ?? "",
|
|
254
|
+
tier: invokeOpts?.tier ?? resp.tier,
|
|
255
|
+
usage: resp.usage ?? emptyUsageStub(),
|
|
256
|
+
startNs,
|
|
257
|
+
startWallClockNs,
|
|
258
|
+
method: "invoke"
|
|
259
|
+
})
|
|
260
|
+
);
|
|
261
|
+
return resp;
|
|
262
|
+
};
|
|
263
|
+
const recordErr = (err) => {
|
|
264
|
+
const e = err;
|
|
265
|
+
record(
|
|
266
|
+
buildCallStats({
|
|
267
|
+
provider: inner.provider,
|
|
268
|
+
model,
|
|
269
|
+
tier: invokeOpts?.tier,
|
|
270
|
+
usage: emptyUsageStub(),
|
|
271
|
+
startNs,
|
|
272
|
+
startWallClockNs,
|
|
273
|
+
method: "invoke",
|
|
274
|
+
error: {
|
|
275
|
+
type: e?.name ?? "Error",
|
|
276
|
+
message: e?.message ?? String(err)
|
|
277
|
+
}
|
|
278
|
+
})
|
|
279
|
+
);
|
|
280
|
+
};
|
|
281
|
+
return adaptInvokeResult(inner.invoke(messages, invokeOpts), {
|
|
282
|
+
onResp: recordResp,
|
|
283
|
+
onError: recordErr,
|
|
284
|
+
name: "adapterStats/invokeTap"
|
|
285
|
+
});
|
|
286
|
+
},
|
|
287
|
+
async *stream(messages, invokeOpts) {
|
|
288
|
+
const startNs = monotonicNs();
|
|
289
|
+
const startWallClockNs = wallClockNs();
|
|
290
|
+
const model = inner.model ?? invokeOpts?.model ?? "";
|
|
291
|
+
let finalUsage;
|
|
292
|
+
try {
|
|
293
|
+
for await (const delta of inner.stream(messages, invokeOpts)) {
|
|
294
|
+
if (delta.type === "usage") finalUsage = delta.usage;
|
|
295
|
+
yield delta;
|
|
296
|
+
}
|
|
297
|
+
record(
|
|
298
|
+
buildCallStats({
|
|
299
|
+
provider: inner.provider,
|
|
300
|
+
model,
|
|
301
|
+
tier: invokeOpts?.tier,
|
|
302
|
+
usage: finalUsage ?? emptyUsageStub(),
|
|
303
|
+
startNs,
|
|
304
|
+
startWallClockNs,
|
|
305
|
+
method: "stream"
|
|
306
|
+
})
|
|
307
|
+
);
|
|
308
|
+
} catch (err) {
|
|
309
|
+
const e = err;
|
|
310
|
+
record(
|
|
311
|
+
buildCallStats({
|
|
312
|
+
provider: inner.provider,
|
|
313
|
+
model,
|
|
314
|
+
tier: invokeOpts?.tier,
|
|
315
|
+
usage: finalUsage ?? emptyUsageStub(),
|
|
316
|
+
startNs,
|
|
317
|
+
startWallClockNs,
|
|
318
|
+
method: "stream",
|
|
319
|
+
error: {
|
|
320
|
+
type: e?.name ?? "Error",
|
|
321
|
+
message: e?.message ?? String(err)
|
|
322
|
+
}
|
|
323
|
+
})
|
|
324
|
+
);
|
|
325
|
+
throw err;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
withLayer(wrap, "observableAdapter", inner);
|
|
330
|
+
let disposed = false;
|
|
331
|
+
const dispose = () => {
|
|
332
|
+
if (disposed) return;
|
|
333
|
+
disposed = true;
|
|
334
|
+
for (const fn of unsubKeepalives) fn();
|
|
335
|
+
unsubKeepalives.length = 0;
|
|
336
|
+
};
|
|
337
|
+
const stats = {
|
|
338
|
+
lastCall,
|
|
339
|
+
allCalls,
|
|
340
|
+
totalCalls,
|
|
341
|
+
totalInputTokens,
|
|
342
|
+
totalOutputTokens,
|
|
343
|
+
reset,
|
|
344
|
+
dispose
|
|
345
|
+
};
|
|
346
|
+
return { adapter: wrap, stats };
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// src/utils/ai/adapters/core/pricing.ts
|
|
350
|
+
function rateAt(rate, totalInput) {
|
|
351
|
+
if (rate == null) return 0;
|
|
352
|
+
if (typeof rate === "number") return rate;
|
|
353
|
+
if (rate.thresholdTokens != null && rate.pricePerMillionAbove != null && totalInput > rate.thresholdTokens) {
|
|
354
|
+
return rate.pricePerMillionAbove;
|
|
355
|
+
}
|
|
356
|
+
return rate.pricePerMillion;
|
|
357
|
+
}
|
|
358
|
+
function zeroPrice(currency = "USD") {
|
|
359
|
+
return { total: 0, currency };
|
|
360
|
+
}
|
|
361
|
+
function computePrice(usage, pricing, opts) {
|
|
362
|
+
const totalInput = sumInputTokens(usage);
|
|
363
|
+
const currency = pricing.currency ?? "USD";
|
|
364
|
+
const withBreakdown = opts?.withBreakdown === true;
|
|
365
|
+
const breakdown = withBreakdown ? {} : null;
|
|
366
|
+
let total = 0;
|
|
367
|
+
const addLine = (key, tokens, rate) => {
|
|
368
|
+
if (!tokens || rate == null) return;
|
|
369
|
+
const rateUsd = rateAt(rate, totalInput);
|
|
370
|
+
const line = tokens * rateUsd / 1e6;
|
|
371
|
+
total += line;
|
|
372
|
+
if (withBreakdown) breakdown[key] = (breakdown[key] ?? 0) + line;
|
|
373
|
+
};
|
|
374
|
+
const i = usage.input;
|
|
375
|
+
const pi = pricing.input;
|
|
376
|
+
if (pi) {
|
|
377
|
+
addLine("input.regular", i.regular, pi.regular);
|
|
378
|
+
addLine("input.cacheRead", i.cacheRead ?? 0, pi.cacheRead);
|
|
379
|
+
addLine("input.cacheWrite5m", i.cacheWrite5m ?? 0, pi.cacheWrite5m);
|
|
380
|
+
addLine("input.cacheWrite1h", i.cacheWrite1h ?? 0, pi.cacheWrite1h);
|
|
381
|
+
addLine("input.cacheWriteOther", i.cacheWriteOther ?? 0, pi.cacheWriteOther);
|
|
382
|
+
addLine("input.audio", i.audio ?? 0, pi.audio);
|
|
383
|
+
addLine("input.image", i.image ?? 0, pi.image);
|
|
384
|
+
addLine("input.video", i.video ?? 0, pi.video);
|
|
385
|
+
addLine("input.toolUse", i.toolUse ?? 0, pi.toolUse);
|
|
386
|
+
if (i.extensions && pi.extensions) {
|
|
387
|
+
for (const [k, v] of Object.entries(i.extensions)) {
|
|
388
|
+
addLine(`input.ext.${k}`, v, pi.extensions[k]);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
const o = usage.output;
|
|
393
|
+
const po = pricing.output;
|
|
394
|
+
if (po) {
|
|
395
|
+
addLine("output.regular", o.regular, po.regular);
|
|
396
|
+
addLine("output.reasoning", o.reasoning ?? 0, po.reasoning);
|
|
397
|
+
addLine("output.audio", o.audio ?? 0, po.audio);
|
|
398
|
+
addLine("output.predictionAccepted", o.predictionAccepted ?? 0, po.predictionAccepted);
|
|
399
|
+
addLine("output.predictionRejected", o.predictionRejected ?? 0, po.predictionRejected);
|
|
400
|
+
if (o.extensions && po.extensions) {
|
|
401
|
+
for (const [k, v] of Object.entries(o.extensions)) {
|
|
402
|
+
addLine(`output.ext.${k}`, v, po.extensions[k]);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
const tier = opts?.tier;
|
|
407
|
+
if (tier && pricing.tierMultipliers) {
|
|
408
|
+
const mult = pricing.tierMultipliers[tier];
|
|
409
|
+
if (mult != null) {
|
|
410
|
+
total *= mult;
|
|
411
|
+
if (withBreakdown) {
|
|
412
|
+
for (const k of Object.keys(breakdown)) breakdown[k] *= mult;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
const aux = usage.auxiliary;
|
|
417
|
+
const paux = pricing.auxiliary;
|
|
418
|
+
if (aux && paux) {
|
|
419
|
+
for (const [k, units] of Object.entries(aux)) {
|
|
420
|
+
const rate = paux[k];
|
|
421
|
+
if (rate == null || !units) continue;
|
|
422
|
+
const line = units * rate;
|
|
423
|
+
total += line;
|
|
424
|
+
if (withBreakdown) breakdown[`auxiliary.${k}`] = line;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return withBreakdown ? { total, currency, breakdown } : { total, currency };
|
|
428
|
+
}
|
|
429
|
+
function registryKey(provider, model) {
|
|
430
|
+
return `${provider}::${model}`;
|
|
431
|
+
}
|
|
432
|
+
function createPricingRegistry(initial) {
|
|
433
|
+
const map = /* @__PURE__ */ new Map();
|
|
434
|
+
const indexByProvider = /* @__PURE__ */ new Map();
|
|
435
|
+
const register = (provider, model, pricing) => {
|
|
436
|
+
map.set(registryKey(provider, model), { provider, model, pricing });
|
|
437
|
+
let models = indexByProvider.get(provider);
|
|
438
|
+
if (!models) {
|
|
439
|
+
models = /* @__PURE__ */ new Set();
|
|
440
|
+
indexByProvider.set(provider, models);
|
|
441
|
+
}
|
|
442
|
+
models.add(model);
|
|
443
|
+
};
|
|
444
|
+
if (initial) {
|
|
445
|
+
for (const [p, m, pricing] of initial) register(p, m, pricing);
|
|
446
|
+
}
|
|
447
|
+
return {
|
|
448
|
+
register,
|
|
449
|
+
lookup(provider, model) {
|
|
450
|
+
const exact = map.get(registryKey(provider, model));
|
|
451
|
+
if (exact) return exact.pricing;
|
|
452
|
+
const models = indexByProvider.get(provider);
|
|
453
|
+
if (!models) return void 0;
|
|
454
|
+
let best;
|
|
455
|
+
for (const candidate of models) {
|
|
456
|
+
if (model.startsWith(candidate)) {
|
|
457
|
+
if (!best || candidate.length > best.key.length) {
|
|
458
|
+
const entry = map.get(registryKey(provider, candidate));
|
|
459
|
+
if (entry) best = { key: candidate, pricing: entry.pricing };
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return best?.pricing;
|
|
464
|
+
},
|
|
465
|
+
remove(provider, model) {
|
|
466
|
+
const existed = map.delete(registryKey(provider, model));
|
|
467
|
+
if (existed) {
|
|
468
|
+
const models = indexByProvider.get(provider);
|
|
469
|
+
models?.delete(model);
|
|
470
|
+
if (models && models.size === 0) indexByProvider.delete(provider);
|
|
471
|
+
}
|
|
472
|
+
return existed;
|
|
473
|
+
},
|
|
474
|
+
entries() {
|
|
475
|
+
const iter = map.values();
|
|
476
|
+
return (function* () {
|
|
477
|
+
for (const { provider, model, pricing } of iter) {
|
|
478
|
+
yield [provider, model, pricing];
|
|
479
|
+
}
|
|
480
|
+
})();
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
function registryPricing(registry, defaultCurrency = "USD") {
|
|
485
|
+
return (usage, ctx) => {
|
|
486
|
+
const pricing = registry.lookup(ctx.provider, ctx.model);
|
|
487
|
+
if (!pricing) return zeroPrice(defaultCurrency);
|
|
488
|
+
return computePrice(usage, pricing, { tier: ctx.tier, withBreakdown: ctx.withBreakdown });
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
function composePricing(...fns) {
|
|
492
|
+
return (usage, ctx) => {
|
|
493
|
+
for (const fn of fns) {
|
|
494
|
+
const p = fn(usage, ctx);
|
|
495
|
+
if (p.total !== 0) return p;
|
|
496
|
+
}
|
|
497
|
+
return fns.length > 0 ? fns[0](usage, ctx) : zeroPrice();
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
function pricingFor(capabilities, usage, opts) {
|
|
501
|
+
if (!capabilities?.pricing) return zeroPrice();
|
|
502
|
+
return computePrice(usage, capabilities.pricing, opts);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// src/utils/ai/adapters/middleware/breaker.ts
|
|
506
|
+
import { fromAny } from "@graphrefly/pure-ts/extra";
|
|
507
|
+
function withLLMBreaker(inner, opts = {}) {
|
|
508
|
+
const breaker = opts.breaker ?? circuitBreaker(opts);
|
|
509
|
+
const adapter = adapterWrapper(inner, {
|
|
510
|
+
async invoke(messages, invokeOpts) {
|
|
511
|
+
if (!breaker.canExecute()) throw new CircuitOpenError();
|
|
512
|
+
try {
|
|
513
|
+
const resp = await firstValueFrom(fromAny(inner.invoke(messages, invokeOpts)));
|
|
514
|
+
breaker.recordSuccess();
|
|
515
|
+
return resp;
|
|
516
|
+
} catch (err) {
|
|
517
|
+
breaker.recordFailure(err);
|
|
518
|
+
throw err;
|
|
519
|
+
}
|
|
520
|
+
},
|
|
521
|
+
async *stream(messages, invokeOpts) {
|
|
522
|
+
if (!breaker.canExecute()) throw new CircuitOpenError();
|
|
523
|
+
try {
|
|
524
|
+
for await (const d of inner.stream(messages, invokeOpts)) yield d;
|
|
525
|
+
breaker.recordSuccess();
|
|
526
|
+
} catch (err) {
|
|
527
|
+
breaker.recordFailure(err);
|
|
528
|
+
throw err;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
withLayer(adapter, "withLLMBreaker", inner);
|
|
533
|
+
return { adapter, breaker };
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// src/utils/ai/adapters/middleware/budget-gate.ts
|
|
537
|
+
import { DATA, monotonicNs as monotonicNs2, node as node3 } from "@graphrefly/pure-ts/core";
|
|
538
|
+
import { keepalive as keepalive2, reactiveLog as reactiveLog2 } from "@graphrefly/pure-ts/extra";
|
|
539
|
+
var BudgetExhaustedError = class extends Error {
|
|
540
|
+
constructor(which, limit, observed) {
|
|
541
|
+
super(`Budget exhausted: ${which} (limit=${limit}, observed=${observed})`);
|
|
542
|
+
this.which = which;
|
|
543
|
+
this.limit = limit;
|
|
544
|
+
this.observed = observed;
|
|
545
|
+
}
|
|
546
|
+
name = "BudgetExhaustedError";
|
|
547
|
+
};
|
|
548
|
+
var EMPTY_TOTALS = Object.freeze({
|
|
549
|
+
calls: 0,
|
|
550
|
+
inputTokens: 0,
|
|
551
|
+
outputTokens: 0,
|
|
552
|
+
usd: 0
|
|
553
|
+
});
|
|
554
|
+
var makeEmptyTotals = () => ({
|
|
555
|
+
calls: 0,
|
|
556
|
+
inputTokens: 0,
|
|
557
|
+
outputTokens: 0,
|
|
558
|
+
usd: 0
|
|
559
|
+
});
|
|
560
|
+
function withBudgetGate(inner, opts) {
|
|
561
|
+
const log = reactiveLog2(void 0, {
|
|
562
|
+
name: opts.name ? `${opts.name}/log` : "budgetGate/log",
|
|
563
|
+
maxSize: opts.logMax ?? 1e3
|
|
564
|
+
});
|
|
565
|
+
const totals = node3([], {
|
|
566
|
+
name: opts.name ? `${opts.name}/totals` : "budgetGate/totals",
|
|
567
|
+
initial: makeEmptyTotals()
|
|
568
|
+
});
|
|
569
|
+
const isOpen = node3(
|
|
570
|
+
[totals],
|
|
571
|
+
(batchData, actions, ctx) => {
|
|
572
|
+
const data = batchData.map(
|
|
573
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
574
|
+
);
|
|
575
|
+
const tt = data[0];
|
|
576
|
+
if (opts.caps.calls != null && tt.calls >= opts.caps.calls) {
|
|
577
|
+
actions.emit(false);
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
if (opts.caps.inputTokens != null && tt.inputTokens >= opts.caps.inputTokens) {
|
|
581
|
+
actions.emit(false);
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
if (opts.caps.outputTokens != null && tt.outputTokens >= opts.caps.outputTokens) {
|
|
585
|
+
actions.emit(false);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
if (opts.caps.usd != null && tt.usd >= opts.caps.usd) {
|
|
589
|
+
actions.emit(false);
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
actions.emit(true);
|
|
593
|
+
},
|
|
594
|
+
{
|
|
595
|
+
describeKind: "derived",
|
|
596
|
+
name: opts.name ? `${opts.name}/isOpen` : "budgetGate/isOpen",
|
|
597
|
+
initial: true
|
|
598
|
+
}
|
|
599
|
+
);
|
|
600
|
+
const disposers = [];
|
|
601
|
+
let disposed = false;
|
|
602
|
+
disposers.push(keepalive2(isOpen));
|
|
603
|
+
if (opts.onExhausted != null) {
|
|
604
|
+
const handler = opts.onExhausted;
|
|
605
|
+
let seeded = false;
|
|
606
|
+
let wasOpen = true;
|
|
607
|
+
const unsub = isOpen.subscribe((msgs) => {
|
|
608
|
+
for (const m of msgs) {
|
|
609
|
+
if (m[0] === DATA) {
|
|
610
|
+
const v = m[1];
|
|
611
|
+
if (seeded && wasOpen && v === false) {
|
|
612
|
+
const which = pickExhaustedKey(totals.cache ?? EMPTY_TOTALS, opts.caps);
|
|
613
|
+
if (which) handler(which);
|
|
614
|
+
}
|
|
615
|
+
wasOpen = v;
|
|
616
|
+
seeded = true;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
});
|
|
620
|
+
disposers.push(unsub);
|
|
621
|
+
}
|
|
622
|
+
const buildClosedError = () => {
|
|
623
|
+
if (isOpen.cache === false) {
|
|
624
|
+
const t = totals.cache ?? EMPTY_TOTALS;
|
|
625
|
+
const which = pickExhaustedKey(t, opts.caps);
|
|
626
|
+
return new BudgetExhaustedError(
|
|
627
|
+
which ?? "budget",
|
|
628
|
+
opts.caps[which ?? "calls"] ?? 0,
|
|
629
|
+
whichValue(t, which ?? "calls")
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
return void 0;
|
|
633
|
+
};
|
|
634
|
+
const record = (usage, meta) => {
|
|
635
|
+
const provider = inner.provider;
|
|
636
|
+
const event = buildCallStats({
|
|
637
|
+
provider,
|
|
638
|
+
model: meta.model,
|
|
639
|
+
tier: meta.tier,
|
|
640
|
+
usage,
|
|
641
|
+
startNs: meta.startNs,
|
|
642
|
+
method: meta.method,
|
|
643
|
+
...meta.error ? { error: meta.error } : {}
|
|
644
|
+
});
|
|
645
|
+
log.append(event);
|
|
646
|
+
const prev = totals.cache ?? EMPTY_TOTALS;
|
|
647
|
+
const usd = opts.pricingFn ? prev.usd + opts.pricingFn(usage, { model: meta.model, provider, tier: meta.tier }).total : prev.usd;
|
|
648
|
+
totals.emit({
|
|
649
|
+
calls: prev.calls + 1,
|
|
650
|
+
inputTokens: prev.inputTokens + sumInputTokens(usage),
|
|
651
|
+
outputTokens: prev.outputTokens + sumOutputTokens(usage),
|
|
652
|
+
usd
|
|
653
|
+
});
|
|
654
|
+
};
|
|
655
|
+
const reset = () => {
|
|
656
|
+
log.clear();
|
|
657
|
+
totals.emit(makeEmptyTotals());
|
|
658
|
+
};
|
|
659
|
+
const inflight = /* @__PURE__ */ new Set();
|
|
660
|
+
let isOpenSeeded = false;
|
|
661
|
+
let isOpenWasOpen = true;
|
|
662
|
+
const isOpenAbortUnsub = isOpen.subscribe((msgs) => {
|
|
663
|
+
for (const m of msgs) {
|
|
664
|
+
if (m[0] !== DATA) continue;
|
|
665
|
+
const v = m[1];
|
|
666
|
+
if (isOpenSeeded && isOpenWasOpen && v === false && inflight.size > 0) {
|
|
667
|
+
const reason = buildClosedError() ?? new Error("budget exhausted");
|
|
668
|
+
for (const ctrl of inflight) {
|
|
669
|
+
try {
|
|
670
|
+
ctrl.abort(reason);
|
|
671
|
+
} catch {
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
isOpenWasOpen = v;
|
|
676
|
+
isOpenSeeded = true;
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
disposers.push(isOpenAbortUnsub);
|
|
680
|
+
function combineSignals(callerSignal) {
|
|
681
|
+
const ctrl = new AbortController();
|
|
682
|
+
if (isOpen.cache === false) {
|
|
683
|
+
ctrl.abort(buildClosedError() ?? new Error("budget exhausted"));
|
|
684
|
+
}
|
|
685
|
+
const onCallerAbort = () => {
|
|
686
|
+
if (!ctrl.signal.aborted) ctrl.abort(callerSignal.reason);
|
|
687
|
+
};
|
|
688
|
+
if (callerSignal != null) {
|
|
689
|
+
if (callerSignal.aborted) {
|
|
690
|
+
ctrl.abort(callerSignal.reason);
|
|
691
|
+
} else {
|
|
692
|
+
callerSignal.addEventListener("abort", onCallerAbort, { once: true });
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
inflight.add(ctrl);
|
|
696
|
+
const cleanup = () => {
|
|
697
|
+
inflight.delete(ctrl);
|
|
698
|
+
if (callerSignal != null) callerSignal.removeEventListener("abort", onCallerAbort);
|
|
699
|
+
};
|
|
700
|
+
return { ctrl, cleanup };
|
|
701
|
+
}
|
|
702
|
+
const wrap = adapterWrapper(inner, {
|
|
703
|
+
invoke(messages, invokeOpts) {
|
|
704
|
+
const closedErr = buildClosedError();
|
|
705
|
+
if (closedErr) return Promise.reject(closedErr);
|
|
706
|
+
const startNs = monotonicNs2();
|
|
707
|
+
const model = inner.model ?? invokeOpts?.model ?? "";
|
|
708
|
+
const { ctrl, cleanup } = combineSignals(invokeOpts?.signal);
|
|
709
|
+
const recordResp = (resp) => {
|
|
710
|
+
cleanup();
|
|
711
|
+
record(resp.usage ?? emptyUsageStub(), {
|
|
712
|
+
model: inner.model ?? invokeOpts?.model ?? resp.model ?? "",
|
|
713
|
+
tier: invokeOpts?.tier ?? resp.tier,
|
|
714
|
+
startNs,
|
|
715
|
+
method: "invoke"
|
|
716
|
+
});
|
|
717
|
+
return resp;
|
|
718
|
+
};
|
|
719
|
+
const recordErr = (err) => {
|
|
720
|
+
cleanup();
|
|
721
|
+
const e = err;
|
|
722
|
+
record(emptyUsageStub(), {
|
|
723
|
+
model,
|
|
724
|
+
tier: invokeOpts?.tier,
|
|
725
|
+
startNs,
|
|
726
|
+
method: "invoke",
|
|
727
|
+
error: { type: e?.name ?? "Error", message: e?.message ?? String(err) }
|
|
728
|
+
});
|
|
729
|
+
};
|
|
730
|
+
const innerOpts = { ...invokeOpts ?? {}, signal: ctrl.signal };
|
|
731
|
+
return adaptInvokeResult(inner.invoke(messages, innerOpts), {
|
|
732
|
+
onResp: recordResp,
|
|
733
|
+
onError: recordErr,
|
|
734
|
+
name: "budgetGate/invokeTap"
|
|
735
|
+
});
|
|
736
|
+
},
|
|
737
|
+
async *stream(messages, invokeOpts) {
|
|
738
|
+
const closedErr = buildClosedError();
|
|
739
|
+
if (closedErr) throw closedErr;
|
|
740
|
+
const startNs = monotonicNs2();
|
|
741
|
+
let finalUsage;
|
|
742
|
+
const { ctrl, cleanup } = combineSignals(invokeOpts?.signal);
|
|
743
|
+
const innerOpts = { ...invokeOpts ?? {}, signal: ctrl.signal };
|
|
744
|
+
try {
|
|
745
|
+
for await (const delta of inner.stream(messages, innerOpts)) {
|
|
746
|
+
if (delta.type === "usage") finalUsage = delta.usage;
|
|
747
|
+
yield delta;
|
|
748
|
+
}
|
|
749
|
+
cleanup();
|
|
750
|
+
record(finalUsage ?? emptyUsageStub(), {
|
|
751
|
+
model: inner.model ?? invokeOpts?.model ?? "",
|
|
752
|
+
tier: invokeOpts?.tier,
|
|
753
|
+
startNs,
|
|
754
|
+
method: "stream"
|
|
755
|
+
});
|
|
756
|
+
} catch (err) {
|
|
757
|
+
cleanup();
|
|
758
|
+
const error = err;
|
|
759
|
+
record(finalUsage ?? emptyUsageStub(), {
|
|
760
|
+
model: inner.model ?? invokeOpts?.model ?? "",
|
|
761
|
+
tier: invokeOpts?.tier,
|
|
762
|
+
startNs,
|
|
763
|
+
method: "stream",
|
|
764
|
+
error: { type: error?.name ?? "Error", message: error?.message ?? String(err) }
|
|
765
|
+
});
|
|
766
|
+
throw err;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
withLayer(wrap, "withBudgetGate", inner);
|
|
771
|
+
const dispose = () => {
|
|
772
|
+
if (disposed) return;
|
|
773
|
+
disposed = true;
|
|
774
|
+
const reason = new Error("withBudgetGate disposed");
|
|
775
|
+
for (const ctrl of inflight) {
|
|
776
|
+
try {
|
|
777
|
+
ctrl.abort(reason);
|
|
778
|
+
} catch {
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
inflight.clear();
|
|
782
|
+
for (const d of disposers) {
|
|
783
|
+
try {
|
|
784
|
+
d();
|
|
785
|
+
} catch {
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
disposers.length = 0;
|
|
789
|
+
};
|
|
790
|
+
return { adapter: wrap, budget: { totals, isOpen, log, reset, dispose } };
|
|
791
|
+
}
|
|
792
|
+
function pickExhaustedKey(t, caps) {
|
|
793
|
+
if (caps.calls != null && t.calls >= caps.calls) return "calls";
|
|
794
|
+
if (caps.inputTokens != null && t.inputTokens >= caps.inputTokens) return "inputTokens";
|
|
795
|
+
if (caps.outputTokens != null && t.outputTokens >= caps.outputTokens) return "outputTokens";
|
|
796
|
+
if (caps.usd != null && t.usd >= caps.usd) return "usd";
|
|
797
|
+
return void 0;
|
|
798
|
+
}
|
|
799
|
+
function whichValue(t, which) {
|
|
800
|
+
switch (which) {
|
|
801
|
+
case "calls":
|
|
802
|
+
return t.calls;
|
|
803
|
+
case "inputTokens":
|
|
804
|
+
return t.inputTokens;
|
|
805
|
+
case "outputTokens":
|
|
806
|
+
return t.outputTokens;
|
|
807
|
+
case "usd":
|
|
808
|
+
return t.usd;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// src/utils/ai/adapters/middleware/dry-run.ts
|
|
813
|
+
import { fromAny as fromAny2, keepalive as keepalive3 } from "@graphrefly/pure-ts/extra";
|
|
814
|
+
function withDryRun(inner, opts) {
|
|
815
|
+
const mock = opts.mock ?? dryRunAdapter({ provider: inner.provider, model: inner.model });
|
|
816
|
+
const enabledLiteral = typeof opts.enabled === "boolean" ? opts.enabled : void 0;
|
|
817
|
+
const enabledNode = enabledLiteral === void 0 ? fromAny2(opts.enabled) : void 0;
|
|
818
|
+
let unsubKeepalive;
|
|
819
|
+
if (enabledNode) unsubKeepalive = keepalive3(enabledNode);
|
|
820
|
+
const isEnabled = () => {
|
|
821
|
+
if (enabledLiteral !== void 0) return enabledLiteral;
|
|
822
|
+
return Boolean(enabledNode?.cache);
|
|
823
|
+
};
|
|
824
|
+
const adapter = adapterWrapper(inner, {
|
|
825
|
+
invoke(messages, invokeOpts) {
|
|
826
|
+
return isEnabled() ? mock.invoke(messages, invokeOpts) : inner.invoke(messages, invokeOpts);
|
|
827
|
+
},
|
|
828
|
+
stream(messages, invokeOpts) {
|
|
829
|
+
return isEnabled() ? mock.stream(messages, invokeOpts) : inner.stream(messages, invokeOpts);
|
|
830
|
+
}
|
|
831
|
+
});
|
|
832
|
+
withLayer(adapter, "withDryRun", inner);
|
|
833
|
+
const dispose = () => {
|
|
834
|
+
if (unsubKeepalive) {
|
|
835
|
+
unsubKeepalive();
|
|
836
|
+
unsubKeepalive = void 0;
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
return { adapter, dispose };
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// src/utils/ai/adapters/middleware/http429-parser.ts
|
|
843
|
+
function parseRateLimitFromError(err) {
|
|
844
|
+
if (err == null || typeof err !== "object") return void 0;
|
|
845
|
+
const like = err;
|
|
846
|
+
const status = like.status;
|
|
847
|
+
const headerLookup = toHeaderGetter(like.headers);
|
|
848
|
+
if (status !== 429 && status !== 503 && !looksLikeRateLimitMessage(like.message)) {
|
|
849
|
+
return void 0;
|
|
850
|
+
}
|
|
851
|
+
const sig = {};
|
|
852
|
+
const retryAfter = headerLookup("retry-after");
|
|
853
|
+
const retryAfterMs = parseRetryAfter(retryAfter);
|
|
854
|
+
if (retryAfterMs != null) sig.retryAfterMs = retryAfterMs;
|
|
855
|
+
const anthReqReset = headerLookup("anthropic-ratelimit-requests-reset");
|
|
856
|
+
if (anthReqReset) {
|
|
857
|
+
const ms = parseIsoResetHeaderToDelayMs(anthReqReset);
|
|
858
|
+
if (ms != null) sig.retryAfterMs = Math.max(sig.retryAfterMs ?? 0, ms);
|
|
859
|
+
}
|
|
860
|
+
const anthTokReset = headerLookup("anthropic-ratelimit-tokens-reset");
|
|
861
|
+
if (anthTokReset) {
|
|
862
|
+
const ms = parseIsoResetHeaderToDelayMs(anthTokReset);
|
|
863
|
+
if (ms != null) sig.retryAfterMs = Math.max(sig.retryAfterMs ?? 0, ms);
|
|
864
|
+
}
|
|
865
|
+
const limitRequests = numHeader(headerLookup, "x-ratelimit-limit-requests");
|
|
866
|
+
if (limitRequests != null) sig.rpmCap = limitRequests;
|
|
867
|
+
const limitTokens = numHeader(headerLookup, "x-ratelimit-limit-tokens");
|
|
868
|
+
if (limitTokens != null) sig.tpmCap = limitTokens;
|
|
869
|
+
const remainingReq = numHeader(headerLookup, "x-ratelimit-remaining-requests");
|
|
870
|
+
const remainingTok = numHeader(headerLookup, "x-ratelimit-remaining-tokens");
|
|
871
|
+
if (remainingReq != null && limitRequests != null && limitRequests > 0) {
|
|
872
|
+
sig.usageHint ??= {};
|
|
873
|
+
sig.usageHint.rpm = 1 - remainingReq / limitRequests;
|
|
874
|
+
}
|
|
875
|
+
if (remainingTok != null && limitTokens != null && limitTokens > 0) {
|
|
876
|
+
sig.usageHint ??= {};
|
|
877
|
+
sig.usageHint.tpm = 1 - remainingTok / limitTokens;
|
|
878
|
+
}
|
|
879
|
+
if (sig.retryAfterMs == null && like.message) {
|
|
880
|
+
const msgMs = parseRetryAfterFromMessage(like.message);
|
|
881
|
+
if (msgMs != null) sig.retryAfterMs = msgMs;
|
|
882
|
+
}
|
|
883
|
+
if (like.headers) sig.metadata = { headers: serializeHeaders(like.headers) };
|
|
884
|
+
if (sig.retryAfterMs == null && sig.rpmCap == null && sig.tpmCap == null && sig.usageHint == null) {
|
|
885
|
+
return sig.metadata ? sig : void 0;
|
|
886
|
+
}
|
|
887
|
+
return sig;
|
|
888
|
+
}
|
|
889
|
+
function toHeaderGetter(h) {
|
|
890
|
+
if (!h) return () => void 0;
|
|
891
|
+
if (typeof h.get === "function") {
|
|
892
|
+
const hh = h;
|
|
893
|
+
return (name) => hh.get(name) ?? hh.get(name.toLowerCase()) ?? void 0;
|
|
894
|
+
}
|
|
895
|
+
const record = h;
|
|
896
|
+
const lc = {};
|
|
897
|
+
for (const [k, v] of Object.entries(record)) {
|
|
898
|
+
const sv = Array.isArray(v) ? v.join(", ") : v;
|
|
899
|
+
if (sv != null) lc[k.toLowerCase()] = sv;
|
|
900
|
+
}
|
|
901
|
+
return (name) => lc[name.toLowerCase()];
|
|
902
|
+
}
|
|
903
|
+
function serializeHeaders(h) {
|
|
904
|
+
const out = {};
|
|
905
|
+
if (typeof h.forEach === "function") {
|
|
906
|
+
h.forEach((v, k) => {
|
|
907
|
+
out[k] = v;
|
|
908
|
+
});
|
|
909
|
+
return out;
|
|
910
|
+
}
|
|
911
|
+
for (const [k, v] of Object.entries(h)) {
|
|
912
|
+
if (v != null) out[k] = Array.isArray(v) ? v.join(", ") : v;
|
|
913
|
+
}
|
|
914
|
+
return out;
|
|
915
|
+
}
|
|
916
|
+
function numHeader(getter, name) {
|
|
917
|
+
const raw = getter(name);
|
|
918
|
+
if (raw == null) return void 0;
|
|
919
|
+
const n = Number(raw);
|
|
920
|
+
return Number.isFinite(n) ? n : void 0;
|
|
921
|
+
}
|
|
922
|
+
function parseRetryAfter(raw) {
|
|
923
|
+
if (!raw) return void 0;
|
|
924
|
+
const trimmed = raw.trim();
|
|
925
|
+
const asNum = Number(trimmed);
|
|
926
|
+
if (Number.isFinite(asNum) && asNum >= 0) return asNum * 1e3;
|
|
927
|
+
const ts = Date.parse(trimmed);
|
|
928
|
+
if (Number.isFinite(ts)) {
|
|
929
|
+
const delta = ts - Date.now();
|
|
930
|
+
if (delta > 0) return delta;
|
|
931
|
+
}
|
|
932
|
+
return void 0;
|
|
933
|
+
}
|
|
934
|
+
function parseIsoResetHeaderToDelayMs(raw) {
|
|
935
|
+
if (!raw) return void 0;
|
|
936
|
+
const ts = Date.parse(raw);
|
|
937
|
+
if (Number.isFinite(ts)) return Math.max(0, ts - Date.now());
|
|
938
|
+
return void 0;
|
|
939
|
+
}
|
|
940
|
+
var RETRY_MSG_RE = /retry\s+(?:in|after)\s+(\d+(?:\.\d+)?)\s*(ms|s|sec|seconds?|m|min|minutes?)/i;
|
|
941
|
+
function parseRetryAfterFromMessage(msg) {
|
|
942
|
+
const m = RETRY_MSG_RE.exec(msg);
|
|
943
|
+
if (!m) return void 0;
|
|
944
|
+
const n = Number(m[1]);
|
|
945
|
+
if (!Number.isFinite(n)) return void 0;
|
|
946
|
+
const unit = (m[2] ?? "s").toLowerCase();
|
|
947
|
+
if (unit === "ms") return n;
|
|
948
|
+
if (unit.startsWith("s")) return n * 1e3;
|
|
949
|
+
if (unit.startsWith("m")) return n * 6e4;
|
|
950
|
+
return void 0;
|
|
951
|
+
}
|
|
952
|
+
var RATE_LIMIT_MSG_RE = /rate\s*limit|too\s*many\s*requests|quota|429/i;
|
|
953
|
+
function looksLikeRateLimitMessage(msg) {
|
|
954
|
+
return !!msg && RATE_LIMIT_MSG_RE.test(msg);
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// src/utils/ai/adapters/middleware/rate-limiter.ts
|
|
958
|
+
import { fromAny as fromAny3 } from "@graphrefly/pure-ts/extra";
|
|
959
|
+
function withRateLimiter(inner, opts = {}) {
|
|
960
|
+
const limiter = opts.limiter ?? adaptiveRateLimiter({
|
|
961
|
+
name: opts.name ?? "rateLimiter",
|
|
962
|
+
rpm: opts.rpm,
|
|
963
|
+
tpm: opts.tpm,
|
|
964
|
+
adaptation: opts.adaptation,
|
|
965
|
+
burstMultiplier: opts.burstMultiplier
|
|
966
|
+
});
|
|
967
|
+
const estimateCost = (messages, invokeOpts) => {
|
|
968
|
+
if (opts.costFn) return opts.costFn(messages, invokeOpts);
|
|
969
|
+
return 0;
|
|
970
|
+
};
|
|
971
|
+
const handleError = (err) => {
|
|
972
|
+
const sig = parseRateLimitFromError(err);
|
|
973
|
+
if (sig) limiter.recordSignal(sig);
|
|
974
|
+
};
|
|
975
|
+
const wrap = adapterWrapper(inner, {
|
|
976
|
+
async invoke(messages, invokeOpts) {
|
|
977
|
+
const tokenCost = estimateCost(messages, invokeOpts);
|
|
978
|
+
await limiter.acquire({ requestCost: 1, tokenCost, signal: invokeOpts?.signal });
|
|
979
|
+
try {
|
|
980
|
+
const resp = await firstValueFrom(fromAny3(inner.invoke(messages, invokeOpts)));
|
|
981
|
+
const usage = resp.usage ?? emptyUsage();
|
|
982
|
+
const actual = sumInputTokens(usage) + sumOutputTokens(usage);
|
|
983
|
+
const delta = actual - tokenCost;
|
|
984
|
+
if (delta > 0) limiter.recordUsage(delta);
|
|
985
|
+
return resp;
|
|
986
|
+
} catch (err) {
|
|
987
|
+
handleError(err);
|
|
988
|
+
throw err;
|
|
989
|
+
}
|
|
990
|
+
},
|
|
991
|
+
async *stream(messages, invokeOpts) {
|
|
992
|
+
const tokenCost = estimateCost(messages, invokeOpts);
|
|
993
|
+
await limiter.acquire({ requestCost: 1, tokenCost, signal: invokeOpts?.signal });
|
|
994
|
+
try {
|
|
995
|
+
let finalTokens = 0;
|
|
996
|
+
for await (const delta of inner.stream(messages, invokeOpts)) {
|
|
997
|
+
if (delta.type === "usage") {
|
|
998
|
+
finalTokens = sumInputTokens(delta.usage) + sumOutputTokens(delta.usage);
|
|
999
|
+
}
|
|
1000
|
+
yield delta;
|
|
1001
|
+
}
|
|
1002
|
+
const d = finalTokens - tokenCost;
|
|
1003
|
+
if (d > 0) limiter.recordUsage(d);
|
|
1004
|
+
} catch (err) {
|
|
1005
|
+
handleError(err);
|
|
1006
|
+
throw err;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
});
|
|
1010
|
+
withLayer(wrap, "withRateLimiter", inner);
|
|
1011
|
+
return { adapter: wrap, limiter };
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
// src/utils/ai/adapters/middleware/retry.ts
|
|
1015
|
+
import { ResettableTimer } from "@graphrefly/pure-ts/core";
|
|
1016
|
+
import { fromAny as fromAny4 } from "@graphrefly/pure-ts/extra";
|
|
1017
|
+
function makeAbortError(reason = "aborted") {
|
|
1018
|
+
const err = new Error(reason);
|
|
1019
|
+
err.name = "AbortError";
|
|
1020
|
+
return err;
|
|
1021
|
+
}
|
|
1022
|
+
function sleep(ms, signal) {
|
|
1023
|
+
if (ms <= 0) return Promise.resolve();
|
|
1024
|
+
if (signal?.aborted) return Promise.reject(makeAbortError());
|
|
1025
|
+
return new Promise((resolve, reject) => {
|
|
1026
|
+
const timer = new ResettableTimer();
|
|
1027
|
+
let onAbort;
|
|
1028
|
+
const cleanup = () => {
|
|
1029
|
+
timer.cancel();
|
|
1030
|
+
if (signal && onAbort) signal.removeEventListener("abort", onAbort);
|
|
1031
|
+
};
|
|
1032
|
+
timer.start(ms, () => {
|
|
1033
|
+
cleanup();
|
|
1034
|
+
resolve();
|
|
1035
|
+
});
|
|
1036
|
+
if (signal) {
|
|
1037
|
+
onAbort = () => {
|
|
1038
|
+
cleanup();
|
|
1039
|
+
reject(makeAbortError());
|
|
1040
|
+
};
|
|
1041
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1042
|
+
}
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
function withRetry(inner, opts = {}) {
|
|
1046
|
+
const attempts = opts.attempts ?? 3;
|
|
1047
|
+
const baseDelayMs = opts.baseDelayMs ?? 500;
|
|
1048
|
+
const maxDelayMs = opts.maxDelayMs ?? 1e4;
|
|
1049
|
+
const strategy = opts.strategy ?? "decorrelated";
|
|
1050
|
+
const jitter = opts.jitter ?? true;
|
|
1051
|
+
const shouldRetry = opts.shouldRetry ?? defaultShouldRetry;
|
|
1052
|
+
const retryStreaming = opts.retryStreaming ?? true;
|
|
1053
|
+
const delay = (attempt, prevDelay) => {
|
|
1054
|
+
if (strategy === "decorrelated") {
|
|
1055
|
+
const upper = Math.min(maxDelayMs, Math.max(baseDelayMs, prevDelay * 3));
|
|
1056
|
+
return baseDelayMs + Math.random() * (upper - baseDelayMs);
|
|
1057
|
+
}
|
|
1058
|
+
const nominal = strategy === "exp" ? baseDelayMs * 2 ** (attempt - 1) : baseDelayMs * attempt;
|
|
1059
|
+
const bounded = Math.min(maxDelayMs, nominal);
|
|
1060
|
+
if (!jitter) return bounded;
|
|
1061
|
+
const jittered = bounded * (0.5 + Math.random());
|
|
1062
|
+
return Math.min(maxDelayMs, jittered);
|
|
1063
|
+
};
|
|
1064
|
+
const wrap = adapterWrapper(inner, {
|
|
1065
|
+
async invoke(messages, invokeOpts) {
|
|
1066
|
+
if (invokeOpts?.signal?.aborted) throw makeAbortError();
|
|
1067
|
+
let lastErr;
|
|
1068
|
+
let prevDelay = baseDelayMs;
|
|
1069
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
1070
|
+
try {
|
|
1071
|
+
return await firstValueFrom(fromAny4(inner.invoke(messages, invokeOpts)));
|
|
1072
|
+
} catch (err) {
|
|
1073
|
+
lastErr = err;
|
|
1074
|
+
if (attempt >= attempts || !shouldRetry(err, attempt)) throw err;
|
|
1075
|
+
const waitMs = delay(attempt, prevDelay);
|
|
1076
|
+
prevDelay = waitMs;
|
|
1077
|
+
await sleep(waitMs, invokeOpts?.signal);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
throw lastErr;
|
|
1081
|
+
},
|
|
1082
|
+
async *stream(messages, invokeOpts) {
|
|
1083
|
+
if (invokeOpts?.signal?.aborted) throw makeAbortError();
|
|
1084
|
+
if (!retryStreaming) {
|
|
1085
|
+
for await (const d of inner.stream(messages, invokeOpts)) yield d;
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
let lastErr;
|
|
1089
|
+
let prevDelay = baseDelayMs;
|
|
1090
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
1091
|
+
let yieldedAny = false;
|
|
1092
|
+
try {
|
|
1093
|
+
for await (const d of inner.stream(messages, invokeOpts)) {
|
|
1094
|
+
yieldedAny = true;
|
|
1095
|
+
yield d;
|
|
1096
|
+
}
|
|
1097
|
+
return;
|
|
1098
|
+
} catch (err) {
|
|
1099
|
+
lastErr = err;
|
|
1100
|
+
if (yieldedAny) throw err;
|
|
1101
|
+
if (attempt >= attempts || !shouldRetry(err, attempt)) throw err;
|
|
1102
|
+
const waitMs = delay(attempt, prevDelay);
|
|
1103
|
+
prevDelay = waitMs;
|
|
1104
|
+
await sleep(waitMs, invokeOpts?.signal);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
throw lastErr;
|
|
1108
|
+
}
|
|
1109
|
+
});
|
|
1110
|
+
withLayer(wrap, "withRetry", inner);
|
|
1111
|
+
return wrap;
|
|
1112
|
+
}
|
|
1113
|
+
function defaultShouldRetry(err, _attempt) {
|
|
1114
|
+
if (err == null) return false;
|
|
1115
|
+
const e = err;
|
|
1116
|
+
if (e.name === "LLMTimeoutError") return true;
|
|
1117
|
+
if (e.name === "AbortError") return false;
|
|
1118
|
+
if (e.message === "aborted") return false;
|
|
1119
|
+
if (e.name === "DOMException" && e.code != null && Number(e.code) === 20) {
|
|
1120
|
+
return false;
|
|
1121
|
+
}
|
|
1122
|
+
if (e.name === "BudgetExhaustedError") return false;
|
|
1123
|
+
if (e.name === "CircuitOpenError") return false;
|
|
1124
|
+
if (e.status != null) {
|
|
1125
|
+
if (e.status === 429) return true;
|
|
1126
|
+
if (e.status >= 500 && e.status < 600) return true;
|
|
1127
|
+
return false;
|
|
1128
|
+
}
|
|
1129
|
+
if (e.code && typeof e.code === "string") {
|
|
1130
|
+
if (/^E[A-Z]+$/.test(e.code)) return true;
|
|
1131
|
+
}
|
|
1132
|
+
if (e.message) {
|
|
1133
|
+
return /network|timeout|socket|fetch|econn|eai_/i.test(e.message);
|
|
1134
|
+
}
|
|
1135
|
+
return false;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
// src/utils/ai/adapters/middleware/timeout.ts
|
|
1139
|
+
import { ResettableTimer as ResettableTimer2 } from "@graphrefly/pure-ts/core";
|
|
1140
|
+
import { fromAny as fromAny5 } from "@graphrefly/pure-ts/extra";
|
|
1141
|
+
var LLMTimeoutError = class extends Error {
|
|
1142
|
+
constructor(ms) {
|
|
1143
|
+
super(`LLM call timed out after ${ms}ms`);
|
|
1144
|
+
this.ms = ms;
|
|
1145
|
+
}
|
|
1146
|
+
name = "LLMTimeoutError";
|
|
1147
|
+
};
|
|
1148
|
+
function withLLMTimeout(inner, ms) {
|
|
1149
|
+
if (ms <= 0) throw new RangeError("withLLMTimeout: ms must be > 0");
|
|
1150
|
+
const linkedSignal = (parent) => {
|
|
1151
|
+
const ac = new AbortController();
|
|
1152
|
+
let timerFired = false;
|
|
1153
|
+
let onParentAbort;
|
|
1154
|
+
const timer = new ResettableTimer2();
|
|
1155
|
+
if (parent) {
|
|
1156
|
+
if (parent.aborted) ac.abort(parent.reason);
|
|
1157
|
+
else {
|
|
1158
|
+
onParentAbort = () => {
|
|
1159
|
+
timer.cancel();
|
|
1160
|
+
ac.abort(parent.reason);
|
|
1161
|
+
};
|
|
1162
|
+
parent.addEventListener("abort", onParentAbort, { once: true });
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
timer.start(ms, () => {
|
|
1166
|
+
timerFired = true;
|
|
1167
|
+
ac.abort(new LLMTimeoutError(ms));
|
|
1168
|
+
});
|
|
1169
|
+
return {
|
|
1170
|
+
signal: ac.signal,
|
|
1171
|
+
cancel: () => {
|
|
1172
|
+
timer.cancel();
|
|
1173
|
+
if (parent && onParentAbort) parent.removeEventListener("abort", onParentAbort);
|
|
1174
|
+
},
|
|
1175
|
+
timedOut: () => timerFired
|
|
1176
|
+
};
|
|
1177
|
+
};
|
|
1178
|
+
const convertAbortToTimeout = (err, timedOut) => {
|
|
1179
|
+
if (!timedOut) throw err;
|
|
1180
|
+
if (err instanceof LLMTimeoutError) throw err;
|
|
1181
|
+
const e = err;
|
|
1182
|
+
const isAbort = e?.name === "AbortError" || e?.name === "DOMException" && Number(e.code) === 20 || err?.message === "aborted";
|
|
1183
|
+
if (isAbort) {
|
|
1184
|
+
const timeout = new LLMTimeoutError(ms);
|
|
1185
|
+
timeout.cause = err;
|
|
1186
|
+
throw timeout;
|
|
1187
|
+
}
|
|
1188
|
+
throw err;
|
|
1189
|
+
};
|
|
1190
|
+
const wrap = adapterWrapper(inner, {
|
|
1191
|
+
async invoke(messages, invokeOpts) {
|
|
1192
|
+
const { signal, cancel, timedOut } = linkedSignal(invokeOpts?.signal);
|
|
1193
|
+
try {
|
|
1194
|
+
return await firstValueFrom(fromAny5(inner.invoke(messages, { ...invokeOpts, signal })));
|
|
1195
|
+
} catch (err) {
|
|
1196
|
+
return convertAbortToTimeout(err, timedOut());
|
|
1197
|
+
} finally {
|
|
1198
|
+
cancel();
|
|
1199
|
+
}
|
|
1200
|
+
},
|
|
1201
|
+
async *stream(messages, invokeOpts) {
|
|
1202
|
+
const { signal, cancel, timedOut } = linkedSignal(invokeOpts?.signal);
|
|
1203
|
+
try {
|
|
1204
|
+
for await (const d of inner.stream(messages, { ...invokeOpts, signal })) yield d;
|
|
1205
|
+
} catch (err) {
|
|
1206
|
+
convertAbortToTimeout(err, timedOut());
|
|
1207
|
+
} finally {
|
|
1208
|
+
cancel();
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
});
|
|
1212
|
+
withLayer(wrap, "withLLMTimeout", inner);
|
|
1213
|
+
return wrap;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
// src/utils/ai/adapters/middleware/resilient-adapter.ts
|
|
1217
|
+
function resilientAdapter(inner, opts = {}) {
|
|
1218
|
+
const bundle = { adapter: inner };
|
|
1219
|
+
let current = inner;
|
|
1220
|
+
if (opts.rateLimit) {
|
|
1221
|
+
const wrapped = withRateLimiter(current, opts.rateLimit);
|
|
1222
|
+
current = wrapped.adapter;
|
|
1223
|
+
bundle.rateLimiter = wrapped.limiter;
|
|
1224
|
+
}
|
|
1225
|
+
if (opts.budget) {
|
|
1226
|
+
const wrapped = withBudgetGate(current, opts.budget);
|
|
1227
|
+
current = wrapped.adapter;
|
|
1228
|
+
bundle.budget = wrapped.budget;
|
|
1229
|
+
}
|
|
1230
|
+
if (opts.breaker) {
|
|
1231
|
+
const wrapped = withLLMBreaker(current, opts.breaker);
|
|
1232
|
+
current = wrapped.adapter;
|
|
1233
|
+
bundle.breaker = wrapped.breaker;
|
|
1234
|
+
}
|
|
1235
|
+
if (opts.timeoutMs != null) {
|
|
1236
|
+
current = withLLMTimeout(current, opts.timeoutMs);
|
|
1237
|
+
}
|
|
1238
|
+
if (opts.retry) {
|
|
1239
|
+
current = withRetry(current, opts.retry);
|
|
1240
|
+
}
|
|
1241
|
+
if (opts.fallback) {
|
|
1242
|
+
if (opts.name === "fallback") {
|
|
1243
|
+
throw new RangeError(
|
|
1244
|
+
'resilientAdapter: `name` cannot be "fallback" \u2014 collides with the secondary tier label.'
|
|
1245
|
+
);
|
|
1246
|
+
}
|
|
1247
|
+
const cascadeOpts = {};
|
|
1248
|
+
if (opts.onFallback) cascadeOpts.onFallback = opts.onFallback;
|
|
1249
|
+
if (opts.onExhausted) cascadeOpts.onExhausted = opts.onExhausted;
|
|
1250
|
+
current = cascadingLlmAdapter(
|
|
1251
|
+
[
|
|
1252
|
+
{ name: opts.name ?? "primary", adapter: current },
|
|
1253
|
+
{ name: "fallback", adapter: opts.fallback }
|
|
1254
|
+
],
|
|
1255
|
+
cascadeOpts
|
|
1256
|
+
);
|
|
1257
|
+
}
|
|
1258
|
+
if (opts.cache) {
|
|
1259
|
+
current = withReplayCache(current, opts.cache);
|
|
1260
|
+
}
|
|
1261
|
+
bundle.adapter = current;
|
|
1262
|
+
return bundle;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
// src/utils/ai/prompts/frozen-context.ts
|
|
1266
|
+
import { factoryTag, node as nodeFactory } from "@graphrefly/pure-ts/core";
|
|
1267
|
+
import { fromAny as fromAny6 } from "@graphrefly/pure-ts/extra";
|
|
1268
|
+
function frozenContext(source, opts) {
|
|
1269
|
+
const src = fromAny6(source);
|
|
1270
|
+
const trigger = opts?.refreshTrigger != null ? fromAny6(opts.refreshTrigger) : null;
|
|
1271
|
+
const frozenArgs = opts?.name !== void 0 ? { name: opts.name } : void 0;
|
|
1272
|
+
const frozenTag = factoryTag("frozenContext", frozenArgs);
|
|
1273
|
+
if (trigger == null) {
|
|
1274
|
+
return nodeFactory(
|
|
1275
|
+
[src],
|
|
1276
|
+
(data, actions, ctx) => {
|
|
1277
|
+
const alreadyEmitted = ctx.store.emitted === true;
|
|
1278
|
+
if (alreadyEmitted) return;
|
|
1279
|
+
const srcBatch = data[0];
|
|
1280
|
+
const srcValue = srcBatch != null && srcBatch.length > 0 ? srcBatch.at(-1) : ctx.prevData[0];
|
|
1281
|
+
if (srcValue === void 0) return;
|
|
1282
|
+
ctx.store.emitted = true;
|
|
1283
|
+
actions.emit(srcValue);
|
|
1284
|
+
const store = ctx.store;
|
|
1285
|
+
return {
|
|
1286
|
+
onInvalidate: () => {
|
|
1287
|
+
store.emitted = false;
|
|
1288
|
+
},
|
|
1289
|
+
onDeactivation: () => {
|
|
1290
|
+
delete store.emitted;
|
|
1291
|
+
},
|
|
1292
|
+
onResubscribableReset: () => {
|
|
1293
|
+
delete store.emitted;
|
|
1294
|
+
}
|
|
1295
|
+
};
|
|
1296
|
+
},
|
|
1297
|
+
{
|
|
1298
|
+
name: opts?.name ?? "frozenContext",
|
|
1299
|
+
describeKind: "derived",
|
|
1300
|
+
initial: null,
|
|
1301
|
+
meta: aiMeta("frozen_context", { ...frozenTag })
|
|
1302
|
+
}
|
|
1303
|
+
);
|
|
1304
|
+
}
|
|
1305
|
+
return nodeFactory(
|
|
1306
|
+
[src, trigger],
|
|
1307
|
+
(data, actions, ctx) => {
|
|
1308
|
+
const triggerBatch = data[1];
|
|
1309
|
+
const triggered = triggerBatch != null && triggerBatch.length > 0;
|
|
1310
|
+
if (!triggered) return;
|
|
1311
|
+
const srcBatch = data[0];
|
|
1312
|
+
const srcValue = srcBatch != null && srcBatch.length > 0 ? srcBatch.at(-1) : ctx.prevData[0];
|
|
1313
|
+
actions.emit(srcValue);
|
|
1314
|
+
},
|
|
1315
|
+
{
|
|
1316
|
+
name: opts?.name ?? "frozenContext",
|
|
1317
|
+
describeKind: "derived",
|
|
1318
|
+
initial: null,
|
|
1319
|
+
meta: aiMeta("frozen_context", { ...frozenTag })
|
|
1320
|
+
}
|
|
1321
|
+
);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
// src/utils/ai/prompts/streaming.ts
|
|
1325
|
+
import { batch, factoryTag as factoryTag2, node as node4, wallClockNs as wallClockNs2 } from "@graphrefly/pure-ts/core";
|
|
1326
|
+
import { filter, fromAny as fromAny7, keepalive as keepalive4, switchMap } from "@graphrefly/pure-ts/extra";
|
|
1327
|
+
async function streamingInvoke(adapter, msgs, invokeOpts, deltaTopic) {
|
|
1328
|
+
let accumulated = "";
|
|
1329
|
+
let seq = 0;
|
|
1330
|
+
for await (const delta of adapter.stream(msgs, invokeOpts)) {
|
|
1331
|
+
deltaTopic.publish({ ...delta, seq: seq++, ts: wallClockNs2() });
|
|
1332
|
+
if (delta.type === "token") accumulated += delta.delta;
|
|
1333
|
+
}
|
|
1334
|
+
return accumulated;
|
|
1335
|
+
}
|
|
1336
|
+
function parseAccumulated(accumulated, format) {
|
|
1337
|
+
if (format === "json") {
|
|
1338
|
+
try {
|
|
1339
|
+
return JSON.parse(stripFences(accumulated));
|
|
1340
|
+
} catch (err) {
|
|
1341
|
+
const preview = accumulated.slice(0, 160);
|
|
1342
|
+
throw new Error(
|
|
1343
|
+
`streamingPromptNode: format:"json" \u2014 failed to parse accumulated text as JSON: ${err.message}; content preview: ${preview}`
|
|
1344
|
+
);
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
return accumulated;
|
|
1348
|
+
}
|
|
1349
|
+
function makeAccumulatedText(deltaTopic, name) {
|
|
1350
|
+
let cleanup;
|
|
1351
|
+
return node4(
|
|
1352
|
+
[deltaTopic.latest],
|
|
1353
|
+
(batchData, actions, ctx) => {
|
|
1354
|
+
if (cleanup === void 0) {
|
|
1355
|
+
const store2 = ctx.store;
|
|
1356
|
+
cleanup = {
|
|
1357
|
+
onDeactivation: () => {
|
|
1358
|
+
delete store2.acc;
|
|
1359
|
+
}
|
|
1360
|
+
};
|
|
1361
|
+
}
|
|
1362
|
+
const data = batchData.map(
|
|
1363
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
1364
|
+
);
|
|
1365
|
+
const d = data[0];
|
|
1366
|
+
const store = ctx.store;
|
|
1367
|
+
if (d === void 0) {
|
|
1368
|
+
actions.emit(store.acc ?? "");
|
|
1369
|
+
return cleanup;
|
|
1370
|
+
}
|
|
1371
|
+
const delta = d;
|
|
1372
|
+
if (delta.seq === 0) store.acc = "";
|
|
1373
|
+
if (delta.type === "token") {
|
|
1374
|
+
store.acc = (store.acc ?? "") + delta.delta;
|
|
1375
|
+
}
|
|
1376
|
+
actions.emit(store.acc ?? "");
|
|
1377
|
+
return cleanup;
|
|
1378
|
+
},
|
|
1379
|
+
{
|
|
1380
|
+
name,
|
|
1381
|
+
describeKind: "derived",
|
|
1382
|
+
meta: aiMeta("accumulated_text"),
|
|
1383
|
+
initial: ""
|
|
1384
|
+
}
|
|
1385
|
+
);
|
|
1386
|
+
}
|
|
1387
|
+
function streamingPromptNode(adapter, deps, prompt, opts) {
|
|
1388
|
+
const sourceName = opts?.name ?? "llm";
|
|
1389
|
+
const format = opts?.format ?? "text";
|
|
1390
|
+
const deltaTopic = topic(`${sourceName}/stream`, {
|
|
1391
|
+
...opts?.retainedLimit != null ? { retainedLimit: opts.retainedLimit } : {}
|
|
1392
|
+
});
|
|
1393
|
+
const messagesNode = node4(
|
|
1394
|
+
deps,
|
|
1395
|
+
(batchData, actions, ctx) => {
|
|
1396
|
+
const data = batchData.map(
|
|
1397
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
1398
|
+
);
|
|
1399
|
+
if (data.some((v) => v == null)) {
|
|
1400
|
+
actions.emit([]);
|
|
1401
|
+
return;
|
|
1402
|
+
}
|
|
1403
|
+
const text = typeof prompt === "string" ? prompt : prompt(...data);
|
|
1404
|
+
if (!text) {
|
|
1405
|
+
actions.emit([]);
|
|
1406
|
+
return;
|
|
1407
|
+
}
|
|
1408
|
+
actions.emit([{ role: "user", content: text }]);
|
|
1409
|
+
},
|
|
1410
|
+
{
|
|
1411
|
+
name: `${sourceName}::messages`,
|
|
1412
|
+
meta: aiMeta("prompt_node::messages"),
|
|
1413
|
+
initial: []
|
|
1414
|
+
}
|
|
1415
|
+
);
|
|
1416
|
+
const output = switchMap(
|
|
1417
|
+
messagesNode,
|
|
1418
|
+
(msgs) => {
|
|
1419
|
+
const chatMsgs = msgs;
|
|
1420
|
+
if (!chatMsgs || chatMsgs.length === 0) {
|
|
1421
|
+
return node4([], { initial: null });
|
|
1422
|
+
}
|
|
1423
|
+
const ac = new AbortController();
|
|
1424
|
+
async function* pumpAndCollect() {
|
|
1425
|
+
try {
|
|
1426
|
+
const accumulated = await streamingInvoke(
|
|
1427
|
+
adapter,
|
|
1428
|
+
chatMsgs,
|
|
1429
|
+
{
|
|
1430
|
+
model: opts?.model,
|
|
1431
|
+
temperature: opts?.temperature,
|
|
1432
|
+
maxTokens: opts?.maxTokens,
|
|
1433
|
+
systemPrompt: opts?.systemPrompt,
|
|
1434
|
+
signal: ac.signal
|
|
1435
|
+
},
|
|
1436
|
+
deltaTopic
|
|
1437
|
+
);
|
|
1438
|
+
yield parseAccumulated(accumulated, format);
|
|
1439
|
+
} finally {
|
|
1440
|
+
ac.abort();
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
return fromAny7(pumpAndCollect());
|
|
1444
|
+
},
|
|
1445
|
+
{ meta: factoryTag2("streamingPromptNode") }
|
|
1446
|
+
);
|
|
1447
|
+
const accumulatedText = makeAccumulatedText(deltaTopic, `${sourceName}::accumulatedText`);
|
|
1448
|
+
const unsubOutput = keepalive4(output);
|
|
1449
|
+
return {
|
|
1450
|
+
output,
|
|
1451
|
+
deltaTopic,
|
|
1452
|
+
accumulatedText,
|
|
1453
|
+
dispose: () => {
|
|
1454
|
+
unsubOutput();
|
|
1455
|
+
deltaTopic.destroy();
|
|
1456
|
+
}
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
function gatedStream(graph, name, adapter, deps, prompt, opts) {
|
|
1460
|
+
const cancelSignal = node4([], { name: `${name}/cancel`, initial: 0 });
|
|
1461
|
+
let cancelCounter = 0;
|
|
1462
|
+
const allDeps = [...deps, cancelSignal];
|
|
1463
|
+
const sourceName = opts?.name ?? name;
|
|
1464
|
+
const format = opts?.format ?? "text";
|
|
1465
|
+
const deltaTopic = topic(`${sourceName}/stream`, {
|
|
1466
|
+
...opts?.retainedLimit != null ? { retainedLimit: opts.retainedLimit } : {}
|
|
1467
|
+
});
|
|
1468
|
+
const messagesNode = node4(
|
|
1469
|
+
allDeps,
|
|
1470
|
+
(batchData, actions, ctx) => {
|
|
1471
|
+
const data = batchData.map(
|
|
1472
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
1473
|
+
);
|
|
1474
|
+
const depValues = data.slice(0, -1);
|
|
1475
|
+
if (depValues.some((v) => v == null)) {
|
|
1476
|
+
actions.emit([]);
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
const text = typeof prompt === "string" ? prompt : prompt(...depValues);
|
|
1480
|
+
if (!text) {
|
|
1481
|
+
actions.emit([]);
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1484
|
+
actions.emit([{ role: "user", content: text }]);
|
|
1485
|
+
},
|
|
1486
|
+
{
|
|
1487
|
+
name: `${sourceName}::messages`,
|
|
1488
|
+
meta: aiMeta("prompt_node::messages"),
|
|
1489
|
+
initial: []
|
|
1490
|
+
}
|
|
1491
|
+
);
|
|
1492
|
+
const output = switchMap(
|
|
1493
|
+
messagesNode,
|
|
1494
|
+
(msgs) => {
|
|
1495
|
+
const chatMsgs = msgs;
|
|
1496
|
+
if (!chatMsgs || chatMsgs.length === 0) {
|
|
1497
|
+
return node4([], { initial: null });
|
|
1498
|
+
}
|
|
1499
|
+
const ac = new AbortController();
|
|
1500
|
+
async function* pumpAndCollect() {
|
|
1501
|
+
try {
|
|
1502
|
+
const accumulated = await streamingInvoke(
|
|
1503
|
+
adapter,
|
|
1504
|
+
chatMsgs,
|
|
1505
|
+
{
|
|
1506
|
+
model: opts?.model,
|
|
1507
|
+
temperature: opts?.temperature,
|
|
1508
|
+
maxTokens: opts?.maxTokens,
|
|
1509
|
+
systemPrompt: opts?.systemPrompt,
|
|
1510
|
+
signal: ac.signal
|
|
1511
|
+
},
|
|
1512
|
+
deltaTopic
|
|
1513
|
+
);
|
|
1514
|
+
yield parseAccumulated(accumulated, format);
|
|
1515
|
+
} finally {
|
|
1516
|
+
ac.abort();
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
return fromAny7(pumpAndCollect());
|
|
1520
|
+
},
|
|
1521
|
+
{ meta: factoryTag2("gatedStream") }
|
|
1522
|
+
);
|
|
1523
|
+
const accumulatedText = makeAccumulatedText(deltaTopic, `${sourceName}::accumulatedText`);
|
|
1524
|
+
const nonNullOutput = filter(output, (v) => v != null);
|
|
1525
|
+
graph.add(nonNullOutput, { name: `${name}/raw` });
|
|
1526
|
+
const gateSubgraph = pipelineGraph(`${name}/gate-graph`);
|
|
1527
|
+
graph.mount(`${name}/gate-graph`, gateSubgraph);
|
|
1528
|
+
const gateCtrl = gateSubgraph.approvalGate(
|
|
1529
|
+
`${name}/gate`,
|
|
1530
|
+
nonNullOutput,
|
|
1531
|
+
opts?.gate
|
|
1532
|
+
);
|
|
1533
|
+
const unsubOutput = keepalive4(output);
|
|
1534
|
+
const unsubGate = keepalive4(gateCtrl.output);
|
|
1535
|
+
const unsubAccumulated = keepalive4(accumulatedText);
|
|
1536
|
+
graph.addDisposer(unsubOutput);
|
|
1537
|
+
graph.addDisposer(unsubGate);
|
|
1538
|
+
graph.addDisposer(unsubAccumulated);
|
|
1539
|
+
const originalReject = gateCtrl.reject.bind(gateCtrl);
|
|
1540
|
+
const gateWithAbort = {
|
|
1541
|
+
...gateCtrl,
|
|
1542
|
+
reject(count = 1) {
|
|
1543
|
+
batch(() => {
|
|
1544
|
+
originalReject(count);
|
|
1545
|
+
cancelSignal.emit(++cancelCounter);
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1548
|
+
};
|
|
1549
|
+
return {
|
|
1550
|
+
output: gateCtrl.output,
|
|
1551
|
+
deltaTopic,
|
|
1552
|
+
accumulatedText,
|
|
1553
|
+
gate: gateWithAbort,
|
|
1554
|
+
dispose: () => {
|
|
1555
|
+
unsubOutput();
|
|
1556
|
+
unsubGate();
|
|
1557
|
+
unsubAccumulated();
|
|
1558
|
+
deltaTopic.destroy();
|
|
1559
|
+
}
|
|
1560
|
+
};
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
// src/utils/ai/prompts/system-prompt.ts
|
|
1564
|
+
import { node as node5 } from "@graphrefly/pure-ts/core";
|
|
1565
|
+
import { fromAny as fromAny8, keepalive as keepalive5 } from "@graphrefly/pure-ts/extra";
|
|
1566
|
+
function systemPromptBuilder(sections, opts) {
|
|
1567
|
+
const separator = opts?.separator ?? "\n\n";
|
|
1568
|
+
const sectionNodes = sections.map(
|
|
1569
|
+
(s) => typeof s === "string" ? node5([], { initial: s }) : fromAny8(s)
|
|
1570
|
+
);
|
|
1571
|
+
const prompt = node5(
|
|
1572
|
+
sectionNodes,
|
|
1573
|
+
(batchData, actions, ctx) => {
|
|
1574
|
+
const data = batchData.map(
|
|
1575
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
1576
|
+
);
|
|
1577
|
+
actions.emit(data.filter((v) => v != null && v !== "").join(separator));
|
|
1578
|
+
},
|
|
1579
|
+
{
|
|
1580
|
+
name: opts?.name ?? "systemPrompt",
|
|
1581
|
+
describeKind: "derived",
|
|
1582
|
+
meta: aiMeta("system_prompt"),
|
|
1583
|
+
initial: ""
|
|
1584
|
+
}
|
|
1585
|
+
);
|
|
1586
|
+
const unsub = keepalive5(prompt);
|
|
1587
|
+
return Object.assign(prompt, { dispose: unsub });
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
// src/utils/ai/extractors/cost-meter.ts
|
|
1591
|
+
import { node as node6 } from "@graphrefly/pure-ts/core";
|
|
1592
|
+
var costMeterEqual = (a, b) => {
|
|
1593
|
+
if (a === b) return true;
|
|
1594
|
+
return a.chunkCount === b.chunkCount && a.charCount === b.charCount && a.estimatedTokens === b.estimatedTokens && a.estimated === b.estimated;
|
|
1595
|
+
};
|
|
1596
|
+
function costMeterExtractor(deltaTopic, opts) {
|
|
1597
|
+
const charsPerToken = opts?.charsPerToken ?? 4;
|
|
1598
|
+
const ZERO = {
|
|
1599
|
+
chunkCount: 0,
|
|
1600
|
+
charCount: 0,
|
|
1601
|
+
estimatedTokens: 0,
|
|
1602
|
+
estimated: true
|
|
1603
|
+
};
|
|
1604
|
+
let cleanup;
|
|
1605
|
+
return node6(
|
|
1606
|
+
[deltaTopic.latest],
|
|
1607
|
+
(batchData, actions, ctx) => {
|
|
1608
|
+
if (cleanup === void 0) {
|
|
1609
|
+
const store2 = ctx.store;
|
|
1610
|
+
cleanup = {
|
|
1611
|
+
onDeactivation: () => {
|
|
1612
|
+
delete store2.chunkCount;
|
|
1613
|
+
delete store2.charCount;
|
|
1614
|
+
delete store2.usageTokens;
|
|
1615
|
+
delete store2.sawUsage;
|
|
1616
|
+
}
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
const data = batchData.map(
|
|
1620
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
1621
|
+
);
|
|
1622
|
+
const d = data[0];
|
|
1623
|
+
if (d === void 0) {
|
|
1624
|
+
actions.emit(ZERO);
|
|
1625
|
+
return cleanup;
|
|
1626
|
+
}
|
|
1627
|
+
const delta = d;
|
|
1628
|
+
if (!("chunkCount" in ctx.store)) {
|
|
1629
|
+
ctx.store.chunkCount = 0;
|
|
1630
|
+
ctx.store.charCount = 0;
|
|
1631
|
+
ctx.store.usageTokens = 0;
|
|
1632
|
+
ctx.store.sawUsage = false;
|
|
1633
|
+
}
|
|
1634
|
+
const store = ctx.store;
|
|
1635
|
+
if (delta.type === "token") {
|
|
1636
|
+
store.chunkCount += 1;
|
|
1637
|
+
store.charCount += delta.delta.length;
|
|
1638
|
+
} else if (delta.type === "usage") {
|
|
1639
|
+
store.sawUsage = true;
|
|
1640
|
+
store.usageTokens = sumInputTokens(delta.usage) + sumOutputTokens(delta.usage);
|
|
1641
|
+
}
|
|
1642
|
+
const estimatedTokens = store.sawUsage ? store.usageTokens : Math.ceil(store.charCount / charsPerToken);
|
|
1643
|
+
actions.emit({
|
|
1644
|
+
chunkCount: store.chunkCount,
|
|
1645
|
+
charCount: store.charCount,
|
|
1646
|
+
estimatedTokens,
|
|
1647
|
+
estimated: !store.sawUsage
|
|
1648
|
+
});
|
|
1649
|
+
return cleanup;
|
|
1650
|
+
},
|
|
1651
|
+
{
|
|
1652
|
+
name: opts?.name ?? "cost-meter",
|
|
1653
|
+
describeKind: "derived",
|
|
1654
|
+
initial: ZERO,
|
|
1655
|
+
meta: aiMeta("cost_meter_extractor"),
|
|
1656
|
+
equals: costMeterEqual
|
|
1657
|
+
}
|
|
1658
|
+
);
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
// src/utils/ai/extractors/keyword-flag.ts
|
|
1662
|
+
import { node as node7 } from "@graphrefly/pure-ts/core";
|
|
1663
|
+
var keywordFlagsEqual = (a, b) => {
|
|
1664
|
+
if (a === b) return true;
|
|
1665
|
+
if (a == null || b == null) return a === b;
|
|
1666
|
+
if (a.length !== b.length) return false;
|
|
1667
|
+
for (let i = 0; i < a.length; i++) {
|
|
1668
|
+
const x = a[i];
|
|
1669
|
+
const y = b[i];
|
|
1670
|
+
if (x.label !== y.label || x.pattern !== y.pattern || x.match !== y.match || x.position !== y.position) {
|
|
1671
|
+
return false;
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
return true;
|
|
1675
|
+
};
|
|
1676
|
+
function keywordFlagExtractor(accumulatedText, opts) {
|
|
1677
|
+
const maxPatternLength = opts.maxPatternLength ?? 128;
|
|
1678
|
+
for (const p of opts.patterns) {
|
|
1679
|
+
if (p.pattern.source.length > maxPatternLength) {
|
|
1680
|
+
throw new Error(
|
|
1681
|
+
`keywordFlagExtractor: pattern "${p.label}" literal exceeds maxPatternLength (${p.pattern.source.length} > ${maxPatternLength}); raise the option or shorten the pattern.`
|
|
1682
|
+
);
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
const compiled = opts.patterns.map((p) => ({
|
|
1686
|
+
label: p.label,
|
|
1687
|
+
pattern: p.pattern,
|
|
1688
|
+
compiled: new RegExp(p.pattern.source, `${p.pattern.flags.replace("g", "")}g`)
|
|
1689
|
+
}));
|
|
1690
|
+
let cleanup;
|
|
1691
|
+
return node7(
|
|
1692
|
+
[accumulatedText],
|
|
1693
|
+
(batchData, actions, ctx) => {
|
|
1694
|
+
if (cleanup === void 0) {
|
|
1695
|
+
const store = ctx.store;
|
|
1696
|
+
cleanup = {
|
|
1697
|
+
onDeactivation: () => {
|
|
1698
|
+
delete store.flags;
|
|
1699
|
+
delete store.scannedTo;
|
|
1700
|
+
}
|
|
1701
|
+
};
|
|
1702
|
+
}
|
|
1703
|
+
const data = batchData.map(
|
|
1704
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
1705
|
+
);
|
|
1706
|
+
const text = data[0];
|
|
1707
|
+
if (text == null) {
|
|
1708
|
+
actions.emit([]);
|
|
1709
|
+
return cleanup;
|
|
1710
|
+
}
|
|
1711
|
+
const accumulated = text;
|
|
1712
|
+
if (!("flags" in ctx.store)) {
|
|
1713
|
+
ctx.store.flags = [];
|
|
1714
|
+
ctx.store.scannedTo = 0;
|
|
1715
|
+
}
|
|
1716
|
+
const flags = ctx.store.flags;
|
|
1717
|
+
const scannedTo = ctx.store.scannedTo;
|
|
1718
|
+
const startOffset = Math.max(0, scannedTo - maxPatternLength);
|
|
1719
|
+
const region = accumulated.slice(startOffset);
|
|
1720
|
+
let added = false;
|
|
1721
|
+
for (const { pattern, label, compiled: re } of compiled) {
|
|
1722
|
+
re.lastIndex = 0;
|
|
1723
|
+
for (const m of region.matchAll(re)) {
|
|
1724
|
+
const pos = startOffset + (m.index ?? 0);
|
|
1725
|
+
if (pos + m[0].length <= scannedTo) continue;
|
|
1726
|
+
flags.push({ label, pattern, match: m[0], position: pos });
|
|
1727
|
+
added = true;
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
ctx.store.scannedTo = accumulated.length;
|
|
1731
|
+
actions.emit(added ? [...flags] : flags.slice());
|
|
1732
|
+
return cleanup;
|
|
1733
|
+
},
|
|
1734
|
+
{
|
|
1735
|
+
name: opts.name ?? "keyword-flag-extractor",
|
|
1736
|
+
describeKind: "derived",
|
|
1737
|
+
initial: [],
|
|
1738
|
+
meta: aiMeta("keyword_flag_extractor"),
|
|
1739
|
+
equals: keywordFlagsEqual
|
|
1740
|
+
}
|
|
1741
|
+
);
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
// src/utils/ai/extractors/stream-extractor.ts
|
|
1745
|
+
import { node as node8 } from "@graphrefly/pure-ts/core";
|
|
1746
|
+
function streamExtractor(accumulatedText, extractFn, opts) {
|
|
1747
|
+
return node8(
|
|
1748
|
+
[accumulatedText],
|
|
1749
|
+
(batchData, actions, ctx) => {
|
|
1750
|
+
const data = batchData.map(
|
|
1751
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
1752
|
+
);
|
|
1753
|
+
const text = data[0];
|
|
1754
|
+
actions.emit(text == null ? null : extractFn(text));
|
|
1755
|
+
},
|
|
1756
|
+
{
|
|
1757
|
+
name: opts?.name ?? "extractor",
|
|
1758
|
+
describeKind: "derived",
|
|
1759
|
+
initial: null,
|
|
1760
|
+
meta: aiMeta("stream_extractor"),
|
|
1761
|
+
...opts?.equals ? { equals: opts.equals } : {}
|
|
1762
|
+
}
|
|
1763
|
+
);
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
// src/utils/ai/extractors/tool-call.ts
|
|
1767
|
+
import { node as node9 } from "@graphrefly/pure-ts/core";
|
|
1768
|
+
var toolCallsEqual = (a, b) => {
|
|
1769
|
+
if (a === b) return true;
|
|
1770
|
+
if (a == null || b == null) return a === b;
|
|
1771
|
+
if (a.length !== b.length) return false;
|
|
1772
|
+
for (let i = 0; i < a.length; i++) {
|
|
1773
|
+
const x = a[i];
|
|
1774
|
+
const y = b[i];
|
|
1775
|
+
if (x.startIndex !== y.startIndex || x.name !== y.name || x.raw !== y.raw) {
|
|
1776
|
+
return false;
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
return true;
|
|
1780
|
+
};
|
|
1781
|
+
function toolCallExtractor(accumulatedText, opts) {
|
|
1782
|
+
let cleanup;
|
|
1783
|
+
return node9(
|
|
1784
|
+
[accumulatedText],
|
|
1785
|
+
(batchData, actions, ctx) => {
|
|
1786
|
+
if (cleanup === void 0) {
|
|
1787
|
+
const store = ctx.store;
|
|
1788
|
+
cleanup = {
|
|
1789
|
+
onDeactivation: () => {
|
|
1790
|
+
delete store.calls;
|
|
1791
|
+
delete store.scanFrom;
|
|
1792
|
+
}
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1795
|
+
const data = batchData.map(
|
|
1796
|
+
(batch2, i2) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i2]
|
|
1797
|
+
);
|
|
1798
|
+
const text = data[0];
|
|
1799
|
+
if (text == null) {
|
|
1800
|
+
actions.emit([]);
|
|
1801
|
+
return cleanup;
|
|
1802
|
+
}
|
|
1803
|
+
const accumulated = text;
|
|
1804
|
+
if (!("calls" in ctx.store)) {
|
|
1805
|
+
ctx.store.calls = [];
|
|
1806
|
+
ctx.store.scanFrom = 0;
|
|
1807
|
+
}
|
|
1808
|
+
const calls = ctx.store.calls;
|
|
1809
|
+
let i = ctx.store.scanFrom;
|
|
1810
|
+
let added = false;
|
|
1811
|
+
while (i < accumulated.length) {
|
|
1812
|
+
const start = accumulated.indexOf("{", i);
|
|
1813
|
+
if (start === -1) {
|
|
1814
|
+
ctx.store.scanFrom = accumulated.length;
|
|
1815
|
+
break;
|
|
1816
|
+
}
|
|
1817
|
+
let depth = 0;
|
|
1818
|
+
let end = -1;
|
|
1819
|
+
let inString = false;
|
|
1820
|
+
for (let j = start; j < accumulated.length; j++) {
|
|
1821
|
+
const ch = accumulated[j];
|
|
1822
|
+
if (inString) {
|
|
1823
|
+
if (ch === "\\" && j + 1 < accumulated.length) {
|
|
1824
|
+
j++;
|
|
1825
|
+
} else if (ch === '"') {
|
|
1826
|
+
inString = false;
|
|
1827
|
+
}
|
|
1828
|
+
} else if (ch === '"') {
|
|
1829
|
+
inString = true;
|
|
1830
|
+
} else if (ch === "{") {
|
|
1831
|
+
depth++;
|
|
1832
|
+
} else if (ch === "}") {
|
|
1833
|
+
depth--;
|
|
1834
|
+
if (depth === 0) {
|
|
1835
|
+
end = j;
|
|
1836
|
+
break;
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
if (end === -1) {
|
|
1841
|
+
ctx.store.scanFrom = start;
|
|
1842
|
+
break;
|
|
1843
|
+
}
|
|
1844
|
+
const raw = accumulated.slice(start, end + 1);
|
|
1845
|
+
try {
|
|
1846
|
+
const parsed = JSON.parse(raw);
|
|
1847
|
+
if (typeof parsed.name === "string" && parsed.arguments != null && typeof parsed.arguments === "object") {
|
|
1848
|
+
calls.push({
|
|
1849
|
+
name: parsed.name,
|
|
1850
|
+
arguments: parsed.arguments,
|
|
1851
|
+
raw,
|
|
1852
|
+
startIndex: start
|
|
1853
|
+
});
|
|
1854
|
+
added = true;
|
|
1855
|
+
}
|
|
1856
|
+
} catch {
|
|
1857
|
+
}
|
|
1858
|
+
i = end + 1;
|
|
1859
|
+
ctx.store.scanFrom = i;
|
|
1860
|
+
}
|
|
1861
|
+
actions.emit(added ? [...calls] : calls.slice());
|
|
1862
|
+
return cleanup;
|
|
1863
|
+
},
|
|
1864
|
+
{
|
|
1865
|
+
name: opts?.name ?? "tool-call-extractor",
|
|
1866
|
+
describeKind: "derived",
|
|
1867
|
+
initial: [],
|
|
1868
|
+
meta: aiMeta("tool_call_extractor"),
|
|
1869
|
+
equals: toolCallsEqual
|
|
1870
|
+
}
|
|
1871
|
+
);
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
// src/utils/ai/safety/content-gate.ts
|
|
1875
|
+
import { node as node10 } from "@graphrefly/pure-ts/core";
|
|
1876
|
+
function contentGate(accumulatedText, classifier, threshold, opts) {
|
|
1877
|
+
const hardThreshold = threshold * (opts?.hardMultiplier ?? 1.5);
|
|
1878
|
+
const isNodeClassifier = typeof classifier !== "function";
|
|
1879
|
+
const deps = [accumulatedText];
|
|
1880
|
+
if (isNodeClassifier) deps.push(classifier);
|
|
1881
|
+
return node10(
|
|
1882
|
+
deps,
|
|
1883
|
+
(batchData, actions, ctx) => {
|
|
1884
|
+
const data = batchData.map(
|
|
1885
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
1886
|
+
);
|
|
1887
|
+
const text = data[0] ?? "";
|
|
1888
|
+
if (text.length === 0) {
|
|
1889
|
+
actions.emit("allow");
|
|
1890
|
+
return;
|
|
1891
|
+
}
|
|
1892
|
+
const score = isNodeClassifier ? data[1] ?? 0 : classifier(text);
|
|
1893
|
+
if (score >= hardThreshold) {
|
|
1894
|
+
actions.emit("block");
|
|
1895
|
+
return;
|
|
1896
|
+
}
|
|
1897
|
+
if (score >= threshold) {
|
|
1898
|
+
actions.emit("review");
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
actions.emit("allow");
|
|
1902
|
+
},
|
|
1903
|
+
{ describeKind: "derived", name: opts?.name ?? "content-gate", initial: "allow" }
|
|
1904
|
+
);
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
// src/utils/ai/safety/redactor.ts
|
|
1908
|
+
import { node as node11 } from "@graphrefly/pure-ts/core";
|
|
1909
|
+
function redactor(accumulatedText, patterns, replaceFn, opts) {
|
|
1910
|
+
const replace = replaceFn ?? (() => "[REDACTED]");
|
|
1911
|
+
function sanitize(text) {
|
|
1912
|
+
let result = text;
|
|
1913
|
+
for (const pat of patterns) {
|
|
1914
|
+
const global = pat.global ? pat : new RegExp(pat.source, `${pat.flags}g`);
|
|
1915
|
+
result = result.replace(global, (m) => replace(m, pat));
|
|
1916
|
+
}
|
|
1917
|
+
return result;
|
|
1918
|
+
}
|
|
1919
|
+
return node11(
|
|
1920
|
+
[accumulatedText],
|
|
1921
|
+
(batchData, actions, ctx) => {
|
|
1922
|
+
const data = batchData.map(
|
|
1923
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
1924
|
+
);
|
|
1925
|
+
actions.emit(sanitize(data[0] ?? ""));
|
|
1926
|
+
},
|
|
1927
|
+
{ describeKind: "derived", name: opts?.name ?? "redactor", initial: "" }
|
|
1928
|
+
);
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
// src/utils/ai/agents/handoff.ts
|
|
1932
|
+
import { factoryTag as factoryTag3, node as node12 } from "@graphrefly/pure-ts/core";
|
|
1933
|
+
import { fromAny as fromAny9, switchMap as switchMap2 } from "@graphrefly/pure-ts/extra";
|
|
1934
|
+
function handoff(from, toFactory, opts) {
|
|
1935
|
+
const src = fromAny9(from);
|
|
1936
|
+
const cond = opts?.condition != null ? fromAny9(opts.condition) : null;
|
|
1937
|
+
const nullState = node12([], {
|
|
1938
|
+
initial: null,
|
|
1939
|
+
name: opts?.name ? `${opts.name}::null` : "handoff::null"
|
|
1940
|
+
});
|
|
1941
|
+
if (cond == null) {
|
|
1942
|
+
return switchMap2(
|
|
1943
|
+
src,
|
|
1944
|
+
(v) => {
|
|
1945
|
+
if (v == null) return nullState;
|
|
1946
|
+
const input = node12([], { initial: v });
|
|
1947
|
+
return toFactory(input);
|
|
1948
|
+
},
|
|
1949
|
+
{ meta: factoryTag3("handoff") }
|
|
1950
|
+
);
|
|
1951
|
+
}
|
|
1952
|
+
const router = node12(
|
|
1953
|
+
[src, cond],
|
|
1954
|
+
(batchData, actions, ctx) => {
|
|
1955
|
+
const data = batchData.map(
|
|
1956
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
1957
|
+
);
|
|
1958
|
+
actions.emit({ v: data[0], open: data[1] === true });
|
|
1959
|
+
},
|
|
1960
|
+
{ name: opts?.name ? `${opts.name}::router` : "handoff::router", describeKind: "derived" }
|
|
1961
|
+
);
|
|
1962
|
+
return switchMap2(
|
|
1963
|
+
router,
|
|
1964
|
+
({ v, open }) => {
|
|
1965
|
+
if (v == null) return nullState;
|
|
1966
|
+
if (!open) return node12([], { initial: v });
|
|
1967
|
+
const input = node12([], { initial: v });
|
|
1968
|
+
return toFactory(input);
|
|
1969
|
+
},
|
|
1970
|
+
{ meta: factoryTag3("handoff") }
|
|
1971
|
+
);
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
// src/utils/ai/agents/tool-selector.ts
|
|
1975
|
+
import { factoryTag as factoryTag4, node as node13 } from "@graphrefly/pure-ts/core";
|
|
1976
|
+
import { fromAny as fromAny10 } from "@graphrefly/pure-ts/extra";
|
|
1977
|
+
function toolSelector(allTools, constraints, opts) {
|
|
1978
|
+
const allToolsNode = fromAny10(allTools);
|
|
1979
|
+
const constraintNodes = constraints.map((c) => fromAny10(c));
|
|
1980
|
+
const deps = [allToolsNode, ...constraintNodes];
|
|
1981
|
+
return node13(
|
|
1982
|
+
deps,
|
|
1983
|
+
(batchData, actions, ctx) => {
|
|
1984
|
+
const data = batchData.map(
|
|
1985
|
+
(batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
|
|
1986
|
+
);
|
|
1987
|
+
const tools = data[0] ?? [];
|
|
1988
|
+
const preds = data.slice(1);
|
|
1989
|
+
actions.emit(
|
|
1990
|
+
tools.filter((tool) => {
|
|
1991
|
+
for (const pred of preds) {
|
|
1992
|
+
if (pred == null) continue;
|
|
1993
|
+
if (!pred(tool)) return false;
|
|
1994
|
+
}
|
|
1995
|
+
return true;
|
|
1996
|
+
})
|
|
1997
|
+
);
|
|
1998
|
+
},
|
|
1999
|
+
{
|
|
2000
|
+
name: opts?.name ?? "tool-selector",
|
|
2001
|
+
describeKind: "derived",
|
|
2002
|
+
meta: { ...aiMeta("tool_selector"), ...factoryTag4("toolSelector") },
|
|
2003
|
+
equals: (a, b) => {
|
|
2004
|
+
const la = a;
|
|
2005
|
+
const lb = b;
|
|
2006
|
+
if (la.length !== lb.length) return false;
|
|
2007
|
+
for (let i = 0; i < la.length; i++) {
|
|
2008
|
+
if (la[i] !== lb[i]) return false;
|
|
2009
|
+
}
|
|
2010
|
+
return true;
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
);
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
// src/utils/ai/memory/admission.ts
|
|
2017
|
+
function admissionScored(opts) {
|
|
2018
|
+
const thresholds = opts.thresholds ?? {};
|
|
2019
|
+
return (raw) => {
|
|
2020
|
+
const scores = opts.scoreFn(raw);
|
|
2021
|
+
for (const dim of Object.keys(thresholds)) {
|
|
2022
|
+
const min = thresholds[dim];
|
|
2023
|
+
if (min === void 0) continue;
|
|
2024
|
+
const s = scores[dim];
|
|
2025
|
+
const safe = Number.isFinite(s) ? s : Number.NEGATIVE_INFINITY;
|
|
2026
|
+
if (safe < min) return false;
|
|
2027
|
+
}
|
|
2028
|
+
return true;
|
|
2029
|
+
};
|
|
2030
|
+
}
|
|
2031
|
+
function admissionFilter3D(opts) {
|
|
2032
|
+
const thresholds = {
|
|
2033
|
+
persistence: opts.persistenceThreshold ?? 0.3,
|
|
2034
|
+
personalValue: opts.personalValueThreshold ?? 0.3
|
|
2035
|
+
};
|
|
2036
|
+
const base = admissionScored({
|
|
2037
|
+
scoreFn: opts.scoreFn,
|
|
2038
|
+
thresholds
|
|
2039
|
+
});
|
|
2040
|
+
if (!opts.requireStructured) return base;
|
|
2041
|
+
return (raw) => {
|
|
2042
|
+
if (!base(raw)) return false;
|
|
2043
|
+
const s = opts.scoreFn(raw).structure;
|
|
2044
|
+
return Number.isFinite(s) && s > 0;
|
|
2045
|
+
};
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
// src/utils/ai/graph-integration/gauges-as-context.ts
|
|
2049
|
+
function gaugesAsContext(graph, actor, options) {
|
|
2050
|
+
const described = graph.describe({ actor, detail: "full" });
|
|
2051
|
+
const groupByTags = options?.groupByTags ?? true;
|
|
2052
|
+
const separator = options?.separator ?? "\n";
|
|
2053
|
+
const entries = [];
|
|
2054
|
+
const sinceVersion = options?.sinceVersion;
|
|
2055
|
+
for (const [path, node16] of Object.entries(described.nodes)) {
|
|
2056
|
+
const meta = node16.meta ?? {};
|
|
2057
|
+
const desc = meta.description;
|
|
2058
|
+
const format = meta.format;
|
|
2059
|
+
if (!desc && !format) continue;
|
|
2060
|
+
if (sinceVersion != null && node16.v != null) {
|
|
2061
|
+
const lastSeen = sinceVersion.get(path);
|
|
2062
|
+
if (lastSeen != null && lastSeen.id === node16.v.id && node16.v.version <= lastSeen.version)
|
|
2063
|
+
continue;
|
|
2064
|
+
}
|
|
2065
|
+
const label = desc ?? path;
|
|
2066
|
+
const value = node16.value;
|
|
2067
|
+
const unit = meta.unit;
|
|
2068
|
+
let formatted;
|
|
2069
|
+
if (format === "currency" && typeof value === "number") {
|
|
2070
|
+
formatted = `$${value.toFixed(2)}`;
|
|
2071
|
+
} else if (format === "percentage" && typeof value === "number") {
|
|
2072
|
+
formatted = `${(value * 100).toFixed(1)}%`;
|
|
2073
|
+
} else if (value === void 0 || value === null) {
|
|
2074
|
+
formatted = "(no value)";
|
|
2075
|
+
} else {
|
|
2076
|
+
formatted = String(value);
|
|
2077
|
+
}
|
|
2078
|
+
if (unit && format !== "currency" && format !== "percentage") {
|
|
2079
|
+
formatted = `${formatted} ${unit}`;
|
|
2080
|
+
}
|
|
2081
|
+
entries.push({ path, description: label, formatted });
|
|
2082
|
+
}
|
|
2083
|
+
if (entries.length === 0) return "";
|
|
2084
|
+
if (groupByTags) {
|
|
2085
|
+
const tagGroups = /* @__PURE__ */ new Map();
|
|
2086
|
+
const ungrouped = [];
|
|
2087
|
+
for (const entry of entries) {
|
|
2088
|
+
const node16 = described.nodes[entry.path];
|
|
2089
|
+
const tags = node16.meta?.tags;
|
|
2090
|
+
if (tags && tags.length > 0) {
|
|
2091
|
+
const tag = tags[0];
|
|
2092
|
+
let group = tagGroups.get(tag);
|
|
2093
|
+
if (!group) {
|
|
2094
|
+
group = [];
|
|
2095
|
+
tagGroups.set(tag, group);
|
|
2096
|
+
}
|
|
2097
|
+
group.push(entry);
|
|
2098
|
+
} else {
|
|
2099
|
+
ungrouped.push(entry);
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
if (tagGroups.size === 0) {
|
|
2103
|
+
return entries.map((e) => `- ${e.description}: ${e.formatted}`).join(separator);
|
|
2104
|
+
}
|
|
2105
|
+
const sections = [];
|
|
2106
|
+
for (const [tag, group] of [...tagGroups.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
|
|
2107
|
+
sections.push(
|
|
2108
|
+
`[${tag}]${separator}${group.map((e) => `- ${e.description}: ${e.formatted}`).join(separator)}`
|
|
2109
|
+
);
|
|
2110
|
+
}
|
|
2111
|
+
if (ungrouped.length > 0) {
|
|
2112
|
+
sections.push(ungrouped.map((e) => `- ${e.description}: ${e.formatted}`).join(separator));
|
|
2113
|
+
}
|
|
2114
|
+
return sections.join(separator + separator);
|
|
2115
|
+
}
|
|
2116
|
+
return entries.map((e) => `- ${e.description}: ${e.formatted}`).join(separator);
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
// src/utils/ai/graph-integration/graph-from-spec.ts
|
|
2120
|
+
import { COMPLETE, ERROR, node as node14 } from "@graphrefly/pure-ts/core";
|
|
2121
|
+
import { fromAny as fromAny11, switchMap as switchMap3 } from "@graphrefly/pure-ts/extra";
|
|
2122
|
+
var GRAPH_FROM_SPEC_SYSTEM_PROMPT = `You are a graph architect for GraphReFly, a reactive graph protocol.
|
|
2123
|
+
|
|
2124
|
+
Given a natural-language description, produce a JSON graph specification with this structure:
|
|
2125
|
+
|
|
2126
|
+
{
|
|
2127
|
+
"name": "<graph_name>",
|
|
2128
|
+
"nodes": {
|
|
2129
|
+
"<node_name>": {
|
|
2130
|
+
"type": "state" | "derived" | "producer" | "effect" | "operator",
|
|
2131
|
+
"initial": <initial_value_for_state_nodes>,
|
|
2132
|
+
"deps": ["<dep_node_name>", ...],
|
|
2133
|
+
"meta": {
|
|
2134
|
+
"description": "<human-readable purpose>",
|
|
2135
|
+
"type": "string" | "number" | "boolean" | "integer" | "enum",
|
|
2136
|
+
"range": [min, max],
|
|
2137
|
+
"values": ["a", "b"],
|
|
2138
|
+
"format": "currency" | "percentage" | "status",
|
|
2139
|
+
"access": "human" | "llm" | "both" | "system",
|
|
2140
|
+
"unit": "<unit>",
|
|
2141
|
+
"tags": ["<tag>"]
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
Rules:
|
|
2148
|
+
- "state" nodes have no deps and hold user/LLM-writable values (knobs). Use "initial" for the starting value.
|
|
2149
|
+
- "derived" nodes have deps and compute from them (pure, no side effects).
|
|
2150
|
+
- "effect" nodes have deps but produce side effects (no return value).
|
|
2151
|
+
- "producer" nodes have no deps but generate values asynchronously.
|
|
2152
|
+
- "operator" nodes are parameterized transformations with deps.
|
|
2153
|
+
- Use "deps" inside each node to declare dependencies \u2014 no separate "edges" array.
|
|
2154
|
+
- meta.description is required for every node.
|
|
2155
|
+
- Return ONLY valid JSON, no markdown fences or commentary.`;
|
|
2156
|
+
async function graphFromSpec(naturalLanguage, adapter, opts) {
|
|
2157
|
+
const systemPrompt = opts?.systemPromptExtra ? `${GRAPH_FROM_SPEC_SYSTEM_PROMPT}
|
|
2158
|
+
|
|
2159
|
+
${opts.systemPromptExtra}` : GRAPH_FROM_SPEC_SYSTEM_PROMPT;
|
|
2160
|
+
const messages = [
|
|
2161
|
+
{ role: "system", content: systemPrompt },
|
|
2162
|
+
{ role: "user", content: naturalLanguage }
|
|
2163
|
+
];
|
|
2164
|
+
const rawResult = adapter.invoke(messages, {
|
|
2165
|
+
model: opts?.model,
|
|
2166
|
+
temperature: opts?.temperature ?? 0,
|
|
2167
|
+
maxTokens: opts?.maxTokens,
|
|
2168
|
+
signal: opts?.signal
|
|
2169
|
+
});
|
|
2170
|
+
const response = await resolveToolHandlerResult(rawResult);
|
|
2171
|
+
let content = response.content.trim();
|
|
2172
|
+
if (content.startsWith("```")) {
|
|
2173
|
+
content = stripFences(content);
|
|
2174
|
+
}
|
|
2175
|
+
let parsed;
|
|
2176
|
+
try {
|
|
2177
|
+
parsed = JSON.parse(content);
|
|
2178
|
+
} catch {
|
|
2179
|
+
throw new Error(`graphFromSpec: LLM response is not valid JSON: ${content.slice(0, 200)}`);
|
|
2180
|
+
}
|
|
2181
|
+
return compileSpec(parsed, { catalog: opts?.catalog });
|
|
2182
|
+
}
|
|
2183
|
+
function graphFromSpecReactive(input, adapter, opts) {
|
|
2184
|
+
const inputNode = fromAny11(input);
|
|
2185
|
+
return switchMap3(inputNode, (nl) => {
|
|
2186
|
+
if (!nl || typeof nl !== "string" || nl.trim().length === 0) {
|
|
2187
|
+
return node14([], { initial: null });
|
|
2188
|
+
}
|
|
2189
|
+
return node14(
|
|
2190
|
+
(_data, actions) => {
|
|
2191
|
+
const controller = new AbortController();
|
|
2192
|
+
let cancelled = false;
|
|
2193
|
+
graphFromSpec(nl, adapter, { ...opts, signal: controller.signal }).then((g) => {
|
|
2194
|
+
if (cancelled) {
|
|
2195
|
+
g.destroy();
|
|
2196
|
+
return;
|
|
2197
|
+
}
|
|
2198
|
+
actions.emit(g);
|
|
2199
|
+
actions.down([[COMPLETE]]);
|
|
2200
|
+
}).catch((err) => {
|
|
2201
|
+
if (cancelled) return;
|
|
2202
|
+
actions.down([[ERROR, err]]);
|
|
2203
|
+
});
|
|
2204
|
+
return () => {
|
|
2205
|
+
cancelled = true;
|
|
2206
|
+
controller.abort();
|
|
2207
|
+
};
|
|
2208
|
+
},
|
|
2209
|
+
{ describeKind: "producer", ...{ name: "graphFromSpec::call" } }
|
|
2210
|
+
);
|
|
2211
|
+
});
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
// src/utils/ai/graph-integration/knobs-as-tools.ts
|
|
2215
|
+
function metaToJsonSchema(meta) {
|
|
2216
|
+
const schema = {};
|
|
2217
|
+
const metaType = meta.type;
|
|
2218
|
+
if (metaType === "enum" && Array.isArray(meta.values)) {
|
|
2219
|
+
schema.type = "string";
|
|
2220
|
+
schema.enum = meta.values;
|
|
2221
|
+
} else if (metaType === "integer") {
|
|
2222
|
+
schema.type = "integer";
|
|
2223
|
+
} else if (metaType === "number") {
|
|
2224
|
+
schema.type = "number";
|
|
2225
|
+
} else if (metaType === "boolean") {
|
|
2226
|
+
schema.type = "boolean";
|
|
2227
|
+
} else if (metaType === "string") {
|
|
2228
|
+
schema.type = "string";
|
|
2229
|
+
} else {
|
|
2230
|
+
schema.type = ["string", "number", "boolean"];
|
|
2231
|
+
}
|
|
2232
|
+
if (Array.isArray(meta.range) && meta.range.length === 2) {
|
|
2233
|
+
schema.minimum = meta.range[0];
|
|
2234
|
+
schema.maximum = meta.range[1];
|
|
2235
|
+
}
|
|
2236
|
+
if (typeof meta.format === "string") {
|
|
2237
|
+
schema.description = `Format: ${meta.format}`;
|
|
2238
|
+
}
|
|
2239
|
+
if (typeof meta.unit === "string") {
|
|
2240
|
+
if (schema.description) {
|
|
2241
|
+
schema.description += ` (${meta.unit})`;
|
|
2242
|
+
} else {
|
|
2243
|
+
schema.description = `Unit: ${meta.unit}`;
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
return schema;
|
|
2247
|
+
}
|
|
2248
|
+
function knobsAsTools(graph, actor) {
|
|
2249
|
+
const described = graph.describe({ actor, detail: "full" });
|
|
2250
|
+
const openai = [];
|
|
2251
|
+
const mcp = [];
|
|
2252
|
+
const definitions = [];
|
|
2253
|
+
for (const [path, node16] of Object.entries(described.nodes)) {
|
|
2254
|
+
if (node16.type !== "state") continue;
|
|
2255
|
+
if (path.includes("::__meta__::")) continue;
|
|
2256
|
+
if (node16.status === "completed" || node16.status === "errored") continue;
|
|
2257
|
+
const meta = node16.meta ?? {};
|
|
2258
|
+
const access = meta.access;
|
|
2259
|
+
if (access === "human" || access === "system") continue;
|
|
2260
|
+
const description = meta.description ?? `Set the value of ${path}`;
|
|
2261
|
+
const valueSchema = metaToJsonSchema(meta);
|
|
2262
|
+
const parameterSchema = {
|
|
2263
|
+
type: "object",
|
|
2264
|
+
required: ["value"],
|
|
2265
|
+
properties: {
|
|
2266
|
+
value: valueSchema
|
|
2267
|
+
},
|
|
2268
|
+
additionalProperties: false
|
|
2269
|
+
};
|
|
2270
|
+
const sanitizedName = path.replace(/::/g, "__");
|
|
2271
|
+
openai.push({
|
|
2272
|
+
type: "function",
|
|
2273
|
+
function: {
|
|
2274
|
+
name: sanitizedName,
|
|
2275
|
+
description,
|
|
2276
|
+
parameters: parameterSchema
|
|
2277
|
+
}
|
|
2278
|
+
});
|
|
2279
|
+
mcp.push({
|
|
2280
|
+
name: path,
|
|
2281
|
+
description,
|
|
2282
|
+
inputSchema: parameterSchema
|
|
2283
|
+
});
|
|
2284
|
+
const graphRef = graph;
|
|
2285
|
+
const actorRef = actor;
|
|
2286
|
+
const nv = node16.v;
|
|
2287
|
+
definitions.push({
|
|
2288
|
+
name: path,
|
|
2289
|
+
description,
|
|
2290
|
+
parameters: parameterSchema,
|
|
2291
|
+
handler(args) {
|
|
2292
|
+
graphRef.set(path, args.value, actorRef ? { actor: actorRef } : void 0);
|
|
2293
|
+
return args.value;
|
|
2294
|
+
},
|
|
2295
|
+
...nv != null ? { version: { id: nv.id, version: nv.version } } : {}
|
|
2296
|
+
});
|
|
2297
|
+
}
|
|
2298
|
+
return { openai, mcp, definitions };
|
|
2299
|
+
}
|
|
2300
|
+
|
|
2301
|
+
// src/utils/ai/graph-integration/suggest-strategy.ts
|
|
2302
|
+
import { COMPLETE as COMPLETE2, ERROR as ERROR2, node as node15 } from "@graphrefly/pure-ts/core";
|
|
2303
|
+
import { fromAny as fromAny12, switchMap as switchMap4, withLatestFrom } from "@graphrefly/pure-ts/extra";
|
|
2304
|
+
var SUGGEST_STRATEGY_SYSTEM_PROMPT = `You are a reactive graph optimizer for GraphReFly.
|
|
2305
|
+
|
|
2306
|
+
Given a graph's current structure (from describe()) and a problem statement, suggest topology and parameter changes to solve the problem.
|
|
2307
|
+
|
|
2308
|
+
Return ONLY valid JSON with this structure:
|
|
2309
|
+
{
|
|
2310
|
+
"summary": "<one-line summary of the strategy>",
|
|
2311
|
+
"reasoning": "<explanation of why these changes help>",
|
|
2312
|
+
"operations": [
|
|
2313
|
+
{ "type": "add_node", "name": "<name>", "nodeType": "state|derived|effect|producer|operator", "meta": {...}, "initial": <value> },
|
|
2314
|
+
{ "type": "remove_node", "name": "<name>" },
|
|
2315
|
+
{ "type": "connect", "from": "<source>", "to": "<target>" },
|
|
2316
|
+
{ "type": "disconnect", "from": "<source>", "to": "<target>" },
|
|
2317
|
+
{ "type": "set_value", "name": "<name>", "value": <new_value> },
|
|
2318
|
+
{ "type": "update_meta", "name": "<name>", "key": "<meta_key>", "value": <new_value> }
|
|
2319
|
+
]
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
Rules:
|
|
2323
|
+
- Only suggest operations that reference existing nodes (for remove/disconnect/set_value/update_meta) or new nodes you define (for add_node).
|
|
2324
|
+
- Keep changes minimal \u2014 prefer the smallest set of operations that solves the problem.
|
|
2325
|
+
- Return ONLY valid JSON, no markdown fences or commentary.`;
|
|
2326
|
+
async function suggestStrategy(graph, problem, adapter, opts) {
|
|
2327
|
+
const { expand: _, ...described } = graph.describe({ actor: opts?.actor, detail: "standard" });
|
|
2328
|
+
const messages = [
|
|
2329
|
+
{ role: "system", content: SUGGEST_STRATEGY_SYSTEM_PROMPT },
|
|
2330
|
+
{
|
|
2331
|
+
role: "user",
|
|
2332
|
+
content: JSON.stringify({
|
|
2333
|
+
graph: described,
|
|
2334
|
+
problem
|
|
2335
|
+
})
|
|
2336
|
+
}
|
|
2337
|
+
];
|
|
2338
|
+
const rawResult = adapter.invoke(messages, {
|
|
2339
|
+
model: opts?.model,
|
|
2340
|
+
temperature: opts?.temperature ?? 0,
|
|
2341
|
+
maxTokens: opts?.maxTokens,
|
|
2342
|
+
signal: opts?.signal
|
|
2343
|
+
});
|
|
2344
|
+
const response = await resolveToolHandlerResult(rawResult);
|
|
2345
|
+
let content = response.content.trim();
|
|
2346
|
+
if (content.startsWith("```")) {
|
|
2347
|
+
content = content.replace(/^```(?:json)?\s*/, "").replace(/\s*```$/, "");
|
|
2348
|
+
}
|
|
2349
|
+
let parsed;
|
|
2350
|
+
try {
|
|
2351
|
+
parsed = JSON.parse(content);
|
|
2352
|
+
} catch {
|
|
2353
|
+
throw new Error(`suggestStrategy: LLM response is not valid JSON: ${content.slice(0, 200)}`);
|
|
2354
|
+
}
|
|
2355
|
+
const plan = parsed;
|
|
2356
|
+
if (typeof plan.summary !== "string") {
|
|
2357
|
+
throw new Error("suggestStrategy: missing 'summary' in response");
|
|
2358
|
+
}
|
|
2359
|
+
if (typeof plan.reasoning !== "string") {
|
|
2360
|
+
throw new Error("suggestStrategy: missing 'reasoning' in response");
|
|
2361
|
+
}
|
|
2362
|
+
if (!Array.isArray(plan.operations)) {
|
|
2363
|
+
throw new Error("suggestStrategy: missing 'operations' array in response");
|
|
2364
|
+
}
|
|
2365
|
+
return {
|
|
2366
|
+
summary: plan.summary,
|
|
2367
|
+
reasoning: plan.reasoning,
|
|
2368
|
+
operations: plan.operations
|
|
2369
|
+
};
|
|
2370
|
+
}
|
|
2371
|
+
function suggestStrategyReactive(graph, problem, adapter, opts) {
|
|
2372
|
+
const problemNode = fromAny12(problem);
|
|
2373
|
+
const paired = withLatestFrom(problemNode, graph);
|
|
2374
|
+
return switchMap4(paired, (pair) => {
|
|
2375
|
+
if (pair == null) return node15([], { initial: null });
|
|
2376
|
+
const [pText, g] = pair;
|
|
2377
|
+
if (!g || !pText || typeof pText !== "string" || pText.trim().length === 0) {
|
|
2378
|
+
return node15([], { initial: null });
|
|
2379
|
+
}
|
|
2380
|
+
if (g.destroyed) return node15([], { initial: null });
|
|
2381
|
+
return node15(
|
|
2382
|
+
(_data, actions) => {
|
|
2383
|
+
const controller = new AbortController();
|
|
2384
|
+
let cancelled = false;
|
|
2385
|
+
suggestStrategy(g, pText, adapter, { ...opts, signal: controller.signal }).then((plan) => {
|
|
2386
|
+
if (cancelled) return;
|
|
2387
|
+
actions.emit(plan);
|
|
2388
|
+
actions.down([[COMPLETE2]]);
|
|
2389
|
+
}).catch((err) => {
|
|
2390
|
+
if (cancelled) return;
|
|
2391
|
+
actions.down([[ERROR2, err]]);
|
|
2392
|
+
});
|
|
2393
|
+
return () => {
|
|
2394
|
+
cancelled = true;
|
|
2395
|
+
controller.abort();
|
|
2396
|
+
};
|
|
2397
|
+
},
|
|
2398
|
+
{ describeKind: "producer", ...{ name: "suggestStrategy::call" } }
|
|
2399
|
+
);
|
|
2400
|
+
});
|
|
2401
|
+
}
|
|
2402
|
+
|
|
2403
|
+
// src/utils/ai/graph-integration/validate-graph-def.ts
|
|
2404
|
+
var VALID_NODE_TYPES = /* @__PURE__ */ new Set(["state", "derived", "producer", "operator", "effect"]);
|
|
2405
|
+
function validateGraphDef(def) {
|
|
2406
|
+
const errors = [];
|
|
2407
|
+
if (def == null || typeof def !== "object") {
|
|
2408
|
+
return { valid: false, errors: ["Definition must be a non-null object"] };
|
|
2409
|
+
}
|
|
2410
|
+
const d = def;
|
|
2411
|
+
if (typeof d.name !== "string" || d.name.length === 0) {
|
|
2412
|
+
errors.push("Missing or empty 'name' field");
|
|
2413
|
+
}
|
|
2414
|
+
if (d.nodes == null || typeof d.nodes !== "object" || Array.isArray(d.nodes)) {
|
|
2415
|
+
errors.push("Missing or invalid 'nodes' field (must be an object)");
|
|
2416
|
+
return { valid: false, errors };
|
|
2417
|
+
}
|
|
2418
|
+
const nodeNames = new Set(Object.keys(d.nodes));
|
|
2419
|
+
for (const [name, raw] of Object.entries(d.nodes)) {
|
|
2420
|
+
if (raw == null || typeof raw !== "object") {
|
|
2421
|
+
errors.push(`Node "${name}": must be an object`);
|
|
2422
|
+
continue;
|
|
2423
|
+
}
|
|
2424
|
+
const node16 = raw;
|
|
2425
|
+
if (typeof node16.type !== "string" || !VALID_NODE_TYPES.has(node16.type)) {
|
|
2426
|
+
errors.push(
|
|
2427
|
+
`Node "${name}": invalid type "${String(node16.type)}" (expected: ${[...VALID_NODE_TYPES].join(", ")})`
|
|
2428
|
+
);
|
|
2429
|
+
}
|
|
2430
|
+
if (Array.isArray(node16.deps)) {
|
|
2431
|
+
for (const dep of node16.deps) {
|
|
2432
|
+
if (typeof dep === "string" && !nodeNames.has(dep)) {
|
|
2433
|
+
errors.push(`Node "${name}": dep "${dep}" does not reference an existing node`);
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
if (!Array.isArray(d.edges)) {
|
|
2439
|
+
if (d.edges !== void 0) {
|
|
2440
|
+
errors.push("'edges' must be an array");
|
|
2441
|
+
}
|
|
2442
|
+
} else {
|
|
2443
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2444
|
+
for (let i = 0; i < d.edges.length; i++) {
|
|
2445
|
+
const edge = d.edges[i];
|
|
2446
|
+
if (edge == null || typeof edge !== "object") {
|
|
2447
|
+
errors.push(`Edge [${i}]: must be an object`);
|
|
2448
|
+
continue;
|
|
2449
|
+
}
|
|
2450
|
+
const e = edge;
|
|
2451
|
+
if (typeof e.from !== "string" || !nodeNames.has(e.from)) {
|
|
2452
|
+
errors.push(`Edge [${i}]: 'from' "${String(e.from)}" does not reference an existing node`);
|
|
2453
|
+
}
|
|
2454
|
+
if (typeof e.to !== "string" || !nodeNames.has(e.to)) {
|
|
2455
|
+
errors.push(`Edge [${i}]: 'to' "${String(e.to)}" does not reference an existing node`);
|
|
2456
|
+
}
|
|
2457
|
+
const key = `${e.from}->${e.to}`;
|
|
2458
|
+
if (seen.has(key)) {
|
|
2459
|
+
errors.push(`Edge [${i}]: duplicate edge ${key}`);
|
|
2460
|
+
}
|
|
2461
|
+
seen.add(key);
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
return { valid: errors.length === 0, errors };
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
export {
|
|
2468
|
+
createCapabilitiesRegistry,
|
|
2469
|
+
observableAdapter,
|
|
2470
|
+
zeroPrice,
|
|
2471
|
+
computePrice,
|
|
2472
|
+
createPricingRegistry,
|
|
2473
|
+
registryPricing,
|
|
2474
|
+
composePricing,
|
|
2475
|
+
pricingFor,
|
|
2476
|
+
withLLMBreaker,
|
|
2477
|
+
BudgetExhaustedError,
|
|
2478
|
+
withBudgetGate,
|
|
2479
|
+
withDryRun,
|
|
2480
|
+
parseRateLimitFromError,
|
|
2481
|
+
withRateLimiter,
|
|
2482
|
+
withRetry,
|
|
2483
|
+
LLMTimeoutError,
|
|
2484
|
+
withLLMTimeout,
|
|
2485
|
+
resilientAdapter,
|
|
2486
|
+
frozenContext,
|
|
2487
|
+
streamingPromptNode,
|
|
2488
|
+
gatedStream,
|
|
2489
|
+
systemPromptBuilder,
|
|
2490
|
+
costMeterExtractor,
|
|
2491
|
+
keywordFlagExtractor,
|
|
2492
|
+
streamExtractor,
|
|
2493
|
+
toolCallExtractor,
|
|
2494
|
+
contentGate,
|
|
2495
|
+
redactor,
|
|
2496
|
+
handoff,
|
|
2497
|
+
toolSelector,
|
|
2498
|
+
admissionScored,
|
|
2499
|
+
admissionFilter3D,
|
|
2500
|
+
gaugesAsContext,
|
|
2501
|
+
graphFromSpec,
|
|
2502
|
+
graphFromSpecReactive,
|
|
2503
|
+
knobsAsTools,
|
|
2504
|
+
suggestStrategy,
|
|
2505
|
+
suggestStrategyReactive,
|
|
2506
|
+
validateGraphDef
|
|
2507
|
+
};
|
|
2508
|
+
//# sourceMappingURL=chunk-HULCUY35.js.map
|