gatewaysdk 0.3.2__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 (376) hide show
  1. gatewaysdk/__init__.py +540 -0
  2. gatewaysdk/adapter/__init__.py +15 -0
  3. gatewaysdk/adapter/base.py +94 -0
  4. gatewaysdk/adapter/messages.py +270 -0
  5. gatewaysdk/adapter/triplet.py +1026 -0
  6. gatewaysdk/algorithm/__init__.py +39 -0
  7. gatewaysdk/algorithm/apo/__init__.py +5 -0
  8. gatewaysdk/algorithm/apo/apo.py +898 -0
  9. gatewaysdk/algorithm/apo/prompts/apply_edit_variant01.poml +22 -0
  10. gatewaysdk/algorithm/apo/prompts/apply_edit_variant02.poml +18 -0
  11. gatewaysdk/algorithm/apo/prompts/text_gradient_variant01.poml +18 -0
  12. gatewaysdk/algorithm/apo/prompts/text_gradient_variant02.poml +16 -0
  13. gatewaysdk/algorithm/apo/prompts/text_gradient_variant03.poml +107 -0
  14. gatewaysdk/algorithm/base.py +262 -0
  15. gatewaysdk/algorithm/decorator.py +264 -0
  16. gatewaysdk/algorithm/evals/__init__.py +7 -0
  17. gatewaysdk/algorithm/evals/evals.py +217 -0
  18. gatewaysdk/algorithm/fast.py +250 -0
  19. gatewaysdk/algorithm/gepa/__init__.py +61 -0
  20. gatewaysdk/algorithm/gepa/adapter.py +495 -0
  21. gatewaysdk/algorithm/gepa/gepa.py +570 -0
  22. gatewaysdk/algorithm/gepa/lib/__init__.py +18 -0
  23. gatewaysdk/algorithm/gepa/lib/adapters/README.md +12 -0
  24. gatewaysdk/algorithm/gepa/lib/adapters/__init__.py +0 -0
  25. gatewaysdk/algorithm/gepa/lib/adapters/anymaths_adapter/README.md +341 -0
  26. gatewaysdk/algorithm/gepa/lib/adapters/anymaths_adapter/__init__.py +1 -0
  27. gatewaysdk/algorithm/gepa/lib/adapters/anymaths_adapter/anymaths_adapter.py +174 -0
  28. gatewaysdk/algorithm/gepa/lib/adapters/anymaths_adapter/requirements.txt +1 -0
  29. gatewaysdk/algorithm/gepa/lib/adapters/default_adapter/README.md +0 -0
  30. gatewaysdk/algorithm/gepa/lib/adapters/default_adapter/__init__.py +0 -0
  31. gatewaysdk/algorithm/gepa/lib/adapters/default_adapter/default_adapter.py +209 -0
  32. gatewaysdk/algorithm/gepa/lib/adapters/dspy_adapter/README.md +7 -0
  33. gatewaysdk/algorithm/gepa/lib/adapters/dspy_adapter/__init__.py +0 -0
  34. gatewaysdk/algorithm/gepa/lib/adapters/dspy_adapter/dspy_adapter.py +307 -0
  35. gatewaysdk/algorithm/gepa/lib/adapters/dspy_full_program_adapter/README.md +99 -0
  36. gatewaysdk/algorithm/gepa/lib/adapters/dspy_full_program_adapter/dspy_program_proposal_signature.py +137 -0
  37. gatewaysdk/algorithm/gepa/lib/adapters/dspy_full_program_adapter/full_program_adapter.py +268 -0
  38. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/GEPA_RAG.md +621 -0
  39. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/__init__.py +56 -0
  40. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/evaluation_metrics.py +226 -0
  41. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/generic_rag_adapter.py +496 -0
  42. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/rag_pipeline.py +238 -0
  43. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_store_interface.py +212 -0
  44. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/__init__.py +2 -0
  45. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/chroma_store.py +196 -0
  46. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/lancedb_store.py +422 -0
  47. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/milvus_store.py +409 -0
  48. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/qdrant_store.py +368 -0
  49. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/weaviate_store.py +418 -0
  50. gatewaysdk/algorithm/gepa/lib/adapters/mcp_adapter/README.md +552 -0
  51. gatewaysdk/algorithm/gepa/lib/adapters/mcp_adapter/__init__.py +37 -0
  52. gatewaysdk/algorithm/gepa/lib/adapters/mcp_adapter/mcp_adapter.py +699 -0
  53. gatewaysdk/algorithm/gepa/lib/adapters/mcp_adapter/mcp_client.py +364 -0
  54. gatewaysdk/algorithm/gepa/lib/adapters/terminal_bench_adapter/README.md +9 -0
  55. gatewaysdk/algorithm/gepa/lib/adapters/terminal_bench_adapter/__init__.py +0 -0
  56. gatewaysdk/algorithm/gepa/lib/adapters/terminal_bench_adapter/terminal_bench_adapter.py +217 -0
  57. gatewaysdk/algorithm/gepa/lib/api.py +382 -0
  58. gatewaysdk/algorithm/gepa/lib/core/__init__.py +0 -0
  59. gatewaysdk/algorithm/gepa/lib/core/adapter.py +180 -0
  60. gatewaysdk/algorithm/gepa/lib/core/data_loader.py +74 -0
  61. gatewaysdk/algorithm/gepa/lib/core/engine.py +379 -0
  62. gatewaysdk/algorithm/gepa/lib/core/result.py +233 -0
  63. gatewaysdk/algorithm/gepa/lib/core/state.py +636 -0
  64. gatewaysdk/algorithm/gepa/lib/examples/__init__.py +0 -0
  65. gatewaysdk/algorithm/gepa/lib/examples/aime.py +24 -0
  66. gatewaysdk/algorithm/gepa/lib/examples/anymaths-bench/eval_default.py +111 -0
  67. gatewaysdk/algorithm/gepa/lib/examples/anymaths-bench/prompt-templates/instruction_prompt.txt +9 -0
  68. gatewaysdk/algorithm/gepa/lib/examples/anymaths-bench/prompt-templates/optimal_prompt.txt +24 -0
  69. gatewaysdk/algorithm/gepa/lib/examples/anymaths-bench/train_anymaths.py +177 -0
  70. gatewaysdk/algorithm/gepa/lib/examples/dspy_full_program_evolution/arc_agi.ipynb +25705 -0
  71. gatewaysdk/algorithm/gepa/lib/examples/dspy_full_program_evolution/example.ipynb +348 -0
  72. gatewaysdk/algorithm/gepa/lib/examples/mcp_adapter/__init__.py +4 -0
  73. gatewaysdk/algorithm/gepa/lib/examples/mcp_adapter/mcp_optimization_example.py +456 -0
  74. gatewaysdk/algorithm/gepa/lib/examples/rag_adapter/RAG_GUIDE.md +613 -0
  75. gatewaysdk/algorithm/gepa/lib/examples/rag_adapter/__init__.py +9 -0
  76. gatewaysdk/algorithm/gepa/lib/examples/rag_adapter/rag_optimization.py +820 -0
  77. gatewaysdk/algorithm/gepa/lib/examples/rag_adapter/requirements-rag.txt +29 -0
  78. gatewaysdk/algorithm/gepa/lib/examples/terminal-bench/prompt-templates/instruction_prompt.txt +16 -0
  79. gatewaysdk/algorithm/gepa/lib/examples/terminal-bench/prompt-templates/terminus.txt +9 -0
  80. gatewaysdk/algorithm/gepa/lib/examples/terminal-bench/train_terminus.py +161 -0
  81. gatewaysdk/algorithm/gepa/lib/gepa_utils.py +117 -0
  82. gatewaysdk/algorithm/gepa/lib/logging/__init__.py +0 -0
  83. gatewaysdk/algorithm/gepa/lib/logging/experiment_tracker.py +187 -0
  84. gatewaysdk/algorithm/gepa/lib/logging/logger.py +75 -0
  85. gatewaysdk/algorithm/gepa/lib/logging/utils.py +103 -0
  86. gatewaysdk/algorithm/gepa/lib/proposer/__init__.py +0 -0
  87. gatewaysdk/algorithm/gepa/lib/proposer/base.py +31 -0
  88. gatewaysdk/algorithm/gepa/lib/proposer/merge.py +357 -0
  89. gatewaysdk/algorithm/gepa/lib/proposer/reflective_mutation/__init__.py +0 -0
  90. gatewaysdk/algorithm/gepa/lib/proposer/reflective_mutation/base.py +49 -0
  91. gatewaysdk/algorithm/gepa/lib/proposer/reflective_mutation/reflective_mutation.py +176 -0
  92. gatewaysdk/algorithm/gepa/lib/py.typed +0 -0
  93. gatewaysdk/algorithm/gepa/lib/strategies/__init__.py +0 -0
  94. gatewaysdk/algorithm/gepa/lib/strategies/batch_sampler.py +77 -0
  95. gatewaysdk/algorithm/gepa/lib/strategies/candidate_selector.py +50 -0
  96. gatewaysdk/algorithm/gepa/lib/strategies/component_selector.py +36 -0
  97. gatewaysdk/algorithm/gepa/lib/strategies/eval_policy.py +64 -0
  98. gatewaysdk/algorithm/gepa/lib/strategies/instruction_proposal.py +126 -0
  99. gatewaysdk/algorithm/gepa/lib/utils/__init__.py +10 -0
  100. gatewaysdk/algorithm/gepa/lib/utils/stop_condition.py +196 -0
  101. gatewaysdk/algorithm/gepa/tracing.py +105 -0
  102. gatewaysdk/algorithm/utils.py +177 -0
  103. gatewaysdk/algorithm/verl/__init__.py +5 -0
  104. gatewaysdk/algorithm/verl/interface.py +202 -0
  105. gatewaysdk/automations.py +111 -0
  106. gatewaysdk/benchmark_hub/README.md +88 -0
  107. gatewaysdk/benchmark_hub/__init__.py +119 -0
  108. gatewaysdk/benchmark_hub/_archive.py +189 -0
  109. gatewaysdk/benchmark_hub/_tar.py +6 -0
  110. gatewaysdk/benchmark_hub/client.py +992 -0
  111. gatewaysdk/benchmark_hub/dispatch_shard.py +34 -0
  112. gatewaysdk/benchmark_hub/eval_config.py +20 -0
  113. gatewaysdk/benchmark_hub/evals.py +351 -0
  114. gatewaysdk/benchmark_hub/harbor_adapter.py +673 -0
  115. gatewaysdk/benchmark_hub/path_utils.py +81 -0
  116. gatewaysdk/benchmark_hub/save_utils.py +101 -0
  117. gatewaysdk/benchmark_hub/verifiers_adapter.py +327 -0
  118. gatewaysdk/benchmark_hub/versioning.py +72 -0
  119. gatewaysdk/build.py +515 -0
  120. gatewaysdk/cli/__init__.py +58 -0
  121. gatewaysdk/cli/agent_runner.py +132 -0
  122. gatewaysdk/cli/http_client.py +115 -0
  123. gatewaysdk/cli/platform.py +4086 -0
  124. gatewaysdk/cli/prometheus.py +115 -0
  125. gatewaysdk/cli/release_gate.py +215 -0
  126. gatewaysdk/cli/store.py +131 -0
  127. gatewaysdk/cli/vllm.py +29 -0
  128. gatewaysdk/client.py +406 -0
  129. gatewaysdk/config.py +348 -0
  130. gatewaysdk/connectors/__init__.py +25 -0
  131. gatewaysdk/connectors/client.py +203 -0
  132. gatewaysdk/connectors/skill.py +25 -0
  133. gatewaysdk/connectors/template.py +106 -0
  134. gatewaysdk/context.py +606 -0
  135. gatewaysdk/emitter/__init__.py +43 -0
  136. gatewaysdk/emitter/annotation.py +370 -0
  137. gatewaysdk/emitter/exception.py +54 -0
  138. gatewaysdk/emitter/message.py +61 -0
  139. gatewaysdk/emitter/object.py +117 -0
  140. gatewaysdk/emitter/reward.py +320 -0
  141. gatewaysdk/env_var.py +156 -0
  142. gatewaysdk/environment/__init__.py +108 -0
  143. gatewaysdk/environment/_bundle.py +281 -0
  144. gatewaysdk/environment/_harbor.py +276 -0
  145. gatewaysdk/environment/_materialize.py +97 -0
  146. gatewaysdk/environment/_tar.py +33 -0
  147. gatewaysdk/environment/_world.py +346 -0
  148. gatewaysdk/environment/core.py +527 -0
  149. gatewaysdk/environment/errors.py +58 -0
  150. gatewaysdk/environment/runtime.py +150 -0
  151. gatewaysdk/environment/schema/__init__.py +35 -0
  152. gatewaysdk/environment/schema/__main__.py +225 -0
  153. gatewaysdk/environment/schema/_slack_fidelity.py +116 -0
  154. gatewaysdk/environment/schema/_slack_scenario.py +183 -0
  155. gatewaysdk/environment/schema/api.py +1628 -0
  156. gatewaysdk/environment/schema/batch.py +755 -0
  157. gatewaysdk/environment/schema/compiler.py +615 -0
  158. gatewaysdk/environment/schema/conform.py +428 -0
  159. gatewaysdk/environment/schema/connector.py +777 -0
  160. gatewaysdk/environment/schema/connectors/apple-business-manager/handlers.py +17 -0
  161. gatewaysdk/environment/schema/connectors/apple-business-manager/parity.json +28 -0
  162. gatewaysdk/environment/schema/connectors/apple-business-manager/provenance.json +233 -0
  163. gatewaysdk/environment/schema/connectors/apple-business-manager/scope.toml +112 -0
  164. gatewaysdk/environment/schema/connectors/apple-business-manager/world.json +1380 -0
  165. gatewaysdk/environment/schema/connectors/base.json +28 -0
  166. gatewaysdk/environment/schema/connectors/custom/handlers.py +18 -0
  167. gatewaysdk/environment/schema/connectors/custom/world.json +123 -0
  168. gatewaysdk/environment/schema/connectors/github/handlers.py +81 -0
  169. gatewaysdk/environment/schema/connectors/github/parity.json +37 -0
  170. gatewaysdk/environment/schema/connectors/github/provenance.json +134 -0
  171. gatewaysdk/environment/schema/connectors/github/scope.toml +158 -0
  172. gatewaysdk/environment/schema/connectors/github/world.json +5869 -0
  173. gatewaysdk/environment/schema/connectors/google-calendar/handlers.py +23 -0
  174. gatewaysdk/environment/schema/connectors/google-calendar/world.json +209 -0
  175. gatewaysdk/environment/schema/connectors/google-drive/handlers.py +18 -0
  176. gatewaysdk/environment/schema/connectors/google-drive/world.json +286 -0
  177. gatewaysdk/environment/schema/connectors/jamf/handlers.py +34 -0
  178. gatewaysdk/environment/schema/connectors/jamf/parity.json +49 -0
  179. gatewaysdk/environment/schema/connectors/jamf/provenance.json +181 -0
  180. gatewaysdk/environment/schema/connectors/jamf/scope.toml +128 -0
  181. gatewaysdk/environment/schema/connectors/jamf/world.json +2218 -0
  182. gatewaysdk/environment/schema/connectors/jira/handlers.py +28 -0
  183. gatewaysdk/environment/schema/connectors/jira/world.json +389 -0
  184. gatewaysdk/environment/schema/connectors/kandji/handlers.py +38 -0
  185. gatewaysdk/environment/schema/connectors/kandji/parity.json +29 -0
  186. gatewaysdk/environment/schema/connectors/kandji/provenance.json +152 -0
  187. gatewaysdk/environment/schema/connectors/kandji/scope.toml +120 -0
  188. gatewaysdk/environment/schema/connectors/kandji/world.json +765 -0
  189. gatewaysdk/environment/schema/connectors/linear/handlers.py +20 -0
  190. gatewaysdk/environment/schema/connectors/linear/world.json +363 -0
  191. gatewaysdk/environment/schema/connectors/microsoft-teams/fidelity.json +45 -0
  192. gatewaysdk/environment/schema/connectors/microsoft-teams/handlers.py +1 -0
  193. gatewaysdk/environment/schema/connectors/microsoft-teams/provenance.json +851 -0
  194. gatewaysdk/environment/schema/connectors/microsoft-teams/scope.md +231 -0
  195. gatewaysdk/environment/schema/connectors/microsoft-teams/teams-types.json +1710 -0
  196. gatewaysdk/environment/schema/connectors/microsoft-teams/world.json +858 -0
  197. gatewaysdk/environment/schema/connectors/netsuite/handlers.py +32 -0
  198. gatewaysdk/environment/schema/connectors/netsuite/parity.json +50 -0
  199. gatewaysdk/environment/schema/connectors/netsuite/provenance.json +137 -0
  200. gatewaysdk/environment/schema/connectors/netsuite/scope.toml +78 -0
  201. gatewaysdk/environment/schema/connectors/netsuite/world.json +16243 -0
  202. gatewaysdk/environment/schema/connectors/salesforce/handlers.py +806 -0
  203. gatewaysdk/environment/schema/connectors/salesforce/parity.json +46 -0
  204. gatewaysdk/environment/schema/connectors/salesforce/provenance.json +143 -0
  205. gatewaysdk/environment/schema/connectors/salesforce/scope.toml +174 -0
  206. gatewaysdk/environment/schema/connectors/salesforce/world.json +4695 -0
  207. gatewaysdk/environment/schema/connectors/slack/MODEL.md +236 -0
  208. gatewaysdk/environment/schema/connectors/slack/capabilities.json +1039 -0
  209. gatewaysdk/environment/schema/connectors/slack/handlers.py +762 -0
  210. gatewaysdk/environment/schema/connectors/slack/parity.json +65 -0
  211. gatewaysdk/environment/schema/connectors/slack/provenance.json +294 -0
  212. gatewaysdk/environment/schema/connectors/slack/scope.toml +44 -0
  213. gatewaysdk/environment/schema/connectors/slack/world.json +4993 -0
  214. gatewaysdk/environment/schema/connectors/workday/handlers.py +75 -0
  215. gatewaysdk/environment/schema/connectors/workday/parity.json +36 -0
  216. gatewaysdk/environment/schema/connectors/workday/provenance.json +179 -0
  217. gatewaysdk/environment/schema/connectors/workday/scope.toml +180 -0
  218. gatewaysdk/environment/schema/connectors/workday/world.json +806 -0
  219. gatewaysdk/environment/schema/data.py +593 -0
  220. gatewaysdk/environment/schema/extract.py +263 -0
  221. gatewaysdk/environment/schema/host.py +2437 -0
  222. gatewaysdk/environment/schema/host_surfaces.py +275 -0
  223. gatewaysdk/environment/schema/platform.py +1272 -0
  224. gatewaysdk/environment/schema/scaffold.py +250 -0
  225. gatewaysdk/environment/schema/skill.py +118 -0
  226. gatewaysdk/environment/schema/skills/agents/connector-template-author.md +202 -0
  227. gatewaysdk/environment/schema/skills/connector-schema-authoring/CONNECTORS.md +331 -0
  228. gatewaysdk/environment/schema/skills/connector-schema-authoring/CONVENTIONS.md +100 -0
  229. gatewaysdk/environment/schema/skills/connector-schema-authoring/SKILL.md +313 -0
  230. gatewaysdk/environment/schema/skills/world-data-ingestion/ROWS.md +223 -0
  231. gatewaysdk/environment/schema/skills/world-data-ingestion/SKILL.md +293 -0
  232. gatewaysdk/environment/schema/skills/worlds-getting-started/SKILL.md +390 -0
  233. gatewaysdk/environment/schema/slack.py +757 -0
  234. gatewaysdk/environment/schema/snapshot.py +479 -0
  235. gatewaysdk/environment/schema/store.py +904 -0
  236. gatewaysdk/environment/schema/tasks.py +525 -0
  237. gatewaysdk/environment/schema/tools_world.py +322 -0
  238. gatewaysdk/environment/schema/validation.py +577 -0
  239. gatewaysdk/environment/schema/worker.py +78 -0
  240. gatewaysdk/environment/schema/workers.py +500 -0
  241. gatewaysdk/environment/schema/world_tests.py +336 -0
  242. gatewaysdk/environments/__init__.py +24 -0
  243. gatewaysdk/environments/client.py +486 -0
  244. gatewaysdk/environments/types.py +318 -0
  245. gatewaysdk/execution/__init__.py +15 -0
  246. gatewaysdk/execution/base.py +64 -0
  247. gatewaysdk/execution/client_server.py +443 -0
  248. gatewaysdk/execution/events.py +69 -0
  249. gatewaysdk/execution/inter_process.py +16 -0
  250. gatewaysdk/execution/shared_memory.py +282 -0
  251. gatewaysdk/experiments/__init__.py +90 -0
  252. gatewaysdk/experiments/assignment.py +177 -0
  253. gatewaysdk/experiments/client.py +877 -0
  254. gatewaysdk/experiments/exposure.py +222 -0
  255. gatewaysdk/experiments/types.py +81 -0
  256. gatewaysdk/importers/__init__.py +49 -0
  257. gatewaysdk/importers/_normalize.py +91 -0
  258. gatewaysdk/importers/builder.py +173 -0
  259. gatewaysdk/importers/client.py +95 -0
  260. gatewaysdk/importers/langsmith.py +196 -0
  261. gatewaysdk/importers/recipes.py +249 -0
  262. gatewaysdk/instrumentation/__init__.py +300 -0
  263. gatewaysdk/instrumentation/agentops.py +314 -0
  264. gatewaysdk/instrumentation/agentops_langchain.py +45 -0
  265. gatewaysdk/instrumentation/base.py +119 -0
  266. gatewaysdk/instrumentation/litellm.py +83 -0
  267. gatewaysdk/instrumentation/registry.py +273 -0
  268. gatewaysdk/instrumentation/vllm.py +81 -0
  269. gatewaysdk/instrumentation/weave.py +500 -0
  270. gatewaysdk/integrations/__init__.py +15 -0
  271. gatewaysdk/integrations/gateway/__init__.py +11 -0
  272. gatewaysdk/integrations/gateway/client.py +171 -0
  273. gatewaysdk/integrations/tool_access.py +549 -0
  274. gatewaysdk/litagent/__init__.py +11 -0
  275. gatewaysdk/litagent/decorator.py +536 -0
  276. gatewaysdk/litagent/litagent.py +252 -0
  277. gatewaysdk/llm_proxy.py +1742 -0
  278. gatewaysdk/logging.py +370 -0
  279. gatewaysdk/memory.py +278 -0
  280. gatewaysdk/personas.py +186 -0
  281. gatewaysdk/platform/__init__.py +17 -0
  282. gatewaysdk/platform/builder.py +221 -0
  283. gatewaysdk/platform/compatibility.py +67 -0
  284. gatewaysdk/platform/manifest.py +185 -0
  285. gatewaysdk/platform/orchestrator.py +901 -0
  286. gatewaysdk/platform/registry.py +122 -0
  287. gatewaysdk/platform/worker.py +864 -0
  288. gatewaysdk/replay/__init__.py +1032 -0
  289. gatewaysdk/replay/pytest.py +56 -0
  290. gatewaysdk/reward.py +7 -0
  291. gatewaysdk/run.py +1781 -0
  292. gatewaysdk/runner/__init__.py +11 -0
  293. gatewaysdk/runner/agent.py +878 -0
  294. gatewaysdk/runner/base.py +182 -0
  295. gatewaysdk/runner/legacy.py +309 -0
  296. gatewaysdk/security.py +700 -0
  297. gatewaysdk/semconv.py +170 -0
  298. gatewaysdk/server.py +399 -0
  299. gatewaysdk/sessions.py +282 -0
  300. gatewaysdk/store/__init__.py +45 -0
  301. gatewaysdk/store/base.py +908 -0
  302. gatewaysdk/store/client_server.py +2093 -0
  303. gatewaysdk/store/collection/__init__.py +30 -0
  304. gatewaysdk/store/collection/base.py +587 -0
  305. gatewaysdk/store/collection/memory.py +970 -0
  306. gatewaysdk/store/collection/mongo.py +1412 -0
  307. gatewaysdk/store/collection_based.py +1823 -0
  308. gatewaysdk/store/gateway.py +983 -0
  309. gatewaysdk/store/gateway_listener.py +465 -0
  310. gatewaysdk/store/listener.py +58 -0
  311. gatewaysdk/store/memory.py +396 -0
  312. gatewaysdk/store/mongo.py +165 -0
  313. gatewaysdk/store/redis_stream.py +517 -0
  314. gatewaysdk/store/sqlite.py +3 -0
  315. gatewaysdk/store/threading.py +370 -0
  316. gatewaysdk/store/utils.py +142 -0
  317. gatewaysdk/tracer/__init__.py +14 -0
  318. gatewaysdk/tracer/base.py +286 -0
  319. gatewaysdk/tracer/dummy.py +106 -0
  320. gatewaysdk/tracer/otel.py +559 -0
  321. gatewaysdk/tracing/__init__.py +110 -0
  322. gatewaysdk/tracing/api.py +808 -0
  323. gatewaysdk/tracing/attributes.py +9 -0
  324. gatewaysdk/tracing/context.py +272 -0
  325. gatewaysdk/tracing/exporters/__init__.py +10 -0
  326. gatewaysdk/tracing/exporters/gateway.py +228 -0
  327. gatewaysdk/tracing/identity.py +288 -0
  328. gatewaysdk/tracing/init.py +620 -0
  329. gatewaysdk/tracing/instrumentors/__init__.py +15 -0
  330. gatewaysdk/tracing/instrumentors/claude_agent_sdk.py +766 -0
  331. gatewaysdk/tracing/instrumentors/instrumentation_principles.md +294 -0
  332. gatewaysdk/tracing/instrumentors/registry.py +352 -0
  333. gatewaysdk/tracing/mapping.py +729 -0
  334. gatewaysdk/tracing/processors.py +393 -0
  335. gatewaysdk/tracing/push.py +617 -0
  336. gatewaysdk/tracing/push_models.py +247 -0
  337. gatewaysdk/tracing/semconv.py +294 -0
  338. gatewaysdk/tracing/span_builder.py +356 -0
  339. gatewaysdk/trainer/__init__.py +6 -0
  340. gatewaysdk/trainer/init_utils.py +263 -0
  341. gatewaysdk/trainer/legacy.py +359 -0
  342. gatewaysdk/trainer/registry.py +12 -0
  343. gatewaysdk/trainer/trainer.py +638 -0
  344. gatewaysdk/types/__init__.py +63 -0
  345. gatewaysdk/types/core.py +556 -0
  346. gatewaysdk/types/resources.py +204 -0
  347. gatewaysdk/types/tracer.py +515 -0
  348. gatewaysdk/types/tracing.py +162 -0
  349. gatewaysdk/users.py +251 -0
  350. gatewaysdk/utils/__init__.py +1 -0
  351. gatewaysdk/utils/id.py +18 -0
  352. gatewaysdk/utils/metrics.py +1025 -0
  353. gatewaysdk/utils/otel.py +550 -0
  354. gatewaysdk/utils/otlp.py +556 -0
  355. gatewaysdk/utils/redact.py +22 -0
  356. gatewaysdk/utils/server_launcher.py +1045 -0
  357. gatewaysdk/utils/system_snapshot.py +90 -0
  358. gatewaysdk/verl/__init__.py +8 -0
  359. gatewaysdk/verl/__main__.py +6 -0
  360. gatewaysdk/verl/async_server.py +46 -0
  361. gatewaysdk/verl/config.yaml +27 -0
  362. gatewaysdk/verl/daemon.py +1154 -0
  363. gatewaysdk/verl/dataset.py +44 -0
  364. gatewaysdk/verl/entrypoint.py +248 -0
  365. gatewaysdk/verl/trainer.py +549 -0
  366. gatewaysdk/world_browser.py +748 -0
  367. gatewaysdk/world_data.py +453 -0
  368. gatewaysdk/world_sessions.py +978 -0
  369. gatewaysdk/world_tasks.py +285 -0
  370. gatewaysdk/world_tools.py +115 -0
  371. gatewaysdk/worlds.py +639 -0
  372. gatewaysdk-0.3.2.dist-info/METADATA +236 -0
  373. gatewaysdk-0.3.2.dist-info/RECORD +376 -0
  374. gatewaysdk-0.3.2.dist-info/WHEEL +4 -0
  375. gatewaysdk-0.3.2.dist-info/entry_points.txt +5 -0
  376. gatewaysdk-0.3.2.dist-info/licenses/LICENSE +19 -0
