@hona/openeval 0.2.2 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/JUDGING.md +135 -23
- package/README.md +71 -9
- package/package.json +7 -6
- 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 +48 -16
- 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 +8 -1
- 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/containers/runtime/package.json +2 -2
- package/src/infra/containers/runtime/server.mjs +1 -1
- 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 +2 -0
- package/src/infra/recording/index.ts +240 -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/THIRD_PARTY_LICENSES.md +2 -2
- package/viewer/assets/{abnfDiagram-VCTEODGH-B1kcYgQG.js → abnfDiagram-VCTEODGH-Ck7reUId.js} +1 -1
- package/viewer/assets/{angular-html-DrYCUiZv.js → angular-html-DzRW817u.js} +1 -1
- package/viewer/assets/{angular-ts-BgjwQn-Z.js → angular-ts-Dwpo5JSv.js} +1 -1
- package/viewer/assets/{apl-DlHqe8o4.js → apl-bt59SDvg.js} +1 -1
- package/viewer/assets/{arc-C4nf7ZoY.js → arc-Dwbl2Pkh.js} +1 -1
- package/viewer/assets/architecture-7GRP2DOG-BZpt0zSq.js +1 -0
- package/viewer/assets/{architectureDiagram-5GKGNRK7-BIWoe0fO.js → architectureDiagram-5GKGNRK7-BcmO-Qqp.js} +1 -1
- package/viewer/assets/{astro-BrlHnIh9.js → astro-B3siF1pJ.js} +1 -1
- package/viewer/assets/{blade-DOcerOiW.js → blade-BevF_cYv.js} +1 -1
- package/viewer/assets/{blockDiagram-I7D4REHJ-C3x13a9m.js → blockDiagram-I7D4REHJ-MzX9_xf9.js} +1 -1
- package/viewer/assets/{c-BMbThxEo.js → c-gavBjOcY.js} +1 -1
- package/viewer/assets/{c4Diagram-7LVT6UL2-BeWktchx.js → c4Diagram-7LVT6UL2-BbHHPJGg.js} +1 -1
- package/viewer/assets/channel-BnnBJr7O.js +1 -0
- package/viewer/assets/{chapel-k2cjkSmc.js → chapel-DgshBe1K.js} +1 -1
- package/viewer/assets/{chunk-4HAMMTFA-o6YtJsqE.js → chunk-4HAMMTFA-D1Gsg_qO.js} +1 -1
- package/viewer/assets/{chunk-75Z2AOVW-KohQa9Nw.js → chunk-75Z2AOVW-EfPG3FOY.js} +1 -1
- package/viewer/assets/{chunk-DU6HZSFF-C88wxc6m.js → chunk-DU6HZSFF-BxB0lceI.js} +1 -1
- package/viewer/assets/{chunk-F27PBJKO-mO4AP2as.js → chunk-F27PBJKO-DRBDr_-Q.js} +1 -1
- package/viewer/assets/{chunk-GMAD6QVW-DzQX2Cld.js → chunk-GMAD6QVW-AbIWvPs8.js} +1 -1
- package/viewer/assets/{chunk-GVQU2GXP-CS78RfJD.js → chunk-GVQU2GXP-aIYNUxo9.js} +1 -1
- package/viewer/assets/{chunk-IMKFNOWR-DxS42GUo.js → chunk-IMKFNOWR-BwpTTnl_.js} +1 -1
- package/viewer/assets/{chunk-L3NEJ4N5-DGo-uYLy.js → chunk-L3NEJ4N5-KtxD1mfg.js} +1 -1
- package/viewer/assets/{chunk-OSK3NFVY-BOcXQG16.js → chunk-OSK3NFVY-CinbAXbX.js} +1 -1
- package/viewer/assets/{chunk-P2QGCYS3-B7GnZdIQ.js → chunk-P2QGCYS3-Dst8DZSR.js} +1 -1
- package/viewer/assets/{chunk-POPQ4Y6H-DgBcYHog.js → chunk-POPQ4Y6H-DqvBdud7.js} +1 -1
- package/viewer/assets/{chunk-PWAF6VOD-DpEq6qHA.js → chunk-PWAF6VOD-Cl2eG05g.js} +1 -1
- package/viewer/assets/{chunk-SHT3W25Y-CrOGxKM2.js → chunk-SHT3W25Y-D9FbZ836.js} +1 -1
- package/viewer/assets/{chunk-SVP7TREG-4HY7Fljj.js → chunk-SVP7TREG-_4n_lRpO.js} +1 -1
- package/viewer/assets/{chunk-TICWLB2K-B1Rl31EC.js → chunk-TICWLB2K-DUXjjJlY.js} +1 -1
- package/viewer/assets/{chunk-XXDRQBXY-CK8giEW-.js → chunk-XXDRQBXY-BdRoSapX.js} +1 -1
- package/viewer/assets/classDiagram-ZZMXUADV-F9J3BKRU.js +1 -0
- package/viewer/assets/classDiagram-v2-VYDZK3BY-F9J3BKRU.js +1 -0
- package/viewer/assets/{cobol-CupUwvw9.js → cobol-D5zqvXzY.js} +1 -1
- package/viewer/assets/{coffee-C17pkozF.js → coffee-SCAyVn9N.js} +1 -1
- package/viewer/assets/{cose-bilkent-JH36ORCC-V1OmrmCv.js → cose-bilkent-JH36ORCC-B5uDWB-J.js} +1 -1
- package/viewer/assets/{cpp-BJwVQVXg.js → cpp-RUQ97EK5.js} +1 -1
- package/viewer/assets/{crystal-BF-oCN-L.js → crystal-FauNVdkE.js} +1 -1
- package/viewer/assets/{css-BMgkVI3c.js → css-DuzOk7di.js} +1 -1
- package/viewer/assets/{cynefin-OW5HDTMX-BEjY_gsc.js → cynefin-OW5HDTMX-D0N8Dm6P.js} +1 -1
- package/viewer/assets/{cynefinDiagram-5FMLGOSQ-bfSYgr6z.js → cynefinDiagram-5FMLGOSQ-IGGiqH_Y.js} +1 -1
- package/viewer/assets/{dagre-GXQ25YYZ-VtwTgGfa.js → dagre-GXQ25YYZ-PoopsFcY.js} +1 -1
- package/viewer/assets/{diagram-S7CK7UJ4-CHaAAyW7.js → diagram-S7CK7UJ4-D6GuIlRD.js} +1 -1
- package/viewer/assets/{diagram-UQ7AKVKN-CjL65-As.js → diagram-UQ7AKVKN-Cj8lu7Hi.js} +1 -1
- package/viewer/assets/{diagram-VSXAHHWV-Cnxrk1TJ.js → diagram-VSXAHHWV-bI4-SjAp.js} +1 -1
- package/viewer/assets/{diagram-VX7I27RA-D78jPXr7.js → diagram-VX7I27RA-jWvTT618.js} +1 -1
- package/viewer/assets/{diagram-Z3DM3KII-DKjnOaF2.js → diagram-Z3DM3KII-D6Vcvcr8.js} +1 -1
- package/viewer/assets/{dist-BTYPW0dz.js → dist-Cn65YNrn.js} +1 -1
- package/viewer/assets/{ebnfDiagram-PWID7BFC-7XiXh5Lx.js → ebnfDiagram-PWID7BFC-y-ZxfP2H.js} +1 -1
- package/viewer/assets/{edge-B34N_HjN.js → edge-Bc0EBQ7y.js} +1 -1
- package/viewer/assets/{elixir-CQzWMyKD.js → elixir-BmxsT0oc.js} +1 -1
- package/viewer/assets/{elm-BNJiG-wg.js → elm-BrTAZ55m.js} +1 -1
- package/viewer/assets/{erDiagram-RLTQ6QDP-YPFEgZxU.js → erDiagram-RLTQ6QDP-Wa1tikbb.js} +1 -1
- package/viewer/assets/{erb-D5Rm3UNa.js → erb-B60HRxmg.js} +1 -1
- package/viewer/assets/eventmodeling-NTZA5JFV-BNvBHnQf.js +1 -0
- package/viewer/assets/flowDiagram-HODETNUW-zGgqOVuO.js +1 -0
- package/viewer/assets/{ganttDiagram-EL5Y4UJY-ergSGtTP.js → ganttDiagram-EL5Y4UJY-DjskXB68.js} +1 -1
- package/viewer/assets/{git-rebase-BpIMZIRG.js → git-rebase-CK9f68l3.js} +1 -1
- package/viewer/assets/{gitGraph-4MIJSDKK-CZt4REVj.js → gitGraph-4MIJSDKK-CvRhO7Ae.js} +1 -1
- package/viewer/assets/{gitGraphDiagram-WWUBYQGX-h9QMzC2r.js → gitGraphDiagram-WWUBYQGX-Bg_OLNL1.js} +1 -1
- package/viewer/assets/{glimmer-js-SeSwns5_.js → glimmer-js-CVc7keaR.js} +1 -1
- package/viewer/assets/{glimmer-ts-BExI5tTz.js → glimmer-ts-DYraWlmH.js} +1 -1
- package/viewer/assets/{glsl-CXikKw2b.js → glsl-BpYswgfh.js} +1 -1
- package/viewer/assets/{graphql-6GpQIInt.js → graphql-C3iDzxap.js} +1 -1
- package/viewer/assets/{hack-i7rizvpB.js → hack-D8oEoipZ.js} +1 -1
- package/viewer/assets/{haml-C68gmkTf.js → haml-BJb-BQAN.js} +1 -1
- package/viewer/assets/{handlebars-BBn_c0Xt.js → handlebars-wB54lHaB.js} +1 -1
- package/viewer/assets/{html-BObmAZQA.js → html-HIvKkSZ3.js} +1 -1
- package/viewer/assets/{html-derivative-BjMuR1LM.js → html-derivative-CDavbmdn.js} +1 -1
- package/viewer/assets/{http-BJBk8gt0.js → http-DEgShh0-.js} +1 -1
- package/viewer/assets/{hurl-D7obCYfg.js → hurl-D8wvJcyh.js} +1 -1
- package/viewer/assets/{index-FMtYXcX7.js → index-Ck3NBCVJ.js} +9 -7
- package/viewer/assets/{index-Wz0qQyIk.css → index-DAuO1BM4.css} +1 -1
- package/viewer/assets/{info-A6RAGUB7-CrzitQIU.js → info-A6RAGUB7-DL3H6Iqn.js} +1 -1
- package/viewer/assets/{infoDiagram-27XIBGKW-D2CgRDxu.js → infoDiagram-27XIBGKW-DSLzhrL8.js} +1 -1
- package/viewer/assets/{ishikawaDiagram-5VMMS53U-BhnQMHOo.js → ishikawaDiagram-5VMMS53U-B-ycXUrd.js} +1 -1
- package/viewer/assets/{java-5VJU_EW8.js → java-C5iWdXOl.js} +1 -1
- package/viewer/assets/{javascript-r8UgndxQ.js → javascript-PMSXGhX1.js} +1 -1
- package/viewer/assets/{jinja-BY2ibHG5.js → jinja-CJ_l63gX.js} +1 -1
- package/viewer/assets/{jison-C_7YxymZ.js → jison-DGaZyJAT.js} +1 -1
- package/viewer/assets/{journeyDiagram-3NMN7TZE-DSBzKQEa.js → journeyDiagram-3NMN7TZE-2p56tZPm.js} +1 -1
- package/viewer/assets/{json-8e1WlJYD.js → json-CCQ1eo9o.js} +1 -1
- package/viewer/assets/{jsx-BYp5GD4Y.js → jsx-DeLT99JL.js} +1 -1
- package/viewer/assets/{julia-Bkob1uVX.js → julia-DODLsulx.js} +1 -1
- package/viewer/assets/{just-CUnSjty-.js → just-B_Nvjvhv.js} +1 -1
- package/viewer/assets/{kanban-definition-UXKFOSKX-CotbrQue.js → kanban-definition-UXKFOSKX-B42fPx4K.js} +1 -1
- package/viewer/assets/{latex-UdE3ivqk.js → latex-CCjy2I9z.js} +1 -1
- package/viewer/assets/{line-DDh6a6hz.js → line-DGK8UZYe.js} +1 -1
- package/viewer/assets/{linear-BxMsCbKb.js → linear-LxXu6wOl.js} +1 -1
- package/viewer/assets/{liquid-WL4MvEIT.js → liquid-C2tknZP0.js} +1 -1
- package/viewer/assets/{lua-CtOubZta.js → lua-D6UzQw5Z.js} +1 -1
- package/viewer/assets/{marko-C0GSQJi3.js → marko-CGd5W4Hn.js} +1 -1
- package/viewer/assets/{mdc-DUivddFc.js → mdc-Bp5z92Vo.js} +1 -1
- package/viewer/assets/{mermaid-parser.core-FhKE_uv2.js → mermaid-parser.core-xGBt_sNt.js} +3 -3
- package/viewer/assets/{mermaid.core-BSOWwyvd.js → mermaid.core-D1TUMBuT.js} +4 -4
- package/viewer/assets/{mindmap-definition-YA3MSWOX-tsLZ_Opn.js → mindmap-definition-YA3MSWOX-BY9cVMtI.js} +1 -1
- package/viewer/assets/{nginx-B__INAtC.js → nginx-DAsqAd3h.js} +1 -1
- package/viewer/assets/{nim-UEY12GJF.js → nim-COOJz623.js} +1 -1
- package/viewer/assets/{org-DDIZsz95.js → org-CBV1qqrA.js} +1 -1
- package/viewer/assets/{packet-AYTQ26CC-CqdJnqfo.js → packet-AYTQ26CC-61q5HcB3.js} +1 -1
- package/viewer/assets/{pegDiagram-XKGWAZYB-BJs7qu7m.js → pegDiagram-XKGWAZYB-DLEkmimO.js} +1 -1
- package/viewer/assets/{perl-D5KwNZt7.js → perl-6SV_ayGd.js} +1 -1
- package/viewer/assets/{php-BEs7d_Dk.js → php-BUb-Io9m.js} +1 -1
- package/viewer/assets/{pie-WAS4IAKB-lgzqBWqy.js → pie-WAS4IAKB-DgijP3YA.js} +1 -1
- package/viewer/assets/{pieDiagram-E7YTZNPT-Cxe9LnnE.js → pieDiagram-E7YTZNPT-Cp20J80-.js} +1 -1
- package/viewer/assets/{pug-B0dsfQOV.js → pug-D5s94d1b.js} +1 -1
- package/viewer/assets/{qml-XPIhrIzf.js → qml-D8g4NGVo.js} +1 -1
- package/viewer/assets/{quadrantDiagram-AXDQQJYC-D5JGwC11.js → quadrantDiagram-AXDQQJYC-Djsc9xpm.js} +1 -1
- package/viewer/assets/{r-C6hQdpIM.js → r-DXvz5K4A.js} +1 -1
- package/viewer/assets/{radar-RG4KPBEZ-B7JRLhUA.js → radar-RG4KPBEZ-BCmoUpe8.js} +1 -1
- package/viewer/assets/{railroad-74A4TZTK-Df7ZQBLn.js → railroad-74A4TZTK-DZ0SYESf.js} +1 -1
- package/viewer/assets/railroad-abnf-HS5TGJTU-C2CQDbu6.js +1 -0
- package/viewer/assets/railroad-ebnf-LZEXJU2U-6ssJubZr.js +1 -0
- package/viewer/assets/railroad-peg-WCYAUIDC-UOxDGPyg.js +1 -0
- package/viewer/assets/{railroadDiagram-O6MQD6OU-DZJzpmP8.js → railroadDiagram-O6MQD6OU-DmD4JR_t.js} +1 -1
- package/viewer/assets/{razor-C3KSUuOw.js → razor-D9CjUAvE.js} +1 -1
- package/viewer/assets/{regexp-n-T936Rk.js → regexp-CnuLvLnC.js} +1 -1
- package/viewer/assets/{requirementDiagram-BXWQKSXE-Be9lEFrk.js → requirementDiagram-BXWQKSXE-BTci7X6J.js} +1 -1
- package/viewer/assets/{rst-fVnHDyXD.js → rst-Chdv5DuC.js} +1 -1
- package/viewer/assets/{ruby-DuRgxlXF.js → ruby-DXQkNv8k.js} +1 -1
- package/viewer/assets/{sankeyDiagram-P5KCCOFB-BsgKAEBN.js → sankeyDiagram-P5KCCOFB-BaHSMANQ.js} +1 -1
- package/viewer/assets/{sas-C0WA2OFa.js → sas-B6S0Oq1H.js} +1 -1
- package/viewer/assets/{scss-CQDZ4smR.js → scss-BnFPXH54.js} +1 -1
- package/viewer/assets/{sequenceDiagram-WJ2MYXX4-BkUDWL0D.js → sequenceDiagram-WJ2MYXX4-BUk21g1t.js} +1 -1
- package/viewer/assets/{shellscript-CE84G0GP.js → shellscript-Brdg8vyE.js} +1 -1
- package/viewer/assets/{shellsession-BdJvdaqL.js → shellsession-Df33UGC7.js} +1 -1
- package/viewer/assets/{soy-BSxOREC0.js → soy-DE83qari.js} +1 -1
- package/viewer/assets/{sql-D4MN9uRI.js → sql-C838IanB.js} +1 -1
- package/viewer/assets/{src-BT_kESTA.js → src-tvfSkCy9.js} +1 -1
- package/viewer/assets/{stata-B6nXAaGV.js → stata-BjrFc6Ob.js} +1 -1
- package/viewer/assets/{stateDiagram-D77RDMKH-C80wp8xG.js → stateDiagram-D77RDMKH-B7yRJv9-.js} +1 -1
- package/viewer/assets/stateDiagram-v2-MP3YSRHH-BCwhllSg.js +1 -0
- package/viewer/assets/{surrealql-fVjZmhV3.js → surrealql-BQl2P64c.js} +1 -1
- package/viewer/assets/{svelte-DnBQ5p7d.js → svelte-WhVuP9VM.js} +1 -1
- package/viewer/assets/{swimlanes-42K2YHIH-Cff6yT8e.js → swimlanes-42K2YHIH-on6wyUF5.js} +1 -1
- package/viewer/assets/swimlanesDiagram-VR7AAH4N-D0QyhouX.js +8 -0
- package/viewer/assets/{templ-TCx51Uts.js → templ-GlyHWfam.js} +1 -1
- package/viewer/assets/{tex-CF6SMAQ_.js → tex-Wu25UU_Z.js} +1 -1
- package/viewer/assets/{timeline-definition-24CTP7MA-Cje7BvaN.js → timeline-definition-24CTP7MA-DsgJtBig.js} +1 -1
- package/viewer/assets/{treeView-Q6P3EWNA-D-QLY3IO.js → treeView-Q6P3EWNA-Bae2q_db.js} +1 -1
- package/viewer/assets/{treemap-WGGIJYW6-BCHcTa4N.js → treemap-WGGIJYW6-BJsxvsBb.js} +1 -1
- package/viewer/assets/{ts-tags-BqLRnADX.js → ts-tags-C6TgXLV6.js} +1 -1
- package/viewer/assets/{tsx-D7KpDX0b.js → tsx-DVoPHges.js} +1 -1
- package/viewer/assets/{twig-CEZLObpN.js → twig-CKzx4A42.js} +1 -1
- package/viewer/assets/{typescript-DAbIDLbf.js → typescript-DvXz8u_k.js} +1 -1
- package/viewer/assets/{typst-CqN7-whv.js → typst-BcepwfpV.js} +1 -1
- package/viewer/assets/{vennDiagram-4TSXK5OY-Bz20rx02.js → vennDiagram-4TSXK5OY-CKUR4uY_.js} +1 -1
- package/viewer/assets/{vue-kTxN6wdc.js → vue-Bqzme_T-.js} +1 -1
- package/viewer/assets/{vue-html-DQmvvKbd.js → vue-html-DZHKNOUy.js} +1 -1
- package/viewer/assets/{vue-vine-Did3qTVW.js → vue-vine-azvFs0P6.js} +1 -1
- package/viewer/assets/{wardley-WFR3VGLG-CpXaqOit.js → wardley-WFR3VGLG-Ddsu3qLB.js} +1 -1
- package/viewer/assets/{wardleyDiagram-VM6X3IG4-Cz06jHpA.js → wardleyDiagram-VM6X3IG4-CCHx9UX4.js} +1 -1
- package/viewer/assets/{xml-te2hFcAA.js → xml-BZNC4g25.js} +1 -1
- package/viewer/assets/{xsl-X4fuKSVl.js → xsl-DXEWaWc5.js} +1 -1
- package/viewer/assets/{xychartDiagram-S5SC5T6Z-BXCw0sfu.js → xychartDiagram-S5SC5T6Z-CkoTq405.js} +1 -1
- package/viewer/assets/{yaml-NHtDSZab.js → yaml-DLY3wDEk.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
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import type { EvidenceRef, ToolCall } from "../../types";
|
|
2
|
+
import type {
|
|
3
|
+
RecordedEvent,
|
|
4
|
+
RunMetrics,
|
|
5
|
+
ToolMetrics,
|
|
6
|
+
} from "../../judge-context";
|
|
7
|
+
import { mergeRuntime, runtimeMs, type RuntimeInterval } from "../../runtime";
|
|
8
|
+
|
|
9
|
+
const toolsSummary = (tools: ToolCall[]): ToolMetrics => {
|
|
10
|
+
const succeeded = tools.filter((call) => call.status === "succeeded").length;
|
|
11
|
+
const failed = tools.filter((call) => call.status === "failed").length;
|
|
12
|
+
return {
|
|
13
|
+
calls: tools.length,
|
|
14
|
+
succeeded,
|
|
15
|
+
failed,
|
|
16
|
+
unfinished: tools.length - succeeded - failed,
|
|
17
|
+
errorRate: succeeded + failed ? failed / (succeeded + failed) : null,
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/** Measurements use deduplicated native records, never scored criterion values. */
|
|
22
|
+
export function measureRecording(
|
|
23
|
+
supplied: RecordedEvent[],
|
|
24
|
+
tools: ToolCall[],
|
|
25
|
+
evidence: EvidenceRef,
|
|
26
|
+
): RunMetrics {
|
|
27
|
+
const events = [
|
|
28
|
+
...new Map(
|
|
29
|
+
supplied.map((item) => [
|
|
30
|
+
"id" in item.event ? item.event.id : String(item.sequence),
|
|
31
|
+
item.event,
|
|
32
|
+
]),
|
|
33
|
+
).values(),
|
|
34
|
+
].sort(
|
|
35
|
+
(a, b) =>
|
|
36
|
+
("created" in a ? a.created : 0) - ("created" in b ? b.created : 0),
|
|
37
|
+
);
|
|
38
|
+
const count = (type: string) =>
|
|
39
|
+
events.filter((event) => event.type === type).length;
|
|
40
|
+
const tokens = {
|
|
41
|
+
input: 0,
|
|
42
|
+
output: 0,
|
|
43
|
+
reasoning: 0,
|
|
44
|
+
cache: { read: 0, write: 0 },
|
|
45
|
+
};
|
|
46
|
+
let reportedUSD = 0,
|
|
47
|
+
usageRecords = 0,
|
|
48
|
+
usageComplete = true,
|
|
49
|
+
costComplete = true;
|
|
50
|
+
const intervals: RuntimeInterval[] = [],
|
|
51
|
+
starts = new Map<string, number>();
|
|
52
|
+
const executions: RuntimeInterval[] = [],
|
|
53
|
+
executionStarts = new Map<string, number>();
|
|
54
|
+
const created = new Set<string>();
|
|
55
|
+
const sessions = new Set<string>(),
|
|
56
|
+
sequences = new Map<string, number[]>();
|
|
57
|
+
for (const event of events) {
|
|
58
|
+
if (!("data" in event)) continue;
|
|
59
|
+
const data = event.data as Record<string, unknown>;
|
|
60
|
+
if (typeof data.sessionID === "string") sessions.add(data.sessionID);
|
|
61
|
+
if (event.type === "session.created") created.add(event.data.sessionID);
|
|
62
|
+
if (event.type === "session.execution.started")
|
|
63
|
+
executionStarts.set(event.data.sessionID, event.created);
|
|
64
|
+
if (
|
|
65
|
+
[
|
|
66
|
+
"session.execution.succeeded",
|
|
67
|
+
"session.execution.failed",
|
|
68
|
+
"session.execution.interrupted",
|
|
69
|
+
].includes(event.type) &&
|
|
70
|
+
typeof data.sessionID === "string" &&
|
|
71
|
+
"created" in event
|
|
72
|
+
) {
|
|
73
|
+
const start = executionStarts.get(data.sessionID);
|
|
74
|
+
if (start !== undefined) executions.push({ start, end: event.created });
|
|
75
|
+
executionStarts.delete(data.sessionID);
|
|
76
|
+
}
|
|
77
|
+
if ("durable" in event) {
|
|
78
|
+
const values = sequences.get(event.durable.aggregateID) ?? [];
|
|
79
|
+
values.push(event.durable.seq);
|
|
80
|
+
sequences.set(event.durable.aggregateID, values);
|
|
81
|
+
}
|
|
82
|
+
const key = `${data.sessionID}:${data.assistantMessageID ?? "compaction"}`;
|
|
83
|
+
if (
|
|
84
|
+
event.type === "session.step.started" ||
|
|
85
|
+
event.type === "session.compaction.started"
|
|
86
|
+
)
|
|
87
|
+
starts.set(key, event.created);
|
|
88
|
+
if (
|
|
89
|
+
[
|
|
90
|
+
"session.step.ended",
|
|
91
|
+
"session.step.failed",
|
|
92
|
+
"session.compaction.ended",
|
|
93
|
+
"session.compaction.failed",
|
|
94
|
+
].includes(event.type)
|
|
95
|
+
) {
|
|
96
|
+
const start = starts.get(key);
|
|
97
|
+
if (start !== undefined && "created" in event)
|
|
98
|
+
intervals.push({ start, end: event.created });
|
|
99
|
+
starts.delete(key);
|
|
100
|
+
}
|
|
101
|
+
if (
|
|
102
|
+
![
|
|
103
|
+
"session.step.ended",
|
|
104
|
+
"session.step.failed",
|
|
105
|
+
"session.usage.recorded",
|
|
106
|
+
].includes(event.type)
|
|
107
|
+
)
|
|
108
|
+
continue;
|
|
109
|
+
usageRecords++;
|
|
110
|
+
if (typeof data.cost === "number" && Number.isFinite(data.cost))
|
|
111
|
+
reportedUSD += data.cost;
|
|
112
|
+
else costComplete = false;
|
|
113
|
+
const usage = data.tokens as typeof tokens | undefined;
|
|
114
|
+
if (
|
|
115
|
+
!usage ||
|
|
116
|
+
![
|
|
117
|
+
usage.input,
|
|
118
|
+
usage.output,
|
|
119
|
+
usage.reasoning,
|
|
120
|
+
usage.cache?.read,
|
|
121
|
+
usage.cache?.write,
|
|
122
|
+
].every(Number.isFinite)
|
|
123
|
+
) {
|
|
124
|
+
usageComplete = false;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
tokens.input += usage.input;
|
|
128
|
+
tokens.output += usage.output;
|
|
129
|
+
tokens.reasoning += usage.reasoning;
|
|
130
|
+
tokens.cache.read += usage.cache.read;
|
|
131
|
+
tokens.cache.write += usage.cache.write;
|
|
132
|
+
}
|
|
133
|
+
const measuredTokens = usageRecords && usageComplete ? tokens : null;
|
|
134
|
+
const cost = usageRecords && costComplete ? reportedUSD : null;
|
|
135
|
+
const clock = events.reduce(
|
|
136
|
+
(latest, event) =>
|
|
137
|
+
"created" in event ? Math.max(latest, event.created) : latest,
|
|
138
|
+
0,
|
|
139
|
+
);
|
|
140
|
+
const modelActiveMs = runtimeMs(mergeRuntime(intervals), clock);
|
|
141
|
+
const complete =
|
|
142
|
+
sequences.size > 0 &&
|
|
143
|
+
starts.size === 0 &&
|
|
144
|
+
executionStarts.size === 0 &&
|
|
145
|
+
[...sessions].every((id) => created.has(id)) &&
|
|
146
|
+
[...sequences.values()].every((values) => {
|
|
147
|
+
const sorted = [...new Set(values)].sort((a, b) => a - b);
|
|
148
|
+
return sorted.every(
|
|
149
|
+
(value, index) => index === 0 || value === sorted[index - 1] + 1,
|
|
150
|
+
);
|
|
151
|
+
});
|
|
152
|
+
return {
|
|
153
|
+
version: 1,
|
|
154
|
+
scope: "candidate",
|
|
155
|
+
complete,
|
|
156
|
+
sessions: sessions.size,
|
|
157
|
+
requests: {
|
|
158
|
+
started: count("session.step.started"),
|
|
159
|
+
succeeded: count("session.step.ended"),
|
|
160
|
+
failed: count("session.step.failed"),
|
|
161
|
+
retries: count("session.retry.scheduled"),
|
|
162
|
+
},
|
|
163
|
+
tokens: measuredTokens,
|
|
164
|
+
cost: { usd: cost, reportedUSD, complete: cost !== null },
|
|
165
|
+
tools: {
|
|
166
|
+
...toolsSummary(tools),
|
|
167
|
+
byName: Object.fromEntries(
|
|
168
|
+
[...new Set(tools.map((call) => call.name))]
|
|
169
|
+
.sort()
|
|
170
|
+
.map((name) => [
|
|
171
|
+
name,
|
|
172
|
+
toolsSummary(tools.filter((call) => call.name === name)),
|
|
173
|
+
]),
|
|
174
|
+
),
|
|
175
|
+
},
|
|
176
|
+
compactions: {
|
|
177
|
+
started: count("session.compaction.started"),
|
|
178
|
+
completed: count("session.compaction.ended"),
|
|
179
|
+
failed: count("session.compaction.failed"),
|
|
180
|
+
},
|
|
181
|
+
timing: {
|
|
182
|
+
elapsedMs: executions.length
|
|
183
|
+
? runtimeMs(mergeRuntime(executions), clock)
|
|
184
|
+
: null,
|
|
185
|
+
modelActiveMs,
|
|
186
|
+
outputTokensPerSecond:
|
|
187
|
+
measuredTokens && modelActiveMs > 0
|
|
188
|
+
? (measuredTokens.output * 1000) / modelActiveMs
|
|
189
|
+
: null,
|
|
190
|
+
},
|
|
191
|
+
evidence,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
@@ -5,7 +5,7 @@ import { mkdirSync, existsSync } from "node:fs";
|
|
|
5
5
|
import { dirname, resolve } from "node:path";
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
7
7
|
import * as tables from "./schema";
|
|
8
|
-
import { isScored, JUDGE_PROTOCOL,
|
|
8
|
+
import { isScored, JUDGE_PROTOCOL, criterionMean } from "../../judgment";
|
|
9
9
|
import type {
|
|
10
10
|
BenchmarkRun,
|
|
11
11
|
EvalRun,
|
|
@@ -19,7 +19,7 @@ import type {
|
|
|
19
19
|
} from "../../types";
|
|
20
20
|
|
|
21
21
|
const APPLICATION_ID = 0x4f455632;
|
|
22
|
-
const SCHEMA_VERSION =
|
|
22
|
+
const SCHEMA_VERSION = 5;
|
|
23
23
|
const timestamp = () => new Date().toISOString();
|
|
24
24
|
|
|
25
25
|
/** One owner for run selection and append-only finalized execution records. */
|
|
@@ -257,13 +257,16 @@ export class Results {
|
|
|
257
257
|
}
|
|
258
258
|
startJudge(input: JudgeRunInput) {
|
|
259
259
|
if (
|
|
260
|
-
!input.
|
|
261
|
-
|
|
260
|
+
(!input.code &&
|
|
261
|
+
(!input.agent || !input.model || !input.criteria.length)) ||
|
|
262
|
+
(!!input.rubric &&
|
|
263
|
+
(!input.agent || !input.model || !input.criteria.length)) ||
|
|
264
|
+
!["llm", "code", "hybrid"].includes(input.kind) ||
|
|
262
265
|
!input.runtimeHash ||
|
|
263
266
|
input.protocol !== JUDGE_PROTOCOL
|
|
264
267
|
)
|
|
265
268
|
throw new Error(
|
|
266
|
-
"Judge inputs must
|
|
269
|
+
"Judge inputs must include their code or LLM configuration, criteria, runtime, and protocol",
|
|
267
270
|
);
|
|
268
271
|
const value: JudgeRun = {
|
|
269
272
|
id: `judge_${randomUUID()}`,
|
|
@@ -301,21 +304,28 @@ export class Results {
|
|
|
301
304
|
const saved = this.judgeRun(value.id);
|
|
302
305
|
if (!saved || saved.state !== "running")
|
|
303
306
|
throw new Error("Judge run is not running");
|
|
304
|
-
if (
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
307
|
+
if (value.state === "completed") {
|
|
308
|
+
const expected = [
|
|
309
|
+
...value.input.criteria.map((criterion) => criterion.id),
|
|
310
|
+
...Object.keys(value.code?.scores ?? {}),
|
|
311
|
+
];
|
|
312
|
+
const scores = value.judgment?.scores;
|
|
313
|
+
if (
|
|
314
|
+
!scores ||
|
|
315
|
+
Array.isArray(scores) ||
|
|
316
|
+
new Set(expected).size !== expected.length ||
|
|
317
|
+
Object.keys(scores).length !== expected.length ||
|
|
318
|
+
expected.some((id) => !Object.hasOwn(scores, id)) ||
|
|
319
|
+
Object.values(scores).some(
|
|
320
|
+
(score) => score.value !== null && !isScored(score.value),
|
|
314
321
|
) ||
|
|
315
|
-
value.judgment
|
|
316
|
-
(value.
|
|
317
|
-
|
|
318
|
-
|
|
322
|
+
value.judgment!.value !== criterionMean(scores) ||
|
|
323
|
+
(value.input.code && value.code?.state !== "completed")
|
|
324
|
+
)
|
|
325
|
+
throw new Error(
|
|
326
|
+
"A completed judge run requires a valid, complete judgment",
|
|
327
|
+
);
|
|
328
|
+
}
|
|
319
329
|
if (
|
|
320
330
|
value.state === "completed" &&
|
|
321
331
|
this.evalRun(value.input.evalRunId)?.evidence?.hash !==
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite";
|
|
2
|
+
import type { OpenCode } from "@opencode/sdk";
|
|
3
|
+
import type {
|
|
4
|
+
SessionInfo,
|
|
5
|
+
SessionMessageInfo,
|
|
6
|
+
SessionTransferData,
|
|
7
|
+
} from "@opencode/client";
|
|
8
|
+
import type {
|
|
9
|
+
EvalRun,
|
|
10
|
+
EvidenceRef,
|
|
11
|
+
OpenCodeStreamEvent,
|
|
12
|
+
ToolCall,
|
|
13
|
+
Cost,
|
|
14
|
+
Accounting,
|
|
15
|
+
} from "./types";
|
|
16
|
+
|
|
17
|
+
export type JsonValue =
|
|
18
|
+
| null
|
|
19
|
+
| boolean
|
|
20
|
+
| number
|
|
21
|
+
| string
|
|
22
|
+
| JsonValue[]
|
|
23
|
+
| { [key: string]: JsonValue };
|
|
24
|
+
export type ScoreValue = boolean | number | null;
|
|
25
|
+
|
|
26
|
+
/** Code judges are ordinary functions. Only an optional scores map has grading semantics. */
|
|
27
|
+
export type JudgeFunction = (
|
|
28
|
+
context: JudgeContext,
|
|
29
|
+
) => JsonValue | Promise<JsonValue>;
|
|
30
|
+
|
|
31
|
+
export type ToolMetrics = {
|
|
32
|
+
calls: number;
|
|
33
|
+
succeeded: number;
|
|
34
|
+
failed: number;
|
|
35
|
+
unfinished: number;
|
|
36
|
+
/** Failed / (succeeded + failed); null when there are no terminal calls. */
|
|
37
|
+
errorRate: number | null;
|
|
38
|
+
};
|
|
39
|
+
export type RunMetrics = {
|
|
40
|
+
version: 1;
|
|
41
|
+
scope: "candidate";
|
|
42
|
+
/** False for constructed controls or incomplete durable execution history. */
|
|
43
|
+
complete: boolean;
|
|
44
|
+
sessions: number;
|
|
45
|
+
requests: {
|
|
46
|
+
started: number;
|
|
47
|
+
succeeded: number;
|
|
48
|
+
failed: number;
|
|
49
|
+
retries: number;
|
|
50
|
+
};
|
|
51
|
+
tokens: Accounting["tokens"] | null;
|
|
52
|
+
cost: Cost;
|
|
53
|
+
tools: ToolMetrics & { byName: Record<string, ToolMetrics> };
|
|
54
|
+
compactions: { started: number; completed: number; failed: number };
|
|
55
|
+
timing: {
|
|
56
|
+
elapsedMs: number | null;
|
|
57
|
+
modelActiveMs: number;
|
|
58
|
+
/** Output tokens / model-active seconds; overlapping requests count once. */
|
|
59
|
+
outputTokensPerSecond: number | null;
|
|
60
|
+
};
|
|
61
|
+
evidence: EvidenceRef;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export type RecordedEvent = {
|
|
65
|
+
sequence: number;
|
|
66
|
+
time: string;
|
|
67
|
+
event: OpenCodeStreamEvent;
|
|
68
|
+
};
|
|
69
|
+
export type RecordedMessage = {
|
|
70
|
+
sessionID: string;
|
|
71
|
+
message: SessionMessageInfo;
|
|
72
|
+
};
|
|
73
|
+
export type RecordedFile = {
|
|
74
|
+
path: string;
|
|
75
|
+
bytes: number;
|
|
76
|
+
sha256?: string;
|
|
77
|
+
symlink?: string;
|
|
78
|
+
};
|
|
79
|
+
export type Revision = "initial" | "final";
|
|
80
|
+
|
|
81
|
+
export interface JudgeContext {
|
|
82
|
+
/** Missing response text is normalized to an empty string. */
|
|
83
|
+
readonly response: { readonly text: string };
|
|
84
|
+
readonly prompt: string;
|
|
85
|
+
/** Null for constructed evidence that did not execute a candidate. */
|
|
86
|
+
readonly run: Readonly<EvalRun> | null;
|
|
87
|
+
readonly metrics: Readonly<RunMetrics>;
|
|
88
|
+
readonly recording: {
|
|
89
|
+
readonly evidence: EvidenceRef;
|
|
90
|
+
readonly sessionID: string | null;
|
|
91
|
+
readonly coverage: "recorded-session" | "recorded-prefix";
|
|
92
|
+
events(filter?: { sessionID?: string; type?: string }): RecordedEvent[];
|
|
93
|
+
tools(filter?: { sessionID?: string; name?: string }): ToolCall[];
|
|
94
|
+
sessions(): Promise<SessionInfo[]>;
|
|
95
|
+
/** Full projected history, including messages before compaction. */
|
|
96
|
+
messages(sessionID?: string): Promise<RecordedMessage[]>;
|
|
97
|
+
export(sessionID?: string): Promise<SessionTransferData>;
|
|
98
|
+
};
|
|
99
|
+
readonly workspace: {
|
|
100
|
+
files(revision?: Revision): RecordedFile[];
|
|
101
|
+
read(path: string, revision?: Revision): Promise<Uint8Array>;
|
|
102
|
+
text(path: string, revision?: Revision): Promise<string>;
|
|
103
|
+
diff(
|
|
104
|
+
path: string,
|
|
105
|
+
): Promise<{ initial: string | null; final: string | null }>;
|
|
106
|
+
/** Restore a disposable snapshot for author-owned verification commands. */
|
|
107
|
+
materialize(revision?: Revision): Promise<string>;
|
|
108
|
+
};
|
|
109
|
+
readonly native: {
|
|
110
|
+
readonly version: string | null;
|
|
111
|
+
readonly readerVersion: string;
|
|
112
|
+
/** Read-only SQL access to a verified, disposable native database copy. */
|
|
113
|
+
database(): Promise<Database>;
|
|
114
|
+
/** The pinned OpenCode API/SDK over a separate disposable database copy. */
|
|
115
|
+
sdk(): Promise<OpenCode.Interface>;
|
|
116
|
+
schema(): Promise<typeof import("@opencode/schema")>;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Frozen judging source and dependency identity, kept in host-side run records. */
|
|
121
|
+
export type CodeJudgeDefinition = {
|
|
122
|
+
file: string;
|
|
123
|
+
hash: string;
|
|
124
|
+
source: string;
|
|
125
|
+
sourceMap: string;
|
|
126
|
+
dependencies: Record<string, string>;
|
|
127
|
+
};
|
|
128
|
+
export type CodeJudgeExecution = {
|
|
129
|
+
state: "completed" | "failed" | "timed_out";
|
|
130
|
+
startedAt: string;
|
|
131
|
+
completedAt: string;
|
|
132
|
+
elapsedMs: number;
|
|
133
|
+
/** Original JSON, before boolean score normalization. */
|
|
134
|
+
output?: JsonValue;
|
|
135
|
+
scores?: Record<string, number | null>;
|
|
136
|
+
metrics?: RunMetrics;
|
|
137
|
+
error?: string;
|
|
138
|
+
sourceHash: string;
|
|
139
|
+
stdout: string;
|
|
140
|
+
stderr: string;
|
|
141
|
+
};
|
package/src/judgment.ts
CHANGED
|
@@ -1,40 +1,49 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CriterionDefinition, CriterionScore } from "./types";
|
|
2
2
|
|
|
3
|
-
export const JUDGE_PROTOCOL =
|
|
3
|
+
export const JUDGE_PROTOCOL = 4;
|
|
4
4
|
export const isScored = (value: unknown): value is number =>
|
|
5
5
|
typeof value === "number" &&
|
|
6
6
|
Number.isFinite(value) &&
|
|
7
7
|
value >= 0 &&
|
|
8
8
|
value <= 1;
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
export function
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
/** The author declares Markdown criteria; code functions return their own scores. */
|
|
11
|
+
export function rubricCriteria(rubric: string): CriterionDefinition[] {
|
|
12
|
+
if (/^## Metric:/m.test(rubric))
|
|
13
|
+
throw new Error("Use ## Criterion: id — Label for rubric declarations");
|
|
14
|
+
const criteria = [
|
|
15
|
+
...rubric.matchAll(
|
|
16
|
+
/^## Criterion: ([a-z][a-z0-9_]*)[ \t]*[—–-][ \t]*(.+)$/gm,
|
|
17
|
+
),
|
|
14
18
|
].map((match) => ({
|
|
15
19
|
id: match[1],
|
|
16
20
|
name: match[2].trim(),
|
|
17
21
|
}));
|
|
18
|
-
if (new Set(metrics.map((metric) => metric.id)).size !== metrics.length)
|
|
19
|
-
throw new Error("Metric IDs must be unique within judge.md");
|
|
20
22
|
if (
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
new Set(criteria.map((criterion) => criterion.id)).size !== criteria.length
|
|
24
|
+
)
|
|
25
|
+
throw new Error("Criterion IDs must be unique within judge.md");
|
|
26
|
+
if (
|
|
27
|
+
!criteria.length ||
|
|
28
|
+
criteria.some((criterion) => !criterion.name) ||
|
|
29
|
+
criteria.length !== (rubric.match(/^## Criterion:/gm)?.length ?? 0)
|
|
24
30
|
)
|
|
25
31
|
throw new Error(
|
|
26
|
-
"Declare every
|
|
32
|
+
"Declare every criterion as ## Criterion: id — Label in judge.md",
|
|
27
33
|
);
|
|
28
|
-
return
|
|
34
|
+
return criteria;
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
/** Equal weighting within an eval; no task-specific policy is implemented here.
|
|
32
38
|
* https://arxiv.org/html/2607.07946#S5.SS3 (equal task weighting)
|
|
33
39
|
*/
|
|
34
|
-
export function
|
|
35
|
-
|
|
40
|
+
export function criterionMean(
|
|
41
|
+
scores: Readonly<Record<string, Pick<CriterionScore, "value">>>,
|
|
36
42
|
): number | null {
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
const criteria = Object.values(scores);
|
|
44
|
+
return criteria.length &&
|
|
45
|
+
criteria.every((criterion) => isScored(criterion.value))
|
|
46
|
+
? criteria.reduce((sum, criterion) => sum + criterion.value!, 0) /
|
|
47
|
+
criteria.length
|
|
39
48
|
: null;
|
|
40
49
|
}
|
package/src/types.ts
CHANGED
|
@@ -4,6 +4,11 @@ import type {
|
|
|
4
4
|
ConfigEntry,
|
|
5
5
|
AgentInfo,
|
|
6
6
|
} from "@opencode/client";
|
|
7
|
+
import type {
|
|
8
|
+
CodeJudgeDefinition,
|
|
9
|
+
CodeJudgeExecution,
|
|
10
|
+
RunMetrics,
|
|
11
|
+
} from "./judge-context";
|
|
7
12
|
export type OpenCodeStreamEvent = OpenCodeEvent | SessionLogItem;
|
|
8
13
|
|
|
9
14
|
export const CANDIDATE_TIMEOUT_MS = 45 * 60 * 1000;
|
|
@@ -13,18 +18,22 @@ export type ProviderDefinitions = NonNullable<
|
|
|
13
18
|
Extract<ConfigEntry, { type: "document" }>["info"]["providers"]
|
|
14
19
|
>;
|
|
15
20
|
export type SessionState =
|
|
16
|
-
|
|
21
|
+
| "running"
|
|
22
|
+
| "completed"
|
|
23
|
+
| "stopped"
|
|
24
|
+
| "failed"
|
|
25
|
+
| "timed_out";
|
|
17
26
|
export type Stage = "candidate" | "judge";
|
|
18
27
|
|
|
19
28
|
export type Judge = {
|
|
20
|
-
model
|
|
29
|
+
model?: ModelRef;
|
|
21
30
|
timeoutMs?: number;
|
|
22
31
|
websearch?: "exa" | false;
|
|
23
32
|
};
|
|
24
33
|
export type Benchmark = {
|
|
25
34
|
name?: string;
|
|
26
35
|
models: readonly ModelRef[];
|
|
27
|
-
judge
|
|
36
|
+
judge?: Judge;
|
|
28
37
|
repetitions?: number;
|
|
29
38
|
concurrency?: number;
|
|
30
39
|
candidate?: {
|
|
@@ -48,7 +57,8 @@ export type MonitorPolicy = {
|
|
|
48
57
|
export type Eval = {
|
|
49
58
|
/** Let the host judge stop execution once the criterion is conclusively decided. */
|
|
50
59
|
earlyStop?:
|
|
51
|
-
|
|
60
|
+
| boolean
|
|
61
|
+
| (Partial<MonitorPolicy> & { onlyModels?: readonly ModelRef[] });
|
|
52
62
|
workspace?: {
|
|
53
63
|
repository?: string;
|
|
54
64
|
/** Readable file overlays committed in order to the named refs, on the host. */
|
|
@@ -69,15 +79,17 @@ export type EvalDefinition = {
|
|
|
69
79
|
settings: Eval;
|
|
70
80
|
sourceHash: string;
|
|
71
81
|
judgeHash: string;
|
|
72
|
-
/**
|
|
73
|
-
|
|
82
|
+
/** Criteria declared in judge.md; code-defined IDs are discovered from results. */
|
|
83
|
+
criteria: CriterionDefinition[];
|
|
84
|
+
/** A frozen, bundled code judge; never sent to the candidate. */
|
|
85
|
+
code?: CodeJudgeDefinition;
|
|
74
86
|
name: string;
|
|
75
87
|
};
|
|
76
88
|
export type BenchmarkDefinition = {
|
|
77
89
|
name: string;
|
|
78
90
|
directory: string;
|
|
79
91
|
models: ModelRef[];
|
|
80
|
-
judge:
|
|
92
|
+
judge: { model?: ModelRef; timeoutMs: number; websearch: "exa" | false };
|
|
81
93
|
repetitions: number;
|
|
82
94
|
concurrency: number;
|
|
83
95
|
candidate: {
|
|
@@ -113,6 +125,7 @@ export type SessionArchive = {
|
|
|
113
125
|
};
|
|
114
126
|
export type ToolCall = {
|
|
115
127
|
id: string;
|
|
128
|
+
sessionID?: string;
|
|
116
129
|
name: string;
|
|
117
130
|
assistantMessageId: string;
|
|
118
131
|
status: "preparing" | "called" | "succeeded" | "failed";
|
|
@@ -186,44 +199,49 @@ export type EvalRun = {
|
|
|
186
199
|
elapsedMs?: number;
|
|
187
200
|
evidence?: EvidenceRef;
|
|
188
201
|
session?: SessionArchive;
|
|
202
|
+
/** Candidate-only observations, independent of rubric scores. */
|
|
203
|
+
metrics?: RunMetrics;
|
|
189
204
|
error?: string;
|
|
190
205
|
replaces?: string;
|
|
191
206
|
stop?: EvalStop;
|
|
192
207
|
};
|
|
193
|
-
export type
|
|
208
|
+
export type CriterionDefinition = { id: string; name: string };
|
|
194
209
|
export type EvidenceCitation = (
|
|
195
210
|
| { kind: "response" }
|
|
196
|
-
| { kind: "
|
|
211
|
+
| { kind: "recording" }
|
|
212
|
+
| { kind: "tool" | "message" | "event" | "metric"; id: string }
|
|
197
213
|
| { kind: "artifact"; path: string; revision: "initial" | "final" }
|
|
198
214
|
) & { quote?: string; offset?: number };
|
|
199
|
-
export type
|
|
200
|
-
|
|
201
|
-
value: 0 | 1 | null;
|
|
215
|
+
export type CriterionScore = {
|
|
216
|
+
value: number | null;
|
|
202
217
|
reason: string;
|
|
203
218
|
evidence: EvidenceCitation[];
|
|
204
219
|
sources?: string[];
|
|
220
|
+
source: "judge.md" | "judge.ts";
|
|
205
221
|
};
|
|
206
|
-
/** value is the equal-weight
|
|
222
|
+
/** value is the equal-weight criterion mean, or null if any score is unknown. */
|
|
207
223
|
export type Judgment = {
|
|
208
224
|
value: number | null;
|
|
209
225
|
reason: string;
|
|
210
|
-
|
|
226
|
+
scores: Record<string, CriterionScore>;
|
|
211
227
|
};
|
|
212
228
|
export type JudgeRunInput = {
|
|
213
229
|
evalRunId: string;
|
|
214
230
|
evidence: EvidenceRef;
|
|
215
231
|
rubric: string;
|
|
216
232
|
/** Shared native agent profile used for this judgment. */
|
|
217
|
-
agent
|
|
233
|
+
agent?: Pick<AgentInfo, "id" | "mode" | "description" | "permissions"> & {
|
|
218
234
|
system: string;
|
|
219
235
|
};
|
|
220
|
-
model
|
|
236
|
+
model?: ModelRef;
|
|
237
|
+
kind: "llm" | "code" | "hybrid";
|
|
238
|
+
code?: CodeJudgeDefinition;
|
|
221
239
|
judgeHash: string;
|
|
222
240
|
timeoutMs: number;
|
|
223
241
|
websearch: "exa" | false;
|
|
224
242
|
mode: "monitor" | "final";
|
|
225
243
|
runtimeHash: string;
|
|
226
|
-
|
|
244
|
+
criteria: CriterionDefinition[];
|
|
227
245
|
protocol: number;
|
|
228
246
|
monitor?: MonitorPolicy;
|
|
229
247
|
};
|
|
@@ -237,6 +255,7 @@ export type JudgeRun = {
|
|
|
237
255
|
archiveStartedAt?: string;
|
|
238
256
|
judgment?: Judgment;
|
|
239
257
|
session?: SessionArchive;
|
|
258
|
+
code?: CodeJudgeExecution;
|
|
240
259
|
error?: string;
|
|
241
260
|
activity?: "watching" | "queued" | "checking" | "finalizing";
|
|
242
261
|
decisionCheckId?: string;
|