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
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
|
|
6
|
+
INSTALL_MANIFEST = ".evalkit-installed"
|
|
7
|
+
TARGETS_PATH = Path.home() / ".evalkit" / "skills-targets"
|
|
8
|
+
DEFAULT_TARGETS = (Path(".claude/skills"), Path(".agents/skills"))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _read(path: Path) -> list[Path]:
|
|
12
|
+
return [Path(line) for line in path.read_text().split("\n") if line] if path.is_file() else []
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _write(path: Path, targets: list[Path]) -> None:
|
|
16
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
17
|
+
path.write_text("".join(f"{target}\n" for target in targets))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def record(target: Path, path: Path | None = None) -> None:
|
|
21
|
+
registry = path or TARGETS_PATH
|
|
22
|
+
resolved = target.resolve()
|
|
23
|
+
targets = _read(registry)
|
|
24
|
+
if resolved not in targets:
|
|
25
|
+
_write(registry, [*targets, resolved])
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def refresh(
|
|
29
|
+
cwd: Path, cli: Path, run: Callable[[list[str]], object], path: Path | None = None
|
|
30
|
+
) -> None:
|
|
31
|
+
registry = path or TARGETS_PATH
|
|
32
|
+
targets = _read(registry)
|
|
33
|
+
for candidate in DEFAULT_TARGETS:
|
|
34
|
+
found = (cwd / candidate).resolve()
|
|
35
|
+
if (found / INSTALL_MANIFEST).is_file() and found not in targets:
|
|
36
|
+
targets.append(found)
|
|
37
|
+
kept = []
|
|
38
|
+
for target in targets:
|
|
39
|
+
if (target / INSTALL_MANIFEST).is_file():
|
|
40
|
+
run([str(cli), "skills", "install", "--target", str(target)])
|
|
41
|
+
typer.echo(f"refreshed skills in {target}; commit them if the repo tracks them")
|
|
42
|
+
kept.append(target)
|
|
43
|
+
_write(registry, kept)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from evalkit.cli.client import ApiClient
|
|
6
|
+
|
|
7
|
+
tokens_app = typer.Typer(
|
|
8
|
+
no_args_is_help=True, help="Agent tokens for exporting traces from deployed agents."
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def register(app: typer.Typer, client_factory: Callable[[], ApiClient]) -> None:
|
|
13
|
+
app.add_typer(tokens_app, name="tokens")
|
|
14
|
+
|
|
15
|
+
@tokens_app.command("create")
|
|
16
|
+
def tokens_create(
|
|
17
|
+
agent: str = typer.Option(
|
|
18
|
+
..., "--agent", help="myagent (yours) or ouragent@dev (needs write access there)."
|
|
19
|
+
),
|
|
20
|
+
):
|
|
21
|
+
"""Mint an agent token, scoped to the collector, and print it once.
|
|
22
|
+
|
|
23
|
+
The token never expires and is bound to one agent record on the server:
|
|
24
|
+
it can only export spans for that agent.
|
|
25
|
+
|
|
26
|
+
The agent must exist first (evalkit agents create). You need write
|
|
27
|
+
access to its workspace: your own, or a shared one where you are a
|
|
28
|
+
writer. Non-admins list and revoke only their own tokens.
|
|
29
|
+
|
|
30
|
+
Agents cannot be renamed. To replace one, archive it, create the new
|
|
31
|
+
one, mint a token for it and revoke the old token.
|
|
32
|
+
|
|
33
|
+
Example: evalkit tokens create --agent ouragent@dev
|
|
34
|
+
"""
|
|
35
|
+
body = client_factory().post("/api/tokens", json={"agent": agent}).json()
|
|
36
|
+
typer.echo(f"token {body['id']} for {body['agent']} (shown once):")
|
|
37
|
+
typer.echo(body["token"])
|
|
38
|
+
|
|
39
|
+
@tokens_app.command("list")
|
|
40
|
+
def tokens_list():
|
|
41
|
+
"""List the agent tokens you may see. Example: evalkit tokens list"""
|
|
42
|
+
for row in client_factory().get("/api/tokens").json():
|
|
43
|
+
typer.echo(
|
|
44
|
+
f"{row['id']:<6} {row['agent']:<32} by {row['created_by']:<16} "
|
|
45
|
+
f"last used {row['last_used_at'] or 'never'}"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
@tokens_app.command("revoke")
|
|
49
|
+
def tokens_revoke(token_id: int):
|
|
50
|
+
"""Revoke an agent token. Example: evalkit tokens revoke 12"""
|
|
51
|
+
client_factory().delete(f"/api/tokens/{token_id}")
|
|
52
|
+
typer.echo(f"revoked {token_id}")
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import time
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from datetime import UTC, datetime
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
from evalkit.cli.client import ApiClient, ApiError
|
|
12
|
+
from evalkit.client.api import encode
|
|
13
|
+
|
|
14
|
+
traces_app = typer.Typer(
|
|
15
|
+
no_args_is_help=True, help="Check, map and import OpenTelemetry sessions for an agent."
|
|
16
|
+
)
|
|
17
|
+
mapping_app = typer.Typer(no_args_is_help=True, help="Manage an agent's span mapping.")
|
|
18
|
+
traces_app.add_typer(mapping_app, name="mapping")
|
|
19
|
+
|
|
20
|
+
MARK = {"pass": "✓", "warn": "!", "fail": "✗"}
|
|
21
|
+
DUMPS = ("spans.json", "esf.json", "trajectory.json")
|
|
22
|
+
FOLLOW_SECONDS = 2
|
|
23
|
+
ACTIVE_IMPORT = ("running", "stopping")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _line(status: str, label: str, detail: str) -> str:
|
|
27
|
+
return f" {MARK[status]} {label:<14} {detail}"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _trajectories(trajectory: dict) -> list[dict]:
|
|
31
|
+
out = [trajectory] if trajectory else []
|
|
32
|
+
for sub in trajectory.get("subagent_trajectories") or []:
|
|
33
|
+
out.extend(_trajectories(sub))
|
|
34
|
+
return out
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def render_check(session: dict) -> tuple[list[str], bool]:
|
|
38
|
+
esf = session.get("esf") or []
|
|
39
|
+
traces = {s["trace_id"] for s in esf}
|
|
40
|
+
plural = "s" if len(traces) != 1 else ""
|
|
41
|
+
settled = "settled" if session["settled"] else "not settled yet"
|
|
42
|
+
lines = [
|
|
43
|
+
_line(
|
|
44
|
+
"pass" if session["settled"] else "warn",
|
|
45
|
+
"session",
|
|
46
|
+
f"{session['span_count']} spans in {len(traces)} trace{plural}, {settled}",
|
|
47
|
+
)
|
|
48
|
+
]
|
|
49
|
+
root = next((s for s in esf if s["parent_id"] is None), None)
|
|
50
|
+
if root is None:
|
|
51
|
+
lines.append(_line("fail", "root", "no root span (parent_span_id null) in this session"))
|
|
52
|
+
else:
|
|
53
|
+
ended = "ended" if root["ended_at"] else "not ended"
|
|
54
|
+
lines.append(_line("pass", "root", f'"{root["name"]}" ({root["kind"]}), {ended}'))
|
|
55
|
+
version = session.get("mapping_version")
|
|
56
|
+
lines.append(
|
|
57
|
+
_line("pass", "mapping", f"v{version}")
|
|
58
|
+
if version
|
|
59
|
+
else _line("warn", "mapping", "no active mapping; the agent's spans are unmapped")
|
|
60
|
+
)
|
|
61
|
+
llms = [s for s in esf if s["kind"] == "llm"]
|
|
62
|
+
if llms:
|
|
63
|
+
models = sorted({s["model"] for s in llms if s.get("model")})
|
|
64
|
+
bare = sum(1 for s in llms if not s.get("input_messages") and not s.get("output_messages"))
|
|
65
|
+
keys = ("prompt_tokens", "completion_tokens", "cached_tokens")
|
|
66
|
+
totals = {k: sum(s.get(k) or 0 for s in llms) for k in keys}
|
|
67
|
+
detail = (
|
|
68
|
+
f"{len(llms)} spans, model {', '.join(models) or 'unknown'}, tokens "
|
|
69
|
+
f"in={totals['prompt_tokens']} out={totals['completion_tokens']} "
|
|
70
|
+
f"cached={totals['cached_tokens']}"
|
|
71
|
+
)
|
|
72
|
+
if bare:
|
|
73
|
+
detail += f", {bare} without messages (is message content capture on?)"
|
|
74
|
+
no_tokens = not totals["prompt_tokens"] and not totals["completion_tokens"]
|
|
75
|
+
if no_tokens:
|
|
76
|
+
detail += ", no token counts (check the tokens rule)"
|
|
77
|
+
lines.append(_line("warn" if bare or no_tokens else "pass", "llm", detail))
|
|
78
|
+
else:
|
|
79
|
+
lines.append(_line("warn", "llm", "no llm spans; check the kind rule"))
|
|
80
|
+
tools = [s for s in esf if s["kind"] == "tool"]
|
|
81
|
+
trajectory = session.get("trajectory") or {}
|
|
82
|
+
calls = [c for step in trajectory.get("steps") or [] for c in step.get("tool_calls") or []]
|
|
83
|
+
every = _trajectories(trajectory)
|
|
84
|
+
call_ids = {
|
|
85
|
+
c["tool_call_id"]
|
|
86
|
+
for t in every
|
|
87
|
+
for s in t.get("steps") or []
|
|
88
|
+
for c in s.get("tool_calls") or []
|
|
89
|
+
}
|
|
90
|
+
matched = len({s.get("tool_call_id") for s in tools if s.get("tool_call_id")} & call_ids)
|
|
91
|
+
unplaced = [n for t in every for n in (t.get("extra") or {}).get("unplaced_tool_spans") or []]
|
|
92
|
+
detail = f"{len(tools)} spans, {matched} matched to calls by id"
|
|
93
|
+
if unplaced:
|
|
94
|
+
detail += f", {len(unplaced)} in no step ({', '.join(unplaced[:2])})"
|
|
95
|
+
lines.append(_line("pass" if tools and not unplaced else "warn", "tools", detail))
|
|
96
|
+
unmapped = session.get("unmapped_attributes") or []
|
|
97
|
+
if unmapped:
|
|
98
|
+
more = f" (+{len(unmapped) - 2})" if len(unmapped) > 2 else ""
|
|
99
|
+
lines.append(_line("warn", "unmapped", ", ".join(unmapped[:2]) + more))
|
|
100
|
+
else:
|
|
101
|
+
lines.append(_line("pass", "unmapped", "every attribute was read"))
|
|
102
|
+
if trajectory:
|
|
103
|
+
subs = len(trajectory.get("subagent_trajectories") or [])
|
|
104
|
+
lines.append(
|
|
105
|
+
_line(
|
|
106
|
+
"pass",
|
|
107
|
+
"trajectory",
|
|
108
|
+
f"{trajectory.get('schema_version')}, {len(trajectory.get('steps') or [])} "
|
|
109
|
+
f"steps, {len(calls)} tool calls, {subs} subagents",
|
|
110
|
+
)
|
|
111
|
+
)
|
|
112
|
+
else:
|
|
113
|
+
lines.append(_line("fail", "trajectory", "no trajectory"))
|
|
114
|
+
return lines, root is not None
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def utc(value: str) -> datetime:
|
|
118
|
+
parsed = datetime.fromisoformat(value)
|
|
119
|
+
return parsed if parsed.tzinfo else parsed.replace(tzinfo=UTC)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def import_line(view: dict) -> str:
|
|
123
|
+
since, until = utc(view["since"]), utc(view["until"])
|
|
124
|
+
reached = utc(view["resume_from"])
|
|
125
|
+
done = 1.0 if view["status"] == "done" else (reached - since) / (until - since)
|
|
126
|
+
return (
|
|
127
|
+
f"{view['id']:<4} {view['status']:<8} {reached:%Y-%m-%d %H:%M} {round(100 * done):>3}% "
|
|
128
|
+
f"{view['traces']} traces {view['spans']} spans"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def register(
|
|
133
|
+
app: typer.Typer, client_factory: Callable[[], ApiClient], agent_slug: Callable[[str], str]
|
|
134
|
+
) -> None:
|
|
135
|
+
app.add_typer(traces_app, name="traces")
|
|
136
|
+
|
|
137
|
+
@traces_app.command("check")
|
|
138
|
+
def traces_check(
|
|
139
|
+
agent: str = typer.Argument(..., help="myagent (yours) or ouragent@dev."),
|
|
140
|
+
session_id: str = typer.Argument(
|
|
141
|
+
..., help="The session id (an SDK run id or a harness run id)."
|
|
142
|
+
),
|
|
143
|
+
dump: Path = typer.Option(
|
|
144
|
+
None,
|
|
145
|
+
"--dump",
|
|
146
|
+
help="Write the raw spans, ESF or trajectory to this path; the file name picks "
|
|
147
|
+
"which (ends in spans.json, esf.json or trajectory.json, e.g. /tmp/run7-spans.json). "
|
|
148
|
+
"esf.json omits the input messages of LLM calls after each agent's first; the raw "
|
|
149
|
+
"values are in spans.json.",
|
|
150
|
+
),
|
|
151
|
+
mapping: str = typer.Option("active", "--mapping", help="active or draft."),
|
|
152
|
+
):
|
|
153
|
+
"""Print a session's settle state, span kinds, tokens, unmapped attributes and ATIF summary.
|
|
154
|
+
|
|
155
|
+
Exit 1 when the session has no root span. Example: evalkit traces check research-agent 7f3c…
|
|
156
|
+
"""
|
|
157
|
+
client = client_factory()
|
|
158
|
+
slug = agent_slug(agent)
|
|
159
|
+
base = f"/api/agents/{encode(slug)}/sessions/{encode(session_id)}"
|
|
160
|
+
params = {"mapping": mapping, "esf": "true"}
|
|
161
|
+
session = client.get(f"{base}/trajectory", params=params).json()
|
|
162
|
+
if dump is not None:
|
|
163
|
+
if dump.name.endswith("spans.json"):
|
|
164
|
+
payload = client.get(f"{base}/spans").json()
|
|
165
|
+
elif dump.name.endswith("esf.json"):
|
|
166
|
+
payload = session.get("esf")
|
|
167
|
+
elif dump.name.endswith("trajectory.json"):
|
|
168
|
+
payload = session.get("trajectory")
|
|
169
|
+
else:
|
|
170
|
+
raise ApiError(f"--dump file name must end in one of {', '.join(DUMPS)}")
|
|
171
|
+
dump.parent.mkdir(parents=True, exist_ok=True)
|
|
172
|
+
dump.write_text(json.dumps(payload, indent=2))
|
|
173
|
+
typer.echo(f"wrote {dump}")
|
|
174
|
+
lines, ok = render_check(session)
|
|
175
|
+
for line in lines:
|
|
176
|
+
typer.echo(line)
|
|
177
|
+
if not ok:
|
|
178
|
+
raise typer.Exit(code=1)
|
|
179
|
+
|
|
180
|
+
def print_session_check(client: ApiClient, slug: str, session_id: str) -> None:
|
|
181
|
+
settle = int(client.get("/api/meta").json().get("settle_seconds") or 0)
|
|
182
|
+
time.sleep(settle)
|
|
183
|
+
path = f"/api/agents/{encode(slug)}/sessions/{encode(session_id)}/trajectory"
|
|
184
|
+
session = client.get(path, params={"esf": "true"}).json()
|
|
185
|
+
for line in render_check(session)[0]:
|
|
186
|
+
typer.echo(line)
|
|
187
|
+
|
|
188
|
+
def follow(client: ApiClient, agent: str, slug: str, import_id: int) -> None:
|
|
189
|
+
last = None
|
|
190
|
+
while True:
|
|
191
|
+
view = client.get(f"/api/agents/{encode(slug)}/imports/{import_id}").json()
|
|
192
|
+
line = import_line(view)
|
|
193
|
+
if line != last:
|
|
194
|
+
typer.echo(line)
|
|
195
|
+
last = line
|
|
196
|
+
if view["status"] == "done":
|
|
197
|
+
if view["sample_session"]:
|
|
198
|
+
typer.echo(f"check of session {view['sample_session']}:")
|
|
199
|
+
print_session_check(client, slug, view["sample_session"])
|
|
200
|
+
else:
|
|
201
|
+
typer.echo("no sessions were imported")
|
|
202
|
+
return
|
|
203
|
+
if view["status"] not in ACTIVE_IMPORT:
|
|
204
|
+
typer.echo(f"{view['status']}: {view['error'] or 'stopped by a user'}")
|
|
205
|
+
typer.echo(f"to continue: evalkit traces imports {agent} {import_id} --continue")
|
|
206
|
+
raise typer.Exit(code=1)
|
|
207
|
+
time.sleep(FOLLOW_SECONDS)
|
|
208
|
+
|
|
209
|
+
@traces_app.command("import")
|
|
210
|
+
def traces_import(
|
|
211
|
+
agent: str,
|
|
212
|
+
session_id: str | None = typer.Argument(
|
|
213
|
+
None, help="One session to import. Leave out and pass --since for a time range."
|
|
214
|
+
),
|
|
215
|
+
source: str = typer.Option(
|
|
216
|
+
..., "--source", help="A trace source name (evalkit trace-sources list)."
|
|
217
|
+
),
|
|
218
|
+
project: str = typer.Option(..., "--project", help="The project name in the trace source."),
|
|
219
|
+
since: str | None = typer.Option(
|
|
220
|
+
None,
|
|
221
|
+
"--since",
|
|
222
|
+
help="Import every trace that started at or after this time (ISO 8601; UTC unless "
|
|
223
|
+
"it carries an offset), as a server job.",
|
|
224
|
+
),
|
|
225
|
+
until: str | None = typer.Option(
|
|
226
|
+
None, "--until", help="End of the range, exclusive (ISO 8601). Default: now."
|
|
227
|
+
),
|
|
228
|
+
):
|
|
229
|
+
"""Import one session, or every trace in a time range, from a trace source.
|
|
230
|
+
|
|
231
|
+
A session import prints its check summary. A range import runs on the server; the CLI
|
|
232
|
+
follows its progress and Ctrl-C only stops following.
|
|
233
|
+
|
|
234
|
+
Examples: evalkit traces import research-agent abc --source phoenix --project ra;
|
|
235
|
+
evalkit traces import research-agent --source phoenix --project ra --since 2026-10-01
|
|
236
|
+
"""
|
|
237
|
+
if (session_id is None) == (since is None):
|
|
238
|
+
raise typer.BadParameter("give either SESSION_ID or --since, not both")
|
|
239
|
+
if until is not None and since is None:
|
|
240
|
+
raise typer.BadParameter("--until needs --since")
|
|
241
|
+
client = client_factory()
|
|
242
|
+
slug = agent_slug(agent)
|
|
243
|
+
if session_id is not None:
|
|
244
|
+
body = client.post(
|
|
245
|
+
f"/api/agents/{encode(slug)}/sessions/import",
|
|
246
|
+
json={"source": source, "project": project, "session_id": session_id},
|
|
247
|
+
).json()
|
|
248
|
+
typer.echo(f"imported {body['imported']} spans")
|
|
249
|
+
print_session_check(client, slug, session_id)
|
|
250
|
+
return
|
|
251
|
+
assert since is not None
|
|
252
|
+
window = {
|
|
253
|
+
"since": utc(since).isoformat(),
|
|
254
|
+
"until": (utc(until) if until else datetime.now(UTC)).isoformat(),
|
|
255
|
+
}
|
|
256
|
+
view = client.post(
|
|
257
|
+
f"/api/agents/{encode(slug)}/imports",
|
|
258
|
+
json={"source": source, "project": project, **window},
|
|
259
|
+
).json()
|
|
260
|
+
typer.echo(f"import {view['id']} started: {view['since']} → {view['until']}")
|
|
261
|
+
follow(client, agent, slug, view["id"])
|
|
262
|
+
|
|
263
|
+
@traces_app.command("imports")
|
|
264
|
+
def traces_imports(
|
|
265
|
+
agent: str,
|
|
266
|
+
import_id: int | None = typer.Argument(None, help="One import to show or follow."),
|
|
267
|
+
stop: bool = typer.Option(False, "--stop", help="Stop a running import."),
|
|
268
|
+
resume: bool = typer.Option(
|
|
269
|
+
False, "--continue", help="Continue a failed or stopped import from where it got to."
|
|
270
|
+
),
|
|
271
|
+
):
|
|
272
|
+
"""List an agent's range imports, or show, follow, stop or continue one.
|
|
273
|
+
|
|
274
|
+
Examples: evalkit traces imports research-agent;
|
|
275
|
+
evalkit traces imports research-agent 12 --continue
|
|
276
|
+
"""
|
|
277
|
+
if stop and resume:
|
|
278
|
+
raise typer.BadParameter("give --stop or --continue, not both")
|
|
279
|
+
if import_id is None and (stop or resume):
|
|
280
|
+
raise typer.BadParameter("--stop and --continue need an import id")
|
|
281
|
+
client = client_factory()
|
|
282
|
+
slug = agent_slug(agent)
|
|
283
|
+
base = f"/api/agents/{encode(slug)}/imports"
|
|
284
|
+
if import_id is None:
|
|
285
|
+
for view in client.get(base).json():
|
|
286
|
+
typer.echo(
|
|
287
|
+
f"{import_line(view)} {view['since']} → {view['until']} "
|
|
288
|
+
f"{view['source']}/{view['project']} by {view['created_by']}"
|
|
289
|
+
)
|
|
290
|
+
return
|
|
291
|
+
if stop:
|
|
292
|
+
typer.echo(import_line(client.post(f"{base}/{import_id}/stop").json()))
|
|
293
|
+
return
|
|
294
|
+
if resume:
|
|
295
|
+
client.post(f"{base}/{import_id}/continue")
|
|
296
|
+
follow(client, agent, slug, import_id)
|
|
297
|
+
|
|
298
|
+
@mapping_app.command("push")
|
|
299
|
+
def mapping_push(
|
|
300
|
+
agent: str,
|
|
301
|
+
file: Path = typer.Argument(..., exists=True, dir_okay=False, help="Mapping JSON file."),
|
|
302
|
+
activate: bool = typer.Option(
|
|
303
|
+
False,
|
|
304
|
+
"--activate",
|
|
305
|
+
help="Also make it the active mapping, which every later run uses.",
|
|
306
|
+
),
|
|
307
|
+
):
|
|
308
|
+
"""Upload a mapping document as the agent's draft.
|
|
309
|
+
|
|
310
|
+
Example: evalkit traces mapping push research-agent eval/span-mapping.json
|
|
311
|
+
"""
|
|
312
|
+
document = json.loads(file.read_text())
|
|
313
|
+
body = (
|
|
314
|
+
client_factory()
|
|
315
|
+
.put(
|
|
316
|
+
f"/api/agents/{encode(agent_slug(agent))}/mappings/draft",
|
|
317
|
+
params={"activate": str(activate).lower()},
|
|
318
|
+
json=document,
|
|
319
|
+
)
|
|
320
|
+
.json()
|
|
321
|
+
)
|
|
322
|
+
typer.echo(f"{body['status']} v{body['version']} for {agent}")
|
|
323
|
+
|
|
324
|
+
@mapping_app.command("list")
|
|
325
|
+
def mapping_list(agent: str):
|
|
326
|
+
"""List an agent's mapping versions. Example: evalkit traces mapping list research-agent"""
|
|
327
|
+
rows = client_factory().get(f"/api/agents/{encode(agent_slug(agent))}/mappings").json()
|
|
328
|
+
for row in rows:
|
|
329
|
+
typer.echo(
|
|
330
|
+
f"v{row['version']:<4} {row['status']:<8} by {row['created_by'] or '-':<16} "
|
|
331
|
+
f"{row['created_at']}"
|
|
332
|
+
)
|
evalkit/cli/update.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from importlib.util import find_spec
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
from evalkit import version
|
|
12
|
+
from evalkit.cli import skill_targets
|
|
13
|
+
from evalkit.cli.client import ApiClient, ApiError
|
|
14
|
+
|
|
15
|
+
PINNED = re.compile(r'"(evalkit-py(?:\[[^\]]*\])?)==([^"]+)"')
|
|
16
|
+
VENDORED = re.compile(r"evalkit-[^\s\"']+\.whl")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def install_command(prefix: Path, requirement: str) -> list[str] | None:
|
|
20
|
+
parts = prefix.parts
|
|
21
|
+
if "uv" in parts and "tools" in parts:
|
|
22
|
+
return ["uv", "tool", "install", "--reinstall", requirement]
|
|
23
|
+
if "pipx" in parts and "venvs" in parts:
|
|
24
|
+
return ["pipx", "install", "--force", requirement]
|
|
25
|
+
return None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def installed_cli(prefix: Path) -> Path:
|
|
29
|
+
return prefix / ("Scripts" if os.name == "nt" else "bin") / "evalkit"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _run_checked(command: list[str]) -> None:
|
|
33
|
+
subprocess.run(command, check=True)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def update_project_pin(cwd: Path, target: str, run: Callable[[list[str]], object]) -> bool:
|
|
37
|
+
pyproject = cwd / "pyproject.toml"
|
|
38
|
+
if not pyproject.is_file():
|
|
39
|
+
return False
|
|
40
|
+
text = pyproject.read_text()
|
|
41
|
+
if PINNED.search(text):
|
|
42
|
+
moved = PINNED.sub(lambda m: f'"{m.group(1)}=={target}"', text)
|
|
43
|
+
if moved != text:
|
|
44
|
+
pyproject.write_text(moved)
|
|
45
|
+
run(["uv", "sync"])
|
|
46
|
+
typer.echo(f"updated {pyproject}")
|
|
47
|
+
return True
|
|
48
|
+
elif VENDORED.search(text):
|
|
49
|
+
typer.echo("this project uses a vendored evalkit wheel; move it to PyPI:")
|
|
50
|
+
typer.echo(f' uv remove evalkit && uv add "{version.DISTRIBUTION}[otel]=={target}"')
|
|
51
|
+
return False
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def run_update(
|
|
55
|
+
client: ApiClient,
|
|
56
|
+
*,
|
|
57
|
+
prefix: Path | None = None,
|
|
58
|
+
run: Callable[[list[str]], object] = _run_checked,
|
|
59
|
+
cwd: Path | None = None,
|
|
60
|
+
skills: bool = True,
|
|
61
|
+
targets_path: Path | None = None,
|
|
62
|
+
server_extra: bool = find_spec("uvicorn") is not None,
|
|
63
|
+
) -> None:
|
|
64
|
+
target = client.get("/api/cli").json()["version"]
|
|
65
|
+
project = cwd or Path.cwd()
|
|
66
|
+
synced = update_project_pin(project, target, run)
|
|
67
|
+
local = version.current()
|
|
68
|
+
if local == target:
|
|
69
|
+
typer.echo(f"evalkit {local} is already current")
|
|
70
|
+
return
|
|
71
|
+
install_prefix = prefix or Path(sys.prefix)
|
|
72
|
+
if synced and install_prefix.resolve() == (project / ".venv").resolve():
|
|
73
|
+
typer.echo(f"installed evalkit {target} into {install_prefix}")
|
|
74
|
+
return
|
|
75
|
+
extra = "[server]" if server_extra else ""
|
|
76
|
+
requirement = f"{version.DISTRIBUTION}{extra}=={target}"
|
|
77
|
+
command = install_command(install_prefix, requirement)
|
|
78
|
+
if command is None:
|
|
79
|
+
typer.echo(f' uv tool install --reinstall "{requirement}"')
|
|
80
|
+
typer.echo(f' pipx install --force "{requirement}"')
|
|
81
|
+
raise ApiError("could not tell how evalkit was installed; run one of the commands above")
|
|
82
|
+
run(command)
|
|
83
|
+
typer.echo(f"installed evalkit {target}")
|
|
84
|
+
if skills:
|
|
85
|
+
skill_targets.refresh(project, installed_cli(install_prefix), run, targets_path)
|
|
File without changes
|
evalkit/client/agents.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from evalkit.client.api import AsyncApi, encode
|
|
2
|
+
from evalkit.contracts.settings import AgentSettings
|
|
3
|
+
from evalkit.core.agents import AgentDefinition
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def definition_of(body: dict) -> AgentDefinition:
|
|
7
|
+
return AgentDefinition(
|
|
8
|
+
id=body["id"],
|
|
9
|
+
name=body["name"],
|
|
10
|
+
workspace=body["workspace"],
|
|
11
|
+
workspace_is_shared=body["workspace_type"] == "shared",
|
|
12
|
+
harness_url=body["harness_url"],
|
|
13
|
+
trajectory_source=body["trajectory_source"],
|
|
14
|
+
repo_url=body["repo_url"],
|
|
15
|
+
settings=AgentSettings.model_validate(body["settings"]),
|
|
16
|
+
archived=body["archived"],
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class HttpAgents:
|
|
21
|
+
def __init__(self, api: AsyncApi):
|
|
22
|
+
self._api = api
|
|
23
|
+
|
|
24
|
+
async def get(self, ref: str) -> AgentDefinition:
|
|
25
|
+
return definition_of((await self._api.get(f"/api/agents/{encode(ref)}")).json())
|