@tangle-network/agent-eval 0.215.1 → 0.216.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -0
- package/dist/adapters/http.d.ts +3 -3
- package/dist/{agent-profile-DmzL8KaJ.d.ts → agent-profile-VFcQncbW.d.ts} +5 -5
- package/dist/{agent-profile-DmzL8KaJ.d.ts.map → agent-profile-VFcQncbW.d.ts.map} +1 -1
- package/dist/{agent-profile-cell-BYc0bxsL.js → agent-profile-cell-BK8mlqlq.js} +3 -3
- package/dist/{agent-profile-cell-BYc0bxsL.js.map → agent-profile-cell-BK8mlqlq.js.map} +1 -1
- package/dist/agreement-irr-BEWLIF3_.js +186 -0
- package/dist/agreement-irr-BEWLIF3_.js.map +1 -0
- package/dist/analyst/index.d.ts +487 -14
- package/dist/analyst/index.d.ts.map +1 -1
- package/dist/analyst/index.js +1547 -12
- package/dist/analyst/index.js.map +1 -1
- package/dist/{analyze-runs-3xpby3p2.js → analyze-runs-C84irm4i.js} +608 -604
- package/dist/analyze-runs-C84irm4i.js.map +1 -0
- package/dist/{analyze-runs-BhFLOztS.d.ts → analyze-runs-D68fd-su.d.ts} +17 -15
- package/dist/analyze-runs-D68fd-su.d.ts.map +1 -0
- package/dist/{baseline-Dm8966du.js → baseline-Udi_PLuT.js} +5 -5
- package/dist/{baseline-Dm8966du.js.map → baseline-Udi_PLuT.js.map} +1 -1
- package/dist/{benchmark-BywPeAUo.js → benchmark-CXmVVHH2.js} +2 -2
- package/dist/{benchmark-BywPeAUo.js.map → benchmark-CXmVVHH2.js.map} +1 -1
- package/dist/{benchmark-command-CgpGi7vY.js → benchmark-command-By0vh8q7.js} +71 -70
- package/dist/benchmark-command-By0vh8q7.js.map +1 -0
- package/dist/benchmarks/index.d.ts +5 -5
- package/dist/benchmarks/index.js +3 -3
- package/dist/builder-eval/index.js +2 -2
- package/dist/campaign/index.d.ts +7 -7
- package/dist/campaign/index.js +14 -14
- package/dist/{campaign-CpnsCgfz.js → campaign-BudZ70zo.js} +245 -247
- package/dist/campaign-BudZ70zo.js.map +1 -0
- package/dist/{campaign-evidence-OcUciD-N.js → campaign-evidence-Clrn4hBV.js} +8 -8
- package/dist/campaign-evidence-Clrn4hBV.js.map +1 -0
- package/dist/{canonical-BsZVgBhW.js → canonical-B2RqLofv.js} +2 -2
- package/dist/{canonical-BsZVgBhW.js.map → canonical-B2RqLofv.js.map} +1 -1
- package/dist/{chat-client-DthPOYGd.js → chat-client-l-MVDlDk.js} +2 -2
- package/dist/{chat-client-DthPOYGd.js.map → chat-client-l-MVDlDk.js.map} +1 -1
- package/dist/{chat-json-call-BrKsyspg.js → chat-json-call-puMArmtW.js} +2 -2
- package/dist/{chat-json-call-BrKsyspg.js.map → chat-json-call-puMArmtW.js.map} +1 -1
- package/dist/{claim-BXcZw-jo.js → claim-q4HQhK1G.js} +4 -4
- package/dist/claim-q4HQhK1G.js.map +1 -0
- package/dist/cli.js +9 -9
- package/dist/cli.js.map +1 -1
- package/dist/cluster-bootstrap-qcUWYFl-.js +66 -0
- package/dist/cluster-bootstrap-qcUWYFl-.js.map +1 -0
- package/dist/contract/index.d.ts +11 -11
- package/dist/contract/index.js +1023 -1079
- package/dist/contract/index.js.map +1 -1
- package/dist/{cost-ledger-D2FnJPBF.js → cost-ledger-BP8V4kUQ.js} +835 -816
- package/dist/cost-ledger-BP8V4kUQ.js.map +1 -0
- package/dist/{cost-ledger-CO7UyEcQ.d.ts → cost-ledger-Jk62OBfF.d.ts} +12 -47
- package/dist/cost-ledger-Jk62OBfF.d.ts.map +1 -0
- package/dist/{counterfactual-DtMWvn7D.js → counterfactual-Dn3veueY.js} +2 -2
- package/dist/{counterfactual-DtMWvn7D.js.map → counterfactual-Dn3veueY.js.map} +1 -1
- package/dist/{default-registry-KP4-Tolz.js → default-registry-COhk9g36.js} +744 -759
- package/dist/default-registry-COhk9g36.js.map +1 -0
- package/dist/{default-registry-B4B7GMvI.d.ts → default-registry-DzHiGruW.d.ts} +6 -6
- package/dist/{default-registry-B4B7GMvI.d.ts.map → default-registry-DzHiGruW.d.ts.map} +1 -1
- package/dist/{define-agent-eval-BdfnqXeP.js → define-agent-eval-CNTPzIkp.js} +10 -10
- package/dist/define-agent-eval-CNTPzIkp.js.map +1 -0
- package/dist/{define-agent-eval-DfXvNho5.d.ts → define-agent-eval-WSck0CZJ.d.ts} +8 -8
- package/dist/{define-agent-eval-DfXvNho5.d.ts.map → define-agent-eval-WSck0CZJ.d.ts.map} +1 -1
- package/dist/{descriptive-CnU8Yq29.js → descriptive-DboxPZrG.js} +2 -2
- package/dist/{descriptive-CnU8Yq29.js.map → descriptive-DboxPZrG.js.map} +1 -1
- package/dist/diagnosis/index.d.ts +3 -3
- package/dist/diagnosis/index.js +4 -4
- package/dist/{dspy-rlm-engine-DZfHM7kT.js → dspy-rlm-engine-LRCu61m5.js} +3 -3
- package/dist/{dspy-rlm-engine-DZfHM7kT.js.map → dspy-rlm-engine-LRCu61m5.js.map} +1 -1
- package/dist/{effect-sizes-DiH8MGOH.js → effect-sizes-BhzEpXMc.js} +2 -2
- package/dist/{effect-sizes-DiH8MGOH.js.map → effect-sizes-BhzEpXMc.js.map} +1 -1
- package/dist/{engine-C37HS2kr.d.ts → engine-3A_4jOlI.d.ts} +5 -5
- package/dist/{engine-C37HS2kr.d.ts.map → engine-3A_4jOlI.d.ts.map} +1 -1
- package/dist/{equal-terms-Blx9Zk5I.js → equal-terms-BtdXayCJ.js} +2 -2
- package/dist/{equal-terms-Blx9Zk5I.js.map → equal-terms-BtdXayCJ.js.map} +1 -1
- package/dist/{errors-Dngq5h35.js → errors-DVZiqS7K.js} +6 -2
- package/dist/{errors-Dngq5h35.js.map → errors-DVZiqS7K.js.map} +1 -1
- package/dist/{eval-campaign-4byTtqrf.js → eval-campaign-90jeaCAI.js} +6 -6
- package/dist/{eval-campaign-4byTtqrf.js.map → eval-campaign-90jeaCAI.js.map} +1 -1
- package/dist/evaluation-6Yoi74gM.d.ts +75 -0
- package/dist/evaluation-6Yoi74gM.d.ts.map +1 -0
- package/dist/evaluation.d.ts +2 -74
- package/dist/evaluation.js +1 -1
- package/dist/{exact-types-Dlb73wN4.d.ts → exact-types-ClugMJfI.d.ts} +2 -2
- package/dist/{exact-types-Dlb73wN4.d.ts.map → exact-types-ClugMJfI.d.ts.map} +1 -1
- package/dist/experiment/index.d.ts +404 -3
- package/dist/experiment/index.d.ts.map +1 -1
- package/dist/experiment/index.js +313 -19
- package/dist/experiment/index.js.map +1 -1
- package/dist/{external-optimizer-process-GngofQML.js → external-optimizer-process-BjMGUuds.js} +3 -3
- package/dist/{external-optimizer-process-GngofQML.js.map → external-optimizer-process-BjMGUuds.js.map} +1 -1
- package/dist/{external-optimizer-subprocess-BUxifb8g.js → external-optimizer-subprocess-BqW0hHcI.js} +791 -532
- package/dist/external-optimizer-subprocess-BqW0hHcI.js.map +1 -0
- package/dist/{feedback-trajectory-BLN_6fEs.d.ts → feedback-trajectory-C4EG0nNH.d.ts} +5 -8
- package/dist/feedback-trajectory-C4EG0nNH.d.ts.map +1 -0
- package/dist/fuzz.d.ts +1 -1
- package/dist/fuzz.js +3 -3
- package/dist/hosted/index.js +1 -1
- package/dist/{index-CPJJr98o.d.ts → index-BFRO6chs.d.ts} +3 -2
- package/dist/index-BFRO6chs.d.ts.map +1 -0
- package/dist/{index-Ch9VxCpK.d.ts → index-BO41eGj5.d.ts} +2 -2
- package/dist/{index-Ch9VxCpK.d.ts.map → index-BO41eGj5.d.ts.map} +1 -1
- package/dist/{index-B3WBm953.d.ts → index-CyszSg4O.d.ts} +165 -162
- package/dist/index-CyszSg4O.d.ts.map +1 -0
- package/dist/{index-B7m2uzJL.d.ts → index-DPcngtwt.d.ts} +30 -17
- package/dist/index-DPcngtwt.d.ts.map +1 -0
- package/dist/{index-tYLUvk_w.d.ts → index-DV-jSzxF.d.ts} +9 -9
- package/dist/{index-tYLUvk_w.d.ts.map → index-DV-jSzxF.d.ts.map} +1 -1
- package/dist/index.d.ts +1969 -1871
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +162 -201
- package/dist/index.js.map +1 -1
- package/dist/{integrity-BvnVARVl.js → integrity-BXOsAb3i.js} +2 -2
- package/dist/{integrity-BvnVARVl.js.map → integrity-BXOsAb3i.js.map} +1 -1
- package/dist/{integrity-CCAxGVK6.d.ts → integrity-DAMEDFaC.d.ts} +2 -2
- package/dist/{integrity-CCAxGVK6.d.ts.map → integrity-DAMEDFaC.d.ts.map} +1 -1
- package/dist/{integrity-BV1ZDf42.js → integrity-dLiDe2kD.js} +2 -5
- package/dist/integrity-dLiDe2kD.js.map +1 -0
- package/dist/{internal-CRHwS9iz.js → internal-Epl-YBZW.js} +3 -3
- package/dist/{internal-CRHwS9iz.js.map → internal-Epl-YBZW.js.map} +1 -1
- package/dist/interval-CELpye1n.js +219 -0
- package/dist/interval-CELpye1n.js.map +1 -0
- package/dist/interval-ohuOJurX.d.ts +47 -0
- package/dist/interval-ohuOJurX.d.ts.map +1 -0
- package/dist/{journal-DvKCvjty.js → journal-DfRz9kps.js} +2 -2
- package/dist/{journal-DvKCvjty.js.map → journal-DfRz9kps.js.map} +1 -1
- package/dist/{judge-calibration-N44V04Se.js → judge-calibration-BpCy5XQl.js} +3 -3
- package/dist/{judge-calibration-N44V04Se.js.map → judge-calibration-BpCy5XQl.js.map} +1 -1
- package/dist/{judge-gate-DNcUrRFA.d.ts → judge-gate-CE7CQAgt.d.ts} +3 -3
- package/dist/{judge-gate-DNcUrRFA.d.ts.map → judge-gate-CE7CQAgt.d.ts.map} +1 -1
- package/dist/{judge-gate-B1qYnkpi.js → judge-gate-iY9s4L44.js} +3 -3
- package/dist/judge-gate-iY9s4L44.js.map +1 -0
- package/dist/{kind-factory-AaEhUADH.js → kind-factory-BobI5Jy3.js} +5 -5
- package/dist/{kind-factory-AaEhUADH.js.map → kind-factory-BobI5Jy3.js.map} +1 -1
- package/dist/ledger-core/index.js +3 -3
- package/dist/{ledger-core-B2hahzrt.js → ledger-core-Gq7yp8lP.js} +4 -4
- package/dist/{ledger-core-B2hahzrt.js.map → ledger-core-Gq7yp8lP.js.map} +1 -1
- package/dist/{llm-client-DQveoxSM.js → llm-client-CyBAoYiX.js} +192 -219
- package/dist/llm-client-CyBAoYiX.js.map +1 -0
- package/dist/{llm-judge-Cd5s5Ei6.js → llm-judge-CG12SQJq.js} +499 -921
- package/dist/llm-judge-CG12SQJq.js.map +1 -0
- package/dist/matrix/index.d.ts +2 -2
- package/dist/matrix/index.js +1 -1
- package/dist/{matrix-DXVAJMLD.d.ts → matrix-DSrSxjjy.d.ts} +4 -4
- package/dist/{matrix-DXVAJMLD.d.ts.map → matrix-DSrSxjjy.d.ts.map} +1 -1
- package/dist/{matrix-_BV9-Lk5.js → matrix-Dm0BQW7U.js} +7 -11
- package/dist/matrix-Dm0BQW7U.js.map +1 -0
- package/dist/{paired-tests-jbwPdSz5.js → mean-DHoMiudD.js} +11 -5
- package/dist/mean-DHoMiudD.js.map +1 -0
- package/dist/meta-eval/index.d.ts +3 -3
- package/dist/meta-eval/index.js +9 -70
- package/dist/meta-eval/index.js.map +1 -1
- package/dist/mint-DNU8QPG4.d.ts +81 -0
- package/dist/mint-DNU8QPG4.d.ts.map +1 -0
- package/dist/{mint-Csor1BLJ.js → mint-QaD5cA0u.js} +3 -3
- package/dist/{mint-Csor1BLJ.js.map → mint-QaD5cA0u.js.map} +1 -1
- package/dist/{multiplicity-D9cjmStq.js → multiplicity-DQUFcbW4.js} +2 -2
- package/dist/{multiplicity-D9cjmStq.js.map → multiplicity-DQUFcbW4.js.map} +1 -1
- package/dist/multishot/golden/index.d.ts +1 -1
- package/dist/multishot/golden/index.d.ts.map +1 -1
- package/dist/multishot/golden/index.js +3 -6
- package/dist/multishot/golden/index.js.map +1 -1
- package/dist/multishot/index.d.ts +2 -2
- package/dist/multishot/index.js +1 -1
- package/dist/nonnegative-number-DvdMxg_f.js +9 -0
- package/dist/nonnegative-number-DvdMxg_f.js.map +1 -0
- package/dist/openapi.json +1 -1
- package/dist/{otel-spans-C8YIJWy1.js → otel-spans-B9tUXRHF.js} +3 -3
- package/dist/{otel-spans-C8YIJWy1.js.map → otel-spans-B9tUXRHF.js.map} +1 -1
- package/dist/{paired-arms-DzKn0TfY.js → paired-arms-CwMGJsrS.js} +5 -5
- package/dist/{paired-arms-DzKn0TfY.js.map → paired-arms-CwMGJsrS.js.map} +1 -1
- package/dist/{paired-binary-Q36bhn2R.js → paired-binary-CvpFHfKZ.js} +2 -2
- package/dist/{paired-binary-Q36bhn2R.js.map → paired-binary-CvpFHfKZ.js.map} +1 -1
- package/dist/{paired-promotion-decision-BN6IQTiu.js → paired-promotion-decision-DsAPYGCm.js} +3 -3
- package/dist/{paired-promotion-decision-BN6IQTiu.js.map → paired-promotion-decision-DsAPYGCm.js.map} +1 -1
- package/dist/{search-kernel-BztlERLv.js → pareto-Cm6ndrWN.js} +883 -861
- package/dist/pareto-Cm6ndrWN.js.map +1 -0
- package/dist/pipelines/index.d.ts +2 -2
- package/dist/pipelines/index.js +3 -3
- package/dist/{power-and-mde-fK5Qocwo.js → power-and-mde-Hj2ubb4B.js} +2 -2
- package/dist/{power-and-mde-fK5Qocwo.js.map → power-and-mde-Hj2ubb4B.js.map} +1 -1
- package/dist/predicate-FdKmElA_.js +38 -0
- package/dist/predicate-FdKmElA_.js.map +1 -0
- package/dist/{prime-protocol-DcAK9pC8.js → prime-protocol-CHKgA3a6.js} +2 -2
- package/dist/{prime-protocol-DcAK9pC8.js.map → prime-protocol-CHKgA3a6.js.map} +1 -1
- package/dist/{prime-protocol-BHia9vDz.d.ts → prime-protocol-HiB9HX7E.d.ts} +3 -3
- package/dist/{prime-protocol-BHia9vDz.d.ts.map → prime-protocol-HiB9HX7E.d.ts.map} +1 -1
- package/dist/{produced-state-BGp4BX8t.js → produced-state-BsDmnwxc.js} +8 -8
- package/dist/{produced-state-BGp4BX8t.js.map → produced-state-BsDmnwxc.js.map} +1 -1
- package/dist/profile-cell.js +1 -1
- package/dist/{release-confidence-BK2QCB5M.d.ts → promotion-gate-BawrdPYr.d.ts} +102 -102
- package/dist/promotion-gate-BawrdPYr.d.ts.map +1 -0
- package/dist/{promotion-policy-CWW35UWq.js → promotion-policy-KO57gbyV.js} +4 -4
- package/dist/{promotion-policy-CWW35UWq.js.map → promotion-policy-KO57gbyV.js.map} +1 -1
- package/dist/{proposal-findings-CXblsskH.js → proposal-findings-CY1xKn_a.js} +2 -36
- package/dist/proposal-findings-CY1xKn_a.js.map +1 -0
- package/dist/{query-B1D1qp2Z.js → query-BUCZCK7F.js} +3 -3
- package/dist/{query-B1D1qp2Z.js.map → query-BUCZCK7F.js.map} +1 -1
- package/dist/{random-Dn5fPWkt.js → random-ByUSnV9w.js} +2 -2
- package/dist/{random-Dn5fPWkt.js.map → random-ByUSnV9w.js.map} +1 -1
- package/dist/{raw-provider-sink-rB2DYxr6.js → raw-provider-sink-DoHz4JNG.js} +2 -2
- package/dist/{raw-provider-sink-rB2DYxr6.js.map → raw-provider-sink-DoHz4JNG.js.map} +1 -1
- package/dist/{redact-Dk1ZdJEm.js → redact-B5xXKqQ3.js} +97 -98
- package/dist/redact-B5xXKqQ3.js.map +1 -0
- package/dist/{redact-Cveoq6fJ.d.ts → redact-mtCCcT8z.d.ts} +4 -20
- package/dist/redact-mtCCcT8z.d.ts.map +1 -0
- package/dist/{registry-CMYIaDgS.d.ts → registry-D7_hm2fK.d.ts} +11 -13
- package/dist/registry-D7_hm2fK.d.ts.map +1 -0
- package/dist/{release-confidence-Dbe9AS_X.js → release-confidence-CpuP65S5.js} +5 -5
- package/dist/{release-confidence-Dbe9AS_X.js.map → release-confidence-CpuP65S5.js.map} +1 -1
- package/dist/{report-command-CtIIsQKP.js → report-command-SC9nqb4M.js} +128 -177
- package/dist/report-command-SC9nqb4M.js.map +1 -0
- package/dist/reporting-html-Kvlc8oMt.js +100 -0
- package/dist/reporting-html-Kvlc8oMt.js.map +1 -0
- package/dist/reporting.d.ts +3 -3
- package/dist/reporting.js +6 -6
- package/dist/{researcher-f6mZhh58.d.ts → researcher-CEcfku-T.d.ts} +5 -5
- package/dist/{researcher-f6mZhh58.d.ts.map → researcher-CEcfku-T.d.ts.map} +1 -1
- package/dist/reward-CpCmAM8L.d.ts +78 -0
- package/dist/reward-CpCmAM8L.d.ts.map +1 -0
- package/dist/{reward-hacking-BFcQgkux.js → reward-hacking-E0d-WVcP.js} +2 -2
- package/dist/{reward-hacking-BFcQgkux.js.map → reward-hacking-E0d-WVcP.js.map} +1 -1
- package/dist/{reward-hacking-DHA7c1l8.d.ts → reward-hacking-RVdZ6Kkt.d.ts} +2 -2
- package/dist/{reward-hacking-DHA7c1l8.d.ts.map → reward-hacking-RVdZ6Kkt.d.ts.map} +1 -1
- package/dist/rl.d.ts +8 -8
- package/dist/rl.js +14 -14
- package/dist/rollout/index.d.ts +3 -2
- package/dist/rollout/index.js +2 -2
- package/dist/{rollout-D9bKKBnZ.js → rollout-DZV1t2Wg.js} +2 -2
- package/dist/{rollout-D9bKKBnZ.js.map → rollout-DZV1t2Wg.js.map} +1 -1
- package/dist/round-decimal-COrKglMh.js +10 -0
- package/dist/round-decimal-COrKglMh.js.map +1 -0
- package/dist/{rubric-predictive-validity-2SgHxoa5.d.ts → rubric-predictive-validity-C03EC7ZE.d.ts} +2 -2
- package/dist/{rubric-predictive-validity-2SgHxoa5.d.ts.map → rubric-predictive-validity-C03EC7ZE.d.ts.map} +1 -1
- package/dist/{rubric-predictive-validity-BsgkBfT0.js → rubric-predictive-validity-DaFW70y9.js} +3 -3
- package/dist/{rubric-predictive-validity-BsgkBfT0.js.map → rubric-predictive-validity-DaFW70y9.js.map} +1 -1
- package/dist/{run-record-DlTZ_lqe.js → run-record-Boc5IUTp.js} +4 -4
- package/dist/{run-record-DlTZ_lqe.js.map → run-record-Boc5IUTp.js.map} +1 -1
- package/dist/{run-record-D1Hw-Jml.d.ts → run-record-C1E24G2A.d.ts} +2 -2
- package/dist/{run-record-D1Hw-Jml.d.ts.map → run-record-C1E24G2A.d.ts.map} +1 -1
- package/dist/{run-record-ES07wfz9.js → run-record-C5e7FjhJ.js} +3 -5
- package/dist/run-record-C5e7FjhJ.js.map +1 -0
- package/dist/search/index.d.ts +46 -32
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/index.js +3 -3
- package/dist/{search-kernel-BqyBZ9Wm.d.ts → search-kernel-DyNEa6IU.d.ts} +14 -10
- package/dist/search-kernel-DyNEa6IU.d.ts.map +1 -0
- package/dist/{search-ledger-d7V8o9Lk.js → search-ledger-CVUGLDZp.js} +189 -199
- package/dist/search-ledger-CVUGLDZp.js.map +1 -0
- package/dist/{search-ledger-file-BqOo-bVo.js → search-ledger-file-DDQUgvCg.js} +4 -4
- package/dist/{search-ledger-file-BqOo-bVo.js.map → search-ledger-file-DDQUgvCg.js.map} +1 -1
- package/dist/search-ledger-types-p2xKfiDJ.d.ts.map +1 -1
- package/dist/{search-shipper-er4pK5_Y.js → search-shipper-BOSD46qv.js} +3 -3
- package/dist/{search-shipper-er4pK5_Y.js.map → search-shipper-BOSD46qv.js.map} +1 -1
- package/dist/{search-summary-CBvz3u_S.js → search-summary-BQCSWf1g.js} +5 -5
- package/dist/{search-summary-CBvz3u_S.js.map → search-summary-BQCSWf1g.js.map} +1 -1
- package/dist/{semantic-concept-judge-BPqbwIVs.js → semantic-concept-judge-BQF8te0T.js} +12 -14
- package/dist/semantic-concept-judge-BQF8te0T.js.map +1 -0
- package/dist/{sequential-D-1PPCmM.js → sequential-Bf_pbE50.js} +5 -5
- package/dist/{sequential-D-1PPCmM.js.map → sequential-Bf_pbE50.js.map} +1 -1
- package/dist/{sequential-eprocess-D1jKoihe.js → sequential-eprocess-DM_qENCl.js} +2 -2
- package/dist/{sequential-eprocess-D1jKoihe.js.map → sequential-eprocess-DM_qENCl.js.map} +1 -1
- package/dist/{server-DbcC7xMl.js → server-e9oWO_bN.js} +4 -4
- package/dist/{server-DbcC7xMl.js.map → server-e9oWO_bN.js.map} +1 -1
- package/dist/{single-run-lock-fVu3MZWH.js → single-run-lock-CV9Eyd_q.js} +2 -2
- package/dist/{single-run-lock-fVu3MZWH.js.map → single-run-lock-CV9Eyd_q.js.map} +1 -1
- package/dist/{skillopt-optimization-method-Dcepr6QL.js → skillopt-optimization-method-BiwA8nfX.js} +427 -12
- package/dist/skillopt-optimization-method-BiwA8nfX.js.map +1 -0
- package/dist/{spans-D9_ehFuk.d.ts → spans-BHAUXMGN.d.ts} +2 -2
- package/dist/{spans-D9_ehFuk.d.ts.map → spans-BHAUXMGN.d.ts.map} +1 -1
- package/dist/{statistical-heldout-1Gbmex7v.js → statistical-heldout-42NlCNDe.js} +3 -3
- package/dist/{statistical-heldout-1Gbmex7v.js.map → statistical-heldout-42NlCNDe.js.map} +1 -1
- package/dist/{statistical-heldout-CJTj2EoS.d.ts → statistical-heldout-CYpGaoDH.d.ts} +3 -3
- package/dist/{statistical-heldout-CJTj2EoS.d.ts.map → statistical-heldout-CYpGaoDH.d.ts.map} +1 -1
- package/dist/{store-otlp-DWVhUgEj.js → store-otlp-DJ9dtA5x.js} +135 -132
- package/dist/store-otlp-DJ9dtA5x.js.map +1 -0
- package/dist/{store-tool-spans-BNICrhsb.js → store-tool-spans-CIX5arAG.js} +7 -7
- package/dist/{store-tool-spans-BNICrhsb.js.map → store-tool-spans-CIX5arAG.js.map} +1 -1
- package/dist/{store-tool-spans-BNzls3OD.d.ts → store-tool-spans-DdCSPa7C.d.ts} +162 -161
- package/dist/store-tool-spans-DdCSPa7C.d.ts.map +1 -0
- package/dist/storyboard/index.d.ts.map +1 -1
- package/dist/storyboard/index.js +20 -3
- package/dist/storyboard/index.js.map +1 -1
- package/dist/{student-t-BQeKJx2N.js → student-t-DVPW7CdL.js} +2 -2
- package/dist/{student-t-BQeKJx2N.js.map → student-t-DVPW7CdL.js.map} +1 -1
- package/dist/{summary-report-DtdRucM0.js → summary-report-V_JACR4Y.js} +526 -614
- package/dist/summary-report-V_JACR4Y.js.map +1 -0
- package/dist/{summary-report-C-CtItCN.d.ts → summary-report-bdFDXq0b.d.ts} +10 -5
- package/dist/summary-report-bdFDXq0b.d.ts.map +1 -0
- package/dist/supervisor-run/index.d.ts +154 -150
- package/dist/supervisor-run/index.d.ts.map +1 -1
- package/dist/supervisor-run/index.js +65 -3
- package/dist/supervisor-run/index.js.map +1 -1
- package/dist/systemone-BomhHr2c.d.ts +135 -0
- package/dist/systemone-BomhHr2c.d.ts.map +1 -0
- package/dist/systemone-protocol.js +1 -1
- package/dist/{systemone-review-C4dZgrgN.d.ts → systemone-review-CUVcQJu6.d.ts} +2 -2
- package/dist/{systemone-review-C4dZgrgN.d.ts.map → systemone-review-CUVcQJu6.d.ts.map} +1 -1
- package/dist/{systemone-review-DTClwgmE.js → systemone-review-D7sXwsqq.js} +3 -3
- package/dist/{systemone-review-DTClwgmE.js.map → systemone-review-D7sXwsqq.js.map} +1 -1
- package/dist/systemone.d.ts +4 -134
- package/dist/systemone.js +4 -4
- package/dist/{task-failure-attributes-DngaLdE4.js → task-failure-attributes-hEmASjix.js} +2 -2
- package/dist/{task-failure-attributes-DngaLdE4.js.map → task-failure-attributes-hEmASjix.js.map} +1 -1
- package/dist/{terminal-record-BHocwFw1.js → terminal-record-DZyQZ3pz.js} +14 -10
- package/dist/terminal-record-DZyQZ3pz.js.map +1 -0
- package/dist/{tool-groups-BKRrtqy4.d.ts → tool-groups-C3NEcdCM.d.ts} +3 -3
- package/dist/tool-groups-C3NEcdCM.d.ts.map +1 -0
- package/dist/{tool-waste-Wi4g6Ekb.d.ts → tool-waste-BKgvd-TP.d.ts} +30 -30
- package/dist/tool-waste-BKgvd-TP.d.ts.map +1 -0
- package/dist/{tool-waste-BYt5rdt8.js → tool-waste-BlesqTqW.js} +5 -158
- package/dist/tool-waste-BlesqTqW.js.map +1 -0
- package/dist/{trace-questions-CLx8vt6t.d.ts → trace-questions-CM2CAocU.d.ts} +4 -4
- package/dist/{trace-questions-CLx8vt6t.d.ts.map → trace-questions-CM2CAocU.d.ts.map} +1 -1
- package/dist/trace-repair/index.d.ts +3 -3
- package/dist/trace-repair/index.d.ts.map +1 -1
- package/dist/trace-repair/index.js +7 -13
- package/dist/trace-repair/index.js.map +1 -1
- package/dist/traces.d.ts +76 -58
- package/dist/traces.d.ts.map +1 -1
- package/dist/traces.js +9 -9
- package/dist/trajectory-replay/index.js +3 -3
- package/dist/{tree-rXLW3M_4.js → tree-C1XYeXvy.js} +2277 -2339
- package/dist/tree-C1XYeXvy.js.map +1 -0
- package/dist/{types-DjOMwGY_.d.ts → types-BqkVmHfv.d.ts} +7 -1
- package/dist/types-BqkVmHfv.d.ts.map +1 -0
- package/dist/{types-DBZ7keha.d.ts → types-C02qtnG8.d.ts} +4 -46
- package/dist/types-C02qtnG8.d.ts.map +1 -0
- package/dist/{types-DHb5TI36.d.ts → types-C1tnkEgM.d.ts} +347 -6
- package/dist/types-C1tnkEgM.d.ts.map +1 -0
- package/dist/{types-DinHtRJp.d.ts → types-Cbe2fWBa.d.ts} +3 -3
- package/dist/{types-DinHtRJp.d.ts.map → types-Cbe2fWBa.d.ts.map} +1 -1
- package/dist/{types-CGEmVYOk.d.ts → types-Cq8mSbq8.d.ts} +78 -72
- package/dist/types-Cq8mSbq8.d.ts.map +1 -0
- package/dist/{types-CW5b90JH.js → types-IXD2HJzu.js} +16 -3
- package/dist/types-IXD2HJzu.js.map +1 -0
- package/dist/{verdict-DhPoXApk.js → verdict-Dl0tiT1X.js} +2 -2
- package/dist/{verdict-DhPoXApk.js.map → verdict-Dl0tiT1X.js.map} +1 -1
- package/dist/{verdict-cache-BQEsVy9n.js → verdict-cache-Bm8EKL2s.js} +2 -2
- package/dist/{verdict-cache-BQEsVy9n.js.map → verdict-cache-Bm8EKL2s.js.map} +1 -1
- package/dist/wire/index.d.ts +3 -3
- package/dist/wire/index.js +1 -1
- package/docs/concepts.md +1 -0
- package/docs/design/mlbenchmarks-book-review.md +1 -1
- package/docs/design/mlbenchmarks-review/probes.mts +23 -31
- package/docs/experiment.md +1 -1
- package/docs/finding-layers.md +69 -0
- package/package.json +1 -1
- package/dist/analyze-runs-3xpby3p2.js.map +0 -1
- package/dist/analyze-runs-BhFLOztS.d.ts.map +0 -1
- package/dist/ast-DJ6Bc7ab.js +0 -558
- package/dist/ast-DJ6Bc7ab.js.map +0 -1
- package/dist/ast-hI-vjW6J.d.ts +0 -457
- package/dist/ast-hI-vjW6J.d.ts.map +0 -1
- package/dist/benchmark-command-CgpGi7vY.js.map +0 -1
- package/dist/campaign-CpnsCgfz.js.map +0 -1
- package/dist/campaign-evidence-OcUciD-N.js.map +0 -1
- package/dist/claim-BXcZw-jo.js.map +0 -1
- package/dist/cost-ledger-CO7UyEcQ.d.ts.map +0 -1
- package/dist/cost-ledger-D2FnJPBF.js.map +0 -1
- package/dist/default-registry-KP4-Tolz.js.map +0 -1
- package/dist/define-agent-eval-BdfnqXeP.js.map +0 -1
- package/dist/evaluation.d.ts.map +0 -1
- package/dist/external-optimizer-subprocess-BUxifb8g.js.map +0 -1
- package/dist/feedback-trajectory-BLN_6fEs.d.ts.map +0 -1
- package/dist/index-B3WBm953.d.ts.map +0 -1
- package/dist/index-B7m2uzJL.d.ts.map +0 -1
- package/dist/index-CPJJr98o.d.ts.map +0 -1
- package/dist/integrity-BV1ZDf42.js.map +0 -1
- package/dist/judge-gate-B1qYnkpi.js.map +0 -1
- package/dist/llm-client-DQveoxSM.js.map +0 -1
- package/dist/llm-judge-Cd5s5Ei6.js.map +0 -1
- package/dist/matrix-_BV9-Lk5.js.map +0 -1
- package/dist/mint-DCGoBYhB.d.ts +0 -155
- package/dist/mint-DCGoBYhB.d.ts.map +0 -1
- package/dist/paired-tests-jbwPdSz5.js.map +0 -1
- package/dist/proposal-findings-CXblsskH.js.map +0 -1
- package/dist/redact-Cveoq6fJ.d.ts.map +0 -1
- package/dist/redact-Dk1ZdJEm.js.map +0 -1
- package/dist/registry-CMYIaDgS.d.ts.map +0 -1
- package/dist/release-confidence-BK2QCB5M.d.ts.map +0 -1
- package/dist/report-command-CtIIsQKP.js.map +0 -1
- package/dist/run-record-ES07wfz9.js.map +0 -1
- package/dist/search-kernel-BqyBZ9Wm.d.ts.map +0 -1
- package/dist/search-kernel-BztlERLv.js.map +0 -1
- package/dist/search-ledger-d7V8o9Lk.js.map +0 -1
- package/dist/semantic-concept-judge-BPqbwIVs.js.map +0 -1
- package/dist/skillopt-optimization-method-Dcepr6QL.js.map +0 -1
- package/dist/store-otlp-DWVhUgEj.js.map +0 -1
- package/dist/store-tool-spans-BNzls3OD.d.ts.map +0 -1
- package/dist/summary-report-C-CtItCN.d.ts.map +0 -1
- package/dist/summary-report-DtdRucM0.js.map +0 -1
- package/dist/systemone.d.ts.map +0 -1
- package/dist/terminal-record-BHocwFw1.js.map +0 -1
- package/dist/tool-groups-BKRrtqy4.d.ts.map +0 -1
- package/dist/tool-waste-BYt5rdt8.js.map +0 -1
- package/dist/tool-waste-Wi4g6Ekb.d.ts.map +0 -1
- package/dist/tree-rXLW3M_4.js.map +0 -1
- package/dist/types-CGEmVYOk.d.ts.map +0 -1
- package/dist/types-CW5b90JH.js.map +0 -1
- package/dist/types-DBZ7keha.d.ts.map +0 -1
- package/dist/types-DHb5TI36.d.ts.map +0 -1
- package/dist/types-DjOMwGY_.d.ts.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { o as FailureClass } from "./schema-2g7trUwH.js";
|
|
2
|
-
import { a as RunRecord, c as RunSplitTag } from "./run-record-
|
|
2
|
+
import { a as RunRecord, c as RunSplitTag } from "./run-record-C1E24G2A.js";
|
|
3
3
|
import { i as DatasetSplit, n as DatasetManifest, r as DatasetScenario } from "./dataset-DQqhOCPt.js";
|
|
4
|
-
import { b as GateDecision } from "./summary-report-
|
|
4
|
+
import { b as GateDecision } from "./summary-report-bdFDXq0b.js";
|
|
5
5
|
//#region src/statistics/rank-tests.d.ts
|
|
6
6
|
/** How a rank test's p-value was actually computed. */
|
|
7
7
|
type RankTestMethod = 'exact' | 'permutation' | 'asymptotic';
|
|
@@ -72,104 +72,6 @@ interface WilcoxonSignedRankResult {
|
|
|
72
72
|
*/
|
|
73
73
|
declare function wilcoxonSignedRank(before: number[], after: number[], opts?: RankTestOptions): WilcoxonSignedRankResult;
|
|
74
74
|
//#endregion
|
|
75
|
-
//#region src/promotion-gate.d.ts
|
|
76
|
-
/**
|
|
77
|
-
* Bootstrap-CI promotion gate.
|
|
78
|
-
*
|
|
79
|
-
* In any iterative-improvement loop (GEPA, prompt evolution, dataset
|
|
80
|
-
* curation), the question is "did this generation actually improve, or are
|
|
81
|
-
* we celebrating noise?". With small N and noisy outcomes, point-estimate
|
|
82
|
-
* deltas lie. Bootstrap confidence intervals tell the operator whether the
|
|
83
|
-
* delta is real before code or prompts get promoted.
|
|
84
|
-
*
|
|
85
|
-
* This module is pure functions — no I/O, no model calls. Easy to unit-test
|
|
86
|
-
* and to compose into any verdict gate.
|
|
87
|
-
*
|
|
88
|
-
* Default gate:
|
|
89
|
-
* - Bootstrap mean baseline vs candidate (1k resamples).
|
|
90
|
-
* - Compute the delta distribution; pass if the lower CI bound > 0.
|
|
91
|
-
* - Tunable confidence (default 95%) and resample count.
|
|
92
|
-
*
|
|
93
|
-
* Verdict semantics intentionally match the existing `experiments.jsonl`
|
|
94
|
-
* vocabulary:
|
|
95
|
-
* - ADVANCE: candidate's CI lower bound > baseline mean (real win)
|
|
96
|
-
* - KEEP: overlap, but candidate point estimate >= baseline (neutral)
|
|
97
|
-
* - REVERT: candidate's CI upper bound < baseline mean (real regression)
|
|
98
|
-
* - INCONCLUSIVE: not enough samples or CI straddles zero with no signal
|
|
99
|
-
*/
|
|
100
|
-
type Verdict = 'ADVANCE' | 'KEEP' | 'REVERT' | 'INCONCLUSIVE';
|
|
101
|
-
interface BootstrapResult {
|
|
102
|
-
baselineMean: number;
|
|
103
|
-
candidateMean: number;
|
|
104
|
-
/** candidateMean - baselineMean, point estimate. */
|
|
105
|
-
delta: number;
|
|
106
|
-
/** Lower bound of the (1 - alpha) CI on the delta. */
|
|
107
|
-
ciLower: number;
|
|
108
|
-
/** Upper bound of the (1 - alpha) CI on the delta. */
|
|
109
|
-
ciUpper: number;
|
|
110
|
-
/** Number of bootstrap resamples used. */
|
|
111
|
-
iterations: number;
|
|
112
|
-
alpha: number;
|
|
113
|
-
verdict: Verdict;
|
|
114
|
-
}
|
|
115
|
-
interface BootstrapOptions {
|
|
116
|
-
/** Confidence level alpha (default 0.05 → 95% CI). */
|
|
117
|
-
alpha?: number;
|
|
118
|
-
/** Number of resamples (default 1000). */
|
|
119
|
-
iterations?: number;
|
|
120
|
-
/**
|
|
121
|
-
* Minimum total samples (baseline + candidate) below which we always
|
|
122
|
-
* return INCONCLUSIVE — bootstrap with too few samples is meaningless.
|
|
123
|
-
* Default 6 (combined).
|
|
124
|
-
*/
|
|
125
|
-
minTotalSamples?: number;
|
|
126
|
-
/** RNG seed for reproducibility. Absent, the seed is derived from the
|
|
127
|
-
* compared arms, so the same inputs reproduce the same verdict. */
|
|
128
|
-
seed?: number;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Compute the bootstrap CI on (candidateMean - baselineMean) and a verdict.
|
|
132
|
-
*
|
|
133
|
-
* Uses simple percentile bootstrap on the difference of resampled means.
|
|
134
|
-
* That's the standard non-parametric primitive — no distributional
|
|
135
|
-
* assumptions, robust to skew, easy to reason about.
|
|
136
|
-
*/
|
|
137
|
-
declare function bootstrapCi(baseline: number[], candidate: number[], options?: BootstrapOptions): BootstrapResult;
|
|
138
|
-
/**
|
|
139
|
-
* Judge-replay promotion gate.
|
|
140
|
-
*
|
|
141
|
-
* The cheap inner-loop judge that drives an evolution run is by definition
|
|
142
|
-
* fast and noisy. When you're about to promote a winning variant to the
|
|
143
|
-
* canonical default, you want a STRONGER judge (a more expensive model, a
|
|
144
|
-
* human grader, a separately-trained reward model) to confirm the win
|
|
145
|
-
* generalises beyond the inner loop.
|
|
146
|
-
*
|
|
147
|
-
* This helper takes raw winner + baseline outputs, scores both through the
|
|
148
|
-
* stronger judge, and applies `bootstrapCi`. ADVANCE means the stronger
|
|
149
|
-
* judge agrees the winner is real with the configured confidence. Doesn't
|
|
150
|
-
* matter what shape your "output" is — pass a string, an object, anything
|
|
151
|
-
* the judge can read.
|
|
152
|
-
*/
|
|
153
|
-
interface JudgeReplayGateArgs<TOutput> {
|
|
154
|
-
baselineOutputs: TOutput[];
|
|
155
|
-
candidateOutputs: TOutput[];
|
|
156
|
-
/** Stronger judge — async to allow LLM calls. Return a 0..N scalar score. */
|
|
157
|
-
judge: (output: TOutput) => Promise<number> | number;
|
|
158
|
-
alpha?: number;
|
|
159
|
-
iterations?: number;
|
|
160
|
-
/** RNG seed for reproducibility. */
|
|
161
|
-
seed?: number;
|
|
162
|
-
/** Maximum concurrent judge calls. Default 4. */
|
|
163
|
-
judgeConcurrency?: number;
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* Confirm a candidate's win with a stronger judge: score baseline and candidate outputs independently, then bootstrap a CI to verify the lift generalises beyond the inner loop.
|
|
167
|
-
*/
|
|
168
|
-
declare function judgeReplayGate<TOutput>(args: JudgeReplayGateArgs<TOutput>): Promise<BootstrapResult & {
|
|
169
|
-
baselineSamples: number;
|
|
170
|
-
candidateSamples: number;
|
|
171
|
-
}>;
|
|
172
|
-
//#endregion
|
|
173
75
|
//#region src/release-confidence.d.ts
|
|
174
76
|
/** Severity of an actionable finding attached to a run/trace. */
|
|
175
77
|
type AsiSeverity = 'info' | 'warning' | 'error' | 'critical';
|
|
@@ -301,5 +203,103 @@ interface ReleaseConfidenceScorecard {
|
|
|
301
203
|
declare function evaluateReleaseConfidence(input: ReleaseConfidenceInput): ReleaseConfidenceScorecard;
|
|
302
204
|
declare function assertReleaseConfidence(input: ReleaseConfidenceInput): ReleaseConfidenceScorecard;
|
|
303
205
|
//#endregion
|
|
304
|
-
|
|
305
|
-
|
|
206
|
+
//#region src/promotion-gate.d.ts
|
|
207
|
+
/**
|
|
208
|
+
* Bootstrap-CI promotion gate.
|
|
209
|
+
*
|
|
210
|
+
* In any iterative-improvement loop (GEPA, prompt evolution, dataset
|
|
211
|
+
* curation), the question is "did this generation actually improve, or are
|
|
212
|
+
* we celebrating noise?". With small N and noisy outcomes, point-estimate
|
|
213
|
+
* deltas lie. Bootstrap confidence intervals tell the operator whether the
|
|
214
|
+
* delta is real before code or prompts get promoted.
|
|
215
|
+
*
|
|
216
|
+
* This module is pure functions — no I/O, no model calls. Easy to unit-test
|
|
217
|
+
* and to compose into any verdict gate.
|
|
218
|
+
*
|
|
219
|
+
* Default gate:
|
|
220
|
+
* - Bootstrap mean baseline vs candidate (1k resamples).
|
|
221
|
+
* - Compute the delta distribution; pass if the lower CI bound > 0.
|
|
222
|
+
* - Tunable confidence (default 95%) and resample count.
|
|
223
|
+
*
|
|
224
|
+
* Verdict semantics intentionally match the existing `experiments.jsonl`
|
|
225
|
+
* vocabulary:
|
|
226
|
+
* - ADVANCE: candidate's CI lower bound > baseline mean (real win)
|
|
227
|
+
* - KEEP: overlap, but candidate point estimate >= baseline (neutral)
|
|
228
|
+
* - REVERT: candidate's CI upper bound < baseline mean (real regression)
|
|
229
|
+
* - INCONCLUSIVE: not enough samples or CI straddles zero with no signal
|
|
230
|
+
*/
|
|
231
|
+
type Verdict = 'ADVANCE' | 'KEEP' | 'REVERT' | 'INCONCLUSIVE';
|
|
232
|
+
interface BootstrapResult {
|
|
233
|
+
baselineMean: number;
|
|
234
|
+
candidateMean: number;
|
|
235
|
+
/** candidateMean - baselineMean, point estimate. */
|
|
236
|
+
delta: number;
|
|
237
|
+
/** Lower bound of the (1 - alpha) CI on the delta. */
|
|
238
|
+
ciLower: number;
|
|
239
|
+
/** Upper bound of the (1 - alpha) CI on the delta. */
|
|
240
|
+
ciUpper: number;
|
|
241
|
+
/** Number of bootstrap resamples used. */
|
|
242
|
+
iterations: number;
|
|
243
|
+
alpha: number;
|
|
244
|
+
verdict: Verdict;
|
|
245
|
+
}
|
|
246
|
+
interface BootstrapOptions {
|
|
247
|
+
/** Confidence level alpha (default 0.05 → 95% CI). */
|
|
248
|
+
alpha?: number;
|
|
249
|
+
/** Number of resamples (default 1000). */
|
|
250
|
+
iterations?: number;
|
|
251
|
+
/**
|
|
252
|
+
* Minimum total samples (baseline + candidate) below which we always
|
|
253
|
+
* return INCONCLUSIVE — bootstrap with too few samples is meaningless.
|
|
254
|
+
* Default 6 (combined).
|
|
255
|
+
*/
|
|
256
|
+
minTotalSamples?: number;
|
|
257
|
+
/** RNG seed for reproducibility. Absent, the seed is derived from the
|
|
258
|
+
* compared arms, so the same inputs reproduce the same verdict. */
|
|
259
|
+
seed?: number;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Compute the bootstrap CI on (candidateMean - baselineMean) and a verdict.
|
|
263
|
+
*
|
|
264
|
+
* Uses simple percentile bootstrap on the difference of resampled means.
|
|
265
|
+
* That's the standard non-parametric primitive — no distributional
|
|
266
|
+
* assumptions, robust to skew, easy to reason about.
|
|
267
|
+
*/
|
|
268
|
+
declare function bootstrapCi(baseline: number[], candidate: number[], options?: BootstrapOptions): BootstrapResult;
|
|
269
|
+
/**
|
|
270
|
+
* Judge-replay promotion gate.
|
|
271
|
+
*
|
|
272
|
+
* The cheap inner-loop judge that drives an evolution run is by definition
|
|
273
|
+
* fast and noisy. When you're about to promote a winning variant to the
|
|
274
|
+
* canonical default, you want a STRONGER judge (a more expensive model, a
|
|
275
|
+
* human grader, a separately-trained reward model) to confirm the win
|
|
276
|
+
* generalises beyond the inner loop.
|
|
277
|
+
*
|
|
278
|
+
* This helper takes raw winner + baseline outputs, scores both through the
|
|
279
|
+
* stronger judge, and applies `bootstrapCi`. ADVANCE means the stronger
|
|
280
|
+
* judge agrees the winner is real with the configured confidence. Doesn't
|
|
281
|
+
* matter what shape your "output" is — pass a string, an object, anything
|
|
282
|
+
* the judge can read.
|
|
283
|
+
*/
|
|
284
|
+
interface JudgeReplayGateArgs<TOutput> {
|
|
285
|
+
baselineOutputs: TOutput[];
|
|
286
|
+
candidateOutputs: TOutput[];
|
|
287
|
+
/** Stronger judge — async to allow LLM calls. Return a 0..N scalar score. */
|
|
288
|
+
judge: (output: TOutput) => Promise<number> | number;
|
|
289
|
+
alpha?: number;
|
|
290
|
+
iterations?: number;
|
|
291
|
+
/** RNG seed for reproducibility. */
|
|
292
|
+
seed?: number;
|
|
293
|
+
/** Maximum concurrent judge calls. Default 4. */
|
|
294
|
+
judgeConcurrency?: number;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Confirm a candidate's win with a stronger judge: score baseline and candidate outputs independently, then bootstrap a CI to verify the lift generalises beyond the inner loop.
|
|
298
|
+
*/
|
|
299
|
+
declare function judgeReplayGate<TOutput>(args: JudgeReplayGateArgs<TOutput>): Promise<BootstrapResult & {
|
|
300
|
+
baselineSamples: number;
|
|
301
|
+
candidateSamples: number;
|
|
302
|
+
}>;
|
|
303
|
+
//#endregion
|
|
304
|
+
export { WilcoxonSignedRankResult as C, RankTestOptions as S, wilcoxonSignedRank as T, assertReleaseConfidence as _, bootstrapCi as a, RankTestMethod as b, ReleaseConfidenceAxis as c, ReleaseConfidenceIssue as d, ReleaseConfidenceMetrics as f, ReleaseTraceEvidence as g, ReleaseConfidenceThresholds as h, Verdict as i, ReleaseConfidenceAxisName as l, ReleaseConfidenceStatus as m, BootstrapResult as n, judgeReplayGate as o, ReleaseConfidenceScorecard as p, JudgeReplayGateArgs as r, ActionableSideInfo as s, BootstrapOptions as t, ReleaseConfidenceInput as u, evaluateReleaseConfidence as v, mannWhitneyU as w, RankTestMethodRequest as x, MannWhitneyResult as y };
|
|
305
|
+
//# sourceMappingURL=promotion-gate-BawrdPYr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promotion-gate-BawrdPYr.d.ts","names":[],"sources":["../src/statistics/rank-tests.ts","../src/release-confidence.ts","../src/promotion-gate.ts"],"mappings":";;;;;;KAiCY;;;;;KAMA;UAEK;;EAEf,SAAS;;EAET;;;EAGA;;UAYe;;EAEf;;EAEA;;EAEA;;EAEA,QAAQ;;EAER;;;;;;;;;;;;;;iBAec,aACd,aACA,aACA,OAAM,kBACL;UAuFc;;;EAGf;;EAEA;;EAEA,QAAQ;;EAER;;EAEA;;;;;;;;;;;;;;;iBAgBc,mBACd,kBACA,iBACA,OAAM,kBACL;;;;KCzLS;;UAGK;;EAEf;;EAEA;EACA,WAAW;;EAEX;;EAEA;;EAEA;;EAEA;EACA,WAAW;;KAGD;KACA;UAQK;EACf;EACA;EACA,QAAQ;EACR;EACA;EACA;EACA;EACA;;EAEA,eAAe;EACf,MAAM;EACN,WAAW;;UAGI;;EAEf;EACA;EACA;EACA;;EAEA;EACA;EACA;;EAEA;EACA;EACA;;EAEA;;EAEA;;UAGe;EACf;EACA;EACA;EACA,UAAU;EACV,qBAAqB;EACrB,gBAAgB;EAChB,kBAAkB;EAClB,eAAe;EACf,aAAa;;UAGE;EACf,MAAM;EACN,QAAQ;EACR;EACA;;UAGe;EACf,MAAM;EACN;EACA;EACA;;UAGe;EACf;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,aAAa,OAAO;EACpB,cAAc;EACd,oBAAoB,QAAQ,OAAO;EACnC,0BAA0B;;;;;;;EAO1B;;UAGe;EACf;EACA;EACA;EACA,QAAQ;EACR;EACA,MAAM;EACN,QAAQ;EACR,SAAS;EACT,SAAS;EACT,cAAc;EACd;;iBAkBc,0BACd,OAAO,yBACN;iBA4Ha,wBAAwB,OAAO,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;KCtR5D;UAEK;EACf;EACA;;EAEA;;EAEA;;EAEA;;EAEA;EACA;EACA,SAAS;;UAGM;;EAEf;;EAEA;;;;;;EAMA;;;EAGA;;;;;;;;;iBAUc,YACd,oBACA,qBACA,UAAS,mBACR;;;;;;;;;;;;;;;;UA0Gc,oBAAoB;EACnC,iBAAiB;EACjB,kBAAkB;;EAElB,QAAQ,QAAQ,YAAY;EAC5B;EACA;;EAEA;;EAEA;;;;;iBAMoB,gBAAgB,SACpC,MAAM,oBAAoB,WACzB,QAAQ;EAAoB;EAAyB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as decidePairedPromotion } from "./paired-promotion-decision-
|
|
3
|
-
import { o as pairHoldout, r as detectScale } from "./statistical-heldout-
|
|
1
|
+
import { i as pairedBootstrap } from "./mean-DHoMiudD.js";
|
|
2
|
+
import { t as decidePairedPromotion } from "./paired-promotion-decision-DsAPYGCm.js";
|
|
3
|
+
import { o as pairHoldout, r as detectScale } from "./statistical-heldout-42NlCNDe.js";
|
|
4
4
|
//#region src/campaign/gates/promotion-policy.ts
|
|
5
5
|
/**
|
|
6
6
|
* Build paired evidence for each objective and apply a promotion policy.
|
|
@@ -171,4 +171,4 @@ function paretoSignificanceGate(options) {
|
|
|
171
171
|
//#endregion
|
|
172
172
|
export { paretoPolicy as n, paretoSignificanceGate as r, buildEvidenceVector as t };
|
|
173
173
|
|
|
174
|
-
//# sourceMappingURL=promotion-policy-
|
|
174
|
+
//# sourceMappingURL=promotion-policy-KO57gbyV.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promotion-policy-CWW35UWq.js","names":[],"sources":["../src/campaign/gates/promotion-policy.ts"],"sourcesContent":["/**\n * Build paired evidence for each objective and apply a promotion policy.\n * The default policy requires at least one gain and every regression floor to\n * clear. A floor can fail because a larger loss remains plausible; that does\n * not demonstrate an observed regression. Missing evidence stays unresolved.\n * Confidence intervals apply to each axis, without a multiplicity adjustment.\n *\n * Cost and latency remain aggregate constraints because GateContext does not\n * supply paired observations for them. Compose a budget gate when needed.\n */\n\nimport {\n decidePairedPromotion,\n type PairedDecisionMethod,\n type PairedDecisionStatistic,\n type PairedMcNemarEvidence,\n} from '../../paired-promotion-decision'\nimport type { Direction } from '../../pareto'\nimport {\n DECISION_PAIRED_DELTA_STATISTIC,\n type PairedBootstrapResult,\n pairedBootstrap,\n} from '../../statistics'\nimport type { Gate, GateContext, GateDecision, GateResult, JudgeScore, Scenario } from '../types'\nimport { detectScale, pairHoldout } from './statistical-heldout'\n\n/** Where an objective's per-cell scalar comes from. `composite` reads the\n * judge's composite; `dimension` reads a named per-dimension score. */\nexport type ObjectiveSource = { kind: 'composite' } | { kind: 'dimension'; dimension: string }\n\nexport interface PromotionObjective {\n /** Stable label used in reports + `contributingGates`. */\n name: string\n source: ObjectiveSource\n /** 'maximize' (quality dims) or 'minimize' (error/risk/length dims). Orients\n * the paired delta so a positive bootstrap always means \"candidate better\". */\n direction: Direction\n /** Declared binary support {0, binaryScale}, including zero-only observations.\n * Must be finite and positive; paired cell scores must be 0 or this scale.\n * Uses the risk-difference mean and rejects the 'median' statistic. */\n binaryScale?: number\n /** The good-direction paired-delta CI lower bound must EXCEED this to count\n * as a significant gain on this axis. Interpreted in the judge's native\n * scale. Default 0 (⇒ \"confidently better\"). */\n gainThreshold?: number\n /** A floor breach (regression) is declared when the good-direction CI lower\n * bound is below −floorTolerance, or when the exact small-sample test proves\n * a drop past it. Defaults to 0.05 times the declared binary scale, or\n * auto-scales off observed magnitudes (0.05 on [0,1], 5 on 0-100). */\n floorTolerance?: number\n}\n\n/** Per-axis verdict from the shared paired decision rule.\n * 'regressed' includes uncertainty that prevents clearing the regression floor. */\nexport type AxisVerdict = 'improved' | 'regressed' | 'flat' | 'few_runs' | 'indeterminate'\n\nexport interface AxisEvidence {\n name: string\n source: ObjectiveSource\n direction: Direction\n /** Paired bootstrap on the GOOD-DIRECTION delta (oriented by `direction`):\n * a positive value means the candidate is better on this axis.\n *\n * DIAGNOSTIC on a pass/fail axis: there the verdict is decided on Tango's\n * score interval instead, because a percentile bootstrap over a three-atom\n * delta lattice is not a valid interval at the nonzero margin `floorTolerance`\n * and `gainThreshold` create. `ci` carries the interval that decided. */\n bootstrap: PairedBootstrapResult\n /** Which paired statistic `bootstrap.low`/`.high` bracket. `'mean'` unless the\n * caller asked for the median — on a pass/fail axis the median and its whole\n * CI are pinned at 0 by tie domination and can see neither a gain nor a\n * regression. `bootstrap.median` still carries the median point estimate. */\n bootstrapStatistic: 'median' | 'mean'\n /** The interval the axis verdict was actually decided on, good-direction and\n * in the axis's native units. */\n ci: { low: number; high: number }\n /** Which estimator produced `ci`. */\n decisionStatistic: PairedDecisionStatistic\n /** McNemar's exact evidence on a pass/fail axis; null otherwise. */\n mcnemar: PairedMcNemarEvidence | null\n /** `ci` has zero width or non-finite bounds. It cannot establish a gain or\n * clear a regression floor, regardless of the point estimate. */\n indeterminate: boolean\n /** Paired observations contributing to this axis. */\n n: number\n minimumRequired: number\n decisionMethod: PairedDecisionMethod\n gainThreshold: number\n floorTolerance: number\n verdict: AxisVerdict\n}\n\nexport interface EvidenceVector {\n /** One entry per objective — NOTHING averaged across axes. */\n axes: AxisEvidence[]\n /** Smallest paired n across axes that produced observations — the binding\n * evidence-sufficiency constraint. 0 when no axis produced observations. */\n minN: number\n /** Aggregate per-side cost from the gate context (a constraint input, not a\n * CI axis — see the module header). */\n cost: { candidate: number; baseline: number }\n}\n\n/** A promotion strategy: a pure function from the evidence vector to a verdict.\n * Many policies can run over the same `EvidenceVector` and disagree — that's\n * the point (competing strategies, shared evidence). */\nexport type PromotionPolicy = (ev: EvidenceVector) => GateResult\n\nexport interface BuildEvidenceVectorOptions {\n /** Minimum paired observations before an axis can claim significance; below\n * it the axis is `few_runs`. The exact small-sample test may require more\n * observations at the selected confidence. */\n minProductiveRuns?: number\n /** Confidence level for every axis bootstrap. Default 0.95. */\n confidence?: number\n /** Bootstrap resamples. Default 2000. */\n resamples?: number\n /** Fixed bootstrap seed for a deterministic, reproducible verdict. Default 1337. */\n seed?: number\n /** Paired statistic every axis CI is computed on. Default `'mean'` — see\n * {@link DECISION_PAIRED_DELTA_STATISTIC} for why the median is not. */\n statistic?: 'mean' | 'median'\n}\n\n/**\n * The Evidence Bus. For each objective, pair candidate vs baseline by full\n * cellId and bootstrap a CI on the good-direction paired delta. Reuses the\n * exact `pairHoldout` + `pairedBootstrap` machinery the held-out gate uses, so\n * a single source of truth governs pairing granularity + scale handling.\n */\nexport function buildEvidenceVector<TArtifact, TScenario extends Scenario>(\n ctx: GateContext<TArtifact, TScenario>,\n objectives: PromotionObjective[],\n opts: BuildEvidenceVectorOptions = {},\n): EvidenceVector {\n if (objectives.length === 0) {\n throw new Error('buildEvidenceVector: at least 1 objective required')\n }\n const confidence = opts.confidence ?? 0.95\n const resamples = opts.resamples ?? 2000\n const seed = opts.seed ?? 1337\n const baseline = ctx.baselineJudgeScores ?? ctx.judgeScores\n const scenarioIds = new Set(ctx.scenarios.map((s) => s.id))\n\n const axes: AxisEvidence[] = []\n for (const obj of objectives) {\n let select: (s: JudgeScore) => number | undefined\n if (obj.source.kind === 'composite') {\n select = (s) => s.composite\n } else {\n const dim = obj.source.dimension\n select = (s) => s.dimensions[dim]\n }\n const paired = pairHoldout(ctx.judgeScores, baseline, scenarioIds, select)\n // Orient to the good direction: maximize ⇒ bootstrap (candidate − baseline);\n // minimize ⇒ bootstrap (baseline − candidate) by swapping args, so a\n // positive bootstrap always reads as \"candidate better on this axis\".\n const before = obj.direction === 'maximize' ? paired.before : paired.after\n const after = obj.direction === 'maximize' ? paired.after : paired.before\n const n = paired.before.length\n const binaryScale = obj.binaryScale\n const floorTolerance =\n obj.floorTolerance ?? 0.05 * (binaryScale ?? detectScale([...paired.before, ...paired.after]))\n const gainThreshold = obj.gainThreshold ?? 0\n // Axes are decided on the MEAN paired delta — which for a pass/fail axis is\n // exactly the change in success rate. The median is structurally blind on\n // the shapes eval data lands in: with most pairs tied its bootstrap CI\n // collapses to [0,0] and the axis reads 'flat', hiding real gains AND real\n // regressions — pass/fail axes on ANY encoding ({0,1} and the 0-100 one\n // `detectScale` exists for), and low-cardinality axes even below half ties.\n // Orthogonal to `pairedDeltaTest`'s own small-sample switch: that picks the\n // TEST (bootstrap CI at n ≥ 20, exact sign test below), this picks the\n // ESTIMATOR the test is applied to. Both are needed — an exact sign test on\n // a tie-pinned median is still blind.\n const bootstrapStatistic = opts.statistic ?? DECISION_PAIRED_DELTA_STATISTIC\n // Both burdens of proof route through the ONE shared rule\n // (`decidePairedPromotion`), so a pass/fail axis is judged on Tango's score\n // interval — the only paired-binary construction valid at the nonzero\n // margins `gainThreshold` / `floorTolerance` create — and a zero-width\n // interval cannot buy a verdict in either direction.\n const improvement = decidePairedPromotion(before, after, {\n confidence,\n resamples,\n statistic: bootstrapStatistic,\n seed,\n threshold: gainThreshold,\n minPairs: opts.minProductiveRuns,\n binaryScale,\n })\n const regression = decidePairedPromotion(after, before, {\n confidence,\n resamples,\n statistic: bootstrapStatistic,\n seed,\n threshold: floorTolerance,\n minPairs: opts.minProductiveRuns,\n binaryScale,\n })\n const bootstrap =\n improvement.bootstrap ??\n pairedBootstrap(before, after, {\n confidence,\n resamples,\n statistic: bootstrapStatistic,\n seed,\n })\n // A floor breach fires on EITHER burden of proof, because they cover\n // different failures and the floor is the anti-Goodhart guard:\n // - `improvement.low < -floorTolerance` — the CREDIBLE WORST CASE exceeds\n // the tolerance. This is the contract `AxisEvidence.floorTolerance` and\n // `paretoPolicy`'s own reason string state, and it is the conservative\n // posture a safety axis needs: block unless the data can rule the\n // breach out, rather than waiting for the breach to be proven. Read off\n // the DECIDING interval, so a pass/fail axis is not screened by a\n // bootstrap that is pinned wherever ties dominate.\n // - `regression.promote` — a PROVEN drop past the tolerance. Adds the\n // small-sample path, where the decision is an exact sign test because\n // the bootstrap interval is descriptive only.\n // A tied binary axis still has uncertainty about unseen discordant pairs.\n // Its diagnostic bootstrap collapses to zero, so only the deciding score\n // interval can establish that a regression stays within the declared floor.\n const floorBreached = improvement.low < -floorTolerance || regression.promote\n // Floor check precedes the gain check: a credible regression must never be\n // masked as \"improved\". With the defaults (gainThreshold 0, positive floor)\n // the regions are disjoint and order is moot, but a consumer who sets a\n // negative gainThreshold (\"accept small dips\") could otherwise have a real\n // floor breach classified as a gain — anti-Goodhart wins the tie.\n const verdict: AxisVerdict = !improvement.sufficient\n ? 'few_runs'\n : improvement.indeterminate\n ? 'indeterminate'\n : floorBreached\n ? 'regressed'\n : improvement.promote\n ? 'improved'\n : 'flat'\n axes.push({\n name: obj.name,\n source: obj.source,\n direction: obj.direction,\n bootstrap,\n bootstrapStatistic,\n ci: { low: improvement.low, high: improvement.high },\n decisionStatistic: improvement.statistic,\n mcnemar: improvement.mcnemar,\n indeterminate: improvement.indeterminate,\n n,\n minimumRequired: improvement.minimumPairs,\n decisionMethod: improvement.method,\n gainThreshold,\n floorTolerance,\n verdict,\n })\n }\n const ns = axes.map((a) => a.n).filter((n) => n > 0)\n const minN = ns.length > 0 ? Math.min(...ns) : 0\n return { axes, minN, cost: { candidate: ctx.cost.candidate, baseline: ctx.cost.baseline } }\n}\n\n/**\n * Require a supported gain and every configured regression floor to clear.\n * A failed floor holds the candidate, including when uncertainty permits a loss.\n * Missing or indeterminate evidence requires more work; no gain holds release.\n */\nexport const paretoPolicy: PromotionPolicy = (ev) => {\n const contributingGates = ev.axes.map((ax) => ({\n name: `objective:${ax.name}`,\n status:\n ax.verdict === 'regressed'\n ? ('fail' as const)\n : ax.verdict === 'few_runs' || ax.verdict === 'indeterminate'\n ? ('not_evaluated' as const)\n : ('pass' as const),\n detail: {\n direction: ax.direction,\n source: ax.source,\n verdict: ax.verdict,\n n: ax.n,\n deltaMedian: ax.bootstrap.median,\n ciLow: ax.ci.low,\n ciHigh: ax.ci.high,\n decisionStatistic: ax.decisionStatistic,\n decisionMethod: ax.decisionMethod,\n mcnemar: ax.mcnemar,\n indeterminate: ax.indeterminate,\n bootstrapCiLow: ax.bootstrap.low,\n bootstrapCiHigh: ax.bootstrap.high,\n confidence: ax.bootstrap.confidence,\n gainThreshold: ax.gainThreshold,\n floorTolerance: ax.floorTolerance,\n },\n }))\n\n const regressed = ev.axes.filter((a) => a.verdict === 'regressed')\n const insufficient = ev.axes.filter(\n (a) => a.verdict === 'few_runs' || a.verdict === 'indeterminate',\n )\n const improved = ev.axes.filter((a) => a.verdict === 'improved')\n\n let decision: GateDecision\n const reasons: string[] = []\n if (regressed.length > 0) {\n // A gain on another axis cannot excuse an unresolved regression floor.\n decision = 'hold'\n for (const a of regressed) {\n reasons.push(\n `objective '${a.name}' did not clear its regression floor -${a.floorTolerance}: good-direction CI [${a.ci.low.toFixed(3)}, ${a.ci.high.toFixed(3)}] (n=${a.n})`,\n )\n }\n } else if (insufficient.length > 0) {\n // An unresolved axis cannot establish either a gain or a safe floor.\n decision = 'need_more_work'\n for (const a of insufficient) {\n reasons.push(\n a.verdict === 'few_runs'\n ? `objective '${a.name}' has only n=${a.n} paired runs — insufficient evidence to claim significance`\n : `objective '${a.name}' has an indeterminate deciding CI [${a.ci.low}, ${a.ci.high}] — insufficient evidence to clear its regression floor (n=${a.n})`,\n )\n }\n } else if (improved.length > 0) {\n decision = 'ship'\n reasons.push(\n `Supported objective gain: ${improved\n .map(\n (a) =>\n `'${a.name}' +${a.ci.low > 0 ? a.ci.low.toFixed(3) : a.bootstrap.mean.toFixed(3)} (CI.low ${a.ci.low.toFixed(3)})`,\n )\n .join(', ')}; every regression floor cleared`,\n )\n } else {\n // Every floor cleared, but no objective demonstrated a significant gain.\n decision = 'hold'\n reasons.push(\n 'no Pareto improvement: no objective shows a significant gain; every regression floor cleared',\n )\n }\n\n // `delta` surfaces the composite axis if present, else the first axis — a\n // single convenience scalar; the vector lives in `contributingGates`.\n const composite = ev.axes.find((a) => a.source.kind === 'composite') ?? ev.axes[0]\n return { decision, reasons, contributingGates, delta: composite?.bootstrap.median }\n}\n\nexport interface ParetoSignificanceGateOptions extends BuildEvidenceVectorOptions {\n /** The objective vector. Every axis is both a gain source and a safety floor. */\n objectives: PromotionObjective[]\n /** Strategy applied to the evidence vector. Default `paretoPolicy`. Override\n * to run a stricter/looser strategy over the SAME bus (competing policies). */\n policy?: PromotionPolicy\n /** Override the gate name in reports. */\n name?: string\n}\n\n/**\n * Wrap the bus + a policy as a `Gate`. Plugs into the existing\n * `runImprovementLoop({ gate })` slot and composes via `composeGate`; default\n * loop behavior is unchanged because consumers opt in by passing this gate.\n */\nexport function paretoSignificanceGate<TArtifact = unknown, TScenario extends Scenario = Scenario>(\n options: ParetoSignificanceGateOptions,\n): Gate<TArtifact, TScenario> {\n if (options.objectives.length === 0) {\n throw new Error('paretoSignificanceGate: at least 1 objective required')\n }\n const policy = options.policy ?? paretoPolicy\n return {\n name: options.name ?? 'paretoSignificanceGate',\n async decide(ctx: GateContext<TArtifact, TScenario>): Promise<GateResult> {\n const ev = buildEvidenceVector(ctx, options.objectives, options)\n return policy(ev)\n },\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"promotion-policy-KO57gbyV.js","names":[],"sources":["../src/campaign/gates/promotion-policy.ts"],"sourcesContent":["/**\n * Build paired evidence for each objective and apply a promotion policy.\n * The default policy requires at least one gain and every regression floor to\n * clear. A floor can fail because a larger loss remains plausible; that does\n * not demonstrate an observed regression. Missing evidence stays unresolved.\n * Confidence intervals apply to each axis, without a multiplicity adjustment.\n *\n * Cost and latency remain aggregate constraints because GateContext does not\n * supply paired observations for them. Compose a budget gate when needed.\n */\n\nimport {\n decidePairedPromotion,\n type PairedDecisionMethod,\n type PairedDecisionStatistic,\n type PairedMcNemarEvidence,\n} from '../../paired-promotion-decision'\nimport type { Direction } from '../../pareto'\nimport {\n DECISION_PAIRED_DELTA_STATISTIC,\n type PairedBootstrapResult,\n pairedBootstrap,\n} from '../../statistics'\nimport type { Gate, GateContext, GateDecision, GateResult, JudgeScore, Scenario } from '../types'\nimport { detectScale, pairHoldout } from './statistical-heldout'\n\n/** Where an objective's per-cell scalar comes from. `composite` reads the\n * judge's composite; `dimension` reads a named per-dimension score. */\nexport type ObjectiveSource = { kind: 'composite' } | { kind: 'dimension'; dimension: string }\n\nexport interface PromotionObjective {\n /** Stable label used in reports + `contributingGates`. */\n name: string\n source: ObjectiveSource\n /** 'maximize' (quality dims) or 'minimize' (error/risk/length dims). Orients\n * the paired delta so a positive bootstrap always means \"candidate better\". */\n direction: Direction\n /** Declared binary support {0, binaryScale}, including zero-only observations.\n * Must be finite and positive; paired cell scores must be 0 or this scale.\n * Uses the risk-difference mean and rejects the 'median' statistic. */\n binaryScale?: number\n /** The good-direction paired-delta CI lower bound must EXCEED this to count\n * as a significant gain on this axis. Interpreted in the judge's native\n * scale. Default 0 (⇒ \"confidently better\"). */\n gainThreshold?: number\n /** A floor breach (regression) is declared when the good-direction CI lower\n * bound is below −floorTolerance, or when the exact small-sample test proves\n * a drop past it. Defaults to 0.05 times the declared binary scale, or\n * auto-scales off observed magnitudes (0.05 on [0,1], 5 on 0-100). */\n floorTolerance?: number\n}\n\n/** Per-axis verdict from the shared paired decision rule.\n * 'regressed' includes uncertainty that prevents clearing the regression floor. */\nexport type AxisVerdict = 'improved' | 'regressed' | 'flat' | 'few_runs' | 'indeterminate'\n\nexport interface AxisEvidence {\n name: string\n source: ObjectiveSource\n direction: Direction\n /** Paired bootstrap on the GOOD-DIRECTION delta (oriented by `direction`):\n * a positive value means the candidate is better on this axis.\n *\n * DIAGNOSTIC on a pass/fail axis: there the verdict is decided on Tango's\n * score interval instead, because a percentile bootstrap over a three-atom\n * delta lattice is not a valid interval at the nonzero margin `floorTolerance`\n * and `gainThreshold` create. `ci` carries the interval that decided. */\n bootstrap: PairedBootstrapResult\n /** Which paired statistic `bootstrap.low`/`.high` bracket. `'mean'` unless the\n * caller asked for the median — on a pass/fail axis the median and its whole\n * CI are pinned at 0 by tie domination and can see neither a gain nor a\n * regression. `bootstrap.median` still carries the median point estimate. */\n bootstrapStatistic: 'median' | 'mean'\n /** The interval the axis verdict was actually decided on, good-direction and\n * in the axis's native units. */\n ci: { low: number; high: number }\n /** Which estimator produced `ci`. */\n decisionStatistic: PairedDecisionStatistic\n /** McNemar's exact evidence on a pass/fail axis; null otherwise. */\n mcnemar: PairedMcNemarEvidence | null\n /** `ci` has zero width or non-finite bounds. It cannot establish a gain or\n * clear a regression floor, regardless of the point estimate. */\n indeterminate: boolean\n /** Paired observations contributing to this axis. */\n n: number\n minimumRequired: number\n decisionMethod: PairedDecisionMethod\n gainThreshold: number\n floorTolerance: number\n verdict: AxisVerdict\n}\n\nexport interface EvidenceVector {\n /** One entry per objective — NOTHING averaged across axes. */\n axes: AxisEvidence[]\n /** Smallest paired n across axes that produced observations — the binding\n * evidence-sufficiency constraint. 0 when no axis produced observations. */\n minN: number\n /** Aggregate per-side cost from the gate context (a constraint input, not a\n * CI axis — see the module header). */\n cost: { candidate: number; baseline: number }\n}\n\n/** A promotion strategy: a pure function from the evidence vector to a verdict.\n * Many policies can run over the same `EvidenceVector` and disagree — that's\n * the point (competing strategies, shared evidence). */\nexport type PromotionPolicy = (ev: EvidenceVector) => GateResult\n\nexport interface BuildEvidenceVectorOptions {\n /** Minimum paired observations before an axis can claim significance; below\n * it the axis is `few_runs`. The exact small-sample test may require more\n * observations at the selected confidence. */\n minProductiveRuns?: number\n /** Confidence level for every axis bootstrap. Default 0.95. */\n confidence?: number\n /** Bootstrap resamples. Default 2000. */\n resamples?: number\n /** Fixed bootstrap seed for a deterministic, reproducible verdict. Default 1337. */\n seed?: number\n /** Paired statistic every axis CI is computed on. Default `'mean'` — see\n * {@link DECISION_PAIRED_DELTA_STATISTIC} for why the median is not. */\n statistic?: 'mean' | 'median'\n}\n\n/**\n * The Evidence Bus. For each objective, pair candidate vs baseline by full\n * cellId and bootstrap a CI on the good-direction paired delta. Reuses the\n * exact `pairHoldout` + `pairedBootstrap` machinery the held-out gate uses, so\n * a single source of truth governs pairing granularity + scale handling.\n */\nexport function buildEvidenceVector<TArtifact, TScenario extends Scenario>(\n ctx: GateContext<TArtifact, TScenario>,\n objectives: PromotionObjective[],\n opts: BuildEvidenceVectorOptions = {},\n): EvidenceVector {\n if (objectives.length === 0) {\n throw new Error('buildEvidenceVector: at least 1 objective required')\n }\n const confidence = opts.confidence ?? 0.95\n const resamples = opts.resamples ?? 2000\n const seed = opts.seed ?? 1337\n const baseline = ctx.baselineJudgeScores ?? ctx.judgeScores\n const scenarioIds = new Set(ctx.scenarios.map((s) => s.id))\n\n const axes: AxisEvidence[] = []\n for (const obj of objectives) {\n let select: (s: JudgeScore) => number | undefined\n if (obj.source.kind === 'composite') {\n select = (s) => s.composite\n } else {\n const dim = obj.source.dimension\n select = (s) => s.dimensions[dim]\n }\n const paired = pairHoldout(ctx.judgeScores, baseline, scenarioIds, select)\n // Orient to the good direction: maximize ⇒ bootstrap (candidate − baseline);\n // minimize ⇒ bootstrap (baseline − candidate) by swapping args, so a\n // positive bootstrap always reads as \"candidate better on this axis\".\n const before = obj.direction === 'maximize' ? paired.before : paired.after\n const after = obj.direction === 'maximize' ? paired.after : paired.before\n const n = paired.before.length\n const binaryScale = obj.binaryScale\n const floorTolerance =\n obj.floorTolerance ?? 0.05 * (binaryScale ?? detectScale([...paired.before, ...paired.after]))\n const gainThreshold = obj.gainThreshold ?? 0\n // Axes are decided on the MEAN paired delta — which for a pass/fail axis is\n // exactly the change in success rate. The median is structurally blind on\n // the shapes eval data lands in: with most pairs tied its bootstrap CI\n // collapses to [0,0] and the axis reads 'flat', hiding real gains AND real\n // regressions — pass/fail axes on ANY encoding ({0,1} and the 0-100 one\n // `detectScale` exists for), and low-cardinality axes even below half ties.\n // Orthogonal to `pairedDeltaTest`'s own small-sample switch: that picks the\n // TEST (bootstrap CI at n ≥ 20, exact sign test below), this picks the\n // ESTIMATOR the test is applied to. Both are needed — an exact sign test on\n // a tie-pinned median is still blind.\n const bootstrapStatistic = opts.statistic ?? DECISION_PAIRED_DELTA_STATISTIC\n // Both burdens of proof route through the ONE shared rule\n // (`decidePairedPromotion`), so a pass/fail axis is judged on Tango's score\n // interval — the only paired-binary construction valid at the nonzero\n // margins `gainThreshold` / `floorTolerance` create — and a zero-width\n // interval cannot buy a verdict in either direction.\n const improvement = decidePairedPromotion(before, after, {\n confidence,\n resamples,\n statistic: bootstrapStatistic,\n seed,\n threshold: gainThreshold,\n minPairs: opts.minProductiveRuns,\n binaryScale,\n })\n const regression = decidePairedPromotion(after, before, {\n confidence,\n resamples,\n statistic: bootstrapStatistic,\n seed,\n threshold: floorTolerance,\n minPairs: opts.minProductiveRuns,\n binaryScale,\n })\n const bootstrap =\n improvement.bootstrap ??\n pairedBootstrap(before, after, {\n confidence,\n resamples,\n statistic: bootstrapStatistic,\n seed,\n })\n // A floor breach fires on EITHER burden of proof, because they cover\n // different failures and the floor is the anti-Goodhart guard:\n // - `improvement.low < -floorTolerance` — the CREDIBLE WORST CASE exceeds\n // the tolerance. This is the contract `AxisEvidence.floorTolerance` and\n // `paretoPolicy`'s own reason string state, and it is the conservative\n // posture a safety axis needs: block unless the data can rule the\n // breach out, rather than waiting for the breach to be proven. Read off\n // the DECIDING interval, so a pass/fail axis is not screened by a\n // bootstrap that is pinned wherever ties dominate.\n // - `regression.promote` — a PROVEN drop past the tolerance. Adds the\n // small-sample path, where the decision is an exact sign test because\n // the bootstrap interval is descriptive only.\n // A tied binary axis still has uncertainty about unseen discordant pairs.\n // Its diagnostic bootstrap collapses to zero, so only the deciding score\n // interval can establish that a regression stays within the declared floor.\n const floorBreached = improvement.low < -floorTolerance || regression.promote\n // Floor check precedes the gain check: a credible regression must never be\n // masked as \"improved\". With the defaults (gainThreshold 0, positive floor)\n // the regions are disjoint and order is moot, but a consumer who sets a\n // negative gainThreshold (\"accept small dips\") could otherwise have a real\n // floor breach classified as a gain — anti-Goodhart wins the tie.\n const verdict: AxisVerdict = !improvement.sufficient\n ? 'few_runs'\n : improvement.indeterminate\n ? 'indeterminate'\n : floorBreached\n ? 'regressed'\n : improvement.promote\n ? 'improved'\n : 'flat'\n axes.push({\n name: obj.name,\n source: obj.source,\n direction: obj.direction,\n bootstrap,\n bootstrapStatistic,\n ci: { low: improvement.low, high: improvement.high },\n decisionStatistic: improvement.statistic,\n mcnemar: improvement.mcnemar,\n indeterminate: improvement.indeterminate,\n n,\n minimumRequired: improvement.minimumPairs,\n decisionMethod: improvement.method,\n gainThreshold,\n floorTolerance,\n verdict,\n })\n }\n const ns = axes.map((a) => a.n).filter((n) => n > 0)\n const minN = ns.length > 0 ? Math.min(...ns) : 0\n return { axes, minN, cost: { candidate: ctx.cost.candidate, baseline: ctx.cost.baseline } }\n}\n\n/**\n * Require a supported gain and every configured regression floor to clear.\n * A failed floor holds the candidate, including when uncertainty permits a loss.\n * Missing or indeterminate evidence requires more work; no gain holds release.\n */\nexport const paretoPolicy: PromotionPolicy = (ev) => {\n const contributingGates = ev.axes.map((ax) => ({\n name: `objective:${ax.name}`,\n status:\n ax.verdict === 'regressed'\n ? ('fail' as const)\n : ax.verdict === 'few_runs' || ax.verdict === 'indeterminate'\n ? ('not_evaluated' as const)\n : ('pass' as const),\n detail: {\n direction: ax.direction,\n source: ax.source,\n verdict: ax.verdict,\n n: ax.n,\n deltaMedian: ax.bootstrap.median,\n ciLow: ax.ci.low,\n ciHigh: ax.ci.high,\n decisionStatistic: ax.decisionStatistic,\n decisionMethod: ax.decisionMethod,\n mcnemar: ax.mcnemar,\n indeterminate: ax.indeterminate,\n bootstrapCiLow: ax.bootstrap.low,\n bootstrapCiHigh: ax.bootstrap.high,\n confidence: ax.bootstrap.confidence,\n gainThreshold: ax.gainThreshold,\n floorTolerance: ax.floorTolerance,\n },\n }))\n\n const regressed = ev.axes.filter((a) => a.verdict === 'regressed')\n const insufficient = ev.axes.filter(\n (a) => a.verdict === 'few_runs' || a.verdict === 'indeterminate',\n )\n const improved = ev.axes.filter((a) => a.verdict === 'improved')\n\n let decision: GateDecision\n const reasons: string[] = []\n if (regressed.length > 0) {\n // A gain on another axis cannot excuse an unresolved regression floor.\n decision = 'hold'\n for (const a of regressed) {\n reasons.push(\n `objective '${a.name}' did not clear its regression floor -${a.floorTolerance}: good-direction CI [${a.ci.low.toFixed(3)}, ${a.ci.high.toFixed(3)}] (n=${a.n})`,\n )\n }\n } else if (insufficient.length > 0) {\n // An unresolved axis cannot establish either a gain or a safe floor.\n decision = 'need_more_work'\n for (const a of insufficient) {\n reasons.push(\n a.verdict === 'few_runs'\n ? `objective '${a.name}' has only n=${a.n} paired runs — insufficient evidence to claim significance`\n : `objective '${a.name}' has an indeterminate deciding CI [${a.ci.low}, ${a.ci.high}] — insufficient evidence to clear its regression floor (n=${a.n})`,\n )\n }\n } else if (improved.length > 0) {\n decision = 'ship'\n reasons.push(\n `Supported objective gain: ${improved\n .map(\n (a) =>\n `'${a.name}' +${a.ci.low > 0 ? a.ci.low.toFixed(3) : a.bootstrap.mean.toFixed(3)} (CI.low ${a.ci.low.toFixed(3)})`,\n )\n .join(', ')}; every regression floor cleared`,\n )\n } else {\n // Every floor cleared, but no objective demonstrated a significant gain.\n decision = 'hold'\n reasons.push(\n 'no Pareto improvement: no objective shows a significant gain; every regression floor cleared',\n )\n }\n\n // `delta` surfaces the composite axis if present, else the first axis — a\n // single convenience scalar; the vector lives in `contributingGates`.\n const composite = ev.axes.find((a) => a.source.kind === 'composite') ?? ev.axes[0]\n return { decision, reasons, contributingGates, delta: composite?.bootstrap.median }\n}\n\nexport interface ParetoSignificanceGateOptions extends BuildEvidenceVectorOptions {\n /** The objective vector. Every axis is both a gain source and a safety floor. */\n objectives: PromotionObjective[]\n /** Strategy applied to the evidence vector. Default `paretoPolicy`. Override\n * to run a stricter/looser strategy over the SAME bus (competing policies). */\n policy?: PromotionPolicy\n /** Override the gate name in reports. */\n name?: string\n}\n\n/**\n * Wrap the bus + a policy as a `Gate`. Plugs into the existing\n * `runImprovementLoop({ gate })` slot and composes via `composeGate`; default\n * loop behavior is unchanged because consumers opt in by passing this gate.\n */\nexport function paretoSignificanceGate<TArtifact = unknown, TScenario extends Scenario = Scenario>(\n options: ParetoSignificanceGateOptions,\n): Gate<TArtifact, TScenario> {\n if (options.objectives.length === 0) {\n throw new Error('paretoSignificanceGate: at least 1 objective required')\n }\n const policy = options.policy ?? paretoPolicy\n return {\n name: options.name ?? 'paretoSignificanceGate',\n async decide(ctx: GateContext<TArtifact, TScenario>): Promise<GateResult> {\n const ev = buildEvidenceVector(ctx, options.objectives, options)\n return policy(ev)\n },\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,39 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as ProposalFindingSchema } from "./external-optimizer-subprocess-BqW0hHcI.js";
|
|
2
2
|
//#region src/analyst/proposal-findings.ts
|
|
3
|
-
const ProposalFindingSchema = z.object({
|
|
4
|
-
schema_version: z.literal("1.0.0"),
|
|
5
|
-
finding_id: z.string().min(1),
|
|
6
|
-
analyst_id: z.string().min(1),
|
|
7
|
-
produced_at: z.string().min(1),
|
|
8
|
-
severity: z.enum([
|
|
9
|
-
"critical",
|
|
10
|
-
"high",
|
|
11
|
-
"medium",
|
|
12
|
-
"low",
|
|
13
|
-
"info"
|
|
14
|
-
]),
|
|
15
|
-
area: z.string().min(1),
|
|
16
|
-
claim: z.string().min(1),
|
|
17
|
-
rationale: z.string().optional(),
|
|
18
|
-
evidence_refs: z.array(z.object({
|
|
19
|
-
kind: z.enum([
|
|
20
|
-
"span",
|
|
21
|
-
"event",
|
|
22
|
-
"artifact",
|
|
23
|
-
"finding",
|
|
24
|
-
"metric"
|
|
25
|
-
]),
|
|
26
|
-
uri: z.string().min(1),
|
|
27
|
-
excerpt: z.string().optional()
|
|
28
|
-
}).strict()),
|
|
29
|
-
recommended_action: z.string().optional(),
|
|
30
|
-
validation_plan: z.string().optional(),
|
|
31
|
-
confidence: z.number().min(0).max(1),
|
|
32
|
-
subject: z.string().optional(),
|
|
33
|
-
derived_from_judge: z.boolean().optional(),
|
|
34
|
-
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
35
|
-
proposal_origin: z.enum(["search", "production"])
|
|
36
|
-
}).strict();
|
|
37
3
|
/** True when a finding names a source candidate generation may learn from. */
|
|
38
4
|
function isProposalFinding(finding) {
|
|
39
5
|
return ProposalFindingSchema.safeParse(finding).success;
|
|
@@ -57,4 +23,4 @@ function findingLabel(finding, index) {
|
|
|
57
23
|
//#endregion
|
|
58
24
|
export { isProposalFinding as n, assertProposalFindings as t };
|
|
59
25
|
|
|
60
|
-
//# sourceMappingURL=proposal-findings-
|
|
26
|
+
//# sourceMappingURL=proposal-findings-CY1xKn_a.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposal-findings-CY1xKn_a.js","names":[],"sources":["../src/analyst/proposal-findings.ts"],"sourcesContent":["import { ProposalFindingSchema } from './finding-scope'\nimport type { ProposalFinding } from './types'\n\n/** True when a finding names a source candidate generation may learn from. */\nexport function isProposalFinding(finding: unknown): finding is ProposalFinding {\n return ProposalFindingSchema.safeParse(finding).success\n}\n\n/**\n * Reject findings whose source has not been explicitly admitted for candidate\n * generation. Search feedback and observed production behavior are allowed;\n * final evaluation data has no allowed origin.\n */\nexport function assertProposalFindings(\n findings: unknown,\n context = 'proposal findings',\n): ReadonlyArray<ProposalFinding> {\n if (!Array.isArray(findings)) {\n throw new TypeError(`${context}: expected an array`)\n }\n const rejected = findings.flatMap((finding, index) =>\n isProposalFinding(finding) ? [] : [findingLabel(finding, index)],\n )\n if (rejected.length > 0) {\n throw new Error(\n `${context}: every finding must match AnalystFinding and declare ` +\n `proposal_origin as search or production. ` +\n `Rejected findings: [${rejected.join(', ')}].`,\n )\n }\n return findings as ReadonlyArray<ProposalFinding>\n}\n\nfunction findingLabel(finding: unknown, index: number): string {\n if (typeof finding !== 'object' || finding === null) return `index ${index}`\n const id = (finding as { finding_id?: unknown }).finding_id\n return typeof id === 'string' && id.length > 0 ? id : `index ${index}`\n}\n"],"mappings":";;;AAIA,SAAgB,kBAAkB,SAA8C;CAC9E,OAAO,sBAAsB,UAAU,OAAO,CAAC,CAAC;AAClD;;;;;;AAOA,SAAgB,uBACd,UACA,UAAU,qBACsB;CAChC,IAAI,CAAC,MAAM,QAAQ,QAAQ,GACzB,MAAM,IAAI,UAAU,GAAG,QAAQ,oBAAoB;CAErD,MAAM,WAAW,SAAS,SAAS,SAAS,UAC1C,kBAAkB,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,SAAS,KAAK,CAAC,CACjE;CACA,IAAI,SAAS,SAAS,GACpB,MAAM,IAAI,MACR,GAAG,QAAQ,qHAEc,SAAS,KAAK,IAAI,EAAE,GAC/C;CAEF,OAAO;AACT;AAEA,SAAS,aAAa,SAAkB,OAAuB;CAC7D,IAAI,OAAO,YAAY,YAAY,YAAY,MAAM,OAAO,SAAS;CACrE,MAAM,KAAM,QAAqC;CACjD,OAAO,OAAO,OAAO,YAAY,GAAG,SAAS,IAAI,KAAK,SAAS;AACjE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { s as ValidationError } from "./errors-
|
|
2
|
-
import { r as canonicalString } from "./canonical-
|
|
1
|
+
import { s as ValidationError } from "./errors-DVZiqS7K.js";
|
|
2
|
+
import { r as canonicalString } from "./canonical-B2RqLofv.js";
|
|
3
3
|
import { a as isToolSpan, i as isLlmSpan, r as isJudgeSpan } from "./schema-CSf6qWgZ.js";
|
|
4
4
|
//#region src/trace/query.ts
|
|
5
5
|
/**
|
|
@@ -131,4 +131,4 @@ function runMetricExtractor(metric) {
|
|
|
131
131
|
//#endregion
|
|
132
132
|
export { hasCapturedToolArgs as a, runFailureClass as c, toolSpans as d, groupBy as i, runMetricExtractor as l, aggregateLlm as n, judgeSpans as o, argHash as r, llmSpans as s, RUN_METRICS as t, runsForScenario as u };
|
|
133
133
|
|
|
134
|
-
//# sourceMappingURL=query-
|
|
134
|
+
//# sourceMappingURL=query-BUCZCK7F.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-
|
|
1
|
+
{"version":3,"file":"query-BUCZCK7F.js","names":[],"sources":["../src/trace/query.ts"],"sourcesContent":["/**\n * Typed query helpers over TraceStore.\n *\n * Not a full SQL engine — a minimal, composable set of operators that\n * cover the canned-pipeline use cases. For ad-hoc analytics, persist to\n * NDJSON and point DuckDB at it; the schema is stable so external SQL\n * tooling works out of the box.\n */\n\nimport { ValidationError } from '../errors'\nimport { canonicalString } from '../ledger-core/canonical'\nimport type { FailureClass, JudgeSpan, LlmSpan, Run, ToolSpan } from './schema'\nimport { isJudgeSpan, isLlmSpan, isToolSpan } from './schema'\nimport type { TraceStore } from './store'\n\nexport async function runsForScenario(store: TraceStore, scenarioId: string): Promise<Run[]> {\n return store.listRuns({ scenarioId })\n}\n\nexport async function llmSpans(store: TraceStore, runId?: string): Promise<LlmSpan[]> {\n const spans = await store.spans({ runId, kind: 'llm' })\n return spans.filter(isLlmSpan)\n}\n\nexport async function toolSpans(\n store: TraceStore,\n runId?: string,\n toolName?: string,\n): Promise<ToolSpan[]> {\n const spans = await store.spans({ runId, kind: 'tool', toolName })\n return spans.filter(isToolSpan)\n}\n\n/** Query judge-kind spans from the trace store, optionally scoped to a single run. */\nexport async function judgeSpans(store: TraceStore, runId?: string): Promise<JudgeSpan[]> {\n const spans = await store.spans({ runId, kind: 'judge' })\n return spans.filter(isJudgeSpan)\n}\n\n/** Group spans by any key selector. */\nexport function groupBy<T, K extends string | number>(items: T[], key: (t: T) => K): Map<K, T[]> {\n const map = new Map<K, T[]>()\n for (const item of items) {\n const k = key(item)\n let bucket = map.get(k)\n if (!bucket) {\n bucket = []\n map.set(k, bucket)\n }\n bucket.push(item)\n }\n return map\n}\n\n/**\n * Key tool arguments for de-duplication: RFC 8785 canonical JSON, so key\n * order cannot split one call into two keys. Uncaptured args (`undefined`)\n * key to the string `'undefined'` so every call still keys to a string; an\n * args value with no canonical JSON form (a nested `undefined`, a function, a\n * non-finite number) throws `LedgerCanonicalizationError`.\n */\nexport function argHash(args: unknown): string {\n if (args === undefined) return 'undefined'\n return canonicalString(args)\n}\n\n/** Whether argument-based comparisons are valid for this tool call. */\nexport function hasCapturedToolArgs(span: ToolSpan): boolean {\n return span.argsCaptured !== false\n}\n\n/** Sum an LLM-span array into aggregate token + cost. */\nexport function aggregateLlm(spans: LlmSpan[]): {\n inputTokens: number\n outputTokens: number\n cachedTokens: number\n cacheWriteTokens: number\n reasoningTokens: number\n costUsd: number\n} {\n return spans.reduce(\n (acc, s) => ({\n inputTokens: acc.inputTokens + (s.inputTokens ?? 0),\n outputTokens: acc.outputTokens + (s.outputTokens ?? 0),\n cachedTokens: acc.cachedTokens + (s.cachedTokens ?? 0),\n cacheWriteTokens: acc.cacheWriteTokens + (s.cacheWriteTokens ?? 0),\n reasoningTokens: acc.reasoningTokens + (s.reasoningTokens ?? 0),\n costUsd: acc.costUsd + (s.costUsd ?? 0),\n }),\n {\n inputTokens: 0,\n outputTokens: 0,\n cachedTokens: 0,\n cacheWriteTokens: 0,\n reasoningTokens: 0,\n costUsd: 0,\n },\n )\n}\n\n/** Pick the outcome's failure class when present, else derive 'success' from run status. */\nexport function runFailureClass(run: Run): FailureClass {\n if (run.outcome?.failureClass) return run.outcome.failureClass\n if (run.status === 'completed' && run.outcome?.pass !== false) return 'success'\n if (run.status === 'aborted') return 'budget_exceeded'\n return 'unknown'\n}\n\n/**\n * Metrics `regressionView`, `correlationStudy`, and `calibrationCurve` can\n * read from a run without a caller-supplied extractor. The type derives from\n * this array, so a new metric cannot be declared without an extractor arm.\n */\nexport const RUN_METRICS = [\n 'score',\n 'overallScore',\n 'pass',\n 'durationMs',\n 'costUsd',\n 'inputTokens',\n 'outputTokens',\n 'failureClass',\n] as const\n\nexport type RunMetric = (typeof RUN_METRICS)[number]\n\nfunction isRunMetric(metric: string): metric is RunMetric {\n return (RUN_METRICS as readonly string[]).includes(metric)\n}\n\n/**\n * The extractor for one built-in metric. `null` means this run carries no\n * value for the metric — the caller drops that run from the sample.\n *\n * Throws `ValidationError` on a metric name this package does not define:\n * an unrecognized name would otherwise read as \"every run is missing this\n * value\" and produce an empty study instead of a refusal.\n */\nexport function runMetricExtractor(\n metric: string,\n): (run: Run, store: TraceStore) => Promise<number | null> {\n if (!isRunMetric(metric)) {\n throw new ValidationError(\n `unknown run metric '${metric}' — pass an \\`extract\\` function or use one of: ${RUN_METRICS.join(', ')}`,\n )\n }\n return async (run, store) => {\n switch (metric) {\n case 'score':\n case 'overallScore':\n return run.outcome?.score ?? null\n case 'pass':\n return run.outcome?.pass === true ? 1 : 0\n case 'durationMs':\n return run.endedAt && run.startedAt ? run.endedAt - run.startedAt : null\n case 'costUsd':\n return aggregateLlm(await llmSpans(store, run.runId)).costUsd\n case 'inputTokens':\n return aggregateLlm(await llmSpans(store, run.runId)).inputTokens\n case 'outputTokens':\n return aggregateLlm(await llmSpans(store, run.runId)).outputTokens\n case 'failureClass':\n return runFailureClass(run) === 'success' ? 1 : 0\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as ValidationError } from "./errors-
|
|
1
|
+
import { s as ValidationError } from "./errors-DVZiqS7K.js";
|
|
2
2
|
//#region src/statistics/random.ts
|
|
3
3
|
/** Tiny seedable PRNG (mulberry32) — deterministic resampling/shuffling, not
|
|
4
4
|
* cryptographic. Exported so e-process shuffles and bootstrap resampling
|
|
@@ -18,4 +18,4 @@ function mulberry32(seed) {
|
|
|
18
18
|
//#endregion
|
|
19
19
|
export { mulberry32 as t };
|
|
20
20
|
|
|
21
|
-
//# sourceMappingURL=random-
|
|
21
|
+
//# sourceMappingURL=random-ByUSnV9w.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"random-
|
|
1
|
+
{"version":3,"file":"random-ByUSnV9w.js","names":[],"sources":["../src/statistics/random.ts"],"sourcesContent":["import { ValidationError } from '../errors'\n\n/** Tiny seedable PRNG (mulberry32) — deterministic resampling/shuffling, not\n * cryptographic. Exported so e-process shuffles and bootstrap resampling\n * share ONE PRNG implementation. Every distinct 32-bit seed gives a distinct\n * stream, including 0. */\nexport function mulberry32(seed: number): () => number {\n if (!Number.isFinite(seed)) {\n throw new ValidationError(`mulberry32: seed must be a finite number, got ${seed}`)\n }\n let s = seed | 0\n return () => {\n s = (s + 0x6d2b79f5) | 0\n let t = s\n t = Math.imul(t ^ (t >>> 15), t | 1)\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61)\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n"],"mappings":";;;;;;AAMA,SAAgB,WAAW,MAA4B;CACrD,IAAI,CAAC,OAAO,SAAS,IAAI,GACvB,MAAM,IAAI,gBAAgB,iDAAiD,MAAM;CAEnF,IAAI,IAAI,OAAO;CACf,aAAa;EACX,IAAK,IAAI,aAAc;EACvB,IAAI,IAAI;EACR,IAAI,KAAK,KAAK,IAAK,MAAM,IAAK,IAAI,CAAC;EACnC,KAAK,IAAI,KAAK,KAAK,IAAK,MAAM,GAAI,IAAI,EAAE;EACxC,SAAS,IAAK,MAAM,QAAS,KAAK;CACpC;AACF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { o as redact } from "./redact-B5xXKqQ3.js";
|
|
2
2
|
import { promises } from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
//#region src/trace/raw-provider-sink.ts
|
|
@@ -161,4 +161,4 @@ function providerFromBaseUrl(baseUrl) {
|
|
|
161
161
|
//#endregion
|
|
162
162
|
export { providerFromBaseUrl as a, defaultProviderRedactor as i, InMemoryRawProviderSink as n, NoopRawProviderSink as r, FileSystemRawProviderSink as t };
|
|
163
163
|
|
|
164
|
-
//# sourceMappingURL=raw-provider-sink-
|
|
164
|
+
//# sourceMappingURL=raw-provider-sink-DoHz4JNG.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"raw-provider-sink-rB2DYxr6.js","names":["fs"],"sources":["../src/trace/raw-provider-sink.ts"],"sourcesContent":["/**\n * RawProviderSink — first-class persistence for the actual HTTP-level\n * request/response bodies of every LLM provider call.\n *\n * Why this is a separate sink from the structured `LlmSpan`:\n *\n * - `LlmSpan` records the *intent* — model name, messages, output text,\n * usage. It's what dashboards read; it's NOT enough for forensics.\n * - When a downstream consumer reports \"the verifier used the wrong route\"\n * or \"tokens look right but reasoning was missing,\" the only way to\n * answer is the raw HTTP body. Span fields can lie (a proxy can echo\n * a different `model` value than what actually answered); the raw\n * response is ground truth.\n *\n * Default behaviour: opt-in. Pass `rawSink` to `LlmClientOptions` (or the\n * matrix runner / BuilderSession sets it up automatically) and every\n * request, response, and error is recorded — including retries, with the\n * attempt index attached so a flaky call's full event chain is recoverable.\n *\n * Redaction is enforced at sink time. The default redactor runs the redaction\n * core (`./redact`, default profile) over headers, bodies and the error\n * message: credential headers and fields are replaced by name, credential and\n * personal-data values by shape. Override via the sink constructor or the\n * per-call `redactor`. The `redactedFields` array on the persisted event lets\n * a reviewer see what was replaced without exposing the values.\n */\n\nimport { promises as fs } from 'node:fs'\nimport * as path from 'node:path'\nimport { redact } from './redact'\n\nexport type RawProviderDirection = 'request' | 'response' | 'error'\n\nexport interface RawProviderEvent {\n /** Stable id. Generated by the sink if omitted. */\n eventId: string\n /** Trace context populated by `LlmClient` when the call is wrapped in a span. */\n runId?: string\n spanId?: string\n /**\n * Logical provider name. Free-form so callers can use whatever id matches\n * their topology (`'openai'`, `'anthropic'`, `'tangle-router'`, …). When\n * omitted, derived from `baseUrl` in `LlmClientOptions`.\n */\n provider: string\n model: string\n /** Endpoint path, e.g. `'/v1/chat/completions'`. */\n endpoint: string\n /** Base URL used for the call (already-normalised — no trailing slash). */\n baseUrl: string\n /** 0-indexed retry attempt. The first attempt is 0; a retried call gets 1, 2, … */\n attemptIndex: number\n direction: RawProviderDirection\n /** Unix ms. */\n timestamp: number\n /** Wall-clock duration of the call leg. Set on `response` and `error` events; null on `request`. */\n durationMs?: number\n statusCode?: number\n requestHeaders?: Record<string, string>\n requestBody?: unknown\n responseHeaders?: Record<string, string>\n responseBody?: unknown\n /** Set on `direction: 'error'` events. */\n errorMessage?: string\n /** JSON Pointers of the fields the redactor replaced ('/requestHeaders/Authorization', '/requestBody/apiKey', …). */\n redactedFields: string[]\n}\n\nexport interface RawProviderSinkFilter {\n runId?: string\n spanId?: string\n direction?: RawProviderDirection\n attemptIndex?: number\n}\n\nexport interface RawProviderSink {\n record(event: RawProviderEvent): Promise<void>\n /** Optional listing — implementations that durably persist (file, db) should support this. */\n list?(filter?: RawProviderSinkFilter): Promise<RawProviderEvent[]>\n /** Optional teardown for backed implementations. */\n close?(): Promise<void>\n}\n\nexport type ProviderRedactor = (event: RawProviderEvent) => RawProviderEvent\n\n/**\n * The default redactor: the redaction core over the parts of an event that\n * carry provider traffic. Every replaced path is added to `redactedFields`.\n */\nexport function defaultProviderRedactor(event: RawProviderEvent): RawProviderEvent {\n const { requestHeaders, requestBody, responseHeaders, responseBody, errorMessage } = event\n const { value, report } = redact({\n requestHeaders,\n requestBody,\n responseHeaders,\n responseBody,\n errorMessage,\n })\n return {\n ...event,\n ...value,\n redactedFields: [\n ...(event.redactedFields ?? []),\n ...report.findings.map((finding) => finding.path),\n ],\n }\n}\n\n// ── In-memory ────────────────────────────────────────────────────────────\n\nexport interface InMemoryRawProviderSinkOptions {\n redactor?: ProviderRedactor\n}\n\nexport class InMemoryRawProviderSink implements RawProviderSink {\n private events: RawProviderEvent[] = []\n private redactor: ProviderRedactor\n\n constructor(opts: InMemoryRawProviderSinkOptions = {}) {\n this.redactor = opts.redactor ?? defaultProviderRedactor\n }\n\n async record(event: RawProviderEvent): Promise<void> {\n this.events.push(this.redactor({ ...event, redactedFields: event.redactedFields ?? [] }))\n }\n\n async list(filter: RawProviderSinkFilter = {}): Promise<RawProviderEvent[]> {\n return this.events.filter(\n (e) =>\n (filter.runId === undefined || e.runId === filter.runId) &&\n (filter.spanId === undefined || e.spanId === filter.spanId) &&\n (filter.direction === undefined || e.direction === filter.direction) &&\n (filter.attemptIndex === undefined || e.attemptIndex === filter.attemptIndex),\n )\n }\n\n size(): number {\n return this.events.length\n }\n}\n\nexport class NoopRawProviderSink implements RawProviderSink {\n async record(): Promise<void> {\n /* no-op */\n }\n /**\n * Returns an empty array. Implemented so `assertRunCaptured` does not\n * trip the `no_raw_sink` issue when a caller explicitly opts out of\n * capture by passing this sink — opt-out is a deliberate choice, not a\n * misconfiguration.\n */\n async list(): Promise<RawProviderEvent[]> {\n return []\n }\n}\n\n// ── Filesystem (NDJSON) ──────────────────────────────────────────────────\n\nexport interface FileSystemRawProviderSinkOptions {\n /** Directory the NDJSON file is written into. Created if missing. */\n dir: string\n /** File name; default `'raw-provider-events.ndjson'`. */\n fileName?: string\n /** Bytes after which the writer rolls over to a new file (default 32 MiB). */\n rollAtBytes?: number\n redactor?: ProviderRedactor\n}\n\nexport class FileSystemRawProviderSink implements RawProviderSink {\n private dir: string\n private fileName: string\n private rollAtBytes: number\n private redactor: ProviderRedactor\n private bytesWritten = 0\n private rollIndex = 0\n private initPromise: Promise<void> | null = null\n\n constructor(opts: FileSystemRawProviderSinkOptions) {\n this.dir = opts.dir\n this.fileName = opts.fileName ?? 'raw-provider-events.ndjson'\n this.rollAtBytes = opts.rollAtBytes ?? 32 * 1024 * 1024\n this.redactor = opts.redactor ?? defaultProviderRedactor\n }\n\n private async ensureInit(): Promise<void> {\n if (!this.initPromise) {\n this.initPromise = fs.mkdir(this.dir, { recursive: true }).then(() => undefined)\n }\n await this.initPromise\n }\n\n private currentPath(): string {\n if (this.rollIndex === 0) return path.join(this.dir, this.fileName)\n return path.join(this.dir, `${this.fileName}.${this.rollIndex}`)\n }\n\n async record(event: RawProviderEvent): Promise<void> {\n await this.ensureInit()\n const redacted = this.redactor({ ...event, redactedFields: event.redactedFields ?? [] })\n const line = `${JSON.stringify(redacted)}\\n`\n if (this.bytesWritten + line.length > this.rollAtBytes && this.bytesWritten > 0) {\n this.rollIndex += 1\n this.bytesWritten = 0\n }\n await fs.appendFile(this.currentPath(), line, 'utf8')\n this.bytesWritten += line.length\n }\n\n async list(filter: RawProviderSinkFilter = {}): Promise<RawProviderEvent[]> {\n await this.ensureInit()\n const out: RawProviderEvent[] = []\n for (let i = 0; i <= this.rollIndex; i++) {\n const file =\n i === 0 ? path.join(this.dir, this.fileName) : path.join(this.dir, `${this.fileName}.${i}`)\n let body: string\n try {\n body = await fs.readFile(file, 'utf8')\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') continue\n throw err\n }\n for (const line of body.split('\\n')) {\n if (!line) continue\n const event = JSON.parse(line) as RawProviderEvent\n if (filter.runId !== undefined && event.runId !== filter.runId) continue\n if (filter.spanId !== undefined && event.spanId !== filter.spanId) continue\n if (filter.direction !== undefined && event.direction !== filter.direction) continue\n if (filter.attemptIndex !== undefined && event.attemptIndex !== filter.attemptIndex)\n continue\n out.push(event)\n }\n }\n return out\n }\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────\n\n/**\n * Best-effort provider id from a base URL. Falls back to the URL host when\n * none of the well-known patterns match.\n */\nexport function providerFromBaseUrl(baseUrl: string): string {\n const lower = baseUrl.toLowerCase()\n if (lower.includes('api.openai.com')) return 'openai'\n if (lower.includes('api.anthropic.com')) return 'anthropic'\n if (lower.includes('generativelanguage.googleapis.com')) return 'google'\n if (lower.includes('api.together.ai') || lower.includes('api.together.xyz')) return 'together'\n if (lower.includes('api.deepseek.com')) return 'deepseek'\n if (lower.includes('router.tangle.tools')) return 'tangle-router'\n if (lower.includes('api.litellm') || lower.includes('litellm')) return 'litellm'\n try {\n return new URL(baseUrl).host\n } catch {\n return baseUrl\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"raw-provider-sink-DoHz4JNG.js","names":["fs"],"sources":["../src/trace/raw-provider-sink.ts"],"sourcesContent":["/**\n * RawProviderSink — first-class persistence for the actual HTTP-level\n * request/response bodies of every LLM provider call.\n *\n * Why this is a separate sink from the structured `LlmSpan`:\n *\n * - `LlmSpan` records the *intent* — model name, messages, output text,\n * usage. It's what dashboards read; it's NOT enough for forensics.\n * - When a downstream consumer reports \"the verifier used the wrong route\"\n * or \"tokens look right but reasoning was missing,\" the only way to\n * answer is the raw HTTP body. Span fields can lie (a proxy can echo\n * a different `model` value than what actually answered); the raw\n * response is ground truth.\n *\n * Default behaviour: opt-in. Pass `rawSink` to `LlmClientOptions` (or the\n * matrix runner / BuilderSession sets it up automatically) and every\n * request, response, and error is recorded — including retries, with the\n * attempt index attached so a flaky call's full event chain is recoverable.\n *\n * Redaction is enforced at sink time. The default redactor runs the redaction\n * core (`./redact`, default profile) over headers, bodies and the error\n * message: credential headers and fields are replaced by name, credential and\n * personal-data values by shape. Override via the sink constructor or the\n * per-call `redactor`. The `redactedFields` array on the persisted event lets\n * a reviewer see what was replaced without exposing the values.\n */\n\nimport { promises as fs } from 'node:fs'\nimport * as path from 'node:path'\nimport { redact } from './redact'\n\nexport type RawProviderDirection = 'request' | 'response' | 'error'\n\nexport interface RawProviderEvent {\n /** Stable id. Generated by the sink if omitted. */\n eventId: string\n /** Trace context populated by `LlmClient` when the call is wrapped in a span. */\n runId?: string\n spanId?: string\n /**\n * Logical provider name. Free-form so callers can use whatever id matches\n * their topology (`'openai'`, `'anthropic'`, `'tangle-router'`, …). When\n * omitted, derived from `baseUrl` in `LlmClientOptions`.\n */\n provider: string\n model: string\n /** Endpoint path, e.g. `'/v1/chat/completions'`. */\n endpoint: string\n /** Base URL used for the call (already-normalised — no trailing slash). */\n baseUrl: string\n /** 0-indexed retry attempt. The first attempt is 0; a retried call gets 1, 2, … */\n attemptIndex: number\n direction: RawProviderDirection\n /** Unix ms. */\n timestamp: number\n /** Wall-clock duration of the call leg. Set on `response` and `error` events; null on `request`. */\n durationMs?: number\n statusCode?: number\n requestHeaders?: Record<string, string>\n requestBody?: unknown\n responseHeaders?: Record<string, string>\n responseBody?: unknown\n /** Set on `direction: 'error'` events. */\n errorMessage?: string\n /** JSON Pointers of the fields the redactor replaced ('/requestHeaders/Authorization', '/requestBody/apiKey', …). */\n redactedFields: string[]\n}\n\nexport interface RawProviderSinkFilter {\n runId?: string\n spanId?: string\n direction?: RawProviderDirection\n attemptIndex?: number\n}\n\nexport interface RawProviderSink {\n record(event: RawProviderEvent): Promise<void>\n /** Optional listing — implementations that durably persist (file, db) should support this. */\n list?(filter?: RawProviderSinkFilter): Promise<RawProviderEvent[]>\n /** Optional teardown for backed implementations. */\n close?(): Promise<void>\n}\n\nexport type ProviderRedactor = (event: RawProviderEvent) => RawProviderEvent\n\n/**\n * The default redactor: the redaction core over the parts of an event that\n * carry provider traffic. Every replaced path is added to `redactedFields`.\n */\nexport function defaultProviderRedactor(event: RawProviderEvent): RawProviderEvent {\n const { requestHeaders, requestBody, responseHeaders, responseBody, errorMessage } = event\n const { value, report } = redact({\n requestHeaders,\n requestBody,\n responseHeaders,\n responseBody,\n errorMessage,\n })\n return {\n ...event,\n ...value,\n redactedFields: [\n ...(event.redactedFields ?? []),\n ...report.findings.map((finding) => finding.path),\n ],\n }\n}\n\n// ── In-memory ────────────────────────────────────────────────────────────\n\nexport interface InMemoryRawProviderSinkOptions {\n redactor?: ProviderRedactor\n}\n\nexport class InMemoryRawProviderSink implements RawProviderSink {\n private events: RawProviderEvent[] = []\n private redactor: ProviderRedactor\n\n constructor(opts: InMemoryRawProviderSinkOptions = {}) {\n this.redactor = opts.redactor ?? defaultProviderRedactor\n }\n\n async record(event: RawProviderEvent): Promise<void> {\n this.events.push(this.redactor({ ...event, redactedFields: event.redactedFields ?? [] }))\n }\n\n async list(filter: RawProviderSinkFilter = {}): Promise<RawProviderEvent[]> {\n return this.events.filter(\n (e) =>\n (filter.runId === undefined || e.runId === filter.runId) &&\n (filter.spanId === undefined || e.spanId === filter.spanId) &&\n (filter.direction === undefined || e.direction === filter.direction) &&\n (filter.attemptIndex === undefined || e.attemptIndex === filter.attemptIndex),\n )\n }\n\n size(): number {\n return this.events.length\n }\n}\n\nexport class NoopRawProviderSink implements RawProviderSink {\n async record(): Promise<void> {\n /* no-op */\n }\n /**\n * Returns an empty array. Implemented so `assertRunCaptured` does not\n * trip the `no_raw_sink` issue when a caller explicitly opts out of\n * capture by passing this sink — opt-out is a deliberate choice, not a\n * misconfiguration.\n */\n async list(): Promise<RawProviderEvent[]> {\n return []\n }\n}\n\n// ── Filesystem (NDJSON) ──────────────────────────────────────────────────\n\nexport interface FileSystemRawProviderSinkOptions {\n /** Directory the NDJSON file is written into. Created if missing. */\n dir: string\n /** File name; default `'raw-provider-events.ndjson'`. */\n fileName?: string\n /** Bytes after which the writer rolls over to a new file (default 32 MiB). */\n rollAtBytes?: number\n redactor?: ProviderRedactor\n}\n\nexport class FileSystemRawProviderSink implements RawProviderSink {\n private dir: string\n private fileName: string\n private rollAtBytes: number\n private redactor: ProviderRedactor\n private bytesWritten = 0\n private rollIndex = 0\n private initPromise: Promise<void> | null = null\n\n constructor(opts: FileSystemRawProviderSinkOptions) {\n this.dir = opts.dir\n this.fileName = opts.fileName ?? 'raw-provider-events.ndjson'\n this.rollAtBytes = opts.rollAtBytes ?? 32 * 1024 * 1024\n this.redactor = opts.redactor ?? defaultProviderRedactor\n }\n\n private async ensureInit(): Promise<void> {\n if (!this.initPromise) {\n this.initPromise = fs.mkdir(this.dir, { recursive: true }).then(() => undefined)\n }\n await this.initPromise\n }\n\n private currentPath(): string {\n if (this.rollIndex === 0) return path.join(this.dir, this.fileName)\n return path.join(this.dir, `${this.fileName}.${this.rollIndex}`)\n }\n\n async record(event: RawProviderEvent): Promise<void> {\n await this.ensureInit()\n const redacted = this.redactor({ ...event, redactedFields: event.redactedFields ?? [] })\n const line = `${JSON.stringify(redacted)}\\n`\n if (this.bytesWritten + line.length > this.rollAtBytes && this.bytesWritten > 0) {\n this.rollIndex += 1\n this.bytesWritten = 0\n }\n await fs.appendFile(this.currentPath(), line, 'utf8')\n this.bytesWritten += line.length\n }\n\n async list(filter: RawProviderSinkFilter = {}): Promise<RawProviderEvent[]> {\n await this.ensureInit()\n const out: RawProviderEvent[] = []\n for (let i = 0; i <= this.rollIndex; i++) {\n const file =\n i === 0 ? path.join(this.dir, this.fileName) : path.join(this.dir, `${this.fileName}.${i}`)\n let body: string\n try {\n body = await fs.readFile(file, 'utf8')\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') continue\n throw err\n }\n for (const line of body.split('\\n')) {\n if (!line) continue\n const event = JSON.parse(line) as RawProviderEvent\n if (filter.runId !== undefined && event.runId !== filter.runId) continue\n if (filter.spanId !== undefined && event.spanId !== filter.spanId) continue\n if (filter.direction !== undefined && event.direction !== filter.direction) continue\n if (filter.attemptIndex !== undefined && event.attemptIndex !== filter.attemptIndex)\n continue\n out.push(event)\n }\n }\n return out\n }\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────\n\n/**\n * Best-effort provider id from a base URL. Falls back to the URL host when\n * none of the well-known patterns match.\n */\nexport function providerFromBaseUrl(baseUrl: string): string {\n const lower = baseUrl.toLowerCase()\n if (lower.includes('api.openai.com')) return 'openai'\n if (lower.includes('api.anthropic.com')) return 'anthropic'\n if (lower.includes('generativelanguage.googleapis.com')) return 'google'\n if (lower.includes('api.together.ai') || lower.includes('api.together.xyz')) return 'together'\n if (lower.includes('api.deepseek.com')) return 'deepseek'\n if (lower.includes('router.tangle.tools')) return 'tangle-router'\n if (lower.includes('api.litellm') || lower.includes('litellm')) return 'litellm'\n try {\n return new URL(baseUrl).host\n } catch {\n return baseUrl\n }\n}\n"],"mappings":"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"}
|