agentbyte 0.44.1__tar.gz → 0.46.0__tar.gz

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 (378) hide show
  1. {agentbyte-0.44.1 → agentbyte-0.46.0}/.gitignore +3 -0
  2. {agentbyte-0.44.1 → agentbyte-0.46.0}/CHANGELOG.md +40 -0
  3. {agentbyte-0.44.1 → agentbyte-0.46.0}/PKG-INFO +2 -2
  4. {agentbyte-0.44.1 → agentbyte-0.46.0}/README.md +1 -1
  5. agentbyte-0.46.0/src/agentbyte/__about__.py +2 -0
  6. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/cli/main.py +6 -0
  7. agentbyte-0.46.0/src/agentbyte/cli/optim_commands.py +160 -0
  8. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/history/__init__.py +4 -0
  9. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/history/conformance.py +36 -1
  10. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/history/models.py +71 -0
  11. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/history/sql.py +52 -7
  12. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/history/sqlite.py +47 -7
  13. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/history/store.py +52 -1
  14. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/optim/__init__.py +18 -0
  15. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/optim/base.py +20 -1
  16. agentbyte-0.46.0/src/agentbyte/optim/report.py +462 -0
  17. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/webui/eval_routes.py +24 -0
  18. agentbyte-0.46.0/src/agentbyte/webui/ui/assets/index-CrAxIGFr.js +82 -0
  19. agentbyte-0.46.0/src/agentbyte/webui/ui/assets/index-m9IRI-Jx.css +1 -0
  20. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/webui/ui/index.html +2 -2
  21. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/eval/test_eval_history_backends.py +62 -0
  22. agentbyte-0.46.0/tests/optim/test_report.py +263 -0
  23. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/webui/test_eval_routes.py +27 -0
  24. agentbyte-0.44.1/src/agentbyte/__about__.py +0 -2
  25. agentbyte-0.44.1/src/agentbyte/webui/ui/assets/index-BsS4WYZu.css +0 -1
  26. agentbyte-0.44.1/src/agentbyte/webui/ui/assets/index-tGvO1yue.js +0 -82
  27. {agentbyte-0.44.1 → agentbyte-0.46.0}/LICENSE +0 -0
  28. {agentbyte-0.44.1 → agentbyte-0.46.0}/pyproject.toml +0 -0
  29. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/__init__.py +0 -0
  30. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/_optional.py +0 -0
  31. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/agents/__init__.py +0 -0
  32. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/agents/agent.py +0 -0
  33. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/agents/agent_as_tool.py +0 -0
  34. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/agents/base.py +0 -0
  35. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/agents/embedding_agent.py +0 -0
  36. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/agents/types.py +0 -0
  37. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/cancellation_token.py +0 -0
  38. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/catalog.py +0 -0
  39. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/cli/__init__.py +0 -0
  40. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/cli/__main__.py +0 -0
  41. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/cli/eval_commands.py +0 -0
  42. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/cli/loading.py +0 -0
  43. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/compaction/__init__.py +0 -0
  44. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/compaction/counters.py +0 -0
  45. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/compaction/errors.py +0 -0
  46. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/compaction/grouping.py +0 -0
  47. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/compaction/strategies.py +0 -0
  48. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/component.py +0 -0
  49. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/context.py +0 -0
  50. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/context_providers/__init__.py +0 -0
  51. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/context_providers/base.py +0 -0
  52. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/context_providers/skill_tools.py +0 -0
  53. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/context_providers/skills.py +0 -0
  54. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/dataset/__init__.py +0 -0
  55. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/dataset/_aiosqlite.py +0 -0
  56. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/dataset/base.py +0 -0
  57. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/dataset/config.py +0 -0
  58. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/dataset/importer.py +0 -0
  59. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/dataset/json.py +0 -0
  60. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/dataset/loader.py +0 -0
  61. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/dataset/publish.py +0 -0
  62. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/dataset/publish_config.py +0 -0
  63. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/dataset/publishers.py +0 -0
  64. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/dataset/s3.py +0 -0
  65. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/dataset/sources.py +0 -0
  66. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/dataset/sqlite.py +0 -0
  67. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/dataset/sqlite_db.py +0 -0
  68. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/dataset/write_config.py +0 -0
  69. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/dataset/writers.py +0 -0
  70. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/entity.py +0 -0
  71. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/__init__.py +0 -0
  72. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/base.py +0 -0
  73. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/checks/__init__.py +0 -0
  74. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/checks/decorator.py +0 -0
  75. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/checks/keyword.py +0 -0
  76. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/checks/local.py +0 -0
  77. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/checks/process.py +0 -0
  78. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/checks/tool.py +0 -0
  79. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/checks/types.py +0 -0
  80. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/comparison.py +0 -0
  81. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/eval_dataset.py +0 -0
  82. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/history/errors.py +0 -0
  83. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/history/recorder.py +0 -0
  84. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/history/transitions.py +0 -0
  85. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/judges/__init__.py +0 -0
  86. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/judges/base.py +0 -0
  87. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/judges/composite.py +0 -0
  88. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/judges/llm.py +0 -0
  89. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/judges/pairwise.py +0 -0
  90. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/judges/reference.py +0 -0
  91. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/judges/trajectory.py +0 -0
  92. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/judges/validation.py +0 -0
  93. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/pairwise.py +0 -0
  94. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/report.py +0 -0
  95. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/runner.py +0 -0
  96. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/splitting.py +0 -0
  97. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/targets/__init__.py +0 -0
  98. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/targets/agent.py +0 -0
  99. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/targets/model.py +0 -0
  100. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/targets/multi_turn.py +0 -0
  101. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/targets/orchestrator.py +0 -0
  102. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/targets/runtime.py +0 -0
  103. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/targets/workflow.py +0 -0
  104. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/types.py +0 -0
  105. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/workbench/__init__.py +0 -0
  106. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/workbench/coordinator.py +0 -0
  107. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/workbench/jobs.py +0 -0
  108. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/workbench/smoke.py +0 -0
  109. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/workbench/smoke_tasks.json +0 -0
  110. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/workbench/suite.py +0 -0
  111. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/eval/workbench/verdict.py +0 -0
  112. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/execution_trace/__init__.py +0 -0
  113. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/execution_trace/collector.py +0 -0
  114. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/execution_trace/models.py +0 -0
  115. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/__init__.py +0 -0
  116. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/_retry_observability.py +0 -0
  117. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/auth.py +0 -0
  118. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/azure/__init__.py +0 -0
  119. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/azure/auth.py +0 -0
  120. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/azure/chat.py +0 -0
  121. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/azure/embedding.py +0 -0
  122. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/azure/settings.py +0 -0
  123. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/azure_openai.py +0 -0
  124. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/azure_openai_embedding.py +0 -0
  125. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/base.py +0 -0
  126. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/embeddings_base.py +0 -0
  127. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/openai/__init__.py +0 -0
  128. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/openai/chat.py +0 -0
  129. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/openai/embedding.py +0 -0
  130. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/openai/settings.py +0 -0
  131. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/openai_embedding.py +0 -0
  132. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/pricing.py +0 -0
  133. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/retry_policy.py +0 -0
  134. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/settings.py +0 -0
  135. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/llm/types.py +0 -0
  136. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/logger.py +0 -0
  137. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/memory/__init__.py +0 -0
  138. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/memory/base.py +0 -0
  139. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/messages.py +0 -0
  140. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/middleware/__init__.py +0 -0
  141. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/middleware/base.py +0 -0
  142. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/middleware/otel.py +0 -0
  143. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/middleware/retry.py +0 -0
  144. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/middleware/sql_usage.py +0 -0
  145. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/middleware/usage_logger.py +0 -0
  146. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/notebook.py +0 -0
  147. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/optim/config.py +0 -0
  148. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/optim/gepa.py +0 -0
  149. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/optim/mipro.py +0 -0
  150. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/optim/pareto.py +0 -0
  151. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/optim/reflective.py +0 -0
  152. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/optim/spec.py +0 -0
  153. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/optim/trace.py +0 -0
  154. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/orchestration/__init__.py +0 -0
  155. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/orchestration/ai.py +0 -0
  156. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/orchestration/base.py +0 -0
  157. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/orchestration/handoff.py +0 -0
  158. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/orchestration/plan.py +0 -0
  159. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/orchestration/policies.py +0 -0
  160. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/orchestration/round_robin.py +0 -0
  161. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/__init__.py +0 -0
  162. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/agents.py +0 -0
  163. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/clients.py +0 -0
  164. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/instruction_registry.py +0 -0
  165. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/instructions/orchestrator.yaml +0 -0
  166. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/instructions/query_rewriter.yaml +0 -0
  167. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/instructions/researcher.yaml +0 -0
  168. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/instructions/reviewer.yaml +0 -0
  169. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/instructions/writer.yaml +0 -0
  170. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/orchestration.py +0 -0
  171. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/skills/contracts-analyst/SKILL.md +0 -0
  172. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/skills/hr-analyst/SKILL.md +0 -0
  173. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/skills/hr-analyst/resources/departments.md +0 -0
  174. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/skills/hr-analyst/resources/employees.md +0 -0
  175. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/skills/hr-analyst/resources/payroll.md +0 -0
  176. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/streaming.py +0 -0
  177. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/presets/workflow.py +0 -0
  178. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/session_store.py +0 -0
  179. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/skills/__init__.py +0 -0
  180. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/skills/base.py +0 -0
  181. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/skills/resources.py +0 -0
  182. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/skills/scripts.py +0 -0
  183. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/skills/sources.py +0 -0
  184. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/skills/validation.py +0 -0
  185. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/termination/__init__.py +0 -0
  186. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/termination/base.py +0 -0
  187. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/termination/cancellation.py +0 -0
  188. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/termination/composite.py +0 -0
  189. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/termination/consecutive_agent.py +0 -0
  190. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/termination/external.py +0 -0
  191. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/termination/function_call.py +0 -0
  192. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/termination/handoff.py +0 -0
  193. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/termination/max_message.py +0 -0
  194. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/termination/predicate.py +0 -0
  195. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/termination/source.py +0 -0
  196. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/termination/text_mention.py +0 -0
  197. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/termination/timeout.py +0 -0
  198. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/termination/token_usage.py +0 -0
  199. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/tools/__init__.py +0 -0
  200. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/tools/base.py +0 -0
  201. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/tools/coding_tools.py +0 -0
  202. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/tools/core_tools.py +0 -0
  203. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/tools/decorator.py +0 -0
  204. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/tools/memory_tool.py +0 -0
  205. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/tools/research_tools.py +0 -0
  206. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/types.py +0 -0
  207. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/webui/__init__.py +0 -0
  208. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/webui/discovery.py +0 -0
  209. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/webui/execution.py +0 -0
  210. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/webui/models.py +0 -0
  211. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/webui/registry.py +0 -0
  212. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/webui/server.py +0 -0
  213. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/webui/session_store.py +0 -0
  214. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/webui/sessions.py +0 -0
  215. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/webui/ui/vite.svg +0 -0
  216. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/__init__.py +0 -0
  217. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/agent.py +0 -0
  218. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/core/__init__.py +0 -0
  219. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/core/_structure_hash.py +0 -0
  220. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/core/checkpoint.py +0 -0
  221. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/core/models.py +0 -0
  222. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/core/runner.py +0 -0
  223. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/core/workflow.py +0 -0
  224. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/defaults.py +0 -0
  225. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/errors.py +0 -0
  226. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/loader.py +0 -0
  227. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/schema.py +0 -0
  228. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/schema_utils.py +0 -0
  229. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/sqlite_checkpoint.py +0 -0
  230. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/steps/__init__.py +0 -0
  231. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/steps/agent.py +0 -0
  232. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/steps/echo.py +0 -0
  233. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/steps/function.py +0 -0
  234. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/steps/http.py +0 -0
  235. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/steps/step.py +0 -0
  236. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/steps/subworkflow.py +0 -0
  237. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/steps/transform.py +0 -0
  238. {agentbyte-0.44.1 → agentbyte-0.46.0}/src/agentbyte/workflow/visualizer.py +0 -0
  239. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/agents/test_agent_as_tool.py +0 -0
  240. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/agents/test_agent_basic.py +0 -0
  241. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/agents/test_agent_context_providers.py +0 -0
  242. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/agents/test_agent_error_response.py +0 -0
  243. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/agents/test_agent_event_types.py +0 -0
  244. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/agents/test_agent_memory_integration.py +0 -0
  245. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/agents/test_agent_middleware_integration.py +0 -0
  246. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/agents/test_agent_response_accessors.py +0 -0
  247. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/agents/test_agent_retry_middleware.py +0 -0
  248. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/agents/test_agent_stop_at_tools.py +0 -0
  249. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/agents/test_agent_stream_events.py +0 -0
  250. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/agents/test_embedding_agent.py +0 -0
  251. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/agents/test_tool_approval.py +0 -0
  252. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/agents/test_tool_batch_resolution.py +0 -0
  253. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/agents/test_tool_metadata.py +0 -0
  254. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/cli/test_loading.py +0 -0
  255. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/cli/test_registry_check.py +0 -0
  256. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/compaction/test_compaction.py +0 -0
  257. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/context_providers/__init__.py +0 -0
  258. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/context_providers/test_skill_tools.py +0 -0
  259. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/context_providers/test_skills_provider.py +0 -0
  260. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/dataset/fake_s3.py +0 -0
  261. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/dataset/test_dataset_exit.py +0 -0
  262. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/dataset/test_loader.py +0 -0
  263. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/dataset/test_multi_table.py +0 -0
  264. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/dataset/test_publish.py +0 -0
  265. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/dataset/test_sqlite_db.py +0 -0
  266. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/eval/test_eval_dataset.py +0 -0
  267. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/eval/test_eval_history.py +0 -0
  268. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/eval/test_eval_jobs.py +0 -0
  269. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/eval/test_eval_workbench.py +0 -0
  270. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/eval/test_execution_trajectories.py +0 -0
  271. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/eval/test_multi_turn.py +0 -0
  272. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/eval/test_pairwise.py +0 -0
  273. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/eval/test_phase1_runner_and_targets.py +0 -0
  274. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/eval/test_phase2_checks_and_reports.py +0 -0
  275. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/eval/test_score_integrity.py +0 -0
  276. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/eval/test_splitting.py +0 -0
  277. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/eval/test_types_and_judges.py +0 -0
  278. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/examples/test_compaction_webapp.py +0 -0
  279. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/llm/test_azure_client.py +0 -0
  280. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/llm/test_azure_embedding_client.py +0 -0
  281. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/llm/test_llm_types.py +0 -0
  282. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/llm/test_openai_client.py +0 -0
  283. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/llm/test_openai_embedding_client.py +0 -0
  284. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/llm/test_pricing.py +0 -0
  285. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/llm/test_retry_observability.py +0 -0
  286. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/llm/test_retry_policy_api.py +0 -0
  287. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/llm/test_retryable_error_substrings.py +0 -0
  288. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/memory/test_memory.py +0 -0
  289. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/middleware/test_context_compaction.py +0 -0
  290. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/middleware/test_deduplicate_tool_result.py +0 -0
  291. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/middleware/test_middleware_chain.py +0 -0
  292. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/middleware/test_otel.py +0 -0
  293. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/middleware/test_retry_middleware.py +0 -0
  294. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/middleware/test_sql_usage.py +0 -0
  295. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/middleware/test_usage_logger.py +0 -0
  296. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/optim/__init__.py +0 -0
  297. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/optim/test_base.py +0 -0
  298. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/optim/test_base_integration.py +0 -0
  299. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/optim/test_config.py +0 -0
  300. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/optim/test_description_tunable.py +0 -0
  301. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/optim/test_gepa.py +0 -0
  302. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/optim/test_mipro.py +0 -0
  303. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/optim/test_orchestrator_optim.py +0 -0
  304. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/optim/test_pareto.py +0 -0
  305. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/optim/test_reflective.py +0 -0
  306. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/optim/test_score_integrity.py +0 -0
  307. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/optim/test_spec.py +0 -0
  308. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/optim/test_trace.py +0 -0
  309. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/orchestration/test_ai_orchestrator.py +0 -0
  310. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/orchestration/test_base_orchestrator.py +0 -0
  311. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/orchestration/test_handoff_orchestrator.py +0 -0
  312. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/orchestration/test_history_tool_call_pairing.py +0 -0
  313. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/orchestration/test_orchestration_usage_breakdown.py +0 -0
  314. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/orchestration/test_orchestrator_agent_contract.py +0 -0
  315. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/orchestration/test_orchestrator_finalization.py +0 -0
  316. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/orchestration/test_orchestrator_member_events.py +0 -0
  317. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/orchestration/test_orchestrator_otel.py +0 -0
  318. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/orchestration/test_orchestrator_synthesis.py +0 -0
  319. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/orchestration/test_plan_orchestrator.py +0 -0
  320. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/orchestration/test_round_robin.py +0 -0
  321. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/presets/test_agents.py +0 -0
  322. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/presets/test_clients.py +0 -0
  323. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/presets/test_instruction_registry.py +0 -0
  324. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/presets/test_orchestration.py +0 -0
  325. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/presets/test_streaming.py +0 -0
  326. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/presets/test_workflow.py +0 -0
  327. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/skills/__init__.py +0 -0
  328. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/skills/test_base.py +0 -0
  329. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/skills/test_resources.py +0 -0
  330. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/skills/test_scripts.py +0 -0
  331. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/skills/test_sources.py +0 -0
  332. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/termination/test_base.py +0 -0
  333. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/termination/test_cancellation.py +0 -0
  334. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/termination/test_composite.py +0 -0
  335. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/termination/test_consecutive_agent.py +0 -0
  336. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/termination/test_external.py +0 -0
  337. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/termination/test_function_call.py +0 -0
  338. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/termination/test_handoff.py +0 -0
  339. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/termination/test_max_message.py +0 -0
  340. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/termination/test_predicate.py +0 -0
  341. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/termination/test_source.py +0 -0
  342. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/termination/test_text_mention.py +0 -0
  343. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/termination/test_timeout.py +0 -0
  344. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/termination/test_token_usage.py +0 -0
  345. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/test_cancellation_token.py +0 -0
  346. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/test_context.py +0 -0
  347. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/test_logger.py +0 -0
  348. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/test_messages.py +0 -0
  349. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/test_option_enums.py +0 -0
  350. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/test_optional_extras.py +0 -0
  351. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/test_package_api.py +0 -0
  352. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/test_session_store.py +0 -0
  353. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/test_types.py +0 -0
  354. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/test_vanilla_chunker.py +0 -0
  355. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/tools/test_coding_tools.py +0 -0
  356. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/tools/test_memory_tool.py +0 -0
  357. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/tools/test_research_tools.py +0 -0
  358. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/tools/test_tools.py +0 -0
  359. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/webui/__init__.py +0 -0
  360. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/webui/helpers.py +0 -0
  361. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/webui/test_execution.py +0 -0
  362. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/webui/test_package_api.py +0 -0
  363. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/webui/test_registry.py +0 -0
  364. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/webui/test_server.py +0 -0
  365. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/webui/test_sessions.py +0 -0
  366. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/webui/test_workflow_streaming.py +0 -0
  367. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/workflow/recovery_worker.py +0 -0
  368. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/workflow/test_agent_step_imports.py +0 -0
  369. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/workflow/test_checkpoint.py +0 -0
  370. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/workflow/test_subworkflow_step.py +0 -0
  371. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/workflow/test_workflow_agent.py +0 -0
  372. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/workflow/test_workflow_class.py +0 -0
  373. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/workflow/test_workflow_models.py +0 -0
  374. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/workflow/test_workflow_reliability.py +0 -0
  375. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/workflow/test_workflow_runner.py +0 -0
  376. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/workflow/test_workflow_schema.py +0 -0
  377. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/workflow/test_workflow_steps.py +0 -0
  378. {agentbyte-0.44.1 → agentbyte-0.46.0}/tests/workflow/test_workflow_visualizer.py +0 -0
