agentic-qe 3.9.8 → 3.9.10
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/agents/_shared/executor-preamble.md +86 -0
- package/.claude/agents/v3/qe-coverage-specialist.md +20 -1
- package/.claude/agents/v3/qe-fleet-commander.md +20 -1
- package/.claude/agents/v3/qe-pentest-validator.md +20 -1
- package/.claude/agents/v3/qe-queen-coordinator.md +20 -1
- package/.claude/agents/v3/qe-risk-assessor.md +20 -1
- package/.claude/agents/v3/qe-root-cause-analyzer.md +19 -0
- package/.claude/agents/v3/qe-security-auditor.md +20 -1
- package/.claude/agents/v3/qe-test-architect.md +33 -1
- package/.claude/helpers/advisor-call.cjs +283 -0
- package/.claude/skills/README.md +4 -3
- package/.claude/skills/a11y-ally/SKILL.md +40 -18
- package/.claude/skills/accessibility-testing/SKILL.md +4 -0
- package/.claude/skills/compatibility-testing/SKILL.md +23 -0
- package/.claude/skills/e2e-flow-verifier/SKILL.md +87 -52
- package/.claude/skills/enterprise-integration-testing/SKILL.md +4 -0
- package/.claude/skills/localization-testing/SKILL.md +14 -0
- package/.claude/skills/observability-testing-patterns/SKILL.md +16 -0
- package/.claude/skills/qe-browser/SKILL.md +409 -0
- package/.claude/skills/qe-browser/evals/qe-browser.yaml +291 -0
- package/.claude/skills/qe-browser/fixtures/package.json +7 -0
- package/.claude/skills/qe-browser/fixtures/serve-skills.js +130 -0
- package/.claude/skills/qe-browser/references/assertion-kinds.md +132 -0
- package/.claude/skills/qe-browser/references/migration-from-playwright.md +195 -0
- package/.claude/skills/qe-browser/schemas/output.json +188 -0
- package/.claude/skills/qe-browser/scripts/assert.js +378 -0
- package/.claude/skills/qe-browser/scripts/batch.js +292 -0
- package/.claude/skills/qe-browser/scripts/check-injection.js +267 -0
- package/.claude/skills/qe-browser/scripts/intent-score.js +325 -0
- package/.claude/skills/qe-browser/scripts/lib/vibium.js +330 -0
- package/.claude/skills/qe-browser/scripts/package.json +7 -0
- package/.claude/skills/qe-browser/scripts/smoke-test.sh +212 -0
- package/.claude/skills/qe-browser/scripts/validate-config.json +46 -0
- package/.claude/skills/qe-browser/scripts/visual-diff.js +276 -0
- package/.claude/skills/qe-visual-accessibility/SKILL.md +31 -1
- package/.claude/skills/security-visual-testing/SKILL.md +18 -0
- package/.claude/skills/skills-manifest.json +20 -13
- package/.claude/skills/testability-scoring/SKILL.md +23 -0
- package/.claude/skills/trust-tier-manifest.json +14 -3
- package/.claude/skills/visual-testing-advanced/SKILL.md +41 -1
- package/CHANGELOG.md +75 -0
- package/README.md +5 -3
- package/assets/agents/v3/helpers/advisor-call.cjs +283 -0
- package/assets/agents/v3/qe-coverage-specialist.md +20 -1
- package/assets/agents/v3/qe-fleet-commander.md +20 -1
- package/assets/agents/v3/qe-pentest-validator.md +20 -1
- package/assets/agents/v3/qe-queen-coordinator.md +20 -1
- package/assets/agents/v3/qe-risk-assessor.md +20 -1
- package/assets/agents/v3/qe-root-cause-analyzer.md +19 -0
- package/assets/agents/v3/qe-security-auditor.md +20 -1
- package/assets/agents/v3/qe-test-architect.md +33 -1
- package/assets/skills/README.md +4 -3
- package/assets/skills/a11y-ally/SKILL.md +40 -18
- package/assets/skills/accessibility-testing/SKILL.md +4 -0
- package/assets/skills/compatibility-testing/SKILL.md +23 -0
- package/assets/skills/e2e-flow-verifier/SKILL.md +87 -52
- package/assets/skills/enterprise-integration-testing/SKILL.md +4 -0
- package/assets/skills/localization-testing/SKILL.md +14 -0
- package/assets/skills/observability-testing-patterns/SKILL.md +16 -0
- package/assets/skills/qe-browser/SKILL.md +409 -0
- package/assets/skills/qe-browser/evals/qe-browser.yaml +291 -0
- package/assets/skills/qe-browser/fixtures/package.json +7 -0
- package/assets/skills/qe-browser/fixtures/serve-skills.js +130 -0
- package/assets/skills/qe-browser/references/assertion-kinds.md +132 -0
- package/assets/skills/qe-browser/references/migration-from-playwright.md +195 -0
- package/assets/skills/qe-browser/schemas/output.json +188 -0
- package/assets/skills/qe-browser/scripts/assert.js +378 -0
- package/assets/skills/qe-browser/scripts/batch.js +292 -0
- package/assets/skills/qe-browser/scripts/check-injection.js +267 -0
- package/assets/skills/qe-browser/scripts/intent-score.js +325 -0
- package/assets/skills/qe-browser/scripts/lib/vibium.js +330 -0
- package/assets/skills/qe-browser/scripts/package.json +7 -0
- package/assets/skills/qe-browser/scripts/smoke-test.sh +212 -0
- package/assets/skills/qe-browser/scripts/validate-config.json +46 -0
- package/assets/skills/qe-browser/scripts/visual-diff.js +276 -0
- package/assets/skills/qe-visual-accessibility/SKILL.md +31 -1
- package/assets/skills/security-visual-testing/SKILL.md +18 -0
- package/assets/skills/skills-manifest.json +211 -15
- package/assets/skills/testability-scoring/SKILL.md +23 -0
- package/assets/skills/trust-tier-manifest.json +14 -3
- package/assets/skills/visual-testing-advanced/SKILL.md +41 -1
- package/dist/cli/bundle.js +5 -5
- package/dist/cli/chunks/adapter-IKCDCMSI.js +2 -0
- package/dist/cli/chunks/{agent-booster-wasm-LAE4NTVX.js → agent-booster-wasm-HM4XSABF.js} +2 -2
- package/dist/cli/chunks/{agent-handler-FVXHR6XN.js → agent-handler-UDBDLLO4.js} +2 -2
- package/dist/cli/chunks/{agent-memory-branch-Q7LLBA7C.js → agent-memory-branch-VIXQ3DAR.js} +2 -2
- package/dist/cli/chunks/aqe-learning-engine-W4WW7SQW.js +2 -0
- package/dist/cli/chunks/{audit-YRLKHJLX.js → audit-FWTGLQHH.js} +2 -2
- package/dist/cli/chunks/base-UQKFTHOY.js +2 -0
- package/dist/cli/chunks/{better-sqlite3-XFGOGICB.js → better-sqlite3-TYI3CCWU.js} +2 -2
- package/dist/cli/chunks/{brain-handler-KIUSNVSS.js → brain-handler-45ZGBLSB.js} +3 -3
- package/dist/cli/chunks/{branch-enumerator-VKZ4L3FH.js → branch-enumerator-ZBXELCQA.js} +2 -2
- package/dist/cli/chunks/{browser-GZVIYFIB.js → browser-2KM5IKEX.js} +2 -2
- package/dist/cli/chunks/browser-workflow-NMOEM3HW.js +2 -0
- package/dist/cli/chunks/{chunk-7PHNHFZI.js → chunk-226DSROQ.js} +3 -3
- package/dist/cli/chunks/{chunk-MGX2BZWE.js → chunk-27B575K6.js} +2 -2
- package/dist/cli/chunks/{chunk-P7APAQD6.js → chunk-2IJFZW3N.js} +12 -12
- package/dist/cli/chunks/{chunk-TWDWDKOI.js → chunk-32OB4ZYQ.js} +1 -1
- package/dist/cli/chunks/{chunk-E4D36LGH.js → chunk-335CCAOL.js} +1 -1
- package/dist/cli/chunks/{chunk-Q5PARJC6.js → chunk-34WI4QNF.js} +2 -2
- package/dist/cli/chunks/chunk-3A4BL62O.js +2 -0
- package/dist/cli/chunks/{chunk-6ZMM7MXA.js → chunk-3AG647MY.js} +2 -2
- package/dist/cli/chunks/{chunk-LPRHYSXN.js → chunk-3HIDCXW3.js} +1 -1
- package/dist/cli/chunks/{chunk-HN7HYUW6.js → chunk-4EKWEDHA.js} +9 -9
- package/dist/cli/chunks/{chunk-JCROLOP6.js → chunk-4FU6YNDP.js} +2 -2
- package/dist/cli/chunks/{chunk-A4DJMFDM.js → chunk-4LOJJ4VX.js} +1 -1
- package/dist/cli/chunks/{chunk-I25KIHQE.js → chunk-4VOGUZW5.js} +1 -1
- package/dist/cli/chunks/{chunk-KJZU3E5G.js → chunk-4ZR5G4MZ.js} +2 -2
- package/dist/cli/chunks/{chunk-W45FANJG.js → chunk-52ZHPZVX.js} +2 -2
- package/dist/cli/chunks/{chunk-LOANEFGZ.js → chunk-53G3OCGS.js} +2 -2
- package/dist/cli/chunks/{chunk-TZMKO6PC.js → chunk-54TZA65H.js} +2 -2
- package/dist/cli/chunks/{chunk-GHJRX7PV.js → chunk-5QKTLOGO.js} +1 -1
- package/dist/cli/chunks/{chunk-76UL224Z.js → chunk-5TATJQ3Z.js} +2 -2
- package/dist/cli/chunks/{chunk-OGFGNAKQ.js → chunk-5V6DRRLO.js} +2 -2
- package/dist/cli/chunks/{chunk-BXMIQRF3.js → chunk-6X7WKNDF.js} +2 -2
- package/dist/cli/chunks/chunk-7FWZHYYE.js +2 -0
- package/dist/cli/chunks/{chunk-R2LWLZ3Y.js → chunk-A2ULGMMG.js} +1 -1
- package/dist/cli/chunks/{chunk-AVKDT3UL.js → chunk-A53XKLEA.js} +8 -8
- package/dist/cli/chunks/{chunk-GOPE5OB5.js → chunk-A5OIXFFL.js} +1 -1
- package/dist/cli/chunks/{chunk-I7OH6RAC.js → chunk-ACNL4NFI.js} +2 -2
- package/dist/cli/chunks/{chunk-PBPOSPTY.js → chunk-AE6Y5CNJ.js} +2 -2
- package/dist/cli/chunks/{chunk-TN72MXLI.js → chunk-AO4HDN62.js} +2 -2
- package/dist/cli/chunks/{chunk-IHJXFWUL.js → chunk-AOA454FC.js} +2 -2
- package/dist/cli/chunks/{chunk-N2L7RWNX.js → chunk-B2QVWL5R.js} +2 -2
- package/dist/cli/chunks/{chunk-7CFEGUEH.js → chunk-B3L3CT4X.js} +2 -2
- package/dist/cli/chunks/{chunk-XVXSQOQG.js → chunk-B4AFVIOA.js} +2 -2
- package/dist/cli/chunks/{chunk-S72TSJS4.js → chunk-BCSCJBYQ.js} +2 -2
- package/dist/cli/chunks/{chunk-UAI5NPPQ.js → chunk-BIV6HWMT.js} +2 -2
- package/dist/cli/chunks/{chunk-XPL3BXLM.js → chunk-BNNH3KZP.js} +1 -1
- package/dist/cli/chunks/{chunk-JK6JBNGL.js → chunk-C234RGWZ.js} +2 -2
- package/dist/cli/chunks/{chunk-4EAAHMVM.js → chunk-C55GEYDA.js} +2 -2
- package/dist/cli/chunks/{chunk-Y67OXEUM.js → chunk-CEBZHZ4O.js} +1 -1
- package/dist/cli/chunks/{chunk-A2QLTNN5.js → chunk-CFQHIWWH.js} +1 -1
- package/dist/cli/chunks/{chunk-KMGAJRQ6.js → chunk-CJO2V2FB.js} +1 -1
- package/dist/cli/chunks/{chunk-5TGK7VTS.js → chunk-CQNXIYQW.js} +2 -2
- package/dist/cli/chunks/{chunk-IP2Z4Z6X.js → chunk-D2A4TGZY.js} +1 -1
- package/dist/cli/chunks/{chunk-VVNR4R22.js → chunk-DG2OYKUQ.js} +2 -2
- package/dist/cli/chunks/{chunk-ELZ5SKEN.js → chunk-DPYCHODC.js} +2 -2
- package/dist/cli/chunks/{chunk-WUCWFDBE.js → chunk-E4YKNKQL.js} +2 -2
- package/dist/cli/chunks/{chunk-ZCKNGICX.js → chunk-EEWTTYRC.js} +1 -1
- package/dist/cli/chunks/{chunk-IFIYNCT2.js → chunk-EGIYLRW5.js} +2 -2
- package/dist/cli/chunks/{chunk-DLKRK2GU.js → chunk-EHGTNSJ2.js} +1 -1
- package/dist/cli/chunks/{chunk-IIYXSWJN.js → chunk-EJNASXOY.js} +2 -2
- package/dist/cli/chunks/{chunk-ZJ4PMOIZ.js → chunk-F7HRGQRS.js} +2 -2
- package/dist/cli/chunks/{chunk-2QI5RYVR.js → chunk-FF7TSDO4.js} +2 -2
- package/dist/cli/chunks/{chunk-DDDEGBBJ.js → chunk-FIQNVPYY.js} +2 -2
- package/dist/cli/chunks/{chunk-F5VLJFVU.js → chunk-FJOBKT7N.js} +1 -1
- package/dist/cli/chunks/{chunk-JNJYWWBG.js → chunk-FYI52MFF.js} +6 -6
- package/dist/cli/chunks/{chunk-UOSKMAAY.js → chunk-GCNTU3QJ.js} +1 -1
- package/dist/cli/chunks/{chunk-4GMV6Z7Y.js → chunk-H56YBNXW.js} +2 -2
- package/dist/cli/chunks/{chunk-HTL2WT64.js → chunk-HJMLJNCB.js} +1 -1
- package/dist/cli/chunks/chunk-I3IRIJOT.js +2 -0
- package/dist/cli/chunks/chunk-IEQ2VYMO.js +3 -0
- package/dist/cli/chunks/{chunk-PG7CZ6Q4.js → chunk-IGRKFVFD.js} +2 -2
- package/dist/cli/chunks/{chunk-SQ6XZGR4.js → chunk-IJPE6OGD.js} +10 -10
- package/dist/cli/chunks/{chunk-AYKMWP7F.js → chunk-IJUL2UMO.js} +1 -1
- package/dist/cli/chunks/{chunk-JVH7753D.js → chunk-ISZJAZ2D.js} +1 -1
- package/dist/cli/chunks/{chunk-NCXVOOA7.js → chunk-ITDYTODU.js} +2 -2
- package/dist/cli/chunks/{chunk-RGCCSAHI.js → chunk-JHUEBBSX.js} +2 -2
- package/dist/cli/chunks/{chunk-TDPHLQ2M.js → chunk-JN3CC2TX.js} +2 -2
- package/dist/cli/chunks/{chunk-TSDTRJOG.js → chunk-JOEEGNNX.js} +2 -2
- package/dist/cli/chunks/{chunk-QVGSD25D.js → chunk-JQX2DHQT.js} +1 -1
- package/dist/cli/chunks/{chunk-VHZ653XS.js → chunk-JRG4AFUR.js} +3 -3
- package/dist/cli/chunks/{chunk-SP3ZBJ63.js → chunk-JRMNQWRL.js} +3 -3
- package/dist/cli/chunks/{chunk-EKDFIYV5.js → chunk-JXDJMVIG.js} +2 -2
- package/dist/cli/chunks/{chunk-3WOQMFTD.js → chunk-JYPW22JV.js} +2 -2
- package/dist/cli/chunks/{chunk-WJDOOT2M.js → chunk-KK3KVYE7.js} +2 -2
- package/dist/cli/chunks/{chunk-4KX6TMKB.js → chunk-KSRAA6ZD.js} +3 -3
- package/dist/cli/chunks/chunk-KUCU5ML6.js +6 -0
- package/dist/cli/chunks/{chunk-MVW7AACO.js → chunk-KXXLMLMJ.js} +2 -2
- package/dist/cli/chunks/{chunk-HE2NWYHK.js → chunk-LKCFJC4Q.js} +1 -1
- package/dist/cli/chunks/{chunk-237NNDKL.js → chunk-LODXDV4G.js} +2 -2
- package/dist/cli/chunks/{chunk-W4IRWGGR.js → chunk-M4CYXAVP.js} +4 -4
- package/dist/cli/chunks/{chunk-R4VOIXJQ.js → chunk-MOLMS6MA.js} +2 -2
- package/dist/cli/chunks/{chunk-SDMGF3KD.js → chunk-NBTM2J4B.js} +2 -2
- package/dist/cli/chunks/{chunk-X66IXWSO.js → chunk-NIFVFUCU.js} +2 -2
- package/dist/cli/chunks/{chunk-266SKKFM.js → chunk-OOHKW3UE.js} +2 -2
- package/dist/cli/chunks/{chunk-WXEDVKJS.js → chunk-ORA6NIXN.js} +2 -2
- package/dist/cli/chunks/{chunk-ECYDMBDA.js → chunk-OSD55UO7.js} +2 -2
- package/dist/cli/chunks/{chunk-SSURIMCL.js → chunk-OWQRMH3G.js} +2 -2
- package/dist/cli/chunks/chunk-QFUINEBN.js +2 -0
- package/dist/cli/chunks/{chunk-HYACMUUR.js → chunk-RE2IBX7Z.js} +2 -2
- package/dist/cli/chunks/{chunk-2V5VKOJ2.js → chunk-RMQQ5UHM.js} +2 -2
- package/dist/cli/chunks/{chunk-U62WL3WZ.js → chunk-ROEMVTXC.js} +3 -3
- package/dist/cli/chunks/{chunk-YOKRSFGA.js → chunk-SMTAZQJ3.js} +2 -2
- package/dist/cli/chunks/{chunk-OZTSMI7P.js → chunk-TO4NGP3E.js} +1 -1
- package/dist/cli/chunks/{chunk-LFEBTWFS.js → chunk-TTXYZUTQ.js} +2 -2
- package/dist/cli/chunks/{chunk-IZTUAI5T.js → chunk-U4NODKRR.js} +2 -2
- package/dist/cli/chunks/{chunk-JD3GH47Z.js → chunk-U635PSAW.js} +2 -2
- package/dist/cli/chunks/{chunk-6DBYVKGA.js → chunk-UBT7VCKQ.js} +2 -2
- package/dist/cli/chunks/{chunk-YSUMQBMY.js → chunk-UETM5XDO.js} +1 -1
- package/dist/cli/chunks/{chunk-BZB5D4BO.js → chunk-URXG7FMO.js} +4 -3
- package/dist/cli/chunks/{chunk-M2JBQVBP.js → chunk-VIWDVS24.js} +2 -2
- package/dist/cli/chunks/{chunk-6A4FEIE2.js → chunk-VNKCUKUJ.js} +3 -3
- package/dist/cli/chunks/{chunk-6KWX7A3R.js → chunk-VXIXHZCN.js} +2 -2
- package/dist/cli/chunks/{chunk-YIJDCZVX.js → chunk-WFEXEDMC.js} +2 -2
- package/dist/cli/chunks/{chunk-CG3HIYF4.js → chunk-WLX57ULC.js} +2 -2
- package/dist/cli/chunks/{chunk-FKODRXOU.js → chunk-WVQZGLCT.js} +2 -2
- package/dist/cli/chunks/{chunk-677V67MR.js → chunk-WW5DZ6BU.js} +1 -1
- package/dist/cli/chunks/{chunk-7L64UC5U.js → chunk-X364AIY6.js} +1 -1
- package/dist/cli/chunks/{chunk-UGJNR52C.js → chunk-XH7D6EGE.js} +1 -1
- package/dist/cli/chunks/{chunk-66DCG6RO.js → chunk-XICRAXUR.js} +4 -4
- package/dist/cli/chunks/{chunk-ETXK25IY.js → chunk-XMAV7AIC.js} +1 -1
- package/dist/cli/chunks/{chunk-NHXFAXEV.js → chunk-XSUPK7FI.js} +1 -1
- package/dist/cli/chunks/{chunk-3ZAGYTEC.js → chunk-XSWOB74I.js} +2 -2
- package/dist/cli/chunks/chunk-YPIZMTTA.js +14 -0
- package/dist/cli/chunks/{chunk-YDW522M7.js → chunk-YT6KBEXE.js} +2 -2
- package/dist/cli/chunks/{chunk-P2H5ARHM.js → chunk-ZENLP5LF.js} +1 -1
- package/dist/cli/chunks/{ci-A5ZXOEC4.js → ci-WS32HBBS.js} +2 -2
- package/dist/cli/chunks/{ci-output-S47BMRYC.js → ci-output-67R5MSLL.js} +2 -2
- package/dist/cli/chunks/circuit-breaker-MA562FT7.js +2 -0
- package/dist/cli/chunks/{claude-flow-setup-F5WBEBVK.js → claude-flow-setup-4QKGSRS7.js} +2 -2
- package/dist/cli/chunks/client-XQGZKXOB.js +2 -0
- package/dist/cli/chunks/{cline-installer-HLKR4QDR.js → cline-installer-6VSROHRY.js} +2 -2
- package/dist/cli/chunks/{code-MTZWS6JT.js → code-FBPBHVV3.js} +2 -2
- package/dist/cli/chunks/{code-index-extractor-BALTZ2WQ.js → code-index-extractor-62F622V2.js} +2 -2
- package/dist/cli/chunks/{codex-installer-LI2VIGET.js → codex-installer-LSR6DVCU.js} +2 -2
- package/dist/cli/chunks/{completions-TOF4GTNF.js → completions-56QOICBN.js} +2 -2
- package/dist/cli/chunks/{complexity-analyzer-IPFXIT6T.js → complexity-analyzer-SDH4NWIS.js} +2 -2
- package/dist/cli/chunks/{continuedev-installer-KWI66RBI.js → continuedev-installer-S7ZPL3VC.js} +2 -2
- package/dist/cli/chunks/{copilot-installer-REFOE6UF.js → copilot-installer-25GNNKNL.js} +2 -2
- package/dist/cli/chunks/{cost-tracker-M2MZQXCN.js → cost-tracker-73J4Y2RS.js} +2 -2
- package/dist/cli/chunks/{coverage-UR2XSJCR.js → coverage-WEE2AZ5F.js} +3 -3
- package/dist/cli/chunks/cross-domain-router-C2ZFCSXJ.js +2 -0
- package/dist/cli/chunks/{cursor-installer-X4PXCVYH.js → cursor-installer-DHQ644T3.js} +2 -2
- package/dist/cli/chunks/{daemon-5R6ZEEBB.js → daemon-3WUJ5E3X.js} +3 -3
- package/dist/cli/chunks/{dag-attention-scheduler-RUY2RJZA.js → dag-attention-scheduler-IRLAM43H.js} +2 -2
- package/dist/cli/chunks/{detect-PX2AYBHM.js → detect-DTSB4T4R.js} +2 -2
- package/dist/cli/chunks/{domain-handler-5JXWEO3E.js → domain-handler-DDN2Z5XC.js} +2 -2
- package/dist/cli/chunks/{domain-transfer-6M2YLBJY.js → domain-transfer-3RRG4S6R.js} +2 -2
- package/dist/cli/chunks/dream-JSZZ67OO.js +2 -0
- package/dist/cli/chunks/esm-node-X4TES6NX.js +2 -0
- package/dist/cli/chunks/{eval-L6ZBG462.js → eval-UXEP425X.js} +2 -2
- package/dist/cli/chunks/{fast-paths-WIFDALFK.js → fast-paths-4XLHS2VN.js} +2 -2
- package/dist/cli/chunks/{feature-flags-YLBXFUCN.js → feature-flags-6C2HD76K.js} +2 -2
- package/dist/cli/chunks/{feature-flags-GRHF5MTK.js → feature-flags-KXXHAEYF.js} +2 -2
- package/dist/cli/chunks/{file-discovery-4HXUB4HN.js → file-discovery-YSDUIZO4.js} +2 -2
- package/dist/cli/chunks/{fleet-RPLJXOEP.js → fleet-TYDG5DWK.js} +3 -3
- package/dist/cli/chunks/{gnn-wrapper-2D5IOGAT.js → gnn-wrapper-GJVYRPHB.js} +2 -2
- package/dist/cli/chunks/{heartbeat-handler-D5SWZZGA.js → heartbeat-handler-X63CM35O.js} +4 -4
- package/dist/cli/chunks/{heartbeat-scheduler-WSG4Y3M2.js → heartbeat-scheduler-NYH4CMVM.js} +2 -2
- package/dist/cli/chunks/hnsw-adapter-SQCVEHB5.js +2 -0
- package/dist/cli/chunks/hnsw-index-UGVC5IDK.js +2 -0
- package/dist/cli/chunks/{hnsw-legacy-bridge-UH6RWE74.js → hnsw-legacy-bridge-YDVUZTJI.js} +2 -2
- package/dist/cli/chunks/{hnswlib-node-BJ4ZJPMP.js → hnswlib-node-TLBDFWA6.js} +2 -2
- package/dist/cli/chunks/{hooks-KGDQNB5T.js → hooks-B6PVGP7D.js} +6 -6
- package/dist/cli/chunks/hybrid-router-YZEBKUZJ.js +2 -0
- package/dist/cli/chunks/{hypergraph-engine-LARQCK7V.js → hypergraph-engine-OQ2ZEG53.js} +2 -2
- package/dist/cli/chunks/{hypergraph-handler-RACF4AOX.js → hypergraph-handler-VPD424MI.js} +3 -3
- package/dist/cli/chunks/impact-analyzer-ZIXSRWED.js +2 -0
- package/dist/cli/chunks/{init-handler-64AOFMJD.js → init-handler-5WYP6NJW.js} +6 -6
- package/dist/cli/chunks/init-wizard-MO6PCXPX.js +2 -0
- package/dist/cli/chunks/kernel-P54KQB2F.js +2 -0
- package/dist/cli/chunks/{kilocode-installer-4ICIP6QN.js → kilocode-installer-YVY4EVMY.js} +2 -2
- package/dist/cli/chunks/{kiro-installer-J2GOV2OB.js → kiro-installer-GNT4BN3A.js} +2 -2
- package/dist/cli/chunks/knowledge-graph-GU57FQAQ.js +2 -0
- package/dist/cli/chunks/{learning-QD4JVH3K.js → learning-LD2RSBRS.js} +3 -3
- package/dist/cli/chunks/llm-router-ALKXFKLQ.js +36 -0
- package/dist/cli/chunks/{load-EXKUJMBK.js → load-XAOTGZYB.js} +2 -2
- package/dist/cli/chunks/load-test-5RFBTSS7.js +2 -0
- package/dist/cli/chunks/{mcp-NSNDZSMH.js → mcp-WDAJHGH4.js} +2 -2
- package/dist/cli/chunks/{memory-63JTNVZN.js → memory-M7QD57JD.js} +5 -5
- package/dist/cli/chunks/memory-backend-GPOP3IR4.js +2 -0
- package/dist/cli/chunks/memory-handlers-2NHGZLQM.js +2 -0
- package/dist/cli/chunks/multi-model-executor-2XZQK2IN.js +14 -0
- package/dist/cli/chunks/{opencode-installer-244LFSPN.js → opencode-installer-ASCVY3GG.js} +2 -2
- package/dist/cli/chunks/{orchestrator-TZB457J6.js → orchestrator-GOZICWN3.js} +22 -19
- package/dist/cli/chunks/{pipeline-YLBD2Z5Q.js → pipeline-YHQRJWV3.js} +2 -2
- package/dist/cli/chunks/{platform-53PWFZSE.js → platform-4NESYFHN.js} +2 -2
- package/dist/cli/chunks/{plugin-6GUQEFJU.js → plugin-E24I2RVB.js} +2 -2
- package/dist/cli/chunks/{prime-radiant-advanced-wasm-VCOK7FV5.js → prime-radiant-advanced-wasm-CDVSLR7R.js} +2 -2
- package/dist/cli/chunks/protocol-executor-M5IONISJ.js +2 -0
- package/dist/cli/chunks/{protocol-handler-25UEGTE2.js → protocol-handler-TGTDKSZB.js} +2 -2
- package/dist/cli/chunks/{prove-CTOU5F6G.js → prove-WUKDAMSE.js} +2 -2
- package/dist/cli/chunks/provider-manager-BTKK6W7M.js +24 -0
- package/dist/cli/chunks/qe-reasoning-bank-WIEXCBVE.js +2 -0
- package/dist/cli/chunks/{quality-PB7H5UEF.js → quality-RTIOIS2K.js} +2 -2
- package/dist/cli/chunks/queen-coordinator-ZFK6DANW.js +2 -0
- package/dist/cli/chunks/{real-embeddings-RWWYCIE5.js → real-embeddings-4JJKAEMO.js} +2 -2
- package/dist/cli/chunks/{roocode-installer-U4AGYVKL.js → roocode-installer-XU2IXRBM.js} +2 -2
- package/dist/cli/chunks/router-TOFBEI2Q.js +2 -0
- package/dist/cli/chunks/routing-feedback-RC2VDP6W.js +2 -0
- package/dist/cli/chunks/{routing-handler-NTDKDEBE.js → routing-handler-3KBOCIEN.js} +2 -2
- package/dist/cli/chunks/{ruvector-commands-RQKOLQSW.js → ruvector-commands-HHE2ZPX7.js} +2 -2
- package/dist/cli/chunks/{rvf-dual-writer-6EZ7S7OG.js → rvf-dual-writer-GAWM2BUZ.js} +2 -2
- package/dist/cli/chunks/{rvf-migration-adapter-EBTV6FV2.js → rvf-migration-adapter-HQPEC4BN.js} +2 -2
- package/dist/cli/chunks/{rvf-migration-coordinator-MERU7VLY.js → rvf-migration-coordinator-A4K45EFU.js} +2 -2
- package/dist/cli/chunks/rvf-native-adapter-ZOQDH3JY.js +2 -0
- package/dist/cli/chunks/safe-db-RIP3X32S.js +2 -0
- package/dist/cli/chunks/schedule-Q6KZRLWS.js +2 -0
- package/dist/cli/chunks/scheduler-SJO5QPAU.js +2 -0
- package/dist/cli/chunks/{security-JPDLGHMC.js → security-UIKUNOXB.js} +3 -3
- package/dist/cli/chunks/shared-rvf-adapter-JJCR3AWU.js +2 -0
- package/dist/cli/chunks/{shared-rvf-dual-writer-7OGLQE5Y.js → shared-rvf-dual-writer-ZUWSLFPH.js} +2 -2
- package/dist/cli/chunks/sqlite-persistence-HK2S6XAI.js +2 -0
- package/dist/cli/chunks/{status-handler-3TI3DHEL.js → status-handler-E3VSWGA6.js} +2 -2
- package/dist/cli/chunks/{structural-health-WCZKXVWS.js → structural-health-Y22H4BOU.js} +2 -2
- package/dist/cli/chunks/{sync-AM5T4GYO.js → sync-CA4KWZFS.js} +2 -2
- package/dist/cli/chunks/{task-handler-VHDTXPVP.js → task-handler-3EZPIAMD.js} +2 -2
- package/dist/cli/chunks/task-handlers-6UVAQAGP.js +2 -0
- package/dist/cli/chunks/{test-G6P5XGHM.js → test-Q5DOFSJI.js} +4 -4
- package/dist/cli/chunks/{test-scheduling-37RBUN4E.js → test-scheduling-BSXWCIMQ.js} +3 -3
- package/dist/cli/chunks/token-bootstrap-XGEZU2CS.js +2 -0
- package/dist/cli/chunks/{token-usage-5XGVBLFR.js → token-usage-BZX5TCG6.js} +2 -2
- package/dist/cli/chunks/{transformers-JTKWAZJU.js → transformers-7ITQPXAU.js} +2 -2
- package/dist/cli/chunks/{tree-sitter-wasm-parser-KW2GWIIQ.js → tree-sitter-wasm-parser-ZYBBNYR3.js} +2 -2
- package/dist/cli/chunks/{types-7R72BACI.js → types-ACZ5VVRC.js} +2 -2
- package/dist/cli/chunks/unified-memory-EXO6WK33.js +2 -0
- package/dist/cli/chunks/unified-memory-hnsw-7HPSTFVV.js +2 -0
- package/dist/cli/chunks/unified-persistence-WC3O4WOJ.js +2 -0
- package/dist/cli/chunks/{validate-TYB4ZTUL.js → validate-IQL6OVXD.js} +2 -2
- package/dist/cli/chunks/{validate-swarm-3TFI6PLT.js → validate-swarm-J52J2K5X.js} +2 -2
- package/dist/cli/chunks/{vibium-3YELURJT.js → vibium-XSE76PXE.js} +2 -2
- package/dist/cli/chunks/visual-security-COW3OCEE.js +2 -0
- package/dist/cli/chunks/{web-tree-sitter-7Q77A27Y.js → web-tree-sitter-YM6QXUIY.js} +2 -2
- package/dist/cli/chunks/{windsurf-installer-ASARRM2X.js → windsurf-installer-M27DVL4H.js} +2 -2
- package/dist/cli/chunks/{witness-chain-WZ6PNXEY.js → witness-chain-NB5LP73S.js} +2 -2
- package/dist/cli/chunks/witness-chain-XQXF3RSP.js +2 -0
- package/dist/cli/chunks/{workflow-JDTEE6TY.js → workflow-5DODQ6XS.js} +4 -4
- package/dist/cli/chunks/workflow-orchestrator-HSIZEKZM.js +2 -0
- package/dist/cli/chunks/{wrappers-X7WZLBZD.js → wrappers-K7HHCIYD.js} +2 -2
- package/dist/cli/commands/llm-router.js +252 -0
- package/dist/coordination/queen-task-management.js +8 -1
- package/dist/init/browser-engine-installer.d.ts +60 -0
- package/dist/init/browser-engine-installer.js +92 -0
- package/dist/init/init-wizard-steps.js +9 -0
- package/dist/init/phases/09-assets.d.ts +2 -0
- package/dist/init/phases/09-assets.js +65 -0
- package/dist/init/phases/12-verification.js +8 -0
- package/dist/init/skills-installer.js +1 -0
- package/dist/kernel/unified-memory-schemas.d.ts +1 -1
- package/dist/kernel/unified-memory-schemas.js +2 -1
- package/dist/mcp/bundle.js +47 -44
- package/dist/mcp/protocol-server.js +87 -0
- package/dist/routing/advisor/circuit-breaker.d.ts +56 -0
- package/dist/routing/advisor/circuit-breaker.js +128 -0
- package/dist/routing/advisor/domain-prompts.d.ts +14 -0
- package/dist/routing/advisor/domain-prompts.js +53 -0
- package/dist/routing/advisor/index.d.ts +10 -0
- package/dist/routing/advisor/index.js +9 -0
- package/dist/routing/advisor/multi-model-executor.d.ts +60 -0
- package/dist/routing/advisor/multi-model-executor.js +176 -0
- package/dist/routing/advisor/redaction.d.ts +40 -0
- package/dist/routing/advisor/redaction.js +187 -0
- package/dist/routing/advisor/types.d.ts +101 -0
- package/dist/routing/advisor/types.js +9 -0
- package/dist/routing/queen-integration.d.ts +3 -0
- package/dist/routing/queen-integration.js +7 -1
- package/dist/routing/routing-feedback.d.ts +7 -1
- package/dist/routing/routing-feedback.js +57 -11
- package/dist/routing/tiny-dancer-router.d.ts +35 -1
- package/dist/routing/tiny-dancer-router.js +33 -0
- package/dist/routing/types.d.ts +12 -0
- package/package.json +1 -1
- package/dist/cli/chunks/adapter-D4XQUIJD.js +0 -2
- package/dist/cli/chunks/aqe-learning-engine-CGIWYLIP.js +0 -2
- package/dist/cli/chunks/base-BYVP2STR.js +0 -2
- package/dist/cli/chunks/browser-workflow-PC4N5TKL.js +0 -2
- package/dist/cli/chunks/chunk-2K3DJ3EK.js +0 -7
- package/dist/cli/chunks/chunk-JBQ4WGB4.js +0 -14
- package/dist/cli/chunks/chunk-OT4JADWW.js +0 -2
- package/dist/cli/chunks/client-56BU3GAX.js +0 -2
- package/dist/cli/chunks/cross-domain-router-XQT52BTB.js +0 -2
- package/dist/cli/chunks/dream-LFZCN5WK.js +0 -2
- package/dist/cli/chunks/esm-node-EBDIEPKS.js +0 -2
- package/dist/cli/chunks/hnsw-adapter-BMXTVGZB.js +0 -2
- package/dist/cli/chunks/hnsw-index-YX6XLICT.js +0 -2
- package/dist/cli/chunks/impact-analyzer-MGSI2WBK.js +0 -2
- package/dist/cli/chunks/init-wizard-TBDWRRMC.js +0 -2
- package/dist/cli/chunks/kernel-NV7TO2FK.js +0 -2
- package/dist/cli/chunks/knowledge-graph-7REGYH6A.js +0 -2
- package/dist/cli/chunks/llm-router-4K4IT2PQ.js +0 -30
- package/dist/cli/chunks/load-test-RYQK44TT.js +0 -2
- package/dist/cli/chunks/memory-backend-3EBE2DEX.js +0 -2
- package/dist/cli/chunks/memory-handlers-2335MVQJ.js +0 -2
- package/dist/cli/chunks/protocol-executor-MR37S7GX.js +0 -2
- package/dist/cli/chunks/qe-reasoning-bank-DANGLPTH.js +0 -2
- package/dist/cli/chunks/queen-coordinator-4YJPYF5F.js +0 -2
- package/dist/cli/chunks/router-F4IPY4RQ.js +0 -2
- package/dist/cli/chunks/routing-feedback-VGHFIJ5S.js +0 -2
- package/dist/cli/chunks/rvf-native-adapter-2P75WF5A.js +0 -2
- package/dist/cli/chunks/safe-db-47NEO2RS.js +0 -2
- package/dist/cli/chunks/schedule-L5GJW25Z.js +0 -2
- package/dist/cli/chunks/scheduler-NGGGSZMO.js +0 -2
- package/dist/cli/chunks/shared-rvf-adapter-NKNTYGHO.js +0 -2
- package/dist/cli/chunks/sqlite-persistence-TE2ZRHKA.js +0 -2
- package/dist/cli/chunks/task-handlers-GEJ36WNB.js +0 -2
- package/dist/cli/chunks/token-bootstrap-JPE3LWXQ.js +0 -2
- package/dist/cli/chunks/unified-memory-KSBLUZT4.js +0 -2
- package/dist/cli/chunks/unified-memory-hnsw-V3EOMQIZ.js +0 -2
- package/dist/cli/chunks/unified-persistence-URIRJ4BM.js +0 -2
- package/dist/cli/chunks/visual-security-DJOOVCBZ.js +0 -2
- package/dist/cli/chunks/witness-chain-ZWJUCXCJ.js +0 -2
- package/dist/cli/chunks/workflow-orchestrator-5CKA6Q74.js +0 -2
|
@@ -1225,6 +1225,93 @@ export class MCPProtocolServer {
|
|
|
1225
1225
|
},
|
|
1226
1226
|
handler: (params) => handleMigrationPromote(params),
|
|
1227
1227
|
});
|
|
1228
|
+
// ADR-092: Thin MCP wrapper for advisor consultation (Phase 6)
|
|
1229
|
+
this.registerTool({
|
|
1230
|
+
definition: {
|
|
1231
|
+
name: 'advisor_consult',
|
|
1232
|
+
description: 'Consult a stronger advisor model for strategic guidance. Forwards a task description and context to the advisor and returns enumerated action steps. Auto-detects the best available provider. Example: advisor_consult({ agent: "qe-test-architect", task: "Generate tests for auth module", context: "Found 4 classes with external deps" })',
|
|
1233
|
+
category: 'routing',
|
|
1234
|
+
parameters: [
|
|
1235
|
+
{ name: 'agent', type: 'string', description: 'Agent name requesting advice (e.g., qe-test-architect)' },
|
|
1236
|
+
{ name: 'task', type: 'string', description: 'Task description' },
|
|
1237
|
+
{ name: 'context', type: 'string', description: 'What the executor has found so far' },
|
|
1238
|
+
{ name: 'provider', type: 'string', description: 'Provider override (openrouter, claude, ollama)' },
|
|
1239
|
+
{ name: 'model', type: 'string', description: 'Model override' },
|
|
1240
|
+
],
|
|
1241
|
+
},
|
|
1242
|
+
handler: async (params) => {
|
|
1243
|
+
const { execFileSync } = await import('child_process');
|
|
1244
|
+
const { writeFileSync, unlinkSync, mkdirSync } = await import('fs');
|
|
1245
|
+
const { join } = await import('path');
|
|
1246
|
+
const { tmpdir } = await import('os');
|
|
1247
|
+
const p = params;
|
|
1248
|
+
const transcriptDir = join(tmpdir(), 'aqe-advisor');
|
|
1249
|
+
mkdirSync(transcriptDir, { recursive: true });
|
|
1250
|
+
const transcriptPath = join(transcriptDir, `mcp-${Date.now()}.json`);
|
|
1251
|
+
const transcript = {
|
|
1252
|
+
taskDescription: p.task ?? '',
|
|
1253
|
+
messages: [
|
|
1254
|
+
{ role: 'user', content: p.task ?? '' },
|
|
1255
|
+
...(p.context ? [{ role: 'assistant', content: p.context }] : []),
|
|
1256
|
+
],
|
|
1257
|
+
};
|
|
1258
|
+
writeFileSync(transcriptPath, JSON.stringify(transcript));
|
|
1259
|
+
try {
|
|
1260
|
+
const cliArgs = [
|
|
1261
|
+
'llm', 'advise',
|
|
1262
|
+
'--transcript', transcriptPath,
|
|
1263
|
+
'--agent', p.agent ?? 'unknown',
|
|
1264
|
+
'--json',
|
|
1265
|
+
];
|
|
1266
|
+
if (p.provider)
|
|
1267
|
+
cliArgs.push('--provider', p.provider);
|
|
1268
|
+
if (p.model)
|
|
1269
|
+
cliArgs.push('--model', p.model);
|
|
1270
|
+
// Resolve aqe binary with fallback to npx (MCP server may not have aqe on PATH)
|
|
1271
|
+
let aqeBin = 'aqe';
|
|
1272
|
+
try {
|
|
1273
|
+
execFileSync('which', ['aqe'], { encoding: 'utf-8' });
|
|
1274
|
+
}
|
|
1275
|
+
catch {
|
|
1276
|
+
aqeBin = 'npx';
|
|
1277
|
+
cliArgs.unshift('aqe');
|
|
1278
|
+
}
|
|
1279
|
+
const result = execFileSync(aqeBin, cliArgs, {
|
|
1280
|
+
encoding: 'utf-8',
|
|
1281
|
+
timeout: 60000,
|
|
1282
|
+
env: process.env,
|
|
1283
|
+
});
|
|
1284
|
+
try {
|
|
1285
|
+
unlinkSync(transcriptPath);
|
|
1286
|
+
}
|
|
1287
|
+
catch { }
|
|
1288
|
+
const lines = result.split('\n');
|
|
1289
|
+
let jsonStr = '';
|
|
1290
|
+
let depth = 0;
|
|
1291
|
+
let inJson = false;
|
|
1292
|
+
for (const line of lines) {
|
|
1293
|
+
const t = line.trim();
|
|
1294
|
+
if (!inJson && t.startsWith('{'))
|
|
1295
|
+
inJson = true;
|
|
1296
|
+
if (inJson) {
|
|
1297
|
+
jsonStr += line + '\n';
|
|
1298
|
+
depth += (t.match(/{/g) || []).length;
|
|
1299
|
+
depth -= (t.match(/}/g) || []).length;
|
|
1300
|
+
if (depth <= 0)
|
|
1301
|
+
break;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
return JSON.parse(jsonStr || '{}');
|
|
1305
|
+
}
|
|
1306
|
+
catch (err) {
|
|
1307
|
+
try {
|
|
1308
|
+
unlinkSync(transcriptPath);
|
|
1309
|
+
}
|
|
1310
|
+
catch { }
|
|
1311
|
+
return { error: err.message?.slice(0, 300) ?? 'Unknown error' };
|
|
1312
|
+
}
|
|
1313
|
+
},
|
|
1314
|
+
});
|
|
1228
1315
|
// Register QE domain tools not already covered by hardcoded handlers above
|
|
1229
1316
|
const bridgedCount = registerMissingQETools((entry) => this.registerTool(entry));
|
|
1230
1317
|
console.error(`[MCP] Registered ${this.tools.size} tools (${bridgedCount} via QE bridge)`);
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advisor Circuit Breaker
|
|
3
|
+
* ADR-092: hard per-session ceiling on advisor calls
|
|
4
|
+
*
|
|
5
|
+
* Three protection layers:
|
|
6
|
+
* 1. per-task max_uses (enforced by caller)
|
|
7
|
+
* 2. per-call budget_usd (enforced by caller)
|
|
8
|
+
* 3. per-session hard ceiling (enforced here) — 10 advisor calls absolute max
|
|
9
|
+
*
|
|
10
|
+
* State persists to a JSON file at `.agentic-qe/advisor/circuit-breaker.json`
|
|
11
|
+
* so the ceiling survives across CLI invocations within the same session.
|
|
12
|
+
* Each CLI call to `aqe llm advise` is a fresh process — without file-based
|
|
13
|
+
* persistence, each invocation would get a fresh counter.
|
|
14
|
+
*/
|
|
15
|
+
export interface CircuitBreakerConfig {
|
|
16
|
+
/** Max advisor calls per session (default: 10) */
|
|
17
|
+
maxCallsPerSession: number;
|
|
18
|
+
/** Path to persist state (default: .agentic-qe/advisor/circuit-breaker.json) */
|
|
19
|
+
statePath?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface CircuitBreakerState {
|
|
22
|
+
sessionId: string;
|
|
23
|
+
callCount: number;
|
|
24
|
+
maxCalls: number;
|
|
25
|
+
remaining: number;
|
|
26
|
+
tripped: boolean;
|
|
27
|
+
}
|
|
28
|
+
export declare class AdvisorCircuitBreaker {
|
|
29
|
+
private readonly maxCalls;
|
|
30
|
+
private readonly statePath;
|
|
31
|
+
constructor(config?: Partial<CircuitBreakerConfig>);
|
|
32
|
+
/**
|
|
33
|
+
* Check whether another advisor call is allowed for this session.
|
|
34
|
+
* If allowed, increments the counter and persists. Throws on trip.
|
|
35
|
+
*/
|
|
36
|
+
acquire(sessionId: string): CircuitBreakerState;
|
|
37
|
+
/**
|
|
38
|
+
* Get the current state without incrementing.
|
|
39
|
+
*/
|
|
40
|
+
getState(sessionId: string): CircuitBreakerState;
|
|
41
|
+
/**
|
|
42
|
+
* Reset a specific session or all sessions.
|
|
43
|
+
*/
|
|
44
|
+
reset(sessionId?: string): void;
|
|
45
|
+
private load;
|
|
46
|
+
private save;
|
|
47
|
+
private evictStale;
|
|
48
|
+
}
|
|
49
|
+
export declare class AdvisorCircuitBreakerError extends Error {
|
|
50
|
+
readonly sessionId: string;
|
|
51
|
+
readonly callCount: number;
|
|
52
|
+
readonly maxCalls: number;
|
|
53
|
+
readonly exitCode = 3;
|
|
54
|
+
constructor(message: string, sessionId: string, callCount: number, maxCalls: number);
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=circuit-breaker.d.ts.map
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advisor Circuit Breaker
|
|
3
|
+
* ADR-092: hard per-session ceiling on advisor calls
|
|
4
|
+
*
|
|
5
|
+
* Three protection layers:
|
|
6
|
+
* 1. per-task max_uses (enforced by caller)
|
|
7
|
+
* 2. per-call budget_usd (enforced by caller)
|
|
8
|
+
* 3. per-session hard ceiling (enforced here) — 10 advisor calls absolute max
|
|
9
|
+
*
|
|
10
|
+
* State persists to a JSON file at `.agentic-qe/advisor/circuit-breaker.json`
|
|
11
|
+
* so the ceiling survives across CLI invocations within the same session.
|
|
12
|
+
* Each CLI call to `aqe llm advise` is a fresh process — without file-based
|
|
13
|
+
* persistence, each invocation would get a fresh counter.
|
|
14
|
+
*/
|
|
15
|
+
import { readFileSync, writeFileSync, mkdirSync, renameSync } from 'node:fs';
|
|
16
|
+
import { join, dirname } from 'node:path';
|
|
17
|
+
import { homedir } from 'node:os';
|
|
18
|
+
const DEFAULT_CONFIG = {
|
|
19
|
+
maxCallsPerSession: 10,
|
|
20
|
+
};
|
|
21
|
+
// Use home directory for stable path across CWDs and MCP contexts (M5 fix)
|
|
22
|
+
const DEFAULT_STATE_PATH = join(homedir(), '.agentic-qe', 'advisor', 'circuit-breaker.json');
|
|
23
|
+
const SESSION_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
24
|
+
export class AdvisorCircuitBreaker {
|
|
25
|
+
maxCalls;
|
|
26
|
+
statePath;
|
|
27
|
+
constructor(config) {
|
|
28
|
+
this.maxCalls = config?.maxCallsPerSession ?? DEFAULT_CONFIG.maxCallsPerSession;
|
|
29
|
+
this.statePath = config?.statePath ?? DEFAULT_STATE_PATH;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check whether another advisor call is allowed for this session.
|
|
33
|
+
* If allowed, increments the counter and persists. Throws on trip.
|
|
34
|
+
*/
|
|
35
|
+
acquire(sessionId) {
|
|
36
|
+
const state = this.load();
|
|
37
|
+
const entry = state.sessions[sessionId];
|
|
38
|
+
const current = entry?.count ?? 0;
|
|
39
|
+
if (current >= this.maxCalls) {
|
|
40
|
+
throw new AdvisorCircuitBreakerError(`Advisor circuit breaker tripped: ${current} calls in session "${sessionId}" ` +
|
|
41
|
+
`(max: ${this.maxCalls}). Do not retry — continue without the advisor.`, sessionId, current, this.maxCalls);
|
|
42
|
+
}
|
|
43
|
+
const next = current + 1;
|
|
44
|
+
state.sessions[sessionId] = { count: next, lastUpdated: new Date().toISOString() };
|
|
45
|
+
this.save(state);
|
|
46
|
+
return {
|
|
47
|
+
sessionId,
|
|
48
|
+
callCount: next,
|
|
49
|
+
maxCalls: this.maxCalls,
|
|
50
|
+
remaining: this.maxCalls - next,
|
|
51
|
+
tripped: false,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get the current state without incrementing.
|
|
56
|
+
*/
|
|
57
|
+
getState(sessionId) {
|
|
58
|
+
const state = this.load();
|
|
59
|
+
const current = state.sessions[sessionId]?.count ?? 0;
|
|
60
|
+
return {
|
|
61
|
+
sessionId,
|
|
62
|
+
callCount: current,
|
|
63
|
+
maxCalls: this.maxCalls,
|
|
64
|
+
remaining: this.maxCalls - current,
|
|
65
|
+
tripped: current >= this.maxCalls,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Reset a specific session or all sessions.
|
|
70
|
+
*/
|
|
71
|
+
reset(sessionId) {
|
|
72
|
+
if (sessionId) {
|
|
73
|
+
const state = this.load();
|
|
74
|
+
delete state.sessions[sessionId];
|
|
75
|
+
this.save(state);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
this.save({ sessions: {} });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
load() {
|
|
82
|
+
try {
|
|
83
|
+
const raw = readFileSync(this.statePath, 'utf-8');
|
|
84
|
+
const state = JSON.parse(raw);
|
|
85
|
+
this.evictStale(state);
|
|
86
|
+
return state;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return { sessions: {} };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
save(state) {
|
|
93
|
+
try {
|
|
94
|
+
mkdirSync(dirname(this.statePath), { recursive: true });
|
|
95
|
+
// Atomic write via rename to prevent TOCTOU race when concurrent
|
|
96
|
+
// CLI processes write simultaneously (H3 fix from devil's-advocate review)
|
|
97
|
+
const tmpPath = this.statePath + '.tmp.' + process.pid;
|
|
98
|
+
writeFileSync(tmpPath, JSON.stringify(state, null, 2));
|
|
99
|
+
renameSync(tmpPath, this.statePath);
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// Best-effort — if we can't persist, fall back to in-memory-only
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
evictStale(state) {
|
|
106
|
+
const now = Date.now();
|
|
107
|
+
for (const [sid, entry] of Object.entries(state.sessions)) {
|
|
108
|
+
const age = now - new Date(entry.lastUpdated).getTime();
|
|
109
|
+
if (age > SESSION_TTL_MS) {
|
|
110
|
+
delete state.sessions[sid];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export class AdvisorCircuitBreakerError extends Error {
|
|
116
|
+
sessionId;
|
|
117
|
+
callCount;
|
|
118
|
+
maxCalls;
|
|
119
|
+
exitCode = 3;
|
|
120
|
+
constructor(message, sessionId, callCount, maxCalls) {
|
|
121
|
+
super(message);
|
|
122
|
+
this.sessionId = sessionId;
|
|
123
|
+
this.callCount = callCount;
|
|
124
|
+
this.maxCalls = maxCalls;
|
|
125
|
+
this.name = 'AdvisorCircuitBreakerError';
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=circuit-breaker.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain-Specific Advisor System Prompts (ADR-092 Phase 4)
|
|
3
|
+
*
|
|
4
|
+
* Per-domain advisor prompts that replace the generic prompt when the
|
|
5
|
+
* agent's domain is known. These produce more targeted, actionable advice
|
|
6
|
+
* because the advisor knows what KIND of work the executor is doing.
|
|
7
|
+
*/
|
|
8
|
+
export declare const DOMAIN_ADVISOR_PROMPTS: Record<string, string>;
|
|
9
|
+
/**
|
|
10
|
+
* Get the domain-specific advisor prompt, falling back to undefined (which
|
|
11
|
+
* causes MultiModelExecutor to use the default generic prompt).
|
|
12
|
+
*/
|
|
13
|
+
export declare function getDomainAdvisorPrompt(domain: string): string | undefined;
|
|
14
|
+
//# sourceMappingURL=domain-prompts.d.ts.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain-Specific Advisor System Prompts (ADR-092 Phase 4)
|
|
3
|
+
*
|
|
4
|
+
* Per-domain advisor prompts that replace the generic prompt when the
|
|
5
|
+
* agent's domain is known. These produce more targeted, actionable advice
|
|
6
|
+
* because the advisor knows what KIND of work the executor is doing.
|
|
7
|
+
*/
|
|
8
|
+
export const DOMAIN_ADVISOR_PROMPTS = {
|
|
9
|
+
'test-generation': `You are the advisor for a test-generation executor. The executor is writing a test suite for source code it has read.
|
|
10
|
+
|
|
11
|
+
Respond in under 100 words, enumerated steps. Name concrete classes, methods, and dependencies from the source. Focus on:
|
|
12
|
+
1. What to mock (external deps, I/O, time, randomness)
|
|
13
|
+
2. Which methods need priority coverage (public API, error paths, state transitions)
|
|
14
|
+
3. Edge cases the executor will likely miss (boundary values, empty inputs, concurrent access, error cascades)
|
|
15
|
+
4. Test structure recommendations (fixtures, parametrize, grouping)
|
|
16
|
+
|
|
17
|
+
Do NOT write test code — the executor does that. Give strategic direction only.`,
|
|
18
|
+
'security-compliance': `You are the advisor for a security-focused executor (security audit or penetration test validation).
|
|
19
|
+
|
|
20
|
+
Respond in under 100 words, enumerated steps. Name concrete attack vectors, CWE IDs, and code locations. Focus on:
|
|
21
|
+
1. Which input boundaries lack validation (identify specific parameters, headers, query strings)
|
|
22
|
+
2. Authentication/authorization gaps (token handling, session management, privilege escalation paths)
|
|
23
|
+
3. Data exposure risks (logging sensitive data, error messages leaking internals, unredacted PII)
|
|
24
|
+
4. Dependency vulnerabilities (known CVEs in imports, outdated packages)
|
|
25
|
+
|
|
26
|
+
Prioritize by exploitability, not by count. One exploitable finding outweighs ten theoretical ones.`,
|
|
27
|
+
'coverage-analysis': `You are the advisor for a coverage analysis executor examining test gaps.
|
|
28
|
+
|
|
29
|
+
Respond in under 100 words, enumerated steps. Name concrete uncovered files, functions, and branches. Focus on:
|
|
30
|
+
1. Which uncovered code carries the highest business risk (payment paths, auth, data mutations)
|
|
31
|
+
2. Which branches are missed (error handlers, fallback paths, race conditions)
|
|
32
|
+
3. Whether the coverage gaps indicate missing test TYPES (integration tests, edge cases, negative tests)
|
|
33
|
+
4. Quick wins — functions with 0% coverage that are simple to test
|
|
34
|
+
|
|
35
|
+
Do NOT suggest increasing coverage for its own sake. Prioritize by risk.`,
|
|
36
|
+
'cross-domain': `You are the advisor for a fleet commander coordinating multiple QE agents across domains.
|
|
37
|
+
|
|
38
|
+
Respond in under 100 words, enumerated steps. Focus on:
|
|
39
|
+
1. Which domains need the most attention based on the current task context
|
|
40
|
+
2. Agent delegation recommendations (which agent type for which subtask)
|
|
41
|
+
3. Coordination risks (shared state, ordering dependencies, resource contention)
|
|
42
|
+
4. Whether the task decomposition is correct or if subtasks are missing
|
|
43
|
+
|
|
44
|
+
Think about the task holistically — the executor manages agents, not code directly.`,
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Get the domain-specific advisor prompt, falling back to undefined (which
|
|
48
|
+
* causes MultiModelExecutor to use the default generic prompt).
|
|
49
|
+
*/
|
|
50
|
+
export function getDomainAdvisorPrompt(domain) {
|
|
51
|
+
return DOMAIN_ADVISOR_PROMPTS[domain];
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=domain-prompts.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advisor Strategy public exports.
|
|
3
|
+
* ADR-092: Provider-Agnostic Advisor Strategy for QE Agents
|
|
4
|
+
*/
|
|
5
|
+
export type { AdvisorTranscript, ConsultOptions, AdvisorResult, AdvisorConsultation, IMultiModelExecutor, } from './types.js';
|
|
6
|
+
export { MultiModelExecutor, createMultiModelExecutor, DEFAULT_ADVISOR_PROVIDER, DEFAULT_ADVISOR_MODEL, DEFAULT_MAX_WORDS, } from './multi-model-executor.js';
|
|
7
|
+
export { redact, validateProviderForAgent, isSelfHosted, isSecurityAgentAllowed, isSecurityAgent, AdvisorRedactionError, type RedactionMode, type RedactionResult, } from './redaction.js';
|
|
8
|
+
export { AdvisorCircuitBreaker, AdvisorCircuitBreakerError, type CircuitBreakerConfig, type CircuitBreakerState, } from './circuit-breaker.js';
|
|
9
|
+
export { DOMAIN_ADVISOR_PROMPTS, getDomainAdvisorPrompt, } from './domain-prompts.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advisor Strategy public exports.
|
|
3
|
+
* ADR-092: Provider-Agnostic Advisor Strategy for QE Agents
|
|
4
|
+
*/
|
|
5
|
+
export { MultiModelExecutor, createMultiModelExecutor, DEFAULT_ADVISOR_PROVIDER, DEFAULT_ADVISOR_MODEL, DEFAULT_MAX_WORDS, } from './multi-model-executor.js';
|
|
6
|
+
export { redact, validateProviderForAgent, isSelfHosted, isSecurityAgentAllowed, isSecurityAgent, AdvisorRedactionError, } from './redaction.js';
|
|
7
|
+
export { AdvisorCircuitBreaker, AdvisorCircuitBreakerError, } from './circuit-breaker.js';
|
|
8
|
+
export { DOMAIN_ADVISOR_PROMPTS, getDomainAdvisorPrompt, } from './domain-prompts.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MultiModelExecutor — the execution layer for ADR-082's `triggerMultiModel` flag.
|
|
3
|
+
* ADR-092: Provider-Agnostic Advisor Strategy for QE Agents
|
|
4
|
+
*
|
|
5
|
+
* All phases implemented (ADR-092):
|
|
6
|
+
* - Consultation via HybridRouter.chat() with provider auto-detection
|
|
7
|
+
* - Secrets/PII redaction pre-flight (16 pattern categories)
|
|
8
|
+
* - Per-session circuit breaker (file-persisted, atomic writes)
|
|
9
|
+
* - Domain-specific advisor prompts via --advisor-prompt
|
|
10
|
+
* - Consultation sidecar persistence for RoutingFeedbackCollector
|
|
11
|
+
*
|
|
12
|
+
* Architecturally this class is small on purpose. TinyDancerRouter already
|
|
13
|
+
* decides WHEN advice is warranted (via `triggerMultiModel`). HybridRouter
|
|
14
|
+
* already handles provider dispatch, fallback, and cost tracking. This class
|
|
15
|
+
* is the narrow bridge between those two existing layers.
|
|
16
|
+
*/
|
|
17
|
+
import type { HybridRouter } from '../../shared/llm/router/hybrid-router.js';
|
|
18
|
+
import type { ExtendedProviderType } from '../../shared/llm/router/types.js';
|
|
19
|
+
import type { AdvisorResult, AdvisorTranscript, ConsultOptions, IMultiModelExecutor } from './types.js';
|
|
20
|
+
import { type CircuitBreakerState } from './circuit-breaker.js';
|
|
21
|
+
/**
|
|
22
|
+
* Default advisor model per ADR-092 Phase 0.
|
|
23
|
+
* OpenRouter exposes Anthropic Opus — chosen for vendor-independence as the
|
|
24
|
+
* default while direct Anthropic remains available for security-sensitive agents.
|
|
25
|
+
*/
|
|
26
|
+
export declare const DEFAULT_ADVISOR_PROVIDER: ExtendedProviderType;
|
|
27
|
+
export declare const DEFAULT_ADVISOR_MODEL = "anthropic/claude-opus-4";
|
|
28
|
+
export declare const DEFAULT_MAX_WORDS = 100;
|
|
29
|
+
/**
|
|
30
|
+
* Phase 0 MultiModelExecutor implementation.
|
|
31
|
+
*
|
|
32
|
+
* Takes a transcript, calls HybridRouter.chat() with a stronger-tier model,
|
|
33
|
+
* returns structured advice. No redaction, no circuit breaker, no cache —
|
|
34
|
+
* those arrive in Phase 1+.
|
|
35
|
+
*/
|
|
36
|
+
export declare class MultiModelExecutor implements IMultiModelExecutor {
|
|
37
|
+
private readonly router;
|
|
38
|
+
private readonly circuitBreaker;
|
|
39
|
+
constructor(router: HybridRouter, circuitBreakerConfig?: {
|
|
40
|
+
maxCallsPerSession?: number;
|
|
41
|
+
statePath?: string;
|
|
42
|
+
});
|
|
43
|
+
getCircuitBreakerState(sessionId: string): CircuitBreakerState;
|
|
44
|
+
resetCircuitBreaker(sessionId?: string): void;
|
|
45
|
+
consult(transcript: AdvisorTranscript, opts?: ConsultOptions): Promise<AdvisorResult>;
|
|
46
|
+
private persistConsultation;
|
|
47
|
+
/**
|
|
48
|
+
* Serialize a transcript into a single user message for the advisor.
|
|
49
|
+
* Kept simple for Phase 0 — no XML tags, no tool-result wrapping beyond
|
|
50
|
+
* role labels. This matches what most providers accept cleanly and is
|
|
51
|
+
* easy to evolve in Phase 1.
|
|
52
|
+
*/
|
|
53
|
+
private serializeTranscript;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Factory for convenience — most callers construct directly, but this keeps
|
|
57
|
+
* the import surface consistent with other factories in `src/routing/`.
|
|
58
|
+
*/
|
|
59
|
+
export declare function createMultiModelExecutor(router: HybridRouter): MultiModelExecutor;
|
|
60
|
+
//# sourceMappingURL=multi-model-executor.d.ts.map
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MultiModelExecutor — the execution layer for ADR-082's `triggerMultiModel` flag.
|
|
3
|
+
* ADR-092: Provider-Agnostic Advisor Strategy for QE Agents
|
|
4
|
+
*
|
|
5
|
+
* All phases implemented (ADR-092):
|
|
6
|
+
* - Consultation via HybridRouter.chat() with provider auto-detection
|
|
7
|
+
* - Secrets/PII redaction pre-flight (16 pattern categories)
|
|
8
|
+
* - Per-session circuit breaker (file-persisted, atomic writes)
|
|
9
|
+
* - Domain-specific advisor prompts via --advisor-prompt
|
|
10
|
+
* - Consultation sidecar persistence for RoutingFeedbackCollector
|
|
11
|
+
*
|
|
12
|
+
* Architecturally this class is small on purpose. TinyDancerRouter already
|
|
13
|
+
* decides WHEN advice is warranted (via `triggerMultiModel`). HybridRouter
|
|
14
|
+
* already handles provider dispatch, fallback, and cost tracking. This class
|
|
15
|
+
* is the narrow bridge between those two existing layers.
|
|
16
|
+
*/
|
|
17
|
+
import { createHash } from 'crypto';
|
|
18
|
+
import { redact, validateProviderForAgent, isSelfHosted, } from './redaction.js';
|
|
19
|
+
import { AdvisorCircuitBreaker } from './circuit-breaker.js';
|
|
20
|
+
/**
|
|
21
|
+
* Default advisor model per ADR-092 Phase 0.
|
|
22
|
+
* OpenRouter exposes Anthropic Opus — chosen for vendor-independence as the
|
|
23
|
+
* default while direct Anthropic remains available for security-sensitive agents.
|
|
24
|
+
*/
|
|
25
|
+
export const DEFAULT_ADVISOR_PROVIDER = 'openrouter';
|
|
26
|
+
export const DEFAULT_ADVISOR_MODEL = 'anthropic/claude-opus-4';
|
|
27
|
+
export const DEFAULT_MAX_WORDS = 100;
|
|
28
|
+
/**
|
|
29
|
+
* System prompt prepended to every advisor consultation.
|
|
30
|
+
*
|
|
31
|
+
* Text adapted from Anthropic's published canonical system prompt for the
|
|
32
|
+
* advisor tool (platform.claude.com/docs/en/agents-and-tools/tool-use/advisor-tool).
|
|
33
|
+
* Conciseness instruction reduces advisor output tokens by ~35-45% per published
|
|
34
|
+
* measurements without degrading call frequency.
|
|
35
|
+
*/
|
|
36
|
+
const ADVISOR_SYSTEM_PROMPT = `You are the advisor in an executor/advisor pattern. The executor has forwarded its full conversation transcript to you and is waiting for brief strategic guidance.
|
|
37
|
+
|
|
38
|
+
You see the task, every tool call the executor has made, every result it has seen.
|
|
39
|
+
|
|
40
|
+
Respond with a brief plan or correction in under 100 words. Use enumerated steps. No prose explanations. No pleasantries. Do not restate the task — the executor already knows the task. Focus on the next 1-3 concrete actions the executor should take, in order, with one-line reasons.
|
|
41
|
+
|
|
42
|
+
If you see the executor about to commit to a wrong approach, say so in step 1. If you see the executor is on track, say so in one line and name the specific next action. If the transcript lacks enough information to give useful advice, say "INSUFFICIENT CONTEXT" and name the missing piece.`;
|
|
43
|
+
/**
|
|
44
|
+
* Phase 0 MultiModelExecutor implementation.
|
|
45
|
+
*
|
|
46
|
+
* Takes a transcript, calls HybridRouter.chat() with a stronger-tier model,
|
|
47
|
+
* returns structured advice. No redaction, no circuit breaker, no cache —
|
|
48
|
+
* those arrive in Phase 1+.
|
|
49
|
+
*/
|
|
50
|
+
export class MultiModelExecutor {
|
|
51
|
+
router;
|
|
52
|
+
circuitBreaker;
|
|
53
|
+
constructor(router, circuitBreakerConfig) {
|
|
54
|
+
this.router = router;
|
|
55
|
+
this.circuitBreaker = new AdvisorCircuitBreaker(circuitBreakerConfig);
|
|
56
|
+
}
|
|
57
|
+
getCircuitBreakerState(sessionId) {
|
|
58
|
+
return this.circuitBreaker.getState(sessionId);
|
|
59
|
+
}
|
|
60
|
+
resetCircuitBreaker(sessionId) {
|
|
61
|
+
this.circuitBreaker.reset(sessionId);
|
|
62
|
+
}
|
|
63
|
+
async consult(transcript, opts = {}) {
|
|
64
|
+
const provider = opts.provider ?? DEFAULT_ADVISOR_PROVIDER;
|
|
65
|
+
const model = opts.model ?? DEFAULT_ADVISOR_MODEL;
|
|
66
|
+
const maxWords = opts.maxWords ?? DEFAULT_MAX_WORDS;
|
|
67
|
+
const agentName = opts.agentName ?? 'unknown';
|
|
68
|
+
const triggerReason = opts.triggerReason ?? 'manual';
|
|
69
|
+
const sessionId = opts.sessionId ?? 'default';
|
|
70
|
+
const redactionMode = opts.redact ?? 'strict';
|
|
71
|
+
// Phase 1 safety: validate provider is allowed for this agent
|
|
72
|
+
validateProviderForAgent(agentName, provider, redactionMode);
|
|
73
|
+
// Phase 1 safety: enforce per-session hard ceiling
|
|
74
|
+
const cbState = this.circuitBreaker.acquire(sessionId);
|
|
75
|
+
// Phase 1 safety: redact secrets before non-self-hosted providers see the transcript
|
|
76
|
+
let redactions = [];
|
|
77
|
+
let serialized = this.serializeTranscript(transcript, maxWords);
|
|
78
|
+
if (!isSelfHosted(provider)) {
|
|
79
|
+
const redactionResult = redact(serialized, redactionMode);
|
|
80
|
+
serialized = redactionResult.text;
|
|
81
|
+
redactions = redactionResult.redactions;
|
|
82
|
+
}
|
|
83
|
+
const messages = [{ role: 'user', content: serialized }];
|
|
84
|
+
const systemPrompt = opts.advisorSystemPrompt ?? ADVISOR_SYSTEM_PROMPT;
|
|
85
|
+
const params = {
|
|
86
|
+
messages,
|
|
87
|
+
systemPrompt,
|
|
88
|
+
agentType: agentName,
|
|
89
|
+
preferredProvider: provider,
|
|
90
|
+
model,
|
|
91
|
+
maxTokens: Math.max(300, Math.ceil(maxWords * 1.6)),
|
|
92
|
+
temperature: 0.2,
|
|
93
|
+
metadata: {
|
|
94
|
+
advisorCall: true,
|
|
95
|
+
triggerReason,
|
|
96
|
+
adrRef: 'ADR-092',
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
const response = await this.router.chat(params);
|
|
100
|
+
const advice = response.content.trim();
|
|
101
|
+
const adviceHash = createHash('sha256').update(advice).digest('hex');
|
|
102
|
+
const result = {
|
|
103
|
+
advice,
|
|
104
|
+
model: response.model,
|
|
105
|
+
provider: response.provider,
|
|
106
|
+
tokensIn: response.usage?.promptTokens ?? 0,
|
|
107
|
+
tokensOut: response.usage?.completionTokens ?? 0,
|
|
108
|
+
latencyMs: response.latencyMs,
|
|
109
|
+
costUsd: response.cost?.totalCost ?? 0,
|
|
110
|
+
adviceHash,
|
|
111
|
+
triggerReason,
|
|
112
|
+
cacheHit: response.cached ?? false,
|
|
113
|
+
redactionsApplied: redactions,
|
|
114
|
+
circuitBreakerRemaining: cbState.remaining,
|
|
115
|
+
};
|
|
116
|
+
// M1 fix: persist consultation to sidecar file so RoutingFeedbackCollector
|
|
117
|
+
// can pick it up when recording the routing outcome for this session.
|
|
118
|
+
this.persistConsultation(sessionId, result);
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
persistConsultation(sessionId, result) {
|
|
122
|
+
try {
|
|
123
|
+
const { writeFileSync, mkdirSync } = require('fs');
|
|
124
|
+
const { join } = require('path');
|
|
125
|
+
const { homedir } = require('os');
|
|
126
|
+
const dir = join(homedir(), '.agentic-qe', 'advisor', 'consultations');
|
|
127
|
+
mkdirSync(dir, { recursive: true });
|
|
128
|
+
const filePath = join(dir, `${sessionId}.json`);
|
|
129
|
+
writeFileSync(filePath, JSON.stringify({
|
|
130
|
+
model: result.model,
|
|
131
|
+
provider: result.provider,
|
|
132
|
+
tokensIn: result.tokensIn,
|
|
133
|
+
tokensOut: result.tokensOut,
|
|
134
|
+
latencyMs: result.latencyMs,
|
|
135
|
+
costUsd: result.costUsd,
|
|
136
|
+
adviceHash: result.adviceHash,
|
|
137
|
+
triggerReason: result.triggerReason,
|
|
138
|
+
redactionsApplied: result.redactionsApplied,
|
|
139
|
+
timestamp: new Date().toISOString(),
|
|
140
|
+
}, null, 2));
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// Best-effort — don't fail the advisor call if persistence fails
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Serialize a transcript into a single user message for the advisor.
|
|
148
|
+
* Kept simple for Phase 0 — no XML tags, no tool-result wrapping beyond
|
|
149
|
+
* role labels. This matches what most providers accept cleanly and is
|
|
150
|
+
* easy to evolve in Phase 1.
|
|
151
|
+
*/
|
|
152
|
+
serializeTranscript(transcript, maxWords) {
|
|
153
|
+
const parts = [];
|
|
154
|
+
if (transcript.systemPrompt) {
|
|
155
|
+
parts.push(`# Executor System Prompt\n${transcript.systemPrompt}`);
|
|
156
|
+
}
|
|
157
|
+
if (transcript.taskDescription) {
|
|
158
|
+
parts.push(`# Task\n${transcript.taskDescription}`);
|
|
159
|
+
}
|
|
160
|
+
parts.push('# Conversation so far');
|
|
161
|
+
for (const msg of transcript.messages) {
|
|
162
|
+
const tag = msg.role.toUpperCase();
|
|
163
|
+
parts.push(`[${tag}] ${msg.content}`);
|
|
164
|
+
}
|
|
165
|
+
parts.push(`\n# Your job\nRespond with brief strategic guidance in under ${maxWords} words. Use enumerated steps. No prose.`);
|
|
166
|
+
return parts.join('\n\n');
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Factory for convenience — most callers construct directly, but this keeps
|
|
171
|
+
* the import surface consistent with other factories in `src/routing/`.
|
|
172
|
+
*/
|
|
173
|
+
export function createMultiModelExecutor(router) {
|
|
174
|
+
return new MultiModelExecutor(router);
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=multi-model-executor.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secrets / PII Redaction Pre-Flight
|
|
3
|
+
* ADR-092 Phase 1: mandatory before non-self-hosted advisors see the transcript
|
|
4
|
+
*
|
|
5
|
+
* Scans transcript content for credential patterns, API keys, PII, and other
|
|
6
|
+
* sensitive data. Replaces matches with typed redaction markers. Returns the
|
|
7
|
+
* list of redaction categories applied so the audit log can record them.
|
|
8
|
+
*
|
|
9
|
+
* Three modes:
|
|
10
|
+
* strict — redacts credentials + PII + env values (default)
|
|
11
|
+
* balanced — redacts credentials + env values only
|
|
12
|
+
* off — no redaction (rejected for non-self-hosted providers by MultiModelExecutor)
|
|
13
|
+
*/
|
|
14
|
+
export type RedactionMode = 'strict' | 'balanced' | 'off';
|
|
15
|
+
export interface RedactionResult {
|
|
16
|
+
/** The redacted text */
|
|
17
|
+
text: string;
|
|
18
|
+
/** Categories of patterns found and redacted */
|
|
19
|
+
redactions: string[];
|
|
20
|
+
/** Total number of individual replacements made */
|
|
21
|
+
replacementCount: number;
|
|
22
|
+
}
|
|
23
|
+
export declare function isSelfHosted(provider: string): boolean;
|
|
24
|
+
export declare function isSecurityAgentAllowed(provider: string): boolean;
|
|
25
|
+
export declare function isSecurityAgent(agentName: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Redact sensitive patterns from text.
|
|
28
|
+
* Returns the redacted text and a list of categories found.
|
|
29
|
+
*/
|
|
30
|
+
export declare function redact(text: string, mode?: RedactionMode): RedactionResult;
|
|
31
|
+
/**
|
|
32
|
+
* Validate that the advisor call is allowed given the agent and provider.
|
|
33
|
+
* Throws with a descriptive message if the combination is forbidden.
|
|
34
|
+
*/
|
|
35
|
+
export declare function validateProviderForAgent(agentName: string, provider: string, redactionMode: RedactionMode): void;
|
|
36
|
+
export declare class AdvisorRedactionError extends Error {
|
|
37
|
+
readonly exitCode: number;
|
|
38
|
+
constructor(message: string, exitCode: number);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=redaction.d.ts.map
|