@tangle-network/agent-eval 0.217.1 → 0.219.0
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 +57 -1
- package/dist/adapters/http.d.ts +3 -3
- package/dist/adapters/http.d.ts.map +1 -1
- package/dist/adapters/http.js +1 -0
- package/dist/adapters/http.js.map +1 -1
- package/dist/{agent-profile-DTt8uGP9.d.ts → agent-profile-D01Io2Xw.d.ts} +4 -4
- package/dist/{agent-profile-DTt8uGP9.d.ts.map → agent-profile-D01Io2Xw.d.ts.map} +1 -1
- package/dist/analyst/index.d.ts +13 -13
- package/dist/analyst/index.d.ts.map +1 -1
- package/dist/analyst/index.js +10 -10
- package/dist/analyst/index.js.map +1 -1
- package/dist/{analyze-runs-DyeNcenW.d.ts → analyze-runs-BWAHBDAw.d.ts} +4 -4
- package/dist/{analyze-runs-DyeNcenW.d.ts.map → analyze-runs-BWAHBDAw.d.ts.map} +1 -1
- package/dist/{benchmark-command-xQK8nOI6.js → benchmark-command-BzmMTnvC.js} +664 -565
- package/dist/benchmark-command-BzmMTnvC.js.map +1 -0
- package/dist/benchmarks/index.d.ts +5 -5
- package/dist/benchmarks/index.js +3 -3
- package/dist/benchmarks/index.js.map +1 -1
- package/dist/campaign/index.d.ts +8 -8
- package/dist/campaign/index.js +11 -11
- package/dist/{campaign-CJGkxAQ6.js → campaign-BVPC6ODQ.js} +452 -282
- package/dist/campaign-BVPC6ODQ.js.map +1 -0
- package/dist/{campaign-evidence-CQYw8_0H.js → campaign-evidence-DunzcJGv.js} +2 -2
- package/dist/campaign-evidence-DunzcJGv.js.map +1 -0
- package/dist/{chat-client-ldqxYYTN.js → chat-client-CMQ8_h4J.js} +2 -2
- package/dist/{chat-client-ldqxYYTN.js.map → chat-client-CMQ8_h4J.js.map} +1 -1
- package/dist/{chat-json-call-DavzexSp.js → chat-json-call-BrZKn0L3.js} +2 -2
- package/dist/{chat-json-call-DavzexSp.js.map → chat-json-call-BrZKn0L3.js.map} +1 -1
- package/dist/cli.js +10 -10
- package/dist/{completion-verifier-B_jw6C9p.js → completion-verifier-Cigap8CG.js} +5 -5
- package/dist/{completion-verifier-B_jw6C9p.js.map → completion-verifier-Cigap8CG.js.map} +1 -1
- package/dist/contract/index.d.ts +11 -11
- package/dist/contract/index.js +91 -11
- package/dist/contract/index.js.map +1 -1
- package/dist/{cost-ledger-D0352Z4d.js → cost-ledger-BGZB6yY2.js} +75 -2
- package/dist/cost-ledger-BGZB6yY2.js.map +1 -0
- package/dist/{cost-ledger-Jk62OBfF.d.ts → cost-ledger-C1W3ICmP.d.ts} +26 -2
- package/dist/cost-ledger-C1W3ICmP.d.ts.map +1 -0
- package/dist/{default-registry-ClYjq3QE.js → default-registry-BrKmT01n.js} +310 -278
- package/dist/{default-registry-ClYjq3QE.js.map → default-registry-BrKmT01n.js.map} +1 -1
- package/dist/{default-registry-DXgLmoDI.d.ts → default-registry-Cwg_QN3d.d.ts} +6 -6
- package/dist/{default-registry-DXgLmoDI.d.ts.map → default-registry-Cwg_QN3d.d.ts.map} +1 -1
- package/dist/{define-agent-eval-BIkH_gAR.d.ts → define-agent-eval-C2nFhHPu.d.ts} +8 -8
- package/dist/{define-agent-eval-BIkH_gAR.d.ts.map → define-agent-eval-C2nFhHPu.d.ts.map} +1 -1
- package/dist/{define-agent-eval-BDxNlP3D.js → define-agent-eval-UQY3VbJ2.js} +165 -105
- package/dist/define-agent-eval-UQY3VbJ2.js.map +1 -0
- package/dist/diagnosis/index.d.ts +2 -2
- package/dist/{dspy-rlm-engine-DhdCr1Dc.js → dspy-rlm-engine-Bn_Mt_LW.js} +3 -3
- package/dist/{dspy-rlm-engine-DhdCr1Dc.js.map → dspy-rlm-engine-Bn_Mt_LW.js.map} +1 -1
- package/dist/{engine-BvZ0R-36.d.ts → engine-BpGGw6cd.d.ts} +3 -3
- package/dist/{engine-BvZ0R-36.d.ts.map → engine-BpGGw6cd.d.ts.map} +1 -1
- package/dist/eval-campaign-BUMIxKTE.js +393 -0
- package/dist/eval-campaign-BUMIxKTE.js.map +1 -0
- package/dist/{evaluation-jTjC_QQD.d.ts → evaluation-CBdQt_kr.d.ts} +4 -4
- package/dist/{evaluation-jTjC_QQD.d.ts.map → evaluation-CBdQt_kr.d.ts.map} +1 -1
- package/dist/evaluation.d.ts +1 -1
- package/dist/evaluation.js +1 -1
- package/dist/{exact-types-CflbJ9f3.d.ts → exact-types-BYFmYq44.d.ts} +2 -2
- package/dist/{exact-types-CflbJ9f3.d.ts.map → exact-types-BYFmYq44.d.ts.map} +1 -1
- package/dist/experiment/index.d.ts +24 -1
- package/dist/experiment/index.d.ts.map +1 -1
- package/dist/experiment/index.js +110 -71
- package/dist/experiment/index.js.map +1 -1
- package/dist/{exporters-Cl6IeNAu.js → exporters-DWvM16LE.js} +2 -2
- package/dist/{exporters-Cl6IeNAu.js.map → exporters-DWvM16LE.js.map} +1 -1
- package/dist/{external-optimizer-process-KVFGvYX1.js → external-optimizer-process-wOLfzsCC.js} +2 -2
- package/dist/{external-optimizer-process-KVFGvYX1.js.map → external-optimizer-process-wOLfzsCC.js.map} +1 -1
- package/dist/{external-optimizer-subprocess-XIHBOSKt.js → external-optimizer-subprocess-D670Oxf2.js} +4 -4
- package/dist/{external-optimizer-subprocess-XIHBOSKt.js.map → external-optimizer-subprocess-D670Oxf2.js.map} +1 -1
- package/dist/{feedback-trajectory-BWmhRBGu.d.ts → feedback-trajectory-DhB9WzYg.d.ts} +3 -3
- package/dist/{feedback-trajectory-BWmhRBGu.d.ts.map → feedback-trajectory-DhB9WzYg.d.ts.map} +1 -1
- package/dist/{findings-store-BMVQtEsm.js → findings-store-CvNo712L.js} +6 -6
- package/dist/{findings-store-BMVQtEsm.js.map → findings-store-CvNo712L.js.map} +1 -1
- package/dist/fuzz.d.ts +1 -1
- package/dist/fuzz.js +1 -1
- package/dist/{hf-dataset-D9f7-oX7.js → hf-dataset-CKxIJQba.js} +3 -3
- package/dist/{hf-dataset-D9f7-oX7.js.map → hf-dataset-CKxIJQba.js.map} +1 -1
- package/dist/hosted/index.js +1 -1
- package/dist/{index-CX-GAUpw.d.ts → index-CHxwfW5g.d.ts} +2 -2
- package/dist/{index-CX-GAUpw.d.ts.map → index-CHxwfW5g.d.ts.map} +1 -1
- package/dist/{index-BLGqZ81N.d.ts → index-CVFStrQD.d.ts} +8 -8
- package/dist/{index-BLGqZ81N.d.ts.map → index-CVFStrQD.d.ts.map} +1 -1
- package/dist/{index-9jJ2fKSX.d.ts → index-CalAsXMR.d.ts} +7 -5
- package/dist/index-CalAsXMR.d.ts.map +1 -0
- package/dist/{index-CiRwLv2R.d.ts → index-D7fmC-1K.d.ts} +3 -4
- package/dist/index-D7fmC-1K.d.ts.map +1 -0
- package/dist/{index-BiT6RtNH.d.ts → index-DAXfpVf7.d.ts} +10 -10
- package/dist/{index-BiT6RtNH.d.ts.map → index-DAXfpVf7.d.ts.map} +1 -1
- package/dist/{index-ZuWx52WG.d.ts → index-Q6DvdcwI.d.ts} +67 -24
- package/dist/index-Q6DvdcwI.d.ts.map +1 -0
- package/dist/index.d.ts +26 -26
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +615 -692
- package/dist/index.js.map +1 -1
- package/dist/{integrity-DOd9Q86O.js → integrity-C8oUeB0g.js} +322 -197
- package/dist/integrity-C8oUeB0g.js.map +1 -0
- package/dist/{integrity-_qgZLA5p.d.ts → integrity-CCwvezWS.d.ts} +2 -2
- package/dist/{integrity-_qgZLA5p.d.ts.map → integrity-CCwvezWS.d.ts.map} +1 -1
- package/dist/{journal-CR4QikYp.js → journal-C7om8Gum.js} +48 -38
- package/dist/journal-C7om8Gum.js.map +1 -0
- package/dist/judge-gate-Co5tuh57.js.map +1 -1
- package/dist/{judge-gate-DsL0yFcb.d.ts → judge-gate-Dc_mXQsL.d.ts} +2 -2
- package/dist/judge-gate-Dc_mXQsL.d.ts.map +1 -0
- package/dist/{kind-factory-Gy4fXixd.js → kind-factory-BhxbtUsQ.js} +2 -2
- package/dist/{kind-factory-Gy4fXixd.js.map → kind-factory-BhxbtUsQ.js.map} +1 -1
- package/dist/ledger-core/index.d.ts +1 -1
- package/dist/ledger-core/index.js +2 -2
- package/dist/ledger-core/lock-holder.d.ts +2 -0
- package/dist/ledger-core/lock-holder.js +181 -0
- package/dist/ledger-core/lock-holder.js.map +1 -0
- package/dist/{ledger-core-DrJhbms9.js → ledger-core-CAxUdDk0.js} +2 -2
- package/dist/{ledger-core-DrJhbms9.js.map → ledger-core-CAxUdDk0.js.map} +1 -1
- package/dist/{llm-client-BshCREn6.js → llm-client-DXuOTseU.js} +239 -249
- package/dist/llm-client-DXuOTseU.js.map +1 -0
- package/dist/{llm-judge-C8jMTNNG.js → llm-judge-Cc8vDJh_.js} +648 -459
- package/dist/llm-judge-Cc8vDJh_.js.map +1 -0
- package/dist/lock-holder-DaJbfpci.d.ts +86 -0
- package/dist/lock-holder-DaJbfpci.d.ts.map +1 -0
- package/dist/matrix/index.d.ts +2 -2
- package/dist/{matrix-DHe-dwVJ.d.ts → matrix-Cf-AGxGh.d.ts} +4 -4
- package/dist/{matrix-DHe-dwVJ.d.ts.map → matrix-Cf-AGxGh.d.ts.map} +1 -1
- package/dist/meta-eval/index.d.ts +2 -2
- package/dist/{mint-zszyYlpA.js → mint-CbdwjTPW.js} +2 -2
- package/dist/{mint-zszyYlpA.js.map → mint-CbdwjTPW.js.map} +1 -1
- package/dist/{mint-BRZXuwRi.d.ts → mint-CkzpVPdz.d.ts} +3 -3
- package/dist/{mint-BRZXuwRi.d.ts.map → mint-CkzpVPdz.d.ts.map} +1 -1
- package/dist/multishot/golden/index.d.ts +1 -1
- package/dist/multishot/index.d.ts +2 -2
- package/dist/multishot/index.js.map +1 -1
- package/dist/openapi.json +1 -1
- package/dist/{pareto-BzsxidFD.js → pareto-BiBnQXAE.js} +306 -212
- package/dist/pareto-BiBnQXAE.js.map +1 -0
- package/dist/pipelines/index.d.ts.map +1 -1
- package/dist/pipelines/index.js.map +1 -1
- package/dist/{prime-protocol-BWG2DQIk.d.ts → prime-protocol-CckHBxGu.d.ts} +3 -3
- package/dist/{prime-protocol-BWG2DQIk.d.ts.map → prime-protocol-CckHBxGu.d.ts.map} +1 -1
- package/dist/{promotion-gate-DaY95yU6.d.ts → promotion-gate-CkVZHagC.d.ts} +3 -3
- package/dist/{promotion-gate-DaY95yU6.d.ts.map → promotion-gate-CkVZHagC.d.ts.map} +1 -1
- package/dist/{proposal-findings-BbWidvUk.js → proposal-findings-E1aSC_cU.js} +2 -2
- package/dist/{proposal-findings-BbWidvUk.js.map → proposal-findings-E1aSC_cU.js.map} +1 -1
- package/dist/{registry-ssNoHzwD.d.ts → registry-B_yG-1jh.d.ts} +5 -5
- package/dist/{registry-ssNoHzwD.d.ts.map → registry-B_yG-1jh.d.ts.map} +1 -1
- package/dist/{render-C-w2EZ6p.js → render-Cs34y0iX.js} +404 -208
- package/dist/render-Cs34y0iX.js.map +1 -0
- package/dist/reporting.d.ts +3 -3
- package/dist/{researcher-0ABVIdGa.d.ts → researcher-H0p44OYC.d.ts} +5 -5
- package/dist/{researcher-0ABVIdGa.d.ts.map → researcher-H0p44OYC.d.ts.map} +1 -1
- package/dist/{reward-DrZ71vnf.d.ts → reward-BeUgVVC_.d.ts} +2 -2
- package/dist/{reward-DrZ71vnf.d.ts.map → reward-BeUgVVC_.d.ts.map} +1 -1
- package/dist/{reward-hacking-E52wq86n.d.ts → reward-hacking-WTxUbtbb.d.ts} +2 -2
- package/dist/{reward-hacking-E52wq86n.d.ts.map → reward-hacking-WTxUbtbb.d.ts.map} +1 -1
- package/dist/rl.d.ts +8 -8
- package/dist/rl.js +4 -4
- package/dist/rollout/index.d.ts +3 -3
- package/dist/rollout/index.js +5 -5
- package/dist/{rollout-D6C50mfA.js → rollout-Dd1ucT_M.js} +5 -5
- package/dist/{rollout-D6C50mfA.js.map → rollout-Dd1ucT_M.js.map} +1 -1
- package/dist/{rubric-predictive-validity-DiwT8PbL.d.ts → rubric-predictive-validity-noY7uE03.d.ts} +2 -2
- package/dist/{rubric-predictive-validity-DiwT8PbL.d.ts.map → rubric-predictive-validity-noY7uE03.d.ts.map} +1 -1
- package/dist/{run-record-CaxbLq6Y.d.ts → run-record-C3awiXPf.d.ts} +2 -2
- package/dist/{run-record-CaxbLq6Y.d.ts.map → run-record-C3awiXPf.d.ts.map} +1 -1
- package/dist/schema-C-ziyJD7.d.ts.map +1 -1
- package/dist/{schema-DxcKTzbi.js → schema-CvhfLjtZ.js} +77 -47
- package/dist/schema-CvhfLjtZ.js.map +1 -0
- package/dist/search/index.d.ts +2 -2
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/index.js +2 -2
- package/dist/{search-kernel-DxqjBxA-.d.ts → search-kernel-Dloxd6gs.d.ts} +5 -5
- package/dist/{search-kernel-DxqjBxA-.d.ts.map → search-kernel-Dloxd6gs.d.ts.map} +1 -1
- package/dist/{search-ledger-TUvB5gWH.js → search-ledger-CZRqtFbW.js} +252 -245
- package/dist/search-ledger-CZRqtFbW.js.map +1 -0
- package/dist/{search-ledger-file-UKCO2r8a.js → search-ledger-file-Bd5Tioq6.js} +3 -3
- package/dist/{search-ledger-file-UKCO2r8a.js.map → search-ledger-file-Bd5Tioq6.js.map} +1 -1
- package/dist/{search-shipper-Cw2z3-td.js → search-shipper-Dn3NLsuH.js} +3 -3
- package/dist/{search-shipper-Cw2z3-td.js.map → search-shipper-Dn3NLsuH.js.map} +1 -1
- package/dist/{search-summary-DQIvJsSB.js → search-summary-D4bwYnAE.js} +3 -3
- package/dist/{search-summary-DQIvJsSB.js.map → search-summary-D4bwYnAE.js.map} +1 -1
- package/dist/{server-DoVbqqtJ.js → server-8TS8XCvg.js} +3 -3
- package/dist/{server-DoVbqqtJ.js.map → server-8TS8XCvg.js.map} +1 -1
- package/dist/{single-run-lock-U58yf8N6.js → single-run-lock-Dekd8_Wv.js} +7 -7
- package/dist/single-run-lock-Dekd8_Wv.js.map +1 -0
- package/dist/{skillopt-optimization-method-kyL94-ri.js → skillopt-optimization-method-DLKqdhcR.js} +1384 -1059
- package/dist/skillopt-optimization-method-DLKqdhcR.js.map +1 -0
- package/dist/{statistical-heldout-C9AbgREN.d.ts → statistical-heldout-3z3I-kJN.d.ts} +3 -3
- package/dist/{statistical-heldout-C9AbgREN.d.ts.map → statistical-heldout-3z3I-kJN.d.ts.map} +1 -1
- package/dist/{store-otlp-BteDAbHK.js → store-otlp-dyWE3wAG.js} +2 -2
- package/dist/{store-otlp-BteDAbHK.js.map → store-otlp-dyWE3wAG.js.map} +1 -1
- package/dist/{store-tool-spans-D5l_OfTJ.js → store-tool-spans-DIUgZbzu.js} +3 -3
- package/dist/{store-tool-spans-D5l_OfTJ.js.map → store-tool-spans-DIUgZbzu.js.map} +1 -1
- package/dist/{store-tool-spans-DZS0HWVf.d.ts → store-tool-spans-DPwXHQkH.d.ts} +7 -7
- package/dist/{store-tool-spans-DZS0HWVf.d.ts.map → store-tool-spans-DPwXHQkH.d.ts.map} +1 -1
- package/dist/{summary-report-DM7tlml1.d.ts → summary-report-C8V49Jt3.d.ts} +18 -3
- package/dist/summary-report-C8V49Jt3.d.ts.map +1 -0
- package/dist/supervisor-run/index.d.ts.map +1 -1
- package/dist/supervisor-run/index.js +3 -3
- package/dist/{systemone-Bp_Ac0p1.d.ts → systemone-DVA7t76V.d.ts} +6 -6
- package/dist/{systemone-Bp_Ac0p1.d.ts.map → systemone-DVA7t76V.d.ts.map} +1 -1
- package/dist/{systemone-review-CwE6JGIp.d.ts → systemone-review-CUBMuTLi.d.ts} +2 -2
- package/dist/{systemone-review-CwE6JGIp.d.ts.map → systemone-review-CUBMuTLi.d.ts.map} +1 -1
- package/dist/systemone.d.ts +3 -3
- package/dist/{terminal-record-78g6E4vh.js → terminal-record-D4Rv-j1W.js} +241 -193
- package/dist/{terminal-record-78g6E4vh.js.map → terminal-record-D4Rv-j1W.js.map} +1 -1
- package/dist/{tool-groups-DyNz2JZ_.d.ts → tool-groups-LISbBWCg.d.ts} +3 -3
- package/dist/tool-groups-LISbBWCg.d.ts.map +1 -0
- package/dist/{trace-questions-xxwgsuMi.d.ts → trace-questions-C42fYEE4.d.ts} +4 -4
- package/dist/{trace-questions-xxwgsuMi.d.ts.map → trace-questions-C42fYEE4.d.ts.map} +1 -1
- package/dist/trace-repair/index.d.ts +3 -3
- package/dist/traces.d.ts +6 -6
- package/dist/traces.js +3 -3
- package/dist/trajectory-replay/index.d.ts +4 -1
- package/dist/trajectory-replay/index.d.ts.map +1 -1
- package/dist/trajectory-replay/index.js +854 -823
- package/dist/trajectory-replay/index.js.map +1 -1
- package/dist/{tree-BGRglkKd.js → tree-DSqwJpL9.js} +122 -14
- package/dist/tree-DSqwJpL9.js.map +1 -0
- package/dist/{types-CW8ewATZ.d.ts → types-8yQzNm8u.d.ts} +4 -4
- package/dist/{types-CW8ewATZ.d.ts.map → types-8yQzNm8u.d.ts.map} +1 -1
- package/dist/{types-D8GhJoHk.d.ts → types-CHfn1zg5.d.ts} +70 -72
- package/dist/types-CHfn1zg5.d.ts.map +1 -0
- package/dist/{types-DtMbFw6U.d.ts → types-D8GXK9Z5.d.ts} +3 -3
- package/dist/{types-DtMbFw6U.d.ts.map → types-D8GXK9Z5.d.ts.map} +1 -1
- package/dist/{types-D-mgRzlh.d.ts → types-eMhdacVp.d.ts} +2 -2
- package/dist/{types-D-mgRzlh.d.ts.map → types-eMhdacVp.d.ts.map} +1 -1
- package/dist/wire/index.d.ts +3 -3
- package/dist/wire/index.js +1 -1
- package/docs/campaign-proposers.md +16 -0
- package/docs/concepts.md +31 -0
- package/docs/design/statistics-decisions.md +1 -1
- package/docs/eval-surface-map.md +1 -0
- package/docs/profile-json-identity.md +1 -2
- package/docs/public-api.md +100 -88
- package/package.json +8 -6
- package/dist/benchmark-command-xQK8nOI6.js.map +0 -1
- package/dist/campaign-CJGkxAQ6.js.map +0 -1
- package/dist/campaign-evidence-CQYw8_0H.js.map +0 -1
- package/dist/cost-ledger-D0352Z4d.js.map +0 -1
- package/dist/cost-ledger-Jk62OBfF.d.ts.map +0 -1
- package/dist/define-agent-eval-BDxNlP3D.js.map +0 -1
- package/dist/eval-campaign-BLEfBGbA.js +0 -343
- package/dist/eval-campaign-BLEfBGbA.js.map +0 -1
- package/dist/index-9jJ2fKSX.d.ts.map +0 -1
- package/dist/index-CiRwLv2R.d.ts.map +0 -1
- package/dist/index-ZuWx52WG.d.ts.map +0 -1
- package/dist/integrity-DOd9Q86O.js.map +0 -1
- package/dist/journal-CR4QikYp.js.map +0 -1
- package/dist/judge-gate-DsL0yFcb.d.ts.map +0 -1
- package/dist/llm-client-BshCREn6.js.map +0 -1
- package/dist/llm-judge-C8jMTNNG.js.map +0 -1
- package/dist/pareto-BzsxidFD.js.map +0 -1
- package/dist/render-C-w2EZ6p.js.map +0 -1
- package/dist/schema-DxcKTzbi.js.map +0 -1
- package/dist/search-ledger-TUvB5gWH.js.map +0 -1
- package/dist/single-run-lock-U58yf8N6.js.map +0 -1
- package/dist/skillopt-optimization-method-kyL94-ri.js.map +0 -1
- package/dist/summary-report-DM7tlml1.d.ts.map +0 -1
- package/dist/tool-groups-DyNz2JZ_.d.ts.map +0 -1
- package/dist/tree-BGRglkKd.js.map +0 -1
- package/dist/types-D8GhJoHk.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
2
2
|
import { i as JudgeError, n as CaptureIntegrityError, o as NotFoundError, r as ConfigError, s as ValidationError, t as AgentEvalError } from "./errors-BcOs5MKW.js";
|
|
3
3
|
import { a as hashCanonical, r as canonicalString } from "./canonical-Dq2hOQ8L.js";
|
|
4
|
-
import { a as HARNESS_NATIVE_MODEL, c as agentProfileModelId, i as CODING_HARNESSES, l as expandProfileAxes, n as createLlmCorrectnessChecker, o as agentProfileHash, r as verifyCompletion, s as agentProfileId, t as completionVerdict, u as harnessAxisOf } from "./completion-verifier-
|
|
4
|
+
import { a as HARNESS_NATIVE_MODEL, c as agentProfileModelId, i as CODING_HARNESSES, l as expandProfileAxes, n as createLlmCorrectnessChecker, o as agentProfileHash, r as verifyCompletion, s as agentProfileId, t as completionVerdict, u as harnessAxisOf } from "./completion-verifier-Cigap8CG.js";
|
|
5
5
|
import { a as groupRunsByAgentProfileCell, c as verifyAgentProfileCell, i as buildAgentProfileCell, l as hashJson, o as toAgentProfileJson, r as agentProfileCellKey, s as validateAgentProfileCell, t as AGENT_PROFILE_KINDS, u as manifestContentDigest } from "./agent-profile-cell-B1V1gUZs.js";
|
|
6
6
|
import { r as observedSplitScore, t as isRealnessGated } from "./reward-nw2xZGZG.js";
|
|
7
7
|
import { i as isToolSpan, n as isJudgeSpan, r as isLlmSpan, t as FAILURE_CLASSES } from "./schema-Bt2vLFm3.js";
|
|
@@ -23,22 +23,22 @@ import { t as eProcess } from "./sequential-eprocess-DodI6RoF.js";
|
|
|
23
23
|
import { i as pairedDeltaTest, n as pairedDecisionShape, r as minimumPairsForPairedDeltaTest, t as decidePairedPromotion } from "./paired-promotion-decision-D0SHb-ZL.js";
|
|
24
24
|
import { c as runsForScenario, i as judgeSpans, t as argHash } from "./query-B_RZ36an.js";
|
|
25
25
|
import { n as contentHash, r as fileVerdictCache, t as canonicalJson } from "./verdict-cache-CL_7tePD.js";
|
|
26
|
-
import { G as runCanaries, H as redTeamDataset, Q as runCampaign, U as redTeamReport, V as DEFAULT_RED_TEAM_CORPUS, W as scoreRedTeamOutput, a as aggregateRunScore, i as transientDispatchFailure, o as clamp01, t as llmJudge } from "./llm-judge-
|
|
26
|
+
import { G as runCanaries, H as redTeamDataset, Q as runCampaign, U as redTeamReport, V as DEFAULT_RED_TEAM_CORPUS, W as scoreRedTeamOutput, a as aggregateRunScore, i as transientDispatchFailure, o as clamp01, t as llmJudge } from "./llm-judge-Cc8vDJh_.js";
|
|
27
27
|
import { a as resolveModelPricing, i as isModelPriced, n as estimateCost, r as estimateTokens, t as MODEL_PRICING } from "./metrics-BKaPBtIG.js";
|
|
28
|
-
import { c as costForTokenPricing, i as CostCeilingReachedError, l as costForUsage, n as CostAccountingIncompleteError, t as CostLedger } from "./cost-ledger-
|
|
29
|
-
import { D as surfaceContentHash, M as assertRealBackend, N as summarizeBackendIntegrity, _ as parseReflectionResponse, a as ATTESTATION_ALGORITHM, g as buildReflectionPrompt, j as BackendIntegrityError, o as attest, s as verifyAttestation } from "./campaign-evidence-
|
|
28
|
+
import { c as costForTokenPricing, i as CostCeilingReachedError, l as costForUsage, n as CostAccountingIncompleteError, t as CostLedger } from "./cost-ledger-BGZB6yY2.js";
|
|
29
|
+
import { D as surfaceContentHash, M as assertRealBackend, N as summarizeBackendIntegrity, _ as parseReflectionResponse, a as ATTESTATION_ALGORITHM, g as buildReflectionPrompt, j as BackendIntegrityError, o as attest, s as verifyAttestation } from "./campaign-evidence-DunzcJGv.js";
|
|
30
30
|
import { a as redact, c as shareAllowed, n as assessShareSafety, o as redactForShare, s as redactText, t as REDACTION_VERSION } from "./redact-mtkTiJVk.js";
|
|
31
31
|
import { a as makeProposalFinding, i as makeFinding, r as computeFindingId } from "./types-DqFMNTgK.js";
|
|
32
|
-
import { S as requiredPairsForPairedPromotion, n as paretoFrontier, t as dominates, x as pairedPromotionPower } from "./pareto-
|
|
32
|
+
import { S as requiredPairsForPairedPromotion, n as paretoFrontier, t as dominates, x as pairedPromotionPower } from "./pareto-BiBnQXAE.js";
|
|
33
33
|
import { a as LlmCallError, i as stripFencedJson, n as isRecord, o as LlmResponseError } from "./json-BhdsJaOQ.js";
|
|
34
|
-
import { r as selfImprove, t as defineAgentEval } from "./define-agent-eval-
|
|
34
|
+
import { r as selfImprove, t as defineAgentEval } from "./define-agent-eval-UQY3VbJ2.js";
|
|
35
35
|
import { n as equivalenceVerdict, t as certificationEvidenceDigest } from "./verdict-BGQmxQ8A.js";
|
|
36
|
-
import { c as createBoundedTraceAnalysisStore, p as DEFAULT_TRACE_ANALYST_BUDGETS, t as createTraceAnalyst } from "./kind-factory-
|
|
37
|
-
import { _ as readAnalystReview, c as FAILURE_MODE_KIND_SPEC, g as completedAnalystReviewQuality, h as assertUniqueFindingIds, i as DEFAULT_TRACE_ANALYST_KINDS, m as analystRunDigest, n as AnalystRegistry, p as analystFindingDigest, t as buildDefaultAnalystRegistry, v as snapshotAnalystRun, y as validateAnalystReviewDecisions } from "./default-registry-
|
|
36
|
+
import { c as createBoundedTraceAnalysisStore, p as DEFAULT_TRACE_ANALYST_BUDGETS, t as createTraceAnalyst } from "./kind-factory-BhxbtUsQ.js";
|
|
37
|
+
import { _ as readAnalystReview, c as FAILURE_MODE_KIND_SPEC, g as completedAnalystReviewQuality, h as assertUniqueFindingIds, i as DEFAULT_TRACE_ANALYST_KINDS, m as analystRunDigest, n as AnalystRegistry, p as analystFindingDigest, t as buildDefaultAnalystRegistry, v as snapshotAnalystRun, y as validateAnalystReviewDecisions } from "./default-registry-BrKmT01n.js";
|
|
38
38
|
import { OUTPUT_VALUE } from "./trace-attributes.js";
|
|
39
39
|
import { n as extractUsageFromSse, t as extractUsage } from "./extract-usage-BZLU01kR.js";
|
|
40
40
|
import { n as InMemoryRawProviderSink, r as NoopRawProviderSink, t as FileSystemRawProviderSink } from "./raw-provider-sink-75w4FWBj.js";
|
|
41
|
-
import { _ as exportRunAsOtlp, b as captureFetchToRawSink, c as describeTraceInsightScope, g as analyzeTraces, h as tokenizeDomainWords, l as domainEvidencePattern, m as scoreTraceInsightReadiness, n as toolSpansToTraceAnalysisStore, o as buildTraceInsightContext, s as buildTraceInsightPrompt, u as inferDomainKeywords } from "./store-tool-spans-
|
|
41
|
+
import { _ as exportRunAsOtlp, b as captureFetchToRawSink, c as describeTraceInsightScope, g as analyzeTraces, h as tokenizeDomainWords, l as domainEvidencePattern, m as scoreTraceInsightReadiness, n as toolSpansToTraceAnalysisStore, o as buildTraceInsightContext, s as buildTraceInsightPrompt, u as inferDomainKeywords } from "./store-tool-spans-DIUgZbzu.js";
|
|
42
42
|
import { t as TraceEmitter } from "./emitter-DbMXUIVP.js";
|
|
43
43
|
import { n as assertRunCaptured, t as RunIntegrityError } from "./integrity-W4CADcFc.js";
|
|
44
44
|
import { n as InMemoryTraceStore, t as FileSystemTraceStore } from "./store-BhNuLdJw.js";
|
|
@@ -46,19 +46,19 @@ import { t as packageVersion$1 } from "./package-version-D7lQHt_-.js";
|
|
|
46
46
|
import { t as buildTrajectory } from "./trajectory-D_7rLrvE.js";
|
|
47
47
|
import { i as failureBlame, n as classifyFailure, r as classifyFailureReason } from "./failure-taxonomy-Bx5oWqaW.js";
|
|
48
48
|
import { n as runBoundedProcess, t as DEFAULT_BOUNDED_PROCESS_TIMEOUT_MS } from "./bounded-process-Cj9YjXbE.js";
|
|
49
|
-
import { t as runEvalCampaign } from "./eval-campaign-
|
|
50
|
-
import "./rollout-
|
|
51
|
-
import { t as mintRolloutRows } from "./mint-
|
|
49
|
+
import { t as runEvalCampaign } from "./eval-campaign-BUMIxKTE.js";
|
|
50
|
+
import "./rollout-Dd1ucT_M.js";
|
|
51
|
+
import { t as mintRolloutRows } from "./mint-CbdwjTPW.js";
|
|
52
52
|
import { n as pairedEvalueSequence, t as evaluateInterimReleaseConfidence } from "./sequential-BVv1sjsw.js";
|
|
53
|
-
import { a as maximumChargeForLlmRequest, c as ModelSubstitutionError, f as assertServedModels, g as judgeFamily, h as assertCrossFamily, i as costReceiptFromLlmError, l as assertCrossFamilyServed, m as CrossFamilyError, o as backoffMs, p as checkServedModel, r as costReceiptFromLlm, s as isTransientLlmError, u as assertServedModel } from "./llm-client-
|
|
54
|
-
import { n as paidJsonChat } from "./chat-json-call-
|
|
55
|
-
import { t as createDspyRlmTraceEngine } from "./dspy-rlm-engine-
|
|
56
|
-
import { n as diffFindings, r as createChatTraceEngine, t as FindingsStore } from "./findings-store-
|
|
53
|
+
import { a as maximumChargeForLlmRequest, c as ModelSubstitutionError, f as assertServedModels, g as judgeFamily, h as assertCrossFamily, i as costReceiptFromLlmError, l as assertCrossFamilyServed, m as CrossFamilyError, o as backoffMs, p as checkServedModel, r as costReceiptFromLlm, s as isTransientLlmError, u as assertServedModel } from "./llm-client-DXuOTseU.js";
|
|
54
|
+
import { n as paidJsonChat } from "./chat-json-call-BrZKn0L3.js";
|
|
55
|
+
import { t as createDspyRlmTraceEngine } from "./dspy-rlm-engine-Bn_Mt_LW.js";
|
|
56
|
+
import { n as diffFindings, r as createChatTraceEngine, t as FindingsStore } from "./findings-store-CvNo712L.js";
|
|
57
57
|
import { a as budgetBreachView, i as failureClusterView, n as computeToolUseMetrics, r as judgeAgreementView, t as toolWasteView } from "./tool-waste-DLsjS_p-.js";
|
|
58
58
|
import { a as judgeGateDecision, c as snapshotFromJudgeAgreement, g as analyzeSeries, i as assertJudgeMayGate, n as JudgeGateRefusedError, o as measureJudgeAgreement, r as addCalibrationVerdicts, s as registerCalibrationSet, t as DEFAULT_JUDGE_GATE_POLICY } from "./judge-gate-Co5tuh57.js";
|
|
59
|
-
import { a as spanRecordsToTraceAnalysisStore, i as otlpTextToTraceAnalysisStore, r as OtlpFileTraceStore } from "./store-otlp-
|
|
59
|
+
import { a as spanRecordsToTraceAnalysisStore, i as otlpTextToTraceAnalysisStore, r as OtlpFileTraceStore } from "./store-otlp-dyWE3wAG.js";
|
|
60
60
|
import { n as bootstrapCi, t as evaluateReleaseConfidence } from "./release-confidence-CYIFH-fp.js";
|
|
61
|
-
import { t as createChatClient } from "./chat-client-
|
|
61
|
+
import { t as createChatClient } from "./chat-client-CMQ8_h4J.js";
|
|
62
62
|
import { createHash } from "node:crypto";
|
|
63
63
|
import { accessSync, appendFileSync, constants, cpSync, existsSync, mkdirSync, promises, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
64
64
|
import { basename, delimiter, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
@@ -3738,7 +3738,6 @@ function observeAll(detectors, event) {
|
|
|
3738
3738
|
//#region src/control-runtime.ts
|
|
3739
3739
|
async function runAgentControlLoop(config) {
|
|
3740
3740
|
const budget = normalizeBudget(config.budget);
|
|
3741
|
-
const actionFailure = config.actionFailure ?? "continue";
|
|
3742
3741
|
const controller = new AbortController();
|
|
3743
3742
|
const upstreamAbort = () => controller.abort(config.signal?.reason);
|
|
3744
3743
|
if (config.signal) {
|
|
@@ -3747,473 +3746,51 @@ async function runAgentControlLoop(config) {
|
|
|
3747
3746
|
}
|
|
3748
3747
|
const started = Date.now();
|
|
3749
3748
|
const wallTimer = budget.maxWallMs ? setTimeout(() => controller.abort(/* @__PURE__ */ new Error("control runtime wall timeout")), budget.maxWallMs) : void 0;
|
|
3750
|
-
const
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3749
|
+
const run = {
|
|
3750
|
+
config,
|
|
3751
|
+
budget,
|
|
3752
|
+
signal: controller.signal,
|
|
3753
|
+
started,
|
|
3754
|
+
history: [],
|
|
3755
|
+
emitter: config.store ? new TraceEmitter(config.store, { onCaptureError: () => void 0 }) : void 0,
|
|
3756
|
+
runtimeErrors: [],
|
|
3757
|
+
repeatedDetector: repeatedActionDetector({ maxRepeated: config.stopPolicies?.maxRepeatedActions ?? 0 }),
|
|
3758
|
+
progressDetector: noProgressDetector({
|
|
3759
|
+
maxNoProgress: config.stopPolicies?.maxNoProgressSteps ?? 0,
|
|
3760
|
+
minScoreDelta: config.stopPolicies?.minScoreDelta ?? .001
|
|
3761
|
+
}),
|
|
3762
|
+
spentCostUsd: 0,
|
|
3763
|
+
state: void 0,
|
|
3764
|
+
evals: []
|
|
3765
|
+
};
|
|
3759
3766
|
try {
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
intent: config.intent.slice(0, 120),
|
|
3767
|
-
maxSteps: String(budget.maxSteps),
|
|
3768
|
-
...budget.maxCostUsd !== void 0 ? { maxCostUsd: String(budget.maxCostUsd) } : {}
|
|
3769
|
-
}
|
|
3770
|
-
}));
|
|
3771
|
-
let state;
|
|
3772
|
-
let evals;
|
|
3773
|
-
try {
|
|
3774
|
-
state = await config.observe({
|
|
3775
|
-
history,
|
|
3776
|
-
abortSignal: controller.signal
|
|
3777
|
-
});
|
|
3778
|
-
} catch (err) {
|
|
3779
|
-
const error = runtimeError("observe", 0, err);
|
|
3780
|
-
runtimeErrors.push(error);
|
|
3781
|
-
return finish(emitter, {
|
|
3782
|
-
intent: config.intent,
|
|
3783
|
-
pass: false,
|
|
3784
|
-
completed: false,
|
|
3785
|
-
reason: error.message,
|
|
3786
|
-
steps: history,
|
|
3787
|
-
finalState: void 0,
|
|
3788
|
-
finalEvals: [],
|
|
3789
|
-
wallMs: Date.now() - started,
|
|
3790
|
-
spentCostUsd,
|
|
3791
|
-
runId: emitter?.runId ?? null,
|
|
3792
|
-
failureClass: "unknown",
|
|
3793
|
-
runtimeErrors,
|
|
3794
|
-
stoppedBy: "runtime-error"
|
|
3795
|
-
});
|
|
3796
|
-
}
|
|
3797
|
-
try {
|
|
3798
|
-
evals = await config.validate({
|
|
3799
|
-
intent: config.intent,
|
|
3800
|
-
state,
|
|
3801
|
-
history,
|
|
3802
|
-
abortSignal: controller.signal
|
|
3803
|
-
});
|
|
3804
|
-
await recordEvalSpans(emitter, evals, "initial", runtimeErrors, 0);
|
|
3805
|
-
} catch (err) {
|
|
3806
|
-
const error = runtimeError("validate", 0, err);
|
|
3807
|
-
runtimeErrors.push(error);
|
|
3808
|
-
return finish(emitter, {
|
|
3809
|
-
intent: config.intent,
|
|
3810
|
-
pass: false,
|
|
3811
|
-
completed: false,
|
|
3812
|
-
reason: error.message,
|
|
3813
|
-
steps: history,
|
|
3814
|
-
finalState: state,
|
|
3815
|
-
finalEvals: [],
|
|
3816
|
-
wallMs: Date.now() - started,
|
|
3817
|
-
spentCostUsd,
|
|
3818
|
-
runId: emitter?.runId ?? null,
|
|
3819
|
-
failureClass: "unknown",
|
|
3820
|
-
runtimeErrors,
|
|
3821
|
-
stoppedBy: "runtime-error"
|
|
3822
|
-
});
|
|
3823
|
-
}
|
|
3824
|
-
progressDetector.observe({
|
|
3825
|
-
stateFingerprint: fingerprintState(state, config.stopPolicies),
|
|
3826
|
-
score: averageScore(evals)
|
|
3767
|
+
await startTrace(run);
|
|
3768
|
+
const failedStart = await observeInitial(run);
|
|
3769
|
+
if (failedStart) return failedStart;
|
|
3770
|
+
run.progressDetector.observe({
|
|
3771
|
+
stateFingerprint: fingerprintState(run.state, config.stopPolicies),
|
|
3772
|
+
score: averageScore(run.evals)
|
|
3827
3773
|
});
|
|
3828
3774
|
for (let stepIndex = 0; stepIndex < budget.maxSteps; stepIndex++) {
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
pass: false,
|
|
3832
|
-
completed: false,
|
|
3833
|
-
reason: abortReason(controller.signal),
|
|
3834
|
-
score: void 0,
|
|
3835
|
-
steps: history,
|
|
3836
|
-
finalState: state,
|
|
3837
|
-
finalEvals: evals,
|
|
3838
|
-
wallMs: Date.now() - started,
|
|
3839
|
-
spentCostUsd,
|
|
3840
|
-
runId: emitter?.runId ?? null,
|
|
3841
|
-
failureClass: "timeout",
|
|
3842
|
-
runtimeErrors,
|
|
3843
|
-
stoppedBy: "abort"
|
|
3844
|
-
});
|
|
3845
|
-
const budgetStop = budgetStopDecision(budget, spentCostUsd);
|
|
3846
|
-
if (budgetStop.stop) return finish(emitter, {
|
|
3847
|
-
intent: config.intent,
|
|
3848
|
-
pass: false,
|
|
3849
|
-
completed: false,
|
|
3850
|
-
reason: budgetStop.reason,
|
|
3851
|
-
score: averageScore(evals),
|
|
3852
|
-
steps: history,
|
|
3853
|
-
finalState: state,
|
|
3854
|
-
finalEvals: evals,
|
|
3855
|
-
wallMs: Date.now() - started,
|
|
3856
|
-
spentCostUsd,
|
|
3857
|
-
runId: emitter?.runId ?? null,
|
|
3858
|
-
failureClass: "budget_exceeded",
|
|
3859
|
-
runtimeErrors,
|
|
3860
|
-
stoppedBy: "budget"
|
|
3861
|
-
});
|
|
3862
|
-
const ctx = makeContext(config.intent, state, evals, history, budget, stepIndex, started, spentCostUsd, controller.signal, emitter);
|
|
3863
|
-
let stop;
|
|
3864
|
-
try {
|
|
3865
|
-
stop = config.shouldStop ? await config.shouldStop(ctx) : defaultStopDecision(evals);
|
|
3866
|
-
} catch (err) {
|
|
3867
|
-
runtimeErrors.push(runtimeError("stop-policy", stepIndex, err));
|
|
3868
|
-
return finish(emitter, {
|
|
3869
|
-
intent: config.intent,
|
|
3870
|
-
pass: false,
|
|
3871
|
-
completed: false,
|
|
3872
|
-
reason: runtimeErrors[runtimeErrors.length - 1].message,
|
|
3873
|
-
score: averageScore(evals),
|
|
3874
|
-
steps: history,
|
|
3875
|
-
finalState: state,
|
|
3876
|
-
finalEvals: evals,
|
|
3877
|
-
wallMs: Date.now() - started,
|
|
3878
|
-
spentCostUsd,
|
|
3879
|
-
runId: emitter?.runId ?? null,
|
|
3880
|
-
failureClass: "unknown",
|
|
3881
|
-
runtimeErrors,
|
|
3882
|
-
stoppedBy: "runtime-error"
|
|
3883
|
-
});
|
|
3884
|
-
}
|
|
3885
|
-
if (stop.stop) return finish(emitter, {
|
|
3886
|
-
intent: config.intent,
|
|
3887
|
-
pass: stop.pass,
|
|
3888
|
-
completed: true,
|
|
3889
|
-
reason: stop.reason,
|
|
3890
|
-
score: stop.score,
|
|
3891
|
-
steps: history,
|
|
3892
|
-
finalState: state,
|
|
3893
|
-
finalEvals: evals,
|
|
3894
|
-
wallMs: Date.now() - started,
|
|
3895
|
-
spentCostUsd,
|
|
3896
|
-
runId: emitter?.runId ?? null,
|
|
3897
|
-
failureClass: stop.failureClass,
|
|
3898
|
-
runtimeErrors,
|
|
3899
|
-
stoppedBy: "stop-policy"
|
|
3900
|
-
});
|
|
3901
|
-
let decision;
|
|
3902
|
-
try {
|
|
3903
|
-
decision = await config.decide(ctx);
|
|
3904
|
-
} catch (err) {
|
|
3905
|
-
runtimeErrors.push(runtimeError("decide", stepIndex, err));
|
|
3906
|
-
return finish(emitter, {
|
|
3907
|
-
intent: config.intent,
|
|
3908
|
-
pass: false,
|
|
3909
|
-
completed: false,
|
|
3910
|
-
reason: runtimeErrors[runtimeErrors.length - 1].message,
|
|
3911
|
-
score: averageScore(evals),
|
|
3912
|
-
steps: history,
|
|
3913
|
-
finalState: state,
|
|
3914
|
-
finalEvals: evals,
|
|
3915
|
-
wallMs: Date.now() - started,
|
|
3916
|
-
spentCostUsd,
|
|
3917
|
-
runId: emitter?.runId ?? null,
|
|
3918
|
-
failureClass: "unknown",
|
|
3919
|
-
runtimeErrors,
|
|
3920
|
-
stoppedBy: "runtime-error"
|
|
3921
|
-
});
|
|
3922
|
-
}
|
|
3923
|
-
if (decision.type === "stop") {
|
|
3924
|
-
const pass = decision.pass ?? false;
|
|
3925
|
-
return finish(emitter, {
|
|
3926
|
-
intent: config.intent,
|
|
3927
|
-
pass,
|
|
3928
|
-
completed: true,
|
|
3929
|
-
reason: decision.reason,
|
|
3930
|
-
score: decision.score,
|
|
3931
|
-
steps: history,
|
|
3932
|
-
finalState: state,
|
|
3933
|
-
finalEvals: evals,
|
|
3934
|
-
wallMs: Date.now() - started,
|
|
3935
|
-
spentCostUsd,
|
|
3936
|
-
runId: emitter?.runId ?? null,
|
|
3937
|
-
failureClass: pass ? void 0 : decision.failureClass ?? "unknown",
|
|
3938
|
-
runtimeErrors,
|
|
3939
|
-
stoppedBy: "policy"
|
|
3940
|
-
});
|
|
3941
|
-
}
|
|
3942
|
-
const actionFingerprint = fingerprintAction(decision.action, config.stopPolicies);
|
|
3943
|
-
const repeatedActionSignal = repeatedDetector.observe({ actionFingerprint });
|
|
3944
|
-
const repeatedActionStreak = repeatedDetector.streak;
|
|
3945
|
-
if (repeatedActionSignal) return finish(emitter, {
|
|
3946
|
-
intent: config.intent,
|
|
3947
|
-
pass: false,
|
|
3948
|
-
completed: true,
|
|
3949
|
-
reason: repeatedActionSignal.reason,
|
|
3950
|
-
score: averageScore(evals),
|
|
3951
|
-
steps: history,
|
|
3952
|
-
finalState: state,
|
|
3953
|
-
finalEvals: evals,
|
|
3954
|
-
wallMs: Date.now() - started,
|
|
3955
|
-
spentCostUsd,
|
|
3956
|
-
runId: emitter?.runId ?? null,
|
|
3957
|
-
failureClass: "tool_recovery_failure",
|
|
3958
|
-
runtimeErrors,
|
|
3959
|
-
stoppedBy: "stop-policy"
|
|
3960
|
-
});
|
|
3961
|
-
const beforeState = state;
|
|
3962
|
-
const evalsBefore = evals;
|
|
3963
|
-
const scoreBefore = averageScore(evals);
|
|
3964
|
-
const actionStarted = Date.now();
|
|
3965
|
-
const stepHandle = emitter ? await runTrace(emitter, runtimeErrors, stepIndex, () => emitter.tool({
|
|
3966
|
-
name: `control-step-${stepIndex}`,
|
|
3967
|
-
toolName: "agent-control-action",
|
|
3968
|
-
args: decision.action,
|
|
3969
|
-
attributes: {
|
|
3970
|
-
decision: decision.reason ?? "continue",
|
|
3971
|
-
repeatedActionStreak
|
|
3972
|
-
}
|
|
3973
|
-
})) : void 0;
|
|
3974
|
-
let actionOutcome;
|
|
3975
|
-
try {
|
|
3976
|
-
const result = await config.act(decision.action, ctx);
|
|
3977
|
-
const rawCostUsd = config.getActionCostUsd?.({
|
|
3978
|
-
action: decision.action,
|
|
3979
|
-
result,
|
|
3980
|
-
state,
|
|
3981
|
-
evals,
|
|
3982
|
-
history
|
|
3983
|
-
});
|
|
3984
|
-
const costUsd = normalizeActionCostUsd(rawCostUsd, runtimeErrors, stepIndex);
|
|
3985
|
-
if (costUsd !== void 0 && Number.isFinite(costUsd) && costUsd > 0) {
|
|
3986
|
-
spentCostUsd += costUsd;
|
|
3987
|
-
await recordCostBudget(emitter, budget, spentCostUsd, stepHandle, runtimeErrors, stepIndex);
|
|
3988
|
-
}
|
|
3989
|
-
actionOutcome = {
|
|
3990
|
-
ok: true,
|
|
3991
|
-
result,
|
|
3992
|
-
...costUsd !== void 0 ? { costUsd } : {},
|
|
3993
|
-
durationMs: Date.now() - actionStarted
|
|
3994
|
-
};
|
|
3995
|
-
} catch (err) {
|
|
3996
|
-
runtimeErrors.push(runtimeError("act", stepIndex, err));
|
|
3997
|
-
actionOutcome = {
|
|
3998
|
-
ok: false,
|
|
3999
|
-
error: runtimeErrors[runtimeErrors.length - 1].message,
|
|
4000
|
-
durationMs: Date.now() - actionStarted
|
|
4001
|
-
};
|
|
4002
|
-
if (actionFailure === "stop") {
|
|
4003
|
-
await runTrace(emitter, runtimeErrors, stepIndex, () => stepHandle?.fail(actionOutcome.error ?? "action failed"));
|
|
4004
|
-
const step = {
|
|
4005
|
-
index: stepIndex,
|
|
4006
|
-
decision,
|
|
4007
|
-
beforeState,
|
|
4008
|
-
afterState: state,
|
|
4009
|
-
evalsBefore,
|
|
4010
|
-
evalsAfter: evals,
|
|
4011
|
-
actionOutcome,
|
|
4012
|
-
startedAt: new Date(actionStarted).toISOString(),
|
|
4013
|
-
endedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4014
|
-
};
|
|
4015
|
-
history.push(step);
|
|
4016
|
-
await runOnStep(config.onStep, step, runtimeErrors);
|
|
4017
|
-
return finish(emitter, {
|
|
4018
|
-
intent: config.intent,
|
|
4019
|
-
pass: false,
|
|
4020
|
-
completed: false,
|
|
4021
|
-
reason: actionOutcome.error ?? "action failed",
|
|
4022
|
-
score: averageScore(evals),
|
|
4023
|
-
steps: history,
|
|
4024
|
-
finalState: state,
|
|
4025
|
-
finalEvals: evals,
|
|
4026
|
-
wallMs: Date.now() - started,
|
|
4027
|
-
spentCostUsd,
|
|
4028
|
-
runId: emitter?.runId ?? null,
|
|
4029
|
-
failureClass: "unknown",
|
|
4030
|
-
runtimeErrors,
|
|
4031
|
-
stoppedBy: "runtime-error"
|
|
4032
|
-
});
|
|
4033
|
-
}
|
|
4034
|
-
}
|
|
4035
|
-
let observationPhase = "observe";
|
|
4036
|
-
try {
|
|
4037
|
-
state = await config.observe({
|
|
4038
|
-
history,
|
|
4039
|
-
abortSignal: controller.signal
|
|
4040
|
-
});
|
|
4041
|
-
observationPhase = "validate";
|
|
4042
|
-
evals = await config.validate({
|
|
4043
|
-
intent: config.intent,
|
|
4044
|
-
state,
|
|
4045
|
-
history,
|
|
4046
|
-
abortSignal: controller.signal
|
|
4047
|
-
});
|
|
4048
|
-
await recordEvalSpans(emitter, evals, `step-${stepIndex}`, runtimeErrors, stepIndex, stepHandle?.span.spanId);
|
|
4049
|
-
} catch (err) {
|
|
4050
|
-
runtimeErrors.push(runtimeError(observationPhase, stepIndex, err));
|
|
4051
|
-
const afterState = observationPhase === "observe" ? beforeState : state;
|
|
4052
|
-
const step = {
|
|
4053
|
-
index: stepIndex,
|
|
4054
|
-
decision,
|
|
4055
|
-
beforeState,
|
|
4056
|
-
afterState,
|
|
4057
|
-
evalsBefore,
|
|
4058
|
-
evalsAfter: evals,
|
|
4059
|
-
actionOutcome,
|
|
4060
|
-
startedAt: new Date(actionStarted).toISOString(),
|
|
4061
|
-
endedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4062
|
-
};
|
|
4063
|
-
history.push(step);
|
|
4064
|
-
await runTrace(emitter, runtimeErrors, stepIndex, () => stepHandle?.fail(runtimeErrors[runtimeErrors.length - 1].message));
|
|
4065
|
-
await runOnStep(config.onStep, step, runtimeErrors);
|
|
4066
|
-
return finish(emitter, {
|
|
4067
|
-
intent: config.intent,
|
|
4068
|
-
pass: false,
|
|
4069
|
-
completed: false,
|
|
4070
|
-
reason: runtimeErrors[runtimeErrors.length - 1].message,
|
|
4071
|
-
score: averageScore(evals),
|
|
4072
|
-
steps: history,
|
|
4073
|
-
finalState: afterState,
|
|
4074
|
-
finalEvals: evals,
|
|
4075
|
-
wallMs: Date.now() - started,
|
|
4076
|
-
spentCostUsd,
|
|
4077
|
-
runId: emitter?.runId ?? null,
|
|
4078
|
-
failureClass: "unknown",
|
|
4079
|
-
runtimeErrors,
|
|
4080
|
-
stoppedBy: "runtime-error"
|
|
4081
|
-
});
|
|
4082
|
-
}
|
|
4083
|
-
const scoreAfter = averageScore(evals);
|
|
4084
|
-
const stateFingerprint = fingerprintState(state, config.stopPolicies);
|
|
4085
|
-
const noProgressSignal = progressDetector.observe({
|
|
4086
|
-
stateFingerprint,
|
|
4087
|
-
score: scoreAfter
|
|
4088
|
-
});
|
|
4089
|
-
const noProgressStreak = progressDetector.streak;
|
|
4090
|
-
const step = {
|
|
4091
|
-
index: stepIndex,
|
|
4092
|
-
decision,
|
|
4093
|
-
beforeState,
|
|
4094
|
-
afterState: state,
|
|
4095
|
-
evalsBefore,
|
|
4096
|
-
evalsAfter: evals,
|
|
4097
|
-
actionOutcome,
|
|
4098
|
-
startedAt: new Date(actionStarted).toISOString(),
|
|
4099
|
-
endedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4100
|
-
};
|
|
4101
|
-
history.push(step);
|
|
4102
|
-
if (actionOutcome.ok) await runTrace(emitter, runtimeErrors, stepIndex, () => stepHandle?.end({ attributes: {
|
|
4103
|
-
actionCostUsd: actionOutcome.costUsd ?? null,
|
|
4104
|
-
spentCostUsd,
|
|
4105
|
-
scoreBefore: scoreBefore ?? null,
|
|
4106
|
-
scoreAfter: scoreAfter ?? null,
|
|
4107
|
-
noProgressStreak
|
|
4108
|
-
} }));
|
|
4109
|
-
else await runTrace(emitter, runtimeErrors, stepIndex, () => stepHandle?.fail(actionOutcome.error ?? "action failed", { attributes: {
|
|
4110
|
-
spentCostUsd,
|
|
4111
|
-
noProgressStreak
|
|
4112
|
-
} }));
|
|
4113
|
-
await runOnStep(config.onStep, step, runtimeErrors);
|
|
4114
|
-
if (noProgressSignal) return finish(emitter, {
|
|
4115
|
-
intent: config.intent,
|
|
4116
|
-
pass: false,
|
|
4117
|
-
completed: true,
|
|
4118
|
-
reason: noProgressSignal.reason,
|
|
4119
|
-
score: scoreAfter,
|
|
4120
|
-
steps: history,
|
|
4121
|
-
finalState: state,
|
|
4122
|
-
finalEvals: evals,
|
|
4123
|
-
wallMs: Date.now() - started,
|
|
4124
|
-
spentCostUsd,
|
|
4125
|
-
runId: emitter?.runId ?? null,
|
|
4126
|
-
failureClass: "tool_recovery_failure",
|
|
4127
|
-
runtimeErrors,
|
|
4128
|
-
stoppedBy: "stop-policy"
|
|
4129
|
-
});
|
|
4130
|
-
const postStepBudgetStop = budgetStopDecision(budget, spentCostUsd);
|
|
4131
|
-
if (postStepBudgetStop.stop) return finish(emitter, {
|
|
4132
|
-
intent: config.intent,
|
|
4133
|
-
pass: false,
|
|
4134
|
-
completed: false,
|
|
4135
|
-
reason: postStepBudgetStop.reason,
|
|
4136
|
-
score: scoreAfter,
|
|
4137
|
-
steps: history,
|
|
4138
|
-
finalState: state,
|
|
4139
|
-
finalEvals: evals,
|
|
4140
|
-
wallMs: Date.now() - started,
|
|
4141
|
-
spentCostUsd,
|
|
4142
|
-
runId: emitter?.runId ?? null,
|
|
4143
|
-
failureClass: "budget_exceeded",
|
|
4144
|
-
runtimeErrors,
|
|
4145
|
-
stoppedBy: "budget"
|
|
4146
|
-
});
|
|
4147
|
-
const postStepCtx = makeContext(config.intent, state, evals, history, budget, stepIndex + 1, started, spentCostUsd, controller.signal, emitter);
|
|
4148
|
-
let postStepStop;
|
|
4149
|
-
try {
|
|
4150
|
-
postStepStop = config.shouldStop ? await config.shouldStop(postStepCtx) : defaultStopDecision(evals);
|
|
4151
|
-
} catch (err) {
|
|
4152
|
-
runtimeErrors.push(runtimeError("stop-policy", stepIndex + 1, err));
|
|
4153
|
-
return finish(emitter, {
|
|
4154
|
-
intent: config.intent,
|
|
4155
|
-
pass: false,
|
|
4156
|
-
completed: false,
|
|
4157
|
-
reason: runtimeErrors[runtimeErrors.length - 1].message,
|
|
4158
|
-
score: averageScore(evals),
|
|
4159
|
-
steps: history,
|
|
4160
|
-
finalState: state,
|
|
4161
|
-
finalEvals: evals,
|
|
4162
|
-
wallMs: Date.now() - started,
|
|
4163
|
-
spentCostUsd,
|
|
4164
|
-
runId: emitter?.runId ?? null,
|
|
4165
|
-
failureClass: "unknown",
|
|
4166
|
-
runtimeErrors,
|
|
4167
|
-
stoppedBy: "runtime-error"
|
|
4168
|
-
});
|
|
4169
|
-
}
|
|
4170
|
-
if (postStepStop.stop) return finish(emitter, {
|
|
4171
|
-
intent: config.intent,
|
|
4172
|
-
pass: postStepStop.pass,
|
|
4173
|
-
completed: true,
|
|
4174
|
-
reason: postStepStop.reason,
|
|
4175
|
-
score: postStepStop.score,
|
|
4176
|
-
steps: history,
|
|
4177
|
-
finalState: state,
|
|
4178
|
-
finalEvals: evals,
|
|
4179
|
-
wallMs: Date.now() - started,
|
|
4180
|
-
spentCostUsd,
|
|
4181
|
-
runId: emitter?.runId ?? null,
|
|
4182
|
-
failureClass: postStepStop.failureClass,
|
|
4183
|
-
runtimeErrors,
|
|
4184
|
-
stoppedBy: "stop-policy"
|
|
4185
|
-
});
|
|
3775
|
+
const ended = await runStep(run, stepIndex);
|
|
3776
|
+
if (ended) return ended;
|
|
4186
3777
|
}
|
|
4187
|
-
return
|
|
4188
|
-
intent: config.intent,
|
|
3778
|
+
return settle(run, {
|
|
4189
3779
|
pass: false,
|
|
4190
3780
|
completed: false,
|
|
4191
3781
|
reason: `budget exhausted: maxSteps=${budget.maxSteps}`,
|
|
4192
|
-
steps: history,
|
|
4193
|
-
finalState: state,
|
|
4194
|
-
finalEvals: evals,
|
|
4195
|
-
wallMs: Date.now() - started,
|
|
4196
|
-
spentCostUsd,
|
|
4197
|
-
runId: emitter?.runId ?? null,
|
|
4198
3782
|
failureClass: "budget_exceeded",
|
|
4199
|
-
runtimeErrors,
|
|
4200
3783
|
stoppedBy: "budget"
|
|
4201
3784
|
});
|
|
4202
3785
|
} catch (err) {
|
|
4203
|
-
runtimeErrors.push(runtimeError("act", history.length, err));
|
|
4204
|
-
return
|
|
4205
|
-
intent: config.intent,
|
|
3786
|
+
run.runtimeErrors.push(runtimeError("act", run.history.length, err));
|
|
3787
|
+
return settle(run, {
|
|
4206
3788
|
pass: false,
|
|
4207
3789
|
completed: false,
|
|
4208
|
-
reason:
|
|
4209
|
-
steps: history,
|
|
3790
|
+
reason: lastErrorMessage(run),
|
|
4210
3791
|
finalState: void 0,
|
|
4211
3792
|
finalEvals: [],
|
|
4212
|
-
wallMs: Date.now() - started,
|
|
4213
|
-
spentCostUsd,
|
|
4214
|
-
runId: emitter?.runId ?? null,
|
|
4215
3793
|
failureClass: "unknown",
|
|
4216
|
-
runtimeErrors,
|
|
4217
3794
|
stoppedBy: "runtime-error"
|
|
4218
3795
|
});
|
|
4219
3796
|
} finally {
|
|
@@ -4221,6 +3798,349 @@ async function runAgentControlLoop(config) {
|
|
|
4221
3798
|
if (config.signal) config.signal.removeEventListener("abort", upstreamAbort);
|
|
4222
3799
|
}
|
|
4223
3800
|
}
|
|
3801
|
+
/** End the run with `how`; everything not named there is read from the run as it stands now. */
|
|
3802
|
+
function settle(run, how) {
|
|
3803
|
+
return finish(run.emitter, {
|
|
3804
|
+
intent: run.config.intent,
|
|
3805
|
+
pass: how.pass,
|
|
3806
|
+
completed: how.completed,
|
|
3807
|
+
reason: how.reason,
|
|
3808
|
+
..."score" in how ? { score: how.score } : {},
|
|
3809
|
+
steps: run.history,
|
|
3810
|
+
finalState: "finalState" in how ? how.finalState : run.state,
|
|
3811
|
+
finalEvals: how.finalEvals ?? run.evals,
|
|
3812
|
+
wallMs: Date.now() - run.started,
|
|
3813
|
+
spentCostUsd: run.spentCostUsd,
|
|
3814
|
+
runId: run.emitter?.runId ?? null,
|
|
3815
|
+
failureClass: how.failureClass,
|
|
3816
|
+
runtimeErrors: run.runtimeErrors,
|
|
3817
|
+
stoppedBy: how.stoppedBy
|
|
3818
|
+
});
|
|
3819
|
+
}
|
|
3820
|
+
function lastErrorMessage(run) {
|
|
3821
|
+
return run.runtimeErrors[run.runtimeErrors.length - 1].message;
|
|
3822
|
+
}
|
|
3823
|
+
/** End the run on the runtime error just recorded. */
|
|
3824
|
+
function settleOnRuntimeError(run, finalState) {
|
|
3825
|
+
return settle(run, {
|
|
3826
|
+
pass: false,
|
|
3827
|
+
completed: false,
|
|
3828
|
+
reason: lastErrorMessage(run),
|
|
3829
|
+
score: averageScore(run.evals),
|
|
3830
|
+
...finalState ? { finalState: finalState.value } : {},
|
|
3831
|
+
failureClass: "unknown",
|
|
3832
|
+
stoppedBy: "runtime-error"
|
|
3833
|
+
});
|
|
3834
|
+
}
|
|
3835
|
+
async function startTrace(run) {
|
|
3836
|
+
const { emitter, config, budget } = run;
|
|
3837
|
+
if (!emitter) return;
|
|
3838
|
+
await runTrace(emitter, run.runtimeErrors, 0, () => emitter.startRun({
|
|
3839
|
+
scenarioId: config.scenarioId ?? "agent-control-loop",
|
|
3840
|
+
projectId: config.projectId,
|
|
3841
|
+
variantId: config.variantId,
|
|
3842
|
+
layer: "meta",
|
|
3843
|
+
tags: {
|
|
3844
|
+
intent: config.intent.slice(0, 120),
|
|
3845
|
+
maxSteps: String(budget.maxSteps),
|
|
3846
|
+
...budget.maxCostUsd !== void 0 ? { maxCostUsd: String(budget.maxCostUsd) } : {}
|
|
3847
|
+
}
|
|
3848
|
+
}));
|
|
3849
|
+
}
|
|
3850
|
+
/** The first observation and validation. Returns the result that ends the run when either fails. */
|
|
3851
|
+
async function observeInitial(run) {
|
|
3852
|
+
try {
|
|
3853
|
+
run.state = await run.config.observe({
|
|
3854
|
+
history: run.history,
|
|
3855
|
+
abortSignal: run.signal
|
|
3856
|
+
});
|
|
3857
|
+
} catch (err) {
|
|
3858
|
+
const error = runtimeError("observe", 0, err);
|
|
3859
|
+
run.runtimeErrors.push(error);
|
|
3860
|
+
return settle(run, {
|
|
3861
|
+
pass: false,
|
|
3862
|
+
completed: false,
|
|
3863
|
+
reason: error.message,
|
|
3864
|
+
failureClass: "unknown",
|
|
3865
|
+
stoppedBy: "runtime-error"
|
|
3866
|
+
});
|
|
3867
|
+
}
|
|
3868
|
+
try {
|
|
3869
|
+
run.evals = await run.config.validate({
|
|
3870
|
+
intent: run.config.intent,
|
|
3871
|
+
state: run.state,
|
|
3872
|
+
history: run.history,
|
|
3873
|
+
abortSignal: run.signal
|
|
3874
|
+
});
|
|
3875
|
+
await recordEvalSpans(run.emitter, run.evals, "initial", run.runtimeErrors, 0);
|
|
3876
|
+
} catch (err) {
|
|
3877
|
+
const error = runtimeError("validate", 0, err);
|
|
3878
|
+
run.runtimeErrors.push(error);
|
|
3879
|
+
return settle(run, {
|
|
3880
|
+
pass: false,
|
|
3881
|
+
completed: false,
|
|
3882
|
+
reason: error.message,
|
|
3883
|
+
finalEvals: [],
|
|
3884
|
+
failureClass: "unknown",
|
|
3885
|
+
stoppedBy: "runtime-error"
|
|
3886
|
+
});
|
|
3887
|
+
}
|
|
3888
|
+
}
|
|
3889
|
+
/** One decide-act-observe step. Returns the result that ends the run, or nothing to go on. */
|
|
3890
|
+
async function runStep(run, stepIndex) {
|
|
3891
|
+
const halted = await checkAbortAndBudget(run);
|
|
3892
|
+
if (halted) return halted;
|
|
3893
|
+
const ctx = makeRunContext(run, stepIndex);
|
|
3894
|
+
const stopped = await checkStopPolicy(run, ctx, stepIndex);
|
|
3895
|
+
if (stopped) return stopped;
|
|
3896
|
+
const chosen = await decideAction(run, ctx, stepIndex);
|
|
3897
|
+
if ("ended" in chosen) return chosen.ended;
|
|
3898
|
+
const { decision } = chosen.next;
|
|
3899
|
+
const repeated = await detectRepeatedAction(run, decision);
|
|
3900
|
+
if ("ended" in repeated) return repeated.ended;
|
|
3901
|
+
const attempt = await attemptAction(run, ctx, decision, stepIndex, repeated.next);
|
|
3902
|
+
if ("ended" in attempt) return attempt.ended;
|
|
3903
|
+
const observed = await observeAfterAction(run, attempt.next, stepIndex);
|
|
3904
|
+
if (observed) return observed;
|
|
3905
|
+
return recordStepAndCheck(run, attempt.next, stepIndex);
|
|
3906
|
+
}
|
|
3907
|
+
async function checkAbortAndBudget(run) {
|
|
3908
|
+
if (run.signal.aborted) return settle(run, {
|
|
3909
|
+
pass: false,
|
|
3910
|
+
completed: false,
|
|
3911
|
+
reason: abortReason(run.signal),
|
|
3912
|
+
score: void 0,
|
|
3913
|
+
failureClass: "timeout",
|
|
3914
|
+
stoppedBy: "abort"
|
|
3915
|
+
});
|
|
3916
|
+
const budgetStop = budgetStopDecision(run.budget, run.spentCostUsd);
|
|
3917
|
+
if (!budgetStop.stop) return void 0;
|
|
3918
|
+
return settle(run, {
|
|
3919
|
+
pass: false,
|
|
3920
|
+
completed: false,
|
|
3921
|
+
reason: budgetStop.reason,
|
|
3922
|
+
score: averageScore(run.evals),
|
|
3923
|
+
failureClass: "budget_exceeded",
|
|
3924
|
+
stoppedBy: "budget"
|
|
3925
|
+
});
|
|
3926
|
+
}
|
|
3927
|
+
function makeRunContext(run, stepIndex) {
|
|
3928
|
+
return makeContext(run.config.intent, run.state, run.evals, run.history, run.budget, stepIndex, run.started, run.spentCostUsd, run.signal, run.emitter);
|
|
3929
|
+
}
|
|
3930
|
+
/** Ask the stop policy about the current state. `errorStep` is the step a failing policy is recorded against. */
|
|
3931
|
+
async function checkStopPolicy(run, ctx, errorStep) {
|
|
3932
|
+
let stop;
|
|
3933
|
+
try {
|
|
3934
|
+
stop = run.config.shouldStop ? await run.config.shouldStop(ctx) : defaultStopDecision(run.evals);
|
|
3935
|
+
} catch (err) {
|
|
3936
|
+
run.runtimeErrors.push(runtimeError("stop-policy", errorStep, err));
|
|
3937
|
+
return settleOnRuntimeError(run);
|
|
3938
|
+
}
|
|
3939
|
+
if (!stop.stop) return void 0;
|
|
3940
|
+
return settle(run, {
|
|
3941
|
+
pass: stop.pass,
|
|
3942
|
+
completed: true,
|
|
3943
|
+
reason: stop.reason,
|
|
3944
|
+
score: stop.score,
|
|
3945
|
+
failureClass: stop.failureClass,
|
|
3946
|
+
stoppedBy: "stop-policy"
|
|
3947
|
+
});
|
|
3948
|
+
}
|
|
3949
|
+
async function decideAction(run, ctx, stepIndex) {
|
|
3950
|
+
let decision;
|
|
3951
|
+
try {
|
|
3952
|
+
decision = await run.config.decide(ctx);
|
|
3953
|
+
} catch (err) {
|
|
3954
|
+
run.runtimeErrors.push(runtimeError("decide", stepIndex, err));
|
|
3955
|
+
return { ended: await settleOnRuntimeError(run) };
|
|
3956
|
+
}
|
|
3957
|
+
if (decision.type !== "stop") return { next: { decision } };
|
|
3958
|
+
const pass = decision.pass ?? false;
|
|
3959
|
+
return { ended: await settle(run, {
|
|
3960
|
+
pass,
|
|
3961
|
+
completed: true,
|
|
3962
|
+
reason: decision.reason,
|
|
3963
|
+
score: decision.score,
|
|
3964
|
+
failureClass: pass ? void 0 : decision.failureClass ?? "unknown",
|
|
3965
|
+
stoppedBy: "policy"
|
|
3966
|
+
}) };
|
|
3967
|
+
}
|
|
3968
|
+
/** Feed the chosen action to the repeated-action detector; its streak is returned for the step's trace. */
|
|
3969
|
+
async function detectRepeatedAction(run, decision) {
|
|
3970
|
+
const actionFingerprint = fingerprintAction(decision.action, run.config.stopPolicies);
|
|
3971
|
+
const signal = run.repeatedDetector.observe({ actionFingerprint });
|
|
3972
|
+
if (!signal) return { next: run.repeatedDetector.streak };
|
|
3973
|
+
return { ended: await settle(run, {
|
|
3974
|
+
pass: false,
|
|
3975
|
+
completed: true,
|
|
3976
|
+
reason: signal.reason,
|
|
3977
|
+
score: averageScore(run.evals),
|
|
3978
|
+
failureClass: "tool_recovery_failure",
|
|
3979
|
+
stoppedBy: "stop-policy"
|
|
3980
|
+
}) };
|
|
3981
|
+
}
|
|
3982
|
+
/** Run the chosen action under its trace span and price it. A failed action ends the run only when `actionFailure` is 'stop'. */
|
|
3983
|
+
async function attemptAction(run, ctx, decision, stepIndex, repeatedActionStreak) {
|
|
3984
|
+
const { config, emitter, runtimeErrors } = run;
|
|
3985
|
+
const beforeState = run.state;
|
|
3986
|
+
const evalsBefore = run.evals;
|
|
3987
|
+
const scoreBefore = averageScore(run.evals);
|
|
3988
|
+
const actionStarted = Date.now();
|
|
3989
|
+
const stepHandle = emitter ? await runTrace(emitter, runtimeErrors, stepIndex, () => emitter.tool({
|
|
3990
|
+
name: `control-step-${stepIndex}`,
|
|
3991
|
+
toolName: "agent-control-action",
|
|
3992
|
+
args: decision.action,
|
|
3993
|
+
attributes: {
|
|
3994
|
+
decision: decision.reason ?? "continue",
|
|
3995
|
+
repeatedActionStreak
|
|
3996
|
+
}
|
|
3997
|
+
})) : void 0;
|
|
3998
|
+
let outcome;
|
|
3999
|
+
try {
|
|
4000
|
+
const result = await config.act(decision.action, ctx);
|
|
4001
|
+
const rawCostUsd = config.getActionCostUsd?.({
|
|
4002
|
+
action: decision.action,
|
|
4003
|
+
result,
|
|
4004
|
+
state: run.state,
|
|
4005
|
+
evals: run.evals,
|
|
4006
|
+
history: run.history
|
|
4007
|
+
});
|
|
4008
|
+
const costUsd = normalizeActionCostUsd(rawCostUsd, runtimeErrors, stepIndex);
|
|
4009
|
+
if (costUsd !== void 0 && Number.isFinite(costUsd) && costUsd > 0) {
|
|
4010
|
+
run.spentCostUsd += costUsd;
|
|
4011
|
+
await recordCostBudget(emitter, run.budget, run.spentCostUsd, stepHandle, runtimeErrors, stepIndex);
|
|
4012
|
+
}
|
|
4013
|
+
outcome = {
|
|
4014
|
+
ok: true,
|
|
4015
|
+
result,
|
|
4016
|
+
...costUsd !== void 0 ? { costUsd } : {},
|
|
4017
|
+
durationMs: Date.now() - actionStarted
|
|
4018
|
+
};
|
|
4019
|
+
} catch (err) {
|
|
4020
|
+
runtimeErrors.push(runtimeError("act", stepIndex, err));
|
|
4021
|
+
outcome = {
|
|
4022
|
+
ok: false,
|
|
4023
|
+
error: lastErrorMessage(run),
|
|
4024
|
+
durationMs: Date.now() - actionStarted
|
|
4025
|
+
};
|
|
4026
|
+
if ((config.actionFailure ?? "continue") === "stop") {
|
|
4027
|
+
await runTrace(emitter, runtimeErrors, stepIndex, () => stepHandle?.fail(outcome.error ?? "action failed"));
|
|
4028
|
+
const step = buildStep(run, {
|
|
4029
|
+
decision,
|
|
4030
|
+
beforeState,
|
|
4031
|
+
evalsBefore,
|
|
4032
|
+
scoreBefore,
|
|
4033
|
+
actionStarted,
|
|
4034
|
+
stepHandle,
|
|
4035
|
+
outcome
|
|
4036
|
+
}, stepIndex, run.state);
|
|
4037
|
+
run.history.push(step);
|
|
4038
|
+
await runOnStep(config.onStep, step, runtimeErrors);
|
|
4039
|
+
return { ended: await settle(run, {
|
|
4040
|
+
pass: false,
|
|
4041
|
+
completed: false,
|
|
4042
|
+
reason: outcome.error ?? "action failed",
|
|
4043
|
+
score: averageScore(run.evals),
|
|
4044
|
+
failureClass: "unknown",
|
|
4045
|
+
stoppedBy: "runtime-error"
|
|
4046
|
+
}) };
|
|
4047
|
+
}
|
|
4048
|
+
}
|
|
4049
|
+
return { next: {
|
|
4050
|
+
decision,
|
|
4051
|
+
beforeState,
|
|
4052
|
+
evalsBefore,
|
|
4053
|
+
scoreBefore,
|
|
4054
|
+
actionStarted,
|
|
4055
|
+
stepHandle,
|
|
4056
|
+
outcome
|
|
4057
|
+
} };
|
|
4058
|
+
}
|
|
4059
|
+
function buildStep(run, attempt, stepIndex, afterState) {
|
|
4060
|
+
return {
|
|
4061
|
+
index: stepIndex,
|
|
4062
|
+
decision: attempt.decision,
|
|
4063
|
+
beforeState: attempt.beforeState,
|
|
4064
|
+
afterState,
|
|
4065
|
+
evalsBefore: attempt.evalsBefore,
|
|
4066
|
+
evalsAfter: run.evals,
|
|
4067
|
+
actionOutcome: attempt.outcome,
|
|
4068
|
+
startedAt: new Date(attempt.actionStarted).toISOString(),
|
|
4069
|
+
endedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4070
|
+
};
|
|
4071
|
+
}
|
|
4072
|
+
/** Observe and validate after the action. A failure records the step and ends the run. */
|
|
4073
|
+
async function observeAfterAction(run, attempt, stepIndex) {
|
|
4074
|
+
const { config, emitter, runtimeErrors } = run;
|
|
4075
|
+
let observationPhase = "observe";
|
|
4076
|
+
try {
|
|
4077
|
+
run.state = await config.observe({
|
|
4078
|
+
history: run.history,
|
|
4079
|
+
abortSignal: run.signal
|
|
4080
|
+
});
|
|
4081
|
+
observationPhase = "validate";
|
|
4082
|
+
run.evals = await config.validate({
|
|
4083
|
+
intent: config.intent,
|
|
4084
|
+
state: run.state,
|
|
4085
|
+
history: run.history,
|
|
4086
|
+
abortSignal: run.signal
|
|
4087
|
+
});
|
|
4088
|
+
await recordEvalSpans(emitter, run.evals, `step-${stepIndex}`, runtimeErrors, stepIndex, attempt.stepHandle?.span.spanId);
|
|
4089
|
+
return;
|
|
4090
|
+
} catch (err) {
|
|
4091
|
+
runtimeErrors.push(runtimeError(observationPhase, stepIndex, err));
|
|
4092
|
+
const afterState = observationPhase === "observe" ? attempt.beforeState : run.state;
|
|
4093
|
+
const step = buildStep(run, attempt, stepIndex, afterState);
|
|
4094
|
+
run.history.push(step);
|
|
4095
|
+
await runTrace(emitter, runtimeErrors, stepIndex, () => attempt.stepHandle?.fail(lastErrorMessage(run)));
|
|
4096
|
+
await runOnStep(config.onStep, step, runtimeErrors);
|
|
4097
|
+
return settleOnRuntimeError(run, { value: afterState });
|
|
4098
|
+
}
|
|
4099
|
+
}
|
|
4100
|
+
/** Record the finished step, then apply the no-progress, budget and stop-policy checks that follow it. */
|
|
4101
|
+
async function recordStepAndCheck(run, attempt, stepIndex) {
|
|
4102
|
+
const { config, emitter, runtimeErrors } = run;
|
|
4103
|
+
const scoreAfter = averageScore(run.evals);
|
|
4104
|
+
const stateFingerprint = fingerprintState(run.state, config.stopPolicies);
|
|
4105
|
+
const noProgressSignal = run.progressDetector.observe({
|
|
4106
|
+
stateFingerprint,
|
|
4107
|
+
score: scoreAfter
|
|
4108
|
+
});
|
|
4109
|
+
const noProgressStreak = run.progressDetector.streak;
|
|
4110
|
+
const step = buildStep(run, attempt, stepIndex, run.state);
|
|
4111
|
+
run.history.push(step);
|
|
4112
|
+
const { outcome, stepHandle } = attempt;
|
|
4113
|
+
if (outcome.ok) await runTrace(emitter, runtimeErrors, stepIndex, () => stepHandle?.end({ attributes: {
|
|
4114
|
+
actionCostUsd: outcome.costUsd ?? null,
|
|
4115
|
+
spentCostUsd: run.spentCostUsd,
|
|
4116
|
+
scoreBefore: attempt.scoreBefore ?? null,
|
|
4117
|
+
scoreAfter: scoreAfter ?? null,
|
|
4118
|
+
noProgressStreak
|
|
4119
|
+
} }));
|
|
4120
|
+
else await runTrace(emitter, runtimeErrors, stepIndex, () => stepHandle?.fail(outcome.error ?? "action failed", { attributes: {
|
|
4121
|
+
spentCostUsd: run.spentCostUsd,
|
|
4122
|
+
noProgressStreak
|
|
4123
|
+
} }));
|
|
4124
|
+
await runOnStep(config.onStep, step, runtimeErrors);
|
|
4125
|
+
if (noProgressSignal) return settle(run, {
|
|
4126
|
+
pass: false,
|
|
4127
|
+
completed: true,
|
|
4128
|
+
reason: noProgressSignal.reason,
|
|
4129
|
+
score: scoreAfter,
|
|
4130
|
+
failureClass: "tool_recovery_failure",
|
|
4131
|
+
stoppedBy: "stop-policy"
|
|
4132
|
+
});
|
|
4133
|
+
const postStepBudgetStop = budgetStopDecision(run.budget, run.spentCostUsd);
|
|
4134
|
+
if (postStepBudgetStop.stop) return settle(run, {
|
|
4135
|
+
pass: false,
|
|
4136
|
+
completed: false,
|
|
4137
|
+
reason: postStepBudgetStop.reason,
|
|
4138
|
+
score: scoreAfter,
|
|
4139
|
+
failureClass: "budget_exceeded",
|
|
4140
|
+
stoppedBy: "budget"
|
|
4141
|
+
});
|
|
4142
|
+
return checkStopPolicy(run, makeRunContext(run, stepIndex + 1), stepIndex + 1);
|
|
4143
|
+
}
|
|
4224
4144
|
function makeContext(intent, state, evals, history, budget, stepIndex, started, spentCostUsd, abortSignal, emitter) {
|
|
4225
4145
|
return {
|
|
4226
4146
|
intent,
|
|
@@ -6695,6 +6615,152 @@ function wranglerDeployRunner(input) {
|
|
|
6695
6615
|
} };
|
|
6696
6616
|
}
|
|
6697
6617
|
//#endregion
|
|
6618
|
+
//#region src/held-out-gate-inputs.ts
|
|
6619
|
+
/** Drop gamed runs, pair both splits and measure coverage, scores, gaps and cost. */
|
|
6620
|
+
function collectGateInputs(candidate, baseline, baselineKey) {
|
|
6621
|
+
const candidateId = inferCandidateId(candidate, baselineKey);
|
|
6622
|
+
const baselineId = baselineKey;
|
|
6623
|
+
assertScenarioIdentities([...candidate, ...baseline]);
|
|
6624
|
+
const realnessGatedRuns = [...candidate, ...baseline].filter(isRealnessGated).length;
|
|
6625
|
+
const honestCandidate = candidate.filter((run) => !isRealnessGated(run));
|
|
6626
|
+
const honestBaseline = baseline.filter((run) => !isRealnessGated(run));
|
|
6627
|
+
const candidateSearch = scoredRuns(honestCandidate, "search");
|
|
6628
|
+
const baselineSearch = scoredRuns(honestBaseline, "search");
|
|
6629
|
+
const candidateHoldout = scoredRuns(honestCandidate, "holdout");
|
|
6630
|
+
const baselineHoldout = scoredRuns(honestBaseline, "holdout");
|
|
6631
|
+
const searchPairing = pairRunRecords(baselineSearch, candidateSearch);
|
|
6632
|
+
const holdoutPairing = pairRunRecords(baselineHoldout, candidateHoldout);
|
|
6633
|
+
const searchCoverage = splitCoverage(honestBaseline, honestCandidate, "search");
|
|
6634
|
+
const holdoutCoverage = splitCoverage(honestBaseline, honestCandidate, "holdout");
|
|
6635
|
+
const splitScoreOf = (run, split) => observedSplitScore(run, split);
|
|
6636
|
+
const beforeSearch = searchPairing.pairs.map((pair) => splitScoreOf(pair.baseline, "search"));
|
|
6637
|
+
const afterSearch = searchPairing.pairs.map((pair) => splitScoreOf(pair.treatment, "search"));
|
|
6638
|
+
const beforeHoldout = holdoutPairing.pairs.map((pair) => splitScoreOf(pair.baseline, "holdout"));
|
|
6639
|
+
const afterHoldout = holdoutPairing.pairs.map((pair) => splitScoreOf(pair.treatment, "holdout"));
|
|
6640
|
+
const productiveRuns = beforeHoldout.length;
|
|
6641
|
+
const candidateSearchMean = meanOrNull(afterSearch);
|
|
6642
|
+
const candidateHoldoutMean = meanOrNull(afterHoldout);
|
|
6643
|
+
const baselineSearchMean = meanOrNull(beforeSearch);
|
|
6644
|
+
const baselineHoldoutMean = meanOrNull(beforeHoldout);
|
|
6645
|
+
const overfitGap = diffOrNull(candidateSearchMean, candidateHoldoutMean);
|
|
6646
|
+
const baselineOverfitGap = diffOrNull(baselineSearchMean, baselineHoldoutMean);
|
|
6647
|
+
const medianCandidateCost = completeCostMedian([...searchPairing.pairs.map((pair) => pair.treatment), ...holdoutPairing.pairs.map((pair) => pair.treatment)]);
|
|
6648
|
+
const medianBaselineCost = completeCostMedian([...searchPairing.pairs.map((pair) => pair.baseline), ...holdoutPairing.pairs.map((pair) => pair.baseline)]);
|
|
6649
|
+
return {
|
|
6650
|
+
candidateId,
|
|
6651
|
+
baselineId,
|
|
6652
|
+
beforeHoldout,
|
|
6653
|
+
afterHoldout,
|
|
6654
|
+
productiveRuns,
|
|
6655
|
+
overfitGap,
|
|
6656
|
+
baselineOverfitGap,
|
|
6657
|
+
medianCandidateCost,
|
|
6658
|
+
medianBaselineCost,
|
|
6659
|
+
searchCoverage,
|
|
6660
|
+
holdoutCoverage,
|
|
6661
|
+
missingSplitScores: [
|
|
6662
|
+
candidateSearch.length === 0 ? "candidate search" : null,
|
|
6663
|
+
candidateHoldout.length === 0 ? "candidate holdout" : null,
|
|
6664
|
+
baselineSearch.length === 0 ? "baseline search" : null,
|
|
6665
|
+
baselineHoldout.length === 0 ? "baseline holdout" : null
|
|
6666
|
+
].filter((label) => label !== null),
|
|
6667
|
+
commonEvidence: {
|
|
6668
|
+
productiveRuns,
|
|
6669
|
+
unpairedCandidateRuns: holdoutPairing.unpairedTreatment.length,
|
|
6670
|
+
unpairedBaselineRuns: holdoutPairing.unpairedBaseline.length,
|
|
6671
|
+
searchScore: candidateSearchMean,
|
|
6672
|
+
holdoutScore: candidateHoldoutMean,
|
|
6673
|
+
overfitGap,
|
|
6674
|
+
baselineOverfitGap,
|
|
6675
|
+
medianCandidateCost,
|
|
6676
|
+
medianBaselineCost,
|
|
6677
|
+
realnessGatedRuns,
|
|
6678
|
+
searchCoverage,
|
|
6679
|
+
holdoutCoverage
|
|
6680
|
+
}
|
|
6681
|
+
};
|
|
6682
|
+
}
|
|
6683
|
+
function inferCandidateId(candidate, baselineKey) {
|
|
6684
|
+
for (const run of candidate) if (run.candidateId && run.candidateId !== baselineKey) return run.candidateId;
|
|
6685
|
+
return candidate[0]?.candidateId ?? "(unknown candidate)";
|
|
6686
|
+
}
|
|
6687
|
+
function assertScenarioIdentities(runs) {
|
|
6688
|
+
for (const run of runs) if (typeof run.scenarioId !== "string" || run.scenarioId.trim() === "") throw new Error(`HeldOutGate: run ${run.runId} is missing scenarioId`);
|
|
6689
|
+
}
|
|
6690
|
+
/**
|
|
6691
|
+
* Rows carrying a finite score on one split. RAW (`observedSplitScore`) by
|
|
6692
|
+
* choice: the gated runs are already removed by the caller, so applying the
|
|
6693
|
+
* gate again here would only zero runs that are no longer in the set, and the
|
|
6694
|
+
* reported means must describe the runs that actually decided the promotion.
|
|
6695
|
+
*/
|
|
6696
|
+
function scoredRuns(runs, split) {
|
|
6697
|
+
return runs.filter((run) => {
|
|
6698
|
+
if (run.splitTag !== split) return false;
|
|
6699
|
+
const v = observedSplitScore(run, split);
|
|
6700
|
+
return typeof v === "number" && Number.isFinite(v);
|
|
6701
|
+
});
|
|
6702
|
+
}
|
|
6703
|
+
/** Every row tagged to one split, scored or not — the work the split was
|
|
6704
|
+
* DEALT, as opposed to the work it managed to measure. */
|
|
6705
|
+
function dealtRuns(runs, split) {
|
|
6706
|
+
return runs.filter((run) => run.splitTag === split);
|
|
6707
|
+
}
|
|
6708
|
+
function hasFiniteScore(run, split) {
|
|
6709
|
+
const v = observedSplitScore(run, split);
|
|
6710
|
+
return typeof v === "number" && Number.isFinite(v);
|
|
6711
|
+
}
|
|
6712
|
+
/**
|
|
6713
|
+
* Partition one split's dealt work into answered / unscored / one-armed.
|
|
6714
|
+
*
|
|
6715
|
+
* Pairs the UNFILTERED rows with the same `pairRunRecords` the decision uses,
|
|
6716
|
+
* so the denominator comes out of the same identity rules as the numerator and
|
|
6717
|
+
* cannot drift from it. Deliberately a SECOND pairing rather than a widening of
|
|
6718
|
+
* the decision's own: the decision keeps pairing exactly the rows it always
|
|
6719
|
+
* paired, so this check can only ever add a refusal, never move a verdict that
|
|
6720
|
+
* was already being made on a complete set.
|
|
6721
|
+
*/
|
|
6722
|
+
function splitCoverage(baseline, candidate, split) {
|
|
6723
|
+
const pairing = pairRunRecords(dealtRuns(baseline, split), dealtRuns(candidate, split));
|
|
6724
|
+
let answered = 0;
|
|
6725
|
+
for (const pair of pairing.pairs) if (hasFiniteScore(pair.baseline, split) && hasFiniteScore(pair.treatment, split)) answered += 1;
|
|
6726
|
+
const unscoredPairs = pairing.pairs.length - answered;
|
|
6727
|
+
const candidateOnly = pairing.unpairedTreatment.length;
|
|
6728
|
+
const baselineOnly = pairing.unpairedBaseline.length;
|
|
6729
|
+
const dealt = pairing.pairs.length + candidateOnly + baselineOnly;
|
|
6730
|
+
return {
|
|
6731
|
+
dealt,
|
|
6732
|
+
answered,
|
|
6733
|
+
unscoredPairs,
|
|
6734
|
+
candidateOnly,
|
|
6735
|
+
baselineOnly,
|
|
6736
|
+
coverage: dealt === 0 ? 0 : answered / dealt
|
|
6737
|
+
};
|
|
6738
|
+
}
|
|
6739
|
+
function meanOrNull(xs) {
|
|
6740
|
+
if (xs.length === 0) return null;
|
|
6741
|
+
return xs.reduce((s, x) => s + x, 0) / xs.length;
|
|
6742
|
+
}
|
|
6743
|
+
function diffOrNull(a, b) {
|
|
6744
|
+
if (a === null || b === null) return null;
|
|
6745
|
+
return a - b;
|
|
6746
|
+
}
|
|
6747
|
+
function medianFinite(xs) {
|
|
6748
|
+
const ys = xs.filter((x) => Number.isFinite(x)).sort((x, y) => x - y);
|
|
6749
|
+
if (ys.length === 0) return null;
|
|
6750
|
+
const mid = Math.floor(ys.length / 2);
|
|
6751
|
+
return ys.length % 2 === 0 ? (ys[mid - 1] + ys[mid]) / 2 : ys[mid];
|
|
6752
|
+
}
|
|
6753
|
+
function completeCostMedian(runs) {
|
|
6754
|
+
if (runs.length === 0) return null;
|
|
6755
|
+
const costs = [];
|
|
6756
|
+
for (const run of runs) {
|
|
6757
|
+
const usd = run.costProvenance.usd;
|
|
6758
|
+
if (usd === null) return null;
|
|
6759
|
+
costs.push(usd);
|
|
6760
|
+
}
|
|
6761
|
+
return medianFinite(costs);
|
|
6762
|
+
}
|
|
6763
|
+
//#endregion
|
|
6698
6764
|
//#region src/held-out-gate.ts
|
|
6699
6765
|
/**
|
|
6700
6766
|
* HeldOutGate — first-class held-out paired-delta promotion gate.
|
|
@@ -6854,55 +6920,35 @@ var HeldOutGate = class {
|
|
|
6854
6920
|
* Pairing is by `(experimentId, scenarioId, seed)`.
|
|
6855
6921
|
* Missing or duplicate identities throw instead of comparing by position. */
|
|
6856
6922
|
evaluate(candidate, baseline) {
|
|
6857
|
-
const
|
|
6858
|
-
const
|
|
6859
|
-
|
|
6860
|
-
const
|
|
6861
|
-
|
|
6862
|
-
const
|
|
6863
|
-
const
|
|
6864
|
-
|
|
6865
|
-
const
|
|
6866
|
-
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
|
|
6871
|
-
|
|
6872
|
-
|
|
6873
|
-
const afterSearch = searchPairing.pairs.map((pair) => splitScoreOf(pair.treatment, "search"));
|
|
6874
|
-
const beforeHoldout = holdoutPairing.pairs.map((pair) => splitScoreOf(pair.baseline, "holdout"));
|
|
6875
|
-
const afterHoldout = holdoutPairing.pairs.map((pair) => splitScoreOf(pair.treatment, "holdout"));
|
|
6876
|
-
const productiveRuns = beforeHoldout.length;
|
|
6877
|
-
const candidateSearchMean = meanOrNull(afterSearch);
|
|
6878
|
-
const candidateHoldoutMean = meanOrNull(afterHoldout);
|
|
6879
|
-
const baselineSearchMean = meanOrNull(beforeSearch);
|
|
6880
|
-
const baselineHoldoutMean = meanOrNull(beforeHoldout);
|
|
6881
|
-
const overfitGap = diffOrNull(candidateSearchMean, candidateHoldoutMean);
|
|
6882
|
-
const baselineOverfitGap = diffOrNull(baselineSearchMean, baselineHoldoutMean);
|
|
6883
|
-
const medianCandidateCost = completeCostMedian([...searchPairing.pairs.map((pair) => pair.treatment), ...holdoutPairing.pairs.map((pair) => pair.treatment)]);
|
|
6884
|
-
const medianBaselineCost = completeCostMedian([...searchPairing.pairs.map((pair) => pair.baseline), ...holdoutPairing.pairs.map((pair) => pair.baseline)]);
|
|
6885
|
-
const commonEvidence = {
|
|
6886
|
-
productiveRuns,
|
|
6887
|
-
unpairedCandidateRuns: holdoutPairing.unpairedTreatment.length,
|
|
6888
|
-
unpairedBaselineRuns: holdoutPairing.unpairedBaseline.length,
|
|
6889
|
-
searchScore: candidateSearchMean,
|
|
6890
|
-
holdoutScore: candidateHoldoutMean,
|
|
6891
|
-
overfitGap,
|
|
6892
|
-
baselineOverfitGap,
|
|
6893
|
-
medianCandidateCost,
|
|
6894
|
-
medianBaselineCost,
|
|
6895
|
-
realnessGatedRuns,
|
|
6896
|
-
searchCoverage,
|
|
6897
|
-
holdoutCoverage
|
|
6923
|
+
const inputs = collectGateInputs(candidate, baseline, this.baselineKey);
|
|
6924
|
+
const missingEvidence = this.refuseOnMissingEvidence(inputs);
|
|
6925
|
+
if (missingEvidence) return missingEvidence;
|
|
6926
|
+
const { overfitGap, baselineOverfitGap } = inputs;
|
|
6927
|
+
if (overfitGap === null || baselineOverfitGap === null) throw new Error("HeldOutGate: complete split scores did not produce overfit gaps");
|
|
6928
|
+
const { decision, evidence } = this.decidePairedDelta(inputs);
|
|
6929
|
+
const refusal = this.refuseOnDelta(inputs, decision, evidence) ?? this.refuseOnOverfitOrCost(inputs, evidence, overfitGap, baselineOverfitGap);
|
|
6930
|
+
if (refusal) return refusal;
|
|
6931
|
+
const { candidateId, baselineId, productiveRuns, medianCandidateCost, medianBaselineCost } = inputs;
|
|
6932
|
+
return {
|
|
6933
|
+
promote: true,
|
|
6934
|
+
candidateId,
|
|
6935
|
+
baselineId,
|
|
6936
|
+
evidence,
|
|
6937
|
+
reason: `promote: paired holdout ${decision.label} Δ=${fmt(decision.delta)} CI=[${fmt(decision.low)}, ${fmt(decision.high)}] over ${productiveRuns} pairs; overfit gap candidate=${fmt(overfitGap)} vs baseline=${fmt(baselineOverfitGap)}; median cost candidate=$${fmt(medianCandidateCost)} vs baseline=$${fmt(medianBaselineCost)}`,
|
|
6938
|
+
rejectionCode: null
|
|
6898
6939
|
};
|
|
6940
|
+
}
|
|
6941
|
+
/** Refusals decided before any interval is computed: absent split scores,
|
|
6942
|
+
* incomplete coverage, too few paired runs. */
|
|
6943
|
+
refuseOnMissingEvidence(inputs) {
|
|
6944
|
+
const { productiveRuns, searchCoverage, holdoutCoverage } = inputs;
|
|
6899
6945
|
/** Evidence for the early exits, where no CI was computed at all. The
|
|
6900
6946
|
* statistic that WOULD have decided is still reported so a caller can see
|
|
6901
6947
|
* which branch their data lands in without producing a verdict. */
|
|
6902
|
-
const earlyShape = this.chooseShape(beforeHoldout, afterHoldout);
|
|
6948
|
+
const earlyShape = this.chooseShape(inputs.beforeHoldout, inputs.afterHoldout);
|
|
6903
6949
|
const noCiEvidence = {
|
|
6904
|
-
...commonEvidence,
|
|
6905
|
-
medianPairedDelta: productiveRuns > 0 ? medianDelta(beforeHoldout, afterHoldout) : null,
|
|
6950
|
+
...inputs.commonEvidence,
|
|
6951
|
+
medianPairedDelta: productiveRuns > 0 ? medianDelta(inputs.beforeHoldout, inputs.afterHoldout) : null,
|
|
6906
6952
|
deltaStatistic: earlyShape.statistic,
|
|
6907
6953
|
decidingDelta: null,
|
|
6908
6954
|
pairedCI: null,
|
|
@@ -6911,38 +6957,19 @@ var HeldOutGate = class {
|
|
|
6911
6957
|
binaryScale: earlyShape.binaryScale,
|
|
6912
6958
|
tieFraction: earlyShape.tieFraction
|
|
6913
6959
|
};
|
|
6914
|
-
|
|
6915
|
-
candidateSearch.length === 0 ? "candidate search" : null,
|
|
6916
|
-
candidateHoldout.length === 0 ? "candidate holdout" : null,
|
|
6917
|
-
baselineSearch.length === 0 ? "baseline search" : null,
|
|
6918
|
-
baselineHoldout.length === 0 ? "baseline holdout" : null
|
|
6919
|
-
].filter((label) => label !== null);
|
|
6920
|
-
if (missingSplitScores.length > 0) return {
|
|
6921
|
-
promote: false,
|
|
6922
|
-
candidateId,
|
|
6923
|
-
baselineId,
|
|
6924
|
-
evidence: noCiEvidence,
|
|
6925
|
-
reason: `missing_split_scores: ${missingSplitScores.join(", ")} score evidence is absent`,
|
|
6926
|
-
rejectionCode: "missing_split_scores"
|
|
6927
|
-
};
|
|
6960
|
+
if (inputs.missingSplitScores.length > 0) return rejectGate(inputs, noCiEvidence, "missing_split_scores", `missing_split_scores: ${inputs.missingSplitScores.join(", ")} score evidence is absent`);
|
|
6928
6961
|
const shortfalls = [["holdout", holdoutCoverage], ["search", searchCoverage]].filter(([, cov]) => cov.coverage < this.minCoverage);
|
|
6929
|
-
if (shortfalls.length > 0) return {
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
baselineId,
|
|
6941
|
-
evidence: noCiEvidence,
|
|
6942
|
-
reason: `few_runs: ${productiveRuns} paired holdout observation(s) < min ${this.minProductiveRuns}`,
|
|
6943
|
-
rejectionCode: "few_runs"
|
|
6944
|
-
};
|
|
6945
|
-
if (overfitGap === null || baselineOverfitGap === null) throw new Error("HeldOutGate: complete split scores did not produce overfit gaps");
|
|
6962
|
+
if (shortfalls.length > 0) return rejectGate(inputs, noCiEvidence, "incomplete_coverage", `incomplete_coverage: ${shortfalls.map(([split, cov]) => describeCoverage(split, cov)).join("; ")} — required ${fmt(this.minCoverage)} of every dealt item scored on both arms. A missing score is missing data, not an absent item: the gate will not decide on the subset that answered`);
|
|
6963
|
+
if (productiveRuns < this.minProductiveRuns) return rejectGate(inputs, noCiEvidence, "few_runs", `few_runs: ${productiveRuns} paired holdout observation(s) < min ${this.minProductiveRuns}`);
|
|
6964
|
+
return null;
|
|
6965
|
+
}
|
|
6966
|
+
/** The paired holdout delta, decided by the one shared rule (see
|
|
6967
|
+
* `paired-promotion-decision.ts`): the estimator comes from the outcome's
|
|
6968
|
+
* shape, McNemar vetoes at a non-negative threshold, and a zero-width
|
|
6969
|
+
* interval is refused. `medianPairedDelta` stays the literal median on
|
|
6970
|
+
* EVERY path so the number that made the old gate blind remains visible. */
|
|
6971
|
+
decidePairedDelta(inputs) {
|
|
6972
|
+
const { beforeHoldout, afterHoldout } = inputs;
|
|
6946
6973
|
const decision = decidePairedPromotion(beforeHoldout, afterHoldout, {
|
|
6947
6974
|
threshold: this.pairedDeltaThreshold,
|
|
6948
6975
|
confidence: this.confidence,
|
|
@@ -6953,81 +6980,46 @@ var HeldOutGate = class {
|
|
|
6953
6980
|
});
|
|
6954
6981
|
const literalMedian = medianDelta(beforeHoldout, afterHoldout);
|
|
6955
6982
|
const wilcoxon = wilcoxonSignedRank(beforeHoldout, afterHoldout);
|
|
6956
|
-
const { delta: decidingDelta, low, high
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
6961
|
-
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
candidateId,
|
|
6974
|
-
baselineId,
|
|
6975
|
-
evidence,
|
|
6976
|
-
reason: `indeterminate_delta: ${decision.indeterminateCause}, so the paired holdout CI is [${fmt(low)}, ${fmt(high)}] and carries no direction — it cannot clear threshold ${fmt(this.pairedDeltaThreshold)} on evidence`,
|
|
6977
|
-
rejectionCode: "indeterminate_delta"
|
|
6978
|
-
};
|
|
6979
|
-
if (!decision.sufficient) return {
|
|
6980
|
-
promote: false,
|
|
6981
|
-
candidateId,
|
|
6982
|
-
baselineId,
|
|
6983
|
-
evidence,
|
|
6984
|
-
reason: `few_runs: ${productiveRuns} paired holdout observations < ${decision.minimumPairs} required for ${deltaLabel} estimation`,
|
|
6985
|
-
rejectionCode: "few_runs"
|
|
6983
|
+
const { delta: decidingDelta, low, high } = decision;
|
|
6984
|
+
return {
|
|
6985
|
+
decision,
|
|
6986
|
+
evidence: {
|
|
6987
|
+
...inputs.commonEvidence,
|
|
6988
|
+
medianPairedDelta: literalMedian,
|
|
6989
|
+
deltaStatistic: decision.statistic,
|
|
6990
|
+
decidingDelta,
|
|
6991
|
+
pairedCI: {
|
|
6992
|
+
low,
|
|
6993
|
+
high
|
|
6994
|
+
},
|
|
6995
|
+
pairedPValue: wilcoxon.p,
|
|
6996
|
+
mcnemar: decision.mcnemar,
|
|
6997
|
+
binaryScale: decision.binaryScale,
|
|
6998
|
+
tieFraction: decision.tieFraction
|
|
6999
|
+
}
|
|
6986
7000
|
};
|
|
7001
|
+
}
|
|
7002
|
+
/** Refusals read off the paired delta: a zero-width interval, too few pairs
|
|
7003
|
+
* for the chosen estimator, or an interval that does not clear the threshold. */
|
|
7004
|
+
refuseOnDelta(inputs, decision, evidence) {
|
|
7005
|
+
const { delta: decidingDelta, low, high, label: deltaLabel } = decision;
|
|
7006
|
+
if (decision.indeterminate) return rejectGate(inputs, evidence, "indeterminate_delta", `indeterminate_delta: ${decision.indeterminateCause}, so the paired holdout CI is [${fmt(low)}, ${fmt(high)}] and carries no direction — it cannot clear threshold ${fmt(this.pairedDeltaThreshold)} on evidence`);
|
|
7007
|
+
if (!decision.sufficient) return rejectGate(inputs, evidence, "few_runs", `few_runs: ${inputs.productiveRuns} paired holdout observations < ${decision.minimumPairs} required for ${deltaLabel} estimation`);
|
|
6987
7008
|
const exactTestVetoes = decision.exactTestVetoes;
|
|
6988
7009
|
if (!decision.clearsThreshold || exactTestVetoes) {
|
|
6989
7010
|
const detail = exactTestVetoes ? ` McNemar exact p=${decision.mcnemar?.pValue.toExponential(2)} does not reject at α=${fmt(1 - this.confidence)}.` : decision.methodDetail;
|
|
6990
|
-
return {
|
|
6991
|
-
promote: false,
|
|
6992
|
-
candidateId,
|
|
6993
|
-
baselineId,
|
|
6994
|
-
evidence,
|
|
6995
|
-
reason: `negative_delta: paired holdout ${deltaLabel} Δ=${fmt(decidingDelta)} CI=[${fmt(low)}, ${fmt(high)}] does not clear threshold ${fmt(this.pairedDeltaThreshold)}.${detail}`,
|
|
6996
|
-
rejectionCode: "negative_delta"
|
|
6997
|
-
};
|
|
7011
|
+
return rejectGate(inputs, evidence, "negative_delta", `negative_delta: paired holdout ${deltaLabel} Δ=${fmt(decidingDelta)} CI=[${fmt(low)}, ${fmt(high)}] does not clear threshold ${fmt(this.pairedDeltaThreshold)}.${detail}`);
|
|
6998
7012
|
}
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
if (this.costPerTaskCeiling !== void 0 && medianCandidateCost
|
|
7008
|
-
|
|
7009
|
-
candidateId,
|
|
7010
|
-
baselineId,
|
|
7011
|
-
evidence,
|
|
7012
|
-
reason: "missing_cost: candidate cost evidence is incomplete",
|
|
7013
|
-
rejectionCode: "missing_cost"
|
|
7014
|
-
};
|
|
7015
|
-
if (this.costPerTaskCeiling !== void 0 && medianCandidateCost !== null && medianCandidateCost > this.costPerTaskCeiling) return {
|
|
7016
|
-
promote: false,
|
|
7017
|
-
candidateId,
|
|
7018
|
-
baselineId,
|
|
7019
|
-
evidence,
|
|
7020
|
-
reason: `cost_ceiling: candidate median cost $${fmt(medianCandidateCost)} exceeds ceiling $${fmt(this.costPerTaskCeiling)} (baseline $${fmt(medianBaselineCost)})`,
|
|
7021
|
-
rejectionCode: "cost_ceiling"
|
|
7022
|
-
};
|
|
7023
|
-
return {
|
|
7024
|
-
promote: true,
|
|
7025
|
-
candidateId,
|
|
7026
|
-
baselineId,
|
|
7027
|
-
evidence,
|
|
7028
|
-
reason: `promote: paired holdout ${deltaLabel} Δ=${fmt(decidingDelta)} CI=[${fmt(low)}, ${fmt(high)}] over ${productiveRuns} pairs; overfit gap candidate=${fmt(overfitGap)} vs baseline=${fmt(baselineOverfitGap)}; median cost candidate=$${fmt(medianCandidateCost)} vs baseline=$${fmt(medianBaselineCost)}`,
|
|
7029
|
-
rejectionCode: null
|
|
7030
|
-
};
|
|
7013
|
+
return null;
|
|
7014
|
+
}
|
|
7015
|
+
/** The overfit-gap and cost-ceiling refusals, run after the quality gates so
|
|
7016
|
+
* a cost-driven rejection never masks a quality failure. */
|
|
7017
|
+
refuseOnOverfitOrCost(inputs, evidence, overfitGap, baselineOverfitGap) {
|
|
7018
|
+
const { medianCandidateCost, medianBaselineCost } = inputs;
|
|
7019
|
+
if (overfitGap > baselineOverfitGap + this.overfitGapThreshold) return rejectGate(inputs, evidence, "overfit_gap", `overfit_gap: candidate gap=${fmt(overfitGap)} exceeds baseline gap=${fmt(baselineOverfitGap)} by more than ${fmt(this.overfitGapThreshold)}`);
|
|
7020
|
+
if (this.costPerTaskCeiling !== void 0 && medianCandidateCost === null) return rejectGate(inputs, evidence, "missing_cost", "missing_cost: candidate cost evidence is incomplete");
|
|
7021
|
+
if (this.costPerTaskCeiling !== void 0 && medianCandidateCost !== null && medianCandidateCost > this.costPerTaskCeiling) return rejectGate(inputs, evidence, "cost_ceiling", `cost_ceiling: candidate median cost $${fmt(medianCandidateCost)} exceeds ceiling $${fmt(this.costPerTaskCeiling)} (baseline $${fmt(medianBaselineCost)})`);
|
|
7022
|
+
return null;
|
|
7031
7023
|
}
|
|
7032
7024
|
/**
|
|
7033
7025
|
* Which paired statistic decides this data, and the shape facts behind it —
|
|
@@ -7039,60 +7031,15 @@ var HeldOutGate = class {
|
|
|
7039
7031
|
return pairedDecisionShape(before, after, this.deltaStatistic === "median" ? "median" : "mean");
|
|
7040
7032
|
}
|
|
7041
7033
|
};
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
return candidate[0]?.candidateId ?? "(unknown candidate)";
|
|
7045
|
-
}
|
|
7046
|
-
function assertScenarioIdentities(runs) {
|
|
7047
|
-
for (const run of runs) if (typeof run.scenarioId !== "string" || run.scenarioId.trim() === "") throw new Error(`HeldOutGate: run ${run.runId} is missing scenarioId`);
|
|
7048
|
-
}
|
|
7049
|
-
/**
|
|
7050
|
-
* Rows carrying a finite score on one split. RAW (`observedSplitScore`) by
|
|
7051
|
-
* choice: the gated runs are already removed by the caller, so applying the
|
|
7052
|
-
* gate again here would only zero runs that are no longer in the set, and the
|
|
7053
|
-
* reported means must describe the runs that actually decided the promotion.
|
|
7054
|
-
*/
|
|
7055
|
-
function scoredRuns(runs, split) {
|
|
7056
|
-
return runs.filter((run) => {
|
|
7057
|
-
if (run.splitTag !== split) return false;
|
|
7058
|
-
const v = observedSplitScore(run, split);
|
|
7059
|
-
return typeof v === "number" && Number.isFinite(v);
|
|
7060
|
-
});
|
|
7061
|
-
}
|
|
7062
|
-
/** Every row tagged to one split, scored or not — the work the split was
|
|
7063
|
-
* DEALT, as opposed to the work it managed to measure. */
|
|
7064
|
-
function dealtRuns(runs, split) {
|
|
7065
|
-
return runs.filter((run) => run.splitTag === split);
|
|
7066
|
-
}
|
|
7067
|
-
function hasFiniteScore(run, split) {
|
|
7068
|
-
const v = observedSplitScore(run, split);
|
|
7069
|
-
return typeof v === "number" && Number.isFinite(v);
|
|
7070
|
-
}
|
|
7071
|
-
/**
|
|
7072
|
-
* Partition one split's dealt work into answered / unscored / one-armed.
|
|
7073
|
-
*
|
|
7074
|
-
* Pairs the UNFILTERED rows with the same `pairRunRecords` the decision uses,
|
|
7075
|
-
* so the denominator comes out of the same identity rules as the numerator and
|
|
7076
|
-
* cannot drift from it. Deliberately a SECOND pairing rather than a widening of
|
|
7077
|
-
* the decision's own: the decision keeps pairing exactly the rows it always
|
|
7078
|
-
* paired, so this check can only ever add a refusal, never move a verdict that
|
|
7079
|
-
* was already being made on a complete set.
|
|
7080
|
-
*/
|
|
7081
|
-
function splitCoverage(baseline, candidate, split) {
|
|
7082
|
-
const pairing = pairRunRecords(dealtRuns(baseline, split), dealtRuns(candidate, split));
|
|
7083
|
-
let answered = 0;
|
|
7084
|
-
for (const pair of pairing.pairs) if (hasFiniteScore(pair.baseline, split) && hasFiniteScore(pair.treatment, split)) answered += 1;
|
|
7085
|
-
const unscoredPairs = pairing.pairs.length - answered;
|
|
7086
|
-
const candidateOnly = pairing.unpairedTreatment.length;
|
|
7087
|
-
const baselineOnly = pairing.unpairedBaseline.length;
|
|
7088
|
-
const dealt = pairing.pairs.length + candidateOnly + baselineOnly;
|
|
7034
|
+
/** A refusal verdict carrying the evidence gathered so far. */
|
|
7035
|
+
function rejectGate(inputs, evidence, rejectionCode, reason) {
|
|
7089
7036
|
return {
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
|
|
7037
|
+
promote: false,
|
|
7038
|
+
candidateId: inputs.candidateId,
|
|
7039
|
+
baselineId: inputs.baselineId,
|
|
7040
|
+
evidence,
|
|
7041
|
+
reason,
|
|
7042
|
+
rejectionCode
|
|
7096
7043
|
};
|
|
7097
7044
|
}
|
|
7098
7045
|
function describeCoverage(split, cov) {
|
|
@@ -7103,36 +7050,12 @@ function describeCoverage(split, cov) {
|
|
|
7103
7050
|
].filter((part) => part !== null);
|
|
7104
7051
|
return `${split} scored ${cov.answered} of ${cov.dealt} dealt items (coverage ${fmt(cov.coverage)})` + (dark.length > 0 ? ` — ${dark.join(", ")}` : "");
|
|
7105
7052
|
}
|
|
7106
|
-
function meanOrNull(xs) {
|
|
7107
|
-
if (xs.length === 0) return null;
|
|
7108
|
-
return xs.reduce((s, x) => s + x, 0) / xs.length;
|
|
7109
|
-
}
|
|
7110
|
-
function diffOrNull(a, b) {
|
|
7111
|
-
if (a === null || b === null) return null;
|
|
7112
|
-
return a - b;
|
|
7113
|
-
}
|
|
7114
7053
|
function medianDelta(before, after) {
|
|
7115
7054
|
const ds = before.map((b, i) => after[i] - b).sort((x, y) => x - y);
|
|
7116
7055
|
if (ds.length === 0) throw new Error("HeldOutGate: median delta requires at least one pair");
|
|
7117
7056
|
const mid = Math.floor(ds.length / 2);
|
|
7118
7057
|
return ds.length % 2 === 0 ? (ds[mid - 1] + ds[mid]) / 2 : ds[mid];
|
|
7119
7058
|
}
|
|
7120
|
-
function medianFinite(xs) {
|
|
7121
|
-
const ys = xs.filter((x) => Number.isFinite(x)).sort((x, y) => x - y);
|
|
7122
|
-
if (ys.length === 0) return null;
|
|
7123
|
-
const mid = Math.floor(ys.length / 2);
|
|
7124
|
-
return ys.length % 2 === 0 ? (ys[mid - 1] + ys[mid]) / 2 : ys[mid];
|
|
7125
|
-
}
|
|
7126
|
-
function completeCostMedian(runs) {
|
|
7127
|
-
if (runs.length === 0) return null;
|
|
7128
|
-
const costs = [];
|
|
7129
|
-
for (const run of runs) {
|
|
7130
|
-
const usd = run.costProvenance.usd;
|
|
7131
|
-
if (usd === null) return null;
|
|
7132
|
-
costs.push(usd);
|
|
7133
|
-
}
|
|
7134
|
-
return medianFinite(costs);
|
|
7135
|
-
}
|
|
7136
7059
|
function fmt(x) {
|
|
7137
7060
|
if (x === null) return "n/a";
|
|
7138
7061
|
return x.toFixed(4);
|