evalkit-py 0.2.0.dev12__py3-none-any.whl
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.
- evalkit/__init__.py +0 -0
- evalkit/api/__init__.py +0 -0
- evalkit/api/access.py +74 -0
- evalkit/api/agents.py +159 -0
- evalkit/api/app.py +360 -0
- evalkit/api/auth.py +225 -0
- evalkit/api/cli_dist.py +10 -0
- evalkit/api/datasets.py +169 -0
- evalkit/api/deps.py +79 -0
- evalkit/api/download.py +15 -0
- evalkit/api/evaluators.py +121 -0
- evalkit/api/experiments.py +616 -0
- evalkit/api/fixtures.py +95 -0
- evalkit/api/harness_check.py +48 -0
- evalkit/api/imports.py +180 -0
- evalkit/api/limits.py +84 -0
- evalkit/api/llm_providers.py +120 -0
- evalkit/api/mcp/__init__.py +0 -0
- evalkit/api/mcp/auth.py +100 -0
- evalkit/api/mcp/descriptions.py +336 -0
- evalkit/api/mcp/models.py +259 -0
- evalkit/api/mcp/server.py +101 -0
- evalkit/api/mcp/tools.py +844 -0
- evalkit/api/meta.py +19 -0
- evalkit/api/otel.py +350 -0
- evalkit/api/pull.py +197 -0
- evalkit/api/review.py +271 -0
- evalkit/api/runs.py +555 -0
- evalkit/api/server_keys.py +44 -0
- evalkit/api/tokens.py +51 -0
- evalkit/api/trace_imports.py +173 -0
- evalkit/api/trace_sources.py +49 -0
- evalkit/api/traces.py +196 -0
- evalkit/api/users.py +72 -0
- evalkit/api/workspaces.py +131 -0
- evalkit/bundled/contracts/atif-accepted.json +5 -0
- evalkit/bundled/contracts/custom-evaluator-api-v1.json +243 -0
- evalkit/bundled/contracts/harness-api-v1.json +938 -0
- evalkit/bundled/contracts/span-mapping-v1.json +314 -0
- evalkit/bundled/docs/concepts.md +26 -0
- evalkit/bundled/docs/config.md +38 -0
- evalkit/bundled/docs/harness-api.md +44 -0
- evalkit/bundled/docs/install.md +60 -0
- evalkit/bundled/docs/login.md +36 -0
- evalkit/bundled/docs/mappings.md +136 -0
- evalkit/bundled/docs/mcp.md +44 -0
- evalkit/bundled/docs/quickstart.md +142 -0
- evalkit/bundled/docs/sdk-runs.md +171 -0
- evalkit/bundled/docs/tracing.md +171 -0
- evalkit/bundled/docs/try-locally.md +288 -0
- evalkit/bundled/docs/workspaces.md +45 -0
- evalkit/bundled/skills/authoring-eval-cases/SKILL.md +387 -0
- evalkit/bundled/skills/authoring-eval-cases/references/overlays.md +83 -0
- evalkit/bundled/skills/authoring-eval-cases/references/tool-checks.md +71 -0
- evalkit/bundled/skills/connect-traces/SKILL.md +296 -0
- evalkit/bundled/skills/connect-traces/references/gen_ai.json +42 -0
- evalkit/bundled/skills/connect-traces/references/openinference.json +35 -0
- evalkit/bundled/skills/connect-traces/references/span-mapping-schema.md +88 -0
- evalkit/bundled/skills/eval-driven-development/SKILL.md +458 -0
- evalkit/bundled/skills/eval-driven-development/references/analyze-run.md +97 -0
- evalkit/bundled/skills/eval-driven-development/references/diagnose.md +130 -0
- evalkit/bundled/skills/eval-driven-development/references/synthesize-cases.md +87 -0
- evalkit/bundled/skills/eval-driven-development/references/synthesize.md +165 -0
- evalkit/bundled/skills/evalkit-deployment/SKILL.md +332 -0
- evalkit/bundled/skills/evalkit-deployment/config.example.yaml +49 -0
- evalkit/bundled/skills/evalkit-deployment/docker-compose.yml +51 -0
- evalkit/bundled/skills/evalkit-deployment/references/config-and-deploy.md +333 -0
- evalkit/bundled/skills/evalkit-deployment/references/harness-api.md +139 -0
- evalkit/bundled/skills/evalkit-deployment/try/.env.example +11 -0
- evalkit/bundled/skills/evalkit-deployment/try/agent.py +131 -0
- evalkit/bundled/skills/evalkit-deployment/try/cases/acme/balance-sheet/cases.yaml +25 -0
- evalkit/bundled/skills/evalkit-deployment/try/cases/acme/income-statement/cases.yaml +43 -0
- evalkit/bundled/skills/evalkit-deployment/try/config.yaml +17 -0
- evalkit/bundled/skills/evalkit-deployment/try/docker-compose.yml +82 -0
- evalkit/bundled/skills/evalkit-deployment/try/evalkit.yaml +4 -0
- evalkit/bundled/skills/evalkit-deployment/try/mapping.json +42 -0
- evalkit/bundled/skills/evalkit-deployment/try/run.py +33 -0
- evalkit/bundled/skills/evalkit-usage/SKILL.md +509 -0
- evalkit/bundled/skills/evalkit-usage/references/suite-fixtures.md +42 -0
- evalkit/bundled/ui/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- evalkit/bundled/ui/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- evalkit/bundled/ui/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- evalkit/bundled/ui/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- evalkit/bundled/ui/assets/abap-08VXUWAP.js +1 -0
- evalkit/bundled/ui/assets/apex-BWPQTe0t.js +1 -0
- evalkit/bundled/ui/assets/azcli-Bc_sGQ0U.js +1 -0
- evalkit/bundled/ui/assets/bat-i0X4ZdIN.js +1 -0
- evalkit/bundled/ui/assets/bicep-B5-_aFwp.js +2 -0
- evalkit/bundled/ui/assets/cameligo-DMUM7wLl.js +1 -0
- evalkit/bundled/ui/assets/clojure-Cm7r79vr.js +1 -0
- evalkit/bundled/ui/assets/codicon-DF1abBS2.ttf +0 -0
- evalkit/bundled/ui/assets/coffee-Ba7i2nA0.js +1 -0
- evalkit/bundled/ui/assets/cpp-C7h46wYY.js +1 -0
- evalkit/bundled/ui/assets/csharp-BKxtCVv1.js +1 -0
- evalkit/bundled/ui/assets/csp-bTuwJoIa.js +1 -0
- evalkit/bundled/ui/assets/css-DIMkf-bt.js +3 -0
- evalkit/bundled/ui/assets/css.worker-DwfUZ3fB.js +96 -0
- evalkit/bundled/ui/assets/cssMode-C97l1pbB.js +1 -0
- evalkit/bundled/ui/assets/cypher-CVaqCwHa.js +1 -0
- evalkit/bundled/ui/assets/dart-onAF5SnQ.js +1 -0
- evalkit/bundled/ui/assets/dockerfile-DZFCIeNp.js +1 -0
- evalkit/bundled/ui/assets/ecl-94qehhXe.js +1 -0
- evalkit/bundled/ui/assets/editor-DjpsE8to.css +1 -0
- evalkit/bundled/ui/assets/editor.api-NTesIxw5.js +908 -0
- evalkit/bundled/ui/assets/editor.worker-CRz__AKW.js +33 -0
- evalkit/bundled/ui/assets/elixir-6RTg0lbw.js +1 -0
- evalkit/bundled/ui/assets/flow9-C5_-GSwl.js +1 -0
- evalkit/bundled/ui/assets/freemarker2-BWqEFagp.js +3 -0
- evalkit/bundled/ui/assets/fsharp-C8Ef5oNN.js +1 -0
- evalkit/bundled/ui/assets/go-C-y9NEjX.js +1 -0
- evalkit/bundled/ui/assets/graphql-fmXr3nnJ.js +1 -0
- evalkit/bundled/ui/assets/handlebars-DkIF-whN.js +1 -0
- evalkit/bundled/ui/assets/hcl-CpzslTdj.js +1 -0
- evalkit/bundled/ui/assets/html-C_rpeQXJ.js +1 -0
- evalkit/bundled/ui/assets/html.worker-D9ugpX4y.js +509 -0
- evalkit/bundled/ui/assets/htmlMode-B0YIq3DF.js +1 -0
- evalkit/bundled/ui/assets/index-Cw-jBH6M.js +736 -0
- evalkit/bundled/ui/assets/index-DKtoQZtm.css +1 -0
- evalkit/bundled/ui/assets/ini-sBoK_t0W.js +1 -0
- evalkit/bundled/ui/assets/java-BEtHBSE6.js +1 -0
- evalkit/bundled/ui/assets/javascript-D4EGhYA6.js +1 -0
- evalkit/bundled/ui/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- evalkit/bundled/ui/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- evalkit/bundled/ui/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- evalkit/bundled/ui/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- evalkit/bundled/ui/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- evalkit/bundled/ui/assets/json.worker-CV9fqkUp.js +65 -0
- evalkit/bundled/ui/assets/jsonMode-pQjSfIH6.js +7 -0
- evalkit/bundled/ui/assets/julia-Bri6UV-V.js +1 -0
- evalkit/bundled/ui/assets/kotlin-BOotOW0E.js +1 -0
- evalkit/bundled/ui/assets/less-B9JPFI3C.js +2 -0
- evalkit/bundled/ui/assets/lexon-CfSJPG6W.js +1 -0
- evalkit/bundled/ui/assets/liquid-DbrvoYjD.js +1 -0
- evalkit/bundled/ui/assets/lspLanguageFeatures-D0B7cH6y.js +4 -0
- evalkit/bundled/ui/assets/lua-CsQS60Ue.js +1 -0
- evalkit/bundled/ui/assets/m3-D-oSqn_W.js +1 -0
- evalkit/bundled/ui/assets/markdown-Cimd5fb3.js +1 -0
- evalkit/bundled/ui/assets/mdx-B0HrujLR.js +1 -0
- evalkit/bundled/ui/assets/mips-CIPQ_RoX.js +1 -0
- evalkit/bundled/ui/assets/monacoEditor-DsoPncxW.js +68 -0
- evalkit/bundled/ui/assets/monacoEditor-n7clI0si.css +1 -0
- evalkit/bundled/ui/assets/msdax-DauUninz.js +1 -0
- evalkit/bundled/ui/assets/mysql-SOo6toE5.js +1 -0
- evalkit/bundled/ui/assets/objective-c-FvmIjYaQ.js +1 -0
- evalkit/bundled/ui/assets/pascal-DrH0SRf2.js +1 -0
- evalkit/bundled/ui/assets/pascaligo-D-ptJ9y-.js +1 -0
- evalkit/bundled/ui/assets/perl-oz_6vUea.js +1 -0
- evalkit/bundled/ui/assets/pgsql-DTj74zXo.js +1 -0
- evalkit/bundled/ui/assets/php-nr791fC2.js +1 -0
- evalkit/bundled/ui/assets/pla-CopQ2nXW.js +1 -0
- evalkit/bundled/ui/assets/postiats-43DmfD33.js +1 -0
- evalkit/bundled/ui/assets/powerquery-D3hlyOfw.js +1 -0
- evalkit/bundled/ui/assets/powershell-DmHpPYUd.js +1 -0
- evalkit/bundled/ui/assets/protobuf-C531GsRP.js +2 -0
- evalkit/bundled/ui/assets/pug-Z5eAx3Zn.js +1 -0
- evalkit/bundled/ui/assets/python-CieHVM9n.js +1 -0
- evalkit/bundled/ui/assets/qsharp-DkqhCAOL.js +1 -0
- evalkit/bundled/ui/assets/r-BwWrilGY.js +1 -0
- evalkit/bundled/ui/assets/razor-sLewSMyp.js +1 -0
- evalkit/bundled/ui/assets/redis-ClamHrr6.js +1 -0
- evalkit/bundled/ui/assets/redshift-DT7zqm-g.js +1 -0
- evalkit/bundled/ui/assets/restructuredtext-BYgofb2h.js +1 -0
- evalkit/bundled/ui/assets/ruby-DezsRK8O.js +1 -0
- evalkit/bundled/ui/assets/rust-DdL9SqIa.js +1 -0
- evalkit/bundled/ui/assets/sb-CcwsVR0C.js +1 -0
- evalkit/bundled/ui/assets/scala-DHpiXF5c.js +1 -0
- evalkit/bundled/ui/assets/scheme-BeGwcela.js +1 -0
- evalkit/bundled/ui/assets/scss-gp-XZpBa.js +3 -0
- evalkit/bundled/ui/assets/shell-CC2rA5mh.js +1 -0
- evalkit/bundled/ui/assets/solidity-BEEn4gHE.js +1 -0
- evalkit/bundled/ui/assets/sophia-CRfGWb83.js +1 -0
- evalkit/bundled/ui/assets/sparql-D_Lu-MrJ.js +1 -0
- evalkit/bundled/ui/assets/sql-NEE52Syq.js +1 -0
- evalkit/bundled/ui/assets/st-DbInun42.js +1 -0
- evalkit/bundled/ui/assets/swift-Bxkupp3x.js +1 -0
- evalkit/bundled/ui/assets/systemverilog-Bz4Y3fRF.js +1 -0
- evalkit/bundled/ui/assets/tcl-DISqw1ZD.js +1 -0
- evalkit/bundled/ui/assets/ts.worker-DIAQkoB3.js +67741 -0
- evalkit/bundled/ui/assets/tsMode-BcVQ1nu0.js +11 -0
- evalkit/bundled/ui/assets/twig-De2hgUGE.js +1 -0
- evalkit/bundled/ui/assets/typescript-CUvNWd9p.js +1 -0
- evalkit/bundled/ui/assets/typespec-B8J7ngcE.js +1 -0
- evalkit/bundled/ui/assets/vb-DV3o63ZY.js +1 -0
- evalkit/bundled/ui/assets/wgsl-DpFanUEy.js +298 -0
- evalkit/bundled/ui/assets/workers-CwpYQtzp.js +1 -0
- evalkit/bundled/ui/assets/xml-C1HnXMdF.js +1 -0
- evalkit/bundled/ui/assets/yaml-D7Ey3HQu.js +1 -0
- evalkit/bundled/ui/favicon.svg +6 -0
- evalkit/bundled/ui/index.html +14 -0
- evalkit/cli/__init__.py +0 -0
- evalkit/cli/admin_commands.py +590 -0
- evalkit/cli/client.py +67 -0
- evalkit/cli/init_server.py +165 -0
- evalkit/cli/local_run.py +195 -0
- evalkit/cli/main.py +1365 -0
- evalkit/cli/runs_commands.py +539 -0
- evalkit/cli/server_commands.py +130 -0
- evalkit/cli/skill_targets.py +43 -0
- evalkit/cli/tokens_commands.py +52 -0
- evalkit/cli/traces_commands.py +332 -0
- evalkit/cli/update.py +85 -0
- evalkit/client/__init__.py +0 -0
- evalkit/client/agents.py +25 -0
- evalkit/client/api.py +193 -0
- evalkit/client/blob.py +104 -0
- evalkit/client/connection.py +88 -0
- evalkit/client/evaluators.py +11 -0
- evalkit/client/sessions.py +17 -0
- evalkit/client/store.py +139 -0
- evalkit/client/summary.py +46 -0
- evalkit/client/sync.py +198 -0
- evalkit/config.py +227 -0
- evalkit/contracts/__init__.py +0 -0
- evalkit/contracts/atif.py +115 -0
- evalkit/contracts/cases.py +456 -0
- evalkit/contracts/custom_evaluator.py +58 -0
- evalkit/contracts/enums.py +86 -0
- evalkit/contracts/esf.py +120 -0
- evalkit/contracts/harness.py +281 -0
- evalkit/contracts/notes.json +4 -0
- evalkit/contracts/notes.py +7 -0
- evalkit/contracts/settings.py +41 -0
- evalkit/core/__init__.py +0 -0
- evalkit/core/access.py +75 -0
- evalkit/core/agents.py +65 -0
- evalkit/core/blob.py +46 -0
- evalkit/core/capabilities.py +36 -0
- evalkit/core/costmap.py +90 -0
- evalkit/core/custom_eval.py +50 -0
- evalkit/core/data/cost_map.json +81546 -0
- evalkit/core/endpoints.py +31 -0
- evalkit/core/evaluators/__init__.py +29 -0
- evalkit/core/evaluators/base.py +121 -0
- evalkit/core/evaluators/gauges.py +84 -0
- evalkit/core/evaluators/presentation.py +166 -0
- evalkit/core/evaluators/response_time.py +21 -0
- evalkit/core/evaluators/rubrics.py +494 -0
- evalkit/core/evaluators/tool_trajectory.py +187 -0
- evalkit/core/evaluators/trajectory_rubrics.py +198 -0
- evalkit/core/fixtures.py +57 -0
- evalkit/core/harness.py +227 -0
- evalkit/core/harness_check.py +191 -0
- evalkit/core/importer.py +257 -0
- evalkit/core/judge.py +78 -0
- evalkit/core/lint.py +265 -0
- evalkit/core/overlays.py +76 -0
- evalkit/core/paths.py +25 -0
- evalkit/core/promotion.py +94 -0
- evalkit/core/pull.py +198 -0
- evalkit/core/python_eval.py +59 -0
- evalkit/core/remote_evaluators.py +32 -0
- evalkit/core/review.py +220 -0
- evalkit/core/run_digest.py +421 -0
- evalkit/core/runner.py +995 -0
- evalkit/core/scorecard.py +255 -0
- evalkit/core/traces/__init__.py +0 -0
- evalkit/core/traces/convert.py +336 -0
- evalkit/core/traces/importer.py +113 -0
- evalkit/core/traces/mapping.py +385 -0
- evalkit/core/traces/poll.py +38 -0
- evalkit/core/traces/raw.py +21 -0
- evalkit/core/traces/sessions.py +172 -0
- evalkit/core/traces/settle.py +14 -0
- evalkit/core/traces/sources/__init__.py +19 -0
- evalkit/core/traces/sources/base.py +25 -0
- evalkit/core/traces/sources/phoenix.py +121 -0
- evalkit/core/trajectory.py +248 -0
- evalkit/core/workspace.py +30 -0
- evalkit/credentials.py +119 -0
- evalkit/db/__init__.py +0 -0
- evalkit/db/agents.py +289 -0
- evalkit/db/alembic/env.py +90 -0
- evalkit/db/alembic/script.py.mako +28 -0
- evalkit/db/alembic/versions/0011_baseline.py +1002 -0
- evalkit/db/alembic/versions/0012_ticket_token_kind.py +27 -0
- evalkit/db/alembic/versions/0013_keys_and_llm_providers.py +67 -0
- evalkit/db/cases.py +608 -0
- evalkit/db/crypto.py +12 -0
- evalkit/db/evaluators.py +156 -0
- evalkit/db/experiments.py +363 -0
- evalkit/db/fixture_blobs.py +91 -0
- evalkit/db/keys.py +78 -0
- evalkit/db/llm_providers.py +176 -0
- evalkit/db/locks.py +6 -0
- evalkit/db/mappings.py +168 -0
- evalkit/db/models.py +567 -0
- evalkit/db/promotion.py +271 -0
- evalkit/db/rekey.py +46 -0
- evalkit/db/review.py +250 -0
- evalkit/db/review_state.py +50 -0
- evalkit/db/runs.py +533 -0
- evalkit/db/scorecard.py +300 -0
- evalkit/db/session.py +71 -0
- evalkit/db/sessions.py +90 -0
- evalkit/db/spans.py +360 -0
- evalkit/db/store.py +209 -0
- evalkit/db/tokens.py +100 -0
- evalkit/db/trace_imports.py +308 -0
- evalkit/db/trace_sources.py +131 -0
- evalkit/db/users.py +186 -0
- evalkit/db/workspaces.py +232 -0
- evalkit/paths.py +33 -0
- evalkit/sdk/__init__.py +29 -0
- evalkit/sdk/binding.py +69 -0
- evalkit/sdk/evaluators.py +56 -0
- evalkit/sdk/runner.py +957 -0
- evalkit/sdk/tracing.py +166 -0
- evalkit/store/__init__.py +0 -0
- evalkit/store/base.py +354 -0
- evalkit/store/blob.py +69 -0
- evalkit/version.py +44 -0
- evalkit_py-0.2.0.dev12.dist-info/METADATA +205 -0
- evalkit_py-0.2.0.dev12.dist-info/RECORD +371 -0
- evalkit_py-0.2.0.dev12.dist-info/WHEEL +4 -0
- evalkit_py-0.2.0.dev12.dist-info/entry_points.txt +2 -0
- evalkit_py-0.2.0.dev12.dist-info/licenses/LICENSE +661 -0
evalkit/sdk/tracing.py
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import threading
|
|
5
|
+
from collections import OrderedDict
|
|
6
|
+
from collections.abc import Callable, Iterator
|
|
7
|
+
from contextlib import contextmanager
|
|
8
|
+
from contextvars import ContextVar
|
|
9
|
+
from importlib.util import find_spec
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from opentelemetry import trace
|
|
13
|
+
from opentelemetry.context import Context
|
|
14
|
+
|
|
15
|
+
from evalkit.client import connection
|
|
16
|
+
|
|
17
|
+
OTEL_TOKEN_ENV = "EVALKIT_OTEL_TOKEN"
|
|
18
|
+
SERVER_URL_ENV = "EVALKIT_SERVER_URL"
|
|
19
|
+
AGENT_HEADER = "X-Evalkit-Agent"
|
|
20
|
+
STAMPED = ("session.id", "evalkit.experiment_id", "evalkit.case_id", "evalkit.repetition")
|
|
21
|
+
EVAL_MARKER = "evalkit.case_id"
|
|
22
|
+
MAX_EVAL_TRACES = 10_000
|
|
23
|
+
INSTALL_HINT = "evalkit tracing needs the otel extra: uv add 'evalkit-py[otel]'"
|
|
24
|
+
|
|
25
|
+
CURRENT_RUN: ContextVar[dict[str, Any] | None] = ContextVar("evalkit_current_run", default=None)
|
|
26
|
+
|
|
27
|
+
SpanFilter = Callable[[Any], bool]
|
|
28
|
+
|
|
29
|
+
HAS_OTEL_SDK = bool(
|
|
30
|
+
find_spec("opentelemetry.sdk") and find_spec("opentelemetry.exporter.otlp.proto.http")
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
if HAS_OTEL_SDK:
|
|
34
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
|
35
|
+
from opentelemetry.sdk.resources import Resource
|
|
36
|
+
from opentelemetry.sdk.trace import ReadableSpan, SpanProcessor, TracerProvider
|
|
37
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor, SpanExporter
|
|
38
|
+
|
|
39
|
+
class EvalkitSpanProcessor(SpanProcessor):
|
|
40
|
+
def __init__(self, exporter: SpanExporter, only: SpanFilter | None = None) -> None:
|
|
41
|
+
self.batch = BatchSpanProcessor(exporter)
|
|
42
|
+
self.only = only
|
|
43
|
+
self.max_traces = MAX_EVAL_TRACES
|
|
44
|
+
self.kept_traces: OrderedDict[int, None] = OrderedDict()
|
|
45
|
+
self.lock = threading.Lock()
|
|
46
|
+
|
|
47
|
+
def on_start(self, span: Any, parent_context: Context | None = None) -> None:
|
|
48
|
+
attributes = CURRENT_RUN.get()
|
|
49
|
+
if attributes:
|
|
50
|
+
for key in STAMPED:
|
|
51
|
+
if key in attributes:
|
|
52
|
+
span.set_attribute(key, attributes[key])
|
|
53
|
+
if self.only is not None and self.only(span):
|
|
54
|
+
self.keep_trace(trace_of(span))
|
|
55
|
+
|
|
56
|
+
def on_end(self, span: ReadableSpan) -> None:
|
|
57
|
+
if self.only is None:
|
|
58
|
+
self.batch.on_end(span)
|
|
59
|
+
return
|
|
60
|
+
trace_id = trace_of(span)
|
|
61
|
+
if self.only(span):
|
|
62
|
+
self.keep_trace(trace_id)
|
|
63
|
+
if self.is_kept(trace_id):
|
|
64
|
+
self.batch.on_end(span)
|
|
65
|
+
|
|
66
|
+
def is_kept(self, trace_id: int) -> bool:
|
|
67
|
+
with self.lock:
|
|
68
|
+
if trace_id not in self.kept_traces:
|
|
69
|
+
return False
|
|
70
|
+
self.kept_traces.move_to_end(trace_id)
|
|
71
|
+
return True
|
|
72
|
+
|
|
73
|
+
def keep_trace(self, trace_id: int) -> None:
|
|
74
|
+
with self.lock:
|
|
75
|
+
self.kept_traces[trace_id] = None
|
|
76
|
+
self.kept_traces.move_to_end(trace_id)
|
|
77
|
+
while len(self.kept_traces) > self.max_traces:
|
|
78
|
+
self.kept_traces.popitem(last=False)
|
|
79
|
+
|
|
80
|
+
def shutdown(self) -> None:
|
|
81
|
+
self.batch.shutdown()
|
|
82
|
+
|
|
83
|
+
def force_flush(self, timeout_millis: int = 30000) -> bool:
|
|
84
|
+
return self.batch.force_flush(timeout_millis)
|
|
85
|
+
|
|
86
|
+
def configure(
|
|
87
|
+
provider: TracerProvider, exporter: SpanExporter, only: SpanFilter | None = None
|
|
88
|
+
) -> None:
|
|
89
|
+
provider.add_span_processor(EvalkitSpanProcessor(exporter, only))
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def trace_of(span: Any) -> int:
|
|
93
|
+
return span.get_span_context().trace_id
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def collector_url(server_url: str) -> str:
|
|
97
|
+
return f"{server_url.rstrip('/')}/api/otel/v1/traces"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def resolve_destination() -> tuple[str, str | None]:
|
|
101
|
+
token = os.environ.get(OTEL_TOKEN_ENV)
|
|
102
|
+
url = os.environ.get(SERVER_URL_ENV)
|
|
103
|
+
if url and token:
|
|
104
|
+
return url, token
|
|
105
|
+
active = connection.active()
|
|
106
|
+
return url or active.url, token or active.token
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def headers(agent: str) -> dict[str, str]:
|
|
110
|
+
_, token = resolve_destination()
|
|
111
|
+
out = {AGENT_HEADER: agent}
|
|
112
|
+
if token:
|
|
113
|
+
out["Authorization"] = f"Bearer {token}"
|
|
114
|
+
return out
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def exporter(agent: str) -> OTLPSpanExporter:
|
|
118
|
+
if not HAS_OTEL_SDK:
|
|
119
|
+
raise RuntimeError(INSTALL_HINT)
|
|
120
|
+
url, _ = resolve_destination()
|
|
121
|
+
return OTLPSpanExporter(endpoint=collector_url(url), headers=headers(agent))
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def processor(agent: str, only: SpanFilter | None = None) -> EvalkitSpanProcessor:
|
|
125
|
+
return EvalkitSpanProcessor(exporter(agent), only)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def is_eval_span(span: Any) -> bool:
|
|
129
|
+
return EVAL_MARKER in (span.attributes or {})
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@contextmanager
|
|
133
|
+
def eval_run(metadata: dict[str, Any]) -> Iterator[None]:
|
|
134
|
+
attributes = {
|
|
135
|
+
"session.id": metadata.get("session_id"),
|
|
136
|
+
"evalkit.experiment_id": metadata.get("experiment_id"),
|
|
137
|
+
"evalkit.case_id": metadata.get("case_id"),
|
|
138
|
+
"evalkit.repetition": metadata.get("repetition"),
|
|
139
|
+
}
|
|
140
|
+
token = CURRENT_RUN.set({k: v for k, v in attributes.items() if v is not None})
|
|
141
|
+
try:
|
|
142
|
+
yield
|
|
143
|
+
finally:
|
|
144
|
+
CURRENT_RUN.reset(token)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def register(agent: str, only: SpanFilter | None = None) -> None:
|
|
148
|
+
"""Send this process's OpenTelemetry spans to the evalkit server.
|
|
149
|
+
|
|
150
|
+
Adds an exporter to the global tracer provider, or creates one when none is set.
|
|
151
|
+
Call it after your own tracing setup, so it joins your provider. Spans go to the
|
|
152
|
+
server you logged in to (or `EVALKIT_SERVER_URL`), with your token or
|
|
153
|
+
`EVALKIT_OTEL_TOKEN` (an agent token). Needs the `otel` extra.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
agent: The agent the spans belong to, e.g. `myagent` or `myagent@dev`.
|
|
157
|
+
only: Export only the spans this function returns `True` for.
|
|
158
|
+
"""
|
|
159
|
+
span_processor = processor(agent, only)
|
|
160
|
+
current = trace.get_tracer_provider()
|
|
161
|
+
if isinstance(current, TracerProvider):
|
|
162
|
+
provider = current
|
|
163
|
+
else:
|
|
164
|
+
provider = TracerProvider(resource=Resource.create({"evalkit.agent": agent}))
|
|
165
|
+
trace.set_tracer_provider(provider)
|
|
166
|
+
provider.add_span_processor(span_processor)
|
|
File without changes
|
evalkit/store/base.py
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
from collections.abc import AsyncIterator
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Any, Literal, Protocol
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from evalkit.contracts.enums import (
|
|
9
|
+
EvaluationSource,
|
|
10
|
+
EvaluatorKind,
|
|
11
|
+
ExperimentStatus,
|
|
12
|
+
RunStatus,
|
|
13
|
+
TrajectorySource,
|
|
14
|
+
TrajectoryStatus,
|
|
15
|
+
)
|
|
16
|
+
from evalkit.contracts.settings import JudgeSettings, RemoteEvaluatorSettings
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True)
|
|
20
|
+
class BlobStream:
|
|
21
|
+
size: int
|
|
22
|
+
chunks: AsyncIterator[bytes]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class UnknownDataset(KeyError):
|
|
26
|
+
def __init__(self, ref: str):
|
|
27
|
+
super().__init__(ref)
|
|
28
|
+
self.ref = ref
|
|
29
|
+
|
|
30
|
+
def __str__(self) -> str:
|
|
31
|
+
return f"unknown dataset: {self.ref}"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class CaseFile(BaseModel):
|
|
35
|
+
key: str
|
|
36
|
+
sha256: str
|
|
37
|
+
context: str
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class FixtureUse(BaseModel):
|
|
41
|
+
key: str
|
|
42
|
+
sha256: str
|
|
43
|
+
size: int
|
|
44
|
+
datasets: list[str]
|
|
45
|
+
uploaded_by: str | None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class FixtureUsePage(BaseModel):
|
|
49
|
+
items: list[FixtureUse]
|
|
50
|
+
total: int
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class CaseView(BaseModel):
|
|
54
|
+
case_ref: int
|
|
55
|
+
case_id: str
|
|
56
|
+
content_hash: str
|
|
57
|
+
input: dict[str, Any]
|
|
58
|
+
expected: dict[str, Any] | None = None
|
|
59
|
+
evaluators: dict[str, Any] = Field(default_factory=dict)
|
|
60
|
+
effective_evaluators: dict[str, Any] = Field(default_factory=dict)
|
|
61
|
+
tags: list[str] = Field(default_factory=list)
|
|
62
|
+
split_tags: list[str] = Field(default_factory=list)
|
|
63
|
+
source: str | None = None
|
|
64
|
+
files: list[CaseFile] = Field(default_factory=list)
|
|
65
|
+
review_state: str | None = None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class DatasetSyncView(BaseModel):
|
|
69
|
+
id: int
|
|
70
|
+
source: str
|
|
71
|
+
detail: dict[str, Any]
|
|
72
|
+
actor: str
|
|
73
|
+
created_at: datetime
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class DatasetRow(BaseModel):
|
|
77
|
+
id: int
|
|
78
|
+
workspace: str
|
|
79
|
+
workspace_is_shared: bool
|
|
80
|
+
name: str
|
|
81
|
+
kind: str
|
|
82
|
+
last_sync: DatasetSyncView | None = None
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def ref(self) -> str:
|
|
86
|
+
return f"{self.name}@{self.workspace}"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class Selection(BaseModel):
|
|
90
|
+
all: bool = False
|
|
91
|
+
tag: str | None = None
|
|
92
|
+
case_ids: list[str] | None = None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class IncomingCase(BaseModel):
|
|
96
|
+
case_id: str
|
|
97
|
+
content_hash: str
|
|
98
|
+
input: dict[str, Any]
|
|
99
|
+
expected: dict[str, Any] | None = None
|
|
100
|
+
evaluators: dict[str, Any] = Field(default_factory=dict)
|
|
101
|
+
tags: list[str] = Field(default_factory=list)
|
|
102
|
+
path_tags: list[str] = Field(default_factory=list)
|
|
103
|
+
source: str | None = None
|
|
104
|
+
files: list[CaseFile] = Field(default_factory=list)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class IncomingOverlay(BaseModel):
|
|
108
|
+
target_case_id: str
|
|
109
|
+
agents: list[str]
|
|
110
|
+
tags: list[str]
|
|
111
|
+
evaluators: dict[str, Any]
|
|
112
|
+
source_file: str | None = None
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class CarriedReview(BaseModel):
|
|
116
|
+
case_id: str
|
|
117
|
+
reviewer: str
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class SyncResult(BaseModel):
|
|
121
|
+
sync_id: int
|
|
122
|
+
dataset_id: int
|
|
123
|
+
created: list[str] = Field(default_factory=list)
|
|
124
|
+
patched: list[str] = Field(default_factory=list)
|
|
125
|
+
removed: list[str] = Field(default_factory=list)
|
|
126
|
+
unchanged: int = 0
|
|
127
|
+
overlays: int = 0
|
|
128
|
+
carried: list[CarriedReview] = Field(default_factory=list)
|
|
129
|
+
now_unreviewed: list[str] = Field(default_factory=list)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class GitRevision(BaseModel):
|
|
133
|
+
sha: str | None = None
|
|
134
|
+
branch: str | None = None
|
|
135
|
+
dirty: bool | None = None
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class ExperimentSnapshot(BaseModel):
|
|
139
|
+
capabilities: dict[str, Any]
|
|
140
|
+
trajectory_source: TrajectorySource
|
|
141
|
+
trajectory_wait_seconds: int
|
|
142
|
+
remote_evaluators: dict[str, RemoteEvaluatorSettings] = Field(default_factory=dict)
|
|
143
|
+
code_evaluators: list[str] = Field(default_factory=list)
|
|
144
|
+
evalkit_version: str | None = None
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class ExperimentConfig(BaseModel):
|
|
148
|
+
model: str | None = None
|
|
149
|
+
judge: JudgeSettings
|
|
150
|
+
selection: Selection
|
|
151
|
+
revision: GitRevision | None = None
|
|
152
|
+
snapshot: ExperimentSnapshot
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class Experiment(BaseModel):
|
|
156
|
+
id: int
|
|
157
|
+
number: int
|
|
158
|
+
workspace: str
|
|
159
|
+
dataset: str
|
|
160
|
+
agent: str
|
|
161
|
+
agent_id: int
|
|
162
|
+
created_by: str
|
|
163
|
+
status: ExperimentStatus
|
|
164
|
+
status_error: str | None
|
|
165
|
+
lease_holder: str | None
|
|
166
|
+
lease_expires_at: datetime | None
|
|
167
|
+
repetitions: int
|
|
168
|
+
config: ExperimentConfig
|
|
169
|
+
started_at: datetime
|
|
170
|
+
ended_at: datetime | None
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class PinnedVersion(BaseModel):
|
|
174
|
+
case_ref: int
|
|
175
|
+
content_hash: str
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class NewExperiment(BaseModel):
|
|
179
|
+
dataset: str
|
|
180
|
+
agent: str
|
|
181
|
+
runner: str
|
|
182
|
+
repetitions: int
|
|
183
|
+
config: ExperimentConfig
|
|
184
|
+
cases: list[PinnedVersion]
|
|
185
|
+
holder: str
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class AgentRunRecord(BaseModel):
|
|
189
|
+
harness_run_id: str
|
|
190
|
+
status: RunStatus
|
|
191
|
+
answer: str | None = None
|
|
192
|
+
output: dict[str, Any] | None = None
|
|
193
|
+
error: str | None = None
|
|
194
|
+
started_at: datetime
|
|
195
|
+
ended_at: datetime | None = None
|
|
196
|
+
trajectory_key: str | None = None
|
|
197
|
+
trajectory_status: TrajectoryStatus | None = None
|
|
198
|
+
metrics: dict[str, Any] = Field(default_factory=dict)
|
|
199
|
+
title: str | None = None
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class RunRef(BaseModel):
|
|
203
|
+
experiment_run_id: int
|
|
204
|
+
agent_run_id: int
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class CaseRep(BaseModel):
|
|
208
|
+
case_id: str
|
|
209
|
+
repetition: int
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class EvaluationRow(BaseModel):
|
|
213
|
+
producer: str
|
|
214
|
+
name: str
|
|
215
|
+
kind: EvaluatorKind
|
|
216
|
+
source: EvaluationSource
|
|
217
|
+
value: float | None = None
|
|
218
|
+
label: str | None = None
|
|
219
|
+
explanation: str | None = None
|
|
220
|
+
error: str | None = None
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class RunEvalContext(BaseModel):
|
|
224
|
+
experiment_id: int
|
|
225
|
+
repetition: int
|
|
226
|
+
case: CaseView
|
|
227
|
+
evaluations: list[EvaluationRow]
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
class RunForScoring(BaseModel):
|
|
231
|
+
experiment_run_id: int
|
|
232
|
+
case: CaseView
|
|
233
|
+
repetition: int
|
|
234
|
+
agent_run: AgentRunRecord
|
|
235
|
+
agent_run_id: int
|
|
236
|
+
done: set[str]
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class RunDetail(BaseModel):
|
|
240
|
+
experiment_run_id: int
|
|
241
|
+
case_id: str
|
|
242
|
+
repetition: int
|
|
243
|
+
agent_run_id: int
|
|
244
|
+
agent_run: AgentRunRecord
|
|
245
|
+
evaluations: list[EvaluationRow] = Field(default_factory=list)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class AggregateRows(BaseModel):
|
|
249
|
+
experiment: Experiment
|
|
250
|
+
case_scores: list[tuple[str, str, float, str | None, str | None]]
|
|
251
|
+
case_gauges: list[tuple[str, str, float]]
|
|
252
|
+
case_errors: list[tuple[str, str, str]]
|
|
253
|
+
run_errors: list[tuple[str, str]]
|
|
254
|
+
repetitions_seen: dict[str, int]
|
|
255
|
+
sources: dict[str, str]
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
RunState = Literal["pending", "ran", "evaluated"]
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class Progress(BaseModel):
|
|
262
|
+
total: int
|
|
263
|
+
ran: int
|
|
264
|
+
evaluated: int
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class HistoryPoint(BaseModel):
|
|
268
|
+
experiment_id: int
|
|
269
|
+
number: int
|
|
270
|
+
agent: str
|
|
271
|
+
model: str | None = None
|
|
272
|
+
created_by: str
|
|
273
|
+
created_at: datetime
|
|
274
|
+
repetitions: int
|
|
275
|
+
scores: dict[str, float | None]
|
|
276
|
+
cost_usd: float | None = None
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
class UnknownExperiment(KeyError):
|
|
280
|
+
def __init__(self, experiment_id: int):
|
|
281
|
+
super().__init__(f"unknown experiment: {experiment_id}")
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
class Conflict(Exception):
|
|
285
|
+
pass
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
class InvalidRun(ValueError):
|
|
289
|
+
pass
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class ScoreRow(BaseModel):
|
|
293
|
+
name: str
|
|
294
|
+
kind: Literal["evaluator", "gauge"] = "evaluator"
|
|
295
|
+
score: float | None = None
|
|
296
|
+
label: str | None = None
|
|
297
|
+
explanation: str | None = None
|
|
298
|
+
source: str = "builtin"
|
|
299
|
+
error: str | None = None
|
|
300
|
+
annotator_kind: Literal["CODE", "LLM", "HUMAN"] = "CODE"
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
class Store(Protocol):
|
|
304
|
+
async def cases_for(
|
|
305
|
+
self, dataset: str, selection: Selection, *, agent: str | None
|
|
306
|
+
) -> list[CaseView]: ...
|
|
307
|
+
|
|
308
|
+
async def get_experiment(self, exp_id: int) -> Experiment: ...
|
|
309
|
+
|
|
310
|
+
async def pinned_cases(self, exp_id: int) -> list[CaseView]: ...
|
|
311
|
+
|
|
312
|
+
async def transition(
|
|
313
|
+
self, exp_id: int, to: ExperimentStatus, holder: str | None, error: str | None = None
|
|
314
|
+
) -> Experiment: ...
|
|
315
|
+
|
|
316
|
+
async def renew_lease(self, exp_id: int, holder: str) -> bool: ...
|
|
317
|
+
|
|
318
|
+
async def set_model(self, exp_id: int, model: str) -> None: ...
|
|
319
|
+
|
|
320
|
+
async def pending_runs(self, exp_id: int) -> list[CaseRep]: ...
|
|
321
|
+
|
|
322
|
+
async def harness_run_id_used(self, exp_id: int, harness_run_id: str) -> str | None: ...
|
|
323
|
+
|
|
324
|
+
async def record_run(
|
|
325
|
+
self,
|
|
326
|
+
exp_id: int,
|
|
327
|
+
case_id: str,
|
|
328
|
+
repetition: int,
|
|
329
|
+
run: AgentRunRecord,
|
|
330
|
+
*,
|
|
331
|
+
holder: str | None = None,
|
|
332
|
+
) -> RunRef: ...
|
|
333
|
+
|
|
334
|
+
async def runs_to_score(self, exp_id: int, *, force: bool) -> list[RunForScoring]: ...
|
|
335
|
+
|
|
336
|
+
async def publish_evaluations(
|
|
337
|
+
self,
|
|
338
|
+
experiment_run_id: int,
|
|
339
|
+
rows: list[EvaluationRow],
|
|
340
|
+
*,
|
|
341
|
+
force: bool,
|
|
342
|
+
holder: str | None = None,
|
|
343
|
+
) -> None: ...
|
|
344
|
+
|
|
345
|
+
async def aclose(self) -> None: ...
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def select_cases(cases: list[CaseView], selection: Selection) -> list[CaseView]:
|
|
349
|
+
if selection.all:
|
|
350
|
+
return list(cases)
|
|
351
|
+
if selection.tag:
|
|
352
|
+
return [case for case in cases if selection.tag in case.split_tags]
|
|
353
|
+
wanted = set(selection.case_ids or [])
|
|
354
|
+
return [case for case in cases if case.case_id in wanted]
|
evalkit/store/blob.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import AsyncIterator
|
|
4
|
+
|
|
5
|
+
import obstore
|
|
6
|
+
from obstore.exceptions import NotFoundError
|
|
7
|
+
from obstore.store import ObjectStore, from_url
|
|
8
|
+
|
|
9
|
+
from evalkit.store.base import BlobStream
|
|
10
|
+
|
|
11
|
+
CHUNK_BYTES = 1024 * 1024
|
|
12
|
+
|
|
13
|
+
_stores: dict[str, ObjectStore] = {}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _store_for(url: str) -> ObjectStore:
|
|
17
|
+
if url not in _stores:
|
|
18
|
+
_stores[url] = from_url(url, mkdir=True) if url.startswith("file://") else from_url(url)
|
|
19
|
+
return _stores[url]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Obstore:
|
|
23
|
+
def __init__(self, url: str):
|
|
24
|
+
self.url = url
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def _store(self) -> ObjectStore:
|
|
28
|
+
return _store_for(self.url)
|
|
29
|
+
|
|
30
|
+
async def put_object(self, key: str, data: bytes) -> None:
|
|
31
|
+
await obstore.put_async(self._store, key, data)
|
|
32
|
+
|
|
33
|
+
async def put_stream(self, key: str, chunks: AsyncIterator[bytes]) -> None:
|
|
34
|
+
await obstore.put_async(self._store, key, chunks)
|
|
35
|
+
|
|
36
|
+
async def get_object(self, key: str) -> bytes:
|
|
37
|
+
resp = await obstore.get_async(self._store, key)
|
|
38
|
+
return bytes(await resp.bytes_async())
|
|
39
|
+
|
|
40
|
+
async def get_stream(self, key: str) -> BlobStream:
|
|
41
|
+
resp = await obstore.get_async(self._store, key)
|
|
42
|
+
return BlobStream(resp.meta["size"], _chunks(resp.stream(min_chunk_size=CHUNK_BYTES)))
|
|
43
|
+
|
|
44
|
+
async def object_exists(self, key: str) -> bool:
|
|
45
|
+
try:
|
|
46
|
+
await obstore.head_async(self._store, key)
|
|
47
|
+
return True
|
|
48
|
+
except (NotFoundError, FileNotFoundError):
|
|
49
|
+
return False
|
|
50
|
+
|
|
51
|
+
async def list_objects(self, prefix: str) -> list[tuple[str, int]]:
|
|
52
|
+
objects: list[tuple[str, int]] = []
|
|
53
|
+
async for chunk in obstore.list(self._store, prefix=prefix):
|
|
54
|
+
objects.extend((obj["path"], obj["size"]) for obj in chunk)
|
|
55
|
+
return objects
|
|
56
|
+
|
|
57
|
+
async def delete_object(self, key: str) -> None:
|
|
58
|
+
await obstore.delete_async(self._store, key)
|
|
59
|
+
|
|
60
|
+
async def copy_object(self, source: str, destination: str) -> None:
|
|
61
|
+
await obstore.copy_async(self._store, source, destination)
|
|
62
|
+
|
|
63
|
+
async def object_url(self, key: str) -> str:
|
|
64
|
+
return f"{self.url.rstrip('/')}/{key}"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
async def _chunks(stream: AsyncIterator) -> AsyncIterator[bytes]:
|
|
68
|
+
async for chunk in stream:
|
|
69
|
+
yield bytes(chunk)
|
evalkit/version.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib.metadata
|
|
4
|
+
import re
|
|
5
|
+
from enum import StrEnum
|
|
6
|
+
from typing import NamedTuple
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ParsedVersion(NamedTuple):
|
|
10
|
+
major: int
|
|
11
|
+
minor: int
|
|
12
|
+
patch: int
|
|
13
|
+
build_id: str | None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class VersionComparison(StrEnum):
|
|
17
|
+
SAME = "same"
|
|
18
|
+
DIFFERENT = "different"
|
|
19
|
+
INCOMPATIBLE = "incompatible"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
DISTRIBUTION = "evalkit-py"
|
|
23
|
+
_VERSION = re.compile(r"(\d+)\.(\d+)\.(\d+)(?:\.(dev\d+))?(?:\+(.+))?")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def current() -> str:
|
|
27
|
+
return importlib.metadata.version(DISTRIBUTION)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def parse(version: str) -> ParsedVersion:
|
|
31
|
+
match = _VERSION.fullmatch(version)
|
|
32
|
+
if match is None:
|
|
33
|
+
raise ValueError(f"not an evalkit version: {version}")
|
|
34
|
+
major, minor, patch, dev, local = match.groups()
|
|
35
|
+
return ParsedVersion(int(major), int(minor), int(patch), dev or local)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def compare(local: str, remote: str) -> VersionComparison:
|
|
39
|
+
mine, theirs = parse(local), parse(remote)
|
|
40
|
+
if mine.major != theirs.major or (mine.major == 0 and mine.minor != theirs.minor):
|
|
41
|
+
return VersionComparison.INCOMPATIBLE
|
|
42
|
+
if local == remote:
|
|
43
|
+
return VersionComparison.SAME
|
|
44
|
+
return VersionComparison.DIFFERENT
|