@@ -0,0 +1,264 @@
1
+ # Copyright (c) Microsoft. All rights reserved.
2
+
3
+ from __future__ import annotations
4
+
5
+ import functools
6
+ import inspect
7
+ from typing import (
8
+ TYPE_CHECKING,
9
+ Any,
10
+ Awaitable,
11
+ Dict,
12
+ Generic,
13
+ Literal,
14
+ Optional,
15
+ Protocol,
16
+ TypeVar,
17
+ Union,
18
+ cast,
19
+ overload,
20
+ )
21
+
22
+ from gatewaysdk.adapter import TraceAdapter
23
+ from gatewaysdk.store.base import LightningStore
24
+ from gatewaysdk.types import Dataset, NamedResources
25
+
26
+ if TYPE_CHECKING:
27
+ from gatewaysdk.llm_proxy import LLMProxy
28
+
29
+ from .base import Algorithm
30
+
31
+ # Algorithm function signature types
32
+ # We've missed a lot of combinations here.
33
+ # Let's add them in future.
34
+
35
+
36
+ class AlgorithmFuncSyncFull(Protocol):
37
+ def __call__(
38
+ self,
39
+ *,
40
+ store: LightningStore,
41
+ train_dataset: Optional[Dataset[Any]],
42
+ val_dataset: Optional[Dataset[Any]],
43
+ llm_proxy: Optional[LLMProxy],
44
+ adapter: Optional[TraceAdapter[Any]],
45
+ initial_resources: Optional[NamedResources],
46
+ ) -> None: ...
47
+
48
+
49
+ class AlgorithmFuncSyncOnlyStore(Protocol):
50
+ def __call__(self, *, store: LightningStore) -> None: ...
51
+
52
+
53
+ class AlgorithmFuncSyncOnlyDataset(Protocol):
54
+ def __call__(self, *, train_dataset: Optional[Dataset[Any]], val_dataset: Optional[Dataset[Any]]) -> None: ...
55
+
56
+
57
+ class AlgorithmFuncAsyncFull(Protocol):
58
+ def __call__(
59
+ self,
60
+ *,
61
+ store: LightningStore,
62
+ train_dataset: Optional[Dataset[Any]],
63
+ val_dataset: Optional[Dataset[Any]],
64
+ llm_proxy: Optional[LLMProxy],
65
+ adapter: Optional[TraceAdapter[Any]],
66
+ initial_resources: Optional[NamedResources],
67
+ ) -> Awaitable[None]: ...
68
+
69
+
70
+ class AlgorithmFuncAsyncOnlyStore(Protocol):
71
+ def __call__(self, *, store: LightningStore) -> Awaitable[None]: ...
72
+
73
+
74
+ class AlgorithmFuncAsyncOnlyDataset(Protocol):
75
+ def __call__(
76
+ self, *, train_dataset: Optional[Dataset[Any]], val_dataset: Optional[Dataset[Any]]
77
+ ) -> Awaitable[None]: ...
78
+
79
+
80
+ AlgorithmFuncAsync = Union[AlgorithmFuncAsyncOnlyStore, AlgorithmFuncAsyncOnlyDataset, AlgorithmFuncAsyncFull]
81
+
82
+ AlgorithmFuncSync = Union[AlgorithmFuncSyncOnlyStore, AlgorithmFuncSyncOnlyDataset, AlgorithmFuncSyncFull]
83
+
84
+
85
+ class AlgorithmFuncSyncFallback(Protocol):
86
+ def __call__(self, *args: Any, **kwargs: Any) -> Any: ...
87
+
88
+
89
+ class AlgorithmFuncAsyncFallback(Protocol):
90
+ def __call__(self, *args: Any, **kwargs: Any) -> Awaitable[Any]: ...
91
+
92
+
93
+ AlgorithmFuncSyncLike = Union[AlgorithmFuncSync, AlgorithmFuncSyncFallback]
94
+ AlgorithmFuncAsyncLike = Union[AlgorithmFuncAsync, AlgorithmFuncAsyncFallback]
95
+
96
+ AlgorithmFunc = Union[AlgorithmFuncSyncLike, AlgorithmFuncAsyncLike]
97
+
98
+
99
+ AsyncFlag = Literal[True, False]
100
+ AF = TypeVar("AF", bound=AsyncFlag)
101
+
102
+
103
+ class FunctionalAlgorithm(Algorithm, Generic[AF]):
104
+ """An algorithm wrapper built from a callable implementation.
105
+
106
+ Functional algorithms let you provide an ordinary function instead of
107
+ subclassing [`Algorithm`][gatewaysdk.Algorithm]. The wrapper inspects
108
+ the callable signature to supply optional dependencies
109
+ such as the store, adapter, and LLM proxy.
110
+ """
111
+
112
+ @overload
113
+ def __init__(self: "FunctionalAlgorithm[Literal[False]]", algorithm_func: AlgorithmFuncSyncLike) -> None: ...
114
+
115
+ @overload
116
+ def __init__(self: "FunctionalAlgorithm[Literal[True]]", algorithm_func: AlgorithmFuncAsyncLike) -> None: ...
117
+
118
+ def __init__(self, algorithm_func: Union[AlgorithmFuncSyncLike, AlgorithmFuncAsyncLike]) -> None:
119
+ """Wrap a function that implements algorithm behaviour.
120
+
121
+ Args:
122
+ algorithm_func: Sync or async callable implementing the algorithm
123
+ contract. Arguments are detected automatically based on the
124
+ function signature.
125
+ """
126
+ super().__init__()
127
+ self._algorithm_func = algorithm_func
128
+ self._sig = inspect.signature(algorithm_func)
129
+ self._is_async = inspect.iscoroutinefunction(algorithm_func)
130
+
131
+ # Copy function metadata to preserve type hints and other attributes
132
+ functools.update_wrapper(self, algorithm_func) # type: ignore
133
+
134
+ def is_async(self) -> bool:
135
+ return self._is_async
136
+
137
+ @overload
138
+ def run(
139
+ self: "FunctionalAlgorithm[Literal[False]]",
140
+ train_dataset: Optional[Dataset[Any]] = None,
141
+ val_dataset: Optional[Dataset[Any]] = None,
142
+ ) -> None: ...
143
+
144
+ @overload
145
+ def run(
146
+ self: "FunctionalAlgorithm[Literal[True]]",
147
+ train_dataset: Optional[Dataset[Any]] = None,
148
+ val_dataset: Optional[Dataset[Any]] = None,
149
+ ) -> Awaitable[None]: ...
150
+
151
+ def __call__(self, *args: Any, **kwargs: Any) -> Any:
152
+ return self._algorithm_func(*args, **kwargs) # type: ignore
153
+
154
+ def run(
155
+ self,
156
+ train_dataset: Optional[Dataset[Any]] = None,
157
+ val_dataset: Optional[Dataset[Any]] = None,
158
+ ) -> Union[None, Awaitable[None]]:
159
+ """Execute the wrapped function with injected dependencies.
160
+
161
+ Args:
162
+ train_dataset: Optional training dataset passed through when the
163
+ callable declares a `train_dataset` parameter.
164
+ val_dataset: Optional validation dataset passed through when the
165
+ callable declares a `val_dataset` parameter.
166
+
167
+ Returns:
168
+ None for sync callables or an awaitable when the callable is async.
169
+
170
+ Raises:
171
+ TypeError: If a dataset is provided but the function signature does
172
+ not accept the corresponding argument.
173
+ """
174
+ kwargs: Dict[str, Any] = {}
175
+ if "store" in self._sig.parameters:
176
+ kwargs["store"] = self.get_store()
177
+ if "adapter" in self._sig.parameters:
178
+ kwargs["adapter"] = self.get_adapter()
179
+ if "llm_proxy" in self._sig.parameters:
180
+ kwargs["llm_proxy"] = self.get_llm_proxy()
181
+ if "initial_resources" in self._sig.parameters:
182
+ kwargs["initial_resources"] = self.get_initial_resources()
183
+ if "train_dataset" in self._sig.parameters:
184
+ kwargs["train_dataset"] = train_dataset
185
+ elif train_dataset is not None:
186
+ raise TypeError(
187
+ f"train_dataset is provided but not supported by the algorithm function: {self._algorithm_func}"
188
+ )
189
+ if "val_dataset" in self._sig.parameters:
190
+ kwargs["val_dataset"] = val_dataset
191
+ elif val_dataset is not None:
192
+ raise TypeError(
193
+ f"val_dataset is provided but not supported by the algorithm function: {self._algorithm_func}"
194
+ )
195
+ # both sync and async functions can be called with the same signature
196
+ result = self._algorithm_func(**kwargs) # type: ignore[misc]
197
+ if self._is_async:
198
+ return cast(Awaitable[None], result)
199
+ return None
200
+
201
+
202
+ @overload
203
+ def algo(func: AlgorithmFuncAsync) -> FunctionalAlgorithm[Literal[True]]: ...
204
+
205
+
206
+ @overload
207
+ def algo(func: AlgorithmFuncAsyncFallback) -> FunctionalAlgorithm[Any]: ...
208
+
209
+
210
+ @overload
211
+ def algo(func: AlgorithmFuncSync) -> FunctionalAlgorithm[Literal[False]]: ...
212
+
213
+
214
+ @overload
215
+ def algo(func: AlgorithmFuncSyncFallback) -> FunctionalAlgorithm[Any]: ...
216
+
217
+
218
+ def algo(
219
+ func: Union[
220
+ AlgorithmFuncSync,
221
+ AlgorithmFuncAsync,
222
+ AlgorithmFuncSyncFallback,
223
+ AlgorithmFuncAsyncFallback,
224
+ ],
225
+ ) -> Union[FunctionalAlgorithm[Literal[False]], FunctionalAlgorithm[Literal[True]]]:
226
+ """Convert a callable into a [`FunctionalAlgorithm`][gatewaysdk.algorithm.decorator.FunctionalAlgorithm].
227
+
228
+ The decorator inspects the callable signature to decide which dependencies
229
+ to inject at runtime, enabling concise algorithm definitions that still
230
+ leverage the full training runtime.
231
+
232
+ Args:
233
+ func: Function implementing the algorithm logic. May be synchronous or
234
+ asynchronous. The function can expect all of, or a subset of the following parameters:
235
+
236
+ - `store`: [`LightningStore`][gatewaysdk.store.base.LightningStore],
237
+ - `train_dataset`: [`Dataset`][gatewaysdk.Dataset],
238
+ - `val_dataset`: [`Dataset`][gatewaysdk.Dataset],
239
+ - `llm_proxy`: [`LLMProxy`][gatewaysdk.LLMProxy],
240
+ - `adapter`: [`TraceAdapter`][gatewaysdk.TraceAdapter],
241
+ - `initial_resources`: [`NamedResources`][gatewaysdk.NamedResources],
242
+
243
+ If the function does not expect a parameter, the wrapper will not inject it into the call.
244
+ Using `*args` and `**kwargs` will not work and no parameters will be injected.
245
+
246
+ Returns:
247
+ FunctionalAlgorithm that proxies the callable while exposing the
248
+ `Algorithm` interface.
249
+
250
+ Examples:
251
+ ```python
252
+ from gatewaysdk.algorithm.decorator import algo
253
+
254
+ @algo
255
+ def batching_algorithm(*, store, train_dataset, val_dataset):
256
+ for sample in train_dataset:
257
+ store.enqueue_rollout(input=sample, mode="train")
258
+
259
+ @algo
260
+ async def async_algorithm(*, store, train_dataset=None, val_dataset=None):
261
+ await store.enqueue_rollout(input={"prompt": "hello"}, mode="train")
262
+ ```
263
+ """
264
+ return FunctionalAlgorithm(func)
@@ -0,0 +1,7 @@
1
+ # Copyright (c) Gateway. All rights reserved.
2
+
3
+ """Evals algorithm — single-pass agent evaluation."""
4
+
5
+ from .evals import Evals
6
+
7
+ __all__ = ["Evals"]
@@ -0,0 +1,217 @@
1
+ # Copyright (c) Gateway. All rights reserved.
2
+
3
+ """Evals algorithm — single-pass agent evaluation with configurable parallelism.
4
+
5
+ Runs every dataset item through the agent exactly once, collects reward scores,
6
+ and reports aggregate metrics. No optimization, no reflection — just evaluate.
7
+
8
+ Usage via the Gateway Platform UI:
9
+ 1. Select algorithm: "Evals"
10
+ 2. Configure parallelism (how many rollouts run concurrently)
11
+ 3. Pick a dataset and agent
12
+ 4. Start the run
13
+
14
+ The algorithm enqueues rollouts in batches of ``parallelism``, waits for each
15
+ batch to complete, extracts scores, and logs per-batch and aggregate metrics.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import asyncio
21
+ import logging
22
+ import uuid
23
+ from typing import Any, ClassVar, Dict, List, Optional
24
+
25
+ from gatewaysdk.algorithm.base import Algorithm
26
+ from gatewaysdk.algorithm.utils import with_llm_proxy, with_store
27
+ from gatewaysdk.emitter import find_final_reward
28
+ from gatewaysdk.types import Dataset, NamedResources, PromptTemplate
29
+
30
+ logger = logging.getLogger(__name__)
31
+
32
+
33
+ class Evals(Algorithm):
34
+ """Single-pass evaluation algorithm.
35
+
36
+ Runs each dataset item through the agent once, collects the reward score,
37
+ and reports aggregate results. Parallelism controls how many rollouts are
38
+ in-flight at the same time.
39
+ """
40
+
41
+ # Platform metadata — auto-discovered by registry
42
+ name: ClassVar[str] = "evals"
43
+ display_name: ClassVar[str] = "Evals"
44
+ description: ClassVar[str] = "Single-pass agent evaluation"
45
+ requirements: ClassVar[Dict[str, Any]] = {"gpu": False, "min_runners": 1}
46
+ config_schema: ClassVar[Optional[Dict[str, Any]]] = {
47
+ "type": "object",
48
+ "properties": {
49
+ "parallelism": {
50
+ "type": "integer",
51
+ "default": 5,
52
+ "minimum": 1,
53
+ "maximum": 50,
54
+ "description": "Number of rollouts to run concurrently",
55
+ },
56
+ "rollout_timeout": {
57
+ "type": "number",
58
+ "default": 600.0,
59
+ "minimum": 30.0,
60
+ "description": "Timeout per rollout batch in seconds",
61
+ },
62
+ "val_fraction": {
63
+ "type": "number",
64
+ "default": 0.0,
65
+ "minimum": 0.0,
66
+ "maximum": 0.5,
67
+ "description": "Fraction of dataset held out for validation (0 = use all items)",
68
+ },
69
+ },
70
+ }
71
+
72
+ def __init__(
73
+ self,
74
+ *,
75
+ parallelism: int = 5,
76
+ rollout_timeout: float = 600.0,
77
+ ) -> None:
78
+ super().__init__()
79
+ self.parallelism = parallelism
80
+ self.rollout_timeout = rollout_timeout
81
+
82
+ @with_store
83
+ @with_llm_proxy(required=False)
84
+ async def run(
85
+ self,
86
+ llm_proxy, # injected by @with_llm_proxy (may be None)
87
+ store, # injected by @with_store
88
+ train_dataset: Optional[Dataset[Any]] = None,
89
+ val_dataset: Optional[Dataset[Any]] = None,
90
+ ) -> None:
91
+ """Run single-pass evaluation on the dataset.
92
+
93
+ Uses train_dataset as the evaluation set (the Platform UI sends
94
+ the selected dataset as train_dataset). val_dataset is ignored.
95
+ """
96
+ dataset = train_dataset
97
+ if dataset is None:
98
+ raise ValueError("A dataset is required for evaluation.")
99
+
100
+ store = self.get_store()
101
+ assert store is not None
102
+
103
+ initial_resources = self.get_initial_resources()
104
+ if not initial_resources:
105
+ raise ValueError("Initial resources must be set before running Evals.")
106
+
107
+ # Build resources: initial resources + LLM proxy resource (if available)
108
+ # The LLM proxy resource is required by agents using the @gepa.agent
109
+ # or @rollout decorators that declare an `llm: LLM` parameter.
110
+ resources: NamedResources = dict(initial_resources)
111
+ if llm_proxy is not None:
112
+ resources["llm"] = llm_proxy.as_resource()
113
+ logger.info(f"Added LLM proxy resource: model={resources['llm'].model}")
114
+
115
+ # Publish resources once
116
+ resources_id = f"evals-{uuid.uuid4().hex[:8]}"
117
+ await store.update_resources(resources_id, resources)
118
+ logger.info(f"Published resources: {resources_id}")
119
+
120
+ # Prepare dataset items
121
+ items: List[Dict[str, Any]] = []
122
+ for i, item in enumerate(dataset):
123
+ if isinstance(item, dict):
124
+ items.append(item)
125
+ else:
126
+ items.append({"task": item, "id": str(i)})
127
+
128
+ total = len(items)
129
+ logger.info(
130
+ f"Starting evaluation: {total} items, parallelism={self.parallelism}, " f"timeout={self.rollout_timeout}s"
131
+ )
132
+
133
+ # Process in batches
134
+ all_scores: List[Optional[float]] = []
135
+ step = 0
136
+
137
+ for batch_start in range(0, total, self.parallelism):
138
+ batch = items[batch_start : batch_start + self.parallelism]
139
+ batch_num = batch_start // self.parallelism + 1
140
+ total_batches = (total + self.parallelism - 1) // self.parallelism
141
+
142
+ logger.info(f"Batch {batch_num}/{total_batches}: " f"enqueuing {len(batch)} rollouts")
143
+
144
+ # Enqueue rollouts for this batch
145
+ rollout_ids: List[str] = []
146
+ for item in batch:
147
+ rollout = await store.enqueue_rollout(
148
+ input=item,
149
+ mode="test",
150
+ resources_id=resources_id,
151
+ )
152
+ rollout_ids.append(rollout.rollout_id)
153
+
154
+ # Wait for all rollouts in the batch to complete
155
+ try:
156
+ completed = await store.wait_for_rollouts(
157
+ rollout_ids=rollout_ids,
158
+ timeout=self.rollout_timeout,
159
+ )
160
+ except Exception as e:
161
+ logger.error(f"Batch {batch_num} failed: {e}")
162
+ all_scores.extend([None] * len(batch))
163
+ continue
164
+
165
+ # Extract scores from completed rollouts
166
+ batch_scores: List[Optional[float]] = []
167
+ for rollout in completed:
168
+ spans = await store.query_spans(rollout.rollout_id)
169
+ reward = find_final_reward(spans)
170
+ batch_scores.append(reward)
171
+
172
+ all_scores.extend(batch_scores)
173
+
174
+ # Log per-batch metrics
175
+ valid_scores = [s for s in batch_scores if s is not None]
176
+ batch_avg = sum(valid_scores) / len(valid_scores) if valid_scores else 0.0
177
+ batch_completed = sum(1 for r in completed if r.status == "succeeded")
178
+
179
+ step += 1
180
+ if hasattr(store, "log"):
181
+ store.log(
182
+ {
183
+ "batch_avg_score": batch_avg,
184
+ "batch_completed": batch_completed,
185
+ "batch_total": len(batch),
186
+ },
187
+ step=step,
188
+ )
189
+
190
+ logger.info(
191
+ f"Batch {batch_num}/{total_batches} done: "
192
+ f"avg_score={batch_avg:.3f}, "
193
+ f"completed={batch_completed}/{len(batch)}"
194
+ )
195
+
196
+ # Log aggregate metrics
197
+ valid_scores = [s for s in all_scores if s is not None]
198
+ mean_score = sum(valid_scores) / len(valid_scores) if valid_scores else 0.0
199
+ completion_rate = len(valid_scores) / total if total > 0 else 0.0
200
+
201
+ step += 1
202
+ if hasattr(store, "log"):
203
+ store.log(
204
+ {
205
+ "mean_score": mean_score,
206
+ "completion_rate": completion_rate,
207
+ "total_evaluated": len(valid_scores),
208
+ "total_items": total,
209
+ },
210
+ step=step,
211
+ )
212
+
213
+ logger.info(
214
+ f"Evaluation complete: mean_score={mean_score:.3f}, "
215
+ f"completion_rate={completion_rate:.1%}, "
216
+ f"{len(valid_scores)}/{total} items scored"
217
+ )