agentic-qe 3.12.3 → 3.13.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/.agents/skills/aqe-plan-quality/SKILL.md +25 -0
- package/.agents/skills/aqe-plan-quality/agents/openai.yaml +4 -0
- package/.agents/skills/aqe-plan-quality/references/qe-routing.md +22 -0
- package/.agents/skills/aqe-review-quality/SKILL.md +24 -0
- package/.agents/skills/aqe-review-quality/agents/openai.yaml +4 -0
- package/.agents/skills/aqe-review-quality/references/quality-gates.md +20 -0
- package/.agents/skills/aqe-test-change/SKILL.md +26 -0
- package/.agents/skills/aqe-test-change/agents/openai.yaml +4 -0
- package/.agents/skills/aqe-test-change/references/test-specialties.md +23 -0
- package/.claude/helpers/.helpers-version +1 -1
- package/.claude/helpers/auto-memory-hook.mjs +430 -430
- package/.claude/helpers/helpers.manifest.json +6 -5
- package/.claude/helpers/hook-handler.cjs +565 -311
- package/.claude/helpers/intelligence.cjs +1058 -1058
- package/.claude/helpers/ruflo-hook.cjs +5 -1
- package/.claude/helpers/statusline.cjs +995 -682
- package/.claude/skills/qe-court/SKILL.md +186 -0
- package/.claude/skills/qe-court/config.json +27 -0
- package/.claude/skills/qe-court/evals/fixtures/seeded-mutant-delivery/README.md +38 -0
- package/.claude/skills/qe-court/evals/fixtures/seeded-mutant-delivery/budget.test.ts +21 -0
- package/.claude/skills/qe-court/evals/fixtures/seeded-mutant-delivery/budget.ts +25 -0
- package/.claude/skills/qe-court/evals/qe-court.yaml +70 -0
- package/.claude/skills/qe-court/schemas/output.json +92 -0
- package/.claude/skills/qe-court/scripts/validate-config.json +30 -0
- package/.claude/skills/skills-manifest.json +9 -8
- package/.codex/hooks/aqe-codex-hook.cjs +69 -0
- package/.codex/hooks/ruflo-codex-hook.cjs +94 -0
- package/.codex/hooks.json +169 -0
- package/CHANGELOG.md +159 -0
- package/README.md +3 -3
- package/assets/skills/qe-court/SKILL.md +186 -0
- package/assets/skills/qe-court/config.json +27 -0
- package/assets/skills/qe-court/evals/fixtures/seeded-mutant-delivery/README.md +38 -0
- package/assets/skills/qe-court/evals/fixtures/seeded-mutant-delivery/budget.test.ts +21 -0
- package/assets/skills/qe-court/evals/fixtures/seeded-mutant-delivery/budget.ts +25 -0
- package/assets/skills/qe-court/evals/qe-court.yaml +70 -0
- package/assets/skills/qe-court/schemas/output.json +92 -0
- package/assets/skills/qe-court/scripts/validate-config.json +30 -0
- package/assets/skills/skills-manifest.json +9 -8
- package/dist/cli/bundle.js +5 -5
- package/dist/cli/chunks/adapter-VRZNL53W.js +2 -0
- package/dist/cli/chunks/{agent-booster-wasm-XFAQATTH.js → agent-booster-wasm-4VM3DE42.js} +2 -2
- package/dist/cli/chunks/{agent-handler-2ZV4CA3U.js → agent-handler-ZDLMZQQX.js} +2 -2
- package/dist/cli/chunks/{agent-memory-branch-6WGP7F5T.js → agent-memory-branch-P72MDHHV.js} +2 -2
- package/dist/cli/chunks/aqe-learning-engine-XCNMNERX.js +2 -0
- package/dist/cli/chunks/{arena-FWX7XZAE.js → arena-55FZGKEV.js} +4 -4
- package/dist/cli/chunks/{arena-KJUNQK4N.js → arena-GCRBQ26R.js} +2 -2
- package/dist/cli/chunks/{audit-YFUDEOKN.js → audit-VYAYVLIV.js} +3 -3
- package/dist/cli/chunks/base-VZZNR4UR.js +2 -0
- package/dist/cli/chunks/{hnswlib-node-SKTT5KIH.js → better-sqlite3-JDDFYVCX.js} +2 -2
- package/dist/cli/chunks/{brain-handler-ZCK4WTPK.js → brain-handler-IUKMRGWO.js} +3 -3
- package/dist/cli/chunks/{branch-enumerator-HTVINRYG.js → branch-enumerator-TUI3RWLX.js} +2 -2
- package/dist/cli/chunks/{browser-WUL2B77M.js → browser-NBQTZYX2.js} +2 -2
- package/dist/cli/chunks/browser-workflow-5DZNIFUY.js +2 -0
- package/dist/cli/chunks/{chunk-IWQHQLT6.js → chunk-23MT7OBY.js} +2 -2
- package/dist/cli/chunks/{chunk-KE3RK35K.js → chunk-2CQAWYYE.js} +1 -1
- package/dist/cli/chunks/{chunk-ADQFQBFJ.js → chunk-2D2XFUKI.js} +2 -2
- package/dist/cli/chunks/{chunk-2YDZXFO2.js → chunk-2G2QWV7B.js} +2 -2
- package/dist/cli/chunks/{chunk-HGJQSTQD.js → chunk-2ISLQU3G.js} +1 -1
- package/dist/cli/chunks/{chunk-6E47R27C.js → chunk-2OM3TDC4.js} +1 -1
- package/dist/cli/chunks/{chunk-WQASUQ5P.js → chunk-2XZ4BHWS.js} +1 -1
- package/dist/cli/chunks/{chunk-E2U3LTGM.js → chunk-3F4XH4ZA.js} +1 -1
- package/dist/cli/chunks/{chunk-YUDGQZJN.js → chunk-3K4YC3GC.js} +2 -2
- package/dist/cli/chunks/chunk-3KGCBAUH.js +2 -0
- package/dist/cli/chunks/{chunk-PXCJDB7J.js → chunk-3Y6CHW67.js} +1 -1
- package/dist/cli/chunks/{chunk-MOX25RZQ.js → chunk-4QMWWYNU.js} +2 -2
- package/dist/cli/chunks/{chunk-XZGOXLZH.js → chunk-4WGSMODQ.js} +1 -1
- package/dist/cli/chunks/{chunk-2CPJCXV6.js → chunk-55WDVSCM.js} +2 -2
- package/dist/cli/chunks/{chunk-EHO52NKU.js → chunk-5BB5DUL4.js} +2 -2
- package/dist/cli/chunks/{chunk-BEPP57C2.js → chunk-6C3MZLYW.js} +2 -2
- package/dist/cli/chunks/{chunk-DTZFZ5M7.js → chunk-6QKQFHS7.js} +2 -2
- package/dist/cli/chunks/{chunk-KXKACV3E.js → chunk-6XZXMEK4.js} +3 -3
- package/dist/cli/chunks/{chunk-L6GZGEFQ.js → chunk-7D7XFZZI.js} +2 -2
- package/dist/cli/chunks/{chunk-NLDLUHOF.js → chunk-7WEHZCSK.js} +2 -2
- package/dist/cli/chunks/{chunk-TXLPOXAN.js → chunk-A2MG3YXO.js} +1 -1
- package/dist/cli/chunks/{chunk-HJ2LG5IH.js → chunk-AHTOWWSE.js} +1 -1
- package/dist/cli/chunks/{chunk-GV2BS5NC.js → chunk-AOMXMFDH.js} +2 -2
- package/dist/cli/chunks/{chunk-EH7TSJPS.js → chunk-ARTLSAXO.js} +2 -2
- package/dist/cli/chunks/{chunk-CXMOIE7D.js → chunk-AY7S7AWN.js} +2 -2
- package/dist/cli/chunks/{chunk-2LNDU7AW.js → chunk-AYYDO52G.js} +2 -2
- package/dist/cli/chunks/chunk-BBLWZT5I.js +2 -0
- package/dist/cli/chunks/{chunk-KRS4KGX5.js → chunk-BF5BKSDU.js} +2 -2
- package/dist/cli/chunks/{chunk-BQ2K4BPD.js → chunk-BOCEOLLJ.js} +2 -2
- package/dist/cli/chunks/{chunk-KKOFH26C.js → chunk-CE6LYEHT.js} +1 -1
- package/dist/cli/chunks/{chunk-GS6G7AVS.js → chunk-CWP4RMOM.js} +2 -2
- package/dist/cli/chunks/{chunk-DCYBV6HV.js → chunk-CWXDL7AH.js} +1 -1
- package/dist/cli/chunks/{chunk-KGHSKDC7.js → chunk-DTRFZD7N.js} +2 -2
- package/dist/cli/chunks/{chunk-CYSBM52D.js → chunk-DVPGQG4W.js} +2 -2
- package/dist/cli/chunks/{chunk-MSDIIRLM.js → chunk-E4D47QTF.js} +2 -2
- package/dist/cli/chunks/{chunk-MB7TZQW3.js → chunk-EAKHU5YX.js} +3 -3
- package/dist/cli/chunks/{chunk-TP3UAWMB.js → chunk-EGMGOWCE.js} +2 -2
- package/dist/cli/chunks/{chunk-4EHW4TNA.js → chunk-ELMUHNXN.js} +2 -2
- package/dist/cli/chunks/chunk-EVDYFGVH.js +2 -0
- package/dist/cli/chunks/{chunk-D4GMAUTP.js → chunk-FDUSWM6O.js} +98 -88
- package/dist/cli/chunks/{chunk-YEC55GO5.js → chunk-FM272B4O.js} +2 -2
- package/dist/cli/chunks/{chunk-DMD6WVJ2.js → chunk-FQUUMC57.js} +2 -2
- package/dist/cli/chunks/{chunk-Y625LP6K.js → chunk-FQXQJMSF.js} +2 -2
- package/dist/cli/chunks/{chunk-Z3SXMYVI.js → chunk-FRAGSKXQ.js} +3 -3
- package/dist/cli/chunks/{chunk-MOXKKY5Q.js → chunk-GASOBSNB.js} +4 -4
- package/dist/cli/chunks/{chunk-PTPN6HQ7.js → chunk-GJEEPKAT.js} +2 -2
- package/dist/cli/chunks/{chunk-WFPGIP4N.js → chunk-GOV2MHLV.js} +2 -2
- package/dist/cli/chunks/{chunk-NKTLKMUB.js → chunk-GTPZVLL6.js} +1 -1
- package/dist/cli/chunks/chunk-H7YZ2YF2.js +3 -0
- package/dist/cli/chunks/{chunk-WKE6WL5C.js → chunk-HFI5PHG5.js} +3 -3
- package/dist/cli/chunks/chunk-HUMQU4ES.js +153 -0
- package/dist/cli/chunks/{chunk-5FAWIIWF.js → chunk-HYIRFJDB.js} +2 -2
- package/dist/cli/chunks/{chunk-DZ775UGW.js → chunk-IBSBOHUX.js} +2 -2
- package/dist/cli/chunks/{chunk-NAMJGRGC.js → chunk-IJA4WS7B.js} +2 -2
- package/dist/cli/chunks/{chunk-XUUVAAHV.js → chunk-IJP42OGW.js} +2 -2
- package/dist/cli/chunks/{chunk-UZ7FXVH5.js → chunk-IMQKEFW6.js} +1 -1
- package/dist/cli/chunks/{chunk-MZ7SIO6R.js → chunk-INYS35DV.js} +2 -2
- package/dist/cli/chunks/{chunk-MS6VOSPY.js → chunk-IV2VCR75.js} +5 -5
- package/dist/cli/chunks/{chunk-UAPUA6OY.js → chunk-IZO6TPGX.js} +2 -2
- package/dist/cli/chunks/{chunk-XBOCRCC6.js → chunk-J45DX3IK.js} +1 -1
- package/dist/cli/chunks/{chunk-RE42RJYR.js → chunk-J4T6D2OQ.js} +2 -2
- package/dist/cli/chunks/{chunk-Y5L37K7X.js → chunk-JAPOMPFD.js} +2 -2
- package/dist/cli/chunks/{chunk-M7W6VJ65.js → chunk-JELNVHBF.js} +1 -1
- package/dist/cli/chunks/{chunk-YDYKFSD2.js → chunk-JOTNKZ7A.js} +87 -87
- package/dist/cli/chunks/{chunk-VUCVSKJC.js → chunk-KNWDXI3I.js} +2 -2
- package/dist/cli/chunks/{chunk-SPI4LUJ6.js → chunk-KW5NBORV.js} +2 -2
- package/dist/cli/chunks/{chunk-2OX74DOO.js → chunk-L7IOTWWY.js} +1 -1
- package/dist/cli/chunks/{chunk-VFYMWDSJ.js → chunk-LJQ27PUE.js} +1 -1
- package/dist/cli/chunks/{chunk-NT66CT73.js → chunk-LSKQUUUN.js} +2 -2
- package/dist/cli/chunks/{chunk-ROFCS47F.js → chunk-LSZZQ7H6.js} +1 -1
- package/dist/cli/chunks/{chunk-Y6XNISHP.js → chunk-LTKNCYMO.js} +2 -2
- package/dist/cli/chunks/{chunk-7WF3TW3G.js → chunk-LTWT4GZD.js} +4 -4
- package/dist/cli/chunks/chunk-LVHMXGDI.js +29 -0
- package/dist/cli/chunks/{chunk-3YC4YUGB.js → chunk-M3T6FB54.js} +2 -2
- package/dist/cli/chunks/{chunk-M32DTUZM.js → chunk-MAYZTGJ2.js} +3 -3
- package/dist/cli/chunks/{chunk-RLBNAB6Y.js → chunk-MCIO7BDK.js} +1 -1
- package/dist/cli/chunks/{chunk-SFS3UHNF.js → chunk-MPD7RR4P.js} +1 -1
- package/dist/cli/chunks/{chunk-DDYP6FBC.js → chunk-MUFYDKVC.js} +2 -2
- package/dist/cli/chunks/{chunk-ZFLE4D4X.js → chunk-MX5ZDKRR.js} +2 -2
- package/dist/cli/chunks/{chunk-WBZNLFTV.js → chunk-MXKHIZVM.js} +5 -5
- package/dist/cli/chunks/chunk-MY47CR27.js +2 -0
- package/dist/cli/chunks/chunk-N7WAZ2Y6.js +2 -0
- package/dist/cli/chunks/{chunk-2HCMRGMO.js → chunk-NHV4PTG6.js} +2 -2
- package/dist/cli/chunks/{chunk-HJ4U64BL.js → chunk-NP4CP3LR.js} +2 -2
- package/dist/cli/chunks/{chunk-UIHZ34SJ.js → chunk-OCKTPTQ7.js} +2 -2
- package/dist/cli/chunks/{chunk-SGMJ277D.js → chunk-OE4B6LDZ.js} +1 -1
- package/dist/cli/chunks/{chunk-SV7J5FDW.js → chunk-OPQY2333.js} +2 -2
- package/dist/cli/chunks/{chunk-FTM562PF.js → chunk-ORDH4VPL.js} +1 -1
- package/dist/cli/chunks/{chunk-YOG5KQZF.js → chunk-P4Y3G6OB.js} +2 -2
- package/dist/cli/chunks/{chunk-LHAUFY4Y.js → chunk-PIOO2M4W.js} +2 -2
- package/dist/cli/chunks/{chunk-UGW23T6S.js → chunk-PKMCZFET.js} +2 -2
- package/dist/cli/chunks/{chunk-OPG2HV2W.js → chunk-QES4QHQW.js} +1 -1
- package/dist/cli/chunks/{chunk-BDGKB2PT.js → chunk-QG6BXSNJ.js} +2 -2
- package/dist/cli/chunks/{chunk-BSNNTOHY.js → chunk-QLOOW23R.js} +3 -3
- package/dist/cli/chunks/{chunk-AIWRYWK2.js → chunk-RSCGBHLM.js} +2 -2
- package/dist/cli/chunks/{chunk-LCM7TY76.js → chunk-RZ6CO3RZ.js} +2 -2
- package/dist/cli/chunks/chunk-S6F3IJMK.js +2 -0
- package/dist/cli/chunks/{chunk-WUE53ZPH.js → chunk-S6VNPKHO.js} +1 -1
- package/dist/cli/chunks/{chunk-L2X3BWMN.js → chunk-SHWXADCI.js} +2 -2
- package/dist/cli/chunks/{chunk-GMFFMJD6.js → chunk-SPJQJWGK.js} +2 -2
- package/dist/cli/chunks/{chunk-KVHCWH4H.js → chunk-SS6K4FBH.js} +2 -2
- package/dist/cli/chunks/{chunk-ZGKQCUPB.js → chunk-SXADKQJN.js} +2 -2
- package/dist/cli/chunks/{chunk-LGYEOYQJ.js → chunk-TBQTGQ75.js} +2 -2
- package/dist/cli/chunks/{chunk-J2RJOJ5Q.js → chunk-TDGE52HJ.js} +1 -1
- package/dist/cli/chunks/chunk-THFLRJT6.js +54 -0
- package/dist/cli/chunks/{chunk-GGTCD4MA.js → chunk-TQ2MA3SR.js} +1 -1
- package/dist/cli/chunks/{chunk-NOSQI2OW.js → chunk-UCQ66N6M.js} +3 -3
- package/dist/cli/chunks/{chunk-CL6SNCFF.js → chunk-UHGMS2PJ.js} +1 -1
- package/dist/cli/chunks/{chunk-XDHGCBTS.js → chunk-UHKXKWMD.js} +2 -2
- package/dist/cli/chunks/{chunk-PEHEANAM.js → chunk-UJ6TMZC6.js} +2 -2
- package/dist/cli/chunks/{chunk-PSDH7CIL.js → chunk-UKBDH27A.js} +1 -1
- package/dist/cli/chunks/{chunk-ZTKCGEB6.js → chunk-UMCEEXQN.js} +1 -1
- package/dist/cli/chunks/{chunk-KA4EAMMQ.js → chunk-USUFTHHT.js} +3 -3
- package/dist/cli/chunks/{chunk-QILF6BZH.js → chunk-V32MDID3.js} +2 -2
- package/dist/cli/chunks/{chunk-6SUSRXXF.js → chunk-VAJT6QWX.js} +1 -1
- package/dist/cli/chunks/{chunk-7Q74K3HZ.js → chunk-VLUJWI56.js} +1 -1
- package/dist/cli/chunks/{chunk-DW7OI5IF.js → chunk-WINA3XUT.js} +2 -2
- package/dist/cli/chunks/{chunk-S47YGWXK.js → chunk-WWCH5SSF.js} +2 -2
- package/dist/cli/chunks/{chunk-FJACKKRL.js → chunk-WWP2VXYJ.js} +2 -2
- package/dist/cli/chunks/{chunk-N4ML23ZG.js → chunk-WZROSTQZ.js} +1 -1
- package/dist/cli/chunks/{chunk-FXOOOJQD.js → chunk-XFUF654L.js} +1 -1
- package/dist/cli/chunks/{chunk-PDX7IYTJ.js → chunk-XN2CD5S6.js} +2 -2
- package/dist/cli/chunks/{chunk-DHUZHT5D.js → chunk-XOQQGZFY.js} +1 -1
- package/dist/cli/chunks/{chunk-4HP7N6SP.js → chunk-XSCOEY4C.js} +2 -2
- package/dist/cli/chunks/{chunk-KNWBRMLL.js → chunk-Y734CWHJ.js} +2 -2
- package/dist/cli/chunks/{chunk-NJDLJ3KD.js → chunk-YBPCBFEE.js} +2 -2
- package/dist/cli/chunks/{chunk-67BCEHU5.js → chunk-YLAEIS6F.js} +1 -1
- package/dist/cli/chunks/{chunk-E53UR2EW.js → chunk-YMMVCOPF.js} +3 -3
- package/dist/cli/chunks/{chunk-VSD6JE2H.js → chunk-YQCAXYBF.js} +2 -2
- package/dist/cli/chunks/{chunk-32L7DKNQ.js → chunk-YRVUYM62.js} +2 -2
- package/dist/cli/chunks/{chunk-LNIHLNW4.js → chunk-YVKMHXQK.js} +3 -3
- package/dist/cli/chunks/{chunk-CHFTHSMM.js → chunk-ZCLFAOVT.js} +2 -2
- package/dist/cli/chunks/{chunk-AZ24ONMX.js → chunk-ZH6ZBDVV.js} +1 -1
- package/dist/cli/chunks/{chunk-R6WMGSEK.js → chunk-ZHEKGB4A.js} +2 -2
- package/dist/cli/chunks/{chunk-EOUJ6X5H.js → chunk-ZIBW7CB4.js} +1 -1
- package/dist/cli/chunks/{chunk-OBL6W4Z5.js → chunk-ZLCATRXI.js} +2 -2
- package/dist/cli/chunks/{chunk-UGXHMQ6P.js → chunk-ZXX2VFMA.js} +2 -2
- package/dist/cli/chunks/{chunk-72QQDR3Y.js → chunk-ZYPESQ4M.js} +2 -2
- package/dist/cli/chunks/{ci-MMLUV6L6.js → ci-HHL5WQXQ.js} +2 -2
- package/dist/cli/chunks/{ci-output-25GS6RXR.js → ci-output-HVOJC2KN.js} +2 -2
- package/dist/cli/chunks/{circuit-breaker-4OWAN6R6.js → circuit-breaker-HRXMIY2G.js} +2 -2
- package/dist/cli/chunks/{claude-flow-setup-LR3SRBX6.js → claude-flow-setup-3I7WVMZN.js} +2 -2
- package/dist/cli/chunks/client-EY2IYQDL.js +2 -0
- package/dist/cli/chunks/{cline-installer-YSZWRZUI.js → cline-installer-NBREL4QT.js} +2 -2
- package/dist/cli/chunks/{code-UUWUIXI7.js → code-TX4E2RWU.js} +2 -2
- package/dist/cli/chunks/{code-index-extractor-2LSPQORU.js → code-index-extractor-YELOFLSL.js} +2 -2
- package/dist/cli/chunks/codex-installer-HEX3KFRB.js +10 -0
- package/dist/cli/chunks/{completions-YKXBKZSO.js → completions-72GGFRGG.js} +2 -2
- package/dist/cli/chunks/{complexity-analyzer-HNT2QRWB.js → complexity-analyzer-WRAKDYUK.js} +2 -2
- package/dist/cli/chunks/{continuedev-installer-AW5VCB66.js → continuedev-installer-UGYKSKTI.js} +2 -2
- package/dist/cli/chunks/{copilot-installer-B6SVZXQT.js → copilot-installer-RPCRUKIJ.js} +2 -2
- package/dist/cli/chunks/core-handlers-G4GLA4DT.js +2 -0
- package/dist/cli/chunks/{cost-tracker-POZMBN2V.js → cost-tracker-CNHJ7G4M.js} +2 -2
- package/dist/cli/chunks/{coverage-V5BGPN5Q.js → coverage-RHIQ4XEX.js} +3 -3
- package/dist/cli/chunks/cross-domain-router-P3K4IH5H.js +2 -0
- package/dist/cli/chunks/{cursor-installer-EYBI4QVK.js → cursor-installer-KSRVA4V2.js} +2 -2
- package/dist/cli/chunks/{daemon-CF6ENQB2.js → daemon-IT4AAFBW.js} +3 -3
- package/dist/cli/chunks/{daemon-HKARXY2W.js → daemon-QBXSJABV.js} +4 -4
- package/dist/cli/chunks/{dag-attention-scheduler-XIL5IAP7.js → dag-attention-scheduler-F7WCQTLY.js} +2 -2
- package/dist/cli/chunks/{detect-RRX2U2KK.js → detect-2IYU332U.js} +2 -2
- package/dist/cli/chunks/{dist-node-DOANNRCS.js → dist-node-CIYNYCYN.js} +2 -2
- package/dist/cli/chunks/{domain-handler-QMTJV5OR.js → domain-handler-QRYQO2QK.js} +2 -2
- package/dist/cli/chunks/{domain-transfer-FSNH75XW.js → domain-transfer-2OQDOD3G.js} +2 -2
- package/dist/cli/chunks/dream-IT4ZQGEO.js +2 -0
- package/dist/cli/chunks/{embed-and-insert-pattern-NI7PGONV.js → embed-and-insert-pattern-P2IFC7JL.js} +2 -2
- package/dist/cli/chunks/{eval-6ZAF2RY3.js → eval-SBPK37IB.js} +2 -2
- package/dist/cli/chunks/{experience-capture-middleware-JMXR7N5G.js → experience-capture-middleware-3GMFND3F.js} +3 -3
- package/dist/cli/chunks/{fast-paths-YB7XZZ76.js → fast-paths-4OYYII2F.js} +2 -2
- package/dist/cli/chunks/{feature-flags-2RC4GFC4.js → feature-flags-BM6QTMMC.js} +2 -2
- package/dist/cli/chunks/{feature-flags-KJSP7KR6.js → feature-flags-NFCAYUWO.js} +2 -2
- package/dist/cli/chunks/{file-discovery-SUPBXFYI.js → file-discovery-2M3ZUAGC.js} +2 -2
- package/dist/cli/chunks/{fleet-KSXFOLFW.js → fleet-QMGGVIDV.js} +3 -3
- package/dist/cli/chunks/{gnn-wrapper-DFZ5KPPK.js → gnn-wrapper-WGMAGZMO.js} +2 -2
- package/dist/cli/chunks/{heartbeat-handler-G3EADK2H.js → heartbeat-handler-5RSMEZGG.js} +4 -4
- package/dist/cli/chunks/heartbeat-scheduler-UUWSPHF2.js +2 -0
- package/dist/cli/chunks/hnsw-adapter-YUJVSFPD.js +2 -0
- package/dist/cli/chunks/hnsw-index-FQZ47RSJ.js +2 -0
- package/dist/cli/chunks/{hnsw-legacy-bridge-MA676GER.js → hnsw-legacy-bridge-TYPQ2T6P.js} +2 -2
- package/dist/cli/chunks/{better-sqlite3-FE55OGYB.js → hnswlib-node-GMRPPMDM.js} +2 -2
- package/dist/cli/chunks/{hooks-HTCPMZNZ.js → hooks-NUC5P3OJ.js} +10 -10
- package/dist/cli/chunks/hybrid-router-T5MF73NF.js +2 -0
- package/dist/cli/chunks/{hypergraph-engine-QPB3IH4A.js → hypergraph-engine-OIB7WK54.js} +2 -2
- package/dist/cli/chunks/{hypergraph-handler-GBFSVD7N.js → hypergraph-handler-XX2N75QC.js} +3 -3
- package/dist/cli/chunks/impact-analyzer-AEGELYMD.js +2 -0
- package/dist/cli/chunks/{init-handler-XYBTBCPD.js → init-handler-AKSTJMZY.js} +6 -6
- package/dist/cli/chunks/init-wizard-WKX3OGWM.js +2 -0
- package/dist/cli/chunks/kernel-5CVWFIGR.js +2 -0
- package/dist/cli/chunks/{kilocode-installer-LY6JOBFY.js → kilocode-installer-375V5ZZB.js} +2 -2
- package/dist/cli/chunks/{kiro-installer-JF6NXTJL.js → kiro-installer-GKY5GB5Q.js} +2 -2
- package/dist/cli/chunks/knowledge-graph-EGPMNDMT.js +2 -0
- package/dist/cli/chunks/{learning-BIISN67N.js → learning-2CQE3QP6.js} +3 -3
- package/dist/cli/chunks/{llm-router-YZUNVZQE.js → llm-router-FTQNRF45.js} +5 -5
- package/dist/cli/chunks/llm-router-service-H4LXOARB.js +2 -0
- package/dist/cli/chunks/{load-MTWNBNLL.js → load-3DBAO5ZG.js} +2 -2
- package/dist/cli/chunks/load-test-OOOGITSN.js +2 -0
- package/dist/cli/chunks/{mcp-37PYMNHQ.js → mcp-AWR6TDXM.js} +2 -2
- package/dist/cli/chunks/{memory-IXUUDCI3.js → memory-GI4LCNXY.js} +5 -5
- package/dist/cli/chunks/memory-backend-O2YOT4LW.js +2 -0
- package/dist/cli/chunks/{memory-handlers-RM2VOFJX.js → memory-handlers-MALKG7GP.js} +2 -2
- package/dist/cli/chunks/{multi-model-executor-RKKS5XYG.js → multi-model-executor-SWFT5U72.js} +2 -2
- package/dist/cli/chunks/{opencode-installer-3VXI5MTR.js → opencode-installer-EYXGYJX5.js} +2 -2
- package/dist/cli/chunks/{orchestrator-UO3ZOGFZ.js → orchestrator-MP3EAZVC.js} +5 -5
- package/dist/cli/chunks/pattern-null-store-WBOHE2XL.js +2 -0
- package/dist/cli/chunks/{pattern-usage-recorder-YJKRL2GI.js → pattern-usage-recorder-25P3R3W7.js} +2 -2
- package/dist/cli/chunks/{pipeline-GJQJKXWX.js → pipeline-LSAFL25D.js} +2 -2
- package/dist/cli/chunks/{platform-RHVCZK6C.js → platform-IJ6DJ2PG.js} +2 -2
- package/dist/cli/chunks/{plugin-ZKAIW7O6.js → plugin-OXOZRZW2.js} +2 -2
- package/dist/cli/chunks/{prime-radiant-advanced-wasm-4X3DSKQV.js → prime-radiant-advanced-wasm-HJNJQQ3R.js} +2 -2
- package/dist/cli/chunks/protocol-executor-JCNTPW5J.js +2 -0
- package/dist/cli/chunks/{protocol-handler-KKYQZMB2.js → protocol-handler-TCMUH2HL.js} +2 -2
- package/dist/cli/chunks/{prove-OD6RPKWX.js → prove-ADXQ2GOX.js} +2 -2
- package/dist/cli/chunks/provider-manager-LPGQ5GOO.js +2 -0
- package/dist/cli/chunks/qe-reasoning-bank-FWVYVSPP.js +2 -0
- package/dist/cli/chunks/{quality-ZRWBXCKO.js → quality-EWP36ORX.js} +2 -2
- package/dist/cli/chunks/{quality-gate-Y6BWQV7J.js → quality-gate-3BIG7PVU.js} +3 -3
- package/dist/cli/chunks/queen-coordinator-UXNALRVD.js +2 -0
- package/dist/cli/chunks/{real-embeddings-YYEUO4P2.js → real-embeddings-D4NBT7W5.js} +2 -2
- package/dist/cli/chunks/{roocode-installer-JBCPS3FK.js → roocode-installer-DOPWH6YV.js} +2 -2
- package/dist/cli/chunks/router-C6LUIQYY.js +2 -0
- package/dist/cli/chunks/routing-feedback-KMSGGDVD.js +2 -0
- package/dist/cli/chunks/{routing-handler-KTPJOSBJ.js → routing-handler-5ADEFOHS.js} +2 -2
- package/dist/cli/chunks/{ruvector-commands-SCZZVRE7.js → ruvector-commands-PLMEIHSN.js} +2 -2
- package/dist/cli/chunks/{rvf-dual-writer-IP7GELQJ.js → rvf-dual-writer-EQWKVNQB.js} +2 -2
- package/dist/cli/chunks/{rvf-migration-adapter-WLFTDARU.js → rvf-migration-adapter-2OWFUUCG.js} +2 -2
- package/dist/cli/chunks/{rvf-migration-coordinator-MGFDQ5WD.js → rvf-migration-coordinator-URAETAPU.js} +2 -2
- package/dist/cli/chunks/rvf-native-adapter-K54BELUE.js +2 -0
- package/dist/cli/chunks/{rvf-store-integrity-OTOAGT5W.js → rvf-store-integrity-4AWPW4TF.js} +2 -2
- package/dist/cli/chunks/safe-db-NGOZWF2D.js +2 -0
- package/dist/cli/chunks/schedule-B3Y5P64E.js +2 -0
- package/dist/cli/chunks/scheduler-Z6QVRMTB.js +2 -0
- package/dist/cli/chunks/{security-B2CLZKRB.js → security-HDLZVM62.js} +3 -3
- package/dist/cli/chunks/{shared-rvf-adapter-2PMFAQMN.js → shared-rvf-adapter-YQT7PF7X.js} +2 -2
- package/dist/cli/chunks/{shared-rvf-dual-writer-B6P732AV.js → shared-rvf-dual-writer-N5D3NSJ7.js} +2 -2
- package/dist/cli/chunks/sqlite-persistence-PLOUGATS.js +2 -0
- package/dist/cli/chunks/{status-handler-M6SN2W2D.js → status-handler-KLYRJ2MR.js} +2 -2
- package/dist/cli/chunks/{structural-health-YCCTGI3K.js → structural-health-6LKVRP6Y.js} +2 -2
- package/dist/cli/chunks/sync-7VMFPBVB.js +2 -0
- package/dist/cli/chunks/{sync-KSRF77ID.js → sync-YYOW6L6W.js} +2 -2
- package/dist/cli/chunks/{task-handler-MIKRB2SL.js → task-handler-RKQDGFN2.js} +2 -2
- package/dist/cli/chunks/{task-handlers-YXKRUBQ4.js → task-handlers-6YJ4QTEP.js} +3 -3
- package/dist/cli/chunks/{test-MLOLQCB7.js → test-ASPUIUJH.js} +4 -4
- package/dist/cli/chunks/{test-scheduling-3KXESUZS.js → test-scheduling-I7ABQBBU.js} +3 -3
- package/dist/cli/chunks/{token-bootstrap-6V2PMDBJ.js → token-bootstrap-2XZBTODN.js} +2 -2
- package/dist/cli/chunks/{token-usage-DP6THJ3I.js → token-usage-TMUE6PTF.js} +2 -2
- package/dist/cli/chunks/transformers-FDHHH4SL.js +2 -0
- package/dist/cli/chunks/{tree-sitter-wasm-parser-COK2XERS.js → tree-sitter-wasm-parser-G7PGZA5C.js} +2 -2
- package/dist/cli/chunks/{types-PYHUCVOZ.js → types-JGT57UFP.js} +2 -2
- package/dist/cli/chunks/unified-memory-P5YVLMFI.js +2 -0
- package/dist/cli/chunks/unified-memory-hnsw-7HI43A2O.js +2 -0
- package/dist/cli/chunks/unified-persistence-U26YP3N3.js +2 -0
- package/dist/cli/chunks/{upgrade-ONP2HNGL.js → upgrade-V6UQODJF.js} +2 -2
- package/dist/cli/chunks/{validate-NWSICDAY.js → validate-UBZAE5RW.js} +2 -2
- package/dist/cli/chunks/{validate-swarm-KXS5P3U7.js → validate-swarm-TSO2MI5X.js} +2 -2
- package/dist/cli/chunks/{vibium-TZSGZRCQ.js → vibium-7G3VYSQA.js} +2 -2
- package/dist/cli/chunks/visual-security-6FCDY5FF.js +2 -0
- package/dist/cli/chunks/{web-tree-sitter-V2FADNRA.js → web-tree-sitter-MIYJSF2L.js} +2 -2
- package/dist/cli/chunks/{windsurf-installer-GQM7KWDC.js → windsurf-installer-5TLZSQIJ.js} +2 -2
- package/dist/cli/chunks/witness-chain-I3K3WQID.js +2 -0
- package/dist/cli/chunks/{witness-chain-GTITDIA2.js → witness-chain-LTV7H2HM.js} +2 -2
- package/dist/cli/chunks/{witness-key-manager-AHRM2M52.js → witness-key-manager-PAJ2J4AL.js} +2 -2
- package/dist/cli/chunks/{workflow-XCGHEL3I.js → workflow-DL3ESR2H.js} +4 -4
- package/dist/cli/chunks/workflow-orchestrator-MAALP4WA.js +2 -0
- package/dist/cli/chunks/{wrappers-VGO2GO4J.js → wrappers-5HSU665E.js} +2 -2
- package/dist/cli/commands/llm-router.js +1 -0
- package/dist/cli/handlers/init-handler.js +1 -1
- package/dist/coordination/handlers/coverage-collection.d.ts +161 -0
- package/dist/coordination/handlers/coverage-collection.js +639 -0
- package/dist/coordination/handlers/coverage-handlers.js +199 -146
- package/dist/coordination/handlers/handler-types.d.ts +6 -1
- package/dist/coordination/handlers/handler-utils.js +10 -3
- package/dist/coordination/handlers/security-handlers.js +17 -2
- package/dist/coordination/handlers/test-execution-handlers.js +16 -1
- package/dist/coordination/result-saver.js +119 -97
- package/dist/coordination/task-executor.d.ts +26 -1
- package/dist/coordination/task-executor.js +52 -4
- package/dist/domains/code-intelligence/services/knowledge-graph.js +8 -0
- package/dist/domains/coverage-analysis/services/coverage-analyzer.js +4 -0
- package/dist/domains/coverage-analysis/services/gap-detector.js +4 -0
- package/dist/domains/defect-intelligence/services/defect-predictor.js +4 -0
- package/dist/domains/defect-intelligence/services/root-cause-analyzer.js +4 -0
- package/dist/domains/quality-assessment/services/deployment-advisor.js +4 -0
- package/dist/domains/quality-assessment/services/quality-analyzer.js +4 -0
- package/dist/domains/security-compliance/services/scanners/sast-scanner.js +4 -0
- package/dist/domains/test-generation/index.js +17 -2
- package/dist/domains/test-generation/services/test-generator.js +31 -9
- package/dist/init/codex-installer.d.ts +13 -0
- package/dist/init/codex-installer.js +122 -1
- package/dist/init/phases/09-assets.js +4 -0
- package/dist/init/phases/phase-interface.d.ts +1 -1
- package/dist/init/skills-installer.js +1 -0
- package/dist/integrations/embeddings/base/EmbeddingGenerator.js +13 -1
- package/dist/kernel/unified-memory.js +4 -0
- package/dist/learning/qe-flywheel/corpus-scorer.js +10 -7
- package/dist/learning/qe-flywheel/generation.d.ts +7 -0
- package/dist/learning/qe-flywheel/generation.js +5 -0
- package/dist/learning/qe-flywheel/witness-verify.d.ts +86 -0
- package/dist/learning/qe-flywheel/witness-verify.js +156 -0
- package/dist/learning/real-embeddings.js +15 -1
- package/dist/mcp/bundle.js +455 -434
- package/dist/mcp/handlers/domain-handler-configs.js +79 -14
- package/dist/mcp/types.d.ts +42 -4
- package/dist/optimization/session-cache.d.ts +13 -1
- package/dist/optimization/session-cache.js +27 -2
- package/dist/shared/db-recovery.d.ts +55 -0
- package/dist/shared/db-recovery.js +184 -0
- package/dist/shared/llm/billing-modes.js +5 -2
- package/dist/shared/llm/cost-tracker.js +1 -0
- package/dist/shared/llm/interfaces.d.ts +14 -1
- package/dist/shared/llm/llm-router-service.js +59 -4
- package/dist/shared/llm/provider-manager.d.ts +1 -1
- package/dist/shared/llm/provider-manager.js +7 -3
- package/dist/shared/llm/providers/claude-code.js +12 -3
- package/dist/shared/llm/providers/codex.d.ts +58 -0
- package/dist/shared/llm/providers/codex.js +305 -0
- package/dist/shared/llm/providers/index.d.ts +1 -0
- package/dist/shared/llm/providers/index.js +1 -0
- package/dist/shared/llm/router/agent-router-config.d.ts +46 -2
- package/dist/shared/llm/router/agent-router-config.js +124 -2
- package/dist/shared/llm/router/config-store.d.ts +17 -1
- package/dist/shared/llm/router/config-store.js +108 -0
- package/dist/shared/llm/router/hybrid-router.js +2 -2
- package/dist/shared/llm/router/index.d.ts +2 -2
- package/dist/shared/llm/router/index.js +2 -0
- package/dist/shared/llm/router/types.d.ts +44 -0
- package/dist/shared/llm/router/types.js +1 -0
- package/dist/shared/llm/spend-ledger.d.ts +24 -0
- package/dist/shared/llm/spend-ledger.js +86 -15
- package/dist/shared/llm/translation/message-formatter.js +1 -0
- package/dist/shared/safe-db.d.ts +10 -0
- package/dist/shared/safe-db.js +17 -0
- package/dist/skills/qe-court/referee.d.ts +62 -0
- package/dist/skills/qe-court/referee.js +78 -0
- package/dist/validation/gate-reexecute.d.ts +9 -0
- package/dist/validation/gate-reexecute.js +61 -0
- package/dist/validation/paired-bootstrap.d.ts +36 -0
- package/dist/validation/paired-bootstrap.js +58 -0
- package/package.json +9 -2
- package/dist/cli/chunks/adapter-D657MKZY.js +0 -2
- package/dist/cli/chunks/aqe-learning-engine-AFR6OZJK.js +0 -2
- package/dist/cli/chunks/base-K5QRGZWE.js +0 -2
- package/dist/cli/chunks/browser-workflow-ZMMKCGYW.js +0 -2
- package/dist/cli/chunks/chunk-6HQDPDN5.js +0 -2
- package/dist/cli/chunks/chunk-6SQ72FG7.js +0 -2
- package/dist/cli/chunks/chunk-7XUM4LBC.js +0 -2
- package/dist/cli/chunks/chunk-FHHCH7WL.js +0 -2
- package/dist/cli/chunks/chunk-G5OGKVLO.js +0 -2
- package/dist/cli/chunks/chunk-ILRKO6A5.js +0 -43
- package/dist/cli/chunks/chunk-NX522PRH.js +0 -153
- package/dist/cli/chunks/chunk-PPUDKQ4X.js +0 -29
- package/dist/cli/chunks/chunk-RSZOCQOL.js +0 -2
- package/dist/cli/chunks/chunk-ULQCEM7K.js +0 -2
- package/dist/cli/chunks/chunk-XQ5JT7KM.js +0 -3
- package/dist/cli/chunks/client-WI7RRUZO.js +0 -2
- package/dist/cli/chunks/codex-installer-E5BVXZVA.js +0 -8
- package/dist/cli/chunks/core-handlers-T6URR57V.js +0 -2
- package/dist/cli/chunks/cross-domain-router-WHTTKHWM.js +0 -2
- package/dist/cli/chunks/dream-QUL6SURC.js +0 -2
- package/dist/cli/chunks/heartbeat-scheduler-VZNKE33K.js +0 -2
- package/dist/cli/chunks/hnsw-adapter-LGWLDZLC.js +0 -2
- package/dist/cli/chunks/hnsw-index-66FOOI7U.js +0 -2
- package/dist/cli/chunks/hybrid-router-I5MEVQDF.js +0 -2
- package/dist/cli/chunks/impact-analyzer-K6ANYIY3.js +0 -2
- package/dist/cli/chunks/init-wizard-URHGXJ32.js +0 -2
- package/dist/cli/chunks/kernel-OKI5ZY5P.js +0 -2
- package/dist/cli/chunks/knowledge-graph-VQQSK7T5.js +0 -2
- package/dist/cli/chunks/llm-router-service-TISH33SY.js +0 -2
- package/dist/cli/chunks/load-test-KWKWC4Q7.js +0 -2
- package/dist/cli/chunks/memory-backend-JSQQMXVS.js +0 -2
- package/dist/cli/chunks/pattern-null-store-SXBIUKE5.js +0 -2
- package/dist/cli/chunks/protocol-executor-D3Q5P3WY.js +0 -2
- package/dist/cli/chunks/provider-manager-2EIX7E5Q.js +0 -2
- package/dist/cli/chunks/qe-reasoning-bank-ITOW2ZHC.js +0 -2
- package/dist/cli/chunks/queen-coordinator-TO5X2EXL.js +0 -2
- package/dist/cli/chunks/router-GZJQEJU3.js +0 -2
- package/dist/cli/chunks/routing-feedback-CRXSKFNS.js +0 -2
- package/dist/cli/chunks/rvf-native-adapter-WHADT5HX.js +0 -2
- package/dist/cli/chunks/safe-db-MIZ2OFWC.js +0 -2
- package/dist/cli/chunks/schedule-XFILYTYC.js +0 -2
- package/dist/cli/chunks/scheduler-EIPJ777A.js +0 -2
- package/dist/cli/chunks/sqlite-persistence-PFU3GSRD.js +0 -2
- package/dist/cli/chunks/sync-3SDMVAIU.js +0 -2
- package/dist/cli/chunks/transformers-QFOBOP2Y.js +0 -2
- package/dist/cli/chunks/unified-memory-OUVCMFGK.js +0 -2
- package/dist/cli/chunks/unified-memory-hnsw-YGQPOHXB.js +0 -2
- package/dist/cli/chunks/unified-persistence-GFRZVDOW.js +0 -2
- package/dist/cli/chunks/visual-security-LVOOYQ64.js +0 -2
- package/dist/cli/chunks/witness-chain-QNFPV4UL.js +0 -2
- package/dist/cli/chunks/workflow-orchestrator-MIVBCALG.js +0 -2
|
@@ -324,14 +324,97 @@ export function getAgentRoutingCategory(agentType) {
|
|
|
324
324
|
}
|
|
325
325
|
return 'general';
|
|
326
326
|
}
|
|
327
|
+
// ============================================================================
|
|
328
|
+
// On-disk per-agent overrides (issue #568)
|
|
329
|
+
// ============================================================================
|
|
330
|
+
/**
|
|
331
|
+
* Per-agent-type overrides sourced from `.agentic-qe/llm-config.json`'s
|
|
332
|
+
* `agentOverrides` key.
|
|
333
|
+
*
|
|
334
|
+
* Module-level state, deliberately: `getPreferredModelForAgent` is a synchronous
|
|
335
|
+
* pure-lookup function called from many places (rule construction, capability
|
|
336
|
+
* resolution, the router's own dispatch), and threading a config object through
|
|
337
|
+
* all of them would be a far larger change than this feature warrants. The
|
|
338
|
+
* router installs the loaded map once at construction via
|
|
339
|
+
* `setAgentProviderOverrides`.
|
|
340
|
+
*
|
|
341
|
+
* Empty by default, so behavior is unchanged for anyone who never writes the
|
|
342
|
+
* key — the category defaults below remain authoritative.
|
|
343
|
+
*/
|
|
344
|
+
let agentProviderOverrides = {};
|
|
345
|
+
/**
|
|
346
|
+
* Per-provider default model, from the router config's `providers` map.
|
|
347
|
+
*
|
|
348
|
+
* Needed because the category defaults in `DEFAULT_CATEGORY_MODELS` pair a
|
|
349
|
+
* provider with a provider-specific model id. If a user writes
|
|
350
|
+
* `{ "provider": "ollama" }` and we inherited the category *model* too, the
|
|
351
|
+
* agent would be routed to ollama asking for `claude-sonnet-4-6` — a model that
|
|
352
|
+
* provider cannot serve. Changing provider without naming a model must fall
|
|
353
|
+
* back to that provider's own default, not the previous provider's model.
|
|
354
|
+
*/
|
|
355
|
+
let providerDefaultModels = {};
|
|
356
|
+
/**
|
|
357
|
+
* Install the on-disk per-agent overrides (issue #568). Called by the router
|
|
358
|
+
* service after `loadRouterConfig()` has validated them.
|
|
359
|
+
*
|
|
360
|
+
* Replaces the whole map rather than merging, so reloading a config that
|
|
361
|
+
* removed an entry actually removes it.
|
|
362
|
+
*
|
|
363
|
+
* @param overrides validated `agentOverrides` map
|
|
364
|
+
* @param defaultModels per-provider default model ids, so a provider-only
|
|
365
|
+
* override resolves to a model that provider can actually serve
|
|
366
|
+
*/
|
|
367
|
+
export function setAgentProviderOverrides(overrides, defaultModels) {
|
|
368
|
+
agentProviderOverrides = { ...(overrides ?? {}) };
|
|
369
|
+
providerDefaultModels = { ...(defaultModels ?? {}) };
|
|
370
|
+
}
|
|
371
|
+
/** Current on-disk per-agent overrides. Primarily for diagnostics and tests. */
|
|
372
|
+
export function getAgentProviderOverrides() {
|
|
373
|
+
return agentProviderOverrides;
|
|
374
|
+
}
|
|
375
|
+
/** Clear installed overrides. For tests. */
|
|
376
|
+
export function resetAgentProviderOverrides() {
|
|
377
|
+
agentProviderOverrides = {};
|
|
378
|
+
providerDefaultModels = {};
|
|
379
|
+
}
|
|
327
380
|
/**
|
|
328
|
-
* Get the preferred model for an agent type
|
|
381
|
+
* Get the preferred model for an agent type.
|
|
382
|
+
*
|
|
383
|
+
* Resolution order (issue #568):
|
|
384
|
+
* 1. `agentOverrides[agentType]` from `.agentic-qe/llm-config.json` — the
|
|
385
|
+
* user's explicit, hand-written intent, so it wins.
|
|
386
|
+
* 2. the agent's category default (`AGENT_CATEGORY_MAP` ->
|
|
387
|
+
* `DEFAULT_CATEGORY_MODELS`).
|
|
388
|
+
*
|
|
389
|
+
* An override is a *partial*: fields it does not set keep their category
|
|
390
|
+
* default, so `{ "provider": "ollama" }` re-provisions the provider without
|
|
391
|
+
* forcing the user to also restate temperature, token budget, and priority.
|
|
392
|
+
*
|
|
329
393
|
* @param agentType - The agent type identifier
|
|
330
394
|
* @returns The model preference configuration
|
|
331
395
|
*/
|
|
332
396
|
export function getPreferredModelForAgent(agentType) {
|
|
333
397
|
const category = getAgentRoutingCategory(agentType);
|
|
334
|
-
|
|
398
|
+
const base = DEFAULT_CATEGORY_MODELS[category];
|
|
399
|
+
const override = agentProviderOverrides[agentType];
|
|
400
|
+
if (!override)
|
|
401
|
+
return base;
|
|
402
|
+
// Changing provider without naming a model must NOT inherit the previous
|
|
403
|
+
// provider's model id (see `providerDefaultModels`). Prefer that provider's
|
|
404
|
+
// own default; only keep the category model when the provider is unchanged.
|
|
405
|
+
const switchingProvider = override.provider !== undefined && override.provider !== base.provider;
|
|
406
|
+
const resolvedModel = override.model ??
|
|
407
|
+
(switchingProvider ? providerDefaultModels[override.provider] : undefined);
|
|
408
|
+
return {
|
|
409
|
+
...base,
|
|
410
|
+
...(override.provider !== undefined ? { provider: override.provider } : {}),
|
|
411
|
+
...(resolvedModel !== undefined ? { model: resolvedModel } : {}),
|
|
412
|
+
...(override.temperature !== undefined ? { temperature: override.temperature } : {}),
|
|
413
|
+
...(override.maxTokens !== undefined ? { maxTokens: override.maxTokens } : {}),
|
|
414
|
+
// An explicit on-disk entry outranks the built-in category rule by default,
|
|
415
|
+
// so it isn't quietly out-prioritized by DEFAULT_ROUTING_OVERRIDES.
|
|
416
|
+
priority: override.priority ?? base.priority + 100,
|
|
417
|
+
};
|
|
335
418
|
}
|
|
336
419
|
/**
|
|
337
420
|
* Get capability requirements for an agent type
|
|
@@ -410,6 +493,45 @@ export function createAgentRoutingRule(agentType) {
|
|
|
410
493
|
priority: preference.priority,
|
|
411
494
|
};
|
|
412
495
|
}
|
|
496
|
+
/**
|
|
497
|
+
* Build routing rules for exactly the agent types the user overrode on disk
|
|
498
|
+
* (issue #568).
|
|
499
|
+
*
|
|
500
|
+
* Why a separate builder rather than `createAgentRoutingRule`: that one also
|
|
501
|
+
* constrains on `requiresReasoning`, which is right for the generated
|
|
502
|
+
* whole-roster ruleset but wrong here — a user who wrote
|
|
503
|
+
* `"qe-mutation-tester": { "provider": "ollama" }` means *always*, not "only when
|
|
504
|
+
* the request happens to be flagged as needing reasoning". These rules match on
|
|
505
|
+
* agent type alone.
|
|
506
|
+
*
|
|
507
|
+
* Returns `[]` when nothing is overridden, so a project without the key gets the
|
|
508
|
+
* exact rule set it got before.
|
|
509
|
+
*
|
|
510
|
+
* @returns Routing rules, highest priority first
|
|
511
|
+
*/
|
|
512
|
+
export function createOverrideRoutingRules() {
|
|
513
|
+
return Object.keys(agentProviderOverrides)
|
|
514
|
+
.map((agentType) => {
|
|
515
|
+
const preference = getPreferredModelForAgent(agentType);
|
|
516
|
+
return {
|
|
517
|
+
id: `agent-override-${agentType}`,
|
|
518
|
+
name: `User override: ${agentType} -> ${preference.provider}/${preference.model}`,
|
|
519
|
+
description: `Per-agent routing override from .agentic-qe/llm-config.json ` +
|
|
520
|
+
`(agentOverrides["${agentType}"])`,
|
|
521
|
+
condition: { agentType: [agentType] },
|
|
522
|
+
action: {
|
|
523
|
+
provider: preference.provider,
|
|
524
|
+
model: preference.model,
|
|
525
|
+
temperature: preference.temperature,
|
|
526
|
+
maxTokens: preference.maxTokens,
|
|
527
|
+
priority: preference.priority,
|
|
528
|
+
},
|
|
529
|
+
enabled: true,
|
|
530
|
+
priority: preference.priority,
|
|
531
|
+
};
|
|
532
|
+
})
|
|
533
|
+
.sort((a, b) => b.priority - a.priority);
|
|
534
|
+
}
|
|
413
535
|
/**
|
|
414
536
|
* Create routing rules for all agents in a category
|
|
415
537
|
* @param category - The agent category
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* state — we don't disable it implicitly, because users may set keys
|
|
18
18
|
* later via `aqe llm config --set`.
|
|
19
19
|
*/
|
|
20
|
-
import type { RouterConfig, ExtendedProviderType } from './types.js';
|
|
20
|
+
import type { RouterConfig, ExtendedProviderType, AgentProviderOverride } from './types.js';
|
|
21
21
|
/** Filename under .agentic-qe/ */
|
|
22
22
|
export declare const ROUTER_CONFIG_FILENAME = "llm-config.json";
|
|
23
23
|
/**
|
|
@@ -52,6 +52,22 @@ export declare function saveRouterConfigFile(config: Partial<RouterConfig>, proj
|
|
|
52
52
|
* top-level scalars use last-wins.
|
|
53
53
|
*/
|
|
54
54
|
export declare function mergeRouterConfig(base: RouterConfig, override: Partial<RouterConfig>): RouterConfig;
|
|
55
|
+
/**
|
|
56
|
+
* Validate and normalize an on-disk `agentOverrides` map (issue #568).
|
|
57
|
+
*
|
|
58
|
+
* User-hand-edited config is untrusted input: drop entries that name a provider
|
|
59
|
+
* we cannot construct, and strip any `apiKey`-shaped field that leaked in — the
|
|
60
|
+
* same "never persist API keys" discipline `saveRouterConfigFile` already
|
|
61
|
+
* enforces for `providers.*`.
|
|
62
|
+
*
|
|
63
|
+
* Returns the cleaned map plus human-readable warnings for the caller to log.
|
|
64
|
+
* Invalid entries are dropped, never thrown on: a typo in one agent key must not
|
|
65
|
+
* take down router initialization for the whole project.
|
|
66
|
+
*/
|
|
67
|
+
export declare function sanitizeAgentOverrides(raw: unknown): {
|
|
68
|
+
overrides: Record<string, AgentProviderOverride>;
|
|
69
|
+
warnings: string[];
|
|
70
|
+
};
|
|
55
71
|
/**
|
|
56
72
|
* Apply env-detection on top of a merged config: providers whose API
|
|
57
73
|
* keys are present in env are force-enabled (so a user who sets
|
|
@@ -21,6 +21,11 @@ import * as fs from 'fs';
|
|
|
21
21
|
import * as path from 'path';
|
|
22
22
|
import { findProjectRoot } from '../../../kernel/unified-memory.js';
|
|
23
23
|
import { DEFAULT_ROUTER_CONFIG, ALL_PROVIDER_TYPES } from './types.js';
|
|
24
|
+
import { createLogger } from '../../../logging/logger-factory.js';
|
|
25
|
+
// `console.warn` is not usable here: in MCP stdio mode stdout is the protocol
|
|
26
|
+
// channel and console output is suppressed, so a config warning written that
|
|
27
|
+
// way is invisible in the most common way AQE runs (issue #568).
|
|
28
|
+
const logger = createLogger('llm/router/config-store');
|
|
24
29
|
/** Filename under .agentic-qe/ */
|
|
25
30
|
export const ROUTER_CONFIG_FILENAME = 'llm-config.json';
|
|
26
31
|
/**
|
|
@@ -39,6 +44,10 @@ const PROVIDER_ENV_KEYS = {
|
|
|
39
44
|
// availability is gated on the `claude` binary being on PATH (see the
|
|
40
45
|
// provider's isAvailable()).
|
|
41
46
|
'claude-code': [],
|
|
47
|
+
// ADR-124 M3.5: codex authenticates via the user's ChatGPT login
|
|
48
|
+
// (subscription), NOT an env key. Availability is gated on the `codex`
|
|
49
|
+
// binary being on PATH (see the provider's isAvailable()).
|
|
50
|
+
codex: [],
|
|
42
51
|
openai: ['OPENAI_API_KEY'],
|
|
43
52
|
ollama: [], // ollama is local; no key required
|
|
44
53
|
openrouter: ['OPENROUTER_API_KEY'],
|
|
@@ -59,6 +68,7 @@ const PROVIDER_ENV_KEYS = {
|
|
|
59
68
|
const RUNTIME_CONSTRUCTIBLE_PROVIDERS = new Set([
|
|
60
69
|
'claude',
|
|
61
70
|
'claude-code',
|
|
71
|
+
'codex',
|
|
62
72
|
'openai',
|
|
63
73
|
'ollama',
|
|
64
74
|
'openrouter',
|
|
@@ -197,8 +207,97 @@ export function mergeRouterConfig(base, override) {
|
|
|
197
207
|
};
|
|
198
208
|
}
|
|
199
209
|
}
|
|
210
|
+
// Issue #568: `agentOverrides` gets keyed-object merge semantics (like
|
|
211
|
+
// `providers`), NOT the shallow-replace treatment `fallbackChain` gets.
|
|
212
|
+
// Overriding one agent type must not wipe the rest.
|
|
213
|
+
if (base.agentOverrides || override.agentOverrides) {
|
|
214
|
+
merged.agentOverrides = { ...(base.agentOverrides ?? {}) };
|
|
215
|
+
for (const [agentType, cfg] of Object.entries(override.agentOverrides ?? {})) {
|
|
216
|
+
if (!cfg)
|
|
217
|
+
continue;
|
|
218
|
+
merged.agentOverrides[agentType] = {
|
|
219
|
+
...(base.agentOverrides?.[agentType] ?? {}),
|
|
220
|
+
...cfg,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
}
|
|
200
224
|
return merged;
|
|
201
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* Validate and normalize an on-disk `agentOverrides` map (issue #568).
|
|
228
|
+
*
|
|
229
|
+
* User-hand-edited config is untrusted input: drop entries that name a provider
|
|
230
|
+
* we cannot construct, and strip any `apiKey`-shaped field that leaked in — the
|
|
231
|
+
* same "never persist API keys" discipline `saveRouterConfigFile` already
|
|
232
|
+
* enforces for `providers.*`.
|
|
233
|
+
*
|
|
234
|
+
* Returns the cleaned map plus human-readable warnings for the caller to log.
|
|
235
|
+
* Invalid entries are dropped, never thrown on: a typo in one agent key must not
|
|
236
|
+
* take down router initialization for the whole project.
|
|
237
|
+
*/
|
|
238
|
+
export function sanitizeAgentOverrides(raw) {
|
|
239
|
+
const overrides = {};
|
|
240
|
+
const warnings = [];
|
|
241
|
+
if (raw === undefined || raw === null)
|
|
242
|
+
return { overrides, warnings };
|
|
243
|
+
if (typeof raw !== 'object' || Array.isArray(raw)) {
|
|
244
|
+
warnings.push('`agentOverrides` must be an object keyed by agent type; ignoring it.');
|
|
245
|
+
return { overrides, warnings };
|
|
246
|
+
}
|
|
247
|
+
for (const [agentType, value] of Object.entries(raw)) {
|
|
248
|
+
if (!agentType.trim())
|
|
249
|
+
continue;
|
|
250
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
251
|
+
warnings.push(`agentOverrides["${agentType}"] must be an object; ignoring it.`);
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
const entry = value;
|
|
255
|
+
const cleaned = {};
|
|
256
|
+
if (entry.provider !== undefined) {
|
|
257
|
+
const provider = entry.provider;
|
|
258
|
+
if (!ALL_PROVIDER_TYPES.includes(provider)) {
|
|
259
|
+
warnings.push(`agentOverrides["${agentType}"].provider "${String(entry.provider)}" is not a known ` +
|
|
260
|
+
`provider (${ALL_PROVIDER_TYPES.join(', ')}); ignoring this entry.`);
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
if (!RUNTIME_CONSTRUCTIBLE_PROVIDERS.has(provider)) {
|
|
264
|
+
warnings.push(`agentOverrides["${agentType}"].provider "${provider}" cannot be instantiated at ` +
|
|
265
|
+
`runtime yet; ignoring this entry.`);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
cleaned.provider = provider;
|
|
269
|
+
}
|
|
270
|
+
if (typeof entry.model === 'string' && entry.model.trim()) {
|
|
271
|
+
cleaned.model = entry.model.trim();
|
|
272
|
+
}
|
|
273
|
+
if (typeof entry.temperature === 'number' && Number.isFinite(entry.temperature)) {
|
|
274
|
+
cleaned.temperature = entry.temperature;
|
|
275
|
+
}
|
|
276
|
+
if (typeof entry.maxTokens === 'number' && Number.isFinite(entry.maxTokens)) {
|
|
277
|
+
cleaned.maxTokens = entry.maxTokens;
|
|
278
|
+
}
|
|
279
|
+
if (typeof entry.priority === 'number' && Number.isFinite(entry.priority)) {
|
|
280
|
+
cleaned.priority = entry.priority;
|
|
281
|
+
}
|
|
282
|
+
// Secrets are already dropped by construction: `cleaned` is an ALLOW-LIST,
|
|
283
|
+
// so anything not explicitly copied above never survives. This check exists
|
|
284
|
+
// only so a user who pasted a credential in here is TOLD it was discarded
|
|
285
|
+
// rather than silently wondering why their key isn't being used.
|
|
286
|
+
// Deliberately does not echo the value.
|
|
287
|
+
const secretish = Object.keys(entry).filter(k => /^(api[-_]?key|key|token|secret|password|passwd|auth|authorization|bearer|credential)s?$/i.test(k));
|
|
288
|
+
if (secretish.length > 0) {
|
|
289
|
+
warnings.push(`agentOverrides["${agentType}"] contained credential-shaped field(s) ` +
|
|
290
|
+
`[${secretish.join(', ')}] — discarded, not persisted, not logged. Credentials belong ` +
|
|
291
|
+
`in environment variables, never in .agentic-qe/llm-config.json.`);
|
|
292
|
+
}
|
|
293
|
+
if (Object.keys(cleaned).length === 0) {
|
|
294
|
+
warnings.push(`agentOverrides["${agentType}"] had no usable fields; ignoring it.`);
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
overrides[agentType] = cleaned;
|
|
298
|
+
}
|
|
299
|
+
return { overrides, warnings };
|
|
300
|
+
}
|
|
202
301
|
/**
|
|
203
302
|
* Apply env-detection on top of a merged config: providers whose API
|
|
204
303
|
* keys are present in env are force-enabled (so a user who sets
|
|
@@ -282,6 +381,15 @@ export function resolveProviderOverrideFromEnv(env = process.env) {
|
|
|
282
381
|
export function loadRouterConfig(options = {}) {
|
|
283
382
|
const env = options.env ?? process.env;
|
|
284
383
|
const onDisk = loadRouterConfigFile(options.projectRoot);
|
|
384
|
+
// Issue #568: validate the hand-editable per-agent map before it reaches the
|
|
385
|
+
// router. Bad entries are dropped with a warning, never fatal.
|
|
386
|
+
if (onDisk.agentOverrides !== undefined) {
|
|
387
|
+
const { overrides, warnings } = sanitizeAgentOverrides(onDisk.agentOverrides);
|
|
388
|
+
for (const warning of warnings) {
|
|
389
|
+
logger.warn(`[llm-config] ${warning}`);
|
|
390
|
+
}
|
|
391
|
+
onDisk.agentOverrides = overrides;
|
|
392
|
+
}
|
|
285
393
|
const merged = mergeRouterConfig(DEFAULT_ROUTER_CONFIG, onDisk);
|
|
286
394
|
// ADR-123: an explicit `enabled: false` on disk is never resurrected by env.
|
|
287
395
|
const explicitlyDisabled = collectExplicitlyDisabled(onDisk);
|
|
@@ -518,8 +518,8 @@ export class HybridRouter {
|
|
|
518
518
|
metadata: params.metadata,
|
|
519
519
|
});
|
|
520
520
|
// ADR-123: persist the charge to the cross-process ledger so budgets
|
|
521
|
-
// hold across a fleet of processes.
|
|
522
|
-
this.providerManager.recordResponseSpend(response);
|
|
521
|
+
// hold across a fleet of processes. ADR-124 M2.3: attribute to the agent.
|
|
522
|
+
this.providerManager.recordResponseSpend(response, params.agentType);
|
|
523
523
|
const callLatency = Date.now() - callStartTime;
|
|
524
524
|
// Record success in legacy tracker
|
|
525
525
|
this.metrics.recordSuccess(providerType);
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
* - Routing decision audit log
|
|
22
22
|
* - Cost breakdown by agent type
|
|
23
23
|
*/
|
|
24
|
-
export type { ExtendedProviderType, ProviderCapabilities, ExtendedLLMProvider, RequiredFeature, ModelFamily, ModelTier, ModelMapping, ModelRegistry, MessageFormat, SystemPromptStrategy, ToolSchemaFormat, TranslatedMessages, ToolDefinition, TranslatedTools, TranslationOptions, PromptTranslator, RoutingMode, TaskComplexity, RuleCondition, RuleAction, RoutingRule, SelectionReason, RoutingDecision, FallbackBehavior, FallbackChainEntry, FallbackChain, RouterConfig, ChatParams, ChatResponse, StreamChunk, ProviderRoutingMetrics, RouterMetrics, } from './types';
|
|
24
|
+
export type { ExtendedProviderType, ProviderCapabilities, ExtendedLLMProvider, RequiredFeature, ModelFamily, ModelTier, ModelMapping, ModelRegistry, MessageFormat, SystemPromptStrategy, ToolSchemaFormat, TranslatedMessages, ToolDefinition, TranslatedTools, TranslationOptions, PromptTranslator, RoutingMode, TaskComplexity, RuleCondition, RuleAction, RoutingRule, SelectionReason, RoutingDecision, FallbackBehavior, FallbackChainEntry, FallbackChain, RouterConfig, AgentProviderOverride, ChatParams, ChatResponse, StreamChunk, ProviderRoutingMetrics, RouterMetrics, } from './types';
|
|
25
25
|
export { ALL_PROVIDER_TYPES, DEFAULT_PROVIDER_CAPABILITIES, DEFAULT_FALLBACK_BEHAVIOR, DEFAULT_ROUTER_CONFIG, } from './types';
|
|
26
26
|
export { RoutingRuleEngine, DEFAULT_QE_ROUTING_RULES, createRoutingRule, mergeWithDefaultRules, inferComplexity, getExtendedAgentCategory, getModelPreferenceForAgent, agentRequiresAdvancedReasoning, agentIsCostSensitive, agentIsLatencySensitive, getAgentTypesInCategory, getAllAgentCategories, getCategoryModelPreference, createAgentBasedRoutingRule, createCategoryBasedRoutingRules, generateComprehensiveAgentRules, mergeAgentAwareRules, } from './routing-rules';
|
|
27
27
|
export type { ExtendedAgentCategory } from './routing-rules';
|
|
28
28
|
export type { AgentCategory, ModelPreference, AgentCapabilityRequirements, AgentRoutingConfig, AgentRouterConfig, AgentRoutingOverride, } from './agent-router-config';
|
|
29
|
-
export { DEFAULT_CATEGORY_MODELS, AGENT_CATEGORY_MAP, DEFAULT_CATEGORY_CAPABILITIES, DEFAULT_ROUTING_OVERRIDES, ALTERNATIVE_MODELS, getAgentRoutingCategory, getPreferredModelForAgent, getAgentCapabilityRequirements, getAgentsByCategory, requiresAdvancedReasoning, isCostSensitive, isLatencySensitive, createAgentRoutingRule, createCategoryRoutingRules, createAgentAwareRules, createAllAgentRoutingRules, getAlternativeModelsForAgent, buildAgentRouterConfig, } from './agent-router-config';
|
|
29
|
+
export { DEFAULT_CATEGORY_MODELS, AGENT_CATEGORY_MAP, DEFAULT_CATEGORY_CAPABILITIES, DEFAULT_ROUTING_OVERRIDES, ALTERNATIVE_MODELS, getAgentRoutingCategory, getPreferredModelForAgent, getAgentCapabilityRequirements, getAgentsByCategory, requiresAdvancedReasoning, isCostSensitive, isLatencySensitive, createAgentRoutingRule, createCategoryRoutingRules, createAgentAwareRules, createAllAgentRoutingRules, setAgentProviderOverrides, getAgentProviderOverrides, resetAgentProviderOverrides, createOverrideRoutingRules, getAlternativeModelsForAgent, buildAgentRouterConfig, } from './agent-router-config';
|
|
30
30
|
export { HybridRouter, createHybridRouter, createQERouter, } from './hybrid-router';
|
|
31
31
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -38,6 +38,8 @@ DEFAULT_CATEGORY_MODELS, AGENT_CATEGORY_MAP, DEFAULT_CATEGORY_CAPABILITIES, DEFA
|
|
|
38
38
|
getAgentRoutingCategory, getPreferredModelForAgent, getAgentCapabilityRequirements, getAgentsByCategory, requiresAdvancedReasoning, isCostSensitive, isLatencySensitive,
|
|
39
39
|
// Rule generation
|
|
40
40
|
createAgentRoutingRule, createCategoryRoutingRules, createAgentAwareRules, createAllAgentRoutingRules,
|
|
41
|
+
// On-disk per-agent overrides (issue #568)
|
|
42
|
+
setAgentProviderOverrides, getAgentProviderOverrides, resetAgentProviderOverrides, createOverrideRoutingRules,
|
|
41
43
|
// Alternative models
|
|
42
44
|
getAlternativeModelsForAgent,
|
|
43
45
|
// Configuration builder
|
|
@@ -562,6 +562,50 @@ export interface RouterConfig {
|
|
|
562
562
|
cacheConfig?: RouterCacheConfig;
|
|
563
563
|
/** Audit logging configuration (ADR-043) */
|
|
564
564
|
auditConfig?: AuditConfig;
|
|
565
|
+
/**
|
|
566
|
+
* Per-agent-type provider/model overrides (issue #568).
|
|
567
|
+
*
|
|
568
|
+
* Keyed by agent type (`qe-security-scanner`, `qe-test-architect`, ...).
|
|
569
|
+
* These take priority over the category defaults in
|
|
570
|
+
* `agent-router-config.ts` (`AGENT_CATEGORY_MAP` -> `DEFAULT_CATEGORY_MODELS`),
|
|
571
|
+
* letting a user route security-sensitive agents to a stronger model and
|
|
572
|
+
* mechanical ones to a cheap/local provider without touching
|
|
573
|
+
* `defaultProvider`.
|
|
574
|
+
*
|
|
575
|
+
* Set on disk in `.agentic-qe/llm-config.json`:
|
|
576
|
+
* ```jsonc
|
|
577
|
+
* {
|
|
578
|
+
* "defaultProvider": "claude-code",
|
|
579
|
+
* "agentOverrides": {
|
|
580
|
+
* "qe-security-scanner": { "provider": "cognitum", "model": "cognitum-high" },
|
|
581
|
+
* "qe-mutation-tester": { "provider": "ollama" }
|
|
582
|
+
* }
|
|
583
|
+
* }
|
|
584
|
+
* ```
|
|
585
|
+
* Unset fields keep their category default. Never put API keys here.
|
|
586
|
+
*/
|
|
587
|
+
agentOverrides?: Record<string, AgentProviderOverride>;
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* On-disk, per-agent-type routing override (issue #568).
|
|
591
|
+
*
|
|
592
|
+
* A deliberately narrow, hand-editable subset of `ModelPreference` from
|
|
593
|
+
* `agent-router-config.ts`: `provider` and `model` are the only fields a user
|
|
594
|
+
* realistically wants to set by hand, but `temperature`/`maxTokens`/`priority`
|
|
595
|
+
* are accepted for parity with the in-process `AgentRoutingOverride` mechanism.
|
|
596
|
+
* Every field is optional and falls back to the agent's category default.
|
|
597
|
+
*/
|
|
598
|
+
export interface AgentProviderOverride {
|
|
599
|
+
/** Provider to route this agent type through. */
|
|
600
|
+
provider?: ExtendedProviderType;
|
|
601
|
+
/** Model identifier within that provider. */
|
|
602
|
+
model?: string;
|
|
603
|
+
/** Sampling temperature. */
|
|
604
|
+
temperature?: number;
|
|
605
|
+
/** Max tokens for typical requests. */
|
|
606
|
+
maxTokens?: number;
|
|
607
|
+
/** Rule priority; higher wins. Defaults to above the category rule. */
|
|
608
|
+
priority?: number;
|
|
565
609
|
}
|
|
566
610
|
/**
|
|
567
611
|
* Routing context provided with chat requests
|
|
@@ -28,6 +28,12 @@ export interface SpendEntry {
|
|
|
28
28
|
promptTokens: number;
|
|
29
29
|
completionTokens: number;
|
|
30
30
|
requestId: string;
|
|
31
|
+
/**
|
|
32
|
+
* ADR-124 M2.3: the QE agent type/name this charge is attributed to (e.g.
|
|
33
|
+
* 'qe-security-scanner'). Optional — null when the call site has no agent
|
|
34
|
+
* context. Enables per-agent cost attribution across the fleet.
|
|
35
|
+
*/
|
|
36
|
+
agent?: string;
|
|
31
37
|
}
|
|
32
38
|
/** Cross-process spend ledger. */
|
|
33
39
|
export interface SpendLedger {
|
|
@@ -35,16 +41,33 @@ export interface SpendLedger {
|
|
|
35
41
|
record(entry: SpendEntry): void;
|
|
36
42
|
/** Total USD charged within the last `windowMs` (rolling window ending now). */
|
|
37
43
|
spentSince(windowMs: number, nowMs?: number): number;
|
|
44
|
+
/**
|
|
45
|
+
* ADR-124 M2.3: USD charged within the last `windowMs`, broken down by agent
|
|
46
|
+
* type. Charges with no agent are grouped under '(unattributed)'.
|
|
47
|
+
*/
|
|
48
|
+
spentByAgentSince(windowMs: number, nowMs?: number): Record<string, number>;
|
|
38
49
|
}
|
|
50
|
+
/** Bucket used for charges recorded without an agent context. */
|
|
51
|
+
export declare const UNATTRIBUTED_AGENT = "(unattributed)";
|
|
39
52
|
/**
|
|
40
53
|
* SQLite-backed ledger. Cross-process because every process opens its own
|
|
41
54
|
* connection to the same WAL-mode `memory.db`.
|
|
42
55
|
*/
|
|
43
56
|
export declare class SqliteSpendLedger implements SpendLedger {
|
|
44
57
|
private readonly db;
|
|
58
|
+
/**
|
|
59
|
+
* Whether the `agent_type` column exists. If the additive migration couldn't
|
|
60
|
+
* run (e.g. transient lock), this stays false and record() INSERTs WITHOUT the
|
|
61
|
+
* column — so spend is still recorded and the ADR-123 budget cap still holds.
|
|
62
|
+
* A qe-court review (ADR-124) caught the original bug: a swallowed migration
|
|
63
|
+
* made every INSERT reference a missing column, throw, get caught, and silently
|
|
64
|
+
* drop ALL spend — bypassing the budget cap (the #557 class).
|
|
65
|
+
*/
|
|
66
|
+
private hasAgentColumn;
|
|
45
67
|
constructor(db: DatabaseType);
|
|
46
68
|
record(entry: SpendEntry): void;
|
|
47
69
|
spentSince(windowMs: number, nowMs?: number): number;
|
|
70
|
+
spentByAgentSince(windowMs: number, nowMs?: number): Record<string, number>;
|
|
48
71
|
}
|
|
49
72
|
/**
|
|
50
73
|
* In-process fallback ledger. Used when no unified DB is available. Enforces
|
|
@@ -54,6 +77,7 @@ export declare class InMemorySpendLedger implements SpendLedger {
|
|
|
54
77
|
private readonly entries;
|
|
55
78
|
record(entry: SpendEntry): void;
|
|
56
79
|
spentSince(windowMs: number, nowMs?: number): number;
|
|
80
|
+
spentByAgentSince(windowMs: number, nowMs?: number): Record<string, number>;
|
|
57
81
|
}
|
|
58
82
|
/**
|
|
59
83
|
* Build the default ledger. Prefers the unified `memory.db` (cross-process);
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
* connections (one per process) to a WAL-mode DB is exactly the supported
|
|
18
18
|
* cross-process pattern.
|
|
19
19
|
*/
|
|
20
|
+
/** Bucket used for charges recorded without an agent context. */
|
|
21
|
+
export const UNATTRIBUTED_AGENT = '(unattributed)';
|
|
20
22
|
const CREATE_TABLE_SQL = `
|
|
21
23
|
CREATE TABLE IF NOT EXISTS llm_spend (
|
|
22
24
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -37,27 +39,72 @@ CREATE INDEX IF NOT EXISTS idx_llm_spend_ts ON llm_spend(ts);
|
|
|
37
39
|
*/
|
|
38
40
|
export class SqliteSpendLedger {
|
|
39
41
|
db;
|
|
42
|
+
/**
|
|
43
|
+
* Whether the `agent_type` column exists. If the additive migration couldn't
|
|
44
|
+
* run (e.g. transient lock), this stays false and record() INSERTs WITHOUT the
|
|
45
|
+
* column — so spend is still recorded and the ADR-123 budget cap still holds.
|
|
46
|
+
* A qe-court review (ADR-124) caught the original bug: a swallowed migration
|
|
47
|
+
* made every INSERT reference a missing column, throw, get caught, and silently
|
|
48
|
+
* drop ALL spend — bypassing the budget cap (the #557 class).
|
|
49
|
+
*/
|
|
50
|
+
hasAgentColumn = false;
|
|
40
51
|
constructor(db) {
|
|
41
52
|
this.db = db;
|
|
42
53
|
// Additive schema only — CREATE TABLE/INDEX IF NOT EXISTS never drops data.
|
|
43
54
|
this.db.exec(CREATE_TABLE_SQL);
|
|
55
|
+
// ADR-124 M2.3: additive `agent_type` column for per-agent attribution.
|
|
56
|
+
// ALTER TABLE ADD COLUMN is non-destructive (existing rows get NULL); guarded
|
|
57
|
+
// so re-opening an already-migrated DB is a no-op. Never drops or rewrites.
|
|
58
|
+
try {
|
|
59
|
+
const cols = this.db.prepare(`PRAGMA table_info(llm_spend)`).all();
|
|
60
|
+
if (!cols.some((c) => c.name === 'agent_type')) {
|
|
61
|
+
this.db.exec(`ALTER TABLE llm_spend ADD COLUMN agent_type TEXT`);
|
|
62
|
+
}
|
|
63
|
+
this.db.exec(`CREATE INDEX IF NOT EXISTS idx_llm_spend_agent ON llm_spend(agent_type)`);
|
|
64
|
+
this.hasAgentColumn = true;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Attribution is best-effort; never block ledger use on the migration.
|
|
68
|
+
// hasAgentColumn stays false → record() degrades to un-attributed INSERTs.
|
|
69
|
+
}
|
|
44
70
|
}
|
|
45
71
|
record(entry) {
|
|
46
72
|
try {
|
|
47
|
-
this.
|
|
48
|
-
.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
73
|
+
if (this.hasAgentColumn) {
|
|
74
|
+
this.db
|
|
75
|
+
.prepare(`INSERT INTO llm_spend
|
|
76
|
+
(ts, provider, model, cost_usd, cost_source, prompt_tokens, completion_tokens, request_id, agent_type)
|
|
77
|
+
VALUES (@ts, @provider, @model, @cost_usd, @cost_source, @prompt_tokens, @completion_tokens, @request_id, @agent_type)`)
|
|
78
|
+
.run({
|
|
79
|
+
ts: Date.now(),
|
|
80
|
+
provider: entry.provider,
|
|
81
|
+
model: entry.model,
|
|
82
|
+
cost_usd: entry.costUsd,
|
|
83
|
+
cost_source: entry.costSource,
|
|
84
|
+
prompt_tokens: entry.promptTokens,
|
|
85
|
+
completion_tokens: entry.completionTokens,
|
|
86
|
+
request_id: entry.requestId,
|
|
87
|
+
agent_type: entry.agent ?? null,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// Column absent (migration couldn't run) — still record spend so the
|
|
92
|
+
// budget cap holds; just without per-agent attribution.
|
|
93
|
+
this.db
|
|
94
|
+
.prepare(`INSERT INTO llm_spend
|
|
95
|
+
(ts, provider, model, cost_usd, cost_source, prompt_tokens, completion_tokens, request_id)
|
|
96
|
+
VALUES (@ts, @provider, @model, @cost_usd, @cost_source, @prompt_tokens, @completion_tokens, @request_id)`)
|
|
97
|
+
.run({
|
|
98
|
+
ts: Date.now(),
|
|
99
|
+
provider: entry.provider,
|
|
100
|
+
model: entry.model,
|
|
101
|
+
cost_usd: entry.costUsd,
|
|
102
|
+
cost_source: entry.costSource,
|
|
103
|
+
prompt_tokens: entry.promptTokens,
|
|
104
|
+
completion_tokens: entry.completionTokens,
|
|
105
|
+
request_id: entry.requestId,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
61
108
|
}
|
|
62
109
|
catch {
|
|
63
110
|
// A ledger write must never break a generation call.
|
|
@@ -74,6 +121,21 @@ export class SqliteSpendLedger {
|
|
|
74
121
|
return 0;
|
|
75
122
|
}
|
|
76
123
|
}
|
|
124
|
+
spentByAgentSince(windowMs, nowMs = Date.now()) {
|
|
125
|
+
try {
|
|
126
|
+
const rows = this.db
|
|
127
|
+
.prepare(`SELECT COALESCE(agent_type, ?) AS agent, COALESCE(SUM(cost_usd), 0) AS total
|
|
128
|
+
FROM llm_spend WHERE ts >= ? GROUP BY COALESCE(agent_type, ?)`)
|
|
129
|
+
.all(UNATTRIBUTED_AGENT, nowMs - windowMs, UNATTRIBUTED_AGENT);
|
|
130
|
+
const out = {};
|
|
131
|
+
for (const r of rows)
|
|
132
|
+
out[r.agent] = r.total;
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return {};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
77
139
|
}
|
|
78
140
|
/**
|
|
79
141
|
* In-process fallback ledger. Used when no unified DB is available. Enforces
|
|
@@ -82,7 +144,7 @@ export class SqliteSpendLedger {
|
|
|
82
144
|
export class InMemorySpendLedger {
|
|
83
145
|
entries = [];
|
|
84
146
|
record(entry) {
|
|
85
|
-
this.entries.push({ ts: Date.now(), costUsd: entry.costUsd });
|
|
147
|
+
this.entries.push({ ts: Date.now(), costUsd: entry.costUsd, agent: entry.agent ?? UNATTRIBUTED_AGENT });
|
|
86
148
|
}
|
|
87
149
|
spentSince(windowMs, nowMs = Date.now()) {
|
|
88
150
|
const cutoff = nowMs - windowMs;
|
|
@@ -93,6 +155,15 @@ export class InMemorySpendLedger {
|
|
|
93
155
|
}
|
|
94
156
|
return total;
|
|
95
157
|
}
|
|
158
|
+
spentByAgentSince(windowMs, nowMs = Date.now()) {
|
|
159
|
+
const cutoff = nowMs - windowMs;
|
|
160
|
+
const out = {};
|
|
161
|
+
for (const e of this.entries) {
|
|
162
|
+
if (e.ts >= cutoff)
|
|
163
|
+
out[e.agent] = (out[e.agent] ?? 0) + e.costUsd;
|
|
164
|
+
}
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
96
167
|
}
|
|
97
168
|
/**
|
|
98
169
|
* Build the default ledger. Prefers the unified `memory.db` (cross-process);
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
const SYSTEM_PROMPT_STRATEGIES = {
|
|
17
17
|
claude: 'native', // Anthropic supports separate system param
|
|
18
18
|
'claude-code': 'native', // ADR-123: passed via --append-system-prompt
|
|
19
|
+
codex: 'native', // ADR-124 M3.5: provider flattens system into the prompt
|
|
19
20
|
openai: 'native', // OpenAI supports system role messages
|
|
20
21
|
ollama: 'native', // Ollama supports system role
|
|
21
22
|
openrouter: 'native', // OpenRouter passes through to underlying provider
|
package/dist/shared/safe-db.d.ts
CHANGED
|
@@ -18,6 +18,16 @@ export interface SafeDbOptions {
|
|
|
18
18
|
busyTimeout?: number;
|
|
19
19
|
/** Enable WAL mode (default: true for writable, false for readonly) */
|
|
20
20
|
walMode?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* M3.2: on a malformed/corrupt existing DB, auto-restore the newest verified
|
|
23
|
+
* backup (from `.agentic-qe/backups/verified/`) and park the corrupt original,
|
|
24
|
+
* instead of opening a broken DB. Default false; enable for the unified
|
|
25
|
+
* `memory.db` open. Non-destructive: the corrupt file is renamed, never deleted,
|
|
26
|
+
* and nothing happens if no verified backup exists. Ignored for readonly opens.
|
|
27
|
+
*/
|
|
28
|
+
autoRestore?: boolean;
|
|
29
|
+
/** Override the verified-backup directory used by autoRestore. */
|
|
30
|
+
backupDir?: string;
|
|
21
31
|
}
|
|
22
32
|
/**
|
|
23
33
|
* Open a SQLite database with safe defaults that prevent corruption.
|