@theokit/sdk 5.15.1 → 5.15.2
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/CHANGELOG.md +6 -0
- package/dist/a2a/index.cjs +3 -3
- package/dist/a2a/index.js +1 -1
- package/dist/agent-D6WBBNGR.cjs +72 -0
- package/dist/{agent-CB27KF6O.cjs.map → agent-D6WBBNGR.cjs.map} +1 -1
- package/dist/agent-QRIFX2SY.js +63 -0
- package/dist/{agent-66U5QCPF.js.map → agent-QRIFX2SY.js.map} +1 -1
- package/dist/agent-session-store-2LQEPS4H.js +6 -0
- package/dist/{agent-session-store-22GKA7O4.js.map → agent-session-store-2LQEPS4H.js.map} +1 -1
- package/dist/agent-session-store-IOH6BREF.cjs +23 -0
- package/dist/{agent-session-store-WP6NGDVX.cjs.map → agent-session-store-IOH6BREF.cjs.map} +1 -1
- package/dist/auth/index.cjs +15 -15
- package/dist/auth/index.js +3 -3
- package/dist/{batch-N2XDYZED.js → batch-7IGV2OKA.js} +8 -8
- package/dist/{batch-N2XDYZED.js.map → batch-7IGV2OKA.js.map} +1 -1
- package/dist/{batch-VFR2MAUE.cjs → batch-FIWQZ3JD.cjs} +14 -14
- package/dist/{batch-VFR2MAUE.cjs.map → batch-FIWQZ3JD.cjs.map} +1 -1
- package/dist/{chunk-AT2PESXB.cjs → chunk-2UYAL4N7.cjs} +5 -5
- package/dist/chunk-2UYAL4N7.cjs.map +1 -0
- package/dist/{chunk-K2BQQ445.js → chunk-3GQYMKVJ.js} +3 -3
- package/dist/{chunk-K2BQQ445.js.map → chunk-3GQYMKVJ.js.map} +1 -1
- package/dist/{chunk-YSTXFWQE.cjs → chunk-3HL43XBD.cjs} +4 -4
- package/dist/{chunk-YSTXFWQE.cjs.map → chunk-3HL43XBD.cjs.map} +1 -1
- package/dist/{chunk-XESYJ4JC.js → chunk-3VX7JHJI.js} +7 -7
- package/dist/{chunk-XESYJ4JC.js.map → chunk-3VX7JHJI.js.map} +1 -1
- package/dist/{chunk-6XQLTQB6.cjs → chunk-3YCNBOX7.cjs} +3 -3
- package/dist/{chunk-6XQLTQB6.cjs.map → chunk-3YCNBOX7.cjs.map} +1 -1
- package/dist/{chunk-CHKV2L2Y.cjs → chunk-46YYJIHL.cjs} +30 -30
- package/dist/chunk-46YYJIHL.cjs.map +1 -0
- package/dist/{chunk-73IITAF7.js → chunk-4C37ELQL.js} +9 -9
- package/dist/{chunk-73IITAF7.js.map → chunk-4C37ELQL.js.map} +1 -1
- package/dist/{chunk-AGO5S5WD.js → chunk-4E4D6H77.js} +3 -3
- package/dist/{chunk-AGO5S5WD.js.map → chunk-4E4D6H77.js.map} +1 -1
- package/dist/{chunk-R35ZJAYT.cjs → chunk-4JF52NED.cjs} +12 -12
- package/dist/{chunk-R35ZJAYT.cjs.map → chunk-4JF52NED.cjs.map} +1 -1
- package/dist/{chunk-INVEGVGO.js → chunk-4TA47IK4.js} +8 -8
- package/dist/{chunk-INVEGVGO.js.map → chunk-4TA47IK4.js.map} +1 -1
- package/dist/{chunk-MLGETTYX.js → chunk-4YUIYSZO.js} +6 -6
- package/dist/{chunk-MLGETTYX.js.map → chunk-4YUIYSZO.js.map} +1 -1
- package/dist/{chunk-RZL2W4C3.js → chunk-5L7S2VOL.js} +5 -5
- package/dist/{chunk-RZL2W4C3.js.map → chunk-5L7S2VOL.js.map} +1 -1
- package/dist/{chunk-3WKWBYPO.cjs → chunk-6EHOJLJ3.cjs} +20 -20
- package/dist/chunk-6EHOJLJ3.cjs.map +1 -0
- package/dist/{chunk-XOU3CL7S.cjs → chunk-6HQFPX7N.cjs} +28 -28
- package/dist/chunk-6HQFPX7N.cjs.map +1 -0
- package/dist/{chunk-3E3VSMB6.cjs → chunk-6XT5LAZG.cjs} +58 -58
- package/dist/chunk-6XT5LAZG.cjs.map +1 -0
- package/dist/{chunk-R427EOZE.cjs → chunk-7EFT6N5C.cjs} +13 -13
- package/dist/{chunk-R427EOZE.cjs.map → chunk-7EFT6N5C.cjs.map} +1 -1
- package/dist/{chunk-L7V4DDIE.cjs → chunk-7VNFOGRD.cjs} +12 -12
- package/dist/chunk-7VNFOGRD.cjs.map +1 -0
- package/dist/{chunk-YKNBTHMD.js → chunk-AQ23NII7.js} +3 -3
- package/dist/{chunk-YKNBTHMD.js.map → chunk-AQ23NII7.js.map} +1 -1
- package/dist/{chunk-O2RCS3SJ.js → chunk-ATGSV4GS.js} +4 -4
- package/dist/{chunk-O2RCS3SJ.js.map → chunk-ATGSV4GS.js.map} +1 -1
- package/dist/{chunk-H7HD6RXO.cjs → chunk-AW72G4TC.cjs} +5 -5
- package/dist/{chunk-H7HD6RXO.cjs.map → chunk-AW72G4TC.cjs.map} +1 -1
- package/dist/{chunk-M4U24U6G.js → chunk-AZK3QM36.js} +5 -5
- package/dist/{chunk-M4U24U6G.js.map → chunk-AZK3QM36.js.map} +1 -1
- package/dist/{chunk-QK2ERTO3.js → chunk-BH6M2DGV.js} +4 -4
- package/dist/{chunk-QK2ERTO3.js.map → chunk-BH6M2DGV.js.map} +1 -1
- package/dist/{chunk-26UQG242.cjs → chunk-BTGYRM4J.cjs} +264 -264
- package/dist/chunk-BTGYRM4J.cjs.map +1 -0
- package/dist/{chunk-ZQWRUJHE.js → chunk-CG64VPPU.js} +50 -50
- package/dist/{chunk-ZQWRUJHE.js.map → chunk-CG64VPPU.js.map} +1 -1
- package/dist/{chunk-CBBT42VX.js → chunk-CMDM4VF6.js} +3 -3
- package/dist/{chunk-CBBT42VX.js.map → chunk-CMDM4VF6.js.map} +1 -1
- package/dist/{chunk-OLJOI4LK.js → chunk-CN732Z5C.js} +4 -4
- package/dist/{chunk-OLJOI4LK.js.map → chunk-CN732Z5C.js.map} +1 -1
- package/dist/{chunk-SETHRLQS.cjs → chunk-D3BL3EEB.cjs} +9 -9
- package/dist/chunk-D3BL3EEB.cjs.map +1 -0
- package/dist/{chunk-LCCT5ZXJ.js → chunk-DB5RYCXX.js} +13 -13
- package/dist/{chunk-LCCT5ZXJ.js.map → chunk-DB5RYCXX.js.map} +1 -1
- package/dist/{chunk-SV63WTA2.js → chunk-DBH2WA2U.js} +4 -4
- package/dist/{chunk-SV63WTA2.js.map → chunk-DBH2WA2U.js.map} +1 -1
- package/dist/{chunk-XE3CAY6Z.cjs → chunk-DEHPRORL.cjs} +4 -4
- package/dist/{chunk-XE3CAY6Z.cjs.map → chunk-DEHPRORL.cjs.map} +1 -1
- package/dist/{chunk-UKMBRMGT.js → chunk-DGO4LPLP.js} +4 -4
- package/dist/{chunk-UKMBRMGT.js.map → chunk-DGO4LPLP.js.map} +1 -1
- package/dist/{chunk-RS7YQR4X.cjs → chunk-EBX6XUN7.cjs} +7 -7
- package/dist/{chunk-RS7YQR4X.cjs.map → chunk-EBX6XUN7.cjs.map} +1 -1
- package/dist/chunk-EDIYR4VR.cjs +18 -0
- package/dist/{chunk-SPEN7RJU.cjs.map → chunk-EDIYR4VR.cjs.map} +1 -1
- package/dist/{chunk-QGDPMM3C.js → chunk-EF5IONLL.js} +5 -5
- package/dist/{chunk-QGDPMM3C.js.map → chunk-EF5IONLL.js.map} +1 -1
- package/dist/{chunk-MSW7LB2V.cjs → chunk-EOWIUDKG.cjs} +5 -5
- package/dist/{chunk-MSW7LB2V.cjs.map → chunk-EOWIUDKG.cjs.map} +1 -1
- package/dist/{chunk-L7JPXZ2C.cjs → chunk-ER3BF23R.cjs} +19 -19
- package/dist/{chunk-L7JPXZ2C.cjs.map → chunk-ER3BF23R.cjs.map} +1 -1
- package/dist/{chunk-BNEUB52I.cjs → chunk-ERBKPA2N.cjs} +4 -4
- package/dist/{chunk-BNEUB52I.cjs.map → chunk-ERBKPA2N.cjs.map} +1 -1
- package/dist/{chunk-4QCJAJAG.js → chunk-F54PXZIA.js} +5 -5
- package/dist/{chunk-4QCJAJAG.js.map → chunk-F54PXZIA.js.map} +1 -1
- package/dist/{chunk-2XWAYCFM.cjs → chunk-FBT2SF2S.cjs} +12 -12
- package/dist/{chunk-2XWAYCFM.cjs.map → chunk-FBT2SF2S.cjs.map} +1 -1
- package/dist/{chunk-AUH2EVWY.cjs → chunk-FZSPVIFK.cjs} +16 -16
- package/dist/chunk-FZSPVIFK.cjs.map +1 -0
- package/dist/{chunk-CYWOJA6B.js → chunk-GA27FFT5.js} +3 -3
- package/dist/{chunk-CYWOJA6B.js.map → chunk-GA27FFT5.js.map} +1 -1
- package/dist/{chunk-HWMGR3HA.js → chunk-GEQLHBJM.js} +6 -6
- package/dist/{chunk-HWMGR3HA.js.map → chunk-GEQLHBJM.js.map} +1 -1
- package/dist/{chunk-IJ7M6GOG.cjs → chunk-GKERJ52A.cjs} +4 -4
- package/dist/{chunk-IJ7M6GOG.cjs.map → chunk-GKERJ52A.cjs.map} +1 -1
- package/dist/{chunk-NEH3BPFD.cjs → chunk-HI5TJWQE.cjs} +19 -19
- package/dist/{chunk-NEH3BPFD.cjs.map → chunk-HI5TJWQE.cjs.map} +1 -1
- package/dist/{chunk-ZOFRNNZD.cjs → chunk-IZV72OEI.cjs} +11 -11
- package/dist/chunk-IZV72OEI.cjs.map +1 -0
- package/dist/{chunk-KU5O7WPK.js → chunk-JD3EKKKB.js} +4 -4
- package/dist/{chunk-KU5O7WPK.js.map → chunk-JD3EKKKB.js.map} +1 -1
- package/dist/{chunk-DFBWYETS.js → chunk-JRP2W2DR.js} +3 -3
- package/dist/{chunk-DFBWYETS.js.map → chunk-JRP2W2DR.js.map} +1 -1
- package/dist/{chunk-26GI3OYA.js → chunk-JRQJMZKY.js} +13 -13
- package/dist/{chunk-26GI3OYA.js.map → chunk-JRQJMZKY.js.map} +1 -1
- package/dist/{chunk-YQ3XC6C2.cjs → chunk-JVH3NNJ3.cjs} +13 -13
- package/dist/chunk-JVH3NNJ3.cjs.map +1 -0
- package/dist/{chunk-VWYFGE27.cjs → chunk-KC2HKUPT.cjs} +56 -56
- package/dist/chunk-KC2HKUPT.cjs.map +1 -0
- package/dist/{chunk-PDOXYXWX.cjs → chunk-KDJTECE6.cjs} +4 -4
- package/dist/{chunk-PDOXYXWX.cjs.map → chunk-KDJTECE6.cjs.map} +1 -1
- package/dist/{chunk-QD6B6W6I.js → chunk-L2KC2G7H.js} +5 -5
- package/dist/{chunk-QD6B6W6I.js.map → chunk-L2KC2G7H.js.map} +1 -1
- package/dist/{chunk-3BBTHFGJ.js → chunk-L5B7EWWH.js} +5 -5
- package/dist/{chunk-3BBTHFGJ.js.map → chunk-L5B7EWWH.js.map} +1 -1
- package/dist/{chunk-X7CE7Y5W.js → chunk-LG4JCJEI.js} +11 -11
- package/dist/{chunk-X7CE7Y5W.js.map → chunk-LG4JCJEI.js.map} +1 -1
- package/dist/{chunk-2HXTNVLM.js → chunk-LSURFRJA.js} +6 -6
- package/dist/{chunk-2HXTNVLM.js.map → chunk-LSURFRJA.js.map} +1 -1
- package/dist/{chunk-55LLQFHW.cjs → chunk-MJGY3E3C.cjs} +4 -4
- package/dist/{chunk-55LLQFHW.cjs.map → chunk-MJGY3E3C.cjs.map} +1 -1
- package/dist/{chunk-EQ5IDL6W.cjs → chunk-MKS5FFH5.cjs} +15 -15
- package/dist/chunk-MKS5FFH5.cjs.map +1 -0
- package/dist/{chunk-WM646HEN.js → chunk-MTNCJ7MQ.js} +6 -6
- package/dist/{chunk-WM646HEN.js.map → chunk-MTNCJ7MQ.js.map} +1 -1
- package/dist/{chunk-SA6K24NB.cjs → chunk-MXJJMP4U.cjs} +7 -7
- package/dist/chunk-MXJJMP4U.cjs.map +1 -0
- package/dist/{chunk-FTXY4D44.cjs → chunk-N2ORTDSO.cjs} +20 -20
- package/dist/chunk-N2ORTDSO.cjs.map +1 -0
- package/dist/{chunk-7YUPSBDV.cjs → chunk-NDXZXGVP.cjs} +6 -6
- package/dist/{chunk-7YUPSBDV.cjs.map → chunk-NDXZXGVP.cjs.map} +1 -1
- package/dist/{chunk-3UMPP553.cjs → chunk-NMRNE6QX.cjs} +11 -11
- package/dist/{chunk-3UMPP553.cjs.map → chunk-NMRNE6QX.cjs.map} +1 -1
- package/dist/{chunk-PKRPV3R7.js → chunk-NO6AG22P.js} +6 -6
- package/dist/{chunk-PKRPV3R7.js.map → chunk-NO6AG22P.js.map} +1 -1
- package/dist/{chunk-NK5EOTDY.js → chunk-OIOSY5G6.js} +3 -3
- package/dist/{chunk-NK5EOTDY.js.map → chunk-OIOSY5G6.js.map} +1 -1
- package/dist/{chunk-RGVMJU57.js → chunk-P7B64NFK.js} +8 -8
- package/dist/{chunk-RGVMJU57.js.map → chunk-P7B64NFK.js.map} +1 -1
- package/dist/{chunk-TDED5XES.js → chunk-PCPYTBVV.js} +6 -6
- package/dist/chunk-PCPYTBVV.js.map +1 -0
- package/dist/{chunk-FBIDOOJM.cjs → chunk-PDFSLD5P.cjs} +6 -6
- package/dist/{chunk-FBIDOOJM.cjs.map → chunk-PDFSLD5P.cjs.map} +1 -1
- package/dist/{chunk-YMVTUV5K.js → chunk-PISZRLES.js} +5 -5
- package/dist/{chunk-YMVTUV5K.js.map → chunk-PISZRLES.js.map} +1 -1
- package/dist/{chunk-BUUUWQMB.cjs → chunk-PNL63WDP.cjs} +4 -4
- package/dist/{chunk-BUUUWQMB.cjs.map → chunk-PNL63WDP.cjs.map} +1 -1
- package/dist/{chunk-VNRNZ3WI.js → chunk-PSMWZYW6.js} +4 -4
- package/dist/{chunk-VNRNZ3WI.js.map → chunk-PSMWZYW6.js.map} +1 -1
- package/dist/{chunk-5645PMVU.cjs → chunk-PXYINWBC.cjs} +20 -20
- package/dist/chunk-PXYINWBC.cjs.map +1 -0
- package/dist/{chunk-RTDVSHJR.cjs → chunk-Q4UOCMAO.cjs} +5 -5
- package/dist/{chunk-RTDVSHJR.cjs.map → chunk-Q4UOCMAO.cjs.map} +1 -1
- package/dist/{chunk-5IRDK5BC.js → chunk-QH6MWGOA.js} +4 -4
- package/dist/{chunk-5IRDK5BC.js.map → chunk-QH6MWGOA.js.map} +1 -1
- package/dist/{chunk-3LMVJTNJ.js → chunk-QPUKIZOT.js} +3 -3
- package/dist/{chunk-3LMVJTNJ.js.map → chunk-QPUKIZOT.js.map} +1 -1
- package/dist/{chunk-SWALPLFQ.cjs → chunk-RTCO3USA.cjs} +16 -16
- package/dist/chunk-RTCO3USA.cjs.map +1 -0
- package/dist/{chunk-SAGRF4IB.js → chunk-S2CMEJ5F.js} +3 -3
- package/dist/{chunk-SAGRF4IB.js.map → chunk-S2CMEJ5F.js.map} +1 -1
- package/dist/{chunk-VZGE7NAI.js → chunk-S5ERB3CH.js} +3 -3
- package/dist/{chunk-VZGE7NAI.js.map → chunk-S5ERB3CH.js.map} +1 -1
- package/dist/{chunk-XJ3WU5CZ.js → chunk-S7IZEVXX.js} +6 -6
- package/dist/{chunk-XJ3WU5CZ.js.map → chunk-S7IZEVXX.js.map} +1 -1
- package/dist/{chunk-Q7UG242V.js → chunk-TIYQDJFK.js} +3 -3
- package/dist/{chunk-Q7UG242V.js.map → chunk-TIYQDJFK.js.map} +1 -1
- package/dist/{chunk-POBZXULR.cjs → chunk-TTNJOM5W.cjs} +16 -16
- package/dist/{chunk-POBZXULR.cjs.map → chunk-TTNJOM5W.cjs.map} +1 -1
- package/dist/{chunk-VCQ37TC5.js → chunk-TTXRNCXY.js} +3 -3
- package/dist/{chunk-VCQ37TC5.js.map → chunk-TTXRNCXY.js.map} +1 -1
- package/dist/{chunk-3HA7N2BB.cjs → chunk-TYKBAKAS.cjs} +5 -5
- package/dist/{chunk-3HA7N2BB.cjs.map → chunk-TYKBAKAS.cjs.map} +1 -1
- package/dist/{chunk-A77UMVMD.cjs → chunk-UMCCYXFZ.cjs} +8 -8
- package/dist/{chunk-A77UMVMD.cjs.map → chunk-UMCCYXFZ.cjs.map} +1 -1
- package/dist/{chunk-3GTN4HOO.js → chunk-UNP4NCMZ.js} +3 -3
- package/dist/{chunk-3GTN4HOO.js.map → chunk-UNP4NCMZ.js.map} +1 -1
- package/dist/{chunk-BPL5CVZ5.js → chunk-VFT63FJF.js} +3 -3
- package/dist/{chunk-BPL5CVZ5.js.map → chunk-VFT63FJF.js.map} +1 -1
- package/dist/{chunk-3KIUY67P.cjs → chunk-VHY6NVCJ.cjs} +30 -30
- package/dist/chunk-VHY6NVCJ.cjs.map +1 -0
- package/dist/{chunk-TRPRTZEH.cjs → chunk-VT3NWHFH.cjs} +6 -6
- package/dist/{chunk-TRPRTZEH.cjs.map → chunk-VT3NWHFH.cjs.map} +1 -1
- package/dist/{chunk-FJWQP6EE.js → chunk-WJ6OGKAO.js} +3 -3
- package/dist/{chunk-FJWQP6EE.js.map → chunk-WJ6OGKAO.js.map} +1 -1
- package/dist/{chunk-FLDHYF5C.cjs → chunk-X2XLSE2N.cjs} +9 -9
- package/dist/chunk-X2XLSE2N.cjs.map +1 -0
- package/dist/{chunk-UDAKAE4Z.cjs → chunk-X4ZYEZPD.cjs} +12 -12
- package/dist/chunk-X4ZYEZPD.cjs.map +1 -0
- package/dist/{chunk-QG4SXZ2A.cjs → chunk-XR6O6G3B.cjs} +27 -27
- package/dist/chunk-XR6O6G3B.cjs.map +1 -0
- package/dist/{chunk-BWYC7RZG.cjs → chunk-XTQWTVVI.cjs} +11 -11
- package/dist/chunk-XTQWTVVI.cjs.map +1 -0
- package/dist/{chunk-MLJDW2YK.js → chunk-YSGS57DA.js} +4 -4
- package/dist/{chunk-MLJDW2YK.js.map → chunk-YSGS57DA.js.map} +1 -1
- package/dist/{chunk-KCM3RMKR.js → chunk-YUQNHLKN.js} +8 -8
- package/dist/{chunk-KCM3RMKR.js.map → chunk-YUQNHLKN.js.map} +1 -1
- package/dist/{chunk-P7QYG4RZ.cjs → chunk-Z5MB2HAN.cjs} +8 -8
- package/dist/{chunk-P7QYG4RZ.cjs.map → chunk-Z5MB2HAN.cjs.map} +1 -1
- package/dist/{chunk-HJ2LV464.js → chunk-ZUWVO442.js} +4 -4
- package/dist/{chunk-HJ2LV464.js.map → chunk-ZUWVO442.js.map} +1 -1
- package/dist/{compact-session-CHBJOYWP.cjs → compact-session-5DWFHMW4.cjs} +21 -21
- package/dist/{compact-session-CHBJOYWP.cjs.map → compact-session-5DWFHMW4.cjs.map} +1 -1
- package/dist/{compact-session-F3J3FMEU.js → compact-session-AL65PEMX.js} +12 -12
- package/dist/{compact-session-F3J3FMEU.js.map → compact-session-AL65PEMX.js.map} +1 -1
- package/dist/context/index.cjs +11 -11
- package/dist/context/index.js +6 -6
- package/dist/context-4XSD2V3G.js +7 -0
- package/dist/{context-7EBZST3L.js.map → context-4XSD2V3G.js.map} +1 -1
- package/dist/context-ZX2VBGSX.cjs +24 -0
- package/dist/{context-4RSI3AXT.cjs.map → context-ZX2VBGSX.cjs.map} +1 -1
- package/dist/cron.cjs +40 -40
- package/dist/cron.js +39 -39
- package/dist/eval.cjs +51 -51
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +41 -41
- package/dist/{executor-THUXNAFR.js → executor-ZHIUSHRV.js} +7 -7
- package/dist/{executor-THUXNAFR.js.map → executor-ZHIUSHRV.js.map} +1 -1
- package/dist/{executor-5QL5AXIZ.cjs → executor-ZTLJZ5LK.cjs} +24 -24
- package/dist/{executor-5QL5AXIZ.cjs.map → executor-ZTLJZ5LK.cjs.map} +1 -1
- package/dist/filesystem/index.cjs +14 -14
- package/dist/filesystem/index.cjs.map +1 -1
- package/dist/filesystem/index.js +4 -4
- package/dist/{fork-agent-S2EPIML7.js → fork-agent-BHVTALT5.js} +3 -3
- package/dist/{fork-agent-S2EPIML7.js.map → fork-agent-BHVTALT5.js.map} +1 -1
- package/dist/{fork-agent-WAEQI2DL.cjs → fork-agent-DCOPPXM2.cjs} +4 -4
- package/dist/{fork-agent-WAEQI2DL.cjs.map → fork-agent-DCOPPXM2.cjs.map} +1 -1
- package/dist/fs-session-store-EZ32TFGB.js +11 -0
- package/dist/{fs-session-store-MYQEVUFL.js.map → fs-session-store-EZ32TFGB.js.map} +1 -1
- package/dist/fs-session-store-G664LDDN.cjs +20 -0
- package/dist/{fs-session-store-CYNTEPJZ.cjs.map → fs-session-store-G664LDDN.cjs.map} +1 -1
- package/dist/generate-object-JFZTK567.cjs +20 -0
- package/dist/{generate-object-A5F576IT.cjs.map → generate-object-JFZTK567.cjs.map} +1 -1
- package/dist/{generate-object-TBDOBBYW.js → generate-object-RPBXY2U3.js} +4 -4
- package/dist/{generate-object-TBDOBBYW.js.map → generate-object-RPBXY2U3.js.map} +1 -1
- package/dist/index-manager-2MJEEN2O.js +18 -0
- package/dist/{index-manager-NF2WRLOU.js.map → index-manager-2MJEEN2O.js.map} +1 -1
- package/dist/index-manager-CT6MMG7S.cjs +27 -0
- package/dist/{index-manager-2KH75BRW.cjs.map → index-manager-CT6MMG7S.cjs.map} +1 -1
- package/dist/index.cjs +130 -130
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +56 -56
- package/dist/{inject-session-LC2TROHM.js → inject-session-E2SZ4A35.js} +6 -6
- package/dist/{inject-session-LC2TROHM.js.map → inject-session-E2SZ4A35.js.map} +1 -1
- package/dist/{inject-session-T4RXANG3.cjs → inject-session-QZULG65O.cjs} +8 -8
- package/dist/{inject-session-T4RXANG3.cjs.map → inject-session-QZULG65O.cjs.map} +1 -1
- package/dist/internal/memory/adapters/index.cjs +4 -4
- package/dist/internal/memory/adapters/index.js +3 -3
- package/dist/internal/memory/storage/index.cjs +45 -45
- package/dist/internal/memory/storage/index.js +9 -9
- package/dist/internal/persistence/index.cjs +22 -22
- package/dist/internal/persistence/index.js +6 -6
- package/dist/internal/security/index.cjs +9 -9
- package/dist/internal/security/index.js +2 -2
- package/dist/mcp-auth.cjs +8 -8
- package/dist/mcp-auth.js +3 -3
- package/dist/models.cjs +30 -30
- package/dist/models.cjs.map +1 -1
- package/dist/models.js +8 -8
- package/dist/{oauth-transaction-store-U34YLEGP.js → oauth-transaction-store-QQBWGNE2.js} +3 -3
- package/dist/{oauth-transaction-store-U34YLEGP.js.map → oauth-transaction-store-QQBWGNE2.js.map} +1 -1
- package/dist/{oauth-transaction-store-OMX436YB.cjs → oauth-transaction-store-YF7WOA6B.cjs} +10 -10
- package/dist/{oauth-transaction-store-OMX436YB.cjs.map → oauth-transaction-store-YF7WOA6B.cjs.map} +1 -1
- package/dist/path-safety.cjs +9 -9
- package/dist/path-safety.js +2 -2
- package/dist/persistence.cjs +41 -41
- package/dist/persistence.cjs.map +1 -1
- package/dist/persistence.js +11 -11
- package/dist/project.cjs +7 -7
- package/dist/project.cjs.map +1 -1
- package/dist/project.js +4 -4
- package/dist/providers.cjs +6 -6
- package/dist/providers.js +4 -4
- package/dist/{registry-5TDAF7RK.js → registry-DOYBR237.js} +6 -6
- package/dist/{registry-5TDAF7RK.js.map → registry-DOYBR237.js.map} +1 -1
- package/dist/{registry-W7TSCLQO.cjs → registry-PB7JFVUJ.cjs} +14 -14
- package/dist/{registry-W7TSCLQO.cjs.map → registry-PB7JFVUJ.cjs.map} +1 -1
- package/dist/sandbox/index.cjs +41 -41
- package/dist/sandbox/index.cjs.map +1 -1
- package/dist/sandbox/index.js +7 -7
- package/dist/sanitize/index.cjs +2 -2
- package/dist/sanitize/index.js +1 -1
- package/dist/server/auth/index.cjs +9 -9
- package/dist/server/auth/index.cjs.map +1 -1
- package/dist/server/auth/index.js +4 -4
- package/dist/{session-transcript-7TZ6HXSX.cjs → session-transcript-EBVGLZ6B.cjs} +17 -17
- package/dist/{session-transcript-7TZ6HXSX.cjs.map → session-transcript-EBVGLZ6B.cjs.map} +1 -1
- package/dist/{session-transcript-BSHZYYY6.js → session-transcript-GU2VE7JX.js} +4 -4
- package/dist/{session-transcript-BSHZYYY6.js.map → session-transcript-GU2VE7JX.js.map} +1 -1
- package/dist/skills.cjs +7 -7
- package/dist/skills.js +4 -4
- package/dist/stream-object-3AU7QDHT.js +7 -0
- package/dist/{stream-object-EKM4WGTI.js.map → stream-object-3AU7QDHT.js.map} +1 -1
- package/dist/stream-object-SLGR2KIA.cjs +20 -0
- package/dist/{stream-object-AS4YYM4B.cjs.map → stream-object-SLGR2KIA.cjs.map} +1 -1
- package/dist/subagents-loader-4PQS7ULK.cjs +16 -0
- package/dist/{subagents-loader-KLWF4QPD.cjs.map → subagents-loader-4PQS7ULK.cjs.map} +1 -1
- package/dist/subagents-loader-CPFVLWLH.js +7 -0
- package/dist/{subagents-loader-SXETS2F2.js.map → subagents-loader-CPFVLWLH.js.map} +1 -1
- package/dist/subagents-loader.cjs +4 -4
- package/dist/subagents-loader.js +3 -3
- package/dist/subagents.cjs +2 -2
- package/dist/subagents.js +1 -1
- package/dist/task-store.cjs +5 -5
- package/dist/task-store.js +2 -2
- package/dist/workflow.cjs +28 -28
- package/dist/workflow.js +5 -5
- package/package.json +1 -1
- package/dist/agent-66U5QCPF.js +0 -63
- package/dist/agent-CB27KF6O.cjs +0 -72
- package/dist/agent-session-store-22GKA7O4.js +0 -6
- package/dist/agent-session-store-WP6NGDVX.cjs +0 -23
- package/dist/chunk-26UQG242.cjs.map +0 -1
- package/dist/chunk-3E3VSMB6.cjs.map +0 -1
- package/dist/chunk-3KIUY67P.cjs.map +0 -1
- package/dist/chunk-3WKWBYPO.cjs.map +0 -1
- package/dist/chunk-5645PMVU.cjs.map +0 -1
- package/dist/chunk-AT2PESXB.cjs.map +0 -1
- package/dist/chunk-AUH2EVWY.cjs.map +0 -1
- package/dist/chunk-BWYC7RZG.cjs.map +0 -1
- package/dist/chunk-CHKV2L2Y.cjs.map +0 -1
- package/dist/chunk-EQ5IDL6W.cjs.map +0 -1
- package/dist/chunk-FLDHYF5C.cjs.map +0 -1
- package/dist/chunk-FTXY4D44.cjs.map +0 -1
- package/dist/chunk-L7V4DDIE.cjs.map +0 -1
- package/dist/chunk-QG4SXZ2A.cjs.map +0 -1
- package/dist/chunk-SA6K24NB.cjs.map +0 -1
- package/dist/chunk-SETHRLQS.cjs.map +0 -1
- package/dist/chunk-SPEN7RJU.cjs +0 -18
- package/dist/chunk-SWALPLFQ.cjs.map +0 -1
- package/dist/chunk-TDED5XES.js.map +0 -1
- package/dist/chunk-UDAKAE4Z.cjs.map +0 -1
- package/dist/chunk-VWYFGE27.cjs.map +0 -1
- package/dist/chunk-XOU3CL7S.cjs.map +0 -1
- package/dist/chunk-YQ3XC6C2.cjs.map +0 -1
- package/dist/chunk-ZOFRNNZD.cjs.map +0 -1
- package/dist/context-4RSI3AXT.cjs +0 -24
- package/dist/context-7EBZST3L.js +0 -7
- package/dist/fs-session-store-CYNTEPJZ.cjs +0 -20
- package/dist/fs-session-store-MYQEVUFL.js +0 -11
- package/dist/generate-object-A5F576IT.cjs +0 -20
- package/dist/index-manager-2KH75BRW.cjs +0 -27
- package/dist/index-manager-NF2WRLOU.js +0 -18
- package/dist/stream-object-AS4YYM4B.cjs +0 -20
- package/dist/stream-object-EKM4WGTI.js +0 -7
- package/dist/subagents-loader-KLWF4QPD.cjs +0 -16
- package/dist/subagents-loader-SXETS2F2.js +0 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/llm/credential-pool-types.ts","../src/internal/llm/credential-pool.ts","../src/internal/llm/credential-pool-context.ts"],"names":["picked"],"mappings":"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","file":"chunk-NK5EOTDY.js","sourcesContent":["/**\n * Types for the credential pool subsystem (ADRs D123-D133).\n *\n * Pool a developer's multiple API keys for the SAME provider so the SDK\n * can rotate transparently on HTTP 429/402/401 instead of jumping\n * straight to a different provider via `FallbackLlmClient`.\n *\n * @internal\n */\n\n/**\n * Rotation strategy when picking the next credential from a pool.\n *\n * - `fill_first` (default): use entries[0] until exhausted, then [1]…\n * - `round_robin`: rotate after each `select()`\n * - `least_used`: pick the entry with the lowest `requestCount`\n * - `random`: random pick among healthy entries\n *\n * Closed enum per ADR D124 — adding a strategy is an explicit semver\n * minor that updates `selectByStrategy` exhaustively.\n *\n * @internal\n */\nexport type CredentialPoolStrategy = \"fill_first\" | \"round_robin\" | \"least_used\" | \"random\";\n\n/** Health flag tracked per credential. */\nexport type CredentialStatus = \"ok\" | \"exhausted\";\n\n/**\n * Provenance of a credential — where it came from when seeded.\n * Free-form string; conventional prefixes:\n *\n * - `env:<VAR_NAME>` — auto-discovered from environment variable\n * - `manual` — added via explicit `apiKeys` config\n * - `explicit-apikey` — wrapped from `AgentOptions.apiKey` single-key path (D132)\n */\nexport type CredentialSource = string;\n\n/**\n * Single credential entry inside a {@link CredentialPool}.\n *\n * `accessToken` is the sensitive field — must never be logged unredacted.\n * The lint gate `tests/lint/no-unredacted-pool-token.test.ts` enforces this.\n *\n * @internal\n */\nexport interface PooledCredential {\n /** Stable identifier (uuid v4) for log lines + telemetry. */\n id: string;\n /** Human-readable label for `Theokit.credentialPool.list()`. */\n label: string;\n /** Provider name (matches `ProviderProfile.name`). */\n provider: string;\n /** Sort key; lower = earlier in fill_first. Unique within a pool. */\n priority: number;\n /** Provenance string. */\n source: CredentialSource;\n /** Sensitive API key. NEVER LOG UNREDACTED. */\n accessToken: string;\n /** Current health. */\n lastStatus: CredentialStatus;\n /** Epoch ms of the last status change. */\n lastStatusAt: number | undefined;\n /** HTTP code that caused exhaustion (401/402/429). */\n lastErrorCode: number | undefined;\n /** Provider-supplied \"retry after this epoch ms\" hint. Overrides cooldown defaults. */\n lastErrorResetAt: number | undefined;\n /** Bumped per successful `select()` for `least_used` strategy. Lazy-persisted. */\n requestCount: number;\n}\n\n/**\n * Serializable snapshot of a single provider's pool. Used by the\n * persistence layer (T2.1) to read/write `~/.theokit/credential-pool.json`.\n *\n * @internal\n */\nexport interface CredentialPoolSnapshot {\n provider: string;\n strategy: CredentialPoolStrategy;\n entries: PooledCredential[];\n}\n\n/**\n * Cooldown ladder by HTTP error code (ADR D125). Provider-supplied\n * `lastErrorResetAt` overrides these defaults when present.\n *\n * @internal\n */\nexport const COOLDOWN_MS: Readonly<Record<number, number>> = {\n 401: 5 * 60 * 1000, // 5 minutes — OAuth refresh can recover quickly\n 402: 60 * 60 * 1000, // 1 hour — billing quota typically hourly+\n 429: 60 * 60 * 1000, // 1 hour — daily-rate-limit windows\n};\n\n/** Default cooldown when no specific code matches. */\nexport const DEFAULT_COOLDOWN_MS = 60 * 60 * 1000;\n","/**\n * In-memory credential pool with strategy-based rotation (ADRs D123-D133).\n *\n * Pure logic. No I/O — persistence lives in `internal/persistence/\n * credential-pool-store.ts`. The pool is the single source of truth for\n * rotation state within a process; if it diverges from disk (e.g.,\n * process killed mid-rotation per EC-I), the next save heals the\n * inconsistency — at the cost of one extra HTTP 429 per crash.\n *\n * Thread safety: the pool uses an in-process async-aware mutex\n * (`cwd-mutex` D9 keyed by `credential-pool:${provider}`). Cross-process\n * safety happens at the persistence layer via `withFileLock` (D61).\n * Two Node processes sharing the same file may double-pick momentarily\n * (worst case = 1 extra 429 per race) — acceptable per ADR D128.\n *\n * @internal\n */\n\nimport { ConfigurationError } from \"../../errors.js\";\nimport { withCwdMutex } from \"../persistence/cwd-mutex.js\";\nimport {\n COOLDOWN_MS,\n type CredentialPoolSnapshot,\n type CredentialPoolStrategy,\n DEFAULT_COOLDOWN_MS,\n type PooledCredential,\n} from \"./credential-pool-types.js\";\nimport { sleepWithAbort } from \"./retry.js\";\n\n/**\n * Construct a `PooledCredential` with sane defaults.\n *\n * @internal\n */\nexport function newPooledCredential(args: {\n provider: string;\n accessToken: string;\n priority: number;\n source: string;\n label?: string;\n}): PooledCredential {\n return {\n id: globalThis.crypto.randomUUID(),\n label: args.label ?? labelFromSource(args.source, args.accessToken),\n provider: args.provider,\n priority: args.priority,\n source: args.source,\n accessToken: args.accessToken,\n lastStatus: \"ok\",\n lastStatusAt: undefined,\n lastErrorCode: undefined,\n lastErrorResetAt: undefined,\n requestCount: 0,\n };\n}\n\n/**\n * Build a human-readable label from the credential source. Used for\n * `Theokit.credentialPool.list()` UX. NEVER includes the raw token.\n *\n * @internal\n */\nfunction labelFromSource(source: string, accessToken: string): string {\n if (source.startsWith(\"env:\")) return source.slice(4);\n const masked =\n accessToken.length > 8 ? `${accessToken.slice(0, 4)}…${accessToken.slice(-4)}` : \"***\";\n return `${source}:${masked}`;\n}\n\n/**\n * Per-provider credential pool. Construct with one or more entries\n * sorted by priority. Throws `ConfigurationError` on empty input.\n *\n * EC-C: identical `accessToken`s are deduplicated during construction\n * (3 copies of \"k1\" → 1 entry). Otherwise an exhaustion event would\n * mark \"k1\" exhausted 3× wastefully.\n *\n * @internal\n */\nexport class CredentialPool {\n readonly provider: string;\n private readonly strategy: CredentialPoolStrategy;\n private entries: PooledCredential[];\n\n constructor(\n provider: string,\n entries: PooledCredential[],\n strategy: CredentialPoolStrategy = \"fill_first\",\n ) {\n if (entries.length === 0) {\n throw new ConfigurationError(\n `credential-pool: cannot construct empty pool for provider \"${provider}\"`,\n { code: \"credential_pool_empty\" },\n );\n }\n this.provider = provider;\n this.strategy = strategy;\n // EC-C: dedupe by accessToken before sort.\n this.entries = dedupeByToken(entries).sort((a, b) => a.priority - b.priority);\n }\n\n /** True if the pool was seeded with at least one entry. */\n hasCredentials(): boolean {\n return this.entries.length > 0;\n }\n\n /** True iff at least one entry is healthy (auto-healed if cooldown expired). */\n hasAvailable(): boolean {\n return this.availableEntries().length > 0;\n }\n\n /**\n * Earliest `lastErrorResetAt` across all entries, or `undefined` if no\n * entry is in cooldown. Used by `waitForAvailable` to compute the\n * upper bound of each jittered sleep window.\n *\n * @internal\n */\n earliestResetAt(): number | undefined {\n let earliest: number | undefined;\n for (const entry of this.entries) {\n if (entry.lastStatus === \"ok\") continue;\n if (entry.lastErrorResetAt === undefined) continue;\n if (earliest === undefined || entry.lastErrorResetAt < earliest) {\n earliest = entry.lastErrorResetAt;\n }\n }\n return earliest;\n }\n\n /**\n * Wait until at least one entry becomes healthy OR `maxWaitMs` elapses\n * OR `signal` aborts. Returns `true` if a healthy entry is available\n * when the call returns, `false` otherwise.\n *\n * T3.9 — Reconnect storm prevention. Concurrent callers each sleep a\n * random fraction of the window to the earliest cooldown reset (full\n * jitter — AWS Brooker 2015) so they do not all wake at the exact\n * instant cooldown expires and hammer the upstream simultaneously.\n *\n * The `sleeper` parameter is a dependency-injection seam for tests:\n * callers in production omit it and the default `setTimeout`-based\n * sleeper is used. The seam avoids the `vi.useFakeTimers()` mismatch\n * that blocked T3.4's wiring.\n *\n * @internal\n */\n async waitForAvailable(\n signal: AbortSignal,\n opts: {\n maxWaitMs: number;\n sleeper?: (ms: number, signal: AbortSignal) => Promise<void>;\n /**\n * Clock seam, the companion to `sleeper`. Production omits it and gets `Date.now`.\n *\n * `sleeper` alone was not enough to make this loop testable: a test could replace the SLEEP\n * but the deadline check still read real wall-clock, so the one case that exercises timeout\n * had to set `maxWaitMs: 5` and race the scheduler — with a comment in the committed file\n * saying so (\"we can't easily ... spec is wall-clock based\"). A sleeper that also advances a\n * virtual clock closes the loop deterministically, which is what `rules/testing.md` § 6 asks\n * for when it says to inject the clock rather than sleep.\n */\n now?: () => number;\n },\n ): Promise<boolean> {\n if (signal.aborted) return false;\n if (this.hasAvailable()) return true;\n const now = opts.now ?? Date.now;\n return await this.pollUntilAvailable(\n signal,\n now() + opts.maxWaitMs,\n opts.sleeper ?? sleepWithAbort,\n now,\n );\n }\n\n /**\n * The polling half of `waitForAvailable`, with both seams already resolved.\n *\n * Its own method because resolving two optional seams and running the loop in one body put the\n * function over the cognitive-complexity gate. The split is also the honest one: everything above\n * is a guard, everything here is the wait.\n */\n private async pollUntilAvailable(\n signal: AbortSignal,\n deadline: number,\n sleeper: (ms: number, signal: AbortSignal) => Promise<void>,\n now: () => number,\n ): Promise<boolean> {\n while (now() < deadline) {\n if (signal.aborted) return false;\n await sleeper(this.computeJitteredSleepMs(deadline, now), signal);\n if (signal.aborted) return false;\n if (this.hasAvailable()) return true;\n }\n return this.hasAvailable();\n }\n\n /**\n * Compute the next jittered sleep window (ms) for `waitForAvailable`.\n * Full-jitter cap: at most (a) time until the earliest reset (plus a\n * 50 ms grace so the entry actually heals before re-probe), or (b) the\n * remaining wait window, whichever is smaller. When no entry has a\n * known reset (rare — only if `markExhaustedAndRotate` was called\n * without `resetAtMs`), fall back to a 250 ms ceiling so we stay\n * responsive without hot-looping.\n */\n private computeJitteredSleepMs(deadline: number, now: () => number = Date.now): number {\n const resetAt = this.earliestResetAt();\n const remaining = deadline - now();\n const ceiling =\n resetAt === undefined\n ? Math.min(remaining, 250)\n : Math.min(remaining, Math.max(0, resetAt - now()) + 50);\n return Math.max(0, Math.floor(Math.random() * ceiling));\n }\n\n /** Live (frozen) view of all entries. */\n list(): readonly PooledCredential[] {\n return this.entries;\n }\n\n /**\n * Pick a healthy entry according to the configured strategy.\n * Mutates `requestCount` and (for round_robin) entry order.\n * Returns null if every entry is in cooldown.\n *\n * @internal\n */\n async select(): Promise<PooledCredential | null> {\n return withCwdMutex(`credential-pool:${this.provider}`, async () => this.selectLocked());\n }\n\n /**\n * Mark the entry whose id matches `entryId` as exhausted with the\n * appropriate cooldown, then return the next healthy entry (or null).\n * If `entryId` is undefined, marks all currently-active entries (rare —\n * only used by admin reset scenarios).\n *\n * @internal\n */\n async markExhaustedAndRotate(args: {\n entryId: string;\n statusCode: number;\n resetAtMs?: number;\n }): Promise<PooledCredential | null> {\n return withCwdMutex(`credential-pool:${this.provider}`, async () => {\n const entry = this.entries.find((e) => e.id === args.entryId);\n if (entry !== undefined) {\n const now = Date.now();\n const cooldown = COOLDOWN_MS[args.statusCode] ?? DEFAULT_COOLDOWN_MS;\n entry.lastStatus = \"exhausted\";\n entry.lastStatusAt = now;\n entry.lastErrorCode = args.statusCode;\n // EC-5: negative or stale resetAt → ignore, fall through to default.\n entry.lastErrorResetAt =\n args.resetAtMs !== undefined && args.resetAtMs > now ? args.resetAtMs : now + cooldown;\n }\n return this.selectLocked();\n });\n }\n\n /** Admin escape hatch: clear all cooldowns. */\n async resetAll(): Promise<void> {\n await withCwdMutex(`credential-pool:${this.provider}`, async () => {\n for (const e of this.entries) {\n e.lastStatus = \"ok\";\n e.lastStatusAt = undefined;\n e.lastErrorCode = undefined;\n e.lastErrorResetAt = undefined;\n }\n });\n }\n\n /** Materialize for persistence. */\n toSnapshot(): CredentialPoolSnapshot {\n return {\n provider: this.provider,\n strategy: this.strategy,\n entries: this.entries.map((e) => ({ ...e })),\n };\n }\n\n /** Hydrate from a previously-saved snapshot. */\n static fromSnapshot(snapshot: CredentialPoolSnapshot): CredentialPool {\n return new CredentialPool(snapshot.provider, snapshot.entries, snapshot.strategy);\n }\n\n // ─── Internal helpers (always called inside the mutex) ───\n\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: strategy dispatch must branch on 4 enum values (random/least_used/round_robin/fill_first) with 1-entry short-circuits per strategy. Each branch is 5-10 lines of focused logic; extracting per-strategy methods fragments the linear narrative.\n private selectLocked(): PooledCredential | null {\n const available = this.availableEntries();\n if (available.length === 0) return null;\n\n if (this.strategy === \"random\") {\n const idx = Math.floor(Math.random() * available.length);\n const picked = available[idx];\n if (picked === undefined) return null; // unreachable; satisfies strict\n picked.requestCount += 1;\n return picked;\n }\n\n if (this.strategy === \"least_used\" && available.length > 1) {\n // EC-3: tie-break by priority ascending (first wins).\n const picked = [...available].sort(\n (a, b) => a.requestCount - b.requestCount || a.priority - b.priority,\n )[0];\n if (picked === undefined) return null;\n picked.requestCount += 1;\n return picked;\n }\n\n if (this.strategy === \"round_robin\" && available.length > 1) {\n // Pick head; move it to the end of `entries` so next call picks the next.\n const picked = available[0];\n if (picked === undefined) return null;\n picked.requestCount += 1;\n const rest = this.entries.filter((e) => e.id !== picked.id);\n // Re-assign priorities: rotated entry gets the highest priority value\n // so it sorts last after `fromSnapshot` rehydration. This makes EC-F\n // (round-robin state survives save/load) work without a separate field.\n const maxPriority = this.entries.length - 1;\n rest.forEach((e, i) => {\n e.priority = i;\n });\n picked.priority = maxPriority;\n this.entries = [...rest, picked];\n return picked;\n }\n\n // fill_first (default) and 1-entry edge case for round_robin/least_used\n const picked = available[0];\n if (picked === undefined) return null;\n picked.requestCount += 1;\n return picked;\n }\n\n private availableEntries(): PooledCredential[] {\n const now = Date.now();\n const out: PooledCredential[] = [];\n for (const entry of this.entries) {\n if (entry.lastStatus === \"ok\") {\n out.push(entry);\n continue;\n }\n // EC-1: auto-heal expired cooldowns inline.\n const resetAt = entry.lastErrorResetAt;\n if (resetAt !== undefined && now >= resetAt) {\n entry.lastStatus = \"ok\";\n entry.lastStatusAt = undefined;\n entry.lastErrorCode = undefined;\n entry.lastErrorResetAt = undefined;\n out.push(entry);\n }\n }\n return out;\n }\n}\n\n/**\n * Drop duplicates by `accessToken`. Keeps the first occurrence (lowest\n * priority wins after sort). EC-C from the edge-case review.\n */\nfunction dedupeByToken(entries: PooledCredential[]): PooledCredential[] {\n const seen = new Set<string>();\n const out: PooledCredential[] = [];\n for (const e of entries) {\n if (seen.has(e.accessToken)) continue;\n seen.add(e.accessToken);\n out.push(e);\n }\n return out;\n}\n","/**\n * Per-fork credential-pool inheritance via `AsyncLocalStorage` (ADR D131).\n *\n * Mirrors the whitelist context pattern from D111\n * (`runtime/async-local-storage.ts`). Forked sub-agents inherit the\n * parent's pool *by reference* so concurrent rotations all observe\n * the same cooldown state — the desired behavior per Hermes parity.\n *\n * @internal\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nimport type { CredentialPool } from \"./credential-pool.js\";\n\n/** ALS slot — keyed by provider name → pool. */\nconst credentialPoolStore = new AsyncLocalStorage<Map<string, CredentialPool>>();\n\n/**\n * Run `fn` with `pools` as the active credential-pool registry for the\n * current async context. Nested calls shadow the outer map (parent\n * pools are not visible to children when the child sets its own).\n *\n * @internal\n */\nexport async function withCredentialPool<T>(\n pools: Map<string, CredentialPool>,\n fn: () => Promise<T>,\n): Promise<T> {\n return credentialPoolStore.run(pools, fn);\n}\n\n/**\n * Pool registered for `provider` in the current async context, or\n * `undefined` when no `withCredentialPool(...)` scope is active.\n *\n * @internal\n */\nexport function currentCredentialPool(provider: string): CredentialPool | undefined {\n return credentialPoolStore.getStore()?.get(provider);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/internal/llm/credential-pool-types.ts","../src/internal/llm/credential-pool.ts","../src/internal/llm/credential-pool-context.ts"],"names":["picked"],"mappings":";;;;;;AAyFO,IAAM,WAAA,GAAgD;AAAA,EAC3D,GAAA,EAAK,IAAI,EAAA,GAAK,GAAA;AAAA;AAAA,EACd,GAAA,EAAK,KAAK,EAAA,GAAK,GAAA;AAAA;AAAA,EACf,GAAA,EAAK,KAAK,EAAA,GAAK;AAAA;AACjB,CAAA;AAGO,IAAM,mBAAA,GAAsB,KAAK,EAAA,GAAK,GAAA;;;AC9DtC,SAAS,oBAAoB,IAAA,EAMf;AACnB,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,UAAA,CAAW,MAAA,CAAO,UAAA,EAAW;AAAA,IACjC,OAAO,IAAA,CAAK,KAAA,IAAS,gBAAgB,IAAA,CAAK,MAAA,EAAQ,KAAK,WAAW,CAAA;AAAA,IAClE,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,QAAQ,IAAA,CAAK,MAAA;AAAA,IACb,aAAa,IAAA,CAAK,WAAA;AAAA,IAClB,UAAA,EAAY,IAAA;AAAA,IACZ,YAAA,EAAc,MAAA;AAAA,IACd,aAAA,EAAe,MAAA;AAAA,IACf,gBAAA,EAAkB,MAAA;AAAA,IAClB,YAAA,EAAc;AAAA,GAChB;AACF;AAQA,SAAS,eAAA,CAAgB,QAAgB,WAAA,EAA6B;AACpE,EAAA,IAAI,OAAO,UAAA,CAAW,MAAM,GAAG,OAAO,MAAA,CAAO,MAAM,CAAC,CAAA;AACpD,EAAA,MAAM,MAAA,GACJ,WAAA,CAAY,MAAA,GAAS,CAAA,GAAI,GAAG,WAAA,CAAY,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,MAAA,EAAI,WAAA,CAAY,KAAA,CAAM,EAAE,CAAC,CAAA,CAAA,GAAK,KAAA;AACnF,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA;AAC5B;AAYO,IAAM,cAAA,GAAN,MAAM,eAAA,CAAe;AAAA,EACjB,QAAA;AAAA,EACQ,QAAA;AAAA,EACT,OAAA;AAAA,EAER,WAAA,CACE,QAAA,EACA,OAAA,EACA,QAAA,GAAmC,YAAA,EACnC;AACA,IAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,MAAA,MAAM,IAAI,kBAAA;AAAA,QACR,8DAA8D,QAAQ,CAAA,CAAA,CAAA;AAAA,QACtE,EAAE,MAAM,uBAAA;AAAwB,OAClC;AAAA,IACF;AACA,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAEhB,IAAA,IAAA,CAAK,OAAA,GAAU,aAAA,CAAc,OAAO,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,QAAA,GAAW,CAAA,CAAE,QAAQ,CAAA;AAAA,EAC9E;AAAA;AAAA,EAGA,cAAA,GAA0B;AACxB,IAAA,OAAO,IAAA,CAAK,QAAQ,MAAA,GAAS,CAAA;AAAA,EAC/B;AAAA;AAAA,EAGA,YAAA,GAAwB;AACtB,IAAA,OAAO,IAAA,CAAK,gBAAA,EAAiB,CAAE,MAAA,GAAS,CAAA;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,eAAA,GAAsC;AACpC,IAAA,IAAI,QAAA;AACJ,IAAA,KAAA,MAAW,KAAA,IAAS,KAAK,OAAA,EAAS;AAChC,MAAA,IAAI,KAAA,CAAM,eAAe,IAAA,EAAM;AAC/B,MAAA,IAAI,KAAA,CAAM,qBAAqB,MAAA,EAAW;AAC1C,MAAA,IAAI,QAAA,KAAa,MAAA,IAAa,KAAA,CAAM,gBAAA,GAAmB,QAAA,EAAU;AAC/D,QAAA,QAAA,GAAW,KAAA,CAAM,gBAAA;AAAA,MACnB;AAAA,IACF;AACA,IAAA,OAAO,QAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,MAAM,gBAAA,CACJ,MAAA,EACA,IAAA,EAekB;AAClB,IAAA,IAAI,MAAA,CAAO,SAAS,OAAO,KAAA;AAC3B,IAAA,IAAI,IAAA,CAAK,YAAA,EAAa,EAAG,OAAO,IAAA;AAChC,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,IAAO,IAAA,CAAK,GAAA;AAC7B,IAAA,OAAO,MAAM,IAAA,CAAK,kBAAA;AAAA,MAChB,MAAA;AAAA,MACA,GAAA,KAAQ,IAAA,CAAK,SAAA;AAAA,MACb,KAAK,OAAA,IAAW,cAAA;AAAA,MAChB;AAAA,KACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,kBAAA,CACZ,MAAA,EACA,QAAA,EACA,SACA,GAAA,EACkB;AAClB,IAAA,OAAO,GAAA,KAAQ,QAAA,EAAU;AACvB,MAAA,IAAI,MAAA,CAAO,SAAS,OAAO,KAAA;AAC3B,MAAA,MAAM,QAAQ,IAAA,CAAK,sBAAA,CAAuB,QAAA,EAAU,GAAG,GAAG,MAAM,CAAA;AAChE,MAAA,IAAI,MAAA,CAAO,SAAS,OAAO,KAAA;AAC3B,MAAA,IAAI,IAAA,CAAK,YAAA,EAAa,EAAG,OAAO,IAAA;AAAA,IAClC;AACA,IAAA,OAAO,KAAK,YAAA,EAAa;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,sBAAA,CAAuB,QAAA,EAAkB,GAAA,GAAoB,IAAA,CAAK,GAAA,EAAa;AACrF,IAAA,MAAM,OAAA,GAAU,KAAK,eAAA,EAAgB;AACrC,IAAA,MAAM,SAAA,GAAY,WAAW,GAAA,EAAI;AACjC,IAAA,MAAM,UACJ,OAAA,KAAY,MAAA,GACR,KAAK,GAAA,CAAI,SAAA,EAAW,GAAG,CAAA,GACvB,IAAA,CAAK,GAAA,CAAI,SAAA,EAAW,KAAK,GAAA,CAAI,CAAA,EAAG,UAAU,GAAA,EAAK,IAAI,EAAE,CAAA;AAC3D,IAAA,OAAO,IAAA,CAAK,IAAI,CAAA,EAAG,IAAA,CAAK,MAAM,IAAA,CAAK,MAAA,EAAO,GAAI,OAAO,CAAC,CAAA;AAAA,EACxD;AAAA;AAAA,EAGA,IAAA,GAAoC;AAClC,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,MAAA,GAA2C;AAC/C,IAAA,OAAO,YAAA,CAAa,mBAAmB,IAAA,CAAK,QAAQ,IAAI,YAAY,IAAA,CAAK,cAAc,CAAA;AAAA,EACzF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,uBAAuB,IAAA,EAIQ;AACnC,IAAA,OAAO,YAAA,CAAa,CAAA,gBAAA,EAAmB,IAAA,CAAK,QAAQ,IAAI,YAAY;AAClE,MAAA,MAAM,KAAA,GAAQ,KAAK,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,IAAA,CAAK,OAAO,CAAA;AAC5D,MAAA,IAAI,UAAU,MAAA,EAAW;AACvB,QAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,QAAA,MAAM,QAAA,GAAW,WAAA,CAAY,IAAA,CAAK,UAAU,CAAA,IAAK,mBAAA;AACjD,QAAA,KAAA,CAAM,UAAA,GAAa,WAAA;AACnB,QAAA,KAAA,CAAM,YAAA,GAAe,GAAA;AACrB,QAAA,KAAA,CAAM,gBAAgB,IAAA,CAAK,UAAA;AAE3B,QAAA,KAAA,CAAM,gBAAA,GACJ,KAAK,SAAA,KAAc,MAAA,IAAa,KAAK,SAAA,GAAY,GAAA,GAAM,IAAA,CAAK,SAAA,GAAY,GAAA,GAAM,QAAA;AAAA,MAClF;AACA,MAAA,OAAO,KAAK,YAAA,EAAa;AAAA,IAC3B,CAAC,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,QAAA,GAA0B;AAC9B,IAAA,MAAM,YAAA,CAAa,CAAA,gBAAA,EAAmB,IAAA,CAAK,QAAQ,IAAI,YAAY;AACjE,MAAA,KAAA,MAAW,CAAA,IAAK,KAAK,OAAA,EAAS;AAC5B,QAAA,CAAA,CAAE,UAAA,GAAa,IAAA;AACf,QAAA,CAAA,CAAE,YAAA,GAAe,MAAA;AACjB,QAAA,CAAA,CAAE,aAAA,GAAgB,MAAA;AAClB,QAAA,CAAA,CAAE,gBAAA,GAAmB,MAAA;AAAA,MACvB;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,UAAA,GAAqC;AACnC,IAAA,OAAO;AAAA,MACL,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,OAAA,EAAS,KAAK,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,CAAA,EAAE,CAAE;AAAA,KAC7C;AAAA,EACF;AAAA;AAAA,EAGA,OAAO,aAAa,QAAA,EAAkD;AACpE,IAAA,OAAO,IAAI,eAAA,CAAe,QAAA,CAAS,UAAU,QAAA,CAAS,OAAA,EAAS,SAAS,QAAQ,CAAA;AAAA,EAClF;AAAA;AAAA;AAAA,EAKQ,YAAA,GAAwC;AAC9C,IAAA,MAAM,SAAA,GAAY,KAAK,gBAAA,EAAiB;AACxC,IAAA,IAAI,SAAA,CAAU,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAEnC,IAAA,IAAI,IAAA,CAAK,aAAa,QAAA,EAAU;AAC9B,MAAA,MAAM,MAAM,IAAA,CAAK,KAAA,CAAM,KAAK,MAAA,EAAO,GAAI,UAAU,MAAM,CAAA;AACvD,MAAA,MAAMA,OAAAA,GAAS,UAAU,GAAG,CAAA;AAC5B,MAAA,IAAIA,OAAAA,KAAW,QAAW,OAAO,IAAA;AACjC,MAAAA,QAAO,YAAA,IAAgB,CAAA;AACvB,MAAA,OAAOA,OAAAA;AAAA,IACT;AAEA,IAAA,IAAI,IAAA,CAAK,QAAA,KAAa,YAAA,IAAgB,SAAA,CAAU,SAAS,CAAA,EAAG;AAE1D,MAAA,MAAMA,OAAAA,GAAS,CAAC,GAAG,SAAS,CAAA,CAAE,IAAA;AAAA,QAC5B,CAAC,GAAG,CAAA,KAAM,CAAA,CAAE,eAAe,CAAA,CAAE,YAAA,IAAgB,CAAA,CAAE,QAAA,GAAW,CAAA,CAAE;AAAA,QAC5D,CAAC,CAAA;AACH,MAAA,IAAIA,OAAAA,KAAW,QAAW,OAAO,IAAA;AACjC,MAAAA,QAAO,YAAA,IAAgB,CAAA;AACvB,MAAA,OAAOA,OAAAA;AAAA,IACT;AAEA,IAAA,IAAI,IAAA,CAAK,QAAA,KAAa,aAAA,IAAiB,SAAA,CAAU,SAAS,CAAA,EAAG;AAE3D,MAAA,MAAMA,OAAAA,GAAS,UAAU,CAAC,CAAA;AAC1B,MAAA,IAAIA,OAAAA,KAAW,QAAW,OAAO,IAAA;AACjC,MAAAA,QAAO,YAAA,IAAgB,CAAA;AACvB,MAAA,MAAM,IAAA,GAAO,KAAK,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAOA,OAAAA,CAAO,EAAE,CAAA;AAI1D,MAAA,MAAM,WAAA,GAAc,IAAA,CAAK,OAAA,CAAQ,MAAA,GAAS,CAAA;AAC1C,MAAA,IAAA,CAAK,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAA,KAAM;AACrB,QAAA,CAAA,CAAE,QAAA,GAAW,CAAA;AAAA,MACf,CAAC,CAAA;AACD,MAAAA,QAAO,QAAA,GAAW,WAAA;AAClB,MAAA,IAAA,CAAK,OAAA,GAAU,CAAC,GAAG,IAAA,EAAMA,OAAM,CAAA;AAC/B,MAAA,OAAOA,OAAAA;AAAA,IACT;AAGA,IAAA,MAAM,MAAA,GAAS,UAAU,CAAC,CAAA;AAC1B,IAAA,IAAI,MAAA,KAAW,QAAW,OAAO,IAAA;AACjC,IAAA,MAAA,CAAO,YAAA,IAAgB,CAAA;AACvB,IAAA,OAAO,MAAA;AAAA,EACT;AAAA,EAEQ,gBAAA,GAAuC;AAC7C,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,MAAM,MAA0B,EAAC;AACjC,IAAA,KAAA,MAAW,KAAA,IAAS,KAAK,OAAA,EAAS;AAChC,MAAA,IAAI,KAAA,CAAM,eAAe,IAAA,EAAM;AAC7B,QAAA,GAAA,CAAI,KAAK,KAAK,CAAA;AACd,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,UAAU,KAAA,CAAM,gBAAA;AACtB,MAAA,IAAI,OAAA,KAAY,MAAA,IAAa,GAAA,IAAO,OAAA,EAAS;AAC3C,QAAA,KAAA,CAAM,UAAA,GAAa,IAAA;AACnB,QAAA,KAAA,CAAM,YAAA,GAAe,MAAA;AACrB,QAAA,KAAA,CAAM,aAAA,GAAgB,MAAA;AACtB,QAAA,KAAA,CAAM,gBAAA,GAAmB,MAAA;AACzB,QAAA,GAAA,CAAI,KAAK,KAAK,CAAA;AAAA,MAChB;AAAA,IACF;AACA,IAAA,OAAO,GAAA;AAAA,EACT;AACF;AAMA,SAAS,cAAc,OAAA,EAAiD;AACtE,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,EAAA,MAAM,MAA0B,EAAC;AACjC,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,WAAW,CAAA,EAAG;AAC7B,IAAA,IAAA,CAAK,GAAA,CAAI,EAAE,WAAW,CAAA;AACtB,IAAA,GAAA,CAAI,KAAK,CAAC,CAAA;AAAA,EACZ;AACA,EAAA,OAAO,GAAA;AACT;ACrWA,IAAM,mBAAA,GAAsB,IAAI,iBAAA,EAA+C;AAS/E,eAAsB,kBAAA,CACpB,OACA,EAAA,EACY;AACZ,EAAA,OAAO,mBAAA,CAAoB,GAAA,CAAI,KAAA,EAAO,EAAE,CAAA;AAC1C;AAQO,SAAS,sBAAsB,QAAA,EAA8C;AAClF,EAAA,OAAO,mBAAA,CAAoB,QAAA,EAAS,EAAG,GAAA,CAAI,QAAQ,CAAA;AACrD","file":"chunk-OIOSY5G6.js","sourcesContent":["/**\n * Types for the credential pool subsystem (ADRs D123-D133).\n *\n * Pool a developer's multiple API keys for the SAME provider so the SDK\n * can rotate transparently on HTTP 429/402/401 instead of jumping\n * straight to a different provider via `FallbackLlmClient`.\n *\n * @internal\n */\n\n/**\n * Rotation strategy when picking the next credential from a pool.\n *\n * - `fill_first` (default): use entries[0] until exhausted, then [1]…\n * - `round_robin`: rotate after each `select()`\n * - `least_used`: pick the entry with the lowest `requestCount`\n * - `random`: random pick among healthy entries\n *\n * Closed enum per ADR D124 — adding a strategy is an explicit semver\n * minor that updates `selectByStrategy` exhaustively.\n *\n * @internal\n */\nexport type CredentialPoolStrategy = \"fill_first\" | \"round_robin\" | \"least_used\" | \"random\";\n\n/** Health flag tracked per credential. */\nexport type CredentialStatus = \"ok\" | \"exhausted\";\n\n/**\n * Provenance of a credential — where it came from when seeded.\n * Free-form string; conventional prefixes:\n *\n * - `env:<VAR_NAME>` — auto-discovered from environment variable\n * - `manual` — added via explicit `apiKeys` config\n * - `explicit-apikey` — wrapped from `AgentOptions.apiKey` single-key path (D132)\n */\nexport type CredentialSource = string;\n\n/**\n * Single credential entry inside a {@link CredentialPool}.\n *\n * `accessToken` is the sensitive field — must never be logged unredacted.\n * The lint gate `tests/lint/no-unredacted-pool-token.test.ts` enforces this.\n *\n * @internal\n */\nexport interface PooledCredential {\n /** Stable identifier (uuid v4) for log lines + telemetry. */\n id: string;\n /** Human-readable label for `Theokit.credentialPool.list()`. */\n label: string;\n /** Provider name (matches `ProviderProfile.name`). */\n provider: string;\n /** Sort key; lower = earlier in fill_first. Unique within a pool. */\n priority: number;\n /** Provenance string. */\n source: CredentialSource;\n /** Sensitive API key. NEVER LOG UNREDACTED. */\n accessToken: string;\n /** Current health. */\n lastStatus: CredentialStatus;\n /** Epoch ms of the last status change. */\n lastStatusAt: number | undefined;\n /** HTTP code that caused exhaustion (401/402/429). */\n lastErrorCode: number | undefined;\n /** Provider-supplied \"retry after this epoch ms\" hint. Overrides cooldown defaults. */\n lastErrorResetAt: number | undefined;\n /** Bumped per successful `select()` for `least_used` strategy. Lazy-persisted. */\n requestCount: number;\n}\n\n/**\n * Serializable snapshot of a single provider's pool. Used by the\n * persistence layer (T2.1) to read/write `~/.theokit/credential-pool.json`.\n *\n * @internal\n */\nexport interface CredentialPoolSnapshot {\n provider: string;\n strategy: CredentialPoolStrategy;\n entries: PooledCredential[];\n}\n\n/**\n * Cooldown ladder by HTTP error code (ADR D125). Provider-supplied\n * `lastErrorResetAt` overrides these defaults when present.\n *\n * @internal\n */\nexport const COOLDOWN_MS: Readonly<Record<number, number>> = {\n 401: 5 * 60 * 1000, // 5 minutes — OAuth refresh can recover quickly\n 402: 60 * 60 * 1000, // 1 hour — billing quota typically hourly+\n 429: 60 * 60 * 1000, // 1 hour — daily-rate-limit windows\n};\n\n/** Default cooldown when no specific code matches. */\nexport const DEFAULT_COOLDOWN_MS = 60 * 60 * 1000;\n","/**\n * In-memory credential pool with strategy-based rotation (ADRs D123-D133).\n *\n * Pure logic. No I/O — persistence lives in `internal/persistence/\n * credential-pool-store.ts`. The pool is the single source of truth for\n * rotation state within a process; if it diverges from disk (e.g.,\n * process killed mid-rotation per EC-I), the next save heals the\n * inconsistency — at the cost of one extra HTTP 429 per crash.\n *\n * Thread safety: the pool uses an in-process async-aware mutex\n * (`cwd-mutex` D9 keyed by `credential-pool:${provider}`). Cross-process\n * safety happens at the persistence layer via `withFileLock` (D61).\n * Two Node processes sharing the same file may double-pick momentarily\n * (worst case = 1 extra 429 per race) — acceptable per ADR D128.\n *\n * @internal\n */\n\nimport { ConfigurationError } from \"../../errors.js\";\nimport { withCwdMutex } from \"../persistence/cwd-mutex.js\";\nimport {\n COOLDOWN_MS,\n type CredentialPoolSnapshot,\n type CredentialPoolStrategy,\n DEFAULT_COOLDOWN_MS,\n type PooledCredential,\n} from \"./credential-pool-types.js\";\nimport { sleepWithAbort } from \"./retry.js\";\n\n/**\n * Construct a `PooledCredential` with sane defaults.\n *\n * @internal\n */\nexport function newPooledCredential(args: {\n provider: string;\n accessToken: string;\n priority: number;\n source: string;\n label?: string;\n}): PooledCredential {\n return {\n id: globalThis.crypto.randomUUID(),\n label: args.label ?? labelFromSource(args.source, args.accessToken),\n provider: args.provider,\n priority: args.priority,\n source: args.source,\n accessToken: args.accessToken,\n lastStatus: \"ok\",\n lastStatusAt: undefined,\n lastErrorCode: undefined,\n lastErrorResetAt: undefined,\n requestCount: 0,\n };\n}\n\n/**\n * Build a human-readable label from the credential source. Used for\n * `Theokit.credentialPool.list()` UX. NEVER includes the raw token.\n *\n * @internal\n */\nfunction labelFromSource(source: string, accessToken: string): string {\n if (source.startsWith(\"env:\")) return source.slice(4);\n const masked =\n accessToken.length > 8 ? `${accessToken.slice(0, 4)}…${accessToken.slice(-4)}` : \"***\";\n return `${source}:${masked}`;\n}\n\n/**\n * Per-provider credential pool. Construct with one or more entries\n * sorted by priority. Throws `ConfigurationError` on empty input.\n *\n * EC-C: identical `accessToken`s are deduplicated during construction\n * (3 copies of \"k1\" → 1 entry). Otherwise an exhaustion event would\n * mark \"k1\" exhausted 3× wastefully.\n *\n * @internal\n */\nexport class CredentialPool {\n readonly provider: string;\n private readonly strategy: CredentialPoolStrategy;\n private entries: PooledCredential[];\n\n constructor(\n provider: string,\n entries: PooledCredential[],\n strategy: CredentialPoolStrategy = \"fill_first\",\n ) {\n if (entries.length === 0) {\n throw new ConfigurationError(\n `credential-pool: cannot construct empty pool for provider \"${provider}\"`,\n { code: \"credential_pool_empty\" },\n );\n }\n this.provider = provider;\n this.strategy = strategy;\n // EC-C: dedupe by accessToken before sort.\n this.entries = dedupeByToken(entries).sort((a, b) => a.priority - b.priority);\n }\n\n /** True if the pool was seeded with at least one entry. */\n hasCredentials(): boolean {\n return this.entries.length > 0;\n }\n\n /** True iff at least one entry is healthy (auto-healed if cooldown expired). */\n hasAvailable(): boolean {\n return this.availableEntries().length > 0;\n }\n\n /**\n * Earliest `lastErrorResetAt` across all entries, or `undefined` if no\n * entry is in cooldown. Used by `waitForAvailable` to compute the\n * upper bound of each jittered sleep window.\n *\n * @internal\n */\n earliestResetAt(): number | undefined {\n let earliest: number | undefined;\n for (const entry of this.entries) {\n if (entry.lastStatus === \"ok\") continue;\n if (entry.lastErrorResetAt === undefined) continue;\n if (earliest === undefined || entry.lastErrorResetAt < earliest) {\n earliest = entry.lastErrorResetAt;\n }\n }\n return earliest;\n }\n\n /**\n * Wait until at least one entry becomes healthy OR `maxWaitMs` elapses\n * OR `signal` aborts. Returns `true` if a healthy entry is available\n * when the call returns, `false` otherwise.\n *\n * T3.9 — Reconnect storm prevention. Concurrent callers each sleep a\n * random fraction of the window to the earliest cooldown reset (full\n * jitter — AWS Brooker 2015) so they do not all wake at the exact\n * instant cooldown expires and hammer the upstream simultaneously.\n *\n * The `sleeper` parameter is a dependency-injection seam for tests:\n * callers in production omit it and the default `setTimeout`-based\n * sleeper is used. The seam avoids the `vi.useFakeTimers()` mismatch\n * that blocked T3.4's wiring.\n *\n * @internal\n */\n async waitForAvailable(\n signal: AbortSignal,\n opts: {\n maxWaitMs: number;\n sleeper?: (ms: number, signal: AbortSignal) => Promise<void>;\n /**\n * Clock seam, the companion to `sleeper`. Production omits it and gets `Date.now`.\n *\n * `sleeper` alone was not enough to make this loop testable: a test could replace the SLEEP\n * but the deadline check still read real wall-clock, so the one case that exercises timeout\n * had to set `maxWaitMs: 5` and race the scheduler — with a comment in the committed file\n * saying so (\"we can't easily ... spec is wall-clock based\"). A sleeper that also advances a\n * virtual clock closes the loop deterministically, which is what `rules/testing.md` § 6 asks\n * for when it says to inject the clock rather than sleep.\n */\n now?: () => number;\n },\n ): Promise<boolean> {\n if (signal.aborted) return false;\n if (this.hasAvailable()) return true;\n const now = opts.now ?? Date.now;\n return await this.pollUntilAvailable(\n signal,\n now() + opts.maxWaitMs,\n opts.sleeper ?? sleepWithAbort,\n now,\n );\n }\n\n /**\n * The polling half of `waitForAvailable`, with both seams already resolved.\n *\n * Its own method because resolving two optional seams and running the loop in one body put the\n * function over the cognitive-complexity gate. The split is also the honest one: everything above\n * is a guard, everything here is the wait.\n */\n private async pollUntilAvailable(\n signal: AbortSignal,\n deadline: number,\n sleeper: (ms: number, signal: AbortSignal) => Promise<void>,\n now: () => number,\n ): Promise<boolean> {\n while (now() < deadline) {\n if (signal.aborted) return false;\n await sleeper(this.computeJitteredSleepMs(deadline, now), signal);\n if (signal.aborted) return false;\n if (this.hasAvailable()) return true;\n }\n return this.hasAvailable();\n }\n\n /**\n * Compute the next jittered sleep window (ms) for `waitForAvailable`.\n * Full-jitter cap: at most (a) time until the earliest reset (plus a\n * 50 ms grace so the entry actually heals before re-probe), or (b) the\n * remaining wait window, whichever is smaller. When no entry has a\n * known reset (rare — only if `markExhaustedAndRotate` was called\n * without `resetAtMs`), fall back to a 250 ms ceiling so we stay\n * responsive without hot-looping.\n */\n private computeJitteredSleepMs(deadline: number, now: () => number = Date.now): number {\n const resetAt = this.earliestResetAt();\n const remaining = deadline - now();\n const ceiling =\n resetAt === undefined\n ? Math.min(remaining, 250)\n : Math.min(remaining, Math.max(0, resetAt - now()) + 50);\n return Math.max(0, Math.floor(Math.random() * ceiling));\n }\n\n /** Live (frozen) view of all entries. */\n list(): readonly PooledCredential[] {\n return this.entries;\n }\n\n /**\n * Pick a healthy entry according to the configured strategy.\n * Mutates `requestCount` and (for round_robin) entry order.\n * Returns null if every entry is in cooldown.\n *\n * @internal\n */\n async select(): Promise<PooledCredential | null> {\n return withCwdMutex(`credential-pool:${this.provider}`, async () => this.selectLocked());\n }\n\n /**\n * Mark the entry whose id matches `entryId` as exhausted with the\n * appropriate cooldown, then return the next healthy entry (or null).\n * If `entryId` is undefined, marks all currently-active entries (rare —\n * only used by admin reset scenarios).\n *\n * @internal\n */\n async markExhaustedAndRotate(args: {\n entryId: string;\n statusCode: number;\n resetAtMs?: number;\n }): Promise<PooledCredential | null> {\n return withCwdMutex(`credential-pool:${this.provider}`, async () => {\n const entry = this.entries.find((e) => e.id === args.entryId);\n if (entry !== undefined) {\n const now = Date.now();\n const cooldown = COOLDOWN_MS[args.statusCode] ?? DEFAULT_COOLDOWN_MS;\n entry.lastStatus = \"exhausted\";\n entry.lastStatusAt = now;\n entry.lastErrorCode = args.statusCode;\n // EC-5: negative or stale resetAt → ignore, fall through to default.\n entry.lastErrorResetAt =\n args.resetAtMs !== undefined && args.resetAtMs > now ? args.resetAtMs : now + cooldown;\n }\n return this.selectLocked();\n });\n }\n\n /** Admin escape hatch: clear all cooldowns. */\n async resetAll(): Promise<void> {\n await withCwdMutex(`credential-pool:${this.provider}`, async () => {\n for (const e of this.entries) {\n e.lastStatus = \"ok\";\n e.lastStatusAt = undefined;\n e.lastErrorCode = undefined;\n e.lastErrorResetAt = undefined;\n }\n });\n }\n\n /** Materialize for persistence. */\n toSnapshot(): CredentialPoolSnapshot {\n return {\n provider: this.provider,\n strategy: this.strategy,\n entries: this.entries.map((e) => ({ ...e })),\n };\n }\n\n /** Hydrate from a previously-saved snapshot. */\n static fromSnapshot(snapshot: CredentialPoolSnapshot): CredentialPool {\n return new CredentialPool(snapshot.provider, snapshot.entries, snapshot.strategy);\n }\n\n // ─── Internal helpers (always called inside the mutex) ───\n\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: strategy dispatch must branch on 4 enum values (random/least_used/round_robin/fill_first) with 1-entry short-circuits per strategy. Each branch is 5-10 lines of focused logic; extracting per-strategy methods fragments the linear narrative.\n private selectLocked(): PooledCredential | null {\n const available = this.availableEntries();\n if (available.length === 0) return null;\n\n if (this.strategy === \"random\") {\n const idx = Math.floor(Math.random() * available.length);\n const picked = available[idx];\n if (picked === undefined) return null; // unreachable; satisfies strict\n picked.requestCount += 1;\n return picked;\n }\n\n if (this.strategy === \"least_used\" && available.length > 1) {\n // EC-3: tie-break by priority ascending (first wins).\n const picked = [...available].sort(\n (a, b) => a.requestCount - b.requestCount || a.priority - b.priority,\n )[0];\n if (picked === undefined) return null;\n picked.requestCount += 1;\n return picked;\n }\n\n if (this.strategy === \"round_robin\" && available.length > 1) {\n // Pick head; move it to the end of `entries` so next call picks the next.\n const picked = available[0];\n if (picked === undefined) return null;\n picked.requestCount += 1;\n const rest = this.entries.filter((e) => e.id !== picked.id);\n // Re-assign priorities: rotated entry gets the highest priority value\n // so it sorts last after `fromSnapshot` rehydration. This makes EC-F\n // (round-robin state survives save/load) work without a separate field.\n const maxPriority = this.entries.length - 1;\n rest.forEach((e, i) => {\n e.priority = i;\n });\n picked.priority = maxPriority;\n this.entries = [...rest, picked];\n return picked;\n }\n\n // fill_first (default) and 1-entry edge case for round_robin/least_used\n const picked = available[0];\n if (picked === undefined) return null;\n picked.requestCount += 1;\n return picked;\n }\n\n private availableEntries(): PooledCredential[] {\n const now = Date.now();\n const out: PooledCredential[] = [];\n for (const entry of this.entries) {\n if (entry.lastStatus === \"ok\") {\n out.push(entry);\n continue;\n }\n // EC-1: auto-heal expired cooldowns inline.\n const resetAt = entry.lastErrorResetAt;\n if (resetAt !== undefined && now >= resetAt) {\n entry.lastStatus = \"ok\";\n entry.lastStatusAt = undefined;\n entry.lastErrorCode = undefined;\n entry.lastErrorResetAt = undefined;\n out.push(entry);\n }\n }\n return out;\n }\n}\n\n/**\n * Drop duplicates by `accessToken`. Keeps the first occurrence (lowest\n * priority wins after sort). EC-C from the edge-case review.\n */\nfunction dedupeByToken(entries: PooledCredential[]): PooledCredential[] {\n const seen = new Set<string>();\n const out: PooledCredential[] = [];\n for (const e of entries) {\n if (seen.has(e.accessToken)) continue;\n seen.add(e.accessToken);\n out.push(e);\n }\n return out;\n}\n","/**\n * Per-fork credential-pool inheritance via `AsyncLocalStorage` (ADR D131).\n *\n * Mirrors the whitelist context pattern from D111\n * (`runtime/async-local-storage.ts`). Forked sub-agents inherit the\n * parent's pool *by reference* so concurrent rotations all observe\n * the same cooldown state — the desired behavior per Hermes parity.\n *\n * @internal\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nimport type { CredentialPool } from \"./credential-pool.js\";\n\n/** ALS slot — keyed by provider name → pool. */\nconst credentialPoolStore = new AsyncLocalStorage<Map<string, CredentialPool>>();\n\n/**\n * Run `fn` with `pools` as the active credential-pool registry for the\n * current async context. Nested calls shadow the outer map (parent\n * pools are not visible to children when the child sets its own).\n *\n * @internal\n */\nexport async function withCredentialPool<T>(\n pools: Map<string, CredentialPool>,\n fn: () => Promise<T>,\n): Promise<T> {\n return credentialPoolStore.run(pools, fn);\n}\n\n/**\n * Pool registered for `provider` in the current async context, or\n * `undefined` when no `withCredentialPool(...)` scope is active.\n *\n * @internal\n */\nexport function currentCredentialPool(provider: string): CredentialPool | undefined {\n return credentialPoolStore.getStore()?.get(provider);\n}\n"]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { acquireSessionWriter } from './chunk-
|
|
2
|
-
import { transcriptPath, legacyTranscriptPath, readTranscript } from './chunk-
|
|
3
|
-
import { appendJsonl } from './chunk-
|
|
1
|
+
import { acquireSessionWriter } from './chunk-QH6MWGOA.js';
|
|
2
|
+
import { transcriptPath, legacyTranscriptPath, readTranscript } from './chunk-3VX7JHJI.js';
|
|
3
|
+
import { appendJsonl } from './chunk-JD3EKKKB.js';
|
|
4
4
|
import { withFileLock } from './chunk-FGGVSHDW.js';
|
|
5
|
-
import { existsSync } from 'fs';
|
|
6
|
-
import { mkdir } from 'fs/promises';
|
|
7
|
-
import { dirname } from 'path';
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import { mkdir } from 'node:fs/promises';
|
|
7
|
+
import { dirname } from 'node:path';
|
|
8
8
|
|
|
9
9
|
var sharedLeases = /* @__PURE__ */ new Map();
|
|
10
10
|
async function acquireShared(path) {
|
|
@@ -130,5 +130,5 @@ var FsSessionStore = class {
|
|
|
130
130
|
};
|
|
131
131
|
|
|
132
132
|
export { FsSessionStore };
|
|
133
|
-
//# sourceMappingURL=chunk-
|
|
134
|
-
//# sourceMappingURL=chunk-
|
|
133
|
+
//# sourceMappingURL=chunk-P7B64NFK.js.map
|
|
134
|
+
//# sourceMappingURL=chunk-P7B64NFK.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/persistence/fs-session-store.ts"],"names":[],"mappings":"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","file":"chunk-RGVMJU57.js","sourcesContent":["/**\n * SE41 — `FsSessionStore`, the DEFAULT reference implementation of the pluggable\n * {@link SessionStore} seam. It reads and append-writes the native Claude-shaped\n * `.jsonl` transcript at `<baseDir>/projects/<encoded-cwd>/<agentId>.jsonl` — the\n * exact on-disk format SE40 introduced (the file the Claude Code CLI can\n * `--continue`). Omitting `local.sessionStore` resolves to this store, so the\n * default persistence path is byte-identical to SE40 behavior.\n *\n * `readRecords` is `readTranscript(transcriptPath(...))` (a missing session →\n * `[]`, not an error — a fresh agent has no history). `appendRecords` is a TRUE\n * append: it reads the prior records, concatenates the new-turn delta, and\n * rewrites the whole line set atomically under the SE40 cross-process file lock\n * (`writeTranscript` never shrinks — the native format is an append-only\n * `parentUuid` DAG). The parent dir is created BEFORE acquiring the lock because\n * the lock's companion `<path>.lock` file needs an existing parent dir (the SE40\n * `mkdir(dirname)`-before-lock fix).\n *\n * @internal\n */\n\nimport { existsSync } from \"node:fs\";\nimport { mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { SessionStore } from \"../../types/session-store.js\";\nimport { withFileLock } from \"./file-lock.js\";\nimport { appendJsonl } from \"./jsonl.js\";\nimport {\n legacyTranscriptPath,\n readTranscript,\n type SessionRecord,\n transcriptPath,\n} from \"./session-transcript.js\";\nimport { acquireSessionWriter, type SessionWriterLease } from \"./session-writer.js\";\n\n/** Options identifying the on-disk transcript location for the FS default store. */\nexport interface FsSessionStoreOptions {\n /** Transcript base dir (`~/.theokit` default, `~/.claude` for CLI interop) — already `~`-expanded. */\n baseDir: string;\n /** The workspace cwd whose encoded form is the transcript project dir. */\n cwd: string;\n}\n\n/**\n * Reference-counted leases, shared per path.\n *\n * `acquireSessionWriter` is STRICT on purpose: two concurrent acquisitions of the same path, and\n * exactly one wins — \"a lease that let both through would be decorative\" (the M81 test says exactly\n * that, and it is right). That is the primitive's contract, and it does not change.\n *\n * But within ONE process it is normal to have more than one store over the same session: the golden\n * compaction tests and the concurrent-send tests do exactly that, and they record real runtime\n * behavior. Applying the raw primitive there would turn a legitimate pattern into a\n * `SessionBusyError`.\n *\n * The reconciliation belongs here, in the primitive's consumer: the process takes ONE lease per path\n * and counts how many stores use it. The last to release actually frees it. Cross-process stays\n * strict — which is the problem M81 states (\"`exec resume --last` can write into the TUI's live\n * session\").\n */\nconst sharedLeases = new Map<string, { lease: SessionWriterLease; refs: number }>();\n\nasync function acquireShared(path: string): Promise<SessionWriterLease> {\n const existing = sharedLeases.get(path);\n if (existing !== undefined) {\n existing.refs++;\n return createProxy(path);\n }\n const lease = await acquireSessionWriter(path);\n sharedLeases.set(path, { lease, refs: 1 });\n return createProxy(path);\n}\n\n/** A handle that decrements the count; the last to release frees the real lease. */\nfunction createProxy(path: string): SessionWriterLease {\n let released = false;\n return {\n sessionPath: path,\n // The proxy forwards the renewal to the ONE real lease this path shares. Renewing through any\n // holder is correct and is the point: the record must say \"someone in this process is still\n // writing\", and the refcount already guarantees they are all the same owner.\n renew: (): void => {\n if (released) return;\n sharedLeases.get(path)?.lease.renew();\n },\n release: async (): Promise<void> => {\n if (released) return;\n released = true;\n const entry = sharedLeases.get(path);\n if (entry === undefined) return;\n entry.refs--;\n if (entry.refs > 0) return;\n sharedLeases.delete(path);\n await entry.lease.release();\n },\n };\n}\n\n/**\n * The default `SessionStore` — reads/append-writes the native `.jsonl` transcript.\n */\nexport class FsSessionStore implements SessionStore {\n readonly #baseDir: string;\n readonly #cwd: string;\n /** One lease per `agentId` — a store serves more than one session over the process lifetime. */\n readonly #leases = new Map<string, SessionWriterLease>();\n /** Memoized per agent so read, append and lease can never disagree about which file is the session. */\n readonly #paths = new Map<string, string>();\n\n constructor(options: FsSessionStoreOptions) {\n this.#baseDir = options.baseDir;\n this.#cwd = options.cwd;\n }\n\n /**\n * The file that IS this agent's session.\n *\n * #400 made transcript filenames UUIDs so `claude --continue` can find them. A transcript written\n * before that lives under the old name, and switching to the new one would not lose the file but\n * would abandon it: the agent would start a second, empty history beside its real one. So an\n * existing legacy file wins, and only a session with no file yet gets the new name.\n *\n * Resolved ONCE per agent. Re-deciding per call would let `acquire` lock one path while\n * `appendRecords` wrote another — the lease would be guarding a file nobody was writing.\n */\n #pathFor(agentId: string): string {\n const memoized = this.#paths.get(agentId);\n if (memoized !== undefined) return memoized;\n const canonical = transcriptPath(this.#baseDir, this.#cwd, agentId);\n const legacy = legacyTranscriptPath(this.#baseDir, this.#cwd, agentId);\n const resolved = legacy !== canonical && existsSync(legacy) ? legacy : canonical;\n this.#paths.set(agentId, resolved);\n return resolved;\n }\n\n async readRecords(agentId: string): Promise<SessionRecord[]> {\n return readTranscript(this.#pathFor(agentId));\n }\n\n async appendRecords(agentId: string, records: readonly SessionRecord[]): Promise<void> {\n // Empty delta → nothing to persist (avoids an unnecessary lock + rewrite).\n if (records.length === 0) return;\n const path = this.#pathFor(agentId);\n // mkdir BEFORE the lock: withFileLock's companion `<path>.lock` needs the parent dir.\n await mkdir(dirname(path), { recursive: true });\n\n await withFileLock(path, async () => {\n // M93 — appends the DELTA instead of rewriting the whole file.\n //\n // Before: `readTranscript` + `writeTranscript` of everything, per turn. O(n) of I/O **and** of\n // parsing on every turn, O(n^2) per session — the consumer note in\n // `agents/lib/session/backtrack.ts` records 1.4 MB / 3000 lines over 200 turns.\n //\n // Correct because the format **is already append-only**: the `parentUuid` DAG does not depend\n // on line order, and every record carries its own parent. `appendJsonl` **already existed in\n // the package** and had a single caller (`eval/runner.ts`) — the primitive was there, it was\n // the store that ignored it (rung 4).\n //\n // `withFileLock` stays — but the earlier claim that \"it is what serializes two concurrent\n // `appendRecords`\" was too strong, and M93's adversarial review measured it: removing it fails\n // no test. The reason is the paragraph above — the `parentUuid` DAG does not depend on line\n // order, so two interleaved batches reconstruct identically. The work the lock was doing\n // (protecting a read-modify-write) disappeared along with the rewrite.\n //\n // What it still covers is the TOCTOU window in `needsLineBreakBefore` (read the last byte,\n // then write): without it, two processes can both conclude \"a \\n is missing\" and produce a\n // blank line — which the reader discards, i.e. benign. It stays as a **declared, not\n // mechanized** defense (the discipline in `error-handling.md` § 4: enumerate the residue\n // rather than let a missing test pass for coverage).\n //\n // `writeTranscript` still exists for **compaction**, the one operation that legitimately\n // rewrites the file.\n for (const record of records) appendJsonl(path, record);\n });\n }\n\n /**\n * Takes the session's writer lease. Throws `SessionBusyError` when another process holds it.\n *\n * **Explicit, and NOT inside `appendRecords`** — M95's adversarial review measured why that\n * matters: the `SessionStore` contract states that \"an `appendRecords` rejection is logged to\n * stderr, NOT thrown to the caller (best-effort write)\". Acquiring there made the\n * `SessionBusyError` get **swallowed**, and the result was worse than the original problem:\n * instead of two writers interleaving lines, the loser **lost the turn silently** — nothing on\n * disk, a stderr warning invisible under the TUI, and no way for the caller to react.\n *\n * At init the error reaches someone who can act: `exec` forks to a new id, which is exactly what\n * the error message itself prescribes. It is the difference between failing where a decision is\n * possible and failing where only loss is.\n */\n async acquire(agentId: string): Promise<void> {\n if (this.#leases.has(agentId)) return;\n const path = this.#pathFor(agentId);\n await mkdir(dirname(path), { recursive: true });\n this.#leases.set(agentId, await acquireShared(path));\n }\n\n /**\n * Releases ONE agent's lease.\n *\n * It exists because `dispose()` releases **every** lease the store holds, and a store injected by\n * the consumer may serve several agents: an init that fails for agent B must not free agent A's\n * lease, which is still live and writing.\n */\n async release(agentId: string): Promise<void> {\n const lease = this.#leases.get(agentId);\n if (lease === undefined) return;\n this.#leases.delete(agentId);\n await lease.release();\n }\n\n /**\n * Releases every lease this store holds.\n *\n * Without it the `.writer.lock` outlives the process and the next open would have to wait out the\n * heartbeat window — recoverable, but 30 s of waiting after a CLEAN shutdown would be an avoidable\n * defect. Idempotent: calling it twice is not an error.\n */\n async dispose(): Promise<void> {\n const leases = [...this.#leases.values()];\n this.#leases.clear();\n for (const lease of leases) await lease.release();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/internal/persistence/fs-session-store.ts"],"names":[],"mappings":"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","file":"chunk-P7B64NFK.js","sourcesContent":["/**\n * SE41 — `FsSessionStore`, the DEFAULT reference implementation of the pluggable\n * {@link SessionStore} seam. It reads and append-writes the native Claude-shaped\n * `.jsonl` transcript at `<baseDir>/projects/<encoded-cwd>/<agentId>.jsonl` — the\n * exact on-disk format SE40 introduced (the file the Claude Code CLI can\n * `--continue`). Omitting `local.sessionStore` resolves to this store, so the\n * default persistence path is byte-identical to SE40 behavior.\n *\n * `readRecords` is `readTranscript(transcriptPath(...))` (a missing session →\n * `[]`, not an error — a fresh agent has no history). `appendRecords` is a TRUE\n * append: it reads the prior records, concatenates the new-turn delta, and\n * rewrites the whole line set atomically under the SE40 cross-process file lock\n * (`writeTranscript` never shrinks — the native format is an append-only\n * `parentUuid` DAG). The parent dir is created BEFORE acquiring the lock because\n * the lock's companion `<path>.lock` file needs an existing parent dir (the SE40\n * `mkdir(dirname)`-before-lock fix).\n *\n * @internal\n */\n\nimport { existsSync } from \"node:fs\";\nimport { mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { SessionStore } from \"../../types/session-store.js\";\nimport { withFileLock } from \"./file-lock.js\";\nimport { appendJsonl } from \"./jsonl.js\";\nimport {\n legacyTranscriptPath,\n readTranscript,\n type SessionRecord,\n transcriptPath,\n} from \"./session-transcript.js\";\nimport { acquireSessionWriter, type SessionWriterLease } from \"./session-writer.js\";\n\n/** Options identifying the on-disk transcript location for the FS default store. */\nexport interface FsSessionStoreOptions {\n /** Transcript base dir (`~/.theokit` default, `~/.claude` for CLI interop) — already `~`-expanded. */\n baseDir: string;\n /** The workspace cwd whose encoded form is the transcript project dir. */\n cwd: string;\n}\n\n/**\n * Reference-counted leases, shared per path.\n *\n * `acquireSessionWriter` is STRICT on purpose: two concurrent acquisitions of the same path, and\n * exactly one wins — \"a lease that let both through would be decorative\" (the M81 test says exactly\n * that, and it is right). That is the primitive's contract, and it does not change.\n *\n * But within ONE process it is normal to have more than one store over the same session: the golden\n * compaction tests and the concurrent-send tests do exactly that, and they record real runtime\n * behavior. Applying the raw primitive there would turn a legitimate pattern into a\n * `SessionBusyError`.\n *\n * The reconciliation belongs here, in the primitive's consumer: the process takes ONE lease per path\n * and counts how many stores use it. The last to release actually frees it. Cross-process stays\n * strict — which is the problem M81 states (\"`exec resume --last` can write into the TUI's live\n * session\").\n */\nconst sharedLeases = new Map<string, { lease: SessionWriterLease; refs: number }>();\n\nasync function acquireShared(path: string): Promise<SessionWriterLease> {\n const existing = sharedLeases.get(path);\n if (existing !== undefined) {\n existing.refs++;\n return createProxy(path);\n }\n const lease = await acquireSessionWriter(path);\n sharedLeases.set(path, { lease, refs: 1 });\n return createProxy(path);\n}\n\n/** A handle that decrements the count; the last to release frees the real lease. */\nfunction createProxy(path: string): SessionWriterLease {\n let released = false;\n return {\n sessionPath: path,\n // The proxy forwards the renewal to the ONE real lease this path shares. Renewing through any\n // holder is correct and is the point: the record must say \"someone in this process is still\n // writing\", and the refcount already guarantees they are all the same owner.\n renew: (): void => {\n if (released) return;\n sharedLeases.get(path)?.lease.renew();\n },\n release: async (): Promise<void> => {\n if (released) return;\n released = true;\n const entry = sharedLeases.get(path);\n if (entry === undefined) return;\n entry.refs--;\n if (entry.refs > 0) return;\n sharedLeases.delete(path);\n await entry.lease.release();\n },\n };\n}\n\n/**\n * The default `SessionStore` — reads/append-writes the native `.jsonl` transcript.\n */\nexport class FsSessionStore implements SessionStore {\n readonly #baseDir: string;\n readonly #cwd: string;\n /** One lease per `agentId` — a store serves more than one session over the process lifetime. */\n readonly #leases = new Map<string, SessionWriterLease>();\n /** Memoized per agent so read, append and lease can never disagree about which file is the session. */\n readonly #paths = new Map<string, string>();\n\n constructor(options: FsSessionStoreOptions) {\n this.#baseDir = options.baseDir;\n this.#cwd = options.cwd;\n }\n\n /**\n * The file that IS this agent's session.\n *\n * #400 made transcript filenames UUIDs so `claude --continue` can find them. A transcript written\n * before that lives under the old name, and switching to the new one would not lose the file but\n * would abandon it: the agent would start a second, empty history beside its real one. So an\n * existing legacy file wins, and only a session with no file yet gets the new name.\n *\n * Resolved ONCE per agent. Re-deciding per call would let `acquire` lock one path while\n * `appendRecords` wrote another — the lease would be guarding a file nobody was writing.\n */\n #pathFor(agentId: string): string {\n const memoized = this.#paths.get(agentId);\n if (memoized !== undefined) return memoized;\n const canonical = transcriptPath(this.#baseDir, this.#cwd, agentId);\n const legacy = legacyTranscriptPath(this.#baseDir, this.#cwd, agentId);\n const resolved = legacy !== canonical && existsSync(legacy) ? legacy : canonical;\n this.#paths.set(agentId, resolved);\n return resolved;\n }\n\n async readRecords(agentId: string): Promise<SessionRecord[]> {\n return readTranscript(this.#pathFor(agentId));\n }\n\n async appendRecords(agentId: string, records: readonly SessionRecord[]): Promise<void> {\n // Empty delta → nothing to persist (avoids an unnecessary lock + rewrite).\n if (records.length === 0) return;\n const path = this.#pathFor(agentId);\n // mkdir BEFORE the lock: withFileLock's companion `<path>.lock` needs the parent dir.\n await mkdir(dirname(path), { recursive: true });\n\n await withFileLock(path, async () => {\n // M93 — appends the DELTA instead of rewriting the whole file.\n //\n // Before: `readTranscript` + `writeTranscript` of everything, per turn. O(n) of I/O **and** of\n // parsing on every turn, O(n^2) per session — the consumer note in\n // `agents/lib/session/backtrack.ts` records 1.4 MB / 3000 lines over 200 turns.\n //\n // Correct because the format **is already append-only**: the `parentUuid` DAG does not depend\n // on line order, and every record carries its own parent. `appendJsonl` **already existed in\n // the package** and had a single caller (`eval/runner.ts`) — the primitive was there, it was\n // the store that ignored it (rung 4).\n //\n // `withFileLock` stays — but the earlier claim that \"it is what serializes two concurrent\n // `appendRecords`\" was too strong, and M93's adversarial review measured it: removing it fails\n // no test. The reason is the paragraph above — the `parentUuid` DAG does not depend on line\n // order, so two interleaved batches reconstruct identically. The work the lock was doing\n // (protecting a read-modify-write) disappeared along with the rewrite.\n //\n // What it still covers is the TOCTOU window in `needsLineBreakBefore` (read the last byte,\n // then write): without it, two processes can both conclude \"a \\n is missing\" and produce a\n // blank line — which the reader discards, i.e. benign. It stays as a **declared, not\n // mechanized** defense (the discipline in `error-handling.md` § 4: enumerate the residue\n // rather than let a missing test pass for coverage).\n //\n // `writeTranscript` still exists for **compaction**, the one operation that legitimately\n // rewrites the file.\n for (const record of records) appendJsonl(path, record);\n });\n }\n\n /**\n * Takes the session's writer lease. Throws `SessionBusyError` when another process holds it.\n *\n * **Explicit, and NOT inside `appendRecords`** — M95's adversarial review measured why that\n * matters: the `SessionStore` contract states that \"an `appendRecords` rejection is logged to\n * stderr, NOT thrown to the caller (best-effort write)\". Acquiring there made the\n * `SessionBusyError` get **swallowed**, and the result was worse than the original problem:\n * instead of two writers interleaving lines, the loser **lost the turn silently** — nothing on\n * disk, a stderr warning invisible under the TUI, and no way for the caller to react.\n *\n * At init the error reaches someone who can act: `exec` forks to a new id, which is exactly what\n * the error message itself prescribes. It is the difference between failing where a decision is\n * possible and failing where only loss is.\n */\n async acquire(agentId: string): Promise<void> {\n if (this.#leases.has(agentId)) return;\n const path = this.#pathFor(agentId);\n await mkdir(dirname(path), { recursive: true });\n this.#leases.set(agentId, await acquireShared(path));\n }\n\n /**\n * Releases ONE agent's lease.\n *\n * It exists because `dispose()` releases **every** lease the store holds, and a store injected by\n * the consumer may serve several agents: an init that fails for agent B must not free agent A's\n * lease, which is still live and writing.\n */\n async release(agentId: string): Promise<void> {\n const lease = this.#leases.get(agentId);\n if (lease === undefined) return;\n this.#leases.delete(agentId);\n await lease.release();\n }\n\n /**\n * Releases every lease this store holds.\n *\n * Without it the `.writer.lock` outlives the process and the next open would have to wait out the\n * heartbeat window — recoverable, but 30 s of waiting after a CLEAN shutdown would be an avoidable\n * defect. Idempotent: calling it twice is not an error.\n */\n async dispose(): Promise<void> {\n const leases = [...this.#leases.values()];\n this.#leases.clear();\n for (const lease of leases) await lease.release();\n }\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { atomicWriteText } from './chunk-
|
|
1
|
+
import { atomicWriteText } from './chunk-AZK3QM36.js';
|
|
2
2
|
import { TheokitAgentError } from './chunk-TNFOU6SB.js';
|
|
3
|
-
import { mkdir, readFile, readdir } from 'fs/promises';
|
|
4
|
-
import { join } from 'path';
|
|
3
|
+
import { mkdir, readFile, readdir } from 'node:fs/promises';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
5
|
|
|
6
6
|
// src/workflow-errors.ts
|
|
7
7
|
var WorkflowDuplicateStepIdError = class extends TheokitAgentError {
|
|
@@ -235,7 +235,7 @@ var JsonFileWorkflowSnapshotStore = class {
|
|
|
235
235
|
}
|
|
236
236
|
async delete(runId) {
|
|
237
237
|
try {
|
|
238
|
-
await (await import('fs/promises')).unlink(this.filePath(runId));
|
|
238
|
+
await (await import('node:fs/promises')).unlink(this.filePath(runId));
|
|
239
239
|
} catch (err) {
|
|
240
240
|
if (err.code !== "ENOENT") throw err;
|
|
241
241
|
}
|
|
@@ -293,5 +293,5 @@ function __resetSnapshotStoresForTests() {
|
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
export { WorkflowAlreadyRunningError, WorkflowCompensateNotImplementedError, WorkflowDuplicateStepIdError, WorkflowInputError, WorkflowMaxIterationsExceededError, WorkflowNestedError, WorkflowNotSerializableError, WorkflowOutputError, WorkflowParallelError, WorkflowResumeStepNotFoundError, WorkflowResumeWorkflowMismatchError, WorkflowSnapshotNotFoundError, WorkflowStateError, __resetSnapshotStoresForTests, getSnapshotStoreFor };
|
|
296
|
-
//# sourceMappingURL=chunk-
|
|
297
|
-
//# sourceMappingURL=chunk-
|
|
296
|
+
//# sourceMappingURL=chunk-PCPYTBVV.js.map
|
|
297
|
+
//# sourceMappingURL=chunk-PCPYTBVV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/workflow-errors.ts","../src/internal/workflow/snapshot-store.ts"],"names":[],"mappings":"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","file":"chunk-PCPYTBVV.js","sourcesContent":["/**\n * The workflow error hierarchy — runtime classes, deliberately NOT in `types/`.\n *\n * `types/index.ts` calls itself \"the canonical public contract\" and re-exports every sibling with\n * `export type *`, which cannot carry a value; `.dependency-cruiser.cjs` restates the same rule as\n * \"src/types/* are pure type definitions\". These twelve classes lived in `types/workflow.ts` anyway\n * and reached consumers only because the DTS rollup hoists a declaration the runtime bundle never\n * emitted — the shape that shipped #279 for `isValidTaskId`. `tests/lint/types-are-types-only.test.ts`\n * is what stops it recurring.\n *\n * The home mirrors `task-errors.ts`: errors for one public surface, next to it, at the src root.\n * Re-exported by name from `workflow.ts`, so `@theokit/sdk/workflow` is unchanged.\n *\n * @public\n */\n\nimport { TheokitAgentError } from \"./errors-base.js\";\nimport type { WorkflowRun } from \"./types/workflow.js\";\n\n/**\n * Thrown by `.commit()` when one step id appears twice anywhere in the workflow — including inside a\n * parallel branch, a branch predicate, the fallback, and the inner step of a `foreach` or `dowhile`.\n *\n * Ids address steps in snapshots and on resume, so this is refused at build time rather than\n * discovered mid-run. Workflows nested with `workflowStep()` are exempt: the child runs in its own\n * executor with its own id-space, so its ids cannot collide with the parent's.\n */\nexport class WorkflowDuplicateStepIdError extends TheokitAgentError {\n override readonly name = \"WorkflowDuplicateStepIdError\";\n constructor(public readonly stepId: string) {\n super(`Duplicate step id \"${stepId}\" in workflow.`, {\n code: \"workflow_duplicate_step_id\",\n isRetryable: false,\n });\n }\n}\n\n/**\n * SE27 — the whole-workflow `inputSchema` rejected `run(input)` (before step 1).\n * `detail` is a pre-formatted issues summary (a string, NOT Zod's `ZodIssue[]`).\n */\nexport class WorkflowInputError extends TheokitAgentError {\n override readonly name = \"WorkflowInputError\";\n constructor(\n public readonly workflowName: string,\n public readonly detail: string,\n ) {\n super(`Workflow \"${workflowName}\" input failed schema validation: ${detail}`, {\n code: \"workflow_input_invalid\",\n isRetryable: false,\n });\n }\n}\n\n/**\n * SE27 — the whole-workflow `outputSchema` rejected the final output (on `completed`).\n * `detail` is a pre-formatted issues summary (a string, NOT Zod's `ZodIssue[]`).\n */\nexport class WorkflowOutputError extends TheokitAgentError {\n override readonly name = \"WorkflowOutputError\";\n constructor(\n public readonly workflowName: string,\n public readonly detail: string,\n ) {\n super(`Workflow \"${workflowName}\" output failed schema validation: ${detail}`, {\n code: \"workflow_output_invalid\",\n isRetryable: false,\n });\n }\n}\n\n/**\n * SE29 — `WorkflowOptions.stateSchema` rejected an `initialState` or a\n * `setState(next)` call. `detail` is a pre-formatted issues summary.\n */\nexport class WorkflowStateError extends TheokitAgentError {\n override readonly name = \"WorkflowStateError\";\n constructor(\n public readonly workflowName: string,\n public readonly detail: string,\n ) {\n super(`Workflow \"${workflowName}\" state failed schema validation: ${detail}`, {\n code: \"workflow_state_invalid\",\n isRetryable: false,\n });\n }\n}\n\n/**\n * SE30 — a nested workflow (via `workflowStep`) did not `complete`. A nested\n * `suspended` is NOT resumable in v1 (resume continues AFTER the step, so the\n * child would be skipped) — restructure with a top-level suspend. A nested\n * `failed`/`cancelled` fails the parent step with the child's error attached.\n */\nexport class WorkflowNestedError extends TheokitAgentError {\n override readonly name = \"WorkflowNestedError\";\n constructor(\n public readonly stepId: string,\n public readonly childName: string,\n public readonly childStatus: Exclude<WorkflowRun[\"status\"], \"completed\">,\n public readonly childError?: { name: string; message: string },\n ) {\n super(\n `Nested workflow \"${childName}\" (step \"${stepId}\") ended with status \"${childStatus}\"${\n childStatus === \"suspended\"\n ? \" — nested suspend/resume is not supported in v1 (use a top-level suspend)\"\n : \"\"\n }${childError ? `: ${childError.name}: ${childError.message}` : \"\"}`,\n // Reconstruct a synthetic Error from the serialized child-error shape so\n // debuggers surface the nested cause chain — the original Error instance is\n // lost at the WorkflowRun serialization boundary, so this is the best\n // achievable without changing the run protocol.\n {\n code: \"workflow_nested_failed\",\n isRetryable: false,\n ...(childError\n ? { cause: Object.assign(new Error(childError.message), { name: childError.name }) }\n : {}),\n },\n );\n }\n}\n\n/**\n * Thrown out of `Workflow.run()` — one of the few workflow failures that rejects instead of arriving\n * as `run.status === \"failed\"` — when the committed workflow already has a run in flight under the\n * same run id.\n *\n * The lock key pairs the id minted at `.commit()` with the run id, not `WorkflowOptions.name`, so\n * two workflows sharing a name are independent and concurrent runs with distinct minted ids never\n * collide. In practice this only fires when a caller pins `WorkflowRunOptions.runId`, or resumes a\n * run id that is still executing. The registry is an in-process map: a crash releases every lock, and\n * it says nothing about runs in other processes.\n */\nexport class WorkflowAlreadyRunningError extends TheokitAgentError {\n override readonly name = \"WorkflowAlreadyRunningError\";\n constructor(\n public readonly workflowName: string,\n public readonly runId: string,\n ) {\n super(`Workflow \"${workflowName}\" run \"${runId}\" already in-flight.`, {\n code: \"workflow_already_running\",\n isRetryable: true,\n });\n }\n}\n\n/**\n * Thrown by `Workflow.resume()` when no snapshot exists for the given run id.\n *\n * The message suggests configuring persistence, which is the common cause but not the only one. The\n * run may never have suspended; it may have suspended under the default memory backend in a process\n * that has since exited; or the snapshot may already have been consumed, since resume deletes it\n * before re-entering the executor and a second resume of the same run id lands here.\n */\nexport class WorkflowSnapshotNotFoundError extends TheokitAgentError {\n override readonly name = \"WorkflowSnapshotNotFoundError\";\n constructor(public readonly runId: string) {\n super(`No snapshot found for runId \"${runId}\". Configure persistence to enable resume.`, {\n code: \"workflow_snapshot_not_found\",\n isRetryable: false,\n });\n }\n}\n\n/**\n * Raised when a `dowhile` step's condition kept returning true past `maxIterations` (default 100).\n *\n * It does not escape `run()`: the step fails, the run ends `status: \"failed\"`, and the error reaches\n * the caller flattened as `run.error` with `name: \"WorkflowMaxIterationsExceededError\"` — match on\n * the name, the instance does not survive. The guard is evaluated before each iteration, so the inner\n * step runs at most `maxIterations` times; raising the ceiling is a `maxIterations` on the step, and\n * there is no global default to change.\n */\nexport class WorkflowMaxIterationsExceededError extends TheokitAgentError {\n override readonly name = \"WorkflowMaxIterationsExceededError\";\n constructor(\n public readonly stepId: string,\n public readonly maxIterations: number,\n ) {\n super(`Step \"${stepId}\" exceeded max iterations (${maxIterations}).`, {\n code: \"workflow_max_iterations_exceeded\",\n isRetryable: false,\n });\n }\n}\n\n/** EC-4 absorbed — JSON.stringify failed on snapshot payload. */\nexport class WorkflowNotSerializableError extends TheokitAgentError {\n override readonly name = \"WorkflowNotSerializableError\";\n constructor(\n public readonly stepId: string,\n public readonly underlying: Error,\n ) {\n super(\n `Workflow snapshot at step \"${stepId}\" failed to serialize as JSON: ${underlying.message}. ` +\n `Persisted snapshots support only JSON-serializable values (no BigInt, no circular refs, no class instances with cycles).`,\n { code: \"workflow_not_serializable\", isRetryable: false },\n );\n }\n}\n\n/** EC-8 absorbed — `currentStepId` from snapshot not found in resumed workflow. */\nexport class WorkflowResumeStepNotFoundError extends TheokitAgentError {\n override readonly name = \"WorkflowResumeStepNotFoundError\";\n constructor(\n public readonly stepId: string,\n public readonly workflowName: string,\n ) {\n super(\n `Cannot resume: step \"${stepId}\" not found in workflow \"${workflowName}\". ` +\n `The Workflow definition diverged from the snapshot.`,\n { code: \"workflow_resume_step_not_found\", isRetryable: false },\n );\n }\n}\n\n/**\n * Thrown by `Workflow.resume()` (and so by a `workflowResumeTool` tool) when the snapshot for the run\n * id was written by a workflow of another name. The snapshot is left in the store, so the workflow\n * that suspended the run can still resume it.\n *\n * Without this check the default store, one process-global memory store, would let workflow B run\n * its own tail on workflow A's accumulated input whenever both declare a step with the suspended id.\n * `name` is a label, not an identity: two workflows that share a name are not told apart here.\n */\nexport class WorkflowResumeWorkflowMismatchError extends TheokitAgentError {\n override readonly name = \"WorkflowResumeWorkflowMismatchError\";\n constructor(\n public readonly runId: string,\n public readonly snapshotWorkflowName: string,\n public readonly workflowName: string,\n ) {\n super(\n `Cannot resume run \"${runId}\" with workflow \"${workflowName}\": ` +\n `the run was suspended by workflow \"${snapshotWorkflowName}\".`,\n { code: \"workflow_resume_workflow_mismatch\", isRetryable: false },\n );\n }\n}\n\n/**\n * Aggregate failure from parallel branches.\n *\n * THE ONE PUBLIC WORKFLOW ERROR STILL OUTSIDE THE SDK HIERARCHY, deliberately. Its ten siblings were\n * reparented onto `TheokitAgentError` so `isTransientError` — and therefore `Retry.create`'s default\n * predicate — can see them at all. This one cannot follow without ceasing to be an `AggregateError`,\n * and `instanceof AggregateError` plus the standard `errors` array is the whole reason a caller\n * catches it: they want the branch failures, not a single message.\n *\n * The cost is stated rather than hidden: `isTransientError(err)` is `false` for this class, so a\n * parallel step whose branches failed transiently is not retried by the SDK's own helper. Inspect\n * `err.errors` and decide per branch — which is what an aggregate asks of a caller anyway, since\n * \"should this be retried\" has no single answer when the branches failed for different reasons.\n */\nexport class WorkflowParallelError extends AggregateError {\n override readonly name = \"WorkflowParallelError\";\n constructor(\n errors: ReadonlyArray<Error>,\n public readonly stepId: string,\n ) {\n super(errors, `${errors.length} branch(es) failed in parallel step \"${stepId}\".`);\n }\n}\n\n/** D238 — saga engine not yet implemented. */\nexport class WorkflowCompensateNotImplementedError extends TheokitAgentError {\n override readonly name = \"WorkflowCompensateNotImplementedError\";\n constructor(public readonly stepId: string) {\n super(\n `Step \"${stepId}\" defines compensate, but saga engine is deferred to v1.2. ` +\n `Remove compensate or implement rollback manually.`,\n { code: \"workflow_compensate_not_implemented\", isRetryable: false },\n );\n }\n}\n","/**\n * Snapshot store interface + InMemory and JsonFile backends (ADR D235).\n *\n * EC-4 absorbed: serialization happens here. `JSON.stringify` failure raises\n * `WorkflowNotSerializableError` instead of letting the underlying `TypeError`\n * leak.\n *\n * @internal\n */\n\nimport { mkdir, readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { WorkflowOptions, WorkflowSnapshot } from \"../../types/workflow.js\";\nimport { WorkflowNotSerializableError } from \"../../workflow-errors.js\";\nimport { atomicWriteText } from \"../persistence/atomic-write.js\";\n\nexport interface WorkflowSnapshotStore {\n save(snapshot: WorkflowSnapshot): Promise<void>;\n load(runId: string): Promise<WorkflowSnapshot | undefined>;\n delete(runId: string): Promise<void>;\n list(\n workflowName?: string,\n ): Promise<ReadonlyArray<{ runId: string; workflowName: string; suspendedAt: number }>>;\n}\n\n/* ─── InMemory backend (default) ─── */\n\nclass InMemoryWorkflowSnapshotStore implements WorkflowSnapshotStore {\n private readonly map = new Map<string, WorkflowSnapshot>();\n\n async save(snapshot: WorkflowSnapshot): Promise<void> {\n // Verify serializability even in-memory so behavior is consistent with json backend.\n try {\n JSON.stringify(snapshot);\n } catch (err) {\n throw new WorkflowNotSerializableError(\n snapshot.currentStepId,\n err instanceof Error ? err : new Error(String(err)),\n );\n }\n this.map.set(snapshot.runId, snapshot);\n }\n async load(runId: string): Promise<WorkflowSnapshot | undefined> {\n return this.map.get(runId);\n }\n async delete(runId: string): Promise<void> {\n this.map.delete(runId);\n }\n async list(\n workflowName?: string,\n ): Promise<ReadonlyArray<{ runId: string; workflowName: string; suspendedAt: number }>> {\n return [...this.map.values()]\n .filter((s) => workflowName === undefined || s.workflowName === workflowName)\n .map((s) => ({\n runId: s.runId,\n workflowName: s.workflowName,\n suspendedAt: s.suspendedAt,\n }));\n }\n}\n\n/* ─── Json file backend (opt-in) ─── */\n\nclass JsonFileWorkflowSnapshotStore implements WorkflowSnapshotStore {\n constructor(private readonly dir: string) {}\n\n private filePath(runId: string): string {\n return join(this.dir, `${runId}.json`);\n }\n\n async save(snapshot: WorkflowSnapshot): Promise<void> {\n let serialized: string;\n try {\n serialized = JSON.stringify(snapshot);\n } catch (err) {\n throw new WorkflowNotSerializableError(\n snapshot.currentStepId,\n err instanceof Error ? err : new Error(String(err)),\n );\n }\n await mkdir(this.dir, { recursive: true });\n await atomicWriteText(this.filePath(snapshot.runId), serialized);\n }\n\n async load(runId: string): Promise<WorkflowSnapshot | undefined> {\n try {\n const raw = await readFile(this.filePath(runId), \"utf8\");\n return JSON.parse(raw) as WorkflowSnapshot;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw err;\n }\n }\n\n async delete(runId: string): Promise<void> {\n try {\n await (await import(\"node:fs/promises\")).unlink(this.filePath(runId));\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") throw err;\n }\n }\n\n private async readEntriesOrEmpty(): Promise<string[]> {\n try {\n return await readdir(this.dir);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw err;\n }\n }\n\n private async readSnapshotSafe(file: string): Promise<WorkflowSnapshot | undefined> {\n try {\n const raw = await readFile(join(this.dir, file), \"utf8\");\n return JSON.parse(raw) as WorkflowSnapshot;\n } catch {\n return undefined;\n }\n }\n\n async list(\n workflowName?: string,\n ): Promise<ReadonlyArray<{ runId: string; workflowName: string; suspendedAt: number }>> {\n const entries = await this.readEntriesOrEmpty();\n const results: Array<{ runId: string; workflowName: string; suspendedAt: number }> = [];\n for (const file of entries) {\n if (!file.endsWith(\".json\")) continue;\n const snap = await this.readSnapshotSafe(file);\n if (snap === undefined) continue;\n if (workflowName !== undefined && snap.workflowName !== workflowName) continue;\n results.push({\n runId: snap.runId,\n workflowName: snap.workflowName,\n suspendedAt: snap.suspendedAt,\n });\n }\n return results;\n }\n}\n\n/* ─── Resolver: per-Workflow store cache ─── */\n\nconst memoryStore = new InMemoryWorkflowSnapshotStore();\nconst jsonStores = new Map<string, JsonFileWorkflowSnapshotStore>();\n\nexport function getSnapshotStoreFor(options: WorkflowOptions): WorkflowSnapshotStore {\n if (options.persistence?.backend === \"json\") {\n const dir = options.persistence.dir as string; // schema enforces dir is set\n let store = jsonStores.get(dir);\n if (store === undefined) {\n store = new JsonFileWorkflowSnapshotStore(dir);\n jsonStores.set(dir, store);\n }\n return store;\n }\n return memoryStore;\n}\n\n/** Test seam — clear in-memory store between tests. */\nexport function __resetSnapshotStoresForTests(): void {\n jsonStores.clear();\n // memoryStore has private map; reset via assignment.\n // biome-ignore lint/suspicious/noExplicitAny: test-only seam\n (memoryStore as any).map.clear();\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkYJNYDJ2T_cjs = require('./chunk-YJNYDJ2T.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkEOWIUDKG_cjs = require('./chunk-EOWIUDKG.cjs');
|
|
5
5
|
var chunkRNXXYF22_cjs = require('./chunk-RNXXYF22.cjs');
|
|
6
6
|
|
|
7
7
|
// src/internal/session/agent-session.ts
|
|
@@ -44,11 +44,11 @@ function persistTurnToTranscript(store, loc, sessionId, turn, onCompact) {
|
|
|
44
44
|
const key = chunkYJNYDJ2T_cjs.transcriptKey(loc.cwd, loc.agentId);
|
|
45
45
|
const chained = (pendingWrites.get(key) ?? Promise.resolve()).then(async () => {
|
|
46
46
|
try {
|
|
47
|
-
await
|
|
47
|
+
await chunkEOWIUDKG_cjs.persistTurn(store, loc, sessionId, turn);
|
|
48
48
|
const count = (recordCounts.get(key) ?? 0) + 1;
|
|
49
49
|
recordCounts.set(key, count);
|
|
50
50
|
if (turn.autoCompact !== void 0) {
|
|
51
|
-
const { autoCompactIfNeeded } = await import('./compact-session-
|
|
51
|
+
const { autoCompactIfNeeded } = await import('./compact-session-5DWFHMW4.cjs');
|
|
52
52
|
const fired = await autoCompactIfNeeded({
|
|
53
53
|
store,
|
|
54
54
|
loc,
|
|
@@ -78,7 +78,7 @@ async function hydrateSession(agentId, loc) {
|
|
|
78
78
|
const key = chunkYJNYDJ2T_cjs.transcriptKey(loc.cwd, agentId);
|
|
79
79
|
if (chunkYJNYDJ2T_cjs.hydratedKeys.has(key)) return;
|
|
80
80
|
chunkYJNYDJ2T_cjs.hydratedKeys.add(key);
|
|
81
|
-
const persisted = await
|
|
81
|
+
const persisted = await chunkEOWIUDKG_cjs.readSessionMessages(loc.store, agentId);
|
|
82
82
|
if (persisted.length === 0) return;
|
|
83
83
|
chunkYJNYDJ2T_cjs.sessions.set(agentId, persisted);
|
|
84
84
|
}
|
|
@@ -114,5 +114,5 @@ exports.flushSessionWrites = flushSessionWrites;
|
|
|
114
114
|
exports.getSessionMessages = getSessionMessages;
|
|
115
115
|
exports.hydrateSession = hydrateSession;
|
|
116
116
|
exports.persistTurnToTranscript = persistTurnToTranscript;
|
|
117
|
-
//# sourceMappingURL=chunk-
|
|
118
|
-
//# sourceMappingURL=chunk-
|
|
117
|
+
//# sourceMappingURL=chunk-PDFSLD5P.cjs.map
|
|
118
|
+
//# sourceMappingURL=chunk-PDFSLD5P.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/session/agent-session.ts"],"names":["sessions","transcriptKey","hydratedKeys","persistTurn","diag","readSessionMessages"],"mappings":"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","file":"chunk-FBIDOOJM.cjs","sourcesContent":["import type { SessionStore } from \"../../types/session-store.js\";\nimport {\n type PersistTurnInput,\n persistTurn,\n readSessionMessages,\n type TranscriptLocation,\n} from \"./agent-session-store.js\";\n\n/**\n * Per-agent conversation history kept across runs (and across `Agent.resume()`\n * within the same process). Lets the fixture responder recall prior facts when\n * the user asks a follow-up question.\n *\n * SE40 — disk persistence IS the native Claude-shaped `.jsonl` transcript. The\n * in-memory cache holds the narrowed `SessionMessage[]` (user/assistant text) so\n * a send can read `priorMessages` synchronously; the whole rich turn (user +\n * assistant + tool blocks) lands on disk once per send via {@link persistTurnToTranscript}\n * (fed by `run.conversation()`). Hydration on resume reconstructs the session by\n * walking the transcript DAG (`readSessionMessages`).\n *\n * @internal\n */\n\n// `SessionMessage` lives in `./session-types.ts` (leaf types file). Re-exported\n// for back-compat with downstream importers that pulled it from here.\nexport type { SessionMessage } from \"./types.js\";\n\nimport type { SessionMessage } from \"./types.js\";\n\n// M75 — the cache lives in a leaf; see session-cache.ts for the reason (cycle broken by extraction).\nexport {\n hydratedKeys,\n invalidateSessionCache,\n sessions,\n transcriptKey,\n} from \"./session-cache.js\";\n\nimport { diag } from \"../diagnostics.js\";\nimport { globalSingleton } from \"../global-singleton.js\";\nimport { hydratedKeys, sessions, transcriptKey } from \"./session-cache.js\";\n\nconst pendingWrites = new Map<string, Promise<void>>();\nconst recordCounts = new Map<string, number>();\n\n/**\n * Append a session message to the in-memory cache only. Disk persistence for the\n * whole turn happens once per send via {@link persistTurnToTranscript}; the cache\n * feeds `priorMessages` / `onBeforeSend.previousMessageCount` synchronously.\n *\n * @internal\n */\nexport function appendSessionMessage(agentId: string, message: SessionMessage): void {\n const existing = sessions.get(agentId) ?? [];\n existing.push(message);\n // `delete` + `set` reinserts at the END: a JS `Map` preserves insertion order, so the first key\n // is always the least recently touched. That is the entire LRU, with no new structure (parsimony\n // rungs 2/5 — the ordering we need is already a language guarantee).\n sessions.delete(agentId);\n sessions.set(agentId, existing);\n enforceCeiling();\n}\n\n/**\n * Ceiling on sessions kept in memory.\n *\n * The runtime only reads the **active** session; the rest is pure cache, rebuildable from the\n * on-disk transcript. 32 is deliberately generous — the primary removal path is the explicit\n * `discardSession()` at the end of the agent's life, and this ceiling is a safety net against a\n * long-lived process running hundreds of sessions (plan risk #2: a tight ceiling could evict a\n * session still referenced by an in-flight async path).\n */\nexport const MAX_CACHED_SESSIONS = 32;\n\nfunction enforceCeiling(): void {\n while (sessions.size > MAX_CACHED_SESSIONS) {\n const oldest = sessions.keys().next().value;\n if (oldest === undefined) return;\n sessions.delete(oldest);\n forgetBookkeeping(oldest);\n }\n}\n\n/**\n * Erases the bookkeeping for an `agentId` across EVERY `cwd` it appears in.\n *\n * The three maps are keyed by `transcriptKey(cwd, agentId)`; `sessions` is the only one keyed by the\n * raw `agentId`. The ceiling's first version deleted from all three using `sessions`' key — that is,\n * deleted nothing — and left `hydratedKeys` **orphaned**. Since `hydrateSession` returns early when\n * the marker is present, an evicted session came back **empty** instead of rehydrating from disk:\n * silent amnesia, and a regression new to M95, because before it nothing evicted.\n *\n * The ceiling only knows the `agentId`, not the `cwd`, so it scans by suffix — which is the format\n * `transcriptKey` produces. A scan rather than an index because these maps hold tens of entries, not\n * thousands: a reverse index here would be new structure for a problem that does not exist.\n */\nfunction forgetBookkeeping(agentId: string): void {\n const suffix = transcriptKey(\"\", agentId).slice(0 - agentId.length - 2);\n for (const k of [...hydratedKeys]) if (k.endsWith(suffix)) hydratedKeys.delete(k);\n for (const k of [...pendingWrites.keys()]) if (k.endsWith(suffix)) pendingWrites.delete(k);\n for (const k of [...recordCounts.keys()]) if (k.endsWith(suffix)) recordCounts.delete(k);\n}\n\n/**\n * Erases the agent's module bookkeeping and returns how many entries were removed.\n *\n * M95 — `invalidateSessionCache` used to clear **two** of the four maps (`sessions`, `hydratedKeys`);\n * `pendingWrites` and `recordCounts` were never touched by id, so they grew for the life of the\n * process. Neither is large per entry — the leak is in count, not volume — but a cache with no owner\n * for removal is a cache that only grows.\n *\n * Returns the count so the caller can prove the removal; a second discard returns 0, which is what\n * makes the idempotency test possible without exposing the maps.\n */\nexport function discardSession(cwd: string, agentId: string): number {\n const key = transcriptKey(cwd, agentId);\n let removed = 0;\n // `sessions` is NOT erased here — and the distinction is measured, not aesthetic. It holds the\n // readable conversation, and there is a legitimate reader AFTER dispose: the golden\n // `two-concurrent-sends-serialize` calls `getSessionMessages(agentId)` after `agent.dispose()`.\n // Erasing it here returned an empty list and broke two goldens. What bounds it is the LRU ceiling\n // above; the three below are pure bookkeeping, with no post-dispose reader.\n //\n // The key is `transcriptKey(cwd, agentId)` in ALL THREE — not the raw `agentId`. The first version\n // erased two of them by `agentId` and therefore **never erased anything**; the test did not catch\n // it because it only asserted that the SECOND call returns 0, which is true either way.\n if (hydratedKeys.delete(key)) removed++;\n if (pendingWrites.delete(key)) removed++;\n if (recordCounts.delete(key)) removed++;\n return removed;\n}\n\nexport function getSessionMessages(agentId: string): SessionMessage[] {\n return sessions.get(agentId) ?? [];\n}\n\n/**\n * Persist a full conversation turn (user + assistant + tool blocks) to the native\n * transcript. Chained per-(agent, transcript) so on-disk order matches send order,\n * and fire-and-forget so `send()` is not blocked by disk I/O. Every\n * M50 — when the caller supplies `turn.autoCompact`, size-driven auto-compaction (usage real vs\n * the model's context window) runs in this same chain, surfaced via the optional `onCompact` observer.\n *\n * @internal\n */\nexport function persistTurnToTranscript(\n store: SessionStore,\n loc: TranscriptLocation,\n sessionId: string,\n turn: PersistTurnInput,\n onCompact?: () => void,\n): void {\n const key = transcriptKey(loc.cwd, loc.agentId);\n // PRE-EXISTING debt, exposed when M75 fixed the Biome config that used to abort before\n // sweeping these files (a nested root under refactor/). It is not new code and was not touched\n // by M75; refactoring SDK internals without review would trade a visible problem for a diff\n // risky. Tracked in usetheodev/theokit-sdk#151.\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: see the reason just above\n const chained = (pendingWrites.get(key) ?? Promise.resolve()).then(async () => {\n try {\n await persistTurn(store, loc, sessionId, turn);\n const count = (recordCounts.get(key) ?? 0) + 1;\n recordCounts.set(key, count);\n // M50 — the 50-turn no-summary boundary stub is GONE (it silently amnesia'd the session).\n // Auto-compaction is now size-driven with a real summary: see `maybeAutoCompact` below,\n // invoked in this same write chain by the post-run lifecycle when usage is known.\n if (turn.autoCompact !== undefined) {\n const { autoCompactIfNeeded } = await import(\"./compact-session.js\");\n const fired = await autoCompactIfNeeded({\n store,\n loc,\n sessionId,\n usageTotal: turn.autoCompact.usageTotal,\n contextWindow: turn.autoCompact.contextWindow,\n turnCount: count,\n summarize: turn.autoCompact.summarize,\n });\n if (fired) onCompact?.();\n }\n } catch (cause) {\n const msg = cause instanceof Error ? cause.message : String(cause);\n diag(`[theokit-sdk] session transcript write failed (${loc.agentId}): ${msg}\\n`);\n }\n });\n pendingWrites.set(\n key,\n chained.then(\n () => undefined,\n () => undefined,\n ),\n );\n}\n\n/**\n * Load the persisted transcript into the in-memory cache. Idempotent per\n * (baseDir, cwd, agentId). Call once per agent lifecycle before the first read.\n *\n * @internal\n */\nexport async function hydrateSession(\n agentId: string,\n loc: { store: SessionStore; cwd: string },\n): Promise<void> {\n const key = transcriptKey(loc.cwd, agentId);\n if (hydratedKeys.has(key)) return;\n hydratedKeys.add(key);\n\n const persisted = await readSessionMessages(loc.store, agentId);\n if (persisted.length === 0) return;\n // M51 review F4 — the DISK is the source of truth at hydration time: after an invalidation\n // (compact/inject), an in-flight turn may have repopulated the cache with a SINGLE message before\n // this hydrate ran; the old \"skip when non-empty\" guard then pinned the parent to a 1-message\n // context (history + injected pair lost until restart). The persist chain serializes writes, so\n // the disk already contains that in-flight turn — replacing is always correct.\n sessions.set(agentId, persisted);\n}\n\n/**\n * Wait for all pending transcript writes to settle. Used by tests and by the\n * agent dispose path so on-disk state matches in-memory before the caller proceeds.\n *\n * @internal\n */\nexport async function flushSessionWrites(): Promise<void> {\n while (pendingWrites.size > 0) {\n const all = Array.from(pendingWrites.values());\n pendingWrites.clear();\n await Promise.all(all);\n }\n}\n\n/**\n * Drop the in-memory message cache for `agentId` and NOTHING else — the hydration marker in\n * `hydratedKeys` deliberately stays.\n *\n * That asymmetry is the feature, not an oversight, and it is what separates this from\n * `invalidateSessionCache`, which drops both. The single caller is the personality switch's\n * `reset: true` path (`internal/personality/switch.ts`): leaving the marker set makes\n * `hydrateSession` return early, so the next send starts from an EMPTY context instead of\n * replaying the pre-reset transcript off disk. Clearing the marker here would re-hydrate the\n * conversation the reset was asked to discard.\n *\n * The same shape read as a bug one function up: `forgetBookkeeping` documents an evicted session\n * coming back empty as \"silent amnesia\". The difference is intent — eviction wants the transcript\n * back, a reset does not. Anyone reaching for this to invalidate a cache wants\n * `invalidateSessionCache(cwd, agentId)` instead.\n */\nexport function clearSession(agentId: string): void {\n sessions.delete(agentId);\n}\n\n/**\n * M50 review F5 — run `fn` serialized on the SAME per-(cwd,agentId) write chain the per-turn\n * persistence uses, so a manual `Agent.compact` can never interleave with an in-flight turn's\n * writes (boundary landing mid-turn would orphan the turn from the replay).\n */\nexport function enqueueSessionWrite<T>(\n cwd: string,\n agentId: string,\n fn: () => Promise<T>,\n): Promise<T> {\n const key = transcriptKey(cwd, agentId);\n const prior = pendingWrites.get(key) ?? Promise.resolve();\n const result = prior.then(fn);\n pendingWrites.set(\n key,\n result.then(\n () => undefined,\n () => undefined,\n ),\n );\n return result;\n}\n\n/** Test-only: drop every cached session and hydration marker. @internal */\nexport function clearAllSessions(): void {\n sessions.clear();\n hydratedKeys.clear();\n recordCounts.clear();\n // M50 review F11 — the auto-compact attempt marks live on globalThis; tests reset them here.\n // Through the helper, with the SAME key compact-session.ts uses: two files hand-rolling one slot is\n // how two copies of a mechanism drift apart.\n globalSingleton(\n \"theokit-sdk.session.auto-compact-attempts\",\n () => new Map<string, number>(),\n ).clear();\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/internal/session/agent-session.ts"],"names":["sessions","transcriptKey","hydratedKeys","persistTurn","diag","readSessionMessages"],"mappings":"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","file":"chunk-PDFSLD5P.cjs","sourcesContent":["import type { SessionStore } from \"../../types/session-store.js\";\nimport {\n type PersistTurnInput,\n persistTurn,\n readSessionMessages,\n type TranscriptLocation,\n} from \"./agent-session-store.js\";\n\n/**\n * Per-agent conversation history kept across runs (and across `Agent.resume()`\n * within the same process). Lets the fixture responder recall prior facts when\n * the user asks a follow-up question.\n *\n * SE40 — disk persistence IS the native Claude-shaped `.jsonl` transcript. The\n * in-memory cache holds the narrowed `SessionMessage[]` (user/assistant text) so\n * a send can read `priorMessages` synchronously; the whole rich turn (user +\n * assistant + tool blocks) lands on disk once per send via {@link persistTurnToTranscript}\n * (fed by `run.conversation()`). Hydration on resume reconstructs the session by\n * walking the transcript DAG (`readSessionMessages`).\n *\n * @internal\n */\n\n// `SessionMessage` lives in `./session-types.ts` (leaf types file). Re-exported\n// for back-compat with downstream importers that pulled it from here.\nexport type { SessionMessage } from \"./types.js\";\n\nimport type { SessionMessage } from \"./types.js\";\n\n// M75 — the cache lives in a leaf; see session-cache.ts for the reason (cycle broken by extraction).\nexport {\n hydratedKeys,\n invalidateSessionCache,\n sessions,\n transcriptKey,\n} from \"./session-cache.js\";\n\nimport { diag } from \"../diagnostics.js\";\nimport { globalSingleton } from \"../global-singleton.js\";\nimport { hydratedKeys, sessions, transcriptKey } from \"./session-cache.js\";\n\nconst pendingWrites = new Map<string, Promise<void>>();\nconst recordCounts = new Map<string, number>();\n\n/**\n * Append a session message to the in-memory cache only. Disk persistence for the\n * whole turn happens once per send via {@link persistTurnToTranscript}; the cache\n * feeds `priorMessages` / `onBeforeSend.previousMessageCount` synchronously.\n *\n * @internal\n */\nexport function appendSessionMessage(agentId: string, message: SessionMessage): void {\n const existing = sessions.get(agentId) ?? [];\n existing.push(message);\n // `delete` + `set` reinserts at the END: a JS `Map` preserves insertion order, so the first key\n // is always the least recently touched. That is the entire LRU, with no new structure (parsimony\n // rungs 2/5 — the ordering we need is already a language guarantee).\n sessions.delete(agentId);\n sessions.set(agentId, existing);\n enforceCeiling();\n}\n\n/**\n * Ceiling on sessions kept in memory.\n *\n * The runtime only reads the **active** session; the rest is pure cache, rebuildable from the\n * on-disk transcript. 32 is deliberately generous — the primary removal path is the explicit\n * `discardSession()` at the end of the agent's life, and this ceiling is a safety net against a\n * long-lived process running hundreds of sessions (plan risk #2: a tight ceiling could evict a\n * session still referenced by an in-flight async path).\n */\nexport const MAX_CACHED_SESSIONS = 32;\n\nfunction enforceCeiling(): void {\n while (sessions.size > MAX_CACHED_SESSIONS) {\n const oldest = sessions.keys().next().value;\n if (oldest === undefined) return;\n sessions.delete(oldest);\n forgetBookkeeping(oldest);\n }\n}\n\n/**\n * Erases the bookkeeping for an `agentId` across EVERY `cwd` it appears in.\n *\n * The three maps are keyed by `transcriptKey(cwd, agentId)`; `sessions` is the only one keyed by the\n * raw `agentId`. The ceiling's first version deleted from all three using `sessions`' key — that is,\n * deleted nothing — and left `hydratedKeys` **orphaned**. Since `hydrateSession` returns early when\n * the marker is present, an evicted session came back **empty** instead of rehydrating from disk:\n * silent amnesia, and a regression new to M95, because before it nothing evicted.\n *\n * The ceiling only knows the `agentId`, not the `cwd`, so it scans by suffix — which is the format\n * `transcriptKey` produces. A scan rather than an index because these maps hold tens of entries, not\n * thousands: a reverse index here would be new structure for a problem that does not exist.\n */\nfunction forgetBookkeeping(agentId: string): void {\n const suffix = transcriptKey(\"\", agentId).slice(0 - agentId.length - 2);\n for (const k of [...hydratedKeys]) if (k.endsWith(suffix)) hydratedKeys.delete(k);\n for (const k of [...pendingWrites.keys()]) if (k.endsWith(suffix)) pendingWrites.delete(k);\n for (const k of [...recordCounts.keys()]) if (k.endsWith(suffix)) recordCounts.delete(k);\n}\n\n/**\n * Erases the agent's module bookkeeping and returns how many entries were removed.\n *\n * M95 — `invalidateSessionCache` used to clear **two** of the four maps (`sessions`, `hydratedKeys`);\n * `pendingWrites` and `recordCounts` were never touched by id, so they grew for the life of the\n * process. Neither is large per entry — the leak is in count, not volume — but a cache with no owner\n * for removal is a cache that only grows.\n *\n * Returns the count so the caller can prove the removal; a second discard returns 0, which is what\n * makes the idempotency test possible without exposing the maps.\n */\nexport function discardSession(cwd: string, agentId: string): number {\n const key = transcriptKey(cwd, agentId);\n let removed = 0;\n // `sessions` is NOT erased here — and the distinction is measured, not aesthetic. It holds the\n // readable conversation, and there is a legitimate reader AFTER dispose: the golden\n // `two-concurrent-sends-serialize` calls `getSessionMessages(agentId)` after `agent.dispose()`.\n // Erasing it here returned an empty list and broke two goldens. What bounds it is the LRU ceiling\n // above; the three below are pure bookkeeping, with no post-dispose reader.\n //\n // The key is `transcriptKey(cwd, agentId)` in ALL THREE — not the raw `agentId`. The first version\n // erased two of them by `agentId` and therefore **never erased anything**; the test did not catch\n // it because it only asserted that the SECOND call returns 0, which is true either way.\n if (hydratedKeys.delete(key)) removed++;\n if (pendingWrites.delete(key)) removed++;\n if (recordCounts.delete(key)) removed++;\n return removed;\n}\n\nexport function getSessionMessages(agentId: string): SessionMessage[] {\n return sessions.get(agentId) ?? [];\n}\n\n/**\n * Persist a full conversation turn (user + assistant + tool blocks) to the native\n * transcript. Chained per-(agent, transcript) so on-disk order matches send order,\n * and fire-and-forget so `send()` is not blocked by disk I/O. Every\n * M50 — when the caller supplies `turn.autoCompact`, size-driven auto-compaction (usage real vs\n * the model's context window) runs in this same chain, surfaced via the optional `onCompact` observer.\n *\n * @internal\n */\nexport function persistTurnToTranscript(\n store: SessionStore,\n loc: TranscriptLocation,\n sessionId: string,\n turn: PersistTurnInput,\n onCompact?: () => void,\n): void {\n const key = transcriptKey(loc.cwd, loc.agentId);\n // PRE-EXISTING debt, exposed when M75 fixed the Biome config that used to abort before\n // sweeping these files (a nested root under refactor/). It is not new code and was not touched\n // by M75; refactoring SDK internals without review would trade a visible problem for a diff\n // risky. Tracked in usetheodev/theokit-sdk#151.\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: see the reason just above\n const chained = (pendingWrites.get(key) ?? Promise.resolve()).then(async () => {\n try {\n await persistTurn(store, loc, sessionId, turn);\n const count = (recordCounts.get(key) ?? 0) + 1;\n recordCounts.set(key, count);\n // M50 — the 50-turn no-summary boundary stub is GONE (it silently amnesia'd the session).\n // Auto-compaction is now size-driven with a real summary: see `maybeAutoCompact` below,\n // invoked in this same write chain by the post-run lifecycle when usage is known.\n if (turn.autoCompact !== undefined) {\n const { autoCompactIfNeeded } = await import(\"./compact-session.js\");\n const fired = await autoCompactIfNeeded({\n store,\n loc,\n sessionId,\n usageTotal: turn.autoCompact.usageTotal,\n contextWindow: turn.autoCompact.contextWindow,\n turnCount: count,\n summarize: turn.autoCompact.summarize,\n });\n if (fired) onCompact?.();\n }\n } catch (cause) {\n const msg = cause instanceof Error ? cause.message : String(cause);\n diag(`[theokit-sdk] session transcript write failed (${loc.agentId}): ${msg}\\n`);\n }\n });\n pendingWrites.set(\n key,\n chained.then(\n () => undefined,\n () => undefined,\n ),\n );\n}\n\n/**\n * Load the persisted transcript into the in-memory cache. Idempotent per\n * (baseDir, cwd, agentId). Call once per agent lifecycle before the first read.\n *\n * @internal\n */\nexport async function hydrateSession(\n agentId: string,\n loc: { store: SessionStore; cwd: string },\n): Promise<void> {\n const key = transcriptKey(loc.cwd, agentId);\n if (hydratedKeys.has(key)) return;\n hydratedKeys.add(key);\n\n const persisted = await readSessionMessages(loc.store, agentId);\n if (persisted.length === 0) return;\n // M51 review F4 — the DISK is the source of truth at hydration time: after an invalidation\n // (compact/inject), an in-flight turn may have repopulated the cache with a SINGLE message before\n // this hydrate ran; the old \"skip when non-empty\" guard then pinned the parent to a 1-message\n // context (history + injected pair lost until restart). The persist chain serializes writes, so\n // the disk already contains that in-flight turn — replacing is always correct.\n sessions.set(agentId, persisted);\n}\n\n/**\n * Wait for all pending transcript writes to settle. Used by tests and by the\n * agent dispose path so on-disk state matches in-memory before the caller proceeds.\n *\n * @internal\n */\nexport async function flushSessionWrites(): Promise<void> {\n while (pendingWrites.size > 0) {\n const all = Array.from(pendingWrites.values());\n pendingWrites.clear();\n await Promise.all(all);\n }\n}\n\n/**\n * Drop the in-memory message cache for `agentId` and NOTHING else — the hydration marker in\n * `hydratedKeys` deliberately stays.\n *\n * That asymmetry is the feature, not an oversight, and it is what separates this from\n * `invalidateSessionCache`, which drops both. The single caller is the personality switch's\n * `reset: true` path (`internal/personality/switch.ts`): leaving the marker set makes\n * `hydrateSession` return early, so the next send starts from an EMPTY context instead of\n * replaying the pre-reset transcript off disk. Clearing the marker here would re-hydrate the\n * conversation the reset was asked to discard.\n *\n * The same shape read as a bug one function up: `forgetBookkeeping` documents an evicted session\n * coming back empty as \"silent amnesia\". The difference is intent — eviction wants the transcript\n * back, a reset does not. Anyone reaching for this to invalidate a cache wants\n * `invalidateSessionCache(cwd, agentId)` instead.\n */\nexport function clearSession(agentId: string): void {\n sessions.delete(agentId);\n}\n\n/**\n * M50 review F5 — run `fn` serialized on the SAME per-(cwd,agentId) write chain the per-turn\n * persistence uses, so a manual `Agent.compact` can never interleave with an in-flight turn's\n * writes (boundary landing mid-turn would orphan the turn from the replay).\n */\nexport function enqueueSessionWrite<T>(\n cwd: string,\n agentId: string,\n fn: () => Promise<T>,\n): Promise<T> {\n const key = transcriptKey(cwd, agentId);\n const prior = pendingWrites.get(key) ?? Promise.resolve();\n const result = prior.then(fn);\n pendingWrites.set(\n key,\n result.then(\n () => undefined,\n () => undefined,\n ),\n );\n return result;\n}\n\n/** Test-only: drop every cached session and hydration marker. @internal */\nexport function clearAllSessions(): void {\n sessions.clear();\n hydratedKeys.clear();\n recordCounts.clear();\n // M50 review F11 — the auto-compact attempt marks live on globalThis; tests reset them here.\n // Through the helper, with the SAME key compact-session.ts uses: two files hand-rolling one slot is\n // how two copies of a mechanism drift apart.\n globalSingleton(\n \"theokit-sdk.session.auto-compact-attempts\",\n () => new Map<string, number>(),\n ).clear();\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { diagFailure } from './chunk-3OY6H3I7.js';
|
|
2
|
-
import { homedir } from 'os';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
import { existsSync } from 'fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
5
|
|
|
6
6
|
var THEOKIT_DIR_LITERAL = ".theokit";
|
|
7
7
|
var CLAUDE_DIR_NAME = ".claude";
|
|
@@ -132,5 +132,5 @@ function displayTheokitHome(cwd) {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
export { CLAUDE_DIR_NAME, THEOKIT_DIR_LITERAL, adapterForConfigPath, adaptersForSurface, displayTheokitHome, getProfilesRoot, getTheokitHome, pluginBundleRoots, projectConfigRoots, reportUndeclaredSources, theokitConfigRoot, undefinedVariablesIn };
|
|
135
|
-
//# sourceMappingURL=chunk-
|
|
136
|
-
//# sourceMappingURL=chunk-
|
|
135
|
+
//# sourceMappingURL=chunk-PISZRLES.js.map
|
|
136
|
+
//# sourceMappingURL=chunk-PISZRLES.js.map
|