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,300 @@
1
+ from typing import NamedTuple
2
+
3
+ from sqlalchemy import Select, func, select
4
+ from sqlalchemy.dialects.postgresql import aggregate_order_by, array_agg
5
+ from sqlalchemy.ext.asyncio import AsyncSession
6
+
7
+ from evalkit.contracts.enums import EvaluationSource, EvaluatorKind, RunStatus
8
+ from evalkit.core.scorecard import BUCKET_EVALUATOR, COST_GAUGE, EXCLUDED_FROM_BUCKETS
9
+ from evalkit.db import models
10
+ from evalkit.db.experiments import get_experiment, list_experiments
11
+ from evalkit.store.base import AggregateRows, HistoryPoint, Progress, RunState
12
+
13
+ Case, Evaluation, ExperimentRun, AgentRun = (
14
+ models.Case,
15
+ models.Evaluation,
16
+ models.ExperimentRun,
17
+ models.AgentRun,
18
+ )
19
+
20
+
21
+ def _source(source: str, producer: str) -> str:
22
+ return "builtin" if source == EvaluationSource.BUILTIN.value else f"custom:{producer}"
23
+
24
+
25
+ def _scores(exp_ids: list[int]) -> Select:
26
+ return (
27
+ select(
28
+ ExperimentRun.experiment_id,
29
+ Case.case_id,
30
+ Evaluation.name,
31
+ func.avg(Evaluation.value),
32
+ array_agg(aggregate_order_by(Evaluation.explanation, ExperimentRun.repetition))[1],
33
+ func.min(Evaluation.bucket),
34
+ )
35
+ .join(ExperimentRun, ExperimentRun.id == Evaluation.experiment_run_id)
36
+ .join(Case, Case.id == ExperimentRun.case_ref)
37
+ .where(
38
+ ExperimentRun.experiment_id.in_(exp_ids),
39
+ Evaluation.error.is_(None),
40
+ Evaluation.kind == EvaluatorKind.SCORE.value,
41
+ Evaluation.value.is_not(None),
42
+ )
43
+ .group_by(ExperimentRun.experiment_id, Case.case_id, Evaluation.name)
44
+ )
45
+
46
+
47
+ async def aggregate(session: AsyncSession, exp_id: int) -> AggregateRows:
48
+ experiment = await get_experiment(session, exp_id)
49
+ scores = await session.execute(_scores([exp_id]))
50
+ gauges = await session.execute(
51
+ select(Case.case_id, Evaluation.name, func.avg(Evaluation.value))
52
+ .join(ExperimentRun, ExperimentRun.id == Evaluation.experiment_run_id)
53
+ .join(Case, Case.id == ExperimentRun.case_ref)
54
+ .where(
55
+ ExperimentRun.experiment_id == exp_id,
56
+ Evaluation.error.is_(None),
57
+ Evaluation.kind == EvaluatorKind.GAUGE.value,
58
+ Evaluation.value.is_not(None),
59
+ )
60
+ .group_by(Case.case_id, Evaluation.name)
61
+ )
62
+ errors = await session.execute(
63
+ select(Case.case_id, Evaluation.name, func.max(Evaluation.error))
64
+ .join(ExperimentRun, ExperimentRun.id == Evaluation.experiment_run_id)
65
+ .join(Case, Case.id == ExperimentRun.case_ref)
66
+ .where(ExperimentRun.experiment_id == exp_id, Evaluation.error.is_not(None))
67
+ .group_by(Case.case_id, Evaluation.name)
68
+ )
69
+ runs = (
70
+ await session.execute(
71
+ select(Case.case_id, ExperimentRun.repetition, AgentRun.error)
72
+ .join(Case, Case.id == ExperimentRun.case_ref)
73
+ .join(AgentRun, AgentRun.id == ExperimentRun.agent_run_id)
74
+ .where(ExperimentRun.experiment_id == exp_id)
75
+ .order_by(Case.case_id, ExperimentRun.repetition)
76
+ )
77
+ ).all()
78
+ sources = await session.execute(
79
+ select(Evaluation.name, Evaluation.source, Evaluation.producer)
80
+ .join(ExperimentRun, ExperimentRun.id == Evaluation.experiment_run_id)
81
+ .where(ExperimentRun.experiment_id == exp_id)
82
+ .distinct()
83
+ )
84
+ repetitions: dict[str, int] = {}
85
+ for case_id, _, _ in runs:
86
+ repetitions[case_id] = repetitions.get(case_id, 0) + 1
87
+ return AggregateRows(
88
+ experiment=experiment,
89
+ case_scores=[(c, n, float(m), e, b) for _, c, n, m, e, b in scores.all()],
90
+ case_gauges=[(c, n, float(m)) for c, n, m in gauges.all()],
91
+ case_errors=[(c, n, e) for c, n, e in errors.all()],
92
+ run_errors=[(c, e) for c, _, e in runs if e],
93
+ repetitions_seen=repetitions,
94
+ sources={name: _source(source, producer) for name, source, producer in sources.all()},
95
+ )
96
+
97
+
98
+ FINISHED = frozenset(
99
+ {RunStatus.COMPLETED, RunStatus.FAILED, RunStatus.TIMEOUT, RunStatus.CANCELLED}
100
+ )
101
+
102
+
103
+ class RunFacts(NamedTuple):
104
+ finished: bool
105
+ scorable: bool
106
+ evaluated: bool
107
+
108
+
109
+ def case_state(repetitions: int, runs: list[RunFacts]) -> RunState:
110
+ finished = [run for run in runs if run.finished]
111
+ if not finished:
112
+ return "pending"
113
+ if len(finished) < repetitions:
114
+ return "ran"
115
+ if all(run.evaluated for run in finished if run.scorable):
116
+ return "evaluated"
117
+ return "ran"
118
+
119
+
120
+ async def case_states_many(
121
+ session: AsyncSession, exp_ids: list[int]
122
+ ) -> dict[int, dict[str, RunState]]:
123
+ if not exp_ids:
124
+ return {}
125
+ repetitions: dict[int, int] = {
126
+ exp_id: reps
127
+ for exp_id, reps in (
128
+ await session.execute(
129
+ select(models.Experiment.id, models.Experiment.repetitions).where(
130
+ models.Experiment.id.in_(exp_ids)
131
+ )
132
+ )
133
+ ).all()
134
+ }
135
+ pinned = await session.execute(
136
+ select(models.ExperimentCase.experiment_id, Case.case_id)
137
+ .join(Case, Case.id == models.ExperimentCase.case_ref)
138
+ .where(models.ExperimentCase.experiment_id.in_(exp_ids))
139
+ )
140
+ has_evaluation = (
141
+ select(Evaluation.id).where(Evaluation.experiment_run_id == ExperimentRun.id).exists()
142
+ )
143
+ runs = await session.execute(
144
+ select(
145
+ ExperimentRun.experiment_id,
146
+ Case.case_id,
147
+ AgentRun.status,
148
+ AgentRun.error.is_(None) | AgentRun.output.is_not(None),
149
+ has_evaluation,
150
+ )
151
+ .join(Case, Case.id == ExperimentRun.case_ref)
152
+ .join(AgentRun, AgentRun.id == ExperimentRun.agent_run_id)
153
+ .where(ExperimentRun.experiment_id.in_(exp_ids))
154
+ )
155
+ facts: dict[tuple[int, str], list[RunFacts]] = {}
156
+ for exp_id, case_id, status, scorable, evaluated in runs.all():
157
+ facts.setdefault((exp_id, case_id), []).append(
158
+ RunFacts(RunStatus(status) in FINISHED, bool(scorable), bool(evaluated))
159
+ )
160
+ out: dict[int, dict[str, RunState]] = {exp_id: {} for exp_id in exp_ids}
161
+ for exp_id, case_id in pinned.all():
162
+ out[exp_id][case_id] = case_state(repetitions[exp_id], facts.get((exp_id, case_id), []))
163
+ return out
164
+
165
+
166
+ async def case_states(session: AsyncSession, exp_id: int) -> dict[str, RunState]:
167
+ await get_experiment(session, exp_id)
168
+ return (await case_states_many(session, [exp_id]))[exp_id]
169
+
170
+
171
+ def _progress(states: dict[str, RunState]) -> Progress:
172
+ return Progress(
173
+ total=len(states),
174
+ ran=sum(1 for s in states.values() if s != "pending"),
175
+ evaluated=sum(1 for s in states.values() if s == "evaluated"),
176
+ )
177
+
178
+
179
+ async def progress(session: AsyncSession, exp_id: int) -> Progress:
180
+ return _progress(await case_states(session, exp_id))
181
+
182
+
183
+ async def progress_many(session: AsyncSession, exp_ids: list[int]) -> dict[int, Progress]:
184
+ return {
185
+ exp_id: _progress(states)
186
+ for exp_id, states in (await case_states_many(session, exp_ids)).items()
187
+ }
188
+
189
+
190
+ async def list_scores(
191
+ session: AsyncSession, exp_ids: list[int]
192
+ ) -> dict[int, dict[str, float | None]]:
193
+ if not exp_ids:
194
+ return {}
195
+ per_name: dict[tuple[int, str, str], list[float]] = {}
196
+ for exp_id, _, name, mean, _, bucket in (await session.execute(_scores(exp_ids))).all():
197
+ if bucket is not None and name not in EXCLUDED_FROM_BUCKETS:
198
+ per_name.setdefault((exp_id, bucket, name), []).append(float(mean))
199
+ by_bucket: dict[tuple[int, str], list[float]] = {}
200
+ for (exp_id, bucket, _), means in per_name.items():
201
+ by_bucket.setdefault((exp_id, bucket), []).append(sum(means) / len(means))
202
+ out: dict[int, dict[str, float | None]] = {exp_id: {} for exp_id in exp_ids}
203
+ for (exp_id, bucket), values in by_bucket.items():
204
+ out[exp_id][bucket] = sum(values) / len(values)
205
+ return out
206
+
207
+
208
+ async def case_history(
209
+ session: AsyncSession,
210
+ dataset_id: int,
211
+ case_ids: list[str] | None,
212
+ *,
213
+ limit: int,
214
+ offset: int = 0,
215
+ ) -> dict[str, list[HistoryPoint]]:
216
+ experiments = await list_experiments(
217
+ session, dataset_id=dataset_id, ran_case_ids=case_ids, limit=limit, offset=offset
218
+ )
219
+ if not experiments:
220
+ return {}
221
+ wanted = {*BUCKET_EVALUATOR.values(), COST_GAUGE}
222
+ query = (
223
+ select(
224
+ ExperimentRun.experiment_id, Case.case_id, Evaluation.name, func.avg(Evaluation.value)
225
+ )
226
+ .join(ExperimentRun, ExperimentRun.id == Evaluation.experiment_run_id)
227
+ .join(Case, Case.id == ExperimentRun.case_ref)
228
+ .where(
229
+ ExperimentRun.experiment_id.in_([e.id for e in experiments]),
230
+ Evaluation.name.in_(wanted),
231
+ Evaluation.error.is_(None),
232
+ Evaluation.value.is_not(None),
233
+ )
234
+ .group_by(ExperimentRun.experiment_id, Case.case_id, Evaluation.name)
235
+ )
236
+ ran = (
237
+ select(ExperimentRun.experiment_id, Case.case_id)
238
+ .join(Case, Case.id == ExperimentRun.case_ref)
239
+ .where(ExperimentRun.experiment_id.in_([e.id for e in experiments]))
240
+ .distinct()
241
+ )
242
+ if case_ids is not None:
243
+ query = query.where(Case.case_id.in_(case_ids))
244
+ ran = ran.where(Case.case_id.in_(case_ids))
245
+ means: dict[tuple[int, str], dict[str, float]] = {}
246
+ for exp_id, case_id, name, mean in (await session.execute(query)).all():
247
+ means.setdefault((exp_id, case_id), {})[name] = float(mean)
248
+ seen = set((await session.execute(ran)).all())
249
+ out: dict[str, list[HistoryPoint]] = {}
250
+ for exp in experiments:
251
+ for exp_id, case_id in sorted(k for k in seen if k[0] == exp.id):
252
+ values = means.get((exp_id, case_id), {})
253
+ out.setdefault(case_id, []).append(
254
+ HistoryPoint(
255
+ experiment_id=exp.id,
256
+ number=exp.number,
257
+ agent=exp.agent,
258
+ model=exp.config.model,
259
+ created_by=exp.created_by,
260
+ created_at=exp.started_at,
261
+ repetitions=exp.repetitions,
262
+ scores={bucket: values.get(name) for bucket, name in BUCKET_EVALUATOR.items()},
263
+ cost_usd=values.get(COST_GAUGE),
264
+ )
265
+ )
266
+ return out
267
+
268
+
269
+ async def list_costs(
270
+ session: AsyncSession, exp_ids: list[int]
271
+ ) -> dict[int, dict[str, float | None]]:
272
+ if not exp_ids:
273
+ return {}
274
+ costs = await session.execute(
275
+ select(ExperimentRun.experiment_id, func.avg(Evaluation.value))
276
+ .join(ExperimentRun, ExperimentRun.id == Evaluation.experiment_run_id)
277
+ .where(
278
+ ExperimentRun.experiment_id.in_(exp_ids),
279
+ Evaluation.name == COST_GAUGE,
280
+ Evaluation.error.is_(None),
281
+ )
282
+ .group_by(ExperimentRun.experiment_id)
283
+ )
284
+ latencies = await session.execute(
285
+ select(
286
+ ExperimentRun.experiment_id,
287
+ func.avg(func.extract("epoch", AgentRun.ended_at - AgentRun.started_at) * 1000),
288
+ )
289
+ .join(AgentRun, AgentRun.id == ExperimentRun.agent_run_id)
290
+ .where(ExperimentRun.experiment_id.in_(exp_ids), AgentRun.ended_at.is_not(None))
291
+ .group_by(ExperimentRun.experiment_id)
292
+ )
293
+ out: dict[int, dict[str, float | None]] = {
294
+ exp_id: {"cost_usd": None, "avg_latency_ms": None} for exp_id in exp_ids
295
+ }
296
+ for exp_id, cost in costs.all():
297
+ out[exp_id]["cost_usd"] = float(cost) if cost is not None else None
298
+ for exp_id, latency in latencies.all():
299
+ out[exp_id]["avg_latency_ms"] = float(latency) if latency is not None else None
300
+ return out
evalkit/db/session.py ADDED
@@ -0,0 +1,71 @@
1
+ import asyncio
2
+ from pathlib import Path
3
+
4
+ from alembic import command
5
+ from alembic.config import Config as AlembicConfig
6
+ from alembic.script import ScriptDirectory
7
+ from sqlalchemy import text
8
+ from sqlalchemy.ext.asyncio import (
9
+ AsyncSession,
10
+ async_sessionmaker,
11
+ create_async_engine,
12
+ )
13
+ from sqlalchemy.pool import NullPool
14
+
15
+
16
+ def make_session_factory(db_url: str) -> async_sessionmaker[AsyncSession]:
17
+ engine = create_async_engine(db_url)
18
+ return async_sessionmaker(engine, expire_on_commit=False)
19
+
20
+
21
+ def run_migrations(db_url: str, revision: str = "head") -> None:
22
+ cfg = AlembicConfig()
23
+ cfg.set_main_option("script_location", str(Path(__file__).parent / "alembic"))
24
+ cfg.set_main_option("sqlalchemy.url", db_url)
25
+ command.upgrade(cfg, revision)
26
+
27
+
28
+ MIGRATION_LOCK_KEY = 7_302_015_486_123_001
29
+
30
+
31
+ async def migrate_under_lock(db_url: str) -> None:
32
+ engine = create_async_engine(db_url, poolclass=NullPool)
33
+ async with engine.connect() as conn:
34
+ await conn.execute(text("SELECT pg_advisory_lock(:key)"), {"key": MIGRATION_LOCK_KEY})
35
+ await asyncio.to_thread(run_migrations, db_url)
36
+ await conn.execute(text("SELECT pg_advisory_unlock(:key)"), {"key": MIGRATION_LOCK_KEY})
37
+ await engine.dispose()
38
+
39
+
40
+ def downgrade_migrations(db_url: str, revision: str) -> None:
41
+ cfg = AlembicConfig()
42
+ cfg.set_main_option("script_location", str(Path(__file__).parent / "alembic"))
43
+ cfg.set_main_option("sqlalchemy.url", db_url)
44
+ command.downgrade(cfg, revision)
45
+
46
+
47
+ def head_revision() -> str:
48
+ script = ScriptDirectory(str(Path(__file__).parent / "alembic"))
49
+ head = script.get_current_head()
50
+ assert head is not None
51
+ return head
52
+
53
+
54
+ async def verify_schema(db_url: str) -> None:
55
+ engine = create_async_engine(db_url)
56
+ try:
57
+ async with engine.connect() as conn:
58
+ result = await conn.execute(text("SELECT version_num FROM alembic_version"))
59
+ current = result.scalar_one_or_none()
60
+ except Exception as exc:
61
+ raise RuntimeError(
62
+ "auth schema not initialized — run `evalkit db upgrade --config <config>`"
63
+ ) from exc
64
+ finally:
65
+ await engine.dispose()
66
+ head = head_revision()
67
+ if current != head:
68
+ raise RuntimeError(
69
+ f"auth schema is at revision {current!r}, expected {head!r} — "
70
+ "run `evalkit db upgrade --config <config>`"
71
+ )
evalkit/db/sessions.py ADDED
@@ -0,0 +1,90 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from collections.abc import AsyncIterator
5
+ from datetime import UTC, datetime
6
+ from typing import Literal
7
+
8
+ from evalkit.config import OtelConfig
9
+ from evalkit.contracts.esf import MappingDocument
10
+ from evalkit.core.agents import AgentDefinition, explicit
11
+ from evalkit.core.traces.raw import RawSpan
12
+ from evalkit.core.traces.sessions import (
13
+ SessionBuilder,
14
+ SessionTooLarge,
15
+ SessionTrajectory,
16
+ later_llm_spans,
17
+ probe_attributes,
18
+ )
19
+ from evalkit.core.workspace import parse_slug
20
+ from evalkit.db.agents import AgentStore
21
+ from evalkit.db.mappings import MappingStore
22
+ from evalkit.db.spans import AttributeDrop, SpanStore
23
+
24
+ CONCURRENT_READS = 2
25
+
26
+
27
+ def _mib(size: int) -> str:
28
+ return f"{size / (1024 * 1024):.1f} MiB"
29
+
30
+
31
+ class DbSessionReader:
32
+ def __init__(
33
+ self, agents: AgentStore, spans: SpanStore, mappings: MappingStore, otel: OtelConfig
34
+ ):
35
+ self._agents = agents
36
+ self._spans = spans
37
+ self._mappings = mappings
38
+ self._otel = otel
39
+ self._reads = asyncio.Semaphore(CONCURRENT_READS)
40
+
41
+ async def agent(self, agent_slug: str) -> AgentDefinition:
42
+ return await self._agents.get(explicit(parse_slug(agent_slug)))
43
+
44
+ def raw(self, record: AgentDefinition, session_id: str) -> AsyncIterator[RawSpan]:
45
+ return self._spans.stream_session_spans(record.id, session_id)
46
+
47
+ async def read(
48
+ self,
49
+ agent_slug: str,
50
+ session_id: str,
51
+ *,
52
+ mapping: Literal["active", "draft"] = "active",
53
+ include_esf: bool = False,
54
+ ) -> SessionTrajectory | None:
55
+ record = await self.agent(agent_slug)
56
+ chosen = await (
57
+ self._mappings.draft(record.id)
58
+ if mapping == "draft"
59
+ else self._mappings.active(record.id)
60
+ )
61
+ document = MappingDocument.model_validate(chosen.document) if chosen else None
62
+ async with self._reads, self._spans.read_session(record.id, session_id) as rows:
63
+ probes = await rows.probes(probe_attributes(document))
64
+ later = later_llm_spans([span for _, span in probes], document)
65
+ drop = AttributeDrop([probes[i][0] for i in later.positions], later.context)
66
+ size = await rows.attribute_bytes(drop)
67
+ limit = self._otel.max_session_bytes
68
+ if size > limit:
69
+ raise SessionTooLarge(
70
+ f"session {session_id} of agent {agent_slug} holds {_mib(size)} of span "
71
+ f"attributes, over this server's otel.max_session_bytes ({_mib(limit)}); "
72
+ "ask the deployment's admin to raise the limit (and the server's memory), "
73
+ "or record less per span"
74
+ )
75
+ builder = SessionBuilder(document)
76
+ async for span in rows.stream(drop):
77
+ builder.add(span)
78
+ return builder.build(
79
+ agent_name=record.name,
80
+ mapping_version=chosen.version if chosen else None,
81
+ now=datetime.now(UTC),
82
+ settle_seconds=self._otel.settle_seconds,
83
+ include_esf=include_esf,
84
+ )
85
+
86
+ async def trajectory(self, agent: str, session_id: str) -> SessionTrajectory:
87
+ result = await self.read(agent, session_id)
88
+ if result is None:
89
+ return SessionTrajectory(settled=False, root_present=False, span_count=0)
90
+ return result