@@ -72,5 +72,8 @@ data/flatfiles/*
72
72
  *.sqlite-shm
73
73
  *.writer.lock
74
74
 
75
+ # Optimization reports written by notebooks (report.md, report.json, trace.json)
76
+ optim-reports/
77
+
75
78
  # marimo local session cache
76
79
  __marimo__/
@@ -6,6 +6,46 @@ The format follows Keep a Changelog principles and semantic versioning.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.46.0] - 2026-10-05
10
+
11
+ ### Added
12
+
13
+ - Evaluation UI: read-only optimization pages (spec 0068 phase 3). The Evaluations home page lists
14
+ stored optimization runs (suite, optimizer, seed → best, cost); `#/evals/optimizations/<id>`
15
+ renders the report — proposed changes as seed/best text, per-task outcomes, remaining failures
16
+ with the judge's reasoning, reflector diagnoses and edits, candidates, cost — with Copy markdown
17
+ and Download report.md.
18
+ - `GET /api/eval/optimizations?suite=` and `GET /api/eval/optimizations/{id}` (`{run, report,
19
+ markdown}`). They read the history store directly, so runs recorded for suites outside the
20
+ server's catalog (e.g. notebook suites) are shown.
21
+
22
+ ## [0.45.0] - 2026-10-05
23
+
24
+ ### Added
25
+
26
+ - Optimization report (spec 0068): `result.report(title=..., pass_score=...)` /
27
+ `agentbyte.optim.build_report(trace)` return an `OptimizationReport` — summary, proposed changes
28
+ (seed vs best text per tuned component), per-task outcomes (`TaskStatus`: fixed, regressed,
29
+ still_failing, passing), remaining failures with the judge's reasoning, every reflector diagnosis
30
+ and edit with its outcome, candidates and cost. `to_markdown()` is written for a reviewer or AI
31
+ coding agent; `save(dir)` writes `report.md`, `report.json` and `trace.json`. Built from the trace
32
+ alone, so a saved trace reproduces the same report.
33
+ - The optimization trace ends with a `result` event (best, rounds, rollouts, cost, latency).
34
+ - Optimization runs in the evaluation history: `OptimizationRunRecord` and
35
+ `save_optimization` / `list_optimizations(suite=...)` / `get_optimization` on the memory, SQLite and
36
+ SQLAlchemy stores; `record.report()` rebuilds the report. Conformance check
37
+ `optimization_runs_round_trip_per_suite`.
38
+ - CLI: `agentbyte optim report <trace.json | run-id> [--history] [--pass-score] [--format] [--out]`
39
+ and `agentbyte optim list [--suite] [--history]`.
40
+
41
+ ### Changed
42
+
43
+ - History database layout version 2 (`STORE_SCHEMA_VERSION`) adds the `optimization_runs` table.
44
+ Opening a layout-1 file as a writer migrates it; a reader on a layout-1 file asks for one writer
45
+ open first; Agentbyte 0.44 refuses a layout-2 file. Run/item records keep `SCHEMA_VERSION` 1.
46
+ The new store methods are not abstract, so stores written against the run-only contract still
47
+ instantiate (they raise `NotImplementedError` for optimization runs).
48
+
9
49
  ## [0.44.1] - 2026-10-05
10
50
 
11
51
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agentbyte
3
- Version: 0.44.1
3
+ Version: 0.46.0
4
4
  Summary: A toolkit for designing multiagent systems
5
5
  Author-email: MrDataPsycho <mr.data.psycho@gmail.com>
6
6
  License-Expression: LicenseRef-Proprietary
@@ -77,7 +77,7 @@ Description-Content-Type: text/markdown
77
77
 
78
78
  Agentbyte is an observability-first agentic AI framework for building and studying multiagent systems with a learning-first, implementation-oriented workflow.
79
79
 
80
- Current release: **0.44.1**
80
+ Current release: **0.46.0**
81
81
 
82
82
  ## Building an Agent
83
83
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Agentbyte is an observability-first agentic AI framework for building and studying multiagent systems with a learning-first, implementation-oriented workflow.
4
4
 
5
- Current release: **0.44.1**
5
+ Current release: **0.46.0**
6
6
 
7
7
  ## Building an Agent
8
8
 
@@ -0,0 +1,2 @@
1
+ __version__ = "0.46.0"
2
+ VERSION = __version__
@@ -9,6 +9,7 @@ import sys
9
9
  from agentbyte.__about__ import VERSION
10
10
  from agentbyte.catalog import BaseInstructionCatalog
11
11
  from agentbyte.cli.eval_commands import add_eval_parser, cmd_eval
12
+ from agentbyte.cli.optim_commands import add_optim_parser, cmd_optim
12
13
  from agentbyte.cli.loading import ObjectImportError, import_object
13
14
 
14
15
 
@@ -302,6 +303,7 @@ def _build_parser() -> argparse.ArgumentParser:
302
303
 
303
304
  # eval
304
305
  add_eval_parser(subparsers)
306
+ add_optim_parser(subparsers)
305
307
 
306
308
  return parser
307
309
 
@@ -329,6 +331,10 @@ def main() -> None:
329
331
  if not args.eval_command:
330
332
  parser.parse_args(["eval", "--help"])
331
333
  sys.exit(cmd_eval(args))
334
+ if args.command == "optim":
335
+ if not args.optim_command:
336
+ parser.parse_args(["optim", "--help"])
337
+ sys.exit(cmd_optim(args))
332
338
 
333
339
  parser.print_help()
334
340
  sys.exit(1)
@@ -0,0 +1,160 @@
1
+ """``agentbyte optim`` sub-commands: report and list optimization runs (spec 0068).
2
+
3
+ ``report`` prints or saves the report of an optimization run, read from a saved trace file
4
+ (``trace.json``) or from a run stored in the evaluation history. ``list`` shows the stored runs,
5
+ optionally for one suite.
6
+
7
+ Exit codes: 0 = done, 2 = the source could not be read or is not an optimization run.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import argparse
13
+ import asyncio
14
+ import json
15
+ import sys
16
+ from pathlib import Path
17
+ from typing import Any
18
+
19
+ EXIT_OK = 0
20
+ EXIT_ERROR = 2
21
+
22
+ DEFAULT_HISTORY = "eval.sqlite"
23
+
24
+
25
+ class _CliError(Exception):
26
+ """A configuration or input problem reported with exit code 2."""
27
+
28
+
29
+ def add_optim_parser(subparsers: Any) -> None:
30
+ """Register ``agentbyte optim`` and its sub-commands."""
31
+ optim_parser = subparsers.add_parser("optim", help="Report optimization runs")
32
+ optim_sub = optim_parser.add_subparsers(dest="optim_command", metavar="<subcommand>")
33
+ history_help = f"SQLite evaluation history file (default: ./{DEFAULT_HISTORY})"
34
+
35
+ report_parser = optim_sub.add_parser(
36
+ "report", help="Print or save the report of an optimization run"
37
+ )
38
+ report_parser.add_argument(
39
+ "source",
40
+ help="A trace file (*.json, from report.save() or trace.save()) or a stored run ID",
41
+ )
42
+ report_parser.add_argument("--history", default=DEFAULT_HISTORY, help=history_help)
43
+ report_parser.add_argument(
44
+ "--pass-score", type=float, default=None,
45
+ help="Score a task needs to pass (default: the stored run's, else 10.0)",
46
+ )
47
+ report_parser.add_argument("--title", default=None, help="Report title")
48
+ report_parser.add_argument("--format", choices=["markdown", "json"], default="markdown")
49
+ report_parser.add_argument(
50
+ "--out", default=None,
51
+ help="Directory to write report.md, report.json and trace.json instead of printing",
52
+ )
53
+
54
+ list_parser = optim_sub.add_parser("list", help="List optimization runs in a history file")
55
+ list_parser.add_argument("--suite", default=None, help="Only runs recorded for this suite")
56
+ list_parser.add_argument("--history", default=DEFAULT_HISTORY, help=history_help)
57
+ list_parser.add_argument("--limit", type=int, default=50)
58
+ list_parser.add_argument("--format", choices=["text", "json"], default="text")
59
+
60
+
61
+ def cmd_optim(args: argparse.Namespace) -> int:
62
+ """Dispatch ``agentbyte optim <subcommand>``."""
63
+ commands = {"report": _cmd_report, "list": _cmd_list}
64
+ command = commands.get(getattr(args, "optim_command", None) or "")
65
+ if command is None:
66
+ print("Usage: agentbyte optim <report|list>", file=sys.stderr)
67
+ return EXIT_ERROR
68
+ try:
69
+ return command(args)
70
+ except _CliError as exc:
71
+ print(f"Error: {exc}", file=sys.stderr)
72
+ return EXIT_ERROR
73
+
74
+
75
+ def _cmd_report(args: argparse.Namespace) -> int:
76
+ path = Path(args.source)
77
+ if path.suffix == ".json" or path.is_file():
78
+ report = _report_from_trace(path, args)
79
+ else:
80
+ report = asyncio.run(_report_from_history(args))
81
+ return _emit(report, args)
82
+
83
+
84
+ def _report_from_trace(path: Path, args: argparse.Namespace) -> Any:
85
+ from agentbyte.optim import DEFAULT_PASS_SCORE, build_report, load_trace
86
+
87
+ if not path.is_file():
88
+ raise _CliError(f"No trace file at {path}")
89
+ try:
90
+ return build_report(
91
+ load_trace(path),
92
+ title=args.title or path.parent.name or "Optimization run",
93
+ pass_score=DEFAULT_PASS_SCORE if args.pass_score is None else args.pass_score,
94
+ )
95
+ except (ValueError, KeyError) as exc:
96
+ raise _CliError(f"{path} is not a reportable optimization trace: {exc}") from exc
97
+
98
+
99
+ async def _report_from_history(args: argparse.Namespace) -> Any:
100
+ async with _open_history(args.history) as store:
101
+ record = await store.get_optimization(args.source)
102
+ if record is None:
103
+ raise _CliError(f"No optimization run {args.source!r} in {args.history}")
104
+ updates = {k: v for k, v in (("title", args.title), ("pass_score", args.pass_score)) if v is not None}
105
+ return record.model_copy(update=updates).report()
106
+
107
+
108
+ def _cmd_list(args: argparse.Namespace) -> int:
109
+ records = asyncio.run(_list(args))
110
+ if args.format == "json":
111
+ print(json.dumps([r.model_dump(mode="json", exclude={"trace"}) for r in records], indent=2))
112
+ return EXIT_OK
113
+ if not records:
114
+ print("No optimization runs recorded" + (f" for suite {args.suite!r}." if args.suite else "."))
115
+ return EXIT_OK
116
+ for r in records:
117
+ cost = "-" if r.cost_usd is None else f"${r.cost_usd:.4f}"
118
+ print(
119
+ f"{r.id} {r.created_at:%Y-%m-%d %H:%M} {r.suite:<20} {r.optimizer or '?':<22} "
120
+ f"{_avg(r.seed_avg)} -> {_avg(r.best_avg)} best={r.best} rollouts={r.eval_count} {cost}"
121
+ )
122
+ return EXIT_OK
123
+
124
+
125
+ async def _list(args: argparse.Namespace) -> list[Any]:
126
+ async with _open_history(args.history) as store:
127
+ return await store.list_optimizations(suite=args.suite, limit=args.limit)
128
+
129
+
130
+ def _open_history(history: str) -> Any:
131
+ from agentbyte.eval.history import EvalHistoryError, SQLiteEvalRunStore
132
+
133
+ if not Path(history).is_file():
134
+ raise _CliError(f"No evaluation history at {history}")
135
+
136
+ class _Reader:
137
+ async def __aenter__(self) -> Any:
138
+ self.store = SQLiteEvalRunStore(history, writer=False)
139
+ try:
140
+ return await self.store.__aenter__()
141
+ except EvalHistoryError as exc:
142
+ raise _CliError(f"Cannot read {history}: {exc}") from exc
143
+
144
+ async def __aexit__(self, *exc: Any) -> None:
145
+ await self.store.__aexit__(*exc)
146
+
147
+ return _Reader()
148
+
149
+
150
+ def _avg(value: float | None) -> str:
151
+ return "—" if value is None else f"{value:.1f}"
152
+
153
+
154
+ def _emit(report: Any, args: argparse.Namespace) -> int:
155
+ if args.out:
156
+ out = report.save(args.out)
157
+ print(f"Wrote {out / 'report.md'}, {out / 'report.json'} and {out / 'trace.json'}")
158
+ return EXIT_OK
159
+ print(report.to_json() if args.format == "json" else report.to_markdown(), end="")
160
+ return EXIT_OK
@@ -22,11 +22,13 @@ from .errors import (
22
22
  from .models import (
23
23
  EVIDENCE_VERSION,
24
24
  SCHEMA_VERSION,
25
+ STORE_SCHEMA_VERSION,
25
26
  CaptureMode,
26
27
  EvalItemRecord,
27
28
  EvalRunRecord,
28
29
  EvidenceStatus,
29
30
  ItemState,
31
+ OptimizationRunRecord,
30
32
  Redactor,
31
33
  RunStatus,
32
34
  StructuredPayload,
@@ -50,6 +52,7 @@ def __getattr__(name: str) -> Any:
50
52
  __all__ = [
51
53
  "EVIDENCE_VERSION",
52
54
  "SCHEMA_VERSION",
55
+ "STORE_SCHEMA_VERSION",
53
56
  "CaptureMode",
54
57
  "EvalHistoryConflictError",
55
58
  "EvalHistoryError",
@@ -67,6 +70,7 @@ __all__ = [
67
70
  "EvidenceStatus",
68
71
  "ItemState",
69
72
  "MemoryEvalRunStore",
73
+ "OptimizationRunRecord",
70
74
  "Redactor",
71
75
  "RunStatus",
72
76
  "SQLiteEvalRunStore",
@@ -17,6 +17,7 @@ from __future__ import annotations
17
17
  import asyncio
18
18
  from collections.abc import Awaitable, Callable
19
19
  from contextlib import AbstractAsyncContextManager
20
+ from typing import Any
20
21
 
21
22
  from pydantic import BaseModel
22
23
 
@@ -32,7 +33,7 @@ from .errors import (
32
33
  EvalRunNotFoundError,
33
34
  EvalSerializationError,
34
35
  )
35
- from .models import EvalItemRecord, EvalRunRecord, StructuredPayload
36
+ from .models import EvalItemRecord, EvalRunRecord, OptimizationRunRecord, StructuredPayload
36
37
  from .recorder import EvalRunRecorder
37
38
  from .store import EvalRunStore
38
39
 
@@ -322,6 +323,40 @@ async def check_recorder_bounds_concurrency_without_lost_writes(store: EvalRunSt
322
323
  assert [i.overall for i in items] == [float(i % 10) for i in range(16)]
323
324
 
324
325
 
326
+ def _optimization_trace(seed_avg: float, best_avg: float) -> Any:
327
+ """A minimal reportable trace: seed, one better candidate, and the closing result."""
328
+ from agentbyte.optim.trace import OptimizationTrace # optim depends on eval; import late
329
+
330
+ trace = OptimizationTrace()
331
+ trace.record("candidate", 0, name="seed", parent=None, rationale="seed", avg=seed_avg,
332
+ eligible=True, task_scores={"t": seed_avg}, components={"instructions": "old"})
333
+ trace.record("candidate", 1, name="next", parent="seed", rationale="r", avg=best_avg,
334
+ eligible=True, task_scores={"t": best_avg}, components={"instructions": "new"})
335
+ trace.record("result", 1, best="next", best_avg=best_avg, optimizer="Scripted", rounds=1,
336
+ eval_count=2, cost={"total": {"usd": 0.25}})
337
+ return trace
338
+
339
+
340
+ async def check_optimization_runs_round_trip_per_suite(store: EvalRunStore) -> None:
341
+ first = OptimizationRunRecord.from_trace(_optimization_trace(2.0, 6.0), suite="alpha")
342
+ second = OptimizationRunRecord.from_trace(_optimization_trace(3.0, 9.0), suite="beta")
343
+ third = OptimizationRunRecord.from_trace(_optimization_trace(6.0, 8.0), suite="alpha")
344
+ for record in (first, second, third):
345
+ assert await store.save_optimization(record) == record
346
+ await _raises(EvalHistoryConflictError, store.save_optimization(first))
347
+
348
+ listed = await store.list_optimizations(suite="alpha")
349
+ assert [r.id for r in listed] == [third.id, first.id]
350
+ assert all(r.trace is None for r in listed)
351
+ assert [r.id for r in await store.list_optimizations(limit=1, offset=1)] == [second.id]
352
+
353
+ loaded = await store.get_optimization(first.id)
354
+ assert loaded == first
355
+ assert (loaded.best, loaded.best_avg, loaded.cost_usd) == ("next", 6.0, 0.25)
356
+ assert loaded.report().changed_components[0].best == "new"
357
+ assert await store.get_optimization("missing") is None
358
+
359
+
325
360
  CHECKS: dict[str, Check] = {
326
361
  name.removeprefix("check_"): check
327
362
  for name, check in dict(globals()).items()
@@ -27,6 +27,9 @@ from .errors import EvalSchemaVersionError, EvalSerializationError
27
27
  SCHEMA_VERSION = 1
28
28
  """Version of the stored run/item record layout."""
29
29
 
30
+ STORE_SCHEMA_VERSION = 2
31
+ """Version of the history database layout. 2 adds the ``optimization_runs`` table (spec 0068)."""
32
+
30
33
  EVIDENCE_VERSION = 1
31
34
  """Version of the serialized full-capture evidence envelope."""
32
35
 
@@ -300,6 +303,72 @@ def _restore_structured(value: Any) -> None:
300
303
  _restore_structured(item)
301
304
 
302
305
 
306
+ class OptimizationRunRecord(BaseModel):
307
+ """One optimization run, stored next to the suite it optimized (spec 0068).
308
+
309
+ The summary fields are derived from the run's trace; ``trace`` is the full
310
+ ``OptimizationTrace.to_dict()`` and is ``None`` in listings. ``report()`` rebuilds the
311
+ ``OptimizationReport`` from the stored trace.
312
+ """
313
+
314
+ model_config = ConfigDict(frozen=True)
315
+
316
+ id: str = Field(default_factory=lambda: str(uuid4()))
317
+ suite: str
318
+ created_at: datetime = Field(default_factory=utc_now)
319
+ title: str = "Optimization run"
320
+ optimizer: str | None = None
321
+ seed: str
322
+ best: str
323
+ seed_avg: float | None = None
324
+ best_avg: float | None = None
325
+ rounds: int = 0
326
+ eval_count: int | None = None
327
+ cost_usd: float | None = None
328
+ pass_score: float = 10.0
329
+ trace: dict[str, Any] | None = None
330
+
331
+ @classmethod
332
+ def from_result(
333
+ cls, result: Any, *, suite: str, pass_score: float = 10.0, title: str | None = None
334
+ ) -> OptimizationRunRecord:
335
+ """Record an ``OptimizationResult`` under ``suite``."""
336
+ return cls.from_trace(result.trace, suite=suite, pass_score=pass_score, title=title)
337
+
338
+ @classmethod
339
+ def from_trace(
340
+ cls, trace: Any, *, suite: str, pass_score: float = 10.0, title: str | None = None
341
+ ) -> OptimizationRunRecord:
342
+ """Record an ``OptimizationTrace`` (live or loaded) under ``suite``."""
343
+ from agentbyte.optim.report import build_report
344
+
345
+ report = build_report(trace, title=title or suite, pass_score=pass_score)
346
+ return cls(
347
+ suite=suite,
348
+ title=report.title,
349
+ optimizer=report.optimizer,
350
+ seed=report.seed,
351
+ best=report.best,
352
+ seed_avg=report.seed_avg,
353
+ best_avg=report.best_avg,
354
+ rounds=report.rounds,
355
+ eval_count=report.eval_count,
356
+ cost_usd=((report.cost or {}).get("total") or {}).get("usd"),
357
+ pass_score=pass_score,
358
+ trace=json.loads(trace.to_json(indent=None)),
359
+ )
360
+
361
+ def report(self) -> Any:
362
+ """The ``OptimizationReport`` rebuilt from the stored trace."""
363
+ if self.trace is None:
364
+ raise ValueError("This record has no trace; load it with get_optimization(id)")
365
+ from agentbyte.optim.report import build_report
366
+ from agentbyte.optim.trace import OptimizationTrace
367
+
368
+ trace = OptimizationTrace(events=list(self.trace.get("events", [])))
369
+ return build_report(trace, title=self.title, pass_score=self.pass_score)
370
+
371
+
303
372
  def deserialize_evidence(text: str) -> EvalScore:
304
373
  """Load evidence JSON as data only; unknown versions raise."""
305
374
  envelope = json.loads(text)
@@ -315,7 +384,9 @@ __all__ = [
315
384
  "ACTIVE_RUN_STATUSES",
316
385
  "EVIDENCE_VERSION",
317
386
  "SCHEMA_VERSION",
387
+ "STORE_SCHEMA_VERSION",
318
388
  "TERMINAL_ITEM_STATES",
389
+ "OptimizationRunRecord",
319
390
  "CaptureMode",
320
391
  "EvalItemRecord",
321
392
  "EvalRunRecord",
@@ -51,13 +51,14 @@ from .errors import (
51
51
  from .models import (
52
52
  ACTIVE_RUN_STATUSES,
53
53
  SCHEMA_VERSION,
54
+ STORE_SCHEMA_VERSION,
54
55
  EvalItemRecord,
55
56
  EvalRunRecord,
56
57
  RunStatus,
57
58
  deserialize_evidence,
58
59
  serialize_evidence,
59
60
  )
60
- from .store import EvalRunStore, _uninterrupted
61
+ from .store import EvalRunStore, _uninterrupted, dump_optimization, load_optimization
61
62
  from .transitions import (
62
63
  admit,
63
64
  admitted_duplicate,
@@ -77,7 +78,11 @@ SessionFactory = Callable[[], "AbstractAsyncContextManager[AsyncSession] | Async
77
78
 
78
79
  # Forward migrations keyed by the version they upgrade from; each is a callable
79
80
  # run on the sync connection inside the opening transaction.
80
- _MIGRATIONS: dict[int, Callable[[Any, "HistoryTables"], None]] = {}
81
+ _MIGRATIONS: dict[int, Callable[[Any, "HistoryTables"], None]] = {
82
+ # spec 0068: optimization runs stored next to suites. checkfirst: a user-managed schema
83
+ # built from history_metadata() may already have the table.
84
+ 1: lambda connection, tables: tables.optimizations.create(connection, checkfirst=True),
85
+ }
81
86
 
82
87
 
83
88
  class HistoryTables:
@@ -109,6 +114,14 @@ class HistoryTables:
109
114
  Column("payload", Text, nullable=False),
110
115
  Column("evidence", Text),
111
116
  )
117
+ self.optimizations = Table(
118
+ "optimization_runs", self.metadata,
119
+ Column("seq", Integer, primary_key=True, autoincrement=True),
120
+ Column("id", String(64), nullable=False, unique=True),
121
+ Column("suite", Text, nullable=False, index=True),
122
+ Column("payload", Text, nullable=False),
123
+ Column("trace", Text),
124
+ )
112
125
 
113
126
 
114
127
  def history_metadata(schema: str | None = None) -> MetaData:
@@ -267,16 +280,18 @@ class SqlEvalRunStore(EvalRunStore):
267
280
  if not (self.writer and self.create_schema):
268
281
  raise EvalSchemaVersionError("Evaluation history tables are not initialized")
269
282
  tables.metadata.create_all(connection)
270
- connection.execute(insert(tables.meta).values(key="schema_version", value=str(SCHEMA_VERSION)))
283
+ connection.execute(
284
+ insert(tables.meta).values(key="schema_version", value=str(STORE_SCHEMA_VERSION))
285
+ )
271
286
  return
272
287
  version = int(row[0])
273
- if version > SCHEMA_VERSION:
288
+ if version > STORE_SCHEMA_VERSION:
274
289
  raise EvalSchemaVersionError(
275
- f"History schema {version} is newer than supported {SCHEMA_VERSION}"
290
+ f"History schema {version} is newer than supported {STORE_SCHEMA_VERSION}"
276
291
  )
277
- if version < SCHEMA_VERSION and not self.writer:
292
+ if version < STORE_SCHEMA_VERSION and not self.writer:
278
293
  raise EvalSchemaVersionError(f"History schema {version} needs migration; open once as writer")
279
- while version < SCHEMA_VERSION:
294
+ while version < STORE_SCHEMA_VERSION:
280
295
  if version not in _MIGRATIONS:
281
296
  raise EvalSchemaVersionError(f"No migration from history schema {version}")
282
297
  _MIGRATIONS[version](connection, tables)
@@ -565,5 +580,35 @@ class SqlEvalRunStore(EvalRunStore):
565
580
 
566
581
  return await self._write(run_id, "delete evaluation run", body)
567
582
 
583
+ async def save_optimization(self, record):
584
+ table = self.tables.optimizations
585
+ payload, trace = dump_optimization(record)
586
+
587
+ async def body(session: AsyncSession) -> Any:
588
+ existing = await session.execute(select(table.c.id).where(table.c.id == record.id))
589
+ if existing.first() is not None:
590
+ raise EvalHistoryConflictError(f"Optimization run {record.id} already exists")
591
+ await session.execute(
592
+ insert(table).values(id=record.id, suite=record.suite, payload=payload, trace=trace)
593
+ )
594
+ return load_optimization(payload, trace)
595
+
596
+ return await self._write(None, "save optimization run", body)
597
+
598
+ async def list_optimizations(self, *, suite=None, limit=50, offset=0):
599
+ table = self.tables.optimizations
600
+ query = select(table.c.payload)
601
+ if suite is not None:
602
+ query = query.where(table.c.suite == suite)
603
+ query = query.order_by(table.c.seq.desc()).limit(max(0, limit)).offset(max(0, offset))
604
+ return [load_optimization(row[0], None) for row in await self._read(None, query)]
605
+
606
+ async def get_optimization(self, optimization_id):
607
+ table = self.tables.optimizations
608
+ rows = await self._read(
609
+ None, select(table.c.payload, table.c.trace).where(table.c.id == optimization_id)
610
+ )
611
+ return load_optimization(rows[0][0], rows[0][1]) if rows else None
612
+
568
613
 
569
614
  __all__ = ["HistoryTables", "SessionFactory", "SqlEvalRunStore", "history_metadata"]
@@ -23,13 +23,14 @@ from .errors import (
23
23
  from .models import (
24
24
  ACTIVE_RUN_STATUSES,
25
25
  SCHEMA_VERSION,
26
+ STORE_SCHEMA_VERSION,
26
27
  EvalItemRecord,
27
28
  EvalRunRecord,
28
29
  RunStatus,
29
30
  deserialize_evidence,
30
31
  serialize_evidence,
31
32
  )
32
- from .store import EvalRunStore, _uninterrupted
33
+ from .store import EvalRunStore, _uninterrupted, dump_optimization, load_optimization
33
34
  from .transitions import (
34
35
  admit,
35
36
  admitted_duplicate,
@@ -56,8 +57,16 @@ _SCHEMA_V1 = (
56
57
  )
57
58
 
58
59
  # Forward migrations keyed by the version they upgrade from. Each runs inside the
59
- # opening transaction, so a failure leaves the previous schema untouched.
60
- _MIGRATIONS: dict[int, tuple[str, ...]] = {}
60
+ # opening transaction, so a failure leaves the previous schema untouched. A new file is
61
+ # created at version 1 and migrated forward like an existing one.
62
+ _MIGRATIONS: dict[int, tuple[str, ...]] = {
63
+ 1: ( # spec 0068: optimization runs stored next to suites
64
+ "CREATE TABLE optimization_runs ("
65
+ "seq INTEGER PRIMARY KEY AUTOINCREMENT, id TEXT NOT NULL UNIQUE, suite TEXT NOT NULL, "
66
+ "payload TEXT NOT NULL, trace TEXT)",
67
+ "CREATE INDEX optimization_runs_suite ON optimization_runs(suite)",
68
+ ),
69
+ }
61
70
 
62
71
 
63
72
  def _admission_key(run: EvalRunRecord) -> str | None:
@@ -165,15 +174,15 @@ class SQLiteEvalRunStore(EvalRunStore):
165
174
  version = 1
166
175
  else:
167
176
  version = int(row[0])
168
- if version > SCHEMA_VERSION:
177
+ if version > STORE_SCHEMA_VERSION:
169
178
  raise EvalSchemaVersionError(
170
- f"History schema {version} is newer than supported {SCHEMA_VERSION}"
179
+ f"History schema {version} is newer than supported {STORE_SCHEMA_VERSION}"
171
180
  )
172
- if version < SCHEMA_VERSION and not self.writer:
181
+ if version < STORE_SCHEMA_VERSION and not self.writer:
173
182
  raise EvalSchemaVersionError(
174
183
  f"History schema {version} needs migration; open once as writer"
175
184
  )
176
- while version < SCHEMA_VERSION:
185
+ while version < STORE_SCHEMA_VERSION:
177
186
  if version not in _MIGRATIONS:
178
187
  raise EvalSchemaVersionError(f"No migration from history schema {version}")
179
188
  for statement in _MIGRATIONS[version]:
@@ -452,5 +461,36 @@ class SQLiteEvalRunStore(EvalRunStore):
452
461
 
453
462
  return await self._write(run_id, "delete evaluation run", body)
454
463
 
464
+ async def save_optimization(self, record):
465
+ payload, trace = dump_optimization(record)
466
+
467
+ async def body(connection: Any) -> Any:
468
+ async with connection.execute(
469
+ "SELECT 1 FROM optimization_runs WHERE id = ?", (record.id,)
470
+ ) as cursor:
471
+ if await cursor.fetchone() is not None:
472
+ raise EvalHistoryConflictError(f"Optimization run {record.id} already exists")
473
+ await connection.execute(
474
+ "INSERT INTO optimization_runs(id, suite, payload, trace) VALUES (?, ?, ?, ?)",
475
+ (record.id, record.suite, payload, trace),
476
+ )
477
+ return load_optimization(payload, trace)
478
+
479
+ return await self._write(None, "save optimization run", body)
480
+
481
+ async def list_optimizations(self, *, suite=None, limit=50, offset=0):
482
+ sql, params = "SELECT payload FROM optimization_runs", []
483
+ if suite is not None:
484
+ sql, params = sql + " WHERE suite = ?", [suite]
485
+ sql += " ORDER BY seq DESC LIMIT ? OFFSET ?"
486
+ rows = await self._read(None, sql, (*params, max(0, limit), max(0, offset)))
487
+ return [load_optimization(row[0], None) for row in rows]
488
+
489
+ async def get_optimization(self, optimization_id):
490
+ rows = await self._read(
491
+ None, "SELECT payload, trace FROM optimization_runs WHERE id = ?", (optimization_id,)
492
+ )
493
+ return load_optimization(rows[0][0], rows[0][1]) if rows else None
494
+
455
495
 
456
496
  __all__ = ["SQLiteEvalRunStore"]