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,296 @@
1
+ ---
2
+ name: connect-traces
3
+ description: Use when wiring a client's OpenTelemetry traces into evalkit so run_experiment or a harness run gets trajectories, when creating an OTel agent (it needs a span mapping), or when `evalkit traces check` shows wrong span kinds, empty messages or missing tokens.
4
+ ---
5
+
6
+ # connect-traces
7
+
8
+ ## Overview
9
+
10
+ evalkit scores an agent on its **trajectory**: the LLM calls, messages, tool
11
+ calls and token counts of one run. When the agent emits OpenTelemetry spans,
12
+ evalkit builds that trajectory from the spans itself: the agent exports every
13
+ span to the evalkit server (the **collector**), the server groups the spans of
14
+ one run into an **agent session** by the `session.id` attribute, reads each
15
+ span into the evalkit span format (**ESF**) with a **mapping**, and converts
16
+ the session to ATIF. Nothing in the client's code converts anything.
17
+
18
+ Your job ends when `evalkit traces check` shows the right span kinds,
19
+ messages, tool calls and tokens for one session. Scoring, scorecards and the
20
+ ATIF conversion are evalkit's side and need nothing from you.
21
+
22
+ Traces replace the trajectory only. The files a run wrote (the run's
23
+ Workspace tab in evalkit) come from the Harness API files endpoints, which
24
+ spans do not carry. If the developer wants that tab, the agent needs a
25
+ Harness API with those endpoints (see the evalkit-usage skill).
26
+
27
+ Every OTel agent has its own mapping, set when the agent is created. Two
28
+ starting points ship in `references/`: `openinference.json` for spans with
29
+ `openinference.span.kind`, and `gen_ai.json` for spans with
30
+ `gen_ai.operation.name`. Copy the one that
31
+ fits and change it if the agent's attributes differ. The mapping also holds
32
+ two run-level settings:
33
+
34
+ - `answer`: where the run's answer comes from. `root` (the usual value), a
35
+ span name, or `<span name>.<output key>`.
36
+ - `exclude_spans`: span names left out of the trajectory.
37
+
38
+ A span the agent's mapping cannot read is not an error: it comes out as kind
39
+ `other` with every attribute listed as unmapped, and the trajectory simply
40
+ lacks it. That is what a wrong mapping looks like in the check.
41
+
42
+ ## Steps
43
+
44
+ 1. **Identify the instrumentation.** Grep the repository for `openinference`
45
+ and `gen_ai.`. Note which one applies, or neither. Then make sure the
46
+ instrumentation records message content: without it evalkit gets token
47
+ counts but no messages, tool arguments or results, and the trajectory is
48
+ close to empty. The GenAI conventions turn content capture off by
49
+ default; the usual switches are:
50
+
51
+ | Instrumentation | Switch |
52
+ | -- | -- |
53
+ | OpenTelemetry GenAI instrumentations (Python `opentelemetry-instrumentation-openai-v2`, Google GenAI, Vertex AI, …) | `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true` |
54
+ | OpenInference | on by default; check `OPENINFERENCE_HIDE_INPUTS` / `OPENINFERENCE_HIDE_OUTPUTS` (and the `_MESSAGES` variants) are not `true` |
55
+ | OpenLLMetry (Traceloop) | on by default; check `TRACELOOP_TRACE_CONTENT` is not `false` |
56
+ | Vercel AI SDK | `experimental_telemetry: { isEnabled: true }`; `recordInputs` / `recordOutputs` default to on |
57
+
58
+ Turn it on wherever spans are exported to evalkit: the process that runs
59
+ the eval, and any deployed agent or worker those runs call. Whether a
60
+ deployed agent also exports its app traffic (runs outside any experiment:
61
+ production, staging, or by hand) is the developer's choice; ask them.
62
+ evalkit shows app sessions on the Runs page too, and `evalkit runs pull
63
+ <agent> --source app` downloads them. Exporting app traffic is also what
64
+ lets the eval-driven-development skill mine new cases from real runs
65
+ (its Loop 2).
66
+ To export only eval runs, see "Choosing what a shared worker exports"
67
+ below.
68
+ 2. **Create the agent with a mapping.** Copy the starting point from
69
+ step 1 into the repo and create the agent with it. Add `--harness-url`
70
+ when the agent also has a Harness API; leave it out for a code-driven
71
+ agent.
72
+
73
+ ```bash
74
+ cp <this skill>/references/openinference.json eval/span-mapping.json
75
+ evalkit agents create <agent> --trajectory-source otel --mapping eval/span-mapping.json
76
+ ```
77
+
78
+ The agent must exist before any span arrives: the collector refuses spans
79
+ for an unknown agent, and neither a token nor the first export creates
80
+ one.
81
+ 3. **Register the exporter.** *After* the client's own tracer provider is set
82
+ up, add
83
+
84
+ ```python
85
+ from evalkit.sdk import tracing
86
+
87
+ tracing.register(agent="<agent name>")
88
+ ```
89
+
90
+ `register` adds an exporter to the provider that exists; placed before the
91
+ client's setup it creates a second provider and the agent's spans never
92
+ reach it. It needs the `otel` extra (`uv add "evalkit-py[otel]==<server version>"`).
93
+ When the client builds its own pipeline and should not touch the global
94
+ provider, use the parts `register` is made of:
95
+ `tracing.processor(agent=...)` returns evalkit's batch processor (it also
96
+ stamps the run's `session.id` and `evalkit.*` attributes),
97
+ `tracing.exporter(agent=...)` the OTLP HTTP exporter inside it, and
98
+ `tracing.headers(agent=...)` its headers. All three read the server URL
99
+ and token like `register` does, `EVALKIT_OTEL_TOKEN` first.
100
+ `register` only sees spans that pass through the provider's span
101
+ processors. Code that hands spans straight to one processor or exporter
102
+ (a bridge that converts another tool's spans, for example) bypasses it;
103
+ give that code `tracing.processor(...)` as well, or one
104
+ `SynchronousMultiSpanProcessor` that holds every processor, evalkit's
105
+ included. Such spans are already finished, so the processor cannot stamp
106
+ them: the bridge copies `session.id` onto each span it converts.
107
+ A non-Python agent, or any exporter outside the process that calls
108
+ `run_experiment`, sets
109
+ `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=<server>/api/otel/v1/traces` and
110
+ `OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer <token>,X-Evalkit-Agent=<agent>"`
111
+ instead, with an agent token from `evalkit tokens create --agent <agent>`.
112
+ The login token expires and a long-running worker then loses every span
113
+ without an error of its own. One process that serves several agents can
114
+ name the agent per span or per resource with the `evalkit.agent`
115
+ attribute; the header is the default for spans that carry none.
116
+ LLM spans that carry the full input of every call (OpenInference and
117
+ GenAI instrumentations do) are large, so also set
118
+ `OTEL_BSP_MAX_EXPORT_BATCH_SIZE=16` and `OTEL_EXPORTER_OTLP_TIMEOUT=60`
119
+ on every process that exports (seconds in Python; other SDKs read
120
+ milliseconds, `60000`). The server refuses a batch over
121
+ `otel.max_batch_bytes` (16 MiB by default) with `413` and the spans are
122
+ lost, and the default 10 s timeout is too short for multi-MB spans.
123
+ 4. **Run one session.** `run_experiment(..., dry_run=True)` runs one case,
124
+ creates no experiment, and prints the session id (`session <id>: N spans
125
+ ...`). The agent's own entry point works too; the Runs page lists the
126
+ session either way.
127
+ 5. **Check it.**
128
+
129
+ ```bash
130
+ evalkit traces check <agent> <session id> --dump spans.json
131
+ ```
132
+
133
+ Read the lines against this table. `spans.json` holds the raw attributes.
134
+
135
+ | Line | What it tells you |
136
+ | -- | -- |
137
+ | `session` | span count, trace count, settled or not |
138
+ | `root` | the root span's name and kind; missing root means the session id is not on the root span |
139
+ | `mapping` | the active version, `vN` |
140
+ | `llm` | spans read as `llm`, the model, token totals; `no llm spans` means the kind rule does not match; `without messages` means those spans carry no messages, usually because message content capture is off |
141
+ | `tools` | spans read as `tool`, and how many carry a `tool_call_id` that matches a call the LLM spans emitted; a gap means tool spans exist but their call ids are not read, so results only match by time and order; `in no step` names tool spans that started before any LLM span and so are not in the trajectory |
142
+ | `unmapped` | attributes no rule read, apart from the mapping's `known_attributes` |
143
+ | `trajectory` | ATIF steps, tool calls, subagents |
144
+
145
+ Then check the agent's top-level span is an AGENT span
146
+ (`openinference.span.kind=AGENT` or `gen_ai.operation.name=invoke_agent`).
147
+ evalkit builds the main trajectory from it, and every AGENT span inside it
148
+ becomes a subagent named by its `agent.name` (`gen_ai.agent.name`). When
149
+ the root span is not an AGENT span, evalkit takes the earliest AGENT span
150
+ that is not inside another one as the main agent. If that span is a tool
151
+ call that starts a subagent partway through the run, the subagent's steps
152
+ end up in the main trajectory and its call has no result. Fix that in the
153
+ agent's instrumentation: mark its top-level span as an AGENT span.
154
+
155
+ If the check fails with `413` and names `otel.max_session_bytes`, the
156
+ session holds more span attributes than the server will build into a
157
+ trajectory (384 MiB by default). The limit counts what a build loads: the
158
+ input messages of each agent's first LLM call, and the output, tool calls
159
+ and tokens of every LLM call, not the input of later calls. Check a shorter session, and tell the
160
+ developer: the deployment's admin can raise the limit together with the
161
+ server's memory.
162
+
163
+ When the lines look right, stop.
164
+ 6. **Fix the mapping** when they do not. Edit `eval/span-mapping.json` (it is
165
+ JSON, one rule per ESF field) and change the attribute keys to the ones in
166
+ `spans.json`.
167
+ `references/span-mapping-schema.md` explains every rule shape and the
168
+ three message formats. Push it as a draft and check with it:
169
+
170
+ ```bash
171
+ evalkit traces mapping push <agent> eval/span-mapping.json
172
+ evalkit traces check <agent> <session id> --mapping draft
173
+ ```
174
+
175
+ Repeat until the unmapped list holds nothing that matters and the counts
176
+ are right. A push replaces the previous draft and gets the next version.
177
+ 7. **Activation needs the developer's approval.** If the developer has
178
+ approved the document in this conversation, run
179
+ `evalkit traces mapping push <agent> eval/span-mapping.json --activate`.
180
+ Otherwise tell them to review it on the agent's Mappings tab (Agents →
181
+ the agent → Mappings in the web UI) and activate it there. Green check
182
+ output is not approval; a mapping applies to every future run of the agent.
183
+
184
+ ## An agent in another process
185
+
186
+ `tracing.register` stamps `session.id` and the `evalkit.*` attributes only on
187
+ spans made in the process that calls `run_experiment`. An agent behind HTTP
188
+ or a job queue, or written in another language, joins the run in one of two
189
+ ways. Pick one, not both.
190
+
191
+ - **Continue the trace.** The task injects the W3C trace context into the
192
+ request (`opentelemetry.propagate.inject(headers)`) and the agent starts its
193
+ spans from it (`traceparent`). Every span in a trace belongs to the session
194
+ of the trace's root, the SDK's `evalkit.run` span, even when the agent
195
+ stamps its own `session.id` or `gen_ai.conversation.id`. The task returns
196
+ only the answer.
197
+ - **Return the agent's session.** The agent puts its own session id on its
198
+ root span as `session.id`, and the task returns
199
+ `RunResult(answer=..., session_id=<that id>)`. Use this when the trace
200
+ context cannot reach the agent, for example through a queue. The SDK moves
201
+ its `evalkit.run` span into that session so no empty session is left
202
+ behind, and the server builds the trajectory from the agent's trace.
203
+
204
+ Either way the run's row on the Runs page links the session to its case.
205
+
206
+ A queue-backed agent usually opens its session in the worker, after the API
207
+ call has returned. Two ways to get the session id to evalkit, no new field
208
+ needed on either path:
209
+
210
+ - **Code-driven (`run_experiment`).** The task returns
211
+ `RunResult(session_id=...)` with whatever id the agent's own API returns.
212
+ If the API cannot return one, the task passes `metadata["session_id"]`
213
+ (the SDK's own session id) along with the job, and the agent uses it as
214
+ its session id; the task then returns only the answer.
215
+ - **Harness API with an `otel` trajectory source.** The session evalkit polls is the `run_id`
216
+ that `POST /runs` returns. Return the agent's own session id as `run_id`,
217
+ or stamp the returned `run_id` on the job's spans as `session.id`.
218
+
219
+ ## Choosing what a shared worker exports
220
+
221
+ A worker that serves app and eval runs exports every span it makes, so each
222
+ app turn also becomes a session on the evalkit server, where
223
+ the developer can browse it on the Runs page. That is a valid setup; ask the
224
+ developer whether they want it. evalkit provides the stamping to tell eval
225
+ runs apart either way. To export only the eval runs:
226
+
227
+ ```python
228
+ from evalkit.sdk import tracing
229
+
230
+ provider.add_span_processor(tracing.processor(agent="<agent>", only=tracing.is_eval_span))
231
+
232
+
233
+ def handle_job(job):
234
+ if job.evalkit: # the task's metadata, sent with the job
235
+ with tracing.eval_run(job.evalkit):
236
+ return run_agent(job)
237
+ return run_agent(job)
238
+ ```
239
+
240
+ `eval_run` stamps `session.id` (the SDK's session id) and the `evalkit.*`
241
+ attributes on every span started inside it, so those spans also join the
242
+ run's session. `is_eval_span` is true for a span that carries
243
+ `evalkit.case_id`. Spans started in another thread need that thread inside
244
+ `eval_run` too. Do not use a sampler: it drops spans for every exporter, the
245
+ client's own backend included.
246
+
247
+ A harness agent learns that a run is an eval run from the `metadata` of
248
+ `POST /runs` (`experiment_id`, `case_id`, `repetition`). That is what it
249
+ passes to `eval_run`, with the `run_id` it returns as the session id:
250
+ `tracing.eval_run({**metadata, "session_id": run_id})`.
251
+
252
+ `only` decides by trace. It runs on each span as it starts and as it ends;
253
+ once it is true for one span, the processor keeps every span of that trace
254
+ that reaches it, including finished spans a bridge hands straight to
255
+ `processor.on_end` and the job's spans started before `eval_run`. Other
256
+ traces are dropped. A custom `only` picks whole traces the same way.
257
+
258
+ - **Order.** A span is kept when its trace is already marked as the span
259
+ ends. The first span started inside `eval_run` marks the trace as it
260
+ starts, so spans that end before it and spans bridged later are kept. A
261
+ span that ends before any span of its trace was marked is dropped; a
262
+ bridge that may hand spans over that early can copy the `evalkit.*`
263
+ attributes onto them so each marks its own trace.
264
+ - **Bridges.** Still copy `session.id` onto every converted span: the server
265
+ takes a trace's session from its root span when the root reaches it, and
266
+ from each span's own `session.id` otherwise.
267
+ - **Memory.** The processor remembers the 10,000 most recently used eval
268
+ traces and forgets the oldest.
269
+ - **Other processes.** Spans from another process in the same trace (an MCP
270
+ gateway pod, for example) never reach this processor; they go through that
271
+ process's own exporter. That process makes its own choice: continue the
272
+ trace, wrap its work in `eval_run` with the run's metadata sent along with
273
+ the request and filter with `only=tracing.is_eval_span`, or export
274
+ everything. Ask the developer which.
275
+
276
+ A worker in another language does the same with its own processor: forward
277
+ a span to the evalkit exporter only when its trace has a span carrying an
278
+ attribute the worker set on eval jobs.
279
+
280
+ ## Capabilities of a code-driven agent
281
+
282
+ A code-driven agent has no capabilities endpoint, so evalkit records
283
+ `thinking: false` (and `artifacts`, `workspace` false) for it and never reads
284
+ capabilities from spans. When the agent's spans carry the model's reasoning,
285
+ set it on the agent:
286
+
287
+ ```bash
288
+ evalkit agents edit <agent> --provides thinking=true
289
+ ```
290
+
291
+ Declare only what works; evaluators gated on a flag trust it.
292
+
293
+ If the agent's spans cannot be expressed with the rule shapes in the schema
294
+ reference, open an evalkit issue rather than working around it.
295
+
296
+ For bugs, feature requests and feedback on evalkit, open an issue at https://github.com/inferedge-ai/evalkit/issues; questions go to https://github.com/inferedge-ai/evalkit/discussions.
@@ -0,0 +1,42 @@
1
+ {
2
+ "schema_version": "1",
3
+ "kind": {
4
+ "attribute": "gen_ai.operation.name",
5
+ "values": {
6
+ "chat": "llm", "text_completion": "llm", "generate_content": "llm",
7
+ "embeddings": "other", "execute_tool": "tool", "invoke_agent": "agent",
8
+ "create_agent": "other"
9
+ }
10
+ },
11
+ "session_id": {"attribute": "gen_ai.conversation.id"},
12
+ "model": {"attribute": "gen_ai.request.model"},
13
+ "system_instructions": {"attribute": "gen_ai.system_instructions", "json": true},
14
+ "input_messages": {"attribute": "gen_ai.input.messages", "message_format": "gen_ai"},
15
+ "output_messages": {"attribute": "gen_ai.output.messages", "message_format": "gen_ai"},
16
+ "tokens": {
17
+ "prompt": {"attribute": "gen_ai.usage.input_tokens"},
18
+ "completion": {"attribute": "gen_ai.usage.output_tokens"},
19
+ "cached": {"attribute": "gen_ai.usage.cache_read.input_tokens"},
20
+ "cache_write": {"attribute": "gen_ai.usage.cache_creation.input_tokens"}
21
+ },
22
+ "cost_usd": null,
23
+ "tool": {
24
+ "name": {"attribute": "gen_ai.tool.name"},
25
+ "call_id": {"attribute": "gen_ai.tool.call.id"},
26
+ "arguments": {"attribute": "gen_ai.tool.call.arguments", "json": true},
27
+ "result": {"attribute": "gen_ai.tool.call.result"}
28
+ },
29
+ "agent_name": {"attribute": "gen_ai.agent.name"},
30
+ "input": {"attribute": "gen_ai.input.messages", "json": true},
31
+ "output": {"attribute": "gen_ai.output.messages", "json": true},
32
+ "known_attributes": [
33
+ "gen_ai.system", "gen_ai.provider.name", "gen_ai.agent.*", "gen_ai.main_agent.*",
34
+ "gen_ai.conversation.id", "gen_ai.conversation.compacted", "gen_ai.data_source.id",
35
+ "gen_ai.operation.name", "gen_ai.output.type", "gen_ai.prompt.*", "gen_ai.request.*",
36
+ "gen_ai.response.*", "gen_ai.skill.*", "gen_ai.system_instructions",
37
+ "gen_ai.token.modality", "gen_ai.tool.definitions", "gen_ai.tool.description",
38
+ "gen_ai.tool.type", "gen_ai.usage.reasoning.output_tokens", "gen_ai.usage.audio.*",
39
+ "gen_ai.usage.image.*", "gen_ai.usage.text.*", "gen_ai.workflow.name",
40
+ "server.address", "server.port", "error.type"
41
+ ]
42
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "schema_version": "1",
3
+ "kind": {
4
+ "attribute": "openinference.span.kind",
5
+ "values": {"LLM": "llm", "TOOL": "tool", "AGENT": "agent", "CHAIN": "chain", "RETRIEVER": "retriever"}
6
+ },
7
+ "session_id": {"attribute": "session.id"},
8
+ "model": {"attribute": "llm.model_name"},
9
+ "input_messages": {"attribute": "llm.input_messages", "message_format": "openinference"},
10
+ "output_messages": {"attribute": "llm.output_messages", "message_format": "openinference"},
11
+ "tokens": {
12
+ "prompt": {"attribute": "llm.token_count.prompt"},
13
+ "completion": {"attribute": "llm.token_count.completion"},
14
+ "cached": {"attribute": "llm.token_count.prompt_details.cache_read"},
15
+ "cache_write": {"attribute": "llm.token_count.prompt_details.cache_write"}
16
+ },
17
+ "cost_usd": {"attribute": "llm.cost.total"},
18
+ "tool": {
19
+ "name": {"attribute": "tool.name"},
20
+ "call_id": {"attribute": "tool.id"},
21
+ "arguments": {"attribute": "input.value", "json": true},
22
+ "result": {"attribute": "output.value"}
23
+ },
24
+ "agent_name": {"attribute": "agent.name"},
25
+ "input": {"attribute": "input.value", "json": true},
26
+ "output": {"attribute": "output.value", "json": true},
27
+ "known_attributes": [
28
+ "openinference.span.kind", "session.id", "user.id", "metadata", "tag.tags",
29
+ "input.mime_type", "output.mime_type", "llm.provider", "llm.system",
30
+ "llm.invocation_parameters", "llm.finish_reason", "llm.tools.*",
31
+ "llm.token_count.total", "llm.token_count.prompt_details.*",
32
+ "llm.token_count.completion_details.*", "llm.cost.*", "tool.description",
33
+ "tool.parameters", "tool.json_schema", "agent.name", "graph.node.*"
34
+ ]
35
+ }
@@ -0,0 +1,88 @@
1
+ # Span mapping schema (version 1)
2
+
3
+ A mapping is one JSON document with one rule per ESF field. Every mapping is
4
+ complete on its own; there is no inheritance. The JSON Schema ships as
5
+ `span-mapping-v1.json` with `evalkit contracts export`.
6
+
7
+ ```json
8
+ {
9
+ "schema_version": "1",
10
+ "kind": {"attribute": "...", "values": {"<raw>": "llm|tool|agent|chain|retriever|other"}},
11
+ "session_id": {"attribute": "..."},
12
+ "model": {"attribute": "..."},
13
+ "system_instructions": {"attribute": "...", "json": true},
14
+ "input_messages": {"attribute": "...", "message_format": "openinference|gen_ai|openai"},
15
+ "output_messages": {"attribute": "...", "message_format": "openinference|gen_ai|openai"},
16
+ "tokens": {
17
+ "prompt": {"attribute": "..."},
18
+ "completion": {"attribute": "..."},
19
+ "cached": {"attribute": "..."},
20
+ "cache_write": {"attribute": "..."}
21
+ },
22
+ "cost_usd": {"attribute": "..."},
23
+ "tool": {
24
+ "name": {"attribute": "..."},
25
+ "call_id": {"attribute": "..."},
26
+ "arguments": {"attribute": "...", "json": true},
27
+ "result": {"attribute": "..."}
28
+ },
29
+ "agent_name": {"attribute": "..."},
30
+ "input": {"attribute": "...", "json": true},
31
+ "output": {"attribute": "...", "json": true},
32
+ "known_attributes": ["...", "prefix.*"],
33
+ "answer": "root",
34
+ "exclude_spans": ["..."]
35
+ }
36
+ ```
37
+
38
+ Two fields apply to the whole run, not to one span:
39
+
40
+ - `answer` (default `root`): where the run's answer comes from. `root`, a
41
+ span name, or `<span name>.<output key>`.
42
+ - `exclude_spans` (default empty): span names left out of the trajectory.
43
+
44
+ ## Rule shapes
45
+
46
+ | Shape | What evalkit does |
47
+ | -- | -- |
48
+ | `{"attribute": K}` | reads attribute `K`; null when absent |
49
+ | `{"attribute": K, "json": true}` | reads `K` and parses it with `json.loads` when it is a string; a parse failure keeps the string |
50
+ | `{"attribute": K, "values": {...}}` | reads `K` and translates the value through the table; for `kind`, an unlisted value becomes `other` |
51
+ | `{"attribute": K, "message_format": F}` | collects the messages laid out per format `F` under `K` (see below) |
52
+ | `null` | the field is never read |
53
+
54
+ Which fields are read depends on the kind: `system_instructions`,
55
+ `input_messages`, `output_messages` and the token rules on `llm` spans; the `tool` rules on
56
+ `tool` spans, and `tool.call_id` on `agent` spans too (the call that started
57
+ a subagent); `agent_name` on `agent` spans (it names the subagent's
58
+ trajectory; the span name is used without it); `input` and `output` on everything that is not an llm span.
59
+ Attributes no rule read are reported as unmapped by `evalkit traces check`,
60
+ except those matching an entry of `known_attributes` (exact keys or glob
61
+ patterns such as `llm.tools.*`): list there the attributes you know about and
62
+ do not need.
63
+
64
+ `system_instructions` holds a system prompt kept outside the input messages,
65
+ as a string or a list of `{"type": "text", "content"}` parts; it becomes the
66
+ first input message, with role `system`. `tokens.cache_write` counts input
67
+ tokens written to the prompt cache; it lands in the step's
68
+ `metrics.extra.cache_creation_input_tokens`.
69
+
70
+ ## Message formats
71
+
72
+ - `openinference`: flattened indexed keys under the attribute prefix `K`:
73
+ `K.{i}.message.role`, `K.{i}.message.content`,
74
+ `K.{i}.message.tool_calls.{j}.tool_call.id`,
75
+ `K.{i}.message.tool_calls.{j}.tool_call.function.name`,
76
+ `K.{i}.message.tool_calls.{j}.tool_call.function.arguments`,
77
+ `K.{i}.message.tool_call_id`, and content parts
78
+ `K.{i}.message.contents.{j}.message_content.type` / `.text`, where type
79
+ `text` is message text (when `message.content` is absent) and type
80
+ `reasoning` is the model's reasoning.
81
+ - `gen_ai`: attribute `K` holds a JSON string: a list of messages with `role`
82
+ and `parts`, each part typed `text` (`content`), `reasoning` (`content`),
83
+ `tool_call` (`id`, `name`, `arguments`) or `tool_call_response` (`id`,
84
+ `response`, or `result` when `response` is absent).
85
+ - `openai`: attribute `K` holds a JSON string: a list of OpenAI chat messages
86
+ with `role`, `content` (a string or a list of `{"type": "text", "text"}`
87
+ parts), `tool_calls` (`id`, `function.name`, `function.arguments` as a JSON
88
+ string) and `tool_call_id`.