@hona/openeval 0.2.2 → 0.3.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/JUDGING.md +134 -23
- package/README.md +67 -9
- package/package.json +3 -2
- package/src/app/cost-plan.ts +20 -16
- package/src/app/eval-state.ts +2 -1
- package/src/app/grade-recording.ts +72 -0
- package/src/app/input-fingerprints.ts +22 -8
- package/src/app/judge-evidence.ts +26 -11
- package/src/app/judge-run.ts +36 -19
- package/src/app/load-benchmark.ts +46 -15
- package/src/app/read-results.ts +35 -2
- package/src/app/read-run.ts +23 -2
- package/src/app/rejudge.ts +2 -1
- package/src/app/run-benchmark.ts +4 -0
- package/src/app/run-eval-pipeline.ts +2 -1
- package/src/app/run-eval.ts +13 -0
- package/src/app/scores.ts +76 -34
- package/src/app/serve-results.ts +2 -0
- package/src/evidence.ts +4 -1
- package/src/index.ts +15 -3
- package/src/infra/evidence/index.ts +39 -2
- package/src/infra/evidence/tool-calls.ts +5 -2
- package/src/infra/judging/agent.ts +3 -2
- package/src/infra/judging/code-result.ts +102 -0
- package/src/infra/judging/code-source.ts +96 -0
- package/src/infra/judging/code-worker.ts +26 -0
- package/src/infra/judging/code.ts +97 -0
- package/src/infra/judging/contract.ts +82 -64
- package/src/infra/judging/evidence-tool.ts +3 -1
- package/src/infra/judging/index.ts +14 -0
- package/src/infra/judging/judge-agent.md +24 -18
- package/src/infra/judging/observer.ts +8 -7
- package/src/infra/judging/submission.ts +8 -8
- package/src/infra/judging/tools.ts +9 -9
- package/src/infra/opencode/host.ts +1 -1
- package/src/infra/opencode/read-recording.ts +6 -1
- package/src/infra/opencode/version.ts +1 -0
- package/src/infra/recording/index.ts +244 -0
- package/src/infra/recording/metrics.ts +193 -0
- package/src/infra/sqlite/index.ts +29 -19
- package/src/judge-context.ts +141 -0
- package/src/judgment.ts +26 -17
- package/src/types.ts +36 -17
- package/src/view.ts +40 -14
- package/viewer/assets/{abnfDiagram-VCTEODGH-B1kcYgQG.js → abnfDiagram-VCTEODGH-rgmalTBh.js} +1 -1
- package/viewer/assets/{angular-html-DrYCUiZv.js → angular-html-CcaajvLj.js} +1 -1
- package/viewer/assets/{angular-ts-BgjwQn-Z.js → angular-ts-COx6AtG2.js} +1 -1
- package/viewer/assets/{apl-DlHqe8o4.js → apl-lBEnC_vz.js} +1 -1
- package/viewer/assets/{arc-C4nf7ZoY.js → arc-BQ0cQOwK.js} +1 -1
- package/viewer/assets/architecture-7GRP2DOG-DcUKSnYa.js +1 -0
- package/viewer/assets/{architectureDiagram-5GKGNRK7-BIWoe0fO.js → architectureDiagram-5GKGNRK7-_XIJP-LV.js} +1 -1
- package/viewer/assets/{astro-BrlHnIh9.js → astro-Ca8FrXna.js} +1 -1
- package/viewer/assets/{blade-DOcerOiW.js → blade-B07ZVjUX.js} +1 -1
- package/viewer/assets/{blockDiagram-I7D4REHJ-C3x13a9m.js → blockDiagram-I7D4REHJ-BdcDRYB-.js} +1 -1
- package/viewer/assets/{c-BMbThxEo.js → c-4MsqXzJK.js} +1 -1
- package/viewer/assets/{c4Diagram-7LVT6UL2-BeWktchx.js → c4Diagram-7LVT6UL2-E3nvwqBd.js} +1 -1
- package/viewer/assets/channel-CViXUg9J.js +1 -0
- package/viewer/assets/{chapel-k2cjkSmc.js → chapel-BlwR_8zu.js} +1 -1
- package/viewer/assets/{chunk-4HAMMTFA-o6YtJsqE.js → chunk-4HAMMTFA-DN_vtpqx.js} +1 -1
- package/viewer/assets/{chunk-75Z2AOVW-KohQa9Nw.js → chunk-75Z2AOVW-DWMGmicp.js} +1 -1
- package/viewer/assets/{chunk-DU6HZSFF-C88wxc6m.js → chunk-DU6HZSFF-D2RGHn75.js} +1 -1
- package/viewer/assets/{chunk-F27PBJKO-mO4AP2as.js → chunk-F27PBJKO-wfQZ5Ilx.js} +1 -1
- package/viewer/assets/{chunk-GMAD6QVW-DzQX2Cld.js → chunk-GMAD6QVW-DrlfUg7k.js} +1 -1
- package/viewer/assets/{chunk-GVQU2GXP-CS78RfJD.js → chunk-GVQU2GXP-BHoRLKIU.js} +1 -1
- package/viewer/assets/{chunk-IMKFNOWR-DxS42GUo.js → chunk-IMKFNOWR-mxLyQhYU.js} +1 -1
- package/viewer/assets/{chunk-L3NEJ4N5-DGo-uYLy.js → chunk-L3NEJ4N5-IpGl-pvp.js} +1 -1
- package/viewer/assets/{chunk-OSK3NFVY-BOcXQG16.js → chunk-OSK3NFVY-t0yN50X6.js} +1 -1
- package/viewer/assets/{chunk-P2QGCYS3-B7GnZdIQ.js → chunk-P2QGCYS3-BPBYYOcK.js} +1 -1
- package/viewer/assets/{chunk-POPQ4Y6H-DgBcYHog.js → chunk-POPQ4Y6H-DIOcv86B.js} +1 -1
- package/viewer/assets/{chunk-PWAF6VOD-DpEq6qHA.js → chunk-PWAF6VOD-CqVB-mzq.js} +1 -1
- package/viewer/assets/{chunk-SHT3W25Y-CrOGxKM2.js → chunk-SHT3W25Y-DwOEgFIr.js} +1 -1
- package/viewer/assets/{chunk-SVP7TREG-4HY7Fljj.js → chunk-SVP7TREG-Dfg1jHc3.js} +1 -1
- package/viewer/assets/{chunk-TICWLB2K-B1Rl31EC.js → chunk-TICWLB2K-DE6tQNRu.js} +1 -1
- package/viewer/assets/{chunk-XXDRQBXY-CK8giEW-.js → chunk-XXDRQBXY-Bu8dW06M.js} +1 -1
- package/viewer/assets/classDiagram-ZZMXUADV-O1Zm0_p8.js +1 -0
- package/viewer/assets/classDiagram-v2-VYDZK3BY-O1Zm0_p8.js +1 -0
- package/viewer/assets/{cobol-CupUwvw9.js → cobol-BS_DrT-b.js} +1 -1
- package/viewer/assets/{coffee-C17pkozF.js → coffee-Clk97ecB.js} +1 -1
- package/viewer/assets/{cose-bilkent-JH36ORCC-V1OmrmCv.js → cose-bilkent-JH36ORCC-B3xA8n2e.js} +1 -1
- package/viewer/assets/{cpp-BJwVQVXg.js → cpp-aunMdKLY.js} +1 -1
- package/viewer/assets/{crystal-BF-oCN-L.js → crystal-B1oihgG5.js} +1 -1
- package/viewer/assets/{css-BMgkVI3c.js → css-ClOubSVo.js} +1 -1
- package/viewer/assets/{cynefin-OW5HDTMX-BEjY_gsc.js → cynefin-OW5HDTMX-DdEeq9jN.js} +1 -1
- package/viewer/assets/{cynefinDiagram-5FMLGOSQ-bfSYgr6z.js → cynefinDiagram-5FMLGOSQ-BwHCV_5V.js} +1 -1
- package/viewer/assets/{dagre-GXQ25YYZ-VtwTgGfa.js → dagre-GXQ25YYZ-BkuWRmq-.js} +1 -1
- package/viewer/assets/{diagram-S7CK7UJ4-CHaAAyW7.js → diagram-S7CK7UJ4-C5WGyCny.js} +1 -1
- package/viewer/assets/{diagram-UQ7AKVKN-CjL65-As.js → diagram-UQ7AKVKN-mdununKH.js} +1 -1
- package/viewer/assets/{diagram-VSXAHHWV-Cnxrk1TJ.js → diagram-VSXAHHWV-CpuvU9Ij.js} +1 -1
- package/viewer/assets/{diagram-VX7I27RA-D78jPXr7.js → diagram-VX7I27RA-CcLmTPwv.js} +1 -1
- package/viewer/assets/{diagram-Z3DM3KII-DKjnOaF2.js → diagram-Z3DM3KII-DWCnKyKY.js} +1 -1
- package/viewer/assets/{dist-BTYPW0dz.js → dist-1DE7d697.js} +1 -1
- package/viewer/assets/{ebnfDiagram-PWID7BFC-7XiXh5Lx.js → ebnfDiagram-PWID7BFC-9M_-_M-B.js} +1 -1
- package/viewer/assets/{edge-B34N_HjN.js → edge-NsPpWeFX.js} +1 -1
- package/viewer/assets/{elixir-CQzWMyKD.js → elixir-CXZ4zQTn.js} +1 -1
- package/viewer/assets/{elm-BNJiG-wg.js → elm-DVXugwZs.js} +1 -1
- package/viewer/assets/{erDiagram-RLTQ6QDP-YPFEgZxU.js → erDiagram-RLTQ6QDP-B2j6iCkZ.js} +1 -1
- package/viewer/assets/{erb-D5Rm3UNa.js → erb-h8ybsnSQ.js} +1 -1
- package/viewer/assets/eventmodeling-NTZA5JFV-CpMf6avu.js +1 -0
- package/viewer/assets/flowDiagram-HODETNUW-DIKEcF1k.js +1 -0
- package/viewer/assets/{ganttDiagram-EL5Y4UJY-ergSGtTP.js → ganttDiagram-EL5Y4UJY-CR2QLJ-I.js} +1 -1
- package/viewer/assets/{git-rebase-BpIMZIRG.js → git-rebase-CT9f4kn8.js} +1 -1
- package/viewer/assets/{gitGraph-4MIJSDKK-CZt4REVj.js → gitGraph-4MIJSDKK-DGw-0dqe.js} +1 -1
- package/viewer/assets/{gitGraphDiagram-WWUBYQGX-h9QMzC2r.js → gitGraphDiagram-WWUBYQGX-BW112jVV.js} +1 -1
- package/viewer/assets/{glimmer-js-SeSwns5_.js → glimmer-js-B17pi1gL.js} +1 -1
- package/viewer/assets/{glimmer-ts-BExI5tTz.js → glimmer-ts-CNmwRbOn.js} +1 -1
- package/viewer/assets/{glsl-CXikKw2b.js → glsl-By4kbzYa.js} +1 -1
- package/viewer/assets/{graphql-6GpQIInt.js → graphql-BrDJs0bG.js} +1 -1
- package/viewer/assets/{hack-i7rizvpB.js → hack-NosEIqRi.js} +1 -1
- package/viewer/assets/{haml-C68gmkTf.js → haml-B-GQD8Zj.js} +1 -1
- package/viewer/assets/{handlebars-BBn_c0Xt.js → handlebars-1vSTccT5.js} +1 -1
- package/viewer/assets/{html-BObmAZQA.js → html-BBEodwWE.js} +1 -1
- package/viewer/assets/{html-derivative-BjMuR1LM.js → html-derivative-ClDEAvlc.js} +1 -1
- package/viewer/assets/{http-BJBk8gt0.js → http-I0uH89QQ.js} +1 -1
- package/viewer/assets/{hurl-D7obCYfg.js → hurl-JU97iWqA.js} +1 -1
- package/viewer/assets/{index-FMtYXcX7.js → index-CXBRQlCH.js} +5 -5
- package/viewer/assets/{index-Wz0qQyIk.css → index-D6HZB4Yz.css} +1 -1
- package/viewer/assets/{info-A6RAGUB7-CrzitQIU.js → info-A6RAGUB7-aRrZ0_i2.js} +1 -1
- package/viewer/assets/{infoDiagram-27XIBGKW-D2CgRDxu.js → infoDiagram-27XIBGKW-BnD3mUdL.js} +1 -1
- package/viewer/assets/{ishikawaDiagram-5VMMS53U-BhnQMHOo.js → ishikawaDiagram-5VMMS53U-u-wcafFg.js} +1 -1
- package/viewer/assets/{java-5VJU_EW8.js → java-BxAxXJLN.js} +1 -1
- package/viewer/assets/{javascript-r8UgndxQ.js → javascript-DNepMMwm.js} +1 -1
- package/viewer/assets/{jinja-BY2ibHG5.js → jinja-CfKdKg9T.js} +1 -1
- package/viewer/assets/{jison-C_7YxymZ.js → jison-C62ElGA9.js} +1 -1
- package/viewer/assets/{journeyDiagram-3NMN7TZE-DSBzKQEa.js → journeyDiagram-3NMN7TZE-E6uhr_fk.js} +1 -1
- package/viewer/assets/{json-8e1WlJYD.js → json-DSQqeQzH.js} +1 -1
- package/viewer/assets/{jsx-BYp5GD4Y.js → jsx-CpZi9Ceb.js} +1 -1
- package/viewer/assets/{julia-Bkob1uVX.js → julia-CypyJgFE.js} +1 -1
- package/viewer/assets/{just-CUnSjty-.js → just-_p8XAy70.js} +1 -1
- package/viewer/assets/{kanban-definition-UXKFOSKX-CotbrQue.js → kanban-definition-UXKFOSKX-Blo6hDj7.js} +1 -1
- package/viewer/assets/{latex-UdE3ivqk.js → latex-Blby6_jP.js} +1 -1
- package/viewer/assets/{line-DDh6a6hz.js → line-CQc5Trjj.js} +1 -1
- package/viewer/assets/{linear-BxMsCbKb.js → linear-BjWjnaEC.js} +1 -1
- package/viewer/assets/{liquid-WL4MvEIT.js → liquid-x3m9Bx2x.js} +1 -1
- package/viewer/assets/{lua-CtOubZta.js → lua-Da9XAgwV.js} +1 -1
- package/viewer/assets/{marko-C0GSQJi3.js → marko-Gu1d_h3t.js} +1 -1
- package/viewer/assets/{mdc-DUivddFc.js → mdc-CM0pUbEe.js} +1 -1
- package/viewer/assets/{mermaid-parser.core-FhKE_uv2.js → mermaid-parser.core-DR191xUW.js} +3 -3
- package/viewer/assets/{mermaid.core-BSOWwyvd.js → mermaid.core-DnwMH2U1.js} +4 -4
- package/viewer/assets/{mindmap-definition-YA3MSWOX-tsLZ_Opn.js → mindmap-definition-YA3MSWOX-KrnPcZeq.js} +1 -1
- package/viewer/assets/{nginx-B__INAtC.js → nginx-DAKCD0HY.js} +1 -1
- package/viewer/assets/{nim-UEY12GJF.js → nim-BvNTuhqF.js} +1 -1
- package/viewer/assets/{org-DDIZsz95.js → org-B-tOc6Cc.js} +1 -1
- package/viewer/assets/{packet-AYTQ26CC-CqdJnqfo.js → packet-AYTQ26CC-Cl2KBEou.js} +1 -1
- package/viewer/assets/{pegDiagram-XKGWAZYB-BJs7qu7m.js → pegDiagram-XKGWAZYB--GvmNzTl.js} +1 -1
- package/viewer/assets/{perl-D5KwNZt7.js → perl-RyNpCOE-.js} +1 -1
- package/viewer/assets/{php-BEs7d_Dk.js → php-D5gke6Nh.js} +1 -1
- package/viewer/assets/{pie-WAS4IAKB-lgzqBWqy.js → pie-WAS4IAKB-RfZPDbVI.js} +1 -1
- package/viewer/assets/{pieDiagram-E7YTZNPT-Cxe9LnnE.js → pieDiagram-E7YTZNPT-BbcD9IEY.js} +1 -1
- package/viewer/assets/{pug-B0dsfQOV.js → pug-CSZdPWzF.js} +1 -1
- package/viewer/assets/{qml-XPIhrIzf.js → qml-CCUSNo18.js} +1 -1
- package/viewer/assets/{quadrantDiagram-AXDQQJYC-D5JGwC11.js → quadrantDiagram-AXDQQJYC-DHP-nbSh.js} +1 -1
- package/viewer/assets/{r-C6hQdpIM.js → r-Cl6F5Lf8.js} +1 -1
- package/viewer/assets/{radar-RG4KPBEZ-B7JRLhUA.js → radar-RG4KPBEZ-DdfC1yOQ.js} +1 -1
- package/viewer/assets/{railroad-74A4TZTK-Df7ZQBLn.js → railroad-74A4TZTK-MHxcKgVS.js} +1 -1
- package/viewer/assets/railroad-abnf-HS5TGJTU-yEJXYTCu.js +1 -0
- package/viewer/assets/railroad-ebnf-LZEXJU2U-CEc058YK.js +1 -0
- package/viewer/assets/railroad-peg-WCYAUIDC-0iFSHGbV.js +1 -0
- package/viewer/assets/{railroadDiagram-O6MQD6OU-DZJzpmP8.js → railroadDiagram-O6MQD6OU-sxdxPqy-.js} +1 -1
- package/viewer/assets/{razor-C3KSUuOw.js → razor-hm0vLE-h.js} +1 -1
- package/viewer/assets/{regexp-n-T936Rk.js → regexp-BhIot3VY.js} +1 -1
- package/viewer/assets/{requirementDiagram-BXWQKSXE-Be9lEFrk.js → requirementDiagram-BXWQKSXE-CrZXt7Yu.js} +1 -1
- package/viewer/assets/{rst-fVnHDyXD.js → rst-C3giCu1C.js} +1 -1
- package/viewer/assets/{ruby-DuRgxlXF.js → ruby-B6fOYc5V.js} +1 -1
- package/viewer/assets/{sankeyDiagram-P5KCCOFB-BsgKAEBN.js → sankeyDiagram-P5KCCOFB-BVK_LjzN.js} +1 -1
- package/viewer/assets/{sas-C0WA2OFa.js → sas-a9NUQlsy.js} +1 -1
- package/viewer/assets/{scss-CQDZ4smR.js → scss-ChVMSp7G.js} +1 -1
- package/viewer/assets/{sequenceDiagram-WJ2MYXX4-BkUDWL0D.js → sequenceDiagram-WJ2MYXX4-B4E1wY9a.js} +1 -1
- package/viewer/assets/{shellscript-CE84G0GP.js → shellscript-Dxbnxou2.js} +1 -1
- package/viewer/assets/{shellsession-BdJvdaqL.js → shellsession-DWcRFAj_.js} +1 -1
- package/viewer/assets/{soy-BSxOREC0.js → soy-C-D-pvKx.js} +1 -1
- package/viewer/assets/{sql-D4MN9uRI.js → sql-W7nl9Rxy.js} +1 -1
- package/viewer/assets/{src-BT_kESTA.js → src-C_D1vmKd.js} +1 -1
- package/viewer/assets/{stata-B6nXAaGV.js → stata-BWq3CAeQ.js} +1 -1
- package/viewer/assets/{stateDiagram-D77RDMKH-C80wp8xG.js → stateDiagram-D77RDMKH-Dc8nXUDp.js} +1 -1
- package/viewer/assets/stateDiagram-v2-MP3YSRHH-SMxxOURe.js +1 -0
- package/viewer/assets/{surrealql-fVjZmhV3.js → surrealql-BkXUcx4E.js} +1 -1
- package/viewer/assets/{svelte-DnBQ5p7d.js → svelte-CowGUt9l.js} +1 -1
- package/viewer/assets/{swimlanes-42K2YHIH-Cff6yT8e.js → swimlanes-42K2YHIH-BtZAMLQ7.js} +1 -1
- package/viewer/assets/swimlanesDiagram-VR7AAH4N-C_XphOba.js +8 -0
- package/viewer/assets/{templ-TCx51Uts.js → templ-ejLYfFxc.js} +1 -1
- package/viewer/assets/{tex-CF6SMAQ_.js → tex-McefVK6r.js} +1 -1
- package/viewer/assets/{timeline-definition-24CTP7MA-Cje7BvaN.js → timeline-definition-24CTP7MA-TvSh-paH.js} +1 -1
- package/viewer/assets/{treeView-Q6P3EWNA-D-QLY3IO.js → treeView-Q6P3EWNA-BRIxIFdd.js} +1 -1
- package/viewer/assets/{treemap-WGGIJYW6-BCHcTa4N.js → treemap-WGGIJYW6-CeY__ApH.js} +1 -1
- package/viewer/assets/{ts-tags-BqLRnADX.js → ts-tags-D8LHJIWj.js} +1 -1
- package/viewer/assets/{tsx-D7KpDX0b.js → tsx-BkPshBHh.js} +1 -1
- package/viewer/assets/{twig-CEZLObpN.js → twig-CmfWCxbk.js} +1 -1
- package/viewer/assets/{typescript-DAbIDLbf.js → typescript-DnVmzADb.js} +1 -1
- package/viewer/assets/{typst-CqN7-whv.js → typst-BpEOIbiv.js} +1 -1
- package/viewer/assets/{vennDiagram-4TSXK5OY-Bz20rx02.js → vennDiagram-4TSXK5OY-Ba-jimVX.js} +1 -1
- package/viewer/assets/{vue-html-DQmvvKbd.js → vue-html-C-XYg42q.js} +1 -1
- package/viewer/assets/{vue-vine-Did3qTVW.js → vue-vine-DK68dTen.js} +1 -1
- package/viewer/assets/{vue-kTxN6wdc.js → vue-zII4ln6o.js} +1 -1
- package/viewer/assets/{wardley-WFR3VGLG-CpXaqOit.js → wardley-WFR3VGLG-e2A2dYzM.js} +1 -1
- package/viewer/assets/{wardleyDiagram-VM6X3IG4-Cz06jHpA.js → wardleyDiagram-VM6X3IG4-D2Rq1FsU.js} +1 -1
- package/viewer/assets/{xml-te2hFcAA.js → xml-Cc-dIbaq.js} +1 -1
- package/viewer/assets/{xsl-X4fuKSVl.js → xsl-C7A6UsbO.js} +1 -1
- package/viewer/assets/{xychartDiagram-S5SC5T6Z-BXCw0sfu.js → xychartDiagram-S5SC5T6Z-De55Qsdg.js} +1 -1
- package/viewer/assets/{yaml-NHtDSZab.js → yaml-BJLNLIRM.js} +1 -1
- package/viewer/index.html +2 -2
- package/viewer/assets/architecture-7GRP2DOG-Be250VKZ.js +0 -1
- package/viewer/assets/channel-DtULXRee.js +0 -1
- package/viewer/assets/classDiagram-ZZMXUADV-Bmqu01Xf.js +0 -1
- package/viewer/assets/classDiagram-v2-VYDZK3BY-Bmqu01Xf.js +0 -1
- package/viewer/assets/eventmodeling-NTZA5JFV-CJCg5f6p.js +0 -1
- package/viewer/assets/flowDiagram-HODETNUW-BFzq4Zvs.js +0 -1
- package/viewer/assets/railroad-abnf-HS5TGJTU-Z8q3QVTf.js +0 -1
- package/viewer/assets/railroad-ebnf-LZEXJU2U-BWoRkG3W.js +0 -1
- package/viewer/assets/railroad-peg-WCYAUIDC-BzoV1cN7.js +0 -1
- package/viewer/assets/stateDiagram-v2-MP3YSRHH-CYdsKKlz.js +0 -1
- package/viewer/assets/swimlanesDiagram-VR7AAH4N-niTUGjMT.js +0 -8
package/src/app/judge-run.ts
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
import { resolve, relative } from "node:path";
|
|
2
2
|
import type { EvalRun, JudgeRun } from "../types";
|
|
3
3
|
import type { ExecutionContext } from "./context";
|
|
4
|
-
import {
|
|
4
|
+
import { gradeRecording } from "./grade-recording";
|
|
5
5
|
import { errorMessage } from "../infra/files";
|
|
6
6
|
import { canJudgeEval } from "./eval-state";
|
|
7
7
|
import { JUDGE_PROTOCOL } from "../judgment";
|
|
8
8
|
import { JUDGE_AGENT } from "../infra/judging/agent";
|
|
9
9
|
|
|
10
|
-
/** A new
|
|
10
|
+
/** A new grading execution becomes active only after all present judges succeed. */
|
|
11
11
|
export async function judgeEvalRun(
|
|
12
12
|
context: ExecutionContext,
|
|
13
13
|
candidate: EvalRun,
|
|
14
14
|
monitoring: Pick<JudgeRun, "monitorError" | "monitorErrorAt"> = {},
|
|
15
15
|
): Promise<JudgeRun> {
|
|
16
16
|
if (!canJudgeEval(candidate))
|
|
17
|
-
throw new Error(
|
|
18
|
-
"Judging requires finalized evidence from a completed, stopped, or timed-out eval run",
|
|
19
|
-
);
|
|
17
|
+
throw new Error("Judging requires finalized candidate evidence");
|
|
20
18
|
const slot = context.results.slot(candidate.slotId)!;
|
|
21
19
|
const definition = context.definition.evals.find(
|
|
22
20
|
(item) => item.id === slot.evalId,
|
|
@@ -25,20 +23,22 @@ export async function judgeEvalRun(
|
|
|
25
23
|
evalRunId: candidate.id,
|
|
26
24
|
evidence: candidate.evidence,
|
|
27
25
|
rubric: definition.judge,
|
|
28
|
-
agent: JUDGE_AGENT,
|
|
29
|
-
model: context.definition.judge.model,
|
|
26
|
+
agent: definition.judge ? JUDGE_AGENT : undefined,
|
|
27
|
+
model: definition.judge ? context.definition.judge.model : undefined,
|
|
28
|
+
kind: definition.code ? (definition.judge ? "hybrid" : "code") : "llm",
|
|
29
|
+
code: definition.code,
|
|
30
30
|
judgeHash: slot.judgeHash,
|
|
31
31
|
timeoutMs: context.definition.judge.timeoutMs,
|
|
32
32
|
websearch: context.definition.judge.websearch,
|
|
33
33
|
mode: "final",
|
|
34
34
|
runtimeHash: context.runtime.judgeHash,
|
|
35
35
|
protocol: JUDGE_PROTOCOL,
|
|
36
|
-
|
|
36
|
+
criteria: definition.criteria,
|
|
37
37
|
});
|
|
38
38
|
const directory = resolve(context.directory, "judge-runs", run.id);
|
|
39
39
|
let completed: JudgeRun;
|
|
40
40
|
try {
|
|
41
|
-
const
|
|
41
|
+
const graded = await gradeRecording(
|
|
42
42
|
{
|
|
43
43
|
...run.input,
|
|
44
44
|
evidence: {
|
|
@@ -46,6 +46,14 @@ export async function judgeEvalRun(
|
|
|
46
46
|
directory: resolve(context.directory, run.input.evidence.directory),
|
|
47
47
|
},
|
|
48
48
|
},
|
|
49
|
+
{
|
|
50
|
+
evidence: {
|
|
51
|
+
...candidate.evidence,
|
|
52
|
+
directory: resolve(context.directory, candidate.evidence.directory),
|
|
53
|
+
},
|
|
54
|
+
run: candidate,
|
|
55
|
+
runDirectory: context.directory,
|
|
56
|
+
},
|
|
49
57
|
directory,
|
|
50
58
|
(event) => {
|
|
51
59
|
const record = {
|
|
@@ -61,16 +69,25 @@ export async function judgeEvalRun(
|
|
|
61
69
|
completed = {
|
|
62
70
|
...run,
|
|
63
71
|
...monitoring,
|
|
64
|
-
state:
|
|
65
|
-
judgment,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
state: graded.state,
|
|
73
|
+
judgment: graded.judgment,
|
|
74
|
+
code: graded.code
|
|
75
|
+
? {
|
|
76
|
+
...graded.code,
|
|
77
|
+
stdout: relative(context.directory, graded.code.stdout),
|
|
78
|
+
stderr: relative(context.directory, graded.code.stderr),
|
|
79
|
+
}
|
|
80
|
+
: undefined,
|
|
81
|
+
session: graded.session
|
|
82
|
+
? {
|
|
83
|
+
...graded.session,
|
|
84
|
+
database: relative(
|
|
85
|
+
context.directory,
|
|
86
|
+
resolve(directory, graded.session.database),
|
|
87
|
+
),
|
|
88
|
+
}
|
|
89
|
+
: undefined,
|
|
90
|
+
error: graded.error,
|
|
74
91
|
completedAt: new Date().toISOString(),
|
|
75
92
|
elapsedMs: Date.now() - Date.parse(run.startedAt),
|
|
76
93
|
};
|
|
@@ -9,7 +9,8 @@ import type {
|
|
|
9
9
|
ModelRef,
|
|
10
10
|
} from "../types";
|
|
11
11
|
import { CANDIDATE_TIMEOUT_MS } from "../types";
|
|
12
|
-
import {
|
|
12
|
+
import { rubricCriteria } from "../judgment";
|
|
13
|
+
import { compileCodeJudge } from "../infra/judging/code-source";
|
|
13
14
|
import { monitorPolicy } from "./monitor-policy";
|
|
14
15
|
import {
|
|
15
16
|
fingerprint,
|
|
@@ -41,9 +42,14 @@ async function declaration<T>(path: string): Promise<T> {
|
|
|
41
42
|
async function loadEval(directory: string): Promise<EvalDefinition> {
|
|
42
43
|
const id = basename(directory),
|
|
43
44
|
prompt = Bun.file(resolve(directory, "prompt.md")),
|
|
44
|
-
judge = Bun.file(resolve(directory, "judge.md"))
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
judge = Bun.file(resolve(directory, "judge.md")),
|
|
46
|
+
codeFile = resolve(directory, "judge.ts");
|
|
47
|
+
const hasMarkdown = await judge.exists(),
|
|
48
|
+
hasCode = await Bun.file(codeFile).exists();
|
|
49
|
+
if (!(await prompt.exists()) || (!hasMarkdown && !hasCode))
|
|
50
|
+
throw new Error(
|
|
51
|
+
`${id} requires prompt.md and at least one of judge.md or judge.ts`,
|
|
52
|
+
);
|
|
47
53
|
const settings = (await Bun.file(resolve(directory, "eval.ts")).exists())
|
|
48
54
|
? await declaration<Eval>(resolve(directory, "eval.ts"))
|
|
49
55
|
: {};
|
|
@@ -56,6 +62,10 @@ async function loadEval(directory: string): Promise<EvalDefinition> {
|
|
|
56
62
|
)
|
|
57
63
|
throw new Error(`${id}/eval.ts has unsupported settings`);
|
|
58
64
|
monitorPolicy(settings.earlyStop);
|
|
65
|
+
if (hasCode && settings.earlyStop)
|
|
66
|
+
throw new Error(
|
|
67
|
+
`${id}: judge.ts grades finalized recordings; earlyStop requires a Markdown-only judge`,
|
|
68
|
+
);
|
|
59
69
|
const source: unknown[] = [];
|
|
60
70
|
if (settings.workspace) {
|
|
61
71
|
const workspace = settings.workspace;
|
|
@@ -157,9 +167,10 @@ async function loadEval(directory: string): Promise<EvalDefinition> {
|
|
|
157
167
|
throw new Error(`${id}: preparation requires argv`);
|
|
158
168
|
}
|
|
159
169
|
const promptText = await prompt.text(),
|
|
160
|
-
judgeText = await judge.text();
|
|
161
|
-
if (!promptText.trim() || !judgeText.trim())
|
|
170
|
+
judgeText = hasMarkdown ? await judge.text() : "";
|
|
171
|
+
if (!promptText.trim() || (hasMarkdown && !judgeText.trim()))
|
|
162
172
|
throw new Error(`${id}: prompt and judge must not be empty`);
|
|
173
|
+
const code = hasCode ? await compileCodeJudge(codeFile) : undefined;
|
|
163
174
|
return {
|
|
164
175
|
id,
|
|
165
176
|
directory,
|
|
@@ -170,8 +181,9 @@ async function loadEval(directory: string): Promise<EvalDefinition> {
|
|
|
170
181
|
settings: { workspace: settings.workspace, prepare: settings.prepare },
|
|
171
182
|
source,
|
|
172
183
|
}),
|
|
173
|
-
judgeHash:
|
|
174
|
-
|
|
184
|
+
judgeHash: fingerprint({ rubric: judgeText, code: code?.hash }),
|
|
185
|
+
criteria: hasMarkdown ? rubricCriteria(judgeText) : [],
|
|
186
|
+
...(code ? { code } : {}),
|
|
175
187
|
name: /^# (.+)$/m.exec(judgeText)?.[1] ?? id,
|
|
176
188
|
};
|
|
177
189
|
}
|
|
@@ -187,10 +199,9 @@ export async function loadBenchmark(
|
|
|
187
199
|
if (
|
|
188
200
|
!definition ||
|
|
189
201
|
!Array.isArray(definition.models) ||
|
|
190
|
-
!definition.models.length
|
|
191
|
-
!definition.judge
|
|
202
|
+
!definition.models.length
|
|
192
203
|
)
|
|
193
|
-
throw new Error("benchmark.ts requires models
|
|
204
|
+
throw new Error("benchmark.ts requires models");
|
|
194
205
|
if (
|
|
195
206
|
Object.keys(definition).some(
|
|
196
207
|
(key) =>
|
|
@@ -207,6 +218,18 @@ export async function loadBenchmark(
|
|
|
207
218
|
)
|
|
208
219
|
throw new Error("benchmark.ts contains unsupported settings");
|
|
209
220
|
const models = definition.models.map(modelRef);
|
|
221
|
+
if (
|
|
222
|
+
definition.judge !== undefined &&
|
|
223
|
+
(!definition.judge ||
|
|
224
|
+
typeof definition.judge !== "object" ||
|
|
225
|
+
Array.isArray(definition.judge) ||
|
|
226
|
+
Object.keys(definition.judge).some(
|
|
227
|
+
(key) => !["model", "timeoutMs", "websearch"].includes(key),
|
|
228
|
+
))
|
|
229
|
+
)
|
|
230
|
+
throw new Error(
|
|
231
|
+
"judge must be an object with model, timeoutMs, or websearch settings",
|
|
232
|
+
);
|
|
210
233
|
if (new Set(models).size !== models.length)
|
|
211
234
|
throw new Error("Benchmark contains duplicate models");
|
|
212
235
|
const timeoutMs = positive(
|
|
@@ -224,6 +247,8 @@ export async function loadBenchmark(
|
|
|
224
247
|
const evals = await Promise.all(
|
|
225
248
|
directories.map((entry) => loadEval(resolve(evalRoot, entry.name))),
|
|
226
249
|
);
|
|
250
|
+
if (evals.some((item) => item.judge) && !definition.judge?.model)
|
|
251
|
+
throw new Error("A benchmark containing judge.md requires judge.model");
|
|
227
252
|
const concurrency = positive(definition.concurrency, 10, "Concurrency");
|
|
228
253
|
if (concurrency < 2 && evals.some((item) => item.settings.earlyStop))
|
|
229
254
|
throw new Error(
|
|
@@ -234,7 +259,7 @@ export async function loadBenchmark(
|
|
|
234
259
|
throw new Error("Container engine must be docker or podman");
|
|
235
260
|
for (const search of [
|
|
236
261
|
definition.candidate?.websearch,
|
|
237
|
-
definition.judge
|
|
262
|
+
definition.judge?.websearch,
|
|
238
263
|
])
|
|
239
264
|
if (search !== undefined && search !== false && search !== "exa")
|
|
240
265
|
throw new Error("Websearch must be exa or false");
|
|
@@ -253,9 +278,15 @@ export async function loadBenchmark(
|
|
|
253
278
|
: {}),
|
|
254
279
|
},
|
|
255
280
|
judge: {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
281
|
+
...(definition.judge?.model
|
|
282
|
+
? { model: modelRef(definition.judge.model) }
|
|
283
|
+
: {}),
|
|
284
|
+
timeoutMs: positive(
|
|
285
|
+
definition.judge?.timeoutMs,
|
|
286
|
+
600_000,
|
|
287
|
+
"Judge timeout",
|
|
288
|
+
),
|
|
289
|
+
websearch: definition.judge?.websearch ?? "exa",
|
|
259
290
|
},
|
|
260
291
|
container: {
|
|
261
292
|
engine,
|
package/src/app/read-results.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
} from "../runtime";
|
|
27
27
|
import { canJudgeEval } from "./eval-state";
|
|
28
28
|
import { CandidateEvidence, type EvidenceQuery } from "../infra/evidence";
|
|
29
|
+
import { contained } from "../infra/files";
|
|
29
30
|
|
|
30
31
|
const scheduled = (slot: Slot, benchmark: BenchmarkRun, now: number) =>
|
|
31
32
|
benchmark.state === "running" &&
|
|
@@ -33,6 +34,8 @@ const scheduled = (slot: Slot, benchmark: BenchmarkRun, now: number) =>
|
|
|
33
34
|
benchmark.scheduledSlotIds.includes(slot.id);
|
|
34
35
|
|
|
35
36
|
const costOf = (run: EvalRun | JudgeRun, results?: Results): Cost => {
|
|
37
|
+
if ("evalRunId" in run.input && run.input.kind === "code")
|
|
38
|
+
return { usd: 0, reportedUSD: 0, complete: true };
|
|
36
39
|
const usd = run.session?.accounting?.costUSD;
|
|
37
40
|
return {
|
|
38
41
|
usd: usd ?? null,
|
|
@@ -162,6 +165,21 @@ export class ResultReader {
|
|
|
162
165
|
using results = await this.database(benchmarkId);
|
|
163
166
|
const judge = results.judgeRun(judgeRunId);
|
|
164
167
|
if (!judge) throw new Error("Unknown judge run");
|
|
168
|
+
const candidate = results.evalRun(judge.input.evalRunId);
|
|
169
|
+
const criteria = new Map(
|
|
170
|
+
judge.input.criteria.map((criterion) => [criterion.id, criterion]),
|
|
171
|
+
);
|
|
172
|
+
for (const id of Object.keys(judge.judgment?.scores ?? {}))
|
|
173
|
+
if (!criteria.has(id))
|
|
174
|
+
criteria.set(id, { id, name: id.replaceAll("_", " ") });
|
|
175
|
+
const log = async (path?: string) =>
|
|
176
|
+
path
|
|
177
|
+
? (
|
|
178
|
+
await Bun.file(contained(dirname(results.path), path))
|
|
179
|
+
.text()
|
|
180
|
+
.catch(() => "")
|
|
181
|
+
).slice(0, 40_000)
|
|
182
|
+
: undefined;
|
|
165
183
|
return {
|
|
166
184
|
judge: {
|
|
167
185
|
id: judge.id,
|
|
@@ -172,8 +190,15 @@ export class ResultReader {
|
|
|
172
190
|
monitorErrorAt: judge.monitorErrorAt,
|
|
173
191
|
monitorLimit: judge.monitorLimit,
|
|
174
192
|
judgment: judge.judgment,
|
|
193
|
+
code: judge.code,
|
|
194
|
+
error: judge.error,
|
|
175
195
|
},
|
|
176
|
-
|
|
196
|
+
kind: judge.input.kind,
|
|
197
|
+
criteria: [...criteria.values()],
|
|
198
|
+
metrics: candidate?.metrics ?? judge.code?.metrics,
|
|
199
|
+
codeSource: judge.input.code?.source,
|
|
200
|
+
codeStdout: await log(judge.code?.stdout),
|
|
201
|
+
codeStderr: await log(judge.code?.stderr),
|
|
177
202
|
stop: results.evalRun(judge.input.evalRunId)?.stop,
|
|
178
203
|
checks: results.judgeChecks(judgeRunId).map((check) => {
|
|
179
204
|
const start = timestampMs(check.executionStartedAt);
|
|
@@ -421,6 +446,7 @@ function stageState(
|
|
|
421
446
|
runtime,
|
|
422
447
|
cost: costOf(run, results),
|
|
423
448
|
message: run.error,
|
|
449
|
+
...("kind" in run.input ? { kind: run.input.kind } : {}),
|
|
424
450
|
};
|
|
425
451
|
}
|
|
426
452
|
|
|
@@ -470,6 +496,13 @@ function liveRun(
|
|
|
470
496
|
evalStage.status,
|
|
471
497
|
);
|
|
472
498
|
const judgeStage: StageState = {
|
|
499
|
+
kind: benchmark.definition.evals.find((item) => item.id === slot.evalId)
|
|
500
|
+
?.code
|
|
501
|
+
? benchmark.definition.evals.find((item) => item.id === slot.evalId)
|
|
502
|
+
?.judge
|
|
503
|
+
? "hybrid"
|
|
504
|
+
: "code"
|
|
505
|
+
: "llm",
|
|
473
506
|
...stageState(
|
|
474
507
|
judge,
|
|
475
508
|
stale,
|
|
@@ -486,7 +519,7 @@ function liveRun(
|
|
|
486
519
|
...(judge?.state === "completed"
|
|
487
520
|
? {
|
|
488
521
|
score: judge.judgment?.value ?? null,
|
|
489
|
-
|
|
522
|
+
scores: judge.judgment?.scores,
|
|
490
523
|
}
|
|
491
524
|
: {}),
|
|
492
525
|
};
|
package/src/app/read-run.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { CandidateEvidence } from "../infra/evidence";
|
|
|
4
4
|
import type { EvidenceRef, Judgment } from "../types";
|
|
5
5
|
import type { EvidenceView } from "../evidence";
|
|
6
6
|
import { validateCitations } from "../infra/judging/contract";
|
|
7
|
+
import { openRecording } from "../infra/recording";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
7
9
|
|
|
8
10
|
/** Read-only records for maintenance clients. Finalized evidence remains authoritative. */
|
|
9
11
|
export function readBenchmarkRun(directory: string) {
|
|
@@ -29,7 +31,26 @@ export async function readEvidence(
|
|
|
29
31
|
return (await CandidateEvidence.open(ref.directory, ref.hash)).view(ref);
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
/**
|
|
34
|
+
/** Open all recorded data with lazy native readers; dispose after inspection. */
|
|
35
|
+
export async function readRecording(directory: string, evalRunId: string) {
|
|
36
|
+
using results = new Results(resolve(directory, "runner.db"), true);
|
|
37
|
+
const run = results.evalRun(evalRunId);
|
|
38
|
+
if (!run?.evidence)
|
|
39
|
+
throw new Error("Select an EvalRun with finalized evidence");
|
|
40
|
+
return openRecording(
|
|
41
|
+
{
|
|
42
|
+
run,
|
|
43
|
+
runDirectory: resolve(directory),
|
|
44
|
+
evidence: {
|
|
45
|
+
...run.evidence,
|
|
46
|
+
directory: resolve(directory, run.evidence.directory),
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
process.platform === "win32" ? "C:/tmp/opencode" : tmpdir(),
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Reference integrity only; interpretation of task facts stays in the judges. */
|
|
33
54
|
export async function verifyJudgmentEvidence(
|
|
34
55
|
judgment: Judgment,
|
|
35
56
|
reference: EvidenceRef,
|
|
@@ -38,6 +59,6 @@ export async function verifyJudgmentEvidence(
|
|
|
38
59
|
await validateCitations(judgment, evidence);
|
|
39
60
|
return {
|
|
40
61
|
hash: evidence.checkpoint.hash,
|
|
41
|
-
|
|
62
|
+
criteria: Object.keys(judgment.scores).length,
|
|
42
63
|
};
|
|
43
64
|
}
|
package/src/app/rejudge.ts
CHANGED
package/src/app/run-benchmark.ts
CHANGED
|
@@ -20,6 +20,7 @@ import { judgeEvalRun } from "./judge-run";
|
|
|
20
20
|
import type { ExecutionContext } from "./context";
|
|
21
21
|
import { canJudgeEval } from "./eval-state";
|
|
22
22
|
import { isScored } from "../judgment";
|
|
23
|
+
import { benchmarkScores } from "./scores";
|
|
23
24
|
import { CostBudget, estimateWork } from "./cost-plan";
|
|
24
25
|
|
|
25
26
|
export type RunBenchmarkOptions = {
|
|
@@ -79,6 +80,9 @@ export function finishBenchmark(context: ExecutionContext) {
|
|
|
79
80
|
judges.some(
|
|
80
81
|
(run) => run.id === slot.judgeRunId && isScored(run.judgment?.value),
|
|
81
82
|
),
|
|
83
|
+
) &&
|
|
84
|
+
benchmarkScores(context.definition, slots, judges).every(
|
|
85
|
+
(score) => score.percentage !== null,
|
|
82
86
|
);
|
|
83
87
|
const currentInputs = planBenchmark(
|
|
84
88
|
context.definition,
|
|
@@ -67,6 +67,7 @@ export async function runEvalPipeline(
|
|
|
67
67
|
evalRunId: candidate!.id,
|
|
68
68
|
evidence: saved,
|
|
69
69
|
rubric: definition.judge,
|
|
70
|
+
kind: "llm",
|
|
70
71
|
agent: JUDGE_AGENT,
|
|
71
72
|
model: context.definition.judge.model,
|
|
72
73
|
judgeHash: slot.judgeHash,
|
|
@@ -75,7 +76,7 @@ export async function runEvalPipeline(
|
|
|
75
76
|
mode: "monitor",
|
|
76
77
|
runtimeHash: context.runtime.judgeHash,
|
|
77
78
|
protocol: JUDGE_PROTOCOL,
|
|
78
|
-
|
|
79
|
+
criteria: definition.criteria,
|
|
79
80
|
monitor: policy,
|
|
80
81
|
});
|
|
81
82
|
return saved;
|
package/src/app/run-eval.ts
CHANGED
|
@@ -3,6 +3,8 @@ import type { Slot, EvalRun } from "../types";
|
|
|
3
3
|
import type { ExecutionContext } from "./context";
|
|
4
4
|
import { executeCandidate } from "../infra/containers/candidate";
|
|
5
5
|
import type { EvidenceFeed } from "../evidence";
|
|
6
|
+
import { CandidateEvidence } from "../infra/evidence";
|
|
7
|
+
import { measureRecording } from "../infra/recording/metrics";
|
|
6
8
|
|
|
7
9
|
/** The normal candidate use case: record its inputs, execute, finalize its evidence. */
|
|
8
10
|
export async function runEval(
|
|
@@ -88,6 +90,17 @@ export async function runEval(
|
|
|
88
90
|
}
|
|
89
91
|
: undefined,
|
|
90
92
|
};
|
|
93
|
+
if (completed.evidence) {
|
|
94
|
+
const evidence = await CandidateEvidence.open(
|
|
95
|
+
resolve(context.directory, completed.evidence.directory),
|
|
96
|
+
completed.evidence.hash,
|
|
97
|
+
);
|
|
98
|
+
completed.metrics = measureRecording(
|
|
99
|
+
evidence.rawEvents(),
|
|
100
|
+
evidence.toolCalls(),
|
|
101
|
+
completed.evidence,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
91
104
|
context.results.finishEval(completed);
|
|
92
105
|
return completed;
|
|
93
106
|
}
|
package/src/app/scores.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { BenchmarkDefinition, JudgeRun, Slot } from "../types";
|
|
2
2
|
import { modelScore } from "../view";
|
|
3
|
+
import { isScored } from "../judgment";
|
|
3
4
|
|
|
4
5
|
/** Scores are derived from a single selection snapshot; every eval has equal weight. */
|
|
5
6
|
export function benchmarkScores(
|
|
@@ -9,46 +10,87 @@ export function benchmarkScores(
|
|
|
9
10
|
evalId?: string,
|
|
10
11
|
) {
|
|
11
12
|
const index = new Map(judges.map((run) => [run.id, run]));
|
|
13
|
+
const evals = definition.evals.filter(
|
|
14
|
+
(item) => !evalId || item.id === evalId,
|
|
15
|
+
);
|
|
16
|
+
const definitions = new Map(
|
|
17
|
+
evals.map((item) => {
|
|
18
|
+
const criteria = new Map(
|
|
19
|
+
item.criteria.map((criterion) => [criterion.id, criterion]),
|
|
20
|
+
);
|
|
21
|
+
for (const slot of slots.filter(
|
|
22
|
+
(slot) => slot.active && slot.evalId === item.id,
|
|
23
|
+
)) {
|
|
24
|
+
const judgment = slot.judgeRunId
|
|
25
|
+
? index.get(slot.judgeRunId)?.judgment
|
|
26
|
+
: undefined;
|
|
27
|
+
for (const id of Object.keys(judgment?.scores ?? {}))
|
|
28
|
+
if (!criteria.has(id))
|
|
29
|
+
criteria.set(id, { id, name: id.replaceAll("_", " ") });
|
|
30
|
+
}
|
|
31
|
+
return [item.id, [...criteria.values()]];
|
|
32
|
+
}),
|
|
33
|
+
);
|
|
12
34
|
return definition.models.map((model) =>
|
|
13
35
|
modelScore(
|
|
14
36
|
model,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
37
|
+
evals.flatMap((item) => {
|
|
38
|
+
const criteria = definitions.get(item.id)!;
|
|
39
|
+
const selected = slots.filter(
|
|
40
|
+
(slot) =>
|
|
41
|
+
slot.active && slot.evalId === item.id && slot.model === model,
|
|
42
|
+
);
|
|
43
|
+
return criteria.map((criterion) => {
|
|
44
|
+
const values = selected
|
|
45
|
+
.map(
|
|
46
|
+
(slot) =>
|
|
47
|
+
(slot.judgeRunId
|
|
48
|
+
? index.get(slot.judgeRunId)?.judgment?.scores
|
|
49
|
+
: undefined)?.[criterion.id]?.value,
|
|
50
|
+
)
|
|
51
|
+
.filter(isScored);
|
|
52
|
+
const scoredSum = values.reduce<number>(
|
|
53
|
+
(sum, value) => sum + value,
|
|
54
|
+
0,
|
|
22
55
|
);
|
|
23
|
-
return
|
|
24
|
-
|
|
25
|
-
|
|
56
|
+
return {
|
|
57
|
+
eval: item.id,
|
|
58
|
+
criterion: criterion.id,
|
|
59
|
+
name: criterion.name,
|
|
60
|
+
value:
|
|
61
|
+
values.length === definition.repetitions
|
|
62
|
+
? scoredSum / definition.repetitions
|
|
63
|
+
: null,
|
|
64
|
+
scored: values.length,
|
|
65
|
+
expected: definition.repetitions,
|
|
66
|
+
passed: values.filter((value) => value === 1).length,
|
|
67
|
+
scoredSum,
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
}),
|
|
71
|
+
evals.map((item) => item.id),
|
|
72
|
+
evals
|
|
73
|
+
.filter(
|
|
74
|
+
(item) =>
|
|
75
|
+
item.code &&
|
|
76
|
+
slots
|
|
77
|
+
.filter(
|
|
26
78
|
(slot) =>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
)?.find((value) => value.id === metric.id)?.value,
|
|
79
|
+
slot.active &&
|
|
80
|
+
slot.evalId === item.id &&
|
|
81
|
+
slot.model === model,
|
|
31
82
|
)
|
|
32
|
-
.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
? scoredSum / definition.repetitions
|
|
44
|
-
: null,
|
|
45
|
-
scored: values.length,
|
|
46
|
-
expected: definition.repetitions,
|
|
47
|
-
passed: scoredSum,
|
|
48
|
-
scoredSum,
|
|
49
|
-
};
|
|
50
|
-
});
|
|
51
|
-
}),
|
|
83
|
+
.some((slot) => {
|
|
84
|
+
const judge = slot.judgeRunId
|
|
85
|
+
? index.get(slot.judgeRunId)
|
|
86
|
+
: undefined;
|
|
87
|
+
return (
|
|
88
|
+
judge?.code?.state !== "completed" ||
|
|
89
|
+
judge.input.code?.hash !== item.code!.hash
|
|
90
|
+
);
|
|
91
|
+
}),
|
|
92
|
+
)
|
|
93
|
+
.map((item) => item.id),
|
|
52
94
|
),
|
|
53
95
|
);
|
|
54
96
|
}
|
package/src/app/serve-results.ts
CHANGED
|
@@ -66,6 +66,8 @@ export async function serveResults(options: {
|
|
|
66
66
|
if (value !== null) query[key] = Number(value);
|
|
67
67
|
}
|
|
68
68
|
const revision = url.searchParams.get("revision");
|
|
69
|
+
if (url.searchParams.has("metric"))
|
|
70
|
+
query.metric = url.searchParams.get("metric")!;
|
|
69
71
|
if (revision === "initial" || revision === "final")
|
|
70
72
|
query.revision = revision;
|
|
71
73
|
return Response.json(
|
package/src/evidence.ts
CHANGED
|
@@ -11,7 +11,10 @@ export type EvidenceQuery = {
|
|
|
11
11
|
| "tool"
|
|
12
12
|
| "artifacts"
|
|
13
13
|
| "artifact"
|
|
14
|
-
| "diff"
|
|
14
|
+
| "diff"
|
|
15
|
+
| "metrics";
|
|
16
|
+
/** A dot-separated measurement path for the metrics query. */
|
|
17
|
+
metric?: string;
|
|
15
18
|
sessionID?: string;
|
|
16
19
|
type?: string;
|
|
17
20
|
id?: string;
|
package/src/index.ts
CHANGED
|
@@ -8,8 +8,8 @@ export type {
|
|
|
8
8
|
EvalRun,
|
|
9
9
|
JudgeRun,
|
|
10
10
|
Judgment,
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
CriterionDefinition,
|
|
12
|
+
CriterionScore,
|
|
13
13
|
EvidenceCitation,
|
|
14
14
|
ToolCall,
|
|
15
15
|
MonitorPolicy,
|
|
@@ -30,7 +30,18 @@ export type {
|
|
|
30
30
|
JudgeSession,
|
|
31
31
|
} from "./evidence";
|
|
32
32
|
export { CANDIDATE_TIMEOUT_MS } from "./types";
|
|
33
|
-
export {
|
|
33
|
+
export { rubricCriteria, criterionMean, isScored } from "./judgment";
|
|
34
|
+
export type {
|
|
35
|
+
JudgeContext,
|
|
36
|
+
JudgeFunction,
|
|
37
|
+
JsonValue,
|
|
38
|
+
ScoreValue,
|
|
39
|
+
RunMetrics,
|
|
40
|
+
ToolMetrics,
|
|
41
|
+
RecordedEvent,
|
|
42
|
+
RecordedMessage,
|
|
43
|
+
RecordedFile,
|
|
44
|
+
} from "./judge-context";
|
|
34
45
|
export { loadBenchmark } from "./app/load-benchmark";
|
|
35
46
|
export {
|
|
36
47
|
runBenchmark,
|
|
@@ -47,6 +58,7 @@ export { judgeEvidence, recordEvidence } from "./app/judge-evidence";
|
|
|
47
58
|
export {
|
|
48
59
|
readBenchmarkRun,
|
|
49
60
|
readEvidence,
|
|
61
|
+
readRecording,
|
|
50
62
|
verifyJudgmentEvidence,
|
|
51
63
|
} from "./app/read-run";
|
|
52
64
|
export { snapshotBenchmarkRun } from "./app/snapshot-run";
|