agentic-qe 3.11.2 → 3.11.4
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/.claude/skills/.validation/templates/eval.template.yaml +36 -0
- package/.claude/skills/qe-quality-assessment/SKILL.md +25 -0
- package/.claude/skills/qe-test-generation/SKILL.md +58 -20
- package/.claude/skills/qe-test-generation/evals/qe-test-generation.yaml +37 -0
- package/.claude/skills/skills-manifest.json +1 -1
- package/CHANGELOG.md +84 -0
- package/assets/skills/.validation/templates/eval.template.yaml +36 -0
- package/assets/skills/enterprise-integration-testing/SKILL.md +1 -1
- package/assets/skills/pentest-validation/SKILL.md +1 -1
- package/assets/skills/qcsd-development-swarm/SKILL.md +27 -6
- package/assets/skills/qe-quality-assessment/SKILL.md +25 -0
- package/assets/skills/qe-test-generation/SKILL.md +58 -20
- package/assets/skills/qe-test-generation/evals/qe-test-generation.yaml +37 -0
- package/dist/cli/bundle.js +5 -5
- package/dist/cli/chunks/adapter-2HMUXHWY.js +2 -0
- package/dist/cli/chunks/{agent-booster-wasm-FNCVODUJ.js → agent-booster-wasm-62I6ZNRW.js} +2 -2
- package/dist/cli/chunks/{agent-handler-JK7VK37B.js → agent-handler-E2TZKKBS.js} +2 -2
- package/dist/cli/chunks/{agent-memory-branch-EPVVJNNA.js → agent-memory-branch-JHAHC2NH.js} +2 -2
- package/dist/cli/chunks/aqe-learning-engine-M2NKRVRE.js +2 -0
- package/dist/cli/chunks/{arena-EH2IMSRW.js → arena-72ZV65BR.js} +4 -4
- package/dist/cli/chunks/{arena-NTHVDZTJ.js → arena-KLG3YSSR.js} +2 -2
- package/dist/cli/chunks/{audit-ODZV2T2B.js → audit-EPB7ETMT.js} +2 -2
- package/dist/cli/chunks/base-CCHC2DAC.js +2 -0
- package/dist/cli/chunks/{hnswlib-node-2KL54YUA.js → better-sqlite3-URULPKRF.js} +2 -2
- package/dist/cli/chunks/{brain-handler-NVB6OJ25.js → brain-handler-FBMYEERK.js} +3 -3
- package/dist/cli/chunks/{branch-enumerator-BIXSELMY.js → branch-enumerator-C7MPNYT7.js} +2 -2
- package/dist/cli/chunks/{browser-S2Y2W33Z.js → browser-UUDUDYLR.js} +2 -2
- package/dist/cli/chunks/browser-workflow-4DGHFYY3.js +2 -0
- package/dist/cli/chunks/{chunk-XXCSJMSR.js → chunk-2KNFS3L5.js} +1 -1
- package/dist/cli/chunks/{chunk-I7UWFV6N.js → chunk-2WPSMQIL.js} +1 -1
- package/dist/cli/chunks/chunk-37ZDGJ3H.js +2 -0
- package/dist/cli/chunks/{chunk-JELN5XTK.js → chunk-3E7D3A35.js} +1 -1
- package/dist/cli/chunks/{chunk-ZBJMVWQR.js → chunk-3FJZMQJ7.js} +2 -2
- package/dist/cli/chunks/chunk-3SBUL72V.js +2 -0
- package/dist/cli/chunks/{chunk-O3IIAIXB.js → chunk-3SKIZDKL.js} +1 -1
- package/dist/cli/chunks/{chunk-LAY35POY.js → chunk-3SRPFBU7.js} +3 -3
- package/dist/cli/chunks/{chunk-6VAFRS5N.js → chunk-4BFCLSDN.js} +2 -2
- package/dist/cli/chunks/{chunk-NZNXEEZR.js → chunk-4JFH3MVA.js} +1 -1
- package/dist/cli/chunks/{chunk-C6UTRG66.js → chunk-4RHNPRAP.js} +2 -2
- package/dist/cli/chunks/{chunk-3NCVUFAL.js → chunk-4YT5YN5G.js} +2 -2
- package/dist/cli/chunks/{chunk-P3VRXQ3H.js → chunk-54B6P2WS.js} +3 -3
- package/dist/cli/chunks/{chunk-H5TM4KIB.js → chunk-5AQ7FXYG.js} +2 -2
- package/dist/cli/chunks/{chunk-WARFZ626.js → chunk-5P7Q5YNC.js} +1 -1
- package/dist/cli/chunks/{chunk-ARUXFZDY.js → chunk-5U2WHPXL.js} +1 -1
- package/dist/cli/chunks/{chunk-MAXOIEUG.js → chunk-5VSQAGA2.js} +1 -1
- package/dist/cli/chunks/{chunk-CEMROADY.js → chunk-5Z4FBCBK.js} +1 -1
- package/dist/cli/chunks/{chunk-I3AD523O.js → chunk-63QUN3JK.js} +1 -1
- package/dist/cli/chunks/{chunk-4FTVTAMN.js → chunk-6545AS2J.js} +2 -2
- package/dist/cli/chunks/{chunk-5BDVFFYF.js → chunk-6GYGAW53.js} +2 -2
- package/dist/cli/chunks/{chunk-OC2W7KIW.js → chunk-6JUOH6L4.js} +2 -2
- package/dist/cli/chunks/{chunk-YDPBCN7H.js → chunk-6W3QHS45.js} +2 -2
- package/dist/cli/chunks/{chunk-WKIYYF3G.js → chunk-7ADD2ZQL.js} +2 -2
- package/dist/cli/chunks/{chunk-7MKF52GT.js → chunk-7AWK43JN.js} +2 -2
- package/dist/cli/chunks/{chunk-FV53RMVB.js → chunk-7IKWF2AD.js} +1 -1
- package/dist/cli/chunks/{chunk-UCXW24HY.js → chunk-7QTB5XIQ.js} +2 -2
- package/dist/cli/chunks/{chunk-HDBJORV7.js → chunk-A4OMK3FO.js} +2 -2
- package/dist/cli/chunks/{chunk-DMUQV2YU.js → chunk-ADFKY3X2.js} +2 -2
- package/dist/cli/chunks/{chunk-SE4S23C7.js → chunk-AE6HXMOG.js} +1 -1
- package/dist/cli/chunks/{chunk-ZH6HYT7C.js → chunk-AJXGGTX7.js} +1 -1
- package/dist/cli/chunks/{chunk-CMVNYVKL.js → chunk-AQIEK4SY.js} +2 -2
- package/dist/cli/chunks/{chunk-H4ZPPHOI.js → chunk-ARPBG6FQ.js} +2 -2
- package/dist/cli/chunks/{chunk-X36TZXDK.js → chunk-AYGEWPN4.js} +1 -1
- package/dist/cli/chunks/{chunk-JSZNI3AO.js → chunk-B5XUWHKQ.js} +1 -1
- package/dist/cli/chunks/{chunk-76RO2RHG.js → chunk-BMQDELPA.js} +1 -1
- package/dist/cli/chunks/{chunk-26ZMIYSK.js → chunk-BRLUNIR4.js} +2 -2
- package/dist/cli/chunks/{chunk-H6MBRYA7.js → chunk-CNF3ZWLM.js} +2 -2
- package/dist/cli/chunks/{chunk-XRDPGJNW.js → chunk-D5S47YUS.js} +2 -2
- package/dist/cli/chunks/{chunk-S6BWEZKK.js → chunk-D6CKKNYC.js} +2 -2
- package/dist/cli/chunks/{chunk-K6IQBVD7.js → chunk-DNOU2HVQ.js} +2 -2
- package/dist/cli/chunks/{chunk-DPFLJMEI.js → chunk-DRMHVY4T.js} +4 -4
- package/dist/cli/chunks/{chunk-3ATEYGVD.js → chunk-EONKMHKO.js} +2 -2
- package/dist/cli/chunks/{chunk-6LQIVIZB.js → chunk-EZRHSHOQ.js} +2 -2
- package/dist/cli/chunks/{chunk-WEBHFIWS.js → chunk-FRFVN6AA.js} +2 -2
- package/dist/cli/chunks/{chunk-YJUJCLXV.js → chunk-FSGMRQFC.js} +2 -2
- package/dist/cli/chunks/{chunk-OFUF3APC.js → chunk-G3TFNY4T.js} +2 -2
- package/dist/cli/chunks/{chunk-PPD5ZLNA.js → chunk-GOQ4P2PB.js} +2 -2
- package/dist/cli/chunks/chunk-GRQ36XUH.js +24 -0
- package/dist/cli/chunks/{chunk-LI3T5YNC.js → chunk-HH6NCBSP.js} +3 -3
- package/dist/cli/chunks/{chunk-NPT7BYGF.js → chunk-HJ24KMC2.js} +1 -1
- package/dist/cli/chunks/{chunk-AK5Q2WCJ.js → chunk-HJO4RNOW.js} +2 -2
- package/dist/cli/chunks/{chunk-VNFL2TPU.js → chunk-HT6WAYIR.js} +1 -1
- package/dist/cli/chunks/{chunk-IO7ZUP2G.js → chunk-HWBMYR5W.js} +3 -3
- package/dist/cli/chunks/{chunk-AKZK46TQ.js → chunk-IB3ZPLFA.js} +2 -2
- package/dist/cli/chunks/{chunk-EDH4H55B.js → chunk-ICCTQ5LO.js} +2 -2
- package/dist/cli/chunks/{chunk-P7MIOTVP.js → chunk-IF3HPQNV.js} +1 -1
- package/dist/cli/chunks/{chunk-DU4GQKTH.js → chunk-IQBZBUP5.js} +2 -2
- package/dist/cli/chunks/{chunk-LFXXA325.js → chunk-JCTCM6IR.js} +1 -1
- package/dist/cli/chunks/{chunk-K426HTEQ.js → chunk-JDFPAJGB.js} +10 -10
- package/dist/cli/chunks/{chunk-CAVBEZV4.js → chunk-JFLSQH2X.js} +2 -2
- package/dist/cli/chunks/{chunk-P5SGBQLY.js → chunk-JNQN5DNS.js} +1 -1
- package/dist/cli/chunks/{chunk-A4ZDKF5F.js → chunk-JPENUVCI.js} +1 -1
- package/dist/cli/chunks/{chunk-5AFO7ZZG.js → chunk-KUZMVH6N.js} +3 -3
- package/dist/cli/chunks/{chunk-KFE6LB4I.js → chunk-KYTFIP6R.js} +2 -2
- package/dist/cli/chunks/{chunk-OU52V67H.js → chunk-LKURMUBU.js} +4 -4
- package/dist/cli/chunks/{chunk-JCH2FHJ7.js → chunk-LLUPRGOR.js} +2 -2
- package/dist/cli/chunks/{chunk-5KMGG3QW.js → chunk-LMJUMUQJ.js} +4 -4
- package/dist/cli/chunks/{chunk-Y4M2HMPR.js → chunk-LW5DHT3Z.js} +2 -2
- package/dist/cli/chunks/{chunk-JC4Z2ADP.js → chunk-MALOUGSF.js} +2 -2
- package/dist/cli/chunks/{chunk-7VM4ZUHT.js → chunk-MCT4CD5M.js} +2 -2
- package/dist/cli/chunks/{chunk-FPZLOVEF.js → chunk-MWFJC5HR.js} +1 -1
- package/dist/cli/chunks/{chunk-7KHZZVF2.js → chunk-MYMIEQSZ.js} +4 -4
- package/dist/cli/chunks/{chunk-EIWZDVMT.js → chunk-N2BJN6AO.js} +3 -3
- package/dist/cli/chunks/{chunk-3J3QXLWP.js → chunk-NBBLPDJX.js} +2 -2
- package/dist/cli/chunks/{chunk-PFDILSVO.js → chunk-NFJT7XXR.js} +1 -1
- package/dist/cli/chunks/{chunk-IXYF5BZY.js → chunk-NSPCZPTB.js} +2 -2
- package/dist/cli/chunks/{chunk-YWG4LHFU.js → chunk-NV3TXXOW.js} +2 -2
- package/dist/cli/chunks/{chunk-ZU3V4CJ4.js → chunk-O5NEJIHB.js} +2 -2
- package/dist/cli/chunks/{chunk-QZLTIGLB.js → chunk-O7PVZ32A.js} +1 -1
- package/dist/cli/chunks/{chunk-42DCMEUM.js → chunk-ODZSQVEW.js} +1 -1
- package/dist/cli/chunks/{chunk-G6LIQFT2.js → chunk-P6S6ZVB5.js} +1 -1
- package/dist/cli/chunks/{chunk-FYY7OJ6Y.js → chunk-PEIQDQXN.js} +2 -2
- package/dist/cli/chunks/{chunk-WZC4HKGZ.js → chunk-PFWJQPUC.js} +2 -2
- package/dist/cli/chunks/{chunk-6SOGYNJG.js → chunk-PQUXFSN6.js} +2 -2
- package/dist/cli/chunks/{chunk-P2RR4SW5.js → chunk-Q7ORVHJB.js} +3 -3
- package/dist/cli/chunks/{chunk-2Q65LTJN.js → chunk-QEVX4GWF.js} +2 -2
- package/dist/cli/chunks/{chunk-AINAWVGD.js → chunk-QJ5NCYJ3.js} +2 -2
- package/dist/cli/chunks/{chunk-75C5GX7D.js → chunk-QMC5MTBV.js} +2 -2
- package/dist/cli/chunks/{chunk-H3LGBH4Y.js → chunk-QSDIY3E2.js} +1 -1
- package/dist/cli/chunks/chunk-RCPD6F4R.js +2 -0
- package/dist/cli/chunks/{chunk-XNREA3FG.js → chunk-RFQBDMAP.js} +1 -1
- package/dist/cli/chunks/{chunk-KO3WB4SU.js → chunk-SFDUT5WM.js} +2 -2
- package/dist/cli/chunks/{chunk-YGR54EAA.js → chunk-SL3SNOO2.js} +2 -2
- package/dist/cli/chunks/{chunk-QFJDR4HC.js → chunk-SRVTNG6L.js} +2 -2
- package/dist/cli/chunks/{chunk-TOGZ37RL.js → chunk-T76RFXQX.js} +2 -2
- package/dist/cli/chunks/{chunk-AAVUZVM6.js → chunk-TCVEKRPI.js} +2 -2
- package/dist/cli/chunks/{chunk-AZQ6HDPM.js → chunk-TCWR6TDN.js} +2 -2
- package/dist/cli/chunks/{chunk-ZP2GE6DM.js → chunk-THKZVOZV.js} +1 -1
- package/dist/cli/chunks/{chunk-4PYJCIRO.js → chunk-TPMBFARK.js} +31 -26
- package/dist/cli/chunks/{chunk-NIW4CLN2.js → chunk-TQ373GGI.js} +2 -2
- package/dist/cli/chunks/{chunk-CUDGKSFX.js → chunk-TSWF3AGQ.js} +2 -2
- package/dist/cli/chunks/{chunk-MN6W7ZNL.js → chunk-TU6YN43Q.js} +1 -1
- package/dist/cli/chunks/{chunk-CAUTOCLZ.js → chunk-U34OZXD6.js} +2 -2
- package/dist/cli/chunks/{chunk-AYXRT2ND.js → chunk-U3AVZGQA.js} +1 -1
- package/dist/cli/chunks/{chunk-NGE5YNKC.js → chunk-UCYTY4LG.js} +2 -2
- package/dist/cli/chunks/{chunk-LRJWKFGY.js → chunk-UJMTKXPI.js} +2 -2
- package/dist/cli/chunks/{chunk-BGVEBYV4.js → chunk-UQ72K44T.js} +2 -2
- package/dist/cli/chunks/{chunk-XY2B2BEJ.js → chunk-VCUCD3B5.js} +2 -2
- package/dist/cli/chunks/{chunk-LY6PTRVL.js → chunk-VJGHRWMH.js} +2 -2
- package/dist/cli/chunks/{chunk-ZRU3OZEU.js → chunk-VKJQAKYG.js} +2 -2
- package/dist/cli/chunks/{chunk-XY4JS3IZ.js → chunk-VO6YJGB4.js} +2 -2
- package/dist/cli/chunks/{chunk-RHSUXQNF.js → chunk-VQU7DMEY.js} +2 -2
- package/dist/cli/chunks/{chunk-27KNLVOY.js → chunk-WMIRAD3J.js} +2 -2
- package/dist/cli/chunks/{chunk-3KTOM7NN.js → chunk-WNMDWP5A.js} +2 -2
- package/dist/cli/chunks/{chunk-G4CQBQBV.js → chunk-WQZ2WRO4.js} +1 -1
- package/dist/cli/chunks/{chunk-UQBGA4UA.js → chunk-WZYNY3VF.js} +1 -1
- package/dist/cli/chunks/{chunk-KEJEZY2R.js → chunk-X64BEXUY.js} +173 -173
- package/dist/cli/chunks/{chunk-7XIQR6VU.js → chunk-XHRLBJTM.js} +2 -2
- package/dist/cli/chunks/{chunk-UQ6WB4N2.js → chunk-XQ6DW5FV.js} +2 -2
- package/dist/cli/chunks/chunk-XXRTWG7O.js +2 -0
- package/dist/cli/chunks/{chunk-LIEA5EON.js → chunk-Y4AXOHW4.js} +1 -1
- package/dist/cli/chunks/{chunk-ZWMXF6AX.js → chunk-YKSWC7I4.js} +2 -2
- package/dist/cli/chunks/{chunk-IMPSB5WW.js → chunk-YNK6SUPU.js} +2 -2
- package/dist/cli/chunks/{chunk-Z2QNTRUX.js → chunk-YUHM72VQ.js} +2 -2
- package/dist/cli/chunks/{chunk-QZ2GQGJX.js → chunk-YZ5EQR37.js} +2 -2
- package/dist/cli/chunks/{chunk-YGRY2TVI.js → chunk-Z2REKBD6.js} +2 -2
- package/dist/cli/chunks/{chunk-ZQYEBLTL.js → chunk-ZFCVT43J.js} +2 -2
- package/dist/cli/chunks/{chunk-XN4G3SRU.js → chunk-ZKCKOQJI.js} +2 -2
- package/dist/cli/chunks/{chunk-CZYSCUJ4.js → chunk-ZSA6V5FH.js} +2 -2
- package/dist/cli/chunks/{chunk-IQOCTGA2.js → chunk-ZSBJNE35.js} +2 -2
- package/dist/cli/chunks/{chunk-JDFF2QMZ.js → chunk-ZYZT2CDX.js} +1 -1
- package/dist/cli/chunks/{ci-SM3EVLZ4.js → ci-HQCRSCC7.js} +2 -2
- package/dist/cli/chunks/{ci-output-YYXICZBC.js → ci-output-YBVXLA6O.js} +2 -2
- package/dist/cli/chunks/{circuit-breaker-CV5UGKXT.js → circuit-breaker-ULGMF2QN.js} +2 -2
- package/dist/cli/chunks/{claude-flow-setup-BSBUZ4B7.js → claude-flow-setup-MKZ2LJXK.js} +2 -2
- package/dist/cli/chunks/client-2OVEDWGU.js +2 -0
- package/dist/cli/chunks/{cline-installer-P2O6STIC.js → cline-installer-WZQ6XBWN.js} +2 -2
- package/dist/cli/chunks/{code-M7DDLBGS.js → code-H3KGH45S.js} +2 -2
- package/dist/cli/chunks/{code-index-extractor-3QZIUYOG.js → code-index-extractor-NUVEAJ7C.js} +2 -2
- package/dist/cli/chunks/{codex-installer-5JVZCCTC.js → codex-installer-JQI6E6CV.js} +2 -2
- package/dist/cli/chunks/{completions-EM7IL2BJ.js → completions-NDF4PFE7.js} +2 -2
- package/dist/cli/chunks/{complexity-analyzer-VJXVB2CV.js → complexity-analyzer-XCZH66HG.js} +2 -2
- package/dist/cli/chunks/{continuedev-installer-RCKJIAEC.js → continuedev-installer-Z4AJGZ7S.js} +2 -2
- package/dist/cli/chunks/{copilot-installer-DZ7LTDOZ.js → copilot-installer-K4IPAL7C.js} +2 -2
- package/dist/cli/chunks/core-handlers-UXRRYP52.js +2 -0
- package/dist/cli/chunks/{cost-tracker-QLOLXVAM.js → cost-tracker-35KXAB23.js} +2 -2
- package/dist/cli/chunks/{coverage-LYHTLWRV.js → coverage-QW5I4TYZ.js} +3 -3
- package/dist/cli/chunks/cross-domain-router-PV3VQVLO.js +2 -0
- package/dist/cli/chunks/{cursor-installer-PSIZ3Y53.js → cursor-installer-P4Z7RMIZ.js} +2 -2
- package/dist/cli/chunks/{daemon-IYDTMA5M.js → daemon-ESUEM6VB.js} +4 -4
- package/dist/cli/chunks/{daemon-YLOAXM4X.js → daemon-WQWTCYBM.js} +3 -3
- package/dist/cli/chunks/{dag-attention-scheduler-I2UIO3Z7.js → dag-attention-scheduler-7XD2VGON.js} +2 -2
- package/dist/cli/chunks/{detect-ZXQ7X7GZ.js → detect-GZ3P4DI7.js} +2 -2
- package/dist/cli/chunks/{dist-node-GK6OZX4H.js → dist-node-6WWAW7OP.js} +2 -2
- package/dist/cli/chunks/{domain-handler-NS3IBLRQ.js → domain-handler-3GTLWARQ.js} +2 -2
- package/dist/cli/chunks/{domain-transfer-5G4RZEWF.js → domain-transfer-TQYO3SVG.js} +2 -2
- package/dist/cli/chunks/dream-UFUXVJQC.js +2 -0
- package/dist/cli/chunks/{embed-and-insert-pattern-V4JJUFR6.js → embed-and-insert-pattern-BGIMA77V.js} +2 -2
- package/dist/cli/chunks/{eval-7Q6PPYKR.js → eval-SXV6DRDD.js} +2 -2
- package/dist/cli/chunks/{experience-capture-middleware-DUBKSYFM.js → experience-capture-middleware-TT6WCT2S.js} +3 -3
- package/dist/cli/chunks/{fast-paths-IDPPMBUW.js → fast-paths-HTAZHEQP.js} +2 -2
- package/dist/cli/chunks/{feature-flags-EPTMAAKA.js → feature-flags-DIE3Z2B4.js} +2 -2
- package/dist/cli/chunks/{feature-flags-KXI6FDY7.js → feature-flags-WBUKU54W.js} +2 -2
- package/dist/cli/chunks/{file-discovery-EDX2OJO7.js → file-discovery-SKDETFS3.js} +2 -2
- package/dist/cli/chunks/{fleet-67BO3LJ4.js → fleet-WCWEPAVU.js} +3 -3
- package/dist/cli/chunks/{gnn-wrapper-YARORYT7.js → gnn-wrapper-KWZOWBYS.js} +2 -2
- package/dist/cli/chunks/{heartbeat-handler-K3JGPBYR.js → heartbeat-handler-3AGYHVG2.js} +4 -4
- package/dist/cli/chunks/heartbeat-scheduler-MBG3SARO.js +2 -0
- package/dist/cli/chunks/hnsw-adapter-5HXA3QB3.js +2 -0
- package/dist/cli/chunks/hnsw-index-PZRQWBRG.js +2 -0
- package/dist/cli/chunks/{hnsw-legacy-bridge-CDDRSV5E.js → hnsw-legacy-bridge-6OJJDZHL.js} +2 -2
- package/dist/cli/chunks/{better-sqlite3-5JTP47LA.js → hnswlib-node-LAFK5QZ4.js} +2 -2
- package/dist/cli/chunks/{hooks-6SCAE6LC.js → hooks-OXEBTLXV.js} +10 -10
- package/dist/cli/chunks/hybrid-router-NQRIE2GG.js +2 -0
- package/dist/cli/chunks/{hypergraph-engine-I3LUMO7I.js → hypergraph-engine-NL74PRHD.js} +2 -2
- package/dist/cli/chunks/{hypergraph-handler-YAKAIVCN.js → hypergraph-handler-KZ54AEEL.js} +3 -3
- package/dist/cli/chunks/impact-analyzer-46347ZDV.js +2 -0
- package/dist/cli/chunks/{init-handler-NBKCZD7Q.js → init-handler-XKZXRXPG.js} +6 -6
- package/dist/cli/chunks/init-wizard-CJYP4WKO.js +2 -0
- package/dist/cli/chunks/kernel-22KQZ56U.js +2 -0
- package/dist/cli/chunks/{kilocode-installer-YGPJCPU3.js → kilocode-installer-WISQMJK7.js} +2 -2
- package/dist/cli/chunks/{kiro-installer-JV3ONVMN.js → kiro-installer-O7TBB3GM.js} +2 -2
- package/dist/cli/chunks/knowledge-graph-KM3JDBGR.js +2 -0
- package/dist/cli/chunks/{learning-2FEZJ5CX.js → learning-6IZBGVRU.js} +3 -3
- package/dist/cli/chunks/{llm-router-SILI4KLU.js → llm-router-QDMQPPQ7.js} +4 -4
- package/dist/cli/chunks/llm-router-service-IFO6GRRO.js +2 -0
- package/dist/cli/chunks/{load-EGXLQVR3.js → load-KLAJJGL5.js} +2 -2
- package/dist/cli/chunks/load-test-TTKCYAPB.js +2 -0
- package/dist/cli/chunks/{mcp-OJH775TL.js → mcp-SZOPQZIZ.js} +2 -2
- package/dist/cli/chunks/{memory-FNEOK4FW.js → memory-G3WY74C6.js} +5 -5
- package/dist/cli/chunks/memory-backend-ELHCX2ZT.js +2 -0
- package/dist/cli/chunks/memory-handlers-3SKYQZTL.js +2 -0
- package/dist/cli/chunks/{multi-model-executor-ORTFWLLE.js → multi-model-executor-TDNQGTOT.js} +2 -2
- package/dist/cli/chunks/{opencode-installer-UAQLW6XX.js → opencode-installer-NGYGEDMV.js} +2 -2
- package/dist/cli/chunks/{orchestrator-VE5KJ2V4.js → orchestrator-KPI5DY2C.js} +5 -5
- package/dist/cli/chunks/pattern-null-store-TMXAYD43.js +2 -0
- package/dist/cli/chunks/{pipeline-FNMDRWTU.js → pipeline-CSDCC675.js} +2 -2
- package/dist/cli/chunks/{platform-MGAKRUQN.js → platform-Q5XKEVKH.js} +2 -2
- package/dist/cli/chunks/{plugin-YX7THX3I.js → plugin-XKKR3GVL.js} +2 -2
- package/dist/cli/chunks/{prime-radiant-advanced-wasm-XJV4RLMK.js → prime-radiant-advanced-wasm-22QVNKEN.js} +2 -2
- package/dist/cli/chunks/protocol-executor-BPLR5EJC.js +2 -0
- package/dist/cli/chunks/{protocol-handler-QFET442Y.js → protocol-handler-REQKTJGG.js} +2 -2
- package/dist/cli/chunks/{prove-QBAESCOC.js → prove-NOFUFSQN.js} +2 -2
- package/dist/cli/chunks/provider-manager-4MMD5QKL.js +2 -0
- package/dist/cli/chunks/qe-reasoning-bank-P7KNT3WZ.js +2 -0
- package/dist/cli/chunks/{quality-ZTNRL6EG.js → quality-3DQ2H5TK.js} +2 -2
- package/dist/cli/chunks/queen-coordinator-NBZZ4MGC.js +2 -0
- package/dist/cli/chunks/{real-embeddings-ZFFDV6HC.js → real-embeddings-FCGNYWLL.js} +2 -2
- package/dist/cli/chunks/{roocode-installer-J4LFL4AE.js → roocode-installer-HX3CNRIR.js} +2 -2
- package/dist/cli/chunks/router-2RXR6J2Q.js +2 -0
- package/dist/cli/chunks/routing-feedback-AVAA76TK.js +2 -0
- package/dist/cli/chunks/{routing-handler-A5QG2TP2.js → routing-handler-YRZ2LDCR.js} +2 -2
- package/dist/cli/chunks/{ruvector-commands-J5JL5WX5.js → ruvector-commands-GCQVBJ4E.js} +2 -2
- package/dist/cli/chunks/{rvf-dual-writer-H7442GMO.js → rvf-dual-writer-B562P3ZC.js} +2 -2
- package/dist/cli/chunks/{rvf-migration-adapter-PTFQUYKC.js → rvf-migration-adapter-NAGFKCMD.js} +2 -2
- package/dist/cli/chunks/{rvf-migration-coordinator-RSNROYRX.js → rvf-migration-coordinator-WWFBEJ5Q.js} +2 -2
- package/dist/cli/chunks/rvf-native-adapter-X2YDJA55.js +2 -0
- package/dist/cli/chunks/safe-db-4PRU65BK.js +2 -0
- package/dist/cli/chunks/schedule-2AST5CHW.js +2 -0
- package/dist/cli/chunks/scheduler-SW6II7OU.js +2 -0
- package/dist/cli/chunks/{security-LHHLMCBA.js → security-IFOYTD75.js} +3 -3
- package/dist/cli/chunks/{shared-rvf-adapter-NPSHVUTM.js → shared-rvf-adapter-TYD5TQ35.js} +2 -2
- package/dist/cli/chunks/{shared-rvf-dual-writer-INQDY5WE.js → shared-rvf-dual-writer-YGOOVDQZ.js} +2 -2
- package/dist/cli/chunks/sqlite-persistence-OB5NEGAK.js +2 -0
- package/dist/cli/chunks/{status-handler-R2KIAMAE.js → status-handler-HFPWSCBY.js} +2 -2
- package/dist/cli/chunks/{structural-health-2VPPIOZX.js → structural-health-KZI6YMKV.js} +2 -2
- package/dist/cli/chunks/{sync-NLASP7AK.js → sync-ABZNNYRC.js} +2 -2
- package/dist/cli/chunks/{sync-ASZ3T5GT.js → sync-Z5BDDBMK.js} +2 -2
- package/dist/cli/chunks/{task-handler-UV5R6LJG.js → task-handler-5ACZEPJ7.js} +2 -2
- package/dist/cli/chunks/{task-handlers-I6YJXPYP.js → task-handlers-UZWDPL6A.js} +3 -3
- package/dist/cli/chunks/{test-TE43TNTI.js → test-APO3MCVV.js} +4 -4
- package/dist/cli/chunks/{test-scheduling-WWWWF2TZ.js → test-scheduling-EFZA5G5C.js} +3 -3
- package/dist/cli/chunks/{token-bootstrap-HEWP7KKS.js → token-bootstrap-J2OPLNUK.js} +2 -2
- package/dist/cli/chunks/{token-usage-3FVHUAW6.js → token-usage-VHWVNN4R.js} +2 -2
- package/dist/cli/chunks/{transformers-O5OFM4XM.js → transformers-PX4HPO75.js} +2 -2
- package/dist/cli/chunks/{tree-sitter-wasm-parser-YOYWFW63.js → tree-sitter-wasm-parser-44HA2Z3F.js} +2 -2
- package/dist/cli/chunks/{types-42GR6PLO.js → types-IMOP7F4R.js} +2 -2
- package/dist/cli/chunks/unified-memory-X7OJYGSD.js +2 -0
- package/dist/cli/chunks/unified-memory-hnsw-O6HOD5YL.js +2 -0
- package/dist/cli/chunks/unified-persistence-C332CER2.js +2 -0
- package/dist/cli/chunks/{upgrade-BU6DJ4LT.js → upgrade-OZ3O6ZZI.js} +2 -2
- package/dist/cli/chunks/{validate-MPTBARGN.js → validate-DRY5BMWX.js} +2 -2
- package/dist/cli/chunks/{validate-swarm-5LUQYHPP.js → validate-swarm-QD3LYPUF.js} +2 -2
- package/dist/cli/chunks/{vibium-MJJDANDL.js → vibium-2J3H2ITD.js} +2 -2
- package/dist/cli/chunks/visual-security-MPUG5HPI.js +2 -0
- package/dist/cli/chunks/{web-tree-sitter-5TF4UGB3.js → web-tree-sitter-KRNUOGKI.js} +2 -2
- package/dist/cli/chunks/{windsurf-installer-NQAOSVCN.js → windsurf-installer-PQIPH3WP.js} +2 -2
- package/dist/cli/chunks/{witness-chain-23UWK2JT.js → witness-chain-HPLOYPS7.js} +2 -2
- package/dist/cli/chunks/witness-chain-Q4BZHPDF.js +2 -0
- package/dist/cli/chunks/{workflow-3QOLXRJC.js → workflow-OAQ3FWCY.js} +4 -4
- package/dist/cli/chunks/workflow-orchestrator-4NDWECYK.js +2 -0
- package/dist/cli/chunks/{wrappers-S6EUZBCX.js → wrappers-UPIU6S5S.js} +2 -2
- package/dist/coordination/consensus/providers/ollama-provider.js +3 -2
- package/dist/feedback/regenerability-gate.d.ts +70 -0
- package/dist/feedback/regenerability-gate.js +91 -0
- package/dist/integrations/ruvector/proof-gate.d.ts +68 -0
- package/dist/integrations/ruvector/proof-gate.js +135 -0
- package/dist/kernel/unified-memory.d.ts +35 -0
- package/dist/kernel/unified-memory.js +105 -0
- package/dist/learning/local-judge-client.js +2 -1
- package/dist/mcp/bundle.js +383 -378
- package/dist/routing/free-tier/coordinator-support.d.ts +6 -3
- package/dist/routing/free-tier/coordinator-support.js +6 -3
- package/dist/routing/free-tier/executor.d.ts +14 -0
- package/dist/routing/free-tier/executor.js +21 -0
- package/dist/routing/free-tier/index.d.ts +1 -0
- package/dist/routing/free-tier/index.js +1 -0
- package/dist/routing/free-tier/pattern-cache.d.ts +57 -0
- package/dist/routing/free-tier/pattern-cache.js +148 -0
- package/dist/routing/free-tier/provider.js +9 -1
- package/dist/routing/value-score.js +3 -0
- package/dist/shared/embeddings/ollama-client.js +2 -1
- package/dist/shared/llm/model-mapping.js +26 -0
- package/dist/shared/llm/model-registry.d.ts +10 -0
- package/dist/shared/llm/model-registry.js +92 -0
- package/dist/shared/llm/ollama-url.d.ts +17 -0
- package/dist/shared/llm/ollama-url.js +25 -0
- package/dist/shared/llm/providers/gemini.js +16 -10
- package/dist/shared/llm/providers/ollama-timeout.d.ts +26 -0
- package/dist/shared/llm/providers/ollama-timeout.js +31 -0
- package/dist/shared/llm/providers/ollama.d.ts +10 -0
- package/dist/shared/llm/providers/ollama.js +31 -4
- package/dist/shared/llm/providers/openrouter.js +20 -20
- package/dist/shared/llm/router/hybrid-router.js +18 -1
- package/dist/validation/conservation-guard.d.ts +39 -0
- package/dist/validation/conservation-guard.js +54 -0
- package/dist/validation/oracle-eval.d.ts +46 -0
- package/dist/validation/oracle-eval.js +108 -0
- package/dist/validation/skill-parity.d.ts +58 -0
- package/dist/validation/skill-parity.js +94 -0
- package/dist/validation/test-gen-prompt.d.ts +10 -0
- package/dist/validation/test-gen-prompt.js +26 -0
- package/package.json +12 -1
- package/dist/cli/chunks/adapter-LDNYC4GH.js +0 -2
- package/dist/cli/chunks/aqe-learning-engine-CA4CT5Q7.js +0 -2
- package/dist/cli/chunks/base-TSDAEMT4.js +0 -2
- package/dist/cli/chunks/browser-workflow-3HCTJBLR.js +0 -2
- package/dist/cli/chunks/chunk-527U4AHC.js +0 -24
- package/dist/cli/chunks/chunk-72VVTMEL.js +0 -2
- package/dist/cli/chunks/chunk-7HYO76F2.js +0 -2
- package/dist/cli/chunks/chunk-K3YM2Z3E.js +0 -2
- package/dist/cli/chunks/client-WRDYZGM2.js +0 -2
- package/dist/cli/chunks/core-handlers-O6E5DNHT.js +0 -2
- package/dist/cli/chunks/cross-domain-router-EV7LQMDO.js +0 -2
- package/dist/cli/chunks/dream-E4C236UL.js +0 -2
- package/dist/cli/chunks/heartbeat-scheduler-WMADLDKT.js +0 -2
- package/dist/cli/chunks/hnsw-adapter-STRDGJ65.js +0 -2
- package/dist/cli/chunks/hnsw-index-DBHX3TSC.js +0 -2
- package/dist/cli/chunks/hybrid-router-L2K55I4T.js +0 -2
- package/dist/cli/chunks/impact-analyzer-WMO7ZGS7.js +0 -2
- package/dist/cli/chunks/init-wizard-ZAB7UZZS.js +0 -2
- package/dist/cli/chunks/kernel-4MUFDEQI.js +0 -2
- package/dist/cli/chunks/knowledge-graph-GZRFGXLX.js +0 -2
- package/dist/cli/chunks/llm-router-service-5ODLU5U5.js +0 -2
- package/dist/cli/chunks/load-test-ZDQFS5XS.js +0 -2
- package/dist/cli/chunks/memory-backend-UK7SQ6ZM.js +0 -2
- package/dist/cli/chunks/memory-handlers-6LDUH3JZ.js +0 -2
- package/dist/cli/chunks/pattern-null-store-LO2QTIBU.js +0 -2
- package/dist/cli/chunks/protocol-executor-JWMYQEOI.js +0 -2
- package/dist/cli/chunks/provider-manager-PEXOHGNB.js +0 -2
- package/dist/cli/chunks/qe-reasoning-bank-7B2G4UGQ.js +0 -2
- package/dist/cli/chunks/queen-coordinator-6OF4HT3S.js +0 -2
- package/dist/cli/chunks/router-GMWRF6DU.js +0 -2
- package/dist/cli/chunks/routing-feedback-XKJSQK3I.js +0 -2
- package/dist/cli/chunks/rvf-native-adapter-YEA6TMXB.js +0 -2
- package/dist/cli/chunks/safe-db-5DOP2J3V.js +0 -2
- package/dist/cli/chunks/schedule-SUWTOBHP.js +0 -2
- package/dist/cli/chunks/scheduler-P4VTC5SQ.js +0 -2
- package/dist/cli/chunks/sqlite-persistence-5Z2RAXH7.js +0 -2
- package/dist/cli/chunks/unified-memory-HCKOPFAY.js +0 -2
- package/dist/cli/chunks/unified-memory-hnsw-6NQPYA5C.js +0 -2
- package/dist/cli/chunks/unified-persistence-NIMKNAFR.js +0 -2
- package/dist/cli/chunks/visual-security-HFGHA57Z.js +0 -2
- package/dist/cli/chunks/witness-chain-VZGGJ7TJ.js +0 -2
- package/dist/cli/chunks/workflow-orchestrator-45L7D4SN.js +0 -2
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adaptive request-timeout sizing for local Ollama generations (#3).
|
|
3
|
+
*
|
|
4
|
+
* Local models vary ~6× in speed (a dense 27B ≈ 15 tok/s vs a 30B MoE ≈ 90
|
|
5
|
+
* tok/s on the same Mac) and thinking models can spend thousands of tokens
|
|
6
|
+
* before answering, so one fixed timeout either strands fast models or times
|
|
7
|
+
* out slow ones mid-generation. We size the timeout from the output cap
|
|
8
|
+
* (num_predict) and the model's observed throughput, with generous headroom.
|
|
9
|
+
*
|
|
10
|
+
* Pure + dependency-free so it is unit-testable in isolation.
|
|
11
|
+
*/
|
|
12
|
+
export declare const OLLAMA_TIMEOUT: {
|
|
13
|
+
/** Conservative throughput assumed before a model has been observed (dense floor). */
|
|
14
|
+
readonly DEFAULT_TOK_PER_SEC: 15;
|
|
15
|
+
/** Multiplier over ideal generation time to absorb variance. */
|
|
16
|
+
readonly SAFETY_FACTOR: 2.5;
|
|
17
|
+
/** Fixed overhead for cold model load / prompt eval (~6–9s measured). */
|
|
18
|
+
readonly LOAD_OVERHEAD_MS: 15000;
|
|
19
|
+
/** Never time out faster than this. */
|
|
20
|
+
readonly FLOOR_MS: 30000;
|
|
21
|
+
/** Never wait longer than this. */
|
|
22
|
+
readonly CEIL_MS: 600000;
|
|
23
|
+
};
|
|
24
|
+
/** Size a timeout (ms) from the output token cap and observed tok/s. */
|
|
25
|
+
export declare function computeAdaptiveTimeoutMs(numPredict: number, tokPerSec?: number): number;
|
|
26
|
+
//# sourceMappingURL=ollama-timeout.d.ts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adaptive request-timeout sizing for local Ollama generations (#3).
|
|
3
|
+
*
|
|
4
|
+
* Local models vary ~6× in speed (a dense 27B ≈ 15 tok/s vs a 30B MoE ≈ 90
|
|
5
|
+
* tok/s on the same Mac) and thinking models can spend thousands of tokens
|
|
6
|
+
* before answering, so one fixed timeout either strands fast models or times
|
|
7
|
+
* out slow ones mid-generation. We size the timeout from the output cap
|
|
8
|
+
* (num_predict) and the model's observed throughput, with generous headroom.
|
|
9
|
+
*
|
|
10
|
+
* Pure + dependency-free so it is unit-testable in isolation.
|
|
11
|
+
*/
|
|
12
|
+
export const OLLAMA_TIMEOUT = {
|
|
13
|
+
/** Conservative throughput assumed before a model has been observed (dense floor). */
|
|
14
|
+
DEFAULT_TOK_PER_SEC: 15,
|
|
15
|
+
/** Multiplier over ideal generation time to absorb variance. */
|
|
16
|
+
SAFETY_FACTOR: 2.5,
|
|
17
|
+
/** Fixed overhead for cold model load / prompt eval (~6–9s measured). */
|
|
18
|
+
LOAD_OVERHEAD_MS: 15_000,
|
|
19
|
+
/** Never time out faster than this. */
|
|
20
|
+
FLOOR_MS: 30_000,
|
|
21
|
+
/** Never wait longer than this. */
|
|
22
|
+
CEIL_MS: 600_000,
|
|
23
|
+
};
|
|
24
|
+
/** Size a timeout (ms) from the output token cap and observed tok/s. */
|
|
25
|
+
export function computeAdaptiveTimeoutMs(numPredict, tokPerSec = OLLAMA_TIMEOUT.DEFAULT_TOK_PER_SEC) {
|
|
26
|
+
const tps = tokPerSec > 0 ? tokPerSec : OLLAMA_TIMEOUT.DEFAULT_TOK_PER_SEC;
|
|
27
|
+
const genMs = (Math.max(0, numPredict) / tps) * 1000;
|
|
28
|
+
const computed = genMs * OLLAMA_TIMEOUT.SAFETY_FACTOR + OLLAMA_TIMEOUT.LOAD_OVERHEAD_MS;
|
|
29
|
+
return Math.min(OLLAMA_TIMEOUT.CEIL_MS, Math.max(OLLAMA_TIMEOUT.FLOOR_MS, Math.round(computed)));
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=ollama-timeout.js.map
|
|
@@ -19,7 +19,17 @@ export declare class OllamaProvider implements LLMProvider {
|
|
|
19
19
|
private config;
|
|
20
20
|
private requestId;
|
|
21
21
|
private availableModels;
|
|
22
|
+
/** EMA of observed generation throughput (tok/s) per model, for adaptive timeouts (#3). */
|
|
23
|
+
private observedTokPerSec;
|
|
22
24
|
constructor(config?: Partial<OllamaConfig>);
|
|
25
|
+
/**
|
|
26
|
+
* Adaptive per-request timeout (#3). An explicitly customized config.timeoutMs
|
|
27
|
+
* (≠ the built-in default) is honored as the caller's intent; otherwise the
|
|
28
|
+
* timeout is sized from num_predict and the model's observed throughput.
|
|
29
|
+
*/
|
|
30
|
+
private timeoutFor;
|
|
31
|
+
/** Fold a completed generation's throughput into the per-model EMA. */
|
|
32
|
+
private recordThroughput;
|
|
23
33
|
/**
|
|
24
34
|
* Check if Ollama is available and running
|
|
25
35
|
*/
|
|
@@ -8,12 +8,14 @@
|
|
|
8
8
|
import { createLLMError, } from '../interfaces';
|
|
9
9
|
import { CostTracker } from '../cost-tracker';
|
|
10
10
|
import { TokenMetricsCollector } from '../../../learning/token-tracker.js';
|
|
11
|
+
import { resolveOllamaBaseUrl } from '../ollama-url.js';
|
|
12
|
+
import { computeAdaptiveTimeoutMs } from './ollama-timeout.js';
|
|
11
13
|
/**
|
|
12
14
|
* Default Ollama configuration
|
|
13
15
|
*/
|
|
14
16
|
export const DEFAULT_OLLAMA_CONFIG = {
|
|
15
17
|
model: 'llama3.1',
|
|
16
|
-
baseUrl: 'http://localhost:11434',
|
|
18
|
+
baseUrl: resolveOllamaBaseUrl('http://localhost:11434'),
|
|
17
19
|
maxTokens: 4096,
|
|
18
20
|
temperature: 0.7,
|
|
19
21
|
timeoutMs: 120000, // Longer timeout for local models
|
|
@@ -32,9 +34,32 @@ export class OllamaProvider {
|
|
|
32
34
|
config;
|
|
33
35
|
requestId = 0;
|
|
34
36
|
availableModels = [];
|
|
37
|
+
/** EMA of observed generation throughput (tok/s) per model, for adaptive timeouts (#3). */
|
|
38
|
+
observedTokPerSec = new Map();
|
|
35
39
|
constructor(config = {}) {
|
|
36
40
|
this.config = { ...DEFAULT_OLLAMA_CONFIG, ...config };
|
|
37
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Adaptive per-request timeout (#3). An explicitly customized config.timeoutMs
|
|
44
|
+
* (≠ the built-in default) is honored as the caller's intent; otherwise the
|
|
45
|
+
* timeout is sized from num_predict and the model's observed throughput.
|
|
46
|
+
*/
|
|
47
|
+
timeoutFor(model, numPredict) {
|
|
48
|
+
const configured = this.config.timeoutMs;
|
|
49
|
+
if (configured && configured !== DEFAULT_OLLAMA_CONFIG.timeoutMs)
|
|
50
|
+
return configured;
|
|
51
|
+
return computeAdaptiveTimeoutMs(numPredict, this.observedTokPerSec.get(model));
|
|
52
|
+
}
|
|
53
|
+
/** Fold a completed generation's throughput into the per-model EMA. */
|
|
54
|
+
recordThroughput(model, evalCount, evalDurationNs) {
|
|
55
|
+
if (!evalCount || !evalDurationNs || evalDurationNs <= 0)
|
|
56
|
+
return;
|
|
57
|
+
const sample = evalCount / (evalDurationNs / 1e9);
|
|
58
|
+
if (!Number.isFinite(sample) || sample <= 0)
|
|
59
|
+
return;
|
|
60
|
+
const prev = this.observedTokPerSec.get(model);
|
|
61
|
+
this.observedTokPerSec.set(model, prev ? prev * 0.5 + sample * 0.5 : sample);
|
|
62
|
+
}
|
|
38
63
|
/**
|
|
39
64
|
* Check if Ollama is available and running
|
|
40
65
|
*/
|
|
@@ -132,12 +157,13 @@ export class OllamaProvider {
|
|
|
132
157
|
stop: options?.stopSequences,
|
|
133
158
|
},
|
|
134
159
|
}),
|
|
135
|
-
}, options?.timeoutMs ?? this.
|
|
160
|
+
}, options?.timeoutMs ?? this.timeoutFor(model, maxTokens));
|
|
136
161
|
if (!response.ok) {
|
|
137
162
|
throw await this.handleApiError(response, model);
|
|
138
163
|
}
|
|
139
164
|
const data = await response.json();
|
|
140
165
|
content = data.message.content;
|
|
166
|
+
this.recordThroughput(model, data.eval_count, data.eval_duration);
|
|
141
167
|
promptTokens = data.prompt_eval_count ?? this.estimateTokens(JSON.stringify(messages));
|
|
142
168
|
completionTokens = data.eval_count ?? this.estimateTokens(content);
|
|
143
169
|
}
|
|
@@ -158,12 +184,13 @@ export class OllamaProvider {
|
|
|
158
184
|
stop: options?.stopSequences,
|
|
159
185
|
},
|
|
160
186
|
}),
|
|
161
|
-
}, options?.timeoutMs ?? this.
|
|
187
|
+
}, options?.timeoutMs ?? this.timeoutFor(model, maxTokens));
|
|
162
188
|
if (!response.ok) {
|
|
163
189
|
throw await this.handleApiError(response, model);
|
|
164
190
|
}
|
|
165
191
|
const data = await response.json();
|
|
166
192
|
content = data.response;
|
|
193
|
+
this.recordThroughput(model, data.eval_count, data.eval_duration);
|
|
167
194
|
promptTokens = data.prompt_eval_count ?? this.estimateTokens(prompt);
|
|
168
195
|
completionTokens = data.eval_count ?? this.estimateTokens(content);
|
|
169
196
|
}
|
|
@@ -321,7 +348,7 @@ export class OllamaProvider {
|
|
|
321
348
|
* Get base URL
|
|
322
349
|
*/
|
|
323
350
|
getBaseUrl() {
|
|
324
|
-
return (this.config.baseUrl ??
|
|
351
|
+
return (this.config.baseUrl ?? resolveOllamaBaseUrl()).replace(/\/$/, '');
|
|
325
352
|
}
|
|
326
353
|
/**
|
|
327
354
|
* Format input to messages array for chat API
|
|
@@ -61,7 +61,7 @@ export const OPENROUTER_PRICING = {
|
|
|
61
61
|
* OpenRouter LLM provider implementation
|
|
62
62
|
*/
|
|
63
63
|
export class OpenRouterProvider {
|
|
64
|
-
type = '
|
|
64
|
+
type = 'openrouter';
|
|
65
65
|
name = 'OpenRouter';
|
|
66
66
|
config;
|
|
67
67
|
requestId = 0;
|
|
@@ -138,7 +138,7 @@ export class OpenRouterProvider {
|
|
|
138
138
|
async generate(input, options) {
|
|
139
139
|
const apiKey = this.getApiKey();
|
|
140
140
|
if (!apiKey) {
|
|
141
|
-
throw createLLMError('OpenRouter API key not configured', 'API_KEY_MISSING', { provider: '
|
|
141
|
+
throw createLLMError('OpenRouter API key not configured', 'API_KEY_MISSING', { provider: 'openrouter', retryable: false });
|
|
142
142
|
}
|
|
143
143
|
const messages = this.formatMessages(input, options?.systemPrompt);
|
|
144
144
|
const model = options?.model ?? this.config.model;
|
|
@@ -193,7 +193,7 @@ export class OpenRouterProvider {
|
|
|
193
193
|
return {
|
|
194
194
|
content,
|
|
195
195
|
model: data.model,
|
|
196
|
-
provider: '
|
|
196
|
+
provider: 'openrouter',
|
|
197
197
|
usage,
|
|
198
198
|
cost,
|
|
199
199
|
latencyMs,
|
|
@@ -206,7 +206,7 @@ export class OpenRouterProvider {
|
|
|
206
206
|
if (error instanceof Error && 'code' in error) {
|
|
207
207
|
throw error; // Re-throw LLM errors
|
|
208
208
|
}
|
|
209
|
-
throw createLLMError(error instanceof Error ? error.message : 'Request failed', 'NETWORK_ERROR', { provider: '
|
|
209
|
+
throw createLLMError(error instanceof Error ? error.message : 'Request failed', 'NETWORK_ERROR', { provider: 'openrouter', model, retryable: true, cause: error });
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
/**
|
|
@@ -216,7 +216,7 @@ export class OpenRouterProvider {
|
|
|
216
216
|
async *generateStream(input, options) {
|
|
217
217
|
const apiKey = this.getApiKey();
|
|
218
218
|
if (!apiKey) {
|
|
219
|
-
throw createLLMError('OpenRouter API key not configured', 'API_KEY_MISSING', { provider: '
|
|
219
|
+
throw createLLMError('OpenRouter API key not configured', 'API_KEY_MISSING', { provider: 'openrouter', retryable: false });
|
|
220
220
|
}
|
|
221
221
|
const messages = this.formatMessages(input, options?.systemPrompt);
|
|
222
222
|
const model = options?.model ?? this.config.model;
|
|
@@ -246,7 +246,7 @@ export class OpenRouterProvider {
|
|
|
246
246
|
throw this.handleApiError(response.status, errorData, model);
|
|
247
247
|
}
|
|
248
248
|
if (!response.body) {
|
|
249
|
-
throw createLLMError('No response body for streaming', 'NETWORK_ERROR', { provider: '
|
|
249
|
+
throw createLLMError('No response body for streaming', 'NETWORK_ERROR', { provider: 'openrouter', model, retryable: true });
|
|
250
250
|
}
|
|
251
251
|
let fullContent = '';
|
|
252
252
|
let finishReason = 'stop';
|
|
@@ -311,7 +311,7 @@ export class OpenRouterProvider {
|
|
|
311
311
|
return {
|
|
312
312
|
content: fullContent,
|
|
313
313
|
model: responseModel,
|
|
314
|
-
provider: '
|
|
314
|
+
provider: 'openrouter',
|
|
315
315
|
usage,
|
|
316
316
|
cost,
|
|
317
317
|
latencyMs,
|
|
@@ -327,7 +327,7 @@ export class OpenRouterProvider {
|
|
|
327
327
|
async embed(text, options) {
|
|
328
328
|
const apiKey = this.getApiKey();
|
|
329
329
|
if (!apiKey) {
|
|
330
|
-
throw createLLMError('OpenRouter API key not configured', 'API_KEY_MISSING', { provider: '
|
|
330
|
+
throw createLLMError('OpenRouter API key not configured', 'API_KEY_MISSING', { provider: 'openrouter', retryable: false });
|
|
331
331
|
}
|
|
332
332
|
const model = options?.model ?? 'openai/text-embedding-3-small';
|
|
333
333
|
const start = Date.now();
|
|
@@ -351,7 +351,7 @@ export class OpenRouterProvider {
|
|
|
351
351
|
return {
|
|
352
352
|
embedding: data.data[0].embedding,
|
|
353
353
|
model: data.model,
|
|
354
|
-
provider: '
|
|
354
|
+
provider: 'openrouter',
|
|
355
355
|
tokenCount: data.usage.total_tokens,
|
|
356
356
|
latencyMs,
|
|
357
357
|
cached: false,
|
|
@@ -361,7 +361,7 @@ export class OpenRouterProvider {
|
|
|
361
361
|
if (error instanceof Error && 'code' in error) {
|
|
362
362
|
throw error;
|
|
363
363
|
}
|
|
364
|
-
throw createLLMError(error instanceof Error ? error.message : 'Embedding request failed', 'NETWORK_ERROR', { provider: '
|
|
364
|
+
throw createLLMError(error instanceof Error ? error.message : 'Embedding request failed', 'NETWORK_ERROR', { provider: 'openrouter', model, retryable: true, cause: error });
|
|
365
365
|
}
|
|
366
366
|
}
|
|
367
367
|
/**
|
|
@@ -378,7 +378,7 @@ export class OpenRouterProvider {
|
|
|
378
378
|
return {
|
|
379
379
|
completion: response.content,
|
|
380
380
|
model: response.model,
|
|
381
|
-
provider: '
|
|
381
|
+
provider: 'openrouter',
|
|
382
382
|
usage: response.usage,
|
|
383
383
|
latencyMs: response.latencyMs,
|
|
384
384
|
cached: response.cached,
|
|
@@ -525,19 +525,19 @@ export class OpenRouterProvider {
|
|
|
525
525
|
switch (status) {
|
|
526
526
|
case 401:
|
|
527
527
|
throw createLLMError(message, 'API_KEY_INVALID', {
|
|
528
|
-
provider: '
|
|
528
|
+
provider: 'openrouter',
|
|
529
529
|
model,
|
|
530
530
|
retryable: false,
|
|
531
531
|
});
|
|
532
532
|
case 402:
|
|
533
533
|
throw createLLMError(message, 'COST_LIMIT_EXCEEDED', {
|
|
534
|
-
provider: '
|
|
534
|
+
provider: 'openrouter',
|
|
535
535
|
model,
|
|
536
536
|
retryable: false,
|
|
537
537
|
});
|
|
538
538
|
case 429:
|
|
539
539
|
throw createLLMError(message, 'RATE_LIMITED', {
|
|
540
|
-
provider: '
|
|
540
|
+
provider: 'openrouter',
|
|
541
541
|
model,
|
|
542
542
|
retryable: true,
|
|
543
543
|
retryAfterMs: 60000,
|
|
@@ -545,19 +545,19 @@ export class OpenRouterProvider {
|
|
|
545
545
|
case 400:
|
|
546
546
|
if (errorCode === 'context_length_exceeded' || errorType === 'invalid_request_error') {
|
|
547
547
|
throw createLLMError(message, 'CONTEXT_LENGTH_EXCEEDED', {
|
|
548
|
-
provider: '
|
|
548
|
+
provider: 'openrouter',
|
|
549
549
|
model,
|
|
550
550
|
retryable: false,
|
|
551
551
|
});
|
|
552
552
|
}
|
|
553
553
|
throw createLLMError(message, 'UNKNOWN', {
|
|
554
|
-
provider: '
|
|
554
|
+
provider: 'openrouter',
|
|
555
555
|
model,
|
|
556
556
|
retryable: false,
|
|
557
557
|
});
|
|
558
558
|
case 404:
|
|
559
559
|
throw createLLMError(message, 'MODEL_NOT_FOUND', {
|
|
560
|
-
provider: '
|
|
560
|
+
provider: 'openrouter',
|
|
561
561
|
model,
|
|
562
562
|
retryable: false,
|
|
563
563
|
});
|
|
@@ -565,14 +565,14 @@ export class OpenRouterProvider {
|
|
|
565
565
|
case 502:
|
|
566
566
|
case 503:
|
|
567
567
|
throw createLLMError(message, 'PROVIDER_UNAVAILABLE', {
|
|
568
|
-
provider: '
|
|
568
|
+
provider: 'openrouter',
|
|
569
569
|
model,
|
|
570
570
|
retryable: true,
|
|
571
571
|
retryAfterMs: 5000,
|
|
572
572
|
});
|
|
573
573
|
default:
|
|
574
574
|
throw createLLMError(message, 'UNKNOWN', {
|
|
575
|
-
provider: '
|
|
575
|
+
provider: 'openrouter',
|
|
576
576
|
model,
|
|
577
577
|
retryable: false,
|
|
578
578
|
});
|
|
@@ -594,7 +594,7 @@ export class OpenRouterProvider {
|
|
|
594
594
|
catch (error) {
|
|
595
595
|
if (error instanceof Error && error.name === 'AbortError') {
|
|
596
596
|
throw createLLMError('Request timed out', 'TIMEOUT', {
|
|
597
|
-
provider: '
|
|
597
|
+
provider: 'openrouter',
|
|
598
598
|
retryable: true,
|
|
599
599
|
});
|
|
600
600
|
}
|
|
@@ -17,6 +17,7 @@ import { applyCyberPin, CYBER_PIN_CHAT_FALLBACK, shouldCyberPin, isOpus47, } fro
|
|
|
17
17
|
import { createRouterMetricsCollector, createCostMetricsCollector, } from '../metrics';
|
|
18
18
|
import { toError } from '../../error-utils.js';
|
|
19
19
|
import { mapModelId, normalizeModelId, getModelMapping, } from '../model-mapping';
|
|
20
|
+
import { modelSupportsTools } from '../model-registry';
|
|
20
21
|
/**
|
|
21
22
|
* Simple LRU-like decision cache
|
|
22
23
|
*/
|
|
@@ -472,8 +473,24 @@ export class HybridRouter {
|
|
|
472
473
|
executionOrder.push({ provider: entry.provider, model });
|
|
473
474
|
}
|
|
474
475
|
}
|
|
476
|
+
// Capability-aware guard: when the request needs tools, drop any candidate
|
|
477
|
+
// whose model is KNOWN to lack tool support (e.g. local llama3, codellama,
|
|
478
|
+
// mistral) so we don't silently strip tool definitions and return a
|
|
479
|
+
// degraded answer. Fail-open — if every candidate is tool-less (or
|
|
480
|
+
// unrecognized) we keep the original order rather than strand the request.
|
|
481
|
+
let order = executionOrder;
|
|
482
|
+
if (params.requiresTools) {
|
|
483
|
+
const toolCapable = executionOrder.filter((e) => modelSupportsTools(e.model));
|
|
484
|
+
if (toolCapable.length > 0 && toolCapable.length < executionOrder.length) {
|
|
485
|
+
const skipped = executionOrder
|
|
486
|
+
.filter((e) => !modelSupportsTools(e.model))
|
|
487
|
+
.map((e) => `${e.provider}:${e.model}`);
|
|
488
|
+
console.warn(`[llm-router] requiresTools: skipping tool-less model(s) ${skipped.join(', ')}`);
|
|
489
|
+
order = toolCapable;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
475
492
|
// Execute with fallback
|
|
476
|
-
for (const { provider: providerType, model } of
|
|
493
|
+
for (const { provider: providerType, model } of order) {
|
|
477
494
|
if (attempts >= fallbackBehavior.maxAttempts)
|
|
478
495
|
break;
|
|
479
496
|
const provider = this.providerManager.getProvider(providerType);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conservation Guard (Phoenix essay 14 "UI Is a Conservation Layer", ADR-114)
|
|
3
|
+
*
|
|
4
|
+
* AQE's human/agent-facing surfaces — CLI commands, output schemas, MCP tools,
|
|
5
|
+
* the dashboard — are its conservation layer: users and CI pipelines build muscle
|
|
6
|
+
* memory and scripts around them. Internals may regenerate freely; these surfaces
|
|
7
|
+
* must change slowly and ADDITIVELY. This module diffs a captured baseline against
|
|
8
|
+
* the current surface and flags breaking removals/renames that are not in the
|
|
9
|
+
* deprecation registry.
|
|
10
|
+
*
|
|
11
|
+
* Pure functions only — extraction + I/O live in scripts/conservation-guard.ts.
|
|
12
|
+
*/
|
|
13
|
+
export interface SurfaceDiff {
|
|
14
|
+
surface: string;
|
|
15
|
+
/** Entries present now but not in the baseline — additive, always allowed. */
|
|
16
|
+
added: string[];
|
|
17
|
+
/** Entries removed from the baseline and NOT in the deprecation registry — breaking. */
|
|
18
|
+
removedBreaking: string[];
|
|
19
|
+
/** Entries removed but listed as deprecated — an allowed, deliberate removal. */
|
|
20
|
+
removedDeprecated: string[];
|
|
21
|
+
/** True when there are no breaking removals. */
|
|
22
|
+
clean: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Diff one surface. Additive changes pass; a removal/rename is breaking unless the
|
|
26
|
+
* removed entry appears in `deprecated` (the deprecation window has been honored).
|
|
27
|
+
*/
|
|
28
|
+
export declare function diffSurface(surface: string, baseline: string[], current: string[], deprecated?: string[]): SurfaceDiff;
|
|
29
|
+
export interface ConservationReport {
|
|
30
|
+
diffs: SurfaceDiff[];
|
|
31
|
+
clean: boolean;
|
|
32
|
+
/** Total breaking removals across all surfaces. */
|
|
33
|
+
breakingCount: number;
|
|
34
|
+
}
|
|
35
|
+
/** Aggregate per-surface diffs into an overall verdict. */
|
|
36
|
+
export declare function aggregate(diffs: SurfaceDiff[]): ConservationReport;
|
|
37
|
+
/** Human-readable report (used by the CLI guard and CI logs). */
|
|
38
|
+
export declare function formatReport(report: ConservationReport): string;
|
|
39
|
+
//# sourceMappingURL=conservation-guard.d.ts.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conservation Guard (Phoenix essay 14 "UI Is a Conservation Layer", ADR-114)
|
|
3
|
+
*
|
|
4
|
+
* AQE's human/agent-facing surfaces — CLI commands, output schemas, MCP tools,
|
|
5
|
+
* the dashboard — are its conservation layer: users and CI pipelines build muscle
|
|
6
|
+
* memory and scripts around them. Internals may regenerate freely; these surfaces
|
|
7
|
+
* must change slowly and ADDITIVELY. This module diffs a captured baseline against
|
|
8
|
+
* the current surface and flags breaking removals/renames that are not in the
|
|
9
|
+
* deprecation registry.
|
|
10
|
+
*
|
|
11
|
+
* Pure functions only — extraction + I/O live in scripts/conservation-guard.ts.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Diff one surface. Additive changes pass; a removal/rename is breaking unless the
|
|
15
|
+
* removed entry appears in `deprecated` (the deprecation window has been honored).
|
|
16
|
+
*/
|
|
17
|
+
export function diffSurface(surface, baseline, current, deprecated = []) {
|
|
18
|
+
const cur = new Set(current);
|
|
19
|
+
const dep = new Set(deprecated);
|
|
20
|
+
const added = current.filter((e) => !baseline.includes(e)).sort();
|
|
21
|
+
const removed = baseline.filter((e) => !cur.has(e));
|
|
22
|
+
const removedBreaking = removed.filter((e) => !dep.has(e)).sort();
|
|
23
|
+
const removedDeprecated = removed.filter((e) => dep.has(e)).sort();
|
|
24
|
+
return {
|
|
25
|
+
surface,
|
|
26
|
+
added,
|
|
27
|
+
removedBreaking,
|
|
28
|
+
removedDeprecated,
|
|
29
|
+
clean: removedBreaking.length === 0,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** Aggregate per-surface diffs into an overall verdict. */
|
|
33
|
+
export function aggregate(diffs) {
|
|
34
|
+
const breakingCount = diffs.reduce((n, d) => n + d.removedBreaking.length, 0);
|
|
35
|
+
return { diffs, clean: breakingCount === 0, breakingCount };
|
|
36
|
+
}
|
|
37
|
+
/** Human-readable report (used by the CLI guard and CI logs). */
|
|
38
|
+
export function formatReport(report) {
|
|
39
|
+
const lines = [];
|
|
40
|
+
for (const d of report.diffs) {
|
|
41
|
+
const status = d.clean ? '✓' : '✗ BREAKING';
|
|
42
|
+
lines.push(`${status} ${d.surface}: +${d.added.length} added, -${d.removedBreaking.length} breaking, -${d.removedDeprecated.length} deprecated`);
|
|
43
|
+
for (const r of d.removedBreaking)
|
|
44
|
+
lines.push(` REMOVED (breaking): ${r}`);
|
|
45
|
+
for (const r of d.removedDeprecated)
|
|
46
|
+
lines.push(` removed (deprecated, ok): ${r}`);
|
|
47
|
+
}
|
|
48
|
+
lines.push('');
|
|
49
|
+
lines.push(report.clean
|
|
50
|
+
? '✓ conservation guard: no breaking surface changes'
|
|
51
|
+
: `✗ conservation guard: ${report.breakingCount} breaking surface change(s) — add to the deprecation registry (with a deprecation window) or restore them. To intentionally rebaseline: --update.`);
|
|
52
|
+
return lines.join('\n');
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=conservation-guard.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agentic QE v3 - Oracle Evaluator for skill evals (Oracle-Evals plan, Phase 0/1)
|
|
3
|
+
*
|
|
4
|
+
* Turns a skill eval from a keyword grep into a real ORACLE: it RUNS a
|
|
5
|
+
* generated test against a reference implementation (must pass) and against
|
|
6
|
+
* first-order operator mutants of that implementation (each surviving mutant
|
|
7
|
+
* is a bug the test failed to catch). The mutation kill rate is the eval's
|
|
8
|
+
* pass signal — a test that asserts nothing scores 0 and fails.
|
|
9
|
+
*
|
|
10
|
+
* Reuses the proven qe-arena primitives (ADR-104): the deterministic operator
|
|
11
|
+
* mutator and the real `node --test` fixture runner. Nothing is simulated.
|
|
12
|
+
*/
|
|
13
|
+
export interface OracleSpec {
|
|
14
|
+
/** Base name (no extension) for the module under test, e.g. "inRange". */
|
|
15
|
+
moduleName: string;
|
|
16
|
+
/** ESM source of the correct implementation, e.g. `export function inRange(...) {...}`. */
|
|
17
|
+
referenceImpl: string;
|
|
18
|
+
/** Generated test source. Imports the impl as `../src/<moduleName>.mjs`. */
|
|
19
|
+
generatedTest: string;
|
|
20
|
+
/** Cap on mutants evaluated (deterministic prefix of the position-sorted list). */
|
|
21
|
+
maxMutants?: number;
|
|
22
|
+
/** Minimum mutation kill rate required to pass. Default 0.5. */
|
|
23
|
+
threshold?: number;
|
|
24
|
+
/** Per-`node --test` timeout in ms. Default 30s (evals run many subprocesses). */
|
|
25
|
+
timeoutMs?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface OracleResult {
|
|
28
|
+
/** Did the generated test pass against the unmutated reference implementation? */
|
|
29
|
+
baselinePassed: boolean;
|
|
30
|
+
mutantsTotal: number;
|
|
31
|
+
mutantsKilled: number;
|
|
32
|
+
/** killed / total, rounded to 4dp (0 when there are no mutants). */
|
|
33
|
+
mutationScore: number;
|
|
34
|
+
/** Mutant ids the test failed to catch (bugs it would let through). */
|
|
35
|
+
survivedMutantIds: string[];
|
|
36
|
+
/** baselinePassed AND mutationScore >= threshold AND at least one mutant existed. */
|
|
37
|
+
passed: boolean;
|
|
38
|
+
/** Human-readable explanation of the verdict. */
|
|
39
|
+
reason: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Evaluate a generated test as an oracle against a reference implementation.
|
|
43
|
+
* Real `node --test` runs; deterministic mutant enumeration.
|
|
44
|
+
*/
|
|
45
|
+
export declare function evaluateOracle(spec: OracleSpec): OracleResult;
|
|
46
|
+
//# sourceMappingURL=oracle-eval.d.ts.map
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agentic QE v3 - Oracle Evaluator for skill evals (Oracle-Evals plan, Phase 0/1)
|
|
3
|
+
*
|
|
4
|
+
* Turns a skill eval from a keyword grep into a real ORACLE: it RUNS a
|
|
5
|
+
* generated test against a reference implementation (must pass) and against
|
|
6
|
+
* first-order operator mutants of that implementation (each surviving mutant
|
|
7
|
+
* is a bug the test failed to catch). The mutation kill rate is the eval's
|
|
8
|
+
* pass signal — a test that asserts nothing scores 0 and fails.
|
|
9
|
+
*
|
|
10
|
+
* Reuses the proven qe-arena primitives (ADR-104): the deterministic operator
|
|
11
|
+
* mutator and the real `node --test` fixture runner. Nothing is simulated.
|
|
12
|
+
*/
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
import { enumerateMutants, applyMutant } from '../arena/mutator.js';
|
|
16
|
+
import { runNodeTest, makeTmpRoot, cleanupTmpRoot } from '../arena/runner.js';
|
|
17
|
+
/** Write a throwaway { src/<m>.mjs, tests/<m>.test.mjs } workspace and return its dir. */
|
|
18
|
+
function materialize(tmpRoot, moduleName, impl, test) {
|
|
19
|
+
const dir = fs.mkdtempSync(path.join(tmpRoot, 'oracle-ws-'));
|
|
20
|
+
fs.mkdirSync(path.join(dir, 'src'), { recursive: true });
|
|
21
|
+
fs.mkdirSync(path.join(dir, 'tests'), { recursive: true });
|
|
22
|
+
fs.writeFileSync(path.join(dir, 'src', `${moduleName}.mjs`), impl);
|
|
23
|
+
fs.writeFileSync(path.join(dir, 'tests', `${moduleName}.test.mjs`), test);
|
|
24
|
+
return dir;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Evaluate a generated test as an oracle against a reference implementation.
|
|
28
|
+
* Real `node --test` runs; deterministic mutant enumeration.
|
|
29
|
+
*/
|
|
30
|
+
export function evaluateOracle(spec) {
|
|
31
|
+
const threshold = spec.threshold ?? 0.5;
|
|
32
|
+
const timeoutMs = spec.timeoutMs ?? 30_000;
|
|
33
|
+
const tmpRoot = makeTmpRoot();
|
|
34
|
+
try {
|
|
35
|
+
// 0. Sanity: reject output that is not a runnable, asserting test. An empty
|
|
36
|
+
// or assertion-less file passes `node --test` (exit 0) but proves nothing —
|
|
37
|
+
// catch it here so the verdict is honest rather than relying on a 0 kill rate.
|
|
38
|
+
if (!/assert\s*[.(]|expect\s*\(|\.(toBe|toEqual|toThrow|toMatch)\b/.test(spec.generatedTest)) {
|
|
39
|
+
return {
|
|
40
|
+
baselinePassed: false,
|
|
41
|
+
mutantsTotal: 0,
|
|
42
|
+
mutantsKilled: 0,
|
|
43
|
+
mutationScore: 0,
|
|
44
|
+
survivedMutantIds: [],
|
|
45
|
+
passed: false,
|
|
46
|
+
reason: 'generated output contains no assertions — not a runnable test',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// 1. Baseline: the test must pass against the correct implementation.
|
|
50
|
+
const baselineDir = materialize(tmpRoot, spec.moduleName, spec.referenceImpl, spec.generatedTest);
|
|
51
|
+
const baseline = runNodeTest(baselineDir, { timeoutMs });
|
|
52
|
+
if (!baseline.ok) {
|
|
53
|
+
return {
|
|
54
|
+
baselinePassed: false,
|
|
55
|
+
mutantsTotal: 0,
|
|
56
|
+
mutantsKilled: 0,
|
|
57
|
+
mutationScore: 0,
|
|
58
|
+
survivedMutantIds: [],
|
|
59
|
+
passed: false,
|
|
60
|
+
reason: 'generated test does not pass against the reference implementation',
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// 2. Mutants: each one the test fails to fail-on is a missed bug.
|
|
64
|
+
let mutants = enumerateMutants(spec.referenceImpl, spec.moduleName);
|
|
65
|
+
if (spec.maxMutants !== undefined && mutants.length > spec.maxMutants) {
|
|
66
|
+
mutants = mutants.slice(0, spec.maxMutants);
|
|
67
|
+
}
|
|
68
|
+
if (mutants.length === 0) {
|
|
69
|
+
return {
|
|
70
|
+
baselinePassed: true,
|
|
71
|
+
mutantsTotal: 0,
|
|
72
|
+
mutantsKilled: 0,
|
|
73
|
+
mutationScore: 0,
|
|
74
|
+
survivedMutantIds: [],
|
|
75
|
+
passed: false,
|
|
76
|
+
reason: 'no operator mutants could be generated for the reference implementation (cannot prove the test catches anything)',
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
let killed = 0;
|
|
80
|
+
const survived = [];
|
|
81
|
+
for (const mutant of mutants) {
|
|
82
|
+
const dir = materialize(tmpRoot, spec.moduleName, applyMutant(spec.referenceImpl, mutant), spec.generatedTest);
|
|
83
|
+
const run = runNodeTest(dir, { timeoutMs });
|
|
84
|
+
if (!run.ok)
|
|
85
|
+
killed++;
|
|
86
|
+
else
|
|
87
|
+
survived.push(mutant.id);
|
|
88
|
+
}
|
|
89
|
+
const total = mutants.length;
|
|
90
|
+
const score = Math.round((killed / total) * 10000) / 10000;
|
|
91
|
+
const passed = score >= threshold;
|
|
92
|
+
return {
|
|
93
|
+
baselinePassed: true,
|
|
94
|
+
mutantsTotal: total,
|
|
95
|
+
mutantsKilled: killed,
|
|
96
|
+
mutationScore: score,
|
|
97
|
+
survivedMutantIds: survived,
|
|
98
|
+
passed,
|
|
99
|
+
reason: passed
|
|
100
|
+
? `killed ${killed}/${total} mutants (score ${(score * 100).toFixed(0)}%)`
|
|
101
|
+
: `mutation score ${(score * 100).toFixed(0)}% < threshold ${(threshold * 100).toFixed(0)}% — ${survived.length} mutant(s) survived`,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
cleanupTmpRoot(tmpRoot);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=oracle-eval.js.map
|