@theokit/sdk 4.52.1 → 4.53.1
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 +48 -8
- package/LICENSE +2 -2
- package/README.md +5 -5
- package/bin/theokit-migrate-config.mjs +11 -2
- package/dist/{agent-BiCINq25.d.ts → agent-B9HXlwID.d.ts} +21 -8
- package/dist/agent-FFVV4U5N.js +50 -0
- package/dist/{agent-RDHK6MVT.js.map → agent-FFVV4U5N.js.map} +1 -1
- package/dist/agent-YLAHVHEH.cjs +59 -0
- package/dist/{agent-U2R2R5JP.cjs.map → agent-YLAHVHEH.cjs.map} +1 -1
- package/dist/{agent-Zta1kvGH.d.cts → agent-nLqeXKIX.d.cts} +21 -8
- package/dist/agent-session-store-DUGBAX5V.cjs +23 -0
- package/dist/{agent-session-store-EPX2WQI4.cjs.map → agent-session-store-DUGBAX5V.cjs.map} +1 -1
- package/dist/agent-session-store-TNCGL5RN.js +6 -0
- package/dist/{agent-session-store-JMU7ASDB.js.map → agent-session-store-TNCGL5RN.js.map} +1 -1
- package/dist/agent.d.ts +16 -1
- package/dist/auth/index.cjs +29 -28
- package/dist/auth/index.cjs.map +1 -1
- package/dist/auth/index.d.cts +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.js +6 -5
- package/dist/auth/index.js.map +1 -1
- package/dist/{batch-NLIS4QTW.js → batch-UPKN4SG6.js} +9 -9
- package/dist/{batch-NLIS4QTW.js.map → batch-UPKN4SG6.js.map} +1 -1
- package/dist/{batch-WQ3AJCDV.cjs → batch-ZEFN5SO7.cjs} +26 -26
- package/dist/{batch-WQ3AJCDV.cjs.map → batch-ZEFN5SO7.cjs.map} +1 -1
- package/dist/{chunk-CY7MIMI4.cjs → chunk-2D43RD5D.cjs} +8 -8
- package/dist/{chunk-CY7MIMI4.cjs.map → chunk-2D43RD5D.cjs.map} +1 -1
- package/dist/{chunk-WLESQ3ZQ.cjs → chunk-2FYEVT2B.cjs} +121 -121
- package/dist/{chunk-WLESQ3ZQ.cjs.map → chunk-2FYEVT2B.cjs.map} +1 -1
- package/dist/{chunk-BBZYXVLZ.cjs → chunk-2ZPEDVLM.cjs} +2 -2
- package/dist/chunk-2ZPEDVLM.cjs.map +1 -0
- package/dist/{chunk-T6QUCG7L.cjs → chunk-3BK6YR5P.cjs} +4 -4
- package/dist/{chunk-T6QUCG7L.cjs.map → chunk-3BK6YR5P.cjs.map} +1 -1
- package/dist/chunk-3V7UJLQT.js +147 -0
- package/dist/chunk-3V7UJLQT.js.map +1 -0
- package/dist/{chunk-ITQ4NO4P.js → chunk-3WVMJY7F.js} +3 -3
- package/dist/{chunk-ITQ4NO4P.js.map → chunk-3WVMJY7F.js.map} +1 -1
- package/dist/{chunk-RAACTJ7C.cjs → chunk-3X6PM7DU.cjs} +4 -4
- package/dist/{chunk-RAACTJ7C.cjs.map → chunk-3X6PM7DU.cjs.map} +1 -1
- package/dist/{chunk-DEZ75ET5.js → chunk-4Q4K4WB5.js} +3 -3
- package/dist/{chunk-DEZ75ET5.js.map → chunk-4Q4K4WB5.js.map} +1 -1
- package/dist/{chunk-4X3SBHPK.js → chunk-5F5NWKPN.js} +20 -4
- package/dist/chunk-5F5NWKPN.js.map +1 -0
- package/dist/chunk-5YKNEMXR.cjs +155 -0
- package/dist/chunk-5YKNEMXR.cjs.map +1 -0
- package/dist/{chunk-3YYDHUNH.cjs → chunk-665SFFFR.cjs} +11 -11
- package/dist/{chunk-3YYDHUNH.cjs.map → chunk-665SFFFR.cjs.map} +1 -1
- package/dist/{chunk-CHVSMEKM.js → chunk-6AZDM6LK.js} +3 -3
- package/dist/chunk-6AZDM6LK.js.map +1 -0
- package/dist/{chunk-AMYY3JHQ.cjs → chunk-ADLLFY3H.cjs} +9 -9
- package/dist/{chunk-AMYY3JHQ.cjs.map → chunk-ADLLFY3H.cjs.map} +1 -1
- package/dist/{chunk-J4RY5DTI.js → chunk-B6HOIWQ6.js} +5 -5
- package/dist/{chunk-J4RY5DTI.js.map → chunk-B6HOIWQ6.js.map} +1 -1
- package/dist/{chunk-EQMLJ52C.cjs → chunk-BDTVFIPB.cjs} +26 -26
- package/dist/{chunk-EQMLJ52C.cjs.map → chunk-BDTVFIPB.cjs.map} +1 -1
- package/dist/{chunk-UJ3SXRZZ.js → chunk-BERBYXFH.js} +3 -3
- package/dist/{chunk-UJ3SXRZZ.js.map → chunk-BERBYXFH.js.map} +1 -1
- package/dist/{chunk-KZBB4YKU.js → chunk-BFYGJGC5.js} +3 -3
- package/dist/{chunk-KZBB4YKU.js.map → chunk-BFYGJGC5.js.map} +1 -1
- package/dist/{chunk-SXSPMRSV.cjs → chunk-BM6N4KHO.cjs} +21 -3
- package/dist/chunk-BM6N4KHO.cjs.map +1 -0
- package/dist/{chunk-2CFEET3Y.cjs → chunk-C4H6PB5J.cjs} +4 -4
- package/dist/chunk-C4H6PB5J.cjs.map +1 -0
- package/dist/{chunk-NFATC6ZF.cjs → chunk-C5DEO6OI.cjs} +4 -4
- package/dist/{chunk-NFATC6ZF.cjs.map → chunk-C5DEO6OI.cjs.map} +1 -1
- package/dist/{chunk-EUBGGYPH.cjs → chunk-CZ2GKKYL.cjs} +5 -5
- package/dist/{chunk-EUBGGYPH.cjs.map → chunk-CZ2GKKYL.cjs.map} +1 -1
- package/dist/{chunk-I732VEDW.js → chunk-D24WJWN2.js} +3 -3
- package/dist/{chunk-I732VEDW.js.map → chunk-D24WJWN2.js.map} +1 -1
- package/dist/{chunk-3R4ZCQAZ.cjs → chunk-D75S2X6I.cjs} +5 -5
- package/dist/{chunk-3R4ZCQAZ.cjs.map → chunk-D75S2X6I.cjs.map} +1 -1
- package/dist/{chunk-5XXUYU3M.js → chunk-DGOG5NXR.js} +3 -3
- package/dist/{chunk-5XXUYU3M.js.map → chunk-DGOG5NXR.js.map} +1 -1
- package/dist/{chunk-RTLUZKDL.cjs → chunk-E7FJOO4G.cjs} +11 -11
- package/dist/{chunk-RTLUZKDL.cjs.map → chunk-E7FJOO4G.cjs.map} +1 -1
- package/dist/{chunk-BWGXYOBZ.cjs → chunk-ELKO4ZLR.cjs} +4 -4
- package/dist/{chunk-BWGXYOBZ.cjs.map → chunk-ELKO4ZLR.cjs.map} +1 -1
- package/dist/{chunk-FBZMSLDC.cjs → chunk-EZ2YEF4F.cjs} +4 -4
- package/dist/{chunk-FBZMSLDC.cjs.map → chunk-EZ2YEF4F.cjs.map} +1 -1
- package/dist/{chunk-6GS7JI64.cjs → chunk-F77UENR6.cjs} +343 -324
- package/dist/chunk-F77UENR6.cjs.map +1 -0
- package/dist/{chunk-OZXPA3ME.js → chunk-FFM3SJTQ.js} +4 -4
- package/dist/{chunk-OZXPA3ME.js.map → chunk-FFM3SJTQ.js.map} +1 -1
- package/dist/{chunk-PLUCC4N5.js → chunk-FIOCJYLA.js} +3 -3
- package/dist/{chunk-PLUCC4N5.js.map → chunk-FIOCJYLA.js.map} +1 -1
- package/dist/{chunk-Z5U2JGEK.cjs → chunk-FOXKFTVZ.cjs} +11 -11
- package/dist/{chunk-Z5U2JGEK.cjs.map → chunk-FOXKFTVZ.cjs.map} +1 -1
- package/dist/{chunk-K42QGAKM.cjs → chunk-FPYT5WZP.cjs} +10 -10
- package/dist/{chunk-K42QGAKM.cjs.map → chunk-FPYT5WZP.cjs.map} +1 -1
- package/dist/{chunk-KELIQH7K.js → chunk-G3JWXOGY.js} +78 -58
- package/dist/chunk-G3JWXOGY.js.map +1 -0
- package/dist/{chunk-DHVNJYTO.js → chunk-GBBDINFK.js} +3 -3
- package/dist/{chunk-DHVNJYTO.js.map → chunk-GBBDINFK.js.map} +1 -1
- package/dist/{chunk-V45L2OYP.cjs → chunk-GD63JPGC.cjs} +9 -9
- package/dist/{chunk-V45L2OYP.cjs.map → chunk-GD63JPGC.cjs.map} +1 -1
- package/dist/{chunk-42PLABFU.js → chunk-GOVJO4YE.js} +5 -5
- package/dist/{chunk-42PLABFU.js.map → chunk-GOVJO4YE.js.map} +1 -1
- package/dist/{chunk-CZHPR2G7.cjs → chunk-HAWE74GQ.cjs} +8 -8
- package/dist/{chunk-CZHPR2G7.cjs.map → chunk-HAWE74GQ.cjs.map} +1 -1
- package/dist/{chunk-KIX45IKP.js → chunk-HE4BIAOS.js} +4 -4
- package/dist/{chunk-KIX45IKP.js.map → chunk-HE4BIAOS.js.map} +1 -1
- package/dist/{chunk-AM2CNBKE.js → chunk-HKCKOAIO.js} +2 -2
- package/dist/chunk-HKCKOAIO.js.map +1 -0
- package/dist/{chunk-V2EJLKGA.js → chunk-HSQ5Q3I5.js} +10 -11
- package/dist/chunk-HSQ5Q3I5.js.map +1 -0
- package/dist/{chunk-QLAWEGTZ.cjs → chunk-JIQRXKTA.cjs} +7 -7
- package/dist/chunk-JIQRXKTA.cjs.map +1 -0
- package/dist/{chunk-EFXJ5C7X.js → chunk-KSWHTR54.js} +5 -5
- package/dist/{chunk-EFXJ5C7X.js.map → chunk-KSWHTR54.js.map} +1 -1
- package/dist/{chunk-6PTCKXD3.js → chunk-LD4MOBFX.js} +8 -8
- package/dist/{chunk-6PTCKXD3.js.map → chunk-LD4MOBFX.js.map} +1 -1
- package/dist/{chunk-2YGIBOUH.cjs → chunk-LPVIRJVF.cjs} +9 -9
- package/dist/chunk-LPVIRJVF.cjs.map +1 -0
- package/dist/{chunk-M5EK7N6R.js → chunk-LS3LMQ23.js} +9 -9
- package/dist/{chunk-M5EK7N6R.js.map → chunk-LS3LMQ23.js.map} +1 -1
- package/dist/{chunk-N43XLTHZ.js → chunk-LTSTGCL6.js} +3 -3
- package/dist/{chunk-N43XLTHZ.js.map → chunk-LTSTGCL6.js.map} +1 -1
- package/dist/{chunk-W4FV7JBH.js → chunk-MSFLYJDY.js} +4 -4
- package/dist/chunk-MSFLYJDY.js.map +1 -0
- package/dist/{chunk-C4EU627W.js → chunk-N5CR3TJZ.js} +4 -4
- package/dist/{chunk-C4EU627W.js.map → chunk-N5CR3TJZ.js.map} +1 -1
- package/dist/{chunk-NACDF3PK.js → chunk-NZL4BNFQ.js} +4 -4
- package/dist/chunk-NZL4BNFQ.js.map +1 -0
- package/dist/{chunk-OI6RHLGC.cjs → chunk-OUOXM36O.cjs} +11 -11
- package/dist/{chunk-OI6RHLGC.cjs.map → chunk-OUOXM36O.cjs.map} +1 -1
- package/dist/{chunk-BXVSBYGW.js → chunk-OY7O3Q6R.js} +5 -5
- package/dist/{chunk-BXVSBYGW.js.map → chunk-OY7O3Q6R.js.map} +1 -1
- package/dist/{chunk-L7EGRCKJ.js → chunk-PBZ7HMBP.js} +4 -4
- package/dist/{chunk-L7EGRCKJ.js.map → chunk-PBZ7HMBP.js.map} +1 -1
- package/dist/{chunk-OIBHY6JQ.js → chunk-PGP7IOJ2.js} +4 -4
- package/dist/{chunk-OIBHY6JQ.js.map → chunk-PGP7IOJ2.js.map} +1 -1
- package/dist/{chunk-R7TKOQMJ.js → chunk-POWRZSK4.js} +3 -3
- package/dist/{chunk-R7TKOQMJ.js.map → chunk-POWRZSK4.js.map} +1 -1
- package/dist/{chunk-R3CKCRK3.cjs → chunk-Q4RESANI.cjs} +4 -4
- package/dist/{chunk-R3CKCRK3.cjs.map → chunk-Q4RESANI.cjs.map} +1 -1
- package/dist/{chunk-ZNEE4WWQ.cjs → chunk-QBTVATSF.cjs} +25 -24
- package/dist/chunk-QBTVATSF.cjs.map +1 -0
- package/dist/{chunk-ZSJPRPN7.js → chunk-R5YZACGK.js} +3 -3
- package/dist/{chunk-ZSJPRPN7.js.map → chunk-R5YZACGK.js.map} +1 -1
- package/dist/{chunk-ADVZIC43.cjs → chunk-RAHSWE5C.cjs} +10 -10
- package/dist/{chunk-ADVZIC43.cjs.map → chunk-RAHSWE5C.cjs.map} +1 -1
- package/dist/{chunk-NOS7PTKP.js → chunk-SEL2ZQMT.js} +7 -7
- package/dist/{chunk-NOS7PTKP.js.map → chunk-SEL2ZQMT.js.map} +1 -1
- package/dist/{chunk-XWCTBGYK.js → chunk-SK4QLUBK.js} +3 -3
- package/dist/chunk-SK4QLUBK.js.map +1 -0
- package/dist/chunk-SSDD676S.js +171 -0
- package/dist/chunk-SSDD676S.js.map +1 -0
- package/dist/{chunk-E3OCRJU6.cjs → chunk-SVO5WPZX.cjs} +11 -11
- package/dist/{chunk-E3OCRJU6.cjs.map → chunk-SVO5WPZX.cjs.map} +1 -1
- package/dist/{chunk-44IISBRZ.cjs → chunk-SZHU7A5B.cjs} +4 -4
- package/dist/{chunk-44IISBRZ.cjs.map → chunk-SZHU7A5B.cjs.map} +1 -1
- package/dist/{chunk-SDJYLCJK.cjs → chunk-TTJ54H3E.cjs} +6 -6
- package/dist/chunk-TTJ54H3E.cjs.map +1 -0
- package/dist/{chunk-HI4ZW62S.js → chunk-U4UJHOSH.js} +4 -4
- package/dist/chunk-U4UJHOSH.js.map +1 -0
- package/dist/{chunk-XGYI2KQH.js → chunk-UFIXH26P.js} +4 -4
- package/dist/{chunk-XGYI2KQH.js.map → chunk-UFIXH26P.js.map} +1 -1
- package/dist/{chunk-JJZ4NIAG.js → chunk-V26QVGUG.js} +7 -6
- package/dist/chunk-V26QVGUG.js.map +1 -0
- package/dist/{chunk-GNPI5IWZ.js → chunk-V6HWJQQV.js} +6 -5
- package/dist/chunk-V6HWJQQV.js.map +1 -0
- package/dist/{chunk-MV4TOCUK.js → chunk-VC5ABJXC.js} +3 -3
- package/dist/{chunk-MV4TOCUK.js.map → chunk-VC5ABJXC.js.map} +1 -1
- package/dist/chunk-VF7X6HDR.cjs +177 -0
- package/dist/chunk-VF7X6HDR.cjs.map +1 -0
- package/dist/{chunk-7HQVDLFI.cjs → chunk-VGPXHHF3.cjs} +11 -9
- package/dist/chunk-VGPXHHF3.cjs.map +1 -0
- package/dist/{chunk-T6ZCG5AP.cjs → chunk-VUKQL3L2.cjs} +18 -19
- package/dist/chunk-VUKQL3L2.cjs.map +1 -0
- package/dist/{chunk-PVBANCWU.cjs → chunk-VW6M4B3Z.cjs} +5 -5
- package/dist/{chunk-PVBANCWU.cjs.map → chunk-VW6M4B3Z.cjs.map} +1 -1
- package/dist/{chunk-KNZU4YO5.cjs → chunk-WQ53UQL4.cjs} +4 -4
- package/dist/{chunk-KNZU4YO5.cjs.map → chunk-WQ53UQL4.cjs.map} +1 -1
- package/dist/{chunk-6DCTL32L.cjs → chunk-XPR366DL.cjs} +17 -17
- package/dist/{chunk-6DCTL32L.cjs.map → chunk-XPR366DL.cjs.map} +1 -1
- package/dist/{chunk-7TB5U7RK.js → chunk-XROIW6BH.js} +6 -6
- package/dist/{chunk-7TB5U7RK.js.map → chunk-XROIW6BH.js.map} +1 -1
- package/dist/{chunk-ECPL5RV6.cjs → chunk-Y4AXQOT4.cjs} +8 -8
- package/dist/{chunk-ECPL5RV6.cjs.map → chunk-Y4AXQOT4.cjs.map} +1 -1
- package/dist/{chunk-E6T264NS.js → chunk-Y4I4EQFK.js} +3 -3
- package/dist/{chunk-E6T264NS.js.map → chunk-Y4I4EQFK.js.map} +1 -1
- package/dist/{chunk-FUASIT3E.cjs → chunk-ZN2DGEY3.cjs} +15 -15
- package/dist/{chunk-FUASIT3E.cjs.map → chunk-ZN2DGEY3.cjs.map} +1 -1
- package/dist/{chunk-YTO5BRBD.cjs → chunk-ZT57WTUJ.cjs} +8 -8
- package/dist/chunk-ZT57WTUJ.cjs.map +1 -0
- package/dist/compact-session-4MNKNMO2.js +21 -0
- package/dist/{compact-session-XLXC2CZN.js.map → compact-session-4MNKNMO2.js.map} +1 -1
- package/dist/compact-session-EPFBQ46Z.cjs +58 -0
- package/dist/{compact-session-FBVWO6B3.cjs.map → compact-session-EPFBQ46Z.cjs.map} +1 -1
- package/dist/compaction.cjs +16 -16
- package/dist/compaction.js +3 -3
- package/dist/concurrency.cjs +6 -6
- package/dist/concurrency.js +4 -4
- package/dist/context-7USNN6LP.cjs +22 -0
- package/dist/{context-4HGPCOH6.cjs.map → context-7USNN6LP.cjs.map} +1 -1
- package/dist/context-ENXZNF6J.js +5 -0
- package/dist/{context-DCECDKWN.js.map → context-ENXZNF6J.js.map} +1 -1
- package/dist/{cron-DyWQsEG6.d.ts → cron-BMjgFH-_.d.ts} +1 -1
- package/dist/{cron-DgHJnMAK.d.cts → cron-DFDdCdMM.d.cts} +1 -1
- package/dist/cron.cjs +33 -32
- package/dist/cron.d.cts +2 -2
- package/dist/cron.d.ts +2 -2
- package/dist/cron.js +32 -31
- package/dist/errors.cjs +21 -21
- package/dist/errors.js +2 -2
- package/dist/eval.cjs +43 -42
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +33 -32
- package/dist/eval.js.map +1 -1
- package/dist/{executor-4SW7QGZ4.cjs → executor-2Z3LGG3I.cjs} +24 -24
- package/dist/{executor-4SW7QGZ4.cjs.map → executor-2Z3LGG3I.cjs.map} +1 -1
- package/dist/{executor-3CGPLVJL.js → executor-2Z6XJJJG.js} +7 -7
- package/dist/{executor-3CGPLVJL.js.map → executor-2Z6XJJJG.js.map} +1 -1
- package/dist/filesystem/index.cjs +7 -7
- package/dist/filesystem/index.js +3 -3
- package/dist/fs-session-store-R5FD3EN6.js +10 -0
- package/dist/{fs-session-store-2TF3ZWMT.js.map → fs-session-store-R5FD3EN6.js.map} +1 -1
- package/dist/fs-session-store-VVY2AHWG.cjs +19 -0
- package/dist/{fs-session-store-TL4RJTXZ.cjs.map → fs-session-store-VVY2AHWG.cjs.map} +1 -1
- package/dist/generate-object-AVXOJK2I.cjs +20 -0
- package/dist/{generate-object-E465DX5I.cjs.map → generate-object-AVXOJK2I.cjs.map} +1 -1
- package/dist/generate-object-WQRCXFD2.js +7 -0
- package/dist/{generate-object-TVQCW2IZ.js.map → generate-object-WQRCXFD2.js.map} +1 -1
- package/dist/index-manager-VRU3A2YL.cjs +21 -0
- package/dist/{index-manager-HGGL4DD5.cjs.map → index-manager-VRU3A2YL.cjs.map} +1 -1
- package/dist/index-manager-WS7TVKUW.js +12 -0
- package/dist/{index-manager-EA6FGIQG.js.map → index-manager-WS7TVKUW.js.map} +1 -1
- package/dist/index.cjs +143 -134
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -8
- package/dist/index.d.ts +64 -8
- package/dist/index.js +45 -44
- package/dist/index.js.map +1 -1
- package/dist/{inject-session-UBAQ7I3G.cjs → inject-session-AUQLBDRS.cjs} +9 -9
- package/dist/{inject-session-UBAQ7I3G.cjs.map → inject-session-AUQLBDRS.cjs.map} +1 -1
- package/dist/{inject-session-UEH5MAKU.js → inject-session-GMBMJVNZ.js} +7 -7
- package/dist/{inject-session-UEH5MAKU.js.map → inject-session-GMBMJVNZ.js.map} +1 -1
- package/dist/internal/auth/auth-types.d.ts +1 -1
- package/dist/internal/auth/oauth-device.d.ts +2 -2
- package/dist/internal/local-agent/mcp-pool.d.ts +2 -4
- package/dist/internal/mcp/oauth.d.ts +14 -0
- package/dist/internal/mcp/token-storage.d.ts +18 -0
- package/dist/internal/memory/adapters/index.cjs +8 -8
- package/dist/internal/memory/adapters/index.js +7 -7
- package/dist/internal/persistence/atomic-write.d.cts +93 -0
- package/dist/internal/persistence/atomic-write.d.ts +93 -0
- package/dist/internal/persistence/file-lock.d.cts +13 -1
- package/dist/internal/persistence/file-lock.d.ts +13 -1
- package/dist/internal/persistence/fts5-sanitize.d.cts +9 -1
- package/dist/internal/persistence/fts5-sanitize.d.ts +9 -1
- package/dist/internal/persistence/index.cjs +25 -25
- package/dist/internal/persistence/index.js +6 -6
- package/dist/internal/persistence/session-dir.d.cts +1 -0
- package/dist/internal/persistence/session-dir.d.ts +1 -0
- package/dist/internal/persistence/session-writer.d.cts +13 -0
- package/dist/internal/persistence/session-writer.d.ts +13 -0
- package/dist/internal/persistence/sqlite-wal.d.cts +9 -1
- package/dist/internal/persistence/sqlite-wal.d.ts +9 -1
- package/dist/internal/persistence/transcript-ops.d.cts +6 -7
- package/dist/internal/persistence/transcript-ops.d.ts +6 -7
- package/dist/internal/providers/builtin/cerebras.d.ts +2 -2
- package/dist/internal/providers/builtin/deepinfra.d.ts +1 -1
- package/dist/internal/providers/catalog-source-models-dev.d.ts +1 -1
- package/dist/internal/runtime/lifecycle/env-policy.d.ts +1 -3
- package/dist/internal/security/index.cjs +13 -13
- package/dist/internal/security/index.js +3 -3
- package/dist/internal/security/path-guard.d.cts +61 -0
- package/dist/internal/security/path-guard.d.ts +61 -0
- package/dist/internal/session/compact-session.d.ts +2 -2
- package/dist/internal/telemetry/tracer.d.ts +24 -0
- package/dist/judge-call-G5SGV2M2.cjs +22 -0
- package/dist/{judge-call-GVIJWQVE.cjs.map → judge-call-G5SGV2M2.cjs.map} +1 -1
- package/dist/judge-call-MDIPTBJI.js +5 -0
- package/dist/{judge-call-QMKGC2ZK.js.map → judge-call-MDIPTBJI.js.map} +1 -1
- package/dist/mcp-auth.cjs +299 -0
- package/dist/mcp-auth.cjs.map +1 -0
- package/dist/mcp-auth.d.cts +17 -0
- package/dist/mcp-auth.d.ts +17 -0
- package/dist/mcp-auth.js +292 -0
- package/dist/mcp-auth.js.map +1 -0
- package/dist/models.cjs +22 -21
- package/dist/models.cjs.map +1 -1
- package/dist/models.js +7 -6
- package/dist/models.js.map +1 -1
- package/dist/path-safety.cjs +10 -10
- package/dist/path-safety.js +3 -3
- package/dist/persistence.cjs +38 -29
- package/dist/persistence.cjs.map +1 -1
- package/dist/persistence.js +18 -9
- package/dist/persistence.js.map +1 -1
- package/dist/project.cjs +5 -5
- package/dist/project.js +3 -3
- package/dist/registry-63ASMXT4.cjs +46 -0
- package/dist/{registry-UBY26R4I.cjs.map → registry-63ASMXT4.cjs.map} +1 -1
- package/dist/registry-O7FJ2MPM.js +9 -0
- package/dist/{registry-GC7BQMSV.js.map → registry-O7FJ2MPM.js.map} +1 -1
- package/dist/retry.cjs +4 -4
- package/dist/retry.js +3 -3
- package/dist/sandbox/bwrap.d.cts +1 -2
- package/dist/sandbox/bwrap.d.ts +1 -2
- package/dist/sandbox/index.cjs +20 -20
- package/dist/sandbox/index.cjs.map +1 -1
- package/dist/sandbox/index.js +5 -5
- package/dist/sandbox/index.js.map +1 -1
- package/dist/server/errors-envelope.cjs +14 -14
- package/dist/server/errors-envelope.js +3 -3
- package/dist/session-transcript-DOM3UTXR.cjs +50 -0
- package/dist/{session-transcript-TNAJ4O3M.cjs.map → session-transcript-DOM3UTXR.cjs.map} +1 -1
- package/dist/session-transcript-RAKEK76V.js +5 -0
- package/dist/{session-transcript-SKIRBEJE.js.map → session-transcript-RAKEK76V.js.map} +1 -1
- package/dist/skills.cjs +7 -7
- package/dist/skills.js +5 -5
- package/dist/stream-object-L3Q7PBMF.cjs +20 -0
- package/dist/{stream-object-T4DAMNVB.cjs.map → stream-object-L3Q7PBMF.cjs.map} +1 -1
- package/dist/stream-object-ZYXWS4B2.js +7 -0
- package/dist/{stream-object-QMNR3YFF.js.map → stream-object-ZYXWS4B2.js.map} +1 -1
- package/dist/subagents-loader-I56GSKAQ.js +6 -0
- package/dist/{subagents-loader-WN2SB6PV.js.map → subagents-loader-I56GSKAQ.js.map} +1 -1
- package/dist/subagents-loader-VRW73QQT.cjs +15 -0
- package/dist/{subagents-loader-3CXBQWWY.cjs.map → subagents-loader-VRW73QQT.cjs.map} +1 -1
- package/dist/subagents-loader.cjs +6 -6
- package/dist/subagents-loader.d.cts +1 -1
- package/dist/subagents-loader.d.ts +1 -1
- package/dist/subagents-loader.js +4 -4
- package/dist/subscription/index.cjs +3 -3
- package/dist/subscription/index.js +2 -2
- package/dist/task-store.cjs +7 -7
- package/dist/task-store.js +4 -4
- package/dist/types/agent.d.ts +19 -6
- package/dist/types/provider-profile.d.ts +2 -2
- package/dist/workflow.cjs +27 -27
- package/dist/workflow.js +6 -6
- package/package.json +28 -18
- package/dist/agent-RDHK6MVT.js +0 -49
- package/dist/agent-U2R2R5JP.cjs +0 -58
- package/dist/agent-session-store-EPX2WQI4.cjs +0 -23
- package/dist/agent-session-store-JMU7ASDB.js +0 -6
- package/dist/chunk-2CFEET3Y.cjs.map +0 -1
- package/dist/chunk-2YGIBOUH.cjs.map +0 -1
- package/dist/chunk-4X3SBHPK.js.map +0 -1
- package/dist/chunk-6GS7JI64.cjs.map +0 -1
- package/dist/chunk-7HQVDLFI.cjs.map +0 -1
- package/dist/chunk-AM2CNBKE.js.map +0 -1
- package/dist/chunk-BBZYXVLZ.cjs.map +0 -1
- package/dist/chunk-BKRTYDVN.js +0 -312
- package/dist/chunk-BKRTYDVN.js.map +0 -1
- package/dist/chunk-CHVSMEKM.js.map +0 -1
- package/dist/chunk-GNPI5IWZ.js.map +0 -1
- package/dist/chunk-HI4ZW62S.js.map +0 -1
- package/dist/chunk-JJZ4NIAG.js.map +0 -1
- package/dist/chunk-KELIQH7K.js.map +0 -1
- package/dist/chunk-NACDF3PK.js.map +0 -1
- package/dist/chunk-QLAWEGTZ.cjs.map +0 -1
- package/dist/chunk-SDJYLCJK.cjs.map +0 -1
- package/dist/chunk-SXSPMRSV.cjs.map +0 -1
- package/dist/chunk-T6ZCG5AP.cjs.map +0 -1
- package/dist/chunk-V2EJLKGA.js.map +0 -1
- package/dist/chunk-W4FV7JBH.js.map +0 -1
- package/dist/chunk-XK54DTRF.cjs +0 -325
- package/dist/chunk-XK54DTRF.cjs.map +0 -1
- package/dist/chunk-XWCTBGYK.js.map +0 -1
- package/dist/chunk-YTO5BRBD.cjs.map +0 -1
- package/dist/chunk-ZNEE4WWQ.cjs.map +0 -1
- package/dist/compact-session-FBVWO6B3.cjs +0 -57
- package/dist/compact-session-XLXC2CZN.js +0 -20
- package/dist/context-4HGPCOH6.cjs +0 -22
- package/dist/context-DCECDKWN.js +0 -5
- package/dist/fs-session-store-2TF3ZWMT.js +0 -10
- package/dist/fs-session-store-TL4RJTXZ.cjs +0 -19
- package/dist/generate-object-E465DX5I.cjs +0 -20
- package/dist/generate-object-TVQCW2IZ.js +0 -7
- package/dist/index-manager-EA6FGIQG.js +0 -12
- package/dist/index-manager-HGGL4DD5.cjs +0 -21
- package/dist/judge-call-GVIJWQVE.cjs +0 -22
- package/dist/judge-call-QMKGC2ZK.js +0 -5
- package/dist/registry-GC7BQMSV.js +0 -9
- package/dist/registry-UBY26R4I.cjs +0 -46
- package/dist/session-transcript-SKIRBEJE.js +0 -5
- package/dist/session-transcript-TNAJ4O3M.cjs +0 -50
- package/dist/stream-object-QMNR3YFF.js +0 -7
- package/dist/stream-object-T4DAMNVB.cjs +0 -20
- package/dist/subagents-loader-3CXBQWWY.cjs +0 -15
- package/dist/subagents-loader-WN2SB6PV.js +0 -6
- package/docs/error-codes.md +0 -179
- package/docs/harness-capability-map.md +0 -304
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/runtime/compression/compression-helpers.ts","../src/compaction.ts"],"names":["TheokitAgentError","diag","redactSecrets"],"mappings":"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","file":"chunk-AMYY3JHQ.cjs","sourcesContent":["/**\n * Compression helpers (T2.3, ADR D92).\n *\n * Scaffold for future compression LLM integration:\n * - `selectCompressionWindow` — splits messages into compress/preserve halves\n * - `assertCompressionReduced` — 10% reduction floor to detect \"compression placebo\"\n *\n * The compression LLM call itself is out of scope for this plan (requires\n * an auxiliary-model ADR). These helpers are used by `Agent.send` when a\n * future iteration adds compression.\n *\n * @internal\n */\n\nexport interface CompressionWindow<M> {\n toCompress: M[];\n toPreserve: M[];\n}\n\n/**\n * Split `messages` into the half to compress (older) and the half to\n * preserve verbatim (recent). When `messages.length <= preserveLast`,\n * everything is preserved.\n *\n * @internal\n */\nexport function selectCompressionWindow<M>(\n messages: readonly M[],\n preserveLast = 6,\n): CompressionWindow<M> {\n if (messages.length <= preserveLast) {\n return { toCompress: [], toPreserve: [...messages] };\n }\n return {\n toCompress: messages.slice(0, -preserveLast),\n toPreserve: messages.slice(-preserveLast),\n };\n}\n\nexport interface CompressionCheck {\n reduced: boolean;\n reductionPct: number;\n reason?: string;\n}\n\n/**\n * Check that compression actually reduced token count by at least `minPct`\n * (default 10%). Returns `{ reduced: false }` for spirals-in-formation\n * (compression LLM outputs that grow or barely shrink).\n *\n * @internal\n */\nexport function assertCompressionReduced(\n before: number,\n after: number,\n minPct = 10,\n): CompressionCheck {\n if (before <= 0) {\n return { reduced: false, reductionPct: 0, reason: \"before count was zero\" };\n }\n const reductionPct = ((before - after) / before) * 100;\n if (reductionPct >= minPct) {\n return { reduced: true, reductionPct };\n }\n return {\n reduced: false,\n reductionPct,\n reason: `compression reduced ${reductionPct.toFixed(1)}% (< ${minPct}% min). Spiral likely.`,\n };\n}\n","/**\n * Public compaction / context-management helpers (M2-1, extended V3-3).\n *\n * Promotes the SDK's compaction capability to a public surface so consumers can\n * compact a transcript, mark/filter conversation checkpoints, and detect\n * context-overflow — without reaching into `internal/`.\n *\n * Two recent-window modes (V3-3):\n * - `keepRecent` (turn-count, default) — keeps the last N turns verbatim and\n * always preserves leading system PROMPTS; reuses the internal\n * `selectCompressionWindow` (no second algorithm).\n * - `keepTokens` (token-budget) — keeps the trailing turns whose accumulated\n * `estimateTokens` fits the budget (theocode `splitTranscript` semantics). In\n * this mode leading system prompts are NOT special-cased (D6).\n *\n * Summarization is delegated to a caller-supplied callback (which receives the\n * older window + the summary template). With `failSafe`, a thrown summarizer\n * returns the ORIGINAL transcript + a structured warn (compaction is an\n * optimization, never a cause of data loss); without it, the error propagates.\n *\n * Public from the `@theokit/sdk/compaction` sub-path.\n */\n\nimport { TheokitAgentError } from \"./errors.js\";\nimport { diag } from \"./internal/diagnostics.js\";\nimport { selectCompressionWindow } from \"./internal/runtime/compression/compression-helpers.js\";\nimport { redactSecrets } from \"./internal/security/redact.js\";\n\n/**\n * Minimal message shape for compaction/compression input. THE canonical public origin (leaf type —\n * rollup-plugin-dts cannot re-export types from internal modules into entry bundles; M42 lesson).\n *\n * @public\n */\nexport interface CompressibleMessage {\n role: \"user\" | \"assistant\" | \"system\";\n content: string;\n}\n\n/**\n * Sentinel prefix marking a conversation checkpoint turn. A visible, structured,\n * prose-unlikely token (no invisible/control bytes — safe to persist and to read\n * in source). Only {@link buildCheckpoint} should produce content beginning with it.\n */\nexport const CHECKPOINT_MARKER = \"[[theokit:checkpoint]] \";\n\n/**\n * The 7-section summary template handed to the `summarize` callback (theocode\n * parity shape). Every header is always present so the summarizer cannot silently\n * drop a category; the model is told to preserve file paths, commands, and error\n * text verbatim. Override per-call via {@link CompactTranscriptOptions.summaryTemplate}.\n */\nexport const SUMMARY_TEMPLATE = `Summarize the conversation so far into these sections (keep every header even if empty):\n\n## Goal\nWhat the user is ultimately trying to achieve.\n\n## Constraints\nHard requirements, conventions, and rules stated.\n\n## Progress\nWhat has been done so far.\n\n## Decisions\nChoices made and their rationale.\n\n## Next\nThe immediate next steps.\n\n## Critical\nAnything that MUST NOT be forgotten (preserve verbatim: error messages, exact values).\n\n## Files\nFile paths touched or referenced (verbatim).`;\n\n/** Reject an empty marker — it would match every turn via `startsWith(\"\")` (EC-3). */\nfunction assertMarker(marker: string): void {\n if (marker === \"\") {\n throw new TheokitAgentError(\"compaction marker must be non-empty\", {\n code: \"invalid_argument\",\n });\n }\n}\n\n/** True for a real system prompt — a `system` turn that is NOT a checkpoint marker. */\nfunction isSystemPrompt(message: CompressibleMessage, marker: string): boolean {\n return message.role === \"system\" && !message.content.startsWith(marker);\n}\n\n/** Carried split: leading system prompts (preserved), the older window, the verbatim tail. */\ninterface TranscriptSplit {\n systemPrompts: CompressibleMessage[];\n head: CompressibleMessage[];\n recent: CompressibleMessage[];\n}\n\n/**\n * Token-budget split (theocode `splitTranscript`): walk from the END accumulating\n * `estimateTokens` until `keepTokens` is exceeded; everything older is the head.\n * Always keeps ≥ 1 recent turn. No system-prompt special-casing (D6).\n */\nfunction selectByTokenBudget(\n messages: CompressibleMessage[],\n keepTokens: number,\n): { head: CompressibleMessage[]; recent: CompressibleMessage[] } {\n let acc = 0;\n let splitIndex = messages.length;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n acc += estimateTokens(messages[i]?.content ?? \"\");\n if (acc > keepTokens && i < messages.length - 1) {\n splitIndex = i + 1;\n break;\n }\n splitIndex = i;\n }\n return { head: messages.slice(0, splitIndex), recent: messages.slice(splitIndex) };\n}\n\n/** Turn-count split (M2): preserve leading system prompts; window the rest by `keepRecent`. */\nfunction splitByRecent(\n messages: CompressibleMessage[],\n keepRecent: number,\n marker: string,\n): TranscriptSplit {\n const systemPrompts = messages.filter((m) => isSystemPrompt(m, marker));\n const rest = messages.filter((m) => !isSystemPrompt(m, marker));\n const { toCompress, toPreserve } = selectCompressionWindow(rest, keepRecent);\n return { systemPrompts, head: toCompress, recent: toPreserve };\n}\n\n/** Options for {@link compactTranscript}. */\nexport interface CompactTranscriptOptions {\n /** Trailing turns preserved verbatim by COUNT (default 6). Ignored when `keepTokens` is set. */\n keepRecent?: number;\n /**\n * Trailing turns preserved verbatim by TOKEN BUDGET (theocode mode). When set,\n * takes precedence over `keepRecent` and disables system-prompt preservation (D6).\n */\n keepTokens?: number;\n /** Checkpoint marker (default {@link CHECKPOINT_MARKER}). Must be non-empty. */\n marker?: string;\n /** Summary template passed to `summarize` (default {@link SUMMARY_TEMPLATE}). */\n summaryTemplate?: string;\n /** Summarize the older window into one turn; if omitted, the older window is dropped. */\n summarize?: (older: CompressibleMessage[], template: string) => Promise<CompressibleMessage>;\n /**\n * When true, a thrown `summarize` returns the ORIGINAL transcript + a structured\n * warn (compaction never loses data). Default false: the error propagates.\n */\n failSafe?: boolean;\n}\n\n/** Sentinel returned by {@link runSummarize} when fail-safe swallowed a throw. */\nconst FAILSAFE_ABORT = Symbol(\"failsafe-abort\");\n\n/** Run the summarizer; on throw, either propagate or (fail-safe) warn + signal abort. */\nasync function runSummarize(\n summarize: NonNullable<CompactTranscriptOptions[\"summarize\"]>,\n head: CompressibleMessage[],\n template: string,\n failSafe: boolean,\n): Promise<CompressibleMessage | typeof FAILSAFE_ABORT> {\n try {\n return await summarize(head, template);\n } catch (err) {\n if (!failSafe) throw err;\n // Unbreakable Rule 8 — never fail silently. The breadcrumb points at the root\n // cause when a summarizer fails every turn and context grows unchecked. The\n // summarizer is caller-supplied, so its error text is routed through\n // `redactSecrets` (ADR D68 — no unredacted output sink in src/).\n // theokit#147 — through the interceptable channel. A summarizer failing every turn is exactly\n // the breadcrumb a TUI host wants in its own panel, not smeared across its alternate screen.\n diag(\n `[compaction] summarizer failed — proceeding uncompacted: ${redactSecrets(err instanceof Error ? err.message : String(err))}\\n`,\n );\n return FAILSAFE_ABORT;\n }\n}\n\n/**\n * Compact a transcript. In `keepRecent` mode (default) the last `keepRecent` turns\n * are kept verbatim and leading system PROMPTS preserved; in `keepTokens` mode the\n * trailing turns within the token budget are kept (no system special-casing, D6).\n * The older window is summarized (via `summarize`, receiving the template) or\n * dropped. Never mutates the input.\n */\nexport async function compactTranscript(\n messages: CompressibleMessage[],\n options: CompactTranscriptOptions = {},\n): Promise<CompressibleMessage[]> {\n const marker = options.marker ?? CHECKPOINT_MARKER;\n assertMarker(marker);\n const split =\n options.keepTokens != null\n ? { systemPrompts: [], ...selectByTokenBudget(messages, options.keepTokens) }\n : splitByRecent(messages, options.keepRecent ?? 6, marker);\n if (split.head.length === 0) {\n return [...messages];\n }\n if (!options.summarize) {\n return [...split.systemPrompts, ...split.recent];\n }\n const template = options.summaryTemplate ?? SUMMARY_TEMPLATE;\n const summary = await runSummarize(\n options.summarize,\n split.head,\n template,\n options.failSafe ?? false,\n );\n if (summary === FAILSAFE_ABORT) {\n return [...messages];\n }\n return [...split.systemPrompts, summary, ...split.recent];\n}\n\n/**\n * Build a checkpoint marker turn (a `system` turn whose content starts with\n * `marker`, default {@link CHECKPOINT_MARKER}). `marker` must be non-empty.\n */\nexport function buildCheckpoint(\n label?: string,\n marker: string = CHECKPOINT_MARKER,\n): CompressibleMessage {\n assertMarker(marker);\n return { role: \"system\", content: marker + (label ?? \"\") };\n}\n\n/** Options for {@link filterFromLatestCheckpoint}. */\nexport interface FilterCheckpointOptions {\n /** Marker to scan for (default {@link CHECKPOINT_MARKER}). */\n marker?: string;\n /**\n * `'after'` (default, M2) returns turns AFTER the latest marker (exclusive);\n * `'from'` (theocode) returns turns FROM the latest marker (inclusive).\n */\n include?: \"after\" | \"from\";\n}\n\n/**\n * Return the turns relative to the most recent checkpoint marker (all turns if\n * none). `include: 'after'` (default) excludes the checkpoint; `'from'` includes\n * it (the summary stands in for the pruned head). Never mutates the input.\n */\nexport function filterFromLatestCheckpoint(\n messages: CompressibleMessage[],\n options: FilterCheckpointOptions = {},\n): CompressibleMessage[] {\n const marker = options.marker ?? CHECKPOINT_MARKER;\n const offset = options.include === \"from\" ? 0 : 1;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n if (messages[i]?.content.startsWith(marker)) {\n return messages.slice(i + offset);\n }\n }\n return [...messages];\n}\n\n/**\n * True iff `err` is a {@link TheokitAgentError} (or subclass) reporting a\n * context-window-exceeded condition (the typed `context_too_long` code). Reads\n * both `code` (set by provider mappers) and `metadata.code` (the preferred field)\n * — never a brittle message regex.\n */\nexport function isContextOverflowError(err: unknown): boolean {\n return (\n err instanceof TheokitAgentError &&\n (err.code === \"context_too_long\" || err.metadata?.code === \"context_too_long\")\n );\n}\n\n/**\n * M77 — the margin is outside `(0, 1]`. Typed, because a margin > 1 would GROW the assumed window,\n * which is the unsafe direction: `shouldCompact` is monotonically decreasing in `contextWindow`, so\n * overestimating it makes the trigger fire too late and the context overflow.\n */\nexport class ContextWindowMarginError extends TheokitAgentError {\n constructor(readonly margin: number) {\n super(\n `context-window margin must be in (0, 1], got ${String(margin)}. ` +\n `A margin above 1 grows the assumed window and delays compaction past the real limit.`,\n { code: \"invalid_context_window_margin\" },\n );\n }\n}\n\n/**\n * M77 — default safety margin on the context window.\n *\n * `0.95` is not a guess: it is the single reference's value. Codex ships\n * `effective_context_window_percent: 95` (`models-manager/src/model_info.rs:158`) and never budgets\n * against 100% of a window. Being MULTIPLICATIVE, it stays conservative at any window size, which a\n * fixed subtraction would not.\n */\nexport const CONTEXT_WINDOW_MARGIN = 0.95;\n\n/**\n * M77 — the floor used ONLY when neither the catalog nor the caller knows the window.\n *\n * Honest about its own weakness. This number has **one** source (the M77 milestone text); the search\n * for a second one failed, because the reference has no fallback at all — Codex returns `Option` and\n * its callers early-return (`core/src/session/turn_context.rs:213`, `core/src/compact_remote.rs:374`).\n *\n * It is conservative only UPWARD. For a model whose real window is larger, budgeting against 128k\n * compacts early — wasteful but safe. For a model whose real window is SMALLER (an 8k or 32k model\n * absent from the catalog), it compacts too late and the context still overflows. That residual risk\n * is real and is why {@link resolveEffectiveContextWindow} never lets this floor compete with a known\n * catalog value, and why the `compaction_fallback` event exists: a surface can show that the budget is\n * a guess instead of the user finding out when the provider rejects the request.\n */\nexport const CONTEXT_WINDOW_FLOOR = 128_000;\n\n/** Where the effective window came from — carried into the M77 structured event. */\nexport type ContextWindowSource = \"override\" | \"catalog\" | \"fallback\";\n\n/** Input to {@link resolveEffectiveContextWindow}. */\nexport interface EffectiveContextWindowInput {\n /** Caller-supplied window, in tokens. Clamped by `catalog` when both are present. */\n readonly override?: number | undefined;\n /** The model's window from the catalog, in tokens. Absent when the model is unknown. */\n readonly catalog?: number | undefined;\n /** Safety margin in `(0, 1]`. Codex uses 0.95 (`model_info.rs:158`). */\n readonly margin: number;\n /** Conservative floor used ONLY when neither `override` nor `catalog` is available. */\n readonly floor?: number | undefined;\n}\n\n/** Result of {@link resolveEffectiveContextWindow}. */\nexport interface EffectiveContextWindow {\n /** The window to budget against, after clamp and margin. */\n readonly window: number;\n /** Which input won — `\"fallback\"` means neither override nor catalog was available. */\n readonly source: ContextWindowSource;\n /** `true` when an `override` above the catalog window was clamped down to it. */\n readonly clamped: boolean;\n}\n\n/**\n * Resolve the window to budget against — the fail-SAFE replacement for reading the catalog directly.\n *\n * Today `post-run-lifecycle.ts` reads `getCatalogModelInfo(model)?.limit?.context` and, when that is\n * `undefined`, auto-compaction simply never fires. That is fail-OPEN: the context grows until the\n * provider rejects the request. (The comment there calls it \"fail-safe\" — M77 corrects it.)\n *\n * Three techniques, two of them borrowed from the single reference:\n *\n * 1. **Override, CLAMPED by the catalog** — Codex `models-manager/src/model_info.rs:26-31` lets\n * config override the window but limits it with `context_window.min(max_context_window)`.\n * Without the clamp, declaring 999k on a 200k model reopens the overflow through another door.\n * 2. **Multiplicative margin** — Codex `model_info.rs:158` (`effective_context_window_percent: 95`)\n * never budgets against 100% of the window. Being multiplicative, it is conservative for ANY\n * window size.\n * 3. **Floor, only when nothing is known** — deliberately NOT a blanket default. A fixed floor is\n * conservative only upward: applied to a small model it would inflate the assumed window and\n * reproduce the very fail-open this function exists to close. Hence the floor never competes\n * with a known catalog value.\n *\n * Pure — no catalog lookup, no I/O. The caller supplies the numbers, mirroring `shouldCompact`.\n */\n/**\n * Absolute cap on a declared context window, applied when no catalog entry exists to compare against.\n *\n * **10M**, not 2M. The first version used 2M on the rationale that it sat \"comfortably above the\n * largest published window\" — adversarial review measured the opposite: Llama 4 Scout publishes\n * **10M**, and it arrives precisely via OpenRouter, the provider **without** a catalog, which is the\n * case this cap exists to cover. The user would have silently lost 80% of the declared window.\n *\n * The cap still serves what motivates it — one extra zero on 400k gives 4M, which passes; two zeros\n * give 40M, which does not. A limit that rejects legitimate configuration is worse than no limit,\n * because failing OPEN is visible when it happens and silently losing 80% is not.\n */\nexport const ABSOLUTE_CONTEXT_WINDOW_CAP = 10_000_000;\n\nexport function resolveEffectiveContextWindow(\n input: EffectiveContextWindowInput,\n): EffectiveContextWindow {\n if (!(input.margin > 0) || input.margin > 1) {\n throw new ContextWindowMarginError(input.margin);\n }\n\n const withMargin = (raw: number): number => Math.floor(raw * input.margin);\n\n if (input.override !== undefined) {\n // The catalog is the preferred cap; without it the ABSOLUTE cap applies.\n //\n // M95 (adversarial review of M94) — the previous version clamped **only** when a catalog entry\n // existed, and the whole reason the `contextWindow` key exists is the model that has NO entry\n // (OpenRouter has zero). So the clamp was missing in exactly the case that justifies the\n // feature, while the documentation — including an already-published CHANGELOG — stated without\n // qualification that \"declaring 10M does not blow past the provider\".\n //\n // The concrete scenario is one extra zero: `context_window = 4000000`. The only guard was a\n // `.positive().int()`, which sets no upper bound. The agent would never compact until the\n // provider refused the turn — the silent fail-OPEN that M77 exists to prevent.\n const cap = input.catalog ?? ABSOLUTE_CONTEXT_WINDOW_CAP;\n const clamped = input.override > cap;\n return { window: withMargin(clamped ? cap : input.override), source: \"override\", clamped };\n }\n\n if (input.catalog !== undefined) {\n return { window: withMargin(input.catalog), source: \"catalog\", clamped: false };\n }\n\n return { window: withMargin(input.floor ?? 0), source: \"fallback\", clamped: false };\n}\n\n/** Input to {@link shouldCompact}: an estimate, the model's window, and reserved headroom. */\nexport interface ShouldCompactInput {\n /** Estimated token count of the next request (e.g. from {@link estimateTokens}). */\n readonly estimated: number;\n /** The model's total context window, in tokens. */\n readonly contextWindow: number;\n /** Tokens to reserve as headroom (output + safety margin). */\n readonly buffer: number;\n /**\n * Tokens reserved for the model's response generation, SEPARATE from `buffer`.\n * Default 0 — omitting it preserves the legacy\n * `estimated >= contextWindow - buffer` result.\n */\n readonly maxOutput?: number;\n}\n\n/**\n * Tokenizer-free token estimate via the conventional ~4-chars-per-token\n * heuristic: `ceil(text.length / 4)`. `\"\"` → 0; any non-empty text → ≥ 1.\n * A cheap PRE-CALL gate for {@link shouldCompact} — NOT exact tokenization\n * (a consumer needing exactness supplies their own tokenizer). Uses UTF-16\n * `.length` (code units), so multibyte text is approximate.\n */\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\n/**\n * Decide BEFORE sending whether to compact: `true` when the `estimated` token\n * count leaves less than `buffer` headroom in the `contextWindow`\n * (`estimated >= contextWindow - buffer`). A `buffer >= contextWindow`\n * (non-positive threshold) always returns `true`. Pure — the caller supplies\n * the window (e.g. from `resolveModelCapabilities`), keeping this decoupled\n * from the per-model catalog.\n */\nexport function shouldCompact(input: ShouldCompactInput): boolean {\n return input.estimated >= input.contextWindow - input.buffer - (input.maxOutput ?? 0);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/internal/runtime/compression/compression-helpers.ts","../src/compaction.ts"],"names":["TheokitAgentError","diag","redactSecrets"],"mappings":"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","file":"chunk-ADLLFY3H.cjs","sourcesContent":["/**\n * Compression helpers (T2.3, ADR D92).\n *\n * Scaffold for future compression LLM integration:\n * - `selectCompressionWindow` — splits messages into compress/preserve halves\n * - `assertCompressionReduced` — 10% reduction floor to detect \"compression placebo\"\n *\n * The compression LLM call itself is out of scope for this plan (requires\n * an auxiliary-model ADR). These helpers are used by `Agent.send` when a\n * future iteration adds compression.\n *\n * @internal\n */\n\nexport interface CompressionWindow<M> {\n toCompress: M[];\n toPreserve: M[];\n}\n\n/**\n * Split `messages` into the half to compress (older) and the half to\n * preserve verbatim (recent). When `messages.length <= preserveLast`,\n * everything is preserved.\n *\n * @internal\n */\nexport function selectCompressionWindow<M>(\n messages: readonly M[],\n preserveLast = 6,\n): CompressionWindow<M> {\n if (messages.length <= preserveLast) {\n return { toCompress: [], toPreserve: [...messages] };\n }\n return {\n toCompress: messages.slice(0, -preserveLast),\n toPreserve: messages.slice(-preserveLast),\n };\n}\n\nexport interface CompressionCheck {\n reduced: boolean;\n reductionPct: number;\n reason?: string;\n}\n\n/**\n * Check that compression actually reduced token count by at least `minPct`\n * (default 10%). Returns `{ reduced: false }` for spirals-in-formation\n * (compression LLM outputs that grow or barely shrink).\n *\n * @internal\n */\nexport function assertCompressionReduced(\n before: number,\n after: number,\n minPct = 10,\n): CompressionCheck {\n if (before <= 0) {\n return { reduced: false, reductionPct: 0, reason: \"before count was zero\" };\n }\n const reductionPct = ((before - after) / before) * 100;\n if (reductionPct >= minPct) {\n return { reduced: true, reductionPct };\n }\n return {\n reduced: false,\n reductionPct,\n reason: `compression reduced ${reductionPct.toFixed(1)}% (< ${minPct}% min). Spiral likely.`,\n };\n}\n","/**\n * Public compaction / context-management helpers (M2-1, extended V3-3).\n *\n * Promotes the SDK's compaction capability to a public surface so consumers can\n * compact a transcript, mark/filter conversation checkpoints, and detect\n * context-overflow — without reaching into `internal/`.\n *\n * Two recent-window modes (V3-3):\n * - `keepRecent` (turn-count, default) — keeps the last N turns verbatim and\n * always preserves leading system PROMPTS; reuses the internal\n * `selectCompressionWindow` (no second algorithm).\n * - `keepTokens` (token-budget) — keeps the trailing turns whose accumulated\n * `estimateTokens` fits the budget (theocode `splitTranscript` semantics). In\n * this mode leading system prompts are NOT special-cased (D6).\n *\n * Summarization is delegated to a caller-supplied callback (which receives the\n * older window + the summary template). With `failSafe`, a thrown summarizer\n * returns the ORIGINAL transcript + a structured warn (compaction is an\n * optimization, never a cause of data loss); without it, the error propagates.\n *\n * Public from the `@theokit/sdk/compaction` sub-path.\n */\n\nimport { TheokitAgentError } from \"./errors.js\";\nimport { diag } from \"./internal/diagnostics.js\";\nimport { selectCompressionWindow } from \"./internal/runtime/compression/compression-helpers.js\";\nimport { redactSecrets } from \"./internal/security/redact.js\";\n\n/**\n * Minimal message shape for compaction/compression input. THE canonical public origin (leaf type —\n * rollup-plugin-dts cannot re-export types from internal modules into entry bundles; M42 lesson).\n *\n * @public\n */\nexport interface CompressibleMessage {\n role: \"user\" | \"assistant\" | \"system\";\n content: string;\n}\n\n/**\n * Sentinel prefix marking a conversation checkpoint turn. A visible, structured,\n * prose-unlikely token (no invisible/control bytes — safe to persist and to read\n * in source). Only {@link buildCheckpoint} should produce content beginning with it.\n */\nexport const CHECKPOINT_MARKER = \"[[theokit:checkpoint]] \";\n\n/**\n * The 7-section summary template handed to the `summarize` callback (theocode\n * parity shape). Every header is always present so the summarizer cannot silently\n * drop a category; the model is told to preserve file paths, commands, and error\n * text verbatim. Override per-call via {@link CompactTranscriptOptions.summaryTemplate}.\n */\nexport const SUMMARY_TEMPLATE = `Summarize the conversation so far into these sections (keep every header even if empty):\n\n## Goal\nWhat the user is ultimately trying to achieve.\n\n## Constraints\nHard requirements, conventions, and rules stated.\n\n## Progress\nWhat has been done so far.\n\n## Decisions\nChoices made and their rationale.\n\n## Next\nThe immediate next steps.\n\n## Critical\nAnything that MUST NOT be forgotten (preserve verbatim: error messages, exact values).\n\n## Files\nFile paths touched or referenced (verbatim).`;\n\n/** Reject an empty marker — it would match every turn via `startsWith(\"\")` (EC-3). */\nfunction assertMarker(marker: string): void {\n if (marker === \"\") {\n throw new TheokitAgentError(\"compaction marker must be non-empty\", {\n code: \"invalid_argument\",\n });\n }\n}\n\n/** True for a real system prompt — a `system` turn that is NOT a checkpoint marker. */\nfunction isSystemPrompt(message: CompressibleMessage, marker: string): boolean {\n return message.role === \"system\" && !message.content.startsWith(marker);\n}\n\n/** Carried split: leading system prompts (preserved), the older window, the verbatim tail. */\ninterface TranscriptSplit {\n systemPrompts: CompressibleMessage[];\n head: CompressibleMessage[];\n recent: CompressibleMessage[];\n}\n\n/**\n * Token-budget split (theocode `splitTranscript`): walk from the END accumulating\n * `estimateTokens` until `keepTokens` is exceeded; everything older is the head.\n * Always keeps ≥ 1 recent turn. No system-prompt special-casing (D6).\n */\nfunction selectByTokenBudget(\n messages: CompressibleMessage[],\n keepTokens: number,\n): { head: CompressibleMessage[]; recent: CompressibleMessage[] } {\n let acc = 0;\n let splitIndex = messages.length;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n acc += estimateTokens(messages[i]?.content ?? \"\");\n if (acc > keepTokens && i < messages.length - 1) {\n splitIndex = i + 1;\n break;\n }\n splitIndex = i;\n }\n return { head: messages.slice(0, splitIndex), recent: messages.slice(splitIndex) };\n}\n\n/** Turn-count split (M2): preserve leading system prompts; window the rest by `keepRecent`. */\nfunction splitByRecent(\n messages: CompressibleMessage[],\n keepRecent: number,\n marker: string,\n): TranscriptSplit {\n const systemPrompts = messages.filter((m) => isSystemPrompt(m, marker));\n const rest = messages.filter((m) => !isSystemPrompt(m, marker));\n const { toCompress, toPreserve } = selectCompressionWindow(rest, keepRecent);\n return { systemPrompts, head: toCompress, recent: toPreserve };\n}\n\n/** Options for {@link compactTranscript}. */\nexport interface CompactTranscriptOptions {\n /** Trailing turns preserved verbatim by COUNT (default 6). Ignored when `keepTokens` is set. */\n keepRecent?: number;\n /**\n * Trailing turns preserved verbatim by TOKEN BUDGET (theocode mode). When set,\n * takes precedence over `keepRecent` and disables system-prompt preservation (D6).\n */\n keepTokens?: number;\n /** Checkpoint marker (default {@link CHECKPOINT_MARKER}). Must be non-empty. */\n marker?: string;\n /** Summary template passed to `summarize` (default {@link SUMMARY_TEMPLATE}). */\n summaryTemplate?: string;\n /** Summarize the older window into one turn; if omitted, the older window is dropped. */\n summarize?: (older: CompressibleMessage[], template: string) => Promise<CompressibleMessage>;\n /**\n * When true, a thrown `summarize` returns the ORIGINAL transcript + a structured\n * warn (compaction never loses data). Default false: the error propagates.\n */\n failSafe?: boolean;\n}\n\n/** Sentinel returned by {@link runSummarize} when fail-safe swallowed a throw. */\nconst FAILSAFE_ABORT = Symbol(\"failsafe-abort\");\n\n/** Run the summarizer; on throw, either propagate or (fail-safe) warn + signal abort. */\nasync function runSummarize(\n summarize: NonNullable<CompactTranscriptOptions[\"summarize\"]>,\n head: CompressibleMessage[],\n template: string,\n failSafe: boolean,\n): Promise<CompressibleMessage | typeof FAILSAFE_ABORT> {\n try {\n return await summarize(head, template);\n } catch (err) {\n if (!failSafe) throw err;\n // Unbreakable Rule 8 — never fail silently. The breadcrumb points at the root\n // cause when a summarizer fails every turn and context grows unchecked. The\n // summarizer is caller-supplied, so its error text is routed through\n // `redactSecrets` (ADR D68 — no unredacted output sink in src/).\n // theokit#147 — through the interceptable channel. A summarizer failing every turn is exactly\n // the breadcrumb a TUI host wants in its own panel, not smeared across its alternate screen.\n diag(\n `[compaction] summarizer failed — proceeding uncompacted: ${redactSecrets(err instanceof Error ? err.message : String(err))}\\n`,\n );\n return FAILSAFE_ABORT;\n }\n}\n\n/**\n * Compact a transcript. In `keepRecent` mode (default) the last `keepRecent` turns\n * are kept verbatim and leading system PROMPTS preserved; in `keepTokens` mode the\n * trailing turns within the token budget are kept (no system special-casing, D6).\n * The older window is summarized (via `summarize`, receiving the template) or\n * dropped. Never mutates the input.\n */\nexport async function compactTranscript(\n messages: CompressibleMessage[],\n options: CompactTranscriptOptions = {},\n): Promise<CompressibleMessage[]> {\n const marker = options.marker ?? CHECKPOINT_MARKER;\n assertMarker(marker);\n const split =\n options.keepTokens != null\n ? { systemPrompts: [], ...selectByTokenBudget(messages, options.keepTokens) }\n : splitByRecent(messages, options.keepRecent ?? 6, marker);\n if (split.head.length === 0) {\n return [...messages];\n }\n if (!options.summarize) {\n return [...split.systemPrompts, ...split.recent];\n }\n const template = options.summaryTemplate ?? SUMMARY_TEMPLATE;\n const summary = await runSummarize(\n options.summarize,\n split.head,\n template,\n options.failSafe ?? false,\n );\n if (summary === FAILSAFE_ABORT) {\n return [...messages];\n }\n return [...split.systemPrompts, summary, ...split.recent];\n}\n\n/**\n * Build a checkpoint marker turn (a `system` turn whose content starts with\n * `marker`, default {@link CHECKPOINT_MARKER}). `marker` must be non-empty.\n */\nexport function buildCheckpoint(\n label?: string,\n marker: string = CHECKPOINT_MARKER,\n): CompressibleMessage {\n assertMarker(marker);\n return { role: \"system\", content: marker + (label ?? \"\") };\n}\n\n/** Options for {@link filterFromLatestCheckpoint}. */\nexport interface FilterCheckpointOptions {\n /** Marker to scan for (default {@link CHECKPOINT_MARKER}). */\n marker?: string;\n /**\n * `'after'` (default, M2) returns turns AFTER the latest marker (exclusive);\n * `'from'` (theocode) returns turns FROM the latest marker (inclusive).\n */\n include?: \"after\" | \"from\";\n}\n\n/**\n * Return the turns relative to the most recent checkpoint marker (all turns if\n * none). `include: 'after'` (default) excludes the checkpoint; `'from'` includes\n * it (the summary stands in for the pruned head). Never mutates the input.\n */\nexport function filterFromLatestCheckpoint(\n messages: CompressibleMessage[],\n options: FilterCheckpointOptions = {},\n): CompressibleMessage[] {\n const marker = options.marker ?? CHECKPOINT_MARKER;\n const offset = options.include === \"from\" ? 0 : 1;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n if (messages[i]?.content.startsWith(marker)) {\n return messages.slice(i + offset);\n }\n }\n return [...messages];\n}\n\n/**\n * True iff `err` is a {@link TheokitAgentError} (or subclass) reporting a\n * context-window-exceeded condition (the typed `context_too_long` code). Reads\n * both `code` (set by provider mappers) and `metadata.code` (the preferred field)\n * — never a brittle message regex.\n */\nexport function isContextOverflowError(err: unknown): boolean {\n return (\n err instanceof TheokitAgentError &&\n (err.code === \"context_too_long\" || err.metadata?.code === \"context_too_long\")\n );\n}\n\n/**\n * M77 — the margin is outside `(0, 1]`. Typed, because a margin > 1 would GROW the assumed window,\n * which is the unsafe direction: `shouldCompact` is monotonically decreasing in `contextWindow`, so\n * overestimating it makes the trigger fire too late and the context overflow.\n */\nexport class ContextWindowMarginError extends TheokitAgentError {\n constructor(readonly margin: number) {\n super(\n `context-window margin must be in (0, 1], got ${String(margin)}. ` +\n `A margin above 1 grows the assumed window and delays compaction past the real limit.`,\n { code: \"invalid_context_window_margin\" },\n );\n }\n}\n\n/**\n * M77 — default safety margin on the context window.\n *\n * `0.95` is not a guess: it is the single reference's value. Codex ships\n * `effective_context_window_percent: 95` (`models-manager/src/model_info.rs:158`) and never budgets\n * against 100% of a window. Being MULTIPLICATIVE, it stays conservative at any window size, which a\n * fixed subtraction would not.\n */\nexport const CONTEXT_WINDOW_MARGIN = 0.95;\n\n/**\n * M77 — the floor used ONLY when neither the catalog nor the caller knows the window.\n *\n * Honest about its own weakness. This number has **one** source (the M77 milestone text); the search\n * for a second one failed, because the reference has no fallback at all — Codex returns `Option` and\n * its callers early-return (`core/src/session/turn_context.rs:213`, `core/src/compact_remote.rs:374`).\n *\n * It is conservative only UPWARD. For a model whose real window is larger, budgeting against 128k\n * compacts early — wasteful but safe. For a model whose real window is SMALLER (an 8k or 32k model\n * absent from the catalog), it compacts too late and the context still overflows. That residual risk\n * is real and is why {@link resolveEffectiveContextWindow} never lets this floor compete with a known\n * catalog value, and why the `compaction_fallback` event exists: a surface can show that the budget is\n * a guess instead of the user finding out when the provider rejects the request.\n */\nexport const CONTEXT_WINDOW_FLOOR = 128_000;\n\n/** Where the effective window came from — carried into the M77 structured event. */\nexport type ContextWindowSource = \"override\" | \"catalog\" | \"fallback\";\n\n/** Input to {@link resolveEffectiveContextWindow}. */\nexport interface EffectiveContextWindowInput {\n /** Caller-supplied window, in tokens. Clamped by `catalog` when both are present. */\n readonly override?: number | undefined;\n /** The model's window from the catalog, in tokens. Absent when the model is unknown. */\n readonly catalog?: number | undefined;\n /** Safety margin in `(0, 1]`. Codex uses 0.95 (`model_info.rs:158`). */\n readonly margin: number;\n /** Conservative floor used ONLY when neither `override` nor `catalog` is available. */\n readonly floor?: number | undefined;\n}\n\n/** Result of {@link resolveEffectiveContextWindow}. */\nexport interface EffectiveContextWindow {\n /** The window to budget against, after clamp and margin. */\n readonly window: number;\n /** Which input won — `\"fallback\"` means neither override nor catalog was available. */\n readonly source: ContextWindowSource;\n /** `true` when an `override` above the catalog window was clamped down to it. */\n readonly clamped: boolean;\n}\n\n/**\n * Resolve the window to budget against — the fail-SAFE replacement for reading the catalog directly.\n *\n * Today `post-run-lifecycle.ts` reads `getCatalogModelInfo(model)?.limit?.context` and, when that is\n * `undefined`, auto-compaction simply never fires. That is fail-OPEN: the context grows until the\n * provider rejects the request. (The comment there calls it \"fail-safe\" — M77 corrects it.)\n *\n * Three techniques, two of them borrowed from the single reference:\n *\n * 1. **Override, CLAMPED by the catalog** — Codex `models-manager/src/model_info.rs:26-31` lets\n * config override the window but limits it with `context_window.min(max_context_window)`.\n * Without the clamp, declaring 999k on a 200k model reopens the overflow through another door.\n * 2. **Multiplicative margin** — Codex `model_info.rs:158` (`effective_context_window_percent: 95`)\n * never budgets against 100% of the window. Being multiplicative, it is conservative for ANY\n * window size.\n * 3. **Floor, only when nothing is known** — deliberately NOT a blanket default. A fixed floor is\n * conservative only upward: applied to a small model it would inflate the assumed window and\n * reproduce the very fail-open this function exists to close. Hence the floor never competes\n * with a known catalog value.\n *\n * Pure — no catalog lookup, no I/O. The caller supplies the numbers, mirroring `shouldCompact`.\n */\n/**\n * Absolute cap on a declared context window, applied when no catalog entry exists to compare against.\n *\n * **10M**, not 2M. The first version used 2M on the rationale that it sat \"comfortably above the\n * largest published window\" — adversarial review measured the opposite: Llama 4 Scout publishes\n * **10M**, and it arrives precisely via OpenRouter, the provider **without** a catalog, which is the\n * case this cap exists to cover. The user would have silently lost 80% of the declared window.\n *\n * The cap still serves what motivates it — one extra zero on 400k gives 4M, which passes; two zeros\n * give 40M, which does not. A limit that rejects legitimate configuration is worse than no limit,\n * because failing OPEN is visible when it happens and silently losing 80% is not.\n */\nexport const ABSOLUTE_CONTEXT_WINDOW_CAP = 10_000_000;\n\nexport function resolveEffectiveContextWindow(\n input: EffectiveContextWindowInput,\n): EffectiveContextWindow {\n if (!(input.margin > 0) || input.margin > 1) {\n throw new ContextWindowMarginError(input.margin);\n }\n\n const withMargin = (raw: number): number => Math.floor(raw * input.margin);\n\n if (input.override !== undefined) {\n // The catalog is the preferred cap; without it the ABSOLUTE cap applies.\n //\n // M95 (adversarial review of M94) — the previous version clamped **only** when a catalog entry\n // existed, and the whole reason the `contextWindow` key exists is the model that has NO entry\n // (OpenRouter has zero). So the clamp was missing in exactly the case that justifies the\n // feature, while the documentation — including an already-published CHANGELOG — stated without\n // qualification that \"declaring 10M does not blow past the provider\".\n //\n // The concrete scenario is one extra zero: `context_window = 4000000`. The only guard was a\n // `.positive().int()`, which sets no upper bound. The agent would never compact until the\n // provider refused the turn — the silent fail-OPEN that M77 exists to prevent.\n const cap = input.catalog ?? ABSOLUTE_CONTEXT_WINDOW_CAP;\n const clamped = input.override > cap;\n return { window: withMargin(clamped ? cap : input.override), source: \"override\", clamped };\n }\n\n if (input.catalog !== undefined) {\n return { window: withMargin(input.catalog), source: \"catalog\", clamped: false };\n }\n\n return { window: withMargin(input.floor ?? 0), source: \"fallback\", clamped: false };\n}\n\n/** Input to {@link shouldCompact}: an estimate, the model's window, and reserved headroom. */\nexport interface ShouldCompactInput {\n /** Estimated token count of the next request (e.g. from {@link estimateTokens}). */\n readonly estimated: number;\n /** The model's total context window, in tokens. */\n readonly contextWindow: number;\n /** Tokens to reserve as headroom (output + safety margin). */\n readonly buffer: number;\n /**\n * Tokens reserved for the model's response generation, SEPARATE from `buffer`.\n * Default 0 — omitting it preserves the legacy\n * `estimated >= contextWindow - buffer` result.\n */\n readonly maxOutput?: number;\n}\n\n/**\n * Tokenizer-free token estimate via the conventional ~4-chars-per-token\n * heuristic: `ceil(text.length / 4)`. `\"\"` → 0; any non-empty text → ≥ 1.\n * A cheap PRE-CALL gate for {@link shouldCompact} — NOT exact tokenization\n * (a consumer needing exactness supplies their own tokenizer). Uses UTF-16\n * `.length` (code units), so multibyte text is approximate.\n */\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\n/**\n * Decide BEFORE sending whether to compact: `true` when the `estimated` token\n * count leaves less than `buffer` headroom in the `contextWindow`\n * (`estimated >= contextWindow - buffer`). A `buffer >= contextWindow`\n * (non-positive threshold) always returns `true`. Pure — the caller supplies\n * the window (e.g. from `resolveModelCapabilities`), keeping this decoupled\n * from the per-model catalog.\n */\nexport function shouldCompact(input: ShouldCompactInput): boolean {\n return input.estimated >= input.contextWindow - input.buffer - (input.maxOutput ?? 0);\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { acquireSessionWriter } from './chunk-
|
|
2
|
-
import { readTranscript, transcriptPath } from './chunk-
|
|
3
|
-
import { withFileLock, appendJsonl } from './chunk-
|
|
1
|
+
import { acquireSessionWriter } from './chunk-POWRZSK4.js';
|
|
2
|
+
import { readTranscript, transcriptPath } from './chunk-N5CR3TJZ.js';
|
|
3
|
+
import { withFileLock, appendJsonl } from './chunk-NZL4BNFQ.js';
|
|
4
4
|
import { mkdir } from 'fs/promises';
|
|
5
5
|
import { dirname } from 'path';
|
|
6
6
|
|
|
@@ -106,5 +106,5 @@ var FsSessionStore = class {
|
|
|
106
106
|
};
|
|
107
107
|
|
|
108
108
|
export { FsSessionStore };
|
|
109
|
-
//# sourceMappingURL=chunk-
|
|
110
|
-
//# sourceMappingURL=chunk-
|
|
109
|
+
//# sourceMappingURL=chunk-B6HOIWQ6.js.map
|
|
110
|
+
//# sourceMappingURL=chunk-B6HOIWQ6.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/persistence/fs-session-store.ts"],"names":[],"mappings":"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","file":"chunk-J4RY5DTI.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 { 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 { readTranscript, type SessionRecord, transcriptPath } 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 * The default `SessionStore` — reads/append-writes the native `.jsonl` transcript.\n *\n * @internal\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\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\n constructor(options: FsSessionStoreOptions) {\n this.#baseDir = options.baseDir;\n this.#cwd = options.cwd;\n }\n\n async readRecords(agentId: string): Promise<SessionRecord[]> {\n return readTranscript(transcriptPath(this.#baseDir, this.#cwd, 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 = transcriptPath(this.#baseDir, this.#cwd, 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 = transcriptPath(this.#baseDir, this.#cwd, 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-B6HOIWQ6.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 { 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 { readTranscript, type SessionRecord, transcriptPath } 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 * The default `SessionStore` — reads/append-writes the native `.jsonl` transcript.\n *\n * @internal\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\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\n constructor(options: FsSessionStoreOptions) {\n this.#baseDir = options.baseDir;\n this.#cwd = options.cwd;\n }\n\n async readRecords(agentId: string): Promise<SessionRecord[]> {\n return readTranscript(transcriptPath(this.#baseDir, this.#cwd, 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 = transcriptPath(this.#baseDir, this.#cwd, 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 = transcriptPath(this.#baseDir, this.#cwd, 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,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunk2RW7K6FN_cjs = require('./chunk-2RW7K6FN.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkJIQRXKTA_cjs = require('./chunk-JIQRXKTA.cjs');
|
|
5
5
|
var chunkYLQQX5W2_cjs = require('./chunk-YLQQX5W2.cjs');
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
var
|
|
6
|
+
var chunkC4H6PB5J_cjs = require('./chunk-C4H6PB5J.cjs');
|
|
7
|
+
var chunkZT57WTUJ_cjs = require('./chunk-ZT57WTUJ.cjs');
|
|
8
|
+
var chunkLPVIRJVF_cjs = require('./chunk-LPVIRJVF.cjs');
|
|
9
|
+
var chunkBM6N4KHO_cjs = require('./chunk-BM6N4KHO.cjs');
|
|
10
10
|
var crypto = require('crypto');
|
|
11
11
|
var promises = require('fs/promises');
|
|
12
12
|
var path = require('path');
|
|
@@ -57,7 +57,7 @@ var PRAGMA_STATEMENTS = [
|
|
|
57
57
|
|
|
58
58
|
// src/internal/memory/index-db.ts
|
|
59
59
|
async function openMemoryDb(opts) {
|
|
60
|
-
return
|
|
60
|
+
return chunkJIQRXKTA_cjs.openSqliteResilient({
|
|
61
61
|
filePath: opts.filePath,
|
|
62
62
|
label: "memory-index",
|
|
63
63
|
recoverCorrupt: opts.recoverCorrupt,
|
|
@@ -72,10 +72,10 @@ function defaultIndexPath(cwd) {
|
|
|
72
72
|
}
|
|
73
73
|
function requireLance() {
|
|
74
74
|
try {
|
|
75
|
-
const r = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-
|
|
75
|
+
const r = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-BDTVFIPB.cjs', document.baseURI).href)));
|
|
76
76
|
return r("@lancedb/lancedb");
|
|
77
77
|
} catch (cause) {
|
|
78
|
-
throw new
|
|
78
|
+
throw new chunkLPVIRJVF_cjs.ConfigurationError(
|
|
79
79
|
'Lance backend selected but `@lancedb/lancedb` is not installed. Install with: `pnpm add @lancedb/lancedb`. SQLite remains available as the default (omit `backend: "lance"`).',
|
|
80
80
|
{ code: "lance_backend_unavailable", cause }
|
|
81
81
|
);
|
|
@@ -105,7 +105,7 @@ var LanceIndex = class _LanceIndex {
|
|
|
105
105
|
const embField = schema.fields.find((f) => f.name === "embedding");
|
|
106
106
|
const existingDim = embField?.type?.listSize ?? embField?.type?.fixedSize;
|
|
107
107
|
if (typeof existingDim === "number" && existingDim !== dim) {
|
|
108
|
-
throw new
|
|
108
|
+
throw new chunkLPVIRJVF_cjs.ConfigurationError(
|
|
109
109
|
`Embedding dimension mismatch in Lance index: storage has ${existingDim}-dim vectors, current provider yields ${dim}-dim. Run \`theokit-migrate-memory\` after switching providers, or use a different storagePath.`,
|
|
110
110
|
{ code: "embedding_dimension_mismatch" }
|
|
111
111
|
);
|
|
@@ -176,7 +176,7 @@ function escapeSqlValue(value) {
|
|
|
176
176
|
for (let i = 0; i < value.length; i++) {
|
|
177
177
|
const code = value.charCodeAt(i);
|
|
178
178
|
if (code === 0 || code >= 1 && code <= 31 || code === 127) {
|
|
179
|
-
throw new
|
|
179
|
+
throw new chunkLPVIRJVF_cjs.ConfigurationError(
|
|
180
180
|
`SQL filter value contains control character at position ${i} (0x${code.toString(16)}). This may indicate an injection attempt.`,
|
|
181
181
|
{ code: "sql_injection_blocked" }
|
|
182
182
|
);
|
|
@@ -275,7 +275,7 @@ function computeTermOverlapScore(query, text) {
|
|
|
275
275
|
var VALID_BACKENDS = ["sqlite-vec", "lance"];
|
|
276
276
|
function assertValidBackend(backend) {
|
|
277
277
|
if (!VALID_BACKENDS.includes(backend)) {
|
|
278
|
-
throw new
|
|
278
|
+
throw new chunkLPVIRJVF_cjs.ConfigurationError(
|
|
279
279
|
`Invalid memory backend "${backend}". Valid values: ${VALID_BACKENDS.join(", ")}.`,
|
|
280
280
|
{ code: "invalid_memory_backend" }
|
|
281
281
|
);
|
|
@@ -283,7 +283,7 @@ function assertValidBackend(backend) {
|
|
|
283
283
|
}
|
|
284
284
|
async function openLanceIndex(opts) {
|
|
285
285
|
if (opts.embedding === void 0) {
|
|
286
|
-
throw new
|
|
286
|
+
throw new chunkLPVIRJVF_cjs.ConfigurationError(
|
|
287
287
|
"Lance backend requires an embedding runtime. Pass `embedding: { provider, model, apiKey }` in Memory.create options (or omit `backend` to use SQLite default).",
|
|
288
288
|
{ code: "lance_requires_embedding" }
|
|
289
289
|
);
|
|
@@ -299,10 +299,10 @@ function legacyMemoryJsonPath(cwd, config) {
|
|
|
299
299
|
if (config.storePath !== void 0) {
|
|
300
300
|
return path.resolve(cwd, config.storePath);
|
|
301
301
|
}
|
|
302
|
-
const namespace =
|
|
303
|
-
const scope =
|
|
304
|
-
const userId =
|
|
305
|
-
return
|
|
302
|
+
const namespace = chunkZT57WTUJ_cjs.sanitizeIdentifier(config.namespace ?? "default");
|
|
303
|
+
const scope = chunkZT57WTUJ_cjs.sanitizeIdentifier(config.scope ?? "agent", { maxLen: 16 });
|
|
304
|
+
const userId = chunkZT57WTUJ_cjs.sanitizeIdentifier(config.userId ?? "default");
|
|
305
|
+
return chunkZT57WTUJ_cjs.safePathJoin(cwd, ".theokit", "memory", namespace, `${scope}-${userId}.json`);
|
|
306
306
|
}
|
|
307
307
|
|
|
308
308
|
// src/internal/memory/storage/markdown-store.ts
|
|
@@ -335,10 +335,10 @@ function appendFactToMarkdown(cwd, fact) {
|
|
|
335
335
|
} catch {
|
|
336
336
|
raw = "";
|
|
337
337
|
}
|
|
338
|
-
const sanitized =
|
|
338
|
+
const sanitized = chunkBM6N4KHO_cjs.redactSecrets(fact.text);
|
|
339
339
|
const next = insertFactBullet(raw, sanitized);
|
|
340
340
|
await promises.mkdir(memoryDir(cwd), { recursive: true });
|
|
341
|
-
await
|
|
341
|
+
await chunkC4H6PB5J_cjs.replaceFileAtomic(path, next);
|
|
342
342
|
});
|
|
343
343
|
}
|
|
344
344
|
function parseFactsSection(raw) {
|
|
@@ -391,7 +391,7 @@ function sessionsDir(cwd) {
|
|
|
391
391
|
return path.join(memoryDir(cwd), "sessions");
|
|
392
392
|
}
|
|
393
393
|
function sessionSummaryPath(cwd, runId) {
|
|
394
|
-
return path.join(sessionsDir(cwd), `${
|
|
394
|
+
return path.join(sessionsDir(cwd), `${chunkZT57WTUJ_cjs.safeFilenameForId(runId, { maxLen: 128 })}.md`);
|
|
395
395
|
}
|
|
396
396
|
function truncate(text) {
|
|
397
397
|
if (text.length <= MAX_TURN_CHARS) return text;
|
|
@@ -401,8 +401,8 @@ async function writeSessionSummary(input) {
|
|
|
401
401
|
if (input.status !== "finished") return;
|
|
402
402
|
const path = sessionSummaryPath(input.cwd, input.runId);
|
|
403
403
|
await promises.mkdir(sessionsDir(input.cwd), { recursive: true });
|
|
404
|
-
const safeUser =
|
|
405
|
-
const safeAssistant =
|
|
404
|
+
const safeUser = chunkBM6N4KHO_cjs.redactSecrets(truncate(input.userText));
|
|
405
|
+
const safeAssistant = chunkBM6N4KHO_cjs.redactSecrets(truncate(input.assistantText));
|
|
406
406
|
const iso = new Date(input.at).toISOString();
|
|
407
407
|
const body = [
|
|
408
408
|
"---",
|
|
@@ -421,7 +421,7 @@ async function writeSessionSummary(input) {
|
|
|
421
421
|
safeAssistant,
|
|
422
422
|
""
|
|
423
423
|
].join("\n");
|
|
424
|
-
await
|
|
424
|
+
await chunkC4H6PB5J_cjs.replaceFileAtomic(path, body);
|
|
425
425
|
}
|
|
426
426
|
|
|
427
427
|
// src/internal/memory/storage/session-loader.ts
|
|
@@ -548,7 +548,7 @@ async function loadSqliteVecExtension(db) {
|
|
|
548
548
|
loadFn(db);
|
|
549
549
|
} catch (cause) {
|
|
550
550
|
const message = cause instanceof Error ? cause.message : String(cause);
|
|
551
|
-
throw new
|
|
551
|
+
throw new chunkLPVIRJVF_cjs.ConfigurationError(
|
|
552
552
|
`sqlite-vec extension unavailable. Install \`sqlite-vec\` and ensure the native binary matches your Node + OS. Cause: ${message}`,
|
|
553
553
|
{ code: "sqlite_vec_unavailable", cause }
|
|
554
554
|
);
|
|
@@ -801,7 +801,7 @@ var IndexManager = class _IndexManager {
|
|
|
801
801
|
}
|
|
802
802
|
// ───── search internals ──────────────────────────────────────────────
|
|
803
803
|
ftsSearch(query, limit) {
|
|
804
|
-
const sanitized =
|
|
804
|
+
const sanitized = chunkJIQRXKTA_cjs.sanitizeFts5Query(query);
|
|
805
805
|
if (sanitized.length === 0) return [];
|
|
806
806
|
const stmt = this.db.prepare(
|
|
807
807
|
`SELECT chunks.id as id, files.rel_path as rel_path, files.source as source,
|
|
@@ -978,5 +978,5 @@ exports.openMemoryDb = openMemoryDb;
|
|
|
978
978
|
exports.readFacts = readFacts;
|
|
979
979
|
exports.readFactsFromMarkdown = readFactsFromMarkdown;
|
|
980
980
|
exports.writeSessionSummary = writeSessionSummary;
|
|
981
|
-
//# sourceMappingURL=chunk-
|
|
982
|
-
//# sourceMappingURL=chunk-
|
|
981
|
+
//# sourceMappingURL=chunk-BDTVFIPB.cjs.map
|
|
982
|
+
//# sourceMappingURL=chunk-BDTVFIPB.cjs.map
|