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.
Files changed (371) hide show
  1. evalkit/__init__.py +0 -0
  2. evalkit/api/__init__.py +0 -0
  3. evalkit/api/access.py +74 -0
  4. evalkit/api/agents.py +159 -0
  5. evalkit/api/app.py +360 -0
  6. evalkit/api/auth.py +225 -0
  7. evalkit/api/cli_dist.py +10 -0
  8. evalkit/api/datasets.py +169 -0
  9. evalkit/api/deps.py +79 -0
  10. evalkit/api/download.py +15 -0
  11. evalkit/api/evaluators.py +121 -0
  12. evalkit/api/experiments.py +616 -0
  13. evalkit/api/fixtures.py +95 -0
  14. evalkit/api/harness_check.py +48 -0
  15. evalkit/api/imports.py +180 -0
  16. evalkit/api/limits.py +84 -0
  17. evalkit/api/llm_providers.py +120 -0
  18. evalkit/api/mcp/__init__.py +0 -0
  19. evalkit/api/mcp/auth.py +100 -0
  20. evalkit/api/mcp/descriptions.py +336 -0
  21. evalkit/api/mcp/models.py +259 -0
  22. evalkit/api/mcp/server.py +101 -0
  23. evalkit/api/mcp/tools.py +844 -0
  24. evalkit/api/meta.py +19 -0
  25. evalkit/api/otel.py +350 -0
  26. evalkit/api/pull.py +197 -0
  27. evalkit/api/review.py +271 -0
  28. evalkit/api/runs.py +555 -0
  29. evalkit/api/server_keys.py +44 -0
  30. evalkit/api/tokens.py +51 -0
  31. evalkit/api/trace_imports.py +173 -0
  32. evalkit/api/trace_sources.py +49 -0
  33. evalkit/api/traces.py +196 -0
  34. evalkit/api/users.py +72 -0
  35. evalkit/api/workspaces.py +131 -0
  36. evalkit/bundled/contracts/atif-accepted.json +5 -0
  37. evalkit/bundled/contracts/custom-evaluator-api-v1.json +243 -0
  38. evalkit/bundled/contracts/harness-api-v1.json +938 -0
  39. evalkit/bundled/contracts/span-mapping-v1.json +314 -0
  40. evalkit/bundled/docs/concepts.md +26 -0
  41. evalkit/bundled/docs/config.md +38 -0
  42. evalkit/bundled/docs/harness-api.md +44 -0
  43. evalkit/bundled/docs/install.md +60 -0
  44. evalkit/bundled/docs/login.md +36 -0
  45. evalkit/bundled/docs/mappings.md +136 -0
  46. evalkit/bundled/docs/mcp.md +44 -0
  47. evalkit/bundled/docs/quickstart.md +142 -0
  48. evalkit/bundled/docs/sdk-runs.md +171 -0
  49. evalkit/bundled/docs/tracing.md +171 -0
  50. evalkit/bundled/docs/try-locally.md +288 -0
  51. evalkit/bundled/docs/workspaces.md +45 -0
  52. evalkit/bundled/skills/authoring-eval-cases/SKILL.md +387 -0
  53. evalkit/bundled/skills/authoring-eval-cases/references/overlays.md +83 -0
  54. evalkit/bundled/skills/authoring-eval-cases/references/tool-checks.md +71 -0
  55. evalkit/bundled/skills/connect-traces/SKILL.md +296 -0
  56. evalkit/bundled/skills/connect-traces/references/gen_ai.json +42 -0
  57. evalkit/bundled/skills/connect-traces/references/openinference.json +35 -0
  58. evalkit/bundled/skills/connect-traces/references/span-mapping-schema.md +88 -0
  59. evalkit/bundled/skills/eval-driven-development/SKILL.md +458 -0
  60. evalkit/bundled/skills/eval-driven-development/references/analyze-run.md +97 -0
  61. evalkit/bundled/skills/eval-driven-development/references/diagnose.md +130 -0
  62. evalkit/bundled/skills/eval-driven-development/references/synthesize-cases.md +87 -0
  63. evalkit/bundled/skills/eval-driven-development/references/synthesize.md +165 -0
  64. evalkit/bundled/skills/evalkit-deployment/SKILL.md +332 -0
  65. evalkit/bundled/skills/evalkit-deployment/config.example.yaml +49 -0
  66. evalkit/bundled/skills/evalkit-deployment/docker-compose.yml +51 -0
  67. evalkit/bundled/skills/evalkit-deployment/references/config-and-deploy.md +333 -0
  68. evalkit/bundled/skills/evalkit-deployment/references/harness-api.md +139 -0
  69. evalkit/bundled/skills/evalkit-deployment/try/.env.example +11 -0
  70. evalkit/bundled/skills/evalkit-deployment/try/agent.py +131 -0
  71. evalkit/bundled/skills/evalkit-deployment/try/cases/acme/balance-sheet/cases.yaml +25 -0
  72. evalkit/bundled/skills/evalkit-deployment/try/cases/acme/income-statement/cases.yaml +43 -0
  73. evalkit/bundled/skills/evalkit-deployment/try/config.yaml +17 -0
  74. evalkit/bundled/skills/evalkit-deployment/try/docker-compose.yml +82 -0
  75. evalkit/bundled/skills/evalkit-deployment/try/evalkit.yaml +4 -0
  76. evalkit/bundled/skills/evalkit-deployment/try/mapping.json +42 -0
  77. evalkit/bundled/skills/evalkit-deployment/try/run.py +33 -0
  78. evalkit/bundled/skills/evalkit-usage/SKILL.md +509 -0
  79. evalkit/bundled/skills/evalkit-usage/references/suite-fixtures.md +42 -0
  80. evalkit/bundled/ui/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  81. evalkit/bundled/ui/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  82. evalkit/bundled/ui/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  83. evalkit/bundled/ui/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  84. evalkit/bundled/ui/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  85. evalkit/bundled/ui/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  86. evalkit/bundled/ui/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  87. evalkit/bundled/ui/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  88. evalkit/bundled/ui/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  89. evalkit/bundled/ui/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  90. evalkit/bundled/ui/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  91. evalkit/bundled/ui/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  92. evalkit/bundled/ui/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  93. evalkit/bundled/ui/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  94. evalkit/bundled/ui/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  95. evalkit/bundled/ui/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  96. evalkit/bundled/ui/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  97. evalkit/bundled/ui/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  98. evalkit/bundled/ui/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  99. evalkit/bundled/ui/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  100. evalkit/bundled/ui/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  101. evalkit/bundled/ui/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  102. evalkit/bundled/ui/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  103. evalkit/bundled/ui/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  104. evalkit/bundled/ui/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  105. evalkit/bundled/ui/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  106. evalkit/bundled/ui/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  107. evalkit/bundled/ui/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  108. evalkit/bundled/ui/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  109. evalkit/bundled/ui/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  110. evalkit/bundled/ui/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  111. evalkit/bundled/ui/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  112. evalkit/bundled/ui/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  113. evalkit/bundled/ui/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  114. evalkit/bundled/ui/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  115. evalkit/bundled/ui/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  116. evalkit/bundled/ui/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  117. evalkit/bundled/ui/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  118. evalkit/bundled/ui/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  119. evalkit/bundled/ui/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  120. evalkit/bundled/ui/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  121. evalkit/bundled/ui/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  122. evalkit/bundled/ui/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  123. evalkit/bundled/ui/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  124. evalkit/bundled/ui/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  125. evalkit/bundled/ui/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  126. evalkit/bundled/ui/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  127. evalkit/bundled/ui/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  128. evalkit/bundled/ui/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  129. evalkit/bundled/ui/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  130. evalkit/bundled/ui/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  131. evalkit/bundled/ui/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  132. evalkit/bundled/ui/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  133. evalkit/bundled/ui/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  134. evalkit/bundled/ui/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  135. evalkit/bundled/ui/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  136. evalkit/bundled/ui/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  137. evalkit/bundled/ui/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  138. evalkit/bundled/ui/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  139. evalkit/bundled/ui/assets/abap-08VXUWAP.js +1 -0
  140. evalkit/bundled/ui/assets/apex-BWPQTe0t.js +1 -0
  141. evalkit/bundled/ui/assets/azcli-Bc_sGQ0U.js +1 -0
  142. evalkit/bundled/ui/assets/bat-i0X4ZdIN.js +1 -0
  143. evalkit/bundled/ui/assets/bicep-B5-_aFwp.js +2 -0
  144. evalkit/bundled/ui/assets/cameligo-DMUM7wLl.js +1 -0
  145. evalkit/bundled/ui/assets/clojure-Cm7r79vr.js +1 -0
  146. evalkit/bundled/ui/assets/codicon-DF1abBS2.ttf +0 -0
  147. evalkit/bundled/ui/assets/coffee-Ba7i2nA0.js +1 -0
  148. evalkit/bundled/ui/assets/cpp-C7h46wYY.js +1 -0
  149. evalkit/bundled/ui/assets/csharp-BKxtCVv1.js +1 -0
  150. evalkit/bundled/ui/assets/csp-bTuwJoIa.js +1 -0
  151. evalkit/bundled/ui/assets/css-DIMkf-bt.js +3 -0
  152. evalkit/bundled/ui/assets/css.worker-DwfUZ3fB.js +96 -0
  153. evalkit/bundled/ui/assets/cssMode-C97l1pbB.js +1 -0
  154. evalkit/bundled/ui/assets/cypher-CVaqCwHa.js +1 -0
  155. evalkit/bundled/ui/assets/dart-onAF5SnQ.js +1 -0
  156. evalkit/bundled/ui/assets/dockerfile-DZFCIeNp.js +1 -0
  157. evalkit/bundled/ui/assets/ecl-94qehhXe.js +1 -0
  158. evalkit/bundled/ui/assets/editor-DjpsE8to.css +1 -0
  159. evalkit/bundled/ui/assets/editor.api-NTesIxw5.js +908 -0
  160. evalkit/bundled/ui/assets/editor.worker-CRz__AKW.js +33 -0
  161. evalkit/bundled/ui/assets/elixir-6RTg0lbw.js +1 -0
  162. evalkit/bundled/ui/assets/flow9-C5_-GSwl.js +1 -0
  163. evalkit/bundled/ui/assets/freemarker2-BWqEFagp.js +3 -0
  164. evalkit/bundled/ui/assets/fsharp-C8Ef5oNN.js +1 -0
  165. evalkit/bundled/ui/assets/go-C-y9NEjX.js +1 -0
  166. evalkit/bundled/ui/assets/graphql-fmXr3nnJ.js +1 -0
  167. evalkit/bundled/ui/assets/handlebars-DkIF-whN.js +1 -0
  168. evalkit/bundled/ui/assets/hcl-CpzslTdj.js +1 -0
  169. evalkit/bundled/ui/assets/html-C_rpeQXJ.js +1 -0
  170. evalkit/bundled/ui/assets/html.worker-D9ugpX4y.js +509 -0
  171. evalkit/bundled/ui/assets/htmlMode-B0YIq3DF.js +1 -0
  172. evalkit/bundled/ui/assets/index-Cw-jBH6M.js +736 -0
  173. evalkit/bundled/ui/assets/index-DKtoQZtm.css +1 -0
  174. evalkit/bundled/ui/assets/ini-sBoK_t0W.js +1 -0
  175. evalkit/bundled/ui/assets/java-BEtHBSE6.js +1 -0
  176. evalkit/bundled/ui/assets/javascript-D4EGhYA6.js +1 -0
  177. evalkit/bundled/ui/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  178. evalkit/bundled/ui/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  179. evalkit/bundled/ui/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  180. evalkit/bundled/ui/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  181. evalkit/bundled/ui/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  182. evalkit/bundled/ui/assets/json.worker-CV9fqkUp.js +65 -0
  183. evalkit/bundled/ui/assets/jsonMode-pQjSfIH6.js +7 -0
  184. evalkit/bundled/ui/assets/julia-Bri6UV-V.js +1 -0
  185. evalkit/bundled/ui/assets/kotlin-BOotOW0E.js +1 -0
  186. evalkit/bundled/ui/assets/less-B9JPFI3C.js +2 -0
  187. evalkit/bundled/ui/assets/lexon-CfSJPG6W.js +1 -0
  188. evalkit/bundled/ui/assets/liquid-DbrvoYjD.js +1 -0
  189. evalkit/bundled/ui/assets/lspLanguageFeatures-D0B7cH6y.js +4 -0
  190. evalkit/bundled/ui/assets/lua-CsQS60Ue.js +1 -0
  191. evalkit/bundled/ui/assets/m3-D-oSqn_W.js +1 -0
  192. evalkit/bundled/ui/assets/markdown-Cimd5fb3.js +1 -0
  193. evalkit/bundled/ui/assets/mdx-B0HrujLR.js +1 -0
  194. evalkit/bundled/ui/assets/mips-CIPQ_RoX.js +1 -0
  195. evalkit/bundled/ui/assets/monacoEditor-DsoPncxW.js +68 -0
  196. evalkit/bundled/ui/assets/monacoEditor-n7clI0si.css +1 -0
  197. evalkit/bundled/ui/assets/msdax-DauUninz.js +1 -0
  198. evalkit/bundled/ui/assets/mysql-SOo6toE5.js +1 -0
  199. evalkit/bundled/ui/assets/objective-c-FvmIjYaQ.js +1 -0
  200. evalkit/bundled/ui/assets/pascal-DrH0SRf2.js +1 -0
  201. evalkit/bundled/ui/assets/pascaligo-D-ptJ9y-.js +1 -0
  202. evalkit/bundled/ui/assets/perl-oz_6vUea.js +1 -0
  203. evalkit/bundled/ui/assets/pgsql-DTj74zXo.js +1 -0
  204. evalkit/bundled/ui/assets/php-nr791fC2.js +1 -0
  205. evalkit/bundled/ui/assets/pla-CopQ2nXW.js +1 -0
  206. evalkit/bundled/ui/assets/postiats-43DmfD33.js +1 -0
  207. evalkit/bundled/ui/assets/powerquery-D3hlyOfw.js +1 -0
  208. evalkit/bundled/ui/assets/powershell-DmHpPYUd.js +1 -0
  209. evalkit/bundled/ui/assets/protobuf-C531GsRP.js +2 -0
  210. evalkit/bundled/ui/assets/pug-Z5eAx3Zn.js +1 -0
  211. evalkit/bundled/ui/assets/python-CieHVM9n.js +1 -0
  212. evalkit/bundled/ui/assets/qsharp-DkqhCAOL.js +1 -0
  213. evalkit/bundled/ui/assets/r-BwWrilGY.js +1 -0
  214. evalkit/bundled/ui/assets/razor-sLewSMyp.js +1 -0
  215. evalkit/bundled/ui/assets/redis-ClamHrr6.js +1 -0
  216. evalkit/bundled/ui/assets/redshift-DT7zqm-g.js +1 -0
  217. evalkit/bundled/ui/assets/restructuredtext-BYgofb2h.js +1 -0
  218. evalkit/bundled/ui/assets/ruby-DezsRK8O.js +1 -0
  219. evalkit/bundled/ui/assets/rust-DdL9SqIa.js +1 -0
  220. evalkit/bundled/ui/assets/sb-CcwsVR0C.js +1 -0
  221. evalkit/bundled/ui/assets/scala-DHpiXF5c.js +1 -0
  222. evalkit/bundled/ui/assets/scheme-BeGwcela.js +1 -0
  223. evalkit/bundled/ui/assets/scss-gp-XZpBa.js +3 -0
  224. evalkit/bundled/ui/assets/shell-CC2rA5mh.js +1 -0
  225. evalkit/bundled/ui/assets/solidity-BEEn4gHE.js +1 -0
  226. evalkit/bundled/ui/assets/sophia-CRfGWb83.js +1 -0
  227. evalkit/bundled/ui/assets/sparql-D_Lu-MrJ.js +1 -0
  228. evalkit/bundled/ui/assets/sql-NEE52Syq.js +1 -0
  229. evalkit/bundled/ui/assets/st-DbInun42.js +1 -0
  230. evalkit/bundled/ui/assets/swift-Bxkupp3x.js +1 -0
  231. evalkit/bundled/ui/assets/systemverilog-Bz4Y3fRF.js +1 -0
  232. evalkit/bundled/ui/assets/tcl-DISqw1ZD.js +1 -0
  233. evalkit/bundled/ui/assets/ts.worker-DIAQkoB3.js +67741 -0
  234. evalkit/bundled/ui/assets/tsMode-BcVQ1nu0.js +11 -0
  235. evalkit/bundled/ui/assets/twig-De2hgUGE.js +1 -0
  236. evalkit/bundled/ui/assets/typescript-CUvNWd9p.js +1 -0
  237. evalkit/bundled/ui/assets/typespec-B8J7ngcE.js +1 -0
  238. evalkit/bundled/ui/assets/vb-DV3o63ZY.js +1 -0
  239. evalkit/bundled/ui/assets/wgsl-DpFanUEy.js +298 -0
  240. evalkit/bundled/ui/assets/workers-CwpYQtzp.js +1 -0
  241. evalkit/bundled/ui/assets/xml-C1HnXMdF.js +1 -0
  242. evalkit/bundled/ui/assets/yaml-D7Ey3HQu.js +1 -0
  243. evalkit/bundled/ui/favicon.svg +6 -0
  244. evalkit/bundled/ui/index.html +14 -0
  245. evalkit/cli/__init__.py +0 -0
  246. evalkit/cli/admin_commands.py +590 -0
  247. evalkit/cli/client.py +67 -0
  248. evalkit/cli/init_server.py +165 -0
  249. evalkit/cli/local_run.py +195 -0
  250. evalkit/cli/main.py +1365 -0
  251. evalkit/cli/runs_commands.py +539 -0
  252. evalkit/cli/server_commands.py +130 -0
  253. evalkit/cli/skill_targets.py +43 -0
  254. evalkit/cli/tokens_commands.py +52 -0
  255. evalkit/cli/traces_commands.py +332 -0
  256. evalkit/cli/update.py +85 -0
  257. evalkit/client/__init__.py +0 -0
  258. evalkit/client/agents.py +25 -0
  259. evalkit/client/api.py +193 -0
  260. evalkit/client/blob.py +104 -0
  261. evalkit/client/connection.py +88 -0
  262. evalkit/client/evaluators.py +11 -0
  263. evalkit/client/sessions.py +17 -0
  264. evalkit/client/store.py +139 -0
  265. evalkit/client/summary.py +46 -0
  266. evalkit/client/sync.py +198 -0
  267. evalkit/config.py +227 -0
  268. evalkit/contracts/__init__.py +0 -0
  269. evalkit/contracts/atif.py +115 -0
  270. evalkit/contracts/cases.py +456 -0
  271. evalkit/contracts/custom_evaluator.py +58 -0
  272. evalkit/contracts/enums.py +86 -0
  273. evalkit/contracts/esf.py +120 -0
  274. evalkit/contracts/harness.py +281 -0
  275. evalkit/contracts/notes.json +4 -0
  276. evalkit/contracts/notes.py +7 -0
  277. evalkit/contracts/settings.py +41 -0
  278. evalkit/core/__init__.py +0 -0
  279. evalkit/core/access.py +75 -0
  280. evalkit/core/agents.py +65 -0
  281. evalkit/core/blob.py +46 -0
  282. evalkit/core/capabilities.py +36 -0
  283. evalkit/core/costmap.py +90 -0
  284. evalkit/core/custom_eval.py +50 -0
  285. evalkit/core/data/cost_map.json +81546 -0
  286. evalkit/core/endpoints.py +31 -0
  287. evalkit/core/evaluators/__init__.py +29 -0
  288. evalkit/core/evaluators/base.py +121 -0
  289. evalkit/core/evaluators/gauges.py +84 -0
  290. evalkit/core/evaluators/presentation.py +166 -0
  291. evalkit/core/evaluators/response_time.py +21 -0
  292. evalkit/core/evaluators/rubrics.py +494 -0
  293. evalkit/core/evaluators/tool_trajectory.py +187 -0
  294. evalkit/core/evaluators/trajectory_rubrics.py +198 -0
  295. evalkit/core/fixtures.py +57 -0
  296. evalkit/core/harness.py +227 -0
  297. evalkit/core/harness_check.py +191 -0
  298. evalkit/core/importer.py +257 -0
  299. evalkit/core/judge.py +78 -0
  300. evalkit/core/lint.py +265 -0
  301. evalkit/core/overlays.py +76 -0
  302. evalkit/core/paths.py +25 -0
  303. evalkit/core/promotion.py +94 -0
  304. evalkit/core/pull.py +198 -0
  305. evalkit/core/python_eval.py +59 -0
  306. evalkit/core/remote_evaluators.py +32 -0
  307. evalkit/core/review.py +220 -0
  308. evalkit/core/run_digest.py +421 -0
  309. evalkit/core/runner.py +995 -0
  310. evalkit/core/scorecard.py +255 -0
  311. evalkit/core/traces/__init__.py +0 -0
  312. evalkit/core/traces/convert.py +336 -0
  313. evalkit/core/traces/importer.py +113 -0
  314. evalkit/core/traces/mapping.py +385 -0
  315. evalkit/core/traces/poll.py +38 -0
  316. evalkit/core/traces/raw.py +21 -0
  317. evalkit/core/traces/sessions.py +172 -0
  318. evalkit/core/traces/settle.py +14 -0
  319. evalkit/core/traces/sources/__init__.py +19 -0
  320. evalkit/core/traces/sources/base.py +25 -0
  321. evalkit/core/traces/sources/phoenix.py +121 -0
  322. evalkit/core/trajectory.py +248 -0
  323. evalkit/core/workspace.py +30 -0
  324. evalkit/credentials.py +119 -0
  325. evalkit/db/__init__.py +0 -0
  326. evalkit/db/agents.py +289 -0
  327. evalkit/db/alembic/env.py +90 -0
  328. evalkit/db/alembic/script.py.mako +28 -0
  329. evalkit/db/alembic/versions/0011_baseline.py +1002 -0
  330. evalkit/db/alembic/versions/0012_ticket_token_kind.py +27 -0
  331. evalkit/db/alembic/versions/0013_keys_and_llm_providers.py +67 -0
  332. evalkit/db/cases.py +608 -0
  333. evalkit/db/crypto.py +12 -0
  334. evalkit/db/evaluators.py +156 -0
  335. evalkit/db/experiments.py +363 -0
  336. evalkit/db/fixture_blobs.py +91 -0
  337. evalkit/db/keys.py +78 -0
  338. evalkit/db/llm_providers.py +176 -0
  339. evalkit/db/locks.py +6 -0
  340. evalkit/db/mappings.py +168 -0
  341. evalkit/db/models.py +567 -0
  342. evalkit/db/promotion.py +271 -0
  343. evalkit/db/rekey.py +46 -0
  344. evalkit/db/review.py +250 -0
  345. evalkit/db/review_state.py +50 -0
  346. evalkit/db/runs.py +533 -0
  347. evalkit/db/scorecard.py +300 -0
  348. evalkit/db/session.py +71 -0
  349. evalkit/db/sessions.py +90 -0
  350. evalkit/db/spans.py +360 -0
  351. evalkit/db/store.py +209 -0
  352. evalkit/db/tokens.py +100 -0
  353. evalkit/db/trace_imports.py +308 -0
  354. evalkit/db/trace_sources.py +131 -0
  355. evalkit/db/users.py +186 -0
  356. evalkit/db/workspaces.py +232 -0
  357. evalkit/paths.py +33 -0
  358. evalkit/sdk/__init__.py +29 -0
  359. evalkit/sdk/binding.py +69 -0
  360. evalkit/sdk/evaluators.py +56 -0
  361. evalkit/sdk/runner.py +957 -0
  362. evalkit/sdk/tracing.py +166 -0
  363. evalkit/store/__init__.py +0 -0
  364. evalkit/store/base.py +354 -0
  365. evalkit/store/blob.py +69 -0
  366. evalkit/version.py +44 -0
  367. evalkit_py-0.2.0.dev12.dist-info/METADATA +205 -0
  368. evalkit_py-0.2.0.dev12.dist-info/RECORD +371 -0
  369. evalkit_py-0.2.0.dev12.dist-info/WHEEL +4 -0
  370. evalkit_py-0.2.0.dev12.dist-info/entry_points.txt +2 -0
  371. 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
@@ -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())