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
evalkit/sdk/tracing.py ADDED
@@ -0,0 +1,166 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import threading
5
+ from collections import OrderedDict
6
+ from collections.abc import Callable, Iterator
7
+ from contextlib import contextmanager
8
+ from contextvars import ContextVar
9
+ from importlib.util import find_spec
10
+ from typing import Any
11
+
12
+ from opentelemetry import trace
13
+ from opentelemetry.context import Context
14
+
15
+ from evalkit.client import connection
16
+
17
+ OTEL_TOKEN_ENV = "EVALKIT_OTEL_TOKEN"
18
+ SERVER_URL_ENV = "EVALKIT_SERVER_URL"
19
+ AGENT_HEADER = "X-Evalkit-Agent"
20
+ STAMPED = ("session.id", "evalkit.experiment_id", "evalkit.case_id", "evalkit.repetition")
21
+ EVAL_MARKER = "evalkit.case_id"
22
+ MAX_EVAL_TRACES = 10_000
23
+ INSTALL_HINT = "evalkit tracing needs the otel extra: uv add 'evalkit-py[otel]'"
24
+
25
+ CURRENT_RUN: ContextVar[dict[str, Any] | None] = ContextVar("evalkit_current_run", default=None)
26
+
27
+ SpanFilter = Callable[[Any], bool]
28
+
29
+ HAS_OTEL_SDK = bool(
30
+ find_spec("opentelemetry.sdk") and find_spec("opentelemetry.exporter.otlp.proto.http")
31
+ )
32
+
33
+ if HAS_OTEL_SDK:
34
+ from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
35
+ from opentelemetry.sdk.resources import Resource
36
+ from opentelemetry.sdk.trace import ReadableSpan, SpanProcessor, TracerProvider
37
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor, SpanExporter
38
+
39
+ class EvalkitSpanProcessor(SpanProcessor):
40
+ def __init__(self, exporter: SpanExporter, only: SpanFilter | None = None) -> None:
41
+ self.batch = BatchSpanProcessor(exporter)
42
+ self.only = only
43
+ self.max_traces = MAX_EVAL_TRACES
44
+ self.kept_traces: OrderedDict[int, None] = OrderedDict()
45
+ self.lock = threading.Lock()
46
+
47
+ def on_start(self, span: Any, parent_context: Context | None = None) -> None:
48
+ attributes = CURRENT_RUN.get()
49
+ if attributes:
50
+ for key in STAMPED:
51
+ if key in attributes:
52
+ span.set_attribute(key, attributes[key])
53
+ if self.only is not None and self.only(span):
54
+ self.keep_trace(trace_of(span))
55
+
56
+ def on_end(self, span: ReadableSpan) -> None:
57
+ if self.only is None:
58
+ self.batch.on_end(span)
59
+ return
60
+ trace_id = trace_of(span)
61
+ if self.only(span):
62
+ self.keep_trace(trace_id)
63
+ if self.is_kept(trace_id):
64
+ self.batch.on_end(span)
65
+
66
+ def is_kept(self, trace_id: int) -> bool:
67
+ with self.lock:
68
+ if trace_id not in self.kept_traces:
69
+ return False
70
+ self.kept_traces.move_to_end(trace_id)
71
+ return True
72
+
73
+ def keep_trace(self, trace_id: int) -> None:
74
+ with self.lock:
75
+ self.kept_traces[trace_id] = None
76
+ self.kept_traces.move_to_end(trace_id)
77
+ while len(self.kept_traces) > self.max_traces:
78
+ self.kept_traces.popitem(last=False)
79
+
80
+ def shutdown(self) -> None:
81
+ self.batch.shutdown()
82
+
83
+ def force_flush(self, timeout_millis: int = 30000) -> bool:
84
+ return self.batch.force_flush(timeout_millis)
85
+
86
+ def configure(
87
+ provider: TracerProvider, exporter: SpanExporter, only: SpanFilter | None = None
88
+ ) -> None:
89
+ provider.add_span_processor(EvalkitSpanProcessor(exporter, only))
90
+
91
+
92
+ def trace_of(span: Any) -> int:
93
+ return span.get_span_context().trace_id
94
+
95
+
96
+ def collector_url(server_url: str) -> str:
97
+ return f"{server_url.rstrip('/')}/api/otel/v1/traces"
98
+
99
+
100
+ def resolve_destination() -> tuple[str, str | None]:
101
+ token = os.environ.get(OTEL_TOKEN_ENV)
102
+ url = os.environ.get(SERVER_URL_ENV)
103
+ if url and token:
104
+ return url, token
105
+ active = connection.active()
106
+ return url or active.url, token or active.token
107
+
108
+
109
+ def headers(agent: str) -> dict[str, str]:
110
+ _, token = resolve_destination()
111
+ out = {AGENT_HEADER: agent}
112
+ if token:
113
+ out["Authorization"] = f"Bearer {token}"
114
+ return out
115
+
116
+
117
+ def exporter(agent: str) -> OTLPSpanExporter:
118
+ if not HAS_OTEL_SDK:
119
+ raise RuntimeError(INSTALL_HINT)
120
+ url, _ = resolve_destination()
121
+ return OTLPSpanExporter(endpoint=collector_url(url), headers=headers(agent))
122
+
123
+
124
+ def processor(agent: str, only: SpanFilter | None = None) -> EvalkitSpanProcessor:
125
+ return EvalkitSpanProcessor(exporter(agent), only)
126
+
127
+
128
+ def is_eval_span(span: Any) -> bool:
129
+ return EVAL_MARKER in (span.attributes or {})
130
+
131
+
132
+ @contextmanager
133
+ def eval_run(metadata: dict[str, Any]) -> Iterator[None]:
134
+ attributes = {
135
+ "session.id": metadata.get("session_id"),
136
+ "evalkit.experiment_id": metadata.get("experiment_id"),
137
+ "evalkit.case_id": metadata.get("case_id"),
138
+ "evalkit.repetition": metadata.get("repetition"),
139
+ }
140
+ token = CURRENT_RUN.set({k: v for k, v in attributes.items() if v is not None})
141
+ try:
142
+ yield
143
+ finally:
144
+ CURRENT_RUN.reset(token)
145
+
146
+
147
+ def register(agent: str, only: SpanFilter | None = None) -> None:
148
+ """Send this process's OpenTelemetry spans to the evalkit server.
149
+
150
+ Adds an exporter to the global tracer provider, or creates one when none is set.
151
+ Call it after your own tracing setup, so it joins your provider. Spans go to the
152
+ server you logged in to (or `EVALKIT_SERVER_URL`), with your token or
153
+ `EVALKIT_OTEL_TOKEN` (an agent token). Needs the `otel` extra.
154
+
155
+ Args:
156
+ agent: The agent the spans belong to, e.g. `myagent` or `myagent@dev`.
157
+ only: Export only the spans this function returns `True` for.
158
+ """
159
+ span_processor = processor(agent, only)
160
+ current = trace.get_tracer_provider()
161
+ if isinstance(current, TracerProvider):
162
+ provider = current
163
+ else:
164
+ provider = TracerProvider(resource=Resource.create({"evalkit.agent": agent}))
165
+ trace.set_tracer_provider(provider)
166
+ provider.add_span_processor(span_processor)
File without changes
evalkit/store/base.py ADDED
@@ -0,0 +1,354 @@
1
+ from collections.abc import AsyncIterator
2
+ from dataclasses import dataclass
3
+ from datetime import datetime
4
+ from typing import Any, Literal, Protocol
5
+
6
+ from pydantic import BaseModel, Field
7
+
8
+ from evalkit.contracts.enums import (
9
+ EvaluationSource,
10
+ EvaluatorKind,
11
+ ExperimentStatus,
12
+ RunStatus,
13
+ TrajectorySource,
14
+ TrajectoryStatus,
15
+ )
16
+ from evalkit.contracts.settings import JudgeSettings, RemoteEvaluatorSettings
17
+
18
+
19
+ @dataclass(frozen=True)
20
+ class BlobStream:
21
+ size: int
22
+ chunks: AsyncIterator[bytes]
23
+
24
+
25
+ class UnknownDataset(KeyError):
26
+ def __init__(self, ref: str):
27
+ super().__init__(ref)
28
+ self.ref = ref
29
+
30
+ def __str__(self) -> str:
31
+ return f"unknown dataset: {self.ref}"
32
+
33
+
34
+ class CaseFile(BaseModel):
35
+ key: str
36
+ sha256: str
37
+ context: str
38
+
39
+
40
+ class FixtureUse(BaseModel):
41
+ key: str
42
+ sha256: str
43
+ size: int
44
+ datasets: list[str]
45
+ uploaded_by: str | None
46
+
47
+
48
+ class FixtureUsePage(BaseModel):
49
+ items: list[FixtureUse]
50
+ total: int
51
+
52
+
53
+ class CaseView(BaseModel):
54
+ case_ref: int
55
+ case_id: str
56
+ content_hash: str
57
+ input: dict[str, Any]
58
+ expected: dict[str, Any] | None = None
59
+ evaluators: dict[str, Any] = Field(default_factory=dict)
60
+ effective_evaluators: dict[str, Any] = Field(default_factory=dict)
61
+ tags: list[str] = Field(default_factory=list)
62
+ split_tags: list[str] = Field(default_factory=list)
63
+ source: str | None = None
64
+ files: list[CaseFile] = Field(default_factory=list)
65
+ review_state: str | None = None
66
+
67
+
68
+ class DatasetSyncView(BaseModel):
69
+ id: int
70
+ source: str
71
+ detail: dict[str, Any]
72
+ actor: str
73
+ created_at: datetime
74
+
75
+
76
+ class DatasetRow(BaseModel):
77
+ id: int
78
+ workspace: str
79
+ workspace_is_shared: bool
80
+ name: str
81
+ kind: str
82
+ last_sync: DatasetSyncView | None = None
83
+
84
+ @property
85
+ def ref(self) -> str:
86
+ return f"{self.name}@{self.workspace}"
87
+
88
+
89
+ class Selection(BaseModel):
90
+ all: bool = False
91
+ tag: str | None = None
92
+ case_ids: list[str] | None = None
93
+
94
+
95
+ class IncomingCase(BaseModel):
96
+ case_id: str
97
+ content_hash: str
98
+ input: dict[str, Any]
99
+ expected: dict[str, Any] | None = None
100
+ evaluators: dict[str, Any] = Field(default_factory=dict)
101
+ tags: list[str] = Field(default_factory=list)
102
+ path_tags: list[str] = Field(default_factory=list)
103
+ source: str | None = None
104
+ files: list[CaseFile] = Field(default_factory=list)
105
+
106
+
107
+ class IncomingOverlay(BaseModel):
108
+ target_case_id: str
109
+ agents: list[str]
110
+ tags: list[str]
111
+ evaluators: dict[str, Any]
112
+ source_file: str | None = None
113
+
114
+
115
+ class CarriedReview(BaseModel):
116
+ case_id: str
117
+ reviewer: str
118
+
119
+
120
+ class SyncResult(BaseModel):
121
+ sync_id: int
122
+ dataset_id: int
123
+ created: list[str] = Field(default_factory=list)
124
+ patched: list[str] = Field(default_factory=list)
125
+ removed: list[str] = Field(default_factory=list)
126
+ unchanged: int = 0
127
+ overlays: int = 0
128
+ carried: list[CarriedReview] = Field(default_factory=list)
129
+ now_unreviewed: list[str] = Field(default_factory=list)
130
+
131
+
132
+ class GitRevision(BaseModel):
133
+ sha: str | None = None
134
+ branch: str | None = None
135
+ dirty: bool | None = None
136
+
137
+
138
+ class ExperimentSnapshot(BaseModel):
139
+ capabilities: dict[str, Any]
140
+ trajectory_source: TrajectorySource
141
+ trajectory_wait_seconds: int
142
+ remote_evaluators: dict[str, RemoteEvaluatorSettings] = Field(default_factory=dict)
143
+ code_evaluators: list[str] = Field(default_factory=list)
144
+ evalkit_version: str | None = None
145
+
146
+
147
+ class ExperimentConfig(BaseModel):
148
+ model: str | None = None
149
+ judge: JudgeSettings
150
+ selection: Selection
151
+ revision: GitRevision | None = None
152
+ snapshot: ExperimentSnapshot
153
+
154
+
155
+ class Experiment(BaseModel):
156
+ id: int
157
+ number: int
158
+ workspace: str
159
+ dataset: str
160
+ agent: str
161
+ agent_id: int
162
+ created_by: str
163
+ status: ExperimentStatus
164
+ status_error: str | None
165
+ lease_holder: str | None
166
+ lease_expires_at: datetime | None
167
+ repetitions: int
168
+ config: ExperimentConfig
169
+ started_at: datetime
170
+ ended_at: datetime | None
171
+
172
+
173
+ class PinnedVersion(BaseModel):
174
+ case_ref: int
175
+ content_hash: str
176
+
177
+
178
+ class NewExperiment(BaseModel):
179
+ dataset: str
180
+ agent: str
181
+ runner: str
182
+ repetitions: int
183
+ config: ExperimentConfig
184
+ cases: list[PinnedVersion]
185
+ holder: str
186
+
187
+
188
+ class AgentRunRecord(BaseModel):
189
+ harness_run_id: str
190
+ status: RunStatus
191
+ answer: str | None = None
192
+ output: dict[str, Any] | None = None
193
+ error: str | None = None
194
+ started_at: datetime
195
+ ended_at: datetime | None = None
196
+ trajectory_key: str | None = None
197
+ trajectory_status: TrajectoryStatus | None = None
198
+ metrics: dict[str, Any] = Field(default_factory=dict)
199
+ title: str | None = None
200
+
201
+
202
+ class RunRef(BaseModel):
203
+ experiment_run_id: int
204
+ agent_run_id: int
205
+
206
+
207
+ class CaseRep(BaseModel):
208
+ case_id: str
209
+ repetition: int
210
+
211
+
212
+ class EvaluationRow(BaseModel):
213
+ producer: str
214
+ name: str
215
+ kind: EvaluatorKind
216
+ source: EvaluationSource
217
+ value: float | None = None
218
+ label: str | None = None
219
+ explanation: str | None = None
220
+ error: str | None = None
221
+
222
+
223
+ class RunEvalContext(BaseModel):
224
+ experiment_id: int
225
+ repetition: int
226
+ case: CaseView
227
+ evaluations: list[EvaluationRow]
228
+
229
+
230
+ class RunForScoring(BaseModel):
231
+ experiment_run_id: int
232
+ case: CaseView
233
+ repetition: int
234
+ agent_run: AgentRunRecord
235
+ agent_run_id: int
236
+ done: set[str]
237
+
238
+
239
+ class RunDetail(BaseModel):
240
+ experiment_run_id: int
241
+ case_id: str
242
+ repetition: int
243
+ agent_run_id: int
244
+ agent_run: AgentRunRecord
245
+ evaluations: list[EvaluationRow] = Field(default_factory=list)
246
+
247
+
248
+ class AggregateRows(BaseModel):
249
+ experiment: Experiment
250
+ case_scores: list[tuple[str, str, float, str | None, str | None]]
251
+ case_gauges: list[tuple[str, str, float]]
252
+ case_errors: list[tuple[str, str, str]]
253
+ run_errors: list[tuple[str, str]]
254
+ repetitions_seen: dict[str, int]
255
+ sources: dict[str, str]
256
+
257
+
258
+ RunState = Literal["pending", "ran", "evaluated"]
259
+
260
+
261
+ class Progress(BaseModel):
262
+ total: int
263
+ ran: int
264
+ evaluated: int
265
+
266
+
267
+ class HistoryPoint(BaseModel):
268
+ experiment_id: int
269
+ number: int
270
+ agent: str
271
+ model: str | None = None
272
+ created_by: str
273
+ created_at: datetime
274
+ repetitions: int
275
+ scores: dict[str, float | None]
276
+ cost_usd: float | None = None
277
+
278
+
279
+ class UnknownExperiment(KeyError):
280
+ def __init__(self, experiment_id: int):
281
+ super().__init__(f"unknown experiment: {experiment_id}")
282
+
283
+
284
+ class Conflict(Exception):
285
+ pass
286
+
287
+
288
+ class InvalidRun(ValueError):
289
+ pass
290
+
291
+
292
+ class ScoreRow(BaseModel):
293
+ name: str
294
+ kind: Literal["evaluator", "gauge"] = "evaluator"
295
+ score: float | None = None
296
+ label: str | None = None
297
+ explanation: str | None = None
298
+ source: str = "builtin"
299
+ error: str | None = None
300
+ annotator_kind: Literal["CODE", "LLM", "HUMAN"] = "CODE"
301
+
302
+
303
+ class Store(Protocol):
304
+ async def cases_for(
305
+ self, dataset: str, selection: Selection, *, agent: str | None
306
+ ) -> list[CaseView]: ...
307
+
308
+ async def get_experiment(self, exp_id: int) -> Experiment: ...
309
+
310
+ async def pinned_cases(self, exp_id: int) -> list[CaseView]: ...
311
+
312
+ async def transition(
313
+ self, exp_id: int, to: ExperimentStatus, holder: str | None, error: str | None = None
314
+ ) -> Experiment: ...
315
+
316
+ async def renew_lease(self, exp_id: int, holder: str) -> bool: ...
317
+
318
+ async def set_model(self, exp_id: int, model: str) -> None: ...
319
+
320
+ async def pending_runs(self, exp_id: int) -> list[CaseRep]: ...
321
+
322
+ async def harness_run_id_used(self, exp_id: int, harness_run_id: str) -> str | None: ...
323
+
324
+ async def record_run(
325
+ self,
326
+ exp_id: int,
327
+ case_id: str,
328
+ repetition: int,
329
+ run: AgentRunRecord,
330
+ *,
331
+ holder: str | None = None,
332
+ ) -> RunRef: ...
333
+
334
+ async def runs_to_score(self, exp_id: int, *, force: bool) -> list[RunForScoring]: ...
335
+
336
+ async def publish_evaluations(
337
+ self,
338
+ experiment_run_id: int,
339
+ rows: list[EvaluationRow],
340
+ *,
341
+ force: bool,
342
+ holder: str | None = None,
343
+ ) -> None: ...
344
+
345
+ async def aclose(self) -> None: ...
346
+
347
+
348
+ def select_cases(cases: list[CaseView], selection: Selection) -> list[CaseView]:
349
+ if selection.all:
350
+ return list(cases)
351
+ if selection.tag:
352
+ return [case for case in cases if selection.tag in case.split_tags]
353
+ wanted = set(selection.case_ids or [])
354
+ return [case for case in cases if case.case_id in wanted]
evalkit/store/blob.py ADDED
@@ -0,0 +1,69 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import AsyncIterator
4
+
5
+ import obstore
6
+ from obstore.exceptions import NotFoundError
7
+ from obstore.store import ObjectStore, from_url
8
+
9
+ from evalkit.store.base import BlobStream
10
+
11
+ CHUNK_BYTES = 1024 * 1024
12
+
13
+ _stores: dict[str, ObjectStore] = {}
14
+
15
+
16
+ def _store_for(url: str) -> ObjectStore:
17
+ if url not in _stores:
18
+ _stores[url] = from_url(url, mkdir=True) if url.startswith("file://") else from_url(url)
19
+ return _stores[url]
20
+
21
+
22
+ class Obstore:
23
+ def __init__(self, url: str):
24
+ self.url = url
25
+
26
+ @property
27
+ def _store(self) -> ObjectStore:
28
+ return _store_for(self.url)
29
+
30
+ async def put_object(self, key: str, data: bytes) -> None:
31
+ await obstore.put_async(self._store, key, data)
32
+
33
+ async def put_stream(self, key: str, chunks: AsyncIterator[bytes]) -> None:
34
+ await obstore.put_async(self._store, key, chunks)
35
+
36
+ async def get_object(self, key: str) -> bytes:
37
+ resp = await obstore.get_async(self._store, key)
38
+ return bytes(await resp.bytes_async())
39
+
40
+ async def get_stream(self, key: str) -> BlobStream:
41
+ resp = await obstore.get_async(self._store, key)
42
+ return BlobStream(resp.meta["size"], _chunks(resp.stream(min_chunk_size=CHUNK_BYTES)))
43
+
44
+ async def object_exists(self, key: str) -> bool:
45
+ try:
46
+ await obstore.head_async(self._store, key)
47
+ return True
48
+ except (NotFoundError, FileNotFoundError):
49
+ return False
50
+
51
+ async def list_objects(self, prefix: str) -> list[tuple[str, int]]:
52
+ objects: list[tuple[str, int]] = []
53
+ async for chunk in obstore.list(self._store, prefix=prefix):
54
+ objects.extend((obj["path"], obj["size"]) for obj in chunk)
55
+ return objects
56
+
57
+ async def delete_object(self, key: str) -> None:
58
+ await obstore.delete_async(self._store, key)
59
+
60
+ async def copy_object(self, source: str, destination: str) -> None:
61
+ await obstore.copy_async(self._store, source, destination)
62
+
63
+ async def object_url(self, key: str) -> str:
64
+ return f"{self.url.rstrip('/')}/{key}"
65
+
66
+
67
+ async def _chunks(stream: AsyncIterator) -> AsyncIterator[bytes]:
68
+ async for chunk in stream:
69
+ yield bytes(chunk)
evalkit/version.py ADDED
@@ -0,0 +1,44 @@
1
+ from __future__ import annotations
2
+
3
+ import importlib.metadata
4
+ import re
5
+ from enum import StrEnum
6
+ from typing import NamedTuple
7
+
8
+
9
+ class ParsedVersion(NamedTuple):
10
+ major: int
11
+ minor: int
12
+ patch: int
13
+ build_id: str | None
14
+
15
+
16
+ class VersionComparison(StrEnum):
17
+ SAME = "same"
18
+ DIFFERENT = "different"
19
+ INCOMPATIBLE = "incompatible"
20
+
21
+
22
+ DISTRIBUTION = "evalkit-py"
23
+ _VERSION = re.compile(r"(\d+)\.(\d+)\.(\d+)(?:\.(dev\d+))?(?:\+(.+))?")
24
+
25
+
26
+ def current() -> str:
27
+ return importlib.metadata.version(DISTRIBUTION)
28
+
29
+
30
+ def parse(version: str) -> ParsedVersion:
31
+ match = _VERSION.fullmatch(version)
32
+ if match is None:
33
+ raise ValueError(f"not an evalkit version: {version}")
34
+ major, minor, patch, dev, local = match.groups()
35
+ return ParsedVersion(int(major), int(minor), int(patch), dev or local)
36
+
37
+
38
+ def compare(local: str, remote: str) -> VersionComparison:
39
+ mine, theirs = parse(local), parse(remote)
40
+ if mine.major != theirs.major or (mine.major == 0 and mine.minor != theirs.minor):
41
+ return VersionComparison.INCOMPATIBLE
42
+ if local == remote:
43
+ return VersionComparison.SAME
44
+ return VersionComparison.DIFFERENT