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/contracts/esf.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Any, Literal
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
5
|
+
|
|
6
|
+
EsfKind = Literal["llm", "tool", "agent", "chain", "retriever", "other"]
|
|
7
|
+
MessageFormat = Literal["openinference", "gen_ai", "openai"]
|
|
8
|
+
MAPPING_SCHEMA_VERSION = "1"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class EsfToolCall(BaseModel):
|
|
12
|
+
id: str
|
|
13
|
+
name: str
|
|
14
|
+
arguments: dict[str, Any] | str
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class EsfMessage(BaseModel):
|
|
18
|
+
role: str
|
|
19
|
+
text: str | None = None
|
|
20
|
+
reasoning: str | None = None
|
|
21
|
+
tool_calls: list[EsfToolCall] | None = None
|
|
22
|
+
tool_call_id: str | None = None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class EsfSpan(BaseModel):
|
|
26
|
+
span_id: str
|
|
27
|
+
trace_id: str
|
|
28
|
+
parent_id: str | None
|
|
29
|
+
name: str
|
|
30
|
+
kind: EsfKind
|
|
31
|
+
started_at: datetime
|
|
32
|
+
ended_at: datetime | None
|
|
33
|
+
error: str | None
|
|
34
|
+
model: str | None = None
|
|
35
|
+
input_messages: list[EsfMessage] | None = None
|
|
36
|
+
output_messages: list[EsfMessage] | None = None
|
|
37
|
+
input: Any | None = None
|
|
38
|
+
output: Any | None = None
|
|
39
|
+
tool_name: str | None = None
|
|
40
|
+
tool_call_id: str | None = None
|
|
41
|
+
agent_name: str | None = None
|
|
42
|
+
prompt_tokens: int | None = None
|
|
43
|
+
completion_tokens: int | None = None
|
|
44
|
+
cached_tokens: int | None = None
|
|
45
|
+
cache_write_tokens: int | None = None
|
|
46
|
+
cost_usd: float | None = None
|
|
47
|
+
unmapped: list[str] = Field(default_factory=list)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class MappingModel(BaseModel):
|
|
51
|
+
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class AttributeRule(MappingModel):
|
|
55
|
+
attribute: str = Field(description="The span attribute key to read.")
|
|
56
|
+
json_: bool = Field(
|
|
57
|
+
default=False,
|
|
58
|
+
alias="json",
|
|
59
|
+
description="Parse the value with json.loads when it is a string; keep the string "
|
|
60
|
+
"on failure.",
|
|
61
|
+
)
|
|
62
|
+
values: dict[str, str] | None = Field(
|
|
63
|
+
default=None, description="Translate the read value through this table."
|
|
64
|
+
)
|
|
65
|
+
message_format: MessageFormat | None = Field(
|
|
66
|
+
default=None,
|
|
67
|
+
description="Collect messages laid out per this format under the attribute key.",
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class TokenRules(MappingModel):
|
|
72
|
+
prompt: AttributeRule | None = None
|
|
73
|
+
completion: AttributeRule | None = None
|
|
74
|
+
cached: AttributeRule | None = None
|
|
75
|
+
cache_write: AttributeRule | None = None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class ToolRules(MappingModel):
|
|
79
|
+
name: AttributeRule | None = None
|
|
80
|
+
call_id: AttributeRule | None = None
|
|
81
|
+
arguments: AttributeRule | None = None
|
|
82
|
+
result: AttributeRule | None = None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class MappingDocument(MappingModel):
|
|
86
|
+
schema_version: Literal["1"]
|
|
87
|
+
kind: AttributeRule | None = None
|
|
88
|
+
session_id: AttributeRule | None = None
|
|
89
|
+
model: AttributeRule | None = None
|
|
90
|
+
system_instructions: AttributeRule | None = Field(
|
|
91
|
+
default=None,
|
|
92
|
+
description="System prompt kept outside the input messages: a string or a list of "
|
|
93
|
+
"text parts. Read on llm spans and put first in the input messages.",
|
|
94
|
+
)
|
|
95
|
+
input_messages: AttributeRule | None = None
|
|
96
|
+
output_messages: AttributeRule | None = None
|
|
97
|
+
tokens: TokenRules = Field(default_factory=TokenRules)
|
|
98
|
+
cost_usd: AttributeRule | None = None
|
|
99
|
+
tool: ToolRules = Field(default_factory=ToolRules)
|
|
100
|
+
agent_name: AttributeRule | None = Field(
|
|
101
|
+
default=None,
|
|
102
|
+
description="The agent's name on agent spans; names the subagent trajectory. The span "
|
|
103
|
+
"name is used when it is absent.",
|
|
104
|
+
)
|
|
105
|
+
input: AttributeRule | None = None
|
|
106
|
+
output: AttributeRule | None = None
|
|
107
|
+
known_attributes: list[str] = Field(
|
|
108
|
+
default_factory=list,
|
|
109
|
+
description="Attributes no rule reads that are expected and need nothing: not reported "
|
|
110
|
+
"as unmapped. Glob patterns such as llm.tools.* are allowed.",
|
|
111
|
+
)
|
|
112
|
+
answer: str = Field(
|
|
113
|
+
default="root",
|
|
114
|
+
description="Where the run's answer comes from: root, a span name, or "
|
|
115
|
+
"<span name>.<output key>.",
|
|
116
|
+
)
|
|
117
|
+
exclude_spans: list[str] = Field(
|
|
118
|
+
default_factory=list,
|
|
119
|
+
description="Span names left out of the trajectory.",
|
|
120
|
+
)
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
from jsonschema.exceptions import SchemaError
|
|
6
|
+
from jsonschema.validators import validator_for
|
|
7
|
+
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class HarnessModel(BaseModel):
|
|
11
|
+
model_config = ConfigDict(extra="allow")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
DEFAULT_INPUT_SCHEMA: dict = {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"required": ["question"],
|
|
17
|
+
"properties": {"question": {"type": "string"}},
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def input_errors(schema: dict, run_input: dict) -> list[str]:
|
|
22
|
+
validator_cls = validator_for(schema)
|
|
23
|
+
validator = validator_cls(schema)
|
|
24
|
+
errors = sorted(validator.iter_errors(run_input), key=lambda e: list(e.absolute_path))
|
|
25
|
+
return [
|
|
26
|
+
f"{'/'.join(str(part) for part in e.absolute_path) or '<root>'}: {e.message}"
|
|
27
|
+
for e in errors
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def answer_text(answer: str | None, output: dict | None) -> str:
|
|
32
|
+
if answer is not None:
|
|
33
|
+
return answer
|
|
34
|
+
return json.dumps(output, sort_keys=True, ensure_ascii=False)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Provides(HarnessModel):
|
|
38
|
+
trajectory: bool = Field(
|
|
39
|
+
default=False, description="Can serve GET runs/{id}/trajectory at all."
|
|
40
|
+
)
|
|
41
|
+
tool_calls: bool = Field(default=False, description="Trajectory reliably contains tool calls.")
|
|
42
|
+
thinking: bool = Field(
|
|
43
|
+
default=False, description="Trajectory reliably contains reasoning content."
|
|
44
|
+
)
|
|
45
|
+
token_usage: bool = Field(default=False, description="Trajectory carries per-step token usage.")
|
|
46
|
+
artifacts: bool = Field(
|
|
47
|
+
default=False, description="Run status reports artifacts the agent produced."
|
|
48
|
+
)
|
|
49
|
+
workspace: bool = Field(default=False, description="Files endpoints are implemented.")
|
|
50
|
+
run_listing: bool = Field(
|
|
51
|
+
default=False,
|
|
52
|
+
description="GET /runs (list) is implemented. Powers the sessions browser.",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class Accepts(HarnessModel):
|
|
57
|
+
files: bool = Field(default=False, description="POST /runs accepts multipart file attachments.")
|
|
58
|
+
file_urls: bool = Field(
|
|
59
|
+
default=False,
|
|
60
|
+
description="POST /runs (JSON body) accepts `files: [{name, url}]` and the harness "
|
|
61
|
+
"fetches each url itself. Preferred over multipart when both are declared. The url "
|
|
62
|
+
"is evalkit's blob store url plus the object key (e.g. s3://bucket/fixtures/<key>); "
|
|
63
|
+
"the harness must have access to it.",
|
|
64
|
+
)
|
|
65
|
+
model_override: bool = Field(default=False, description="POST /runs honours the 'model' field.")
|
|
66
|
+
stop: bool = Field(default=False, description="POST /runs/{id}/stop is implemented.")
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def file_input(self) -> bool:
|
|
70
|
+
return self.file_urls or self.files
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class Limits(HarnessModel):
|
|
74
|
+
max_concurrent_runs: int | None = Field(
|
|
75
|
+
default=None,
|
|
76
|
+
description="Harness-side cap. evalkit uses min(this, its own config).",
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class Capabilities(HarnessModel):
|
|
81
|
+
contract_version: str = Field(
|
|
82
|
+
default="v1", description="Harness API version this harness implements."
|
|
83
|
+
)
|
|
84
|
+
agent: str = Field(description="Harness's own name for itself. Informational.")
|
|
85
|
+
revision: str | None = Field(
|
|
86
|
+
default=None,
|
|
87
|
+
description="Optional. Git commit SHA of the deployed harness; evalkit "
|
|
88
|
+
"records it on the experiment so results are traceable to a build.",
|
|
89
|
+
)
|
|
90
|
+
branch: str | None = Field(
|
|
91
|
+
default=None, description="Optional. Git branch the deployed harness was built from."
|
|
92
|
+
)
|
|
93
|
+
input_schema: dict | None = Field(
|
|
94
|
+
default=None,
|
|
95
|
+
description="Optional. JSON Schema (draft 2020-12 unless `$schema` says otherwise) "
|
|
96
|
+
"of the run input this agent accepts. Excludes `files`, which evalkit sends "
|
|
97
|
+
"separately. When absent, evalkit assumes the default question-and-answer schema: "
|
|
98
|
+
"an object with a required string `question`. evalkit checks case inputs against "
|
|
99
|
+
"the declared or default schema before running an experiment and in "
|
|
100
|
+
"`evalkit lint --agent`.",
|
|
101
|
+
)
|
|
102
|
+
check_input: dict | None = Field(
|
|
103
|
+
default=None,
|
|
104
|
+
description="Optional. The run input `evalkit harness check` sends. Must pass "
|
|
105
|
+
"input_schema, or the default question-and-answer schema when none is declared.",
|
|
106
|
+
)
|
|
107
|
+
provides: Provides = Field(default_factory=Provides)
|
|
108
|
+
accepts: Accepts = Field(default_factory=Accepts)
|
|
109
|
+
limits: Limits = Field(default_factory=Limits)
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def effective_input_schema(self) -> dict:
|
|
113
|
+
return self.input_schema or DEFAULT_INPUT_SCHEMA
|
|
114
|
+
|
|
115
|
+
@model_validator(mode="after")
|
|
116
|
+
def _schema_and_check_input_agree(self) -> "Capabilities":
|
|
117
|
+
if self.input_schema is not None:
|
|
118
|
+
try:
|
|
119
|
+
validator_for(self.input_schema).check_schema(self.input_schema)
|
|
120
|
+
except SchemaError as exc:
|
|
121
|
+
raise ValueError(f"input_schema is not a valid JSON Schema: {exc.message}") from exc
|
|
122
|
+
if self.check_input is not None:
|
|
123
|
+
errors = input_errors(self.effective_input_schema, self.check_input)
|
|
124
|
+
if errors:
|
|
125
|
+
raise ValueError(f"check_input fails input_schema: {errors[0]}")
|
|
126
|
+
return self
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class RunMetadata(HarnessModel):
|
|
130
|
+
experiment_id: str | None = Field(
|
|
131
|
+
default=None,
|
|
132
|
+
description="Experiment id, so eval traffic is distinguishable and traceable.",
|
|
133
|
+
)
|
|
134
|
+
case_id: str | None = Field(default=None, description="Case id for the harness's records.")
|
|
135
|
+
repetition: int | None = Field(default=None, description="Repetition number, 1-based.")
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class FileRef(HarnessModel):
|
|
139
|
+
name: str = Field(description="File name to present to the agent — the fixture key.")
|
|
140
|
+
url: str | None = Field(
|
|
141
|
+
default=None,
|
|
142
|
+
description="Where the harness fetches the bytes from. Present on a JSON request "
|
|
143
|
+
"(accepts.file_urls); absent on multipart, where the bytes arrive as the part with "
|
|
144
|
+
"this name. Opaque to evalkit's experiment runner; the UI still serves the same "
|
|
145
|
+
"fixture via GET /api/fixtures/{name}.",
|
|
146
|
+
)
|
|
147
|
+
context: str | None = Field(
|
|
148
|
+
default=None,
|
|
149
|
+
description="What the file holds, from the suite's fixture registry. evalkit no "
|
|
150
|
+
"longer prepends it to input.question; show it to the agent however suits it.",
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class RunRequest(HarnessModel):
|
|
155
|
+
input: dict = Field(
|
|
156
|
+
description="The case input, verbatim; evalkit never rewrites it. Free-form "
|
|
157
|
+
"object (see capabilities.input_schema); the harness maps it "
|
|
158
|
+
"onto its own invocation."
|
|
159
|
+
)
|
|
160
|
+
model: str | None = Field(
|
|
161
|
+
default=None, description="Optional. Only sent if accepts.model_override."
|
|
162
|
+
)
|
|
163
|
+
metadata: RunMetadata | None = Field(
|
|
164
|
+
default=None,
|
|
165
|
+
description="Optional, for the harness's own records. The harness may ignore it.",
|
|
166
|
+
)
|
|
167
|
+
files: list[FileRef] | None = Field(
|
|
168
|
+
default=None,
|
|
169
|
+
description="Optional. The case's fixture files, each with its context. On a JSON "
|
|
170
|
+
"request (accepts.file_urls) each carries the url to fetch; on multipart it is in "
|
|
171
|
+
"the payload part without urls, next to one file part per entry.",
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class RunCreated(HarnessModel):
|
|
176
|
+
run_id: str = Field(
|
|
177
|
+
description="The harness's own identifier — typically its session id. "
|
|
178
|
+
"Key for every other endpoint."
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class ArtifactRef(HarnessModel):
|
|
183
|
+
name: str = Field(description="Artifact display name.")
|
|
184
|
+
path: str | None = Field(
|
|
185
|
+
default=None, description="Workspace path, fetchable via the files endpoint."
|
|
186
|
+
)
|
|
187
|
+
content_type: str | None = Field(default=None, description="MIME type, if known.")
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class RunStatus(HarnessModel):
|
|
191
|
+
status: Literal["queued", "running", "completed", "failed", "cancelled"] = Field(
|
|
192
|
+
description="Run state. evalkit polls until terminal or timeout."
|
|
193
|
+
)
|
|
194
|
+
answer: str | None = Field(
|
|
195
|
+
default=None,
|
|
196
|
+
description="Final user-visible answer. A completed run carries this, `output`, or both.",
|
|
197
|
+
)
|
|
198
|
+
output: dict | None = Field(
|
|
199
|
+
default=None,
|
|
200
|
+
description="Optional. The agent's structured result, for agents that return "
|
|
201
|
+
"typed data. A completed run carries this, `answer`, or both.",
|
|
202
|
+
)
|
|
203
|
+
model: str = Field(
|
|
204
|
+
description="Required. The model this run executes on — the requested "
|
|
205
|
+
"model when honoured, otherwise the harness's own default. evalkit "
|
|
206
|
+
"records it as the experiment's model and prefers it over the request.",
|
|
207
|
+
)
|
|
208
|
+
artifacts: list[ArtifactRef] | None = Field(
|
|
209
|
+
default=None, description="Optional. Files the agent produced as deliverables."
|
|
210
|
+
)
|
|
211
|
+
error: str | None = Field(
|
|
212
|
+
default=None,
|
|
213
|
+
description="Message when status=failed. A completed run may also carry a "
|
|
214
|
+
"non-fatal error (e.g. partial answer).",
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
@model_validator(mode="after")
|
|
218
|
+
def _completed_carries_answer_or_output(self) -> "RunStatus":
|
|
219
|
+
if self.status == "completed" and self.answer is None and self.output is None:
|
|
220
|
+
raise ValueError("a completed run must carry an answer or an output")
|
|
221
|
+
return self
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class RunListParams(BaseModel):
|
|
225
|
+
query: str | None = Field(
|
|
226
|
+
default=None,
|
|
227
|
+
description="Free-text filter over runs. Text that looks like an id (8 or more "
|
|
228
|
+
"hex characters; dashes and case ignored) matches runs whose id starts with it. "
|
|
229
|
+
"Any other text matches runs whose title contains it, case-insensitive.",
|
|
230
|
+
)
|
|
231
|
+
user_id: str | None = Field(default=None, description="Filter to one user's runs.")
|
|
232
|
+
client_id: str | None = Field(default=None, description="Filter to one client's runs.")
|
|
233
|
+
limit: int = Field(default=50, description="Page size.")
|
|
234
|
+
offset: int = Field(default=0, description="Page start.")
|
|
235
|
+
since: datetime | None = Field(
|
|
236
|
+
default=None, description="Only runs created at or after this time (ISO 8601)."
|
|
237
|
+
)
|
|
238
|
+
until: datetime | None = Field(
|
|
239
|
+
default=None, description="Only runs created before this time (ISO 8601)."
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
def as_query(self) -> dict[str, str | int]:
|
|
243
|
+
return {
|
|
244
|
+
k: v.isoformat().replace("+00:00", "Z") if isinstance(v, datetime) else v
|
|
245
|
+
for k, v in self.model_dump().items()
|
|
246
|
+
if v is not None
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class RunListItem(HarnessModel):
|
|
251
|
+
run_id: str = Field(description="Usable with the other /runs/{id} endpoints.")
|
|
252
|
+
title: str | None = Field(default=None, description="Display title for the run/session.")
|
|
253
|
+
user_id: str | None = Field(
|
|
254
|
+
default=None, description="Optional filter value; fixed dummy if no multi-tenancy."
|
|
255
|
+
)
|
|
256
|
+
client_id: str | None = Field(
|
|
257
|
+
default=None, description="Optional filter value; fixed dummy if no multi-tenancy."
|
|
258
|
+
)
|
|
259
|
+
created_at: datetime | None = Field(default=None, description="Run creation time.")
|
|
260
|
+
session_id: str | None = Field(
|
|
261
|
+
default=None,
|
|
262
|
+
description="The session this run belongs to, for a harness that keeps several of its "
|
|
263
|
+
"own runs per session (for example one per chat message) and answers each of them with "
|
|
264
|
+
"the whole session. evalkit's run is the session: items sharing a session_id are listed "
|
|
265
|
+
"once, as the newest of them.",
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class RunList(HarnessModel):
|
|
270
|
+
runs: list[RunListItem] = Field(description="Page of runs, newest first.")
|
|
271
|
+
total: int = Field(description="Total runs matching the query.")
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
class FileEntry(HarnessModel):
|
|
275
|
+
path: str = Field(description="Workspace-relative path.")
|
|
276
|
+
size: int = Field(description="Size in bytes.")
|
|
277
|
+
content_type: str | None = Field(default=None, description="MIME type, if known.")
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class FileList(HarnessModel):
|
|
281
|
+
files: list[FileEntry] = Field(description="Workspace listing.")
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
{
|
|
2
|
+
"endpoint_note": "Check this URL before saving. The server at this address receives the API key you enter here and the data evalkit sends it: cases, answers and trajectories.",
|
|
3
|
+
"personal_key_note": "Personal agents and evaluators read their API key from your evalkit.yaml (credentials:), never from the server."
|
|
4
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class JudgeSettings(BaseModel):
|
|
5
|
+
"""The LLM judge an experiment uses; exported from `evalkit.sdk` as `Judge`.
|
|
6
|
+
|
|
7
|
+
Its API key comes from `credentials.judges` in `evalkit.yaml`, keyed by `base_url`.
|
|
8
|
+
|
|
9
|
+
Attributes:
|
|
10
|
+
base_url: An OpenAI-compatible endpoint that supports structured output.
|
|
11
|
+
model: The model name at that endpoint.
|
|
12
|
+
reasoning_effort: Passed to the model as `reasoning_effort`.
|
|
13
|
+
max_tokens: The most tokens one judge reply may use.
|
|
14
|
+
concurrency: How many judge calls run at once.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
model_config = ConfigDict(extra="forbid")
|
|
18
|
+
|
|
19
|
+
base_url: str
|
|
20
|
+
model: str
|
|
21
|
+
reasoning_effort: str = "high"
|
|
22
|
+
max_tokens: int = Field(32768, ge=1)
|
|
23
|
+
concurrency: int = Field(16, ge=1)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class AgentSettings(BaseModel):
|
|
27
|
+
model_config = ConfigDict(extra="forbid")
|
|
28
|
+
|
|
29
|
+
max_concurrent_runs: int = Field(default=4, ge=1)
|
|
30
|
+
trajectory_wait_seconds: int = Field(default=60, ge=0)
|
|
31
|
+
run_timeout_seconds: int = Field(default=840, ge=0)
|
|
32
|
+
poll_interval_seconds: int = Field(default=5, ge=0)
|
|
33
|
+
stop_grace_seconds: int = Field(default=120, ge=0)
|
|
34
|
+
provides: dict[str, bool] | None = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class RemoteEvaluatorSettings(BaseModel):
|
|
38
|
+
model_config = ConfigDict(extra="forbid")
|
|
39
|
+
|
|
40
|
+
endpoint: str
|
|
41
|
+
timeout_seconds: int = Field(default=120, ge=1)
|
evalkit/core/__init__.py
ADDED
|
File without changes
|
evalkit/core/access.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
from evalkit.contracts.enums import WorkspaceRole
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class WorkspaceRef:
|
|
9
|
+
id: int
|
|
10
|
+
name: str
|
|
11
|
+
owner_user_id: int | None
|
|
12
|
+
archived: bool
|
|
13
|
+
promotes_to: int | None = None
|
|
14
|
+
promoted_from: int | None = None
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def is_shared(self) -> bool:
|
|
18
|
+
return self.owner_user_id is None
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def is_target(self) -> bool:
|
|
22
|
+
return self.promoted_from is not None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass(frozen=True)
|
|
26
|
+
class Actor:
|
|
27
|
+
id: int
|
|
28
|
+
username: str
|
|
29
|
+
is_admin: bool
|
|
30
|
+
roles: Mapping[int, frozenset[WorkspaceRole]]
|
|
31
|
+
|
|
32
|
+
def has(self, ws: WorkspaceRef, role: WorkspaceRole) -> bool:
|
|
33
|
+
return role in self.roles.get(ws.id, frozenset())
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def can_read(actor: Actor, ws: WorkspaceRef) -> bool:
|
|
37
|
+
return True
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def can_write(actor: Actor, ws: WorkspaceRef) -> bool:
|
|
41
|
+
if not ws.is_shared:
|
|
42
|
+
return ws.owner_user_id == actor.id
|
|
43
|
+
return actor.is_admin or actor.has(ws, WorkspaceRole.WRITER)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def can_review(actor: Actor, ws: WorkspaceRef) -> bool:
|
|
47
|
+
return ws.is_shared and actor.has(ws, WorkspaceRole.REVIEWER)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def can_use_agent(actor: Actor, agent_ws: WorkspaceRef) -> bool:
|
|
51
|
+
if not agent_ws.is_shared:
|
|
52
|
+
return agent_ws.owner_user_id == actor.id
|
|
53
|
+
return True
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def can_change_experiment(actor: Actor, exp_ws: WorkspaceRef, created_by: int | None) -> bool:
|
|
57
|
+
return can_write(actor, exp_ws) or created_by == actor.id
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def can_create_experiment(actor: Actor, exp_ws: WorkspaceRef) -> bool:
|
|
61
|
+
if not exp_ws.is_shared:
|
|
62
|
+
return exp_ws.owner_user_id == actor.id
|
|
63
|
+
return (
|
|
64
|
+
actor.is_admin
|
|
65
|
+
or actor.has(exp_ws, WorkspaceRole.WRITER)
|
|
66
|
+
or actor.has(exp_ws, WorkspaceRole.REVIEWER)
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def experiment_workspace(
|
|
71
|
+
runner_personal: WorkspaceRef, dataset_ws: WorkspaceRef, agent_ws: WorkspaceRef
|
|
72
|
+
) -> WorkspaceRef:
|
|
73
|
+
if dataset_ws.is_shared and agent_ws.is_shared:
|
|
74
|
+
return dataset_ws
|
|
75
|
+
return runner_personal
|
evalkit/core/agents.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
from typing import Protocol
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
from evalkit.contracts.enums import TrajectorySource
|
|
7
|
+
from evalkit.contracts.settings import AgentSettings
|
|
8
|
+
from evalkit.core.workspace import Reference
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AgentDefinition(BaseModel):
|
|
12
|
+
id: int
|
|
13
|
+
name: str
|
|
14
|
+
workspace: str
|
|
15
|
+
workspace_is_shared: bool
|
|
16
|
+
harness_url: str | None
|
|
17
|
+
trajectory_source: TrajectorySource
|
|
18
|
+
repo_url: str | None
|
|
19
|
+
settings: AgentSettings
|
|
20
|
+
archived: bool = False
|
|
21
|
+
has_api_key: bool = False
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def ref(self) -> str:
|
|
25
|
+
return f"{self.name}@{self.workspace}"
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def reference(self) -> Reference:
|
|
29
|
+
return Reference(self.name, self.workspace)
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def is_otel(self) -> bool:
|
|
33
|
+
return self.trajectory_source is TrajectorySource.OTEL
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Driver(StrEnum):
|
|
37
|
+
SERVER = "server"
|
|
38
|
+
CLI = "cli"
|
|
39
|
+
SDK = "sdk"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def driver(agent: AgentDefinition) -> Driver:
|
|
43
|
+
if agent.harness_url is None:
|
|
44
|
+
return Driver.SDK
|
|
45
|
+
if agent.workspace_is_shared:
|
|
46
|
+
return Driver.SERVER
|
|
47
|
+
return Driver.CLI
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def server_may_drive(agent: AgentDefinition) -> bool:
|
|
51
|
+
return driver(agent) is Driver.SERVER
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class UnknownAgent(KeyError):
|
|
55
|
+
def __init__(self, ref: str):
|
|
56
|
+
super().__init__(f"unknown agent: {ref} — create it with evalkit agents create")
|
|
57
|
+
self.ref = ref
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class AgentLookup(Protocol):
|
|
61
|
+
async def get(self, ref: str) -> AgentDefinition: ...
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def explicit(ref: Reference) -> str:
|
|
65
|
+
return f"{ref.name}@{ref.workspace}"
|
evalkit/core/blob.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import AsyncIterator
|
|
4
|
+
from typing import Protocol
|
|
5
|
+
|
|
6
|
+
from evalkit.core.paths import require_safe_path, require_safe_run_id
|
|
7
|
+
from evalkit.store.base import BlobStream
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class BlobStore(Protocol):
|
|
11
|
+
async def put_object(self, key: str, data: bytes) -> None: ...
|
|
12
|
+
|
|
13
|
+
async def put_stream(self, key: str, chunks: AsyncIterator[bytes]) -> None: ...
|
|
14
|
+
|
|
15
|
+
async def get_object(self, key: str) -> bytes: ...
|
|
16
|
+
|
|
17
|
+
async def get_stream(self, key: str) -> BlobStream: ...
|
|
18
|
+
|
|
19
|
+
async def object_exists(self, key: str) -> bool: ...
|
|
20
|
+
|
|
21
|
+
async def list_objects(self, prefix: str) -> list[tuple[str, int]]: ...
|
|
22
|
+
|
|
23
|
+
async def delete_object(self, key: str) -> None: ...
|
|
24
|
+
|
|
25
|
+
async def copy_object(self, source: str, destination: str) -> None: ...
|
|
26
|
+
|
|
27
|
+
async def object_url(self, key: str) -> str: ...
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def trajectory_key(agent_id: int, harness_run_id: str) -> str:
|
|
31
|
+
return f"trajectories/{agent_id}/{harness_run_id}.json"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def artifact_key(agent_id: int, harness_run_id: str, path: str) -> str:
|
|
35
|
+
require_safe_run_id(harness_run_id)
|
|
36
|
+
if path:
|
|
37
|
+
path = require_safe_path(path)
|
|
38
|
+
return f"artifacts/{agent_id}/{harness_run_id}/{path}"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def workspace_key(agent_id: int, harness_run_id: str) -> str:
|
|
42
|
+
return f"workspaces/{agent_id}/{harness_run_id}.json"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def fixture_blob_key(sha256: str) -> str:
|
|
46
|
+
return f"fixtures/sha256/{sha256}"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from evalkit.contracts.harness import Accepts, Capabilities, Limits, Provides
|
|
2
|
+
from evalkit.core.agents import AgentDefinition
|
|
3
|
+
|
|
4
|
+
SDK_CONTRACT_VERSION = "sdk"
|
|
5
|
+
TRACED_FLAGS = ("trajectory", "tool_calls", "token_usage")
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def sdk_capabilities(agent: AgentDefinition) -> Capabilities:
|
|
9
|
+
provides = {
|
|
10
|
+
"trajectory": True,
|
|
11
|
+
"tool_calls": True,
|
|
12
|
+
"token_usage": True,
|
|
13
|
+
"thinking": False,
|
|
14
|
+
"artifacts": False,
|
|
15
|
+
"workspace": False,
|
|
16
|
+
"run_listing": True,
|
|
17
|
+
**(agent.settings.provides or {}),
|
|
18
|
+
}
|
|
19
|
+
return Capabilities(
|
|
20
|
+
contract_version=SDK_CONTRACT_VERSION,
|
|
21
|
+
agent=agent.name,
|
|
22
|
+
provides=Provides(**provides),
|
|
23
|
+
accepts=Accepts(files=True, model_override=True, file_urls=False, stop=False),
|
|
24
|
+
limits=Limits(max_concurrent_runs=agent.settings.max_concurrent_runs),
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def traced_capabilities(caps: Capabilities, agent: AgentDefinition) -> Capabilities:
|
|
29
|
+
if not agent.is_otel:
|
|
30
|
+
return caps
|
|
31
|
+
provides = {
|
|
32
|
+
**caps.provides.model_dump(),
|
|
33
|
+
**dict.fromkeys(TRACED_FLAGS, True),
|
|
34
|
+
**(agent.settings.provides or {}),
|
|
35
|
+
}
|
|
36
|
+
return caps.model_copy(update={"provides": Provides(**provides)})
|