agentbyte 0.31.0__tar.gz → 0.32.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.
- {agentbyte-0.31.0 → agentbyte-0.32.0}/CHANGELOG.md +13 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/PKG-INFO +21 -12
- {agentbyte-0.31.0 → agentbyte-0.32.0}/README.md +12 -5
- {agentbyte-0.31.0 → agentbyte-0.32.0}/pyproject.toml +8 -9
- agentbyte-0.32.0/src/agentbyte/__about__.py +2 -0
- agentbyte-0.32.0/src/agentbyte/eval/history/__init__.py +75 -0
- agentbyte-0.32.0/src/agentbyte/eval/history/conformance.py +341 -0
- agentbyte-0.32.0/src/agentbyte/eval/history/errors.py +63 -0
- agentbyte-0.32.0/src/agentbyte/eval/history/models.py +283 -0
- agentbyte-0.32.0/src/agentbyte/eval/history/recorder.py +300 -0
- agentbyte-0.32.0/src/agentbyte/eval/history/sql.py +555 -0
- agentbyte-0.32.0/src/agentbyte/eval/history/sqlite.py +449 -0
- agentbyte-0.32.0/src/agentbyte/eval/history/store.py +280 -0
- agentbyte-0.32.0/src/agentbyte/eval/history/transitions.py +157 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/runner.py +12 -5
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/middleware/sql_usage.py +1 -1
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/sqlite_checkpoint.py +1 -1
- agentbyte-0.32.0/tests/eval/test_eval_history.py +502 -0
- agentbyte-0.32.0/tests/eval/test_eval_history_backends.py +399 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/eval/test_score_integrity.py +2 -2
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/workflow/test_workflow_reliability.py +1 -1
- agentbyte-0.31.0/src/agentbyte/__about__.py +0 -2
- {agentbyte-0.31.0 → agentbyte-0.32.0}/.gitignore +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/LICENSE +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/agents/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/agents/agent.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/agents/agent_as_tool.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/agents/base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/agents/embedding_agent.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/agents/types.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/cancellation_token.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/catalog.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/cli/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/cli/main.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/compaction/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/compaction/counters.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/compaction/errors.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/compaction/grouping.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/compaction/strategies.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/component.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/context.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/context_providers/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/context_providers/base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/context_providers/skill_tools.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/context_providers/skills.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/dataset/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/dataset/base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/dataset/config.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/dataset/importer.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/dataset/json.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/dataset/loader.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/dataset/publish.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/dataset/publish_config.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/dataset/publishers.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/dataset/sources.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/dataset/sqlite.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/dataset/sqlite_db.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/dataset/write_config.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/dataset/writers.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/entity.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/checks/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/checks/decorator.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/checks/keyword.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/checks/local.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/checks/process.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/checks/tool.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/checks/types.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/comparison.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/eval_dataset.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/judges/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/judges/base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/judges/composite.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/judges/llm.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/judges/pairwise.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/judges/reference.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/judges/trajectory.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/judges/validation.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/pairwise.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/report.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/splitting.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/targets/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/targets/agent.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/targets/model.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/targets/multi_turn.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/targets/orchestrator.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/targets/runtime.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/targets/workflow.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/eval/types.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/execution_trace/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/execution_trace/collector.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/execution_trace/models.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/_retry_observability.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/auth.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/azure/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/azure/auth.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/azure/chat.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/azure/embedding.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/azure/settings.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/azure_openai.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/azure_openai_embedding.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/embeddings_base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/openai/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/openai/chat.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/openai/embedding.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/openai/settings.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/openai_embedding.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/pricing.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/retry_policy.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/settings.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/llm/types.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/logger.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/memory/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/memory/base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/messages.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/middleware/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/middleware/base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/middleware/otel.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/middleware/retry.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/middleware/usage_logger.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/notebook.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/optim/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/optim/base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/optim/config.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/optim/gepa.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/optim/mipro.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/optim/pareto.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/optim/reflective.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/optim/spec.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/optim/trace.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/orchestration/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/orchestration/ai.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/orchestration/base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/orchestration/handoff.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/orchestration/plan.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/orchestration/policies.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/orchestration/round_robin.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/agents.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/clients.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/instruction_registry.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/instructions/orchestrator.yaml +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/instructions/query_rewriter.yaml +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/instructions/researcher.yaml +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/instructions/reviewer.yaml +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/instructions/writer.yaml +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/orchestration.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/skills/contracts-analyst/SKILL.md +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/skills/hr-analyst/SKILL.md +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/skills/hr-analyst/resources/departments.md +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/skills/hr-analyst/resources/employees.md +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/skills/hr-analyst/resources/payroll.md +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/streaming.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/presets/workflow.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/session_store.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/skills/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/skills/base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/skills/resources.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/skills/scripts.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/skills/sources.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/skills/validation.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/termination/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/termination/base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/termination/cancellation.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/termination/composite.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/termination/consecutive_agent.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/termination/external.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/termination/function_call.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/termination/handoff.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/termination/max_message.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/termination/predicate.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/termination/source.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/termination/text_mention.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/termination/timeout.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/termination/token_usage.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/tools/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/tools/base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/tools/coding_tools.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/tools/core_tools.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/tools/decorator.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/tools/memory_tool.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/tools/research_tools.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/types.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/webui/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/webui/discovery.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/webui/execution.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/webui/models.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/webui/registry.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/webui/server.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/webui/session_store.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/webui/sessions.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/webui/ui/assets/index-BF3DwXaF.js +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/webui/ui/assets/index-ar5tOeqt.css +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/webui/ui/index.html +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/webui/ui/vite.svg +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/agent.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/core/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/core/_structure_hash.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/core/checkpoint.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/core/models.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/core/runner.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/core/workflow.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/defaults.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/errors.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/loader.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/schema.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/schema_utils.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/steps/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/steps/agent.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/steps/echo.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/steps/function.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/steps/http.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/steps/step.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/steps/subworkflow.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/steps/transform.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/src/agentbyte/workflow/visualizer.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/agents/test_agent_as_tool.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/agents/test_agent_basic.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/agents/test_agent_context_providers.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/agents/test_agent_error_response.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/agents/test_agent_event_types.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/agents/test_agent_memory_integration.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/agents/test_agent_middleware_integration.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/agents/test_agent_response_accessors.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/agents/test_agent_retry_middleware.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/agents/test_agent_stream_events.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/agents/test_embedding_agent.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/agents/test_tool_approval.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/agents/test_tool_batch_resolution.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/agents/test_tool_metadata.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/cli/test_registry_check.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/compaction/test_compaction.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/context_providers/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/context_providers/test_skill_tools.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/context_providers/test_skills_provider.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/dataset/test_loader.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/dataset/test_multi_table.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/dataset/test_publish.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/dataset/test_sqlite_db.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/eval/test_eval_dataset.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/eval/test_execution_trajectories.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/eval/test_multi_turn.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/eval/test_pairwise.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/eval/test_phase1_runner_and_targets.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/eval/test_phase2_checks_and_reports.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/eval/test_splitting.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/eval/test_types_and_judges.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/examples/test_compaction_webapp.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/llm/test_azure_client.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/llm/test_azure_embedding_client.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/llm/test_llm_types.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/llm/test_openai_client.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/llm/test_openai_embedding_client.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/llm/test_pricing.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/llm/test_retry_observability.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/llm/test_retry_policy_api.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/llm/test_retryable_error_substrings.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/memory/test_memory.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/middleware/test_context_compaction.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/middleware/test_deduplicate_tool_result.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/middleware/test_middleware_chain.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/middleware/test_otel.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/middleware/test_retry_middleware.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/middleware/test_sql_usage.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/middleware/test_usage_logger.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/optim/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/optim/test_base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/optim/test_base_integration.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/optim/test_config.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/optim/test_gepa.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/optim/test_mipro.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/optim/test_pareto.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/optim/test_reflective.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/optim/test_score_integrity.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/optim/test_spec.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/optim/test_trace.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/orchestration/test_ai_orchestrator.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/orchestration/test_base_orchestrator.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/orchestration/test_handoff_orchestrator.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/orchestration/test_orchestrator_finalization.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/orchestration/test_plan_orchestrator.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/orchestration/test_round_robin.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/presets/test_agents.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/presets/test_clients.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/presets/test_instruction_registry.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/presets/test_orchestration.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/presets/test_streaming.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/presets/test_workflow.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/skills/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/skills/test_base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/skills/test_resources.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/skills/test_scripts.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/skills/test_sources.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/termination/test_base.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/termination/test_cancellation.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/termination/test_composite.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/termination/test_consecutive_agent.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/termination/test_external.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/termination/test_function_call.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/termination/test_handoff.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/termination/test_max_message.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/termination/test_predicate.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/termination/test_source.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/termination/test_text_mention.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/termination/test_timeout.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/termination/test_token_usage.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/test_cancellation_token.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/test_context.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/test_logger.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/test_messages.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/test_package_api.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/test_session_store.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/test_types.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/test_vanilla_chunker.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/tools/test_coding_tools.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/tools/test_memory_tool.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/tools/test_research_tools.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/tools/test_tools.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/webui/__init__.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/webui/helpers.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/webui/test_execution.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/webui/test_package_api.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/webui/test_registry.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/webui/test_server.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/webui/test_sessions.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/webui/test_workflow_streaming.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/workflow/recovery_worker.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/workflow/test_agent_step_imports.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/workflow/test_checkpoint.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/workflow/test_subworkflow_step.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/workflow/test_workflow_agent.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/workflow/test_workflow_class.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/workflow/test_workflow_models.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/workflow/test_workflow_runner.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/workflow/test_workflow_schema.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/workflow/test_workflow_steps.py +0 -0
- {agentbyte-0.31.0 → agentbyte-0.32.0}/tests/workflow/test_workflow_visualizer.py +0 -0
|
@@ -6,6 +6,19 @@ The format follows Keep a Changelog principles and semantic versioning.
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.32.0] - 2026-09-30
|
|
10
|
+
|
|
11
|
+
Upgrade notes (breaking):
|
|
12
|
+
|
|
13
|
+
- Optional extras are grouped by database driver. `dataset`, `workflow-sqlite` and `eval-history` are removed; install `agentbyte[sqlite]` instead. pip only warns about an unknown extra, so update install lines before upgrading.
|
|
14
|
+
- New `postgres` extra (`sqlalchemy[asyncio]`, `sqlmodel`, `asyncpg`) for `SqlUsageBackend` and `SqlEvalRunStore`; `sql` is now `sqlite` + `postgres` and installs the same packages as before, plus `greenlet` via `sqlalchemy[asyncio]`.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Evaluation history (spec 0051): new `agentbyte.eval.history` with `EvalRunRecorder` (bounded, index-ordered scheduling; each outcome committed before it is yielded; cancellation and stream close account for every planned item), `EvalRunStore`, `MemoryEvalRunStore` and native-async `SQLiteEvalRunStore` (new `sqlite` extra). Summary capture by default (no transcripts, reasoning or error text); opt-in full capture with a redaction hook and data-only reload of structured output (`StructuredPayload`). Transactional item/counter/revision commits, idempotent replays, explicit `recover_interrupted()`, exclusive single-writer ownership, versioned schema and evidence, atomic owner-scoped admission. Errors: `EvalPersistenceError`, `EvalSerializationError`, `EvalSchemaVersionError`, `EvalStoreOwnershipError`, `EvalQueueFullError`, `EvalHistoryConflictError`.
|
|
19
|
+
- Swappable evaluation history backends: `SqlEvalRunStore` for PostgreSQL through a caller-owned SQLAlchemy session factory (`postgres` extra; row locks, advisory-lock single writer, optional schema, `history_metadata()` for Alembic), public `agentbyte.eval.history.transitions`, and the reusable `agentbyte.eval.history.conformance` suite for custom stores.
|
|
20
|
+
- `EvalRunner.evaluate_task()`: public single-task scoring used by the recorder (previously private `_evaluate_single_task`).
|
|
21
|
+
|
|
9
22
|
## [0.31.0] - 2026-09-30
|
|
10
23
|
|
|
11
24
|
Upgrade notes (breaking):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agentbyte
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.32.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
|
|
@@ -25,7 +25,7 @@ Requires-Dist: openai>=1.107.1; extra == 'all'
|
|
|
25
25
|
Requires-Dist: opentelemetry-api>=1.39.1; extra == 'all'
|
|
26
26
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.39.1; extra == 'all'
|
|
27
27
|
Requires-Dist: opentelemetry-sdk>=1.39.1; extra == 'all'
|
|
28
|
-
Requires-Dist: sqlalchemy>=2.0.43; extra == 'all'
|
|
28
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0.43; extra == 'all'
|
|
29
29
|
Requires-Dist: sqlmodel>=0.0.38; extra == 'all'
|
|
30
30
|
Requires-Dist: uvicorn>=0.42.0; extra == 'all'
|
|
31
31
|
Requires-Dist: youtube-transcript-api>=0.6; extra == 'all'
|
|
@@ -35,8 +35,6 @@ Provides-Extra: azureopenai
|
|
|
35
35
|
Requires-Dist: azure-identity>=1.25.1; extra == 'azureopenai'
|
|
36
36
|
Requires-Dist: openai>=1.107.1; extra == 'azureopenai'
|
|
37
37
|
Provides-Extra: coding
|
|
38
|
-
Provides-Extra: dataset
|
|
39
|
-
Requires-Dist: aiosqlite>=0.22.1; extra == 'dataset'
|
|
40
38
|
Provides-Extra: dev
|
|
41
39
|
Requires-Dist: ipykernel>=7.1.0; extra == 'dev'
|
|
42
40
|
Requires-Dist: nbclient>=0.10.4; extra == 'dev'
|
|
@@ -53,6 +51,10 @@ Provides-Extra: otel
|
|
|
53
51
|
Requires-Dist: opentelemetry-api>=1.39.1; extra == 'otel'
|
|
54
52
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.39.1; extra == 'otel'
|
|
55
53
|
Requires-Dist: opentelemetry-sdk>=1.39.1; extra == 'otel'
|
|
54
|
+
Provides-Extra: postgres
|
|
55
|
+
Requires-Dist: asyncpg>=0.31.0; extra == 'postgres'
|
|
56
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0.43; extra == 'postgres'
|
|
57
|
+
Requires-Dist: sqlmodel>=0.0.38; extra == 'postgres'
|
|
56
58
|
Provides-Extra: research
|
|
57
59
|
Requires-Dist: arxiv>=2.1; extra == 'research'
|
|
58
60
|
Requires-Dist: beautifulsoup4>=4.12; extra == 'research'
|
|
@@ -61,8 +63,10 @@ Requires-Dist: youtube-transcript-api>=0.6; extra == 'research'
|
|
|
61
63
|
Provides-Extra: sql
|
|
62
64
|
Requires-Dist: aiosqlite>=0.22.1; extra == 'sql'
|
|
63
65
|
Requires-Dist: asyncpg>=0.31.0; extra == 'sql'
|
|
64
|
-
Requires-Dist: sqlalchemy>=2.0.43; extra == 'sql'
|
|
66
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0.43; extra == 'sql'
|
|
65
67
|
Requires-Dist: sqlmodel>=0.0.38; extra == 'sql'
|
|
68
|
+
Provides-Extra: sqlite
|
|
69
|
+
Requires-Dist: aiosqlite>=0.22.1; extra == 'sqlite'
|
|
66
70
|
Provides-Extra: test
|
|
67
71
|
Requires-Dist: aiosqlite>=0.22.1; extra == 'test'
|
|
68
72
|
Requires-Dist: arxiv>=2.1; extra == 'test'
|
|
@@ -80,15 +84,13 @@ Requires-Dist: graphviz>=0.21; extra == 'viz'
|
|
|
80
84
|
Provides-Extra: webui
|
|
81
85
|
Requires-Dist: fastapi>=0.135.2; extra == 'webui'
|
|
82
86
|
Requires-Dist: uvicorn[standard]>=0.44.0; extra == 'webui'
|
|
83
|
-
Provides-Extra: workflow-sqlite
|
|
84
|
-
Requires-Dist: aiosqlite>=0.22.1; extra == 'workflow-sqlite'
|
|
85
87
|
Description-Content-Type: text/markdown
|
|
86
88
|
|
|
87
89
|
# Agentbyte
|
|
88
90
|
|
|
89
91
|
Agentbyte is an observability-first agentic AI framework for building and studying multiagent systems with a learning-first, implementation-oriented workflow.
|
|
90
92
|
|
|
91
|
-
Current release: **0.
|
|
93
|
+
Current release: **0.32.0**
|
|
92
94
|
|
|
93
95
|
## Building an Agent
|
|
94
96
|
|
|
@@ -307,10 +309,17 @@ uv sync --all-groups
|
|
|
307
309
|
Optional extras:
|
|
308
310
|
|
|
309
311
|
```bash
|
|
310
|
-
uv sync --extra openai
|
|
311
|
-
uv sync --extra azureopenai
|
|
312
|
-
uv sync --extra
|
|
313
|
-
uv sync --extra
|
|
312
|
+
uv sync --extra openai # OpenAI client
|
|
313
|
+
uv sync --extra azureopenai # Azure OpenAI client + azure-identity
|
|
314
|
+
uv sync --extra aws # S3 datasets (aioboto3)
|
|
315
|
+
uv sync --extra otel # OpenTelemetry export
|
|
316
|
+
uv sync --extra webui # WebUI playground (FastAPI)
|
|
317
|
+
uv sync --extra sqlite # SQLite stores: datasets, workflow checkpoints, eval history
|
|
318
|
+
uv sync --extra postgres # PostgreSQL stores: usage logging, eval history
|
|
319
|
+
uv sync --extra sql # sqlite + postgres
|
|
320
|
+
uv sync --extra optim # prompt optimization (GEPA)
|
|
321
|
+
uv sync --extra viz # workflow diagrams (graphviz)
|
|
322
|
+
uv sync --extra research # research tools
|
|
314
323
|
```
|
|
315
324
|
|
|
316
325
|
### Install in another project (pip / uv add)
|
|
@@ -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.
|
|
5
|
+
Current release: **0.32.0**
|
|
6
6
|
|
|
7
7
|
## Building an Agent
|
|
8
8
|
|
|
@@ -221,10 +221,17 @@ uv sync --all-groups
|
|
|
221
221
|
Optional extras:
|
|
222
222
|
|
|
223
223
|
```bash
|
|
224
|
-
uv sync --extra openai
|
|
225
|
-
uv sync --extra azureopenai
|
|
226
|
-
uv sync --extra
|
|
227
|
-
uv sync --extra
|
|
224
|
+
uv sync --extra openai # OpenAI client
|
|
225
|
+
uv sync --extra azureopenai # Azure OpenAI client + azure-identity
|
|
226
|
+
uv sync --extra aws # S3 datasets (aioboto3)
|
|
227
|
+
uv sync --extra otel # OpenTelemetry export
|
|
228
|
+
uv sync --extra webui # WebUI playground (FastAPI)
|
|
229
|
+
uv sync --extra sqlite # SQLite stores: datasets, workflow checkpoints, eval history
|
|
230
|
+
uv sync --extra postgres # PostgreSQL stores: usage logging, eval history
|
|
231
|
+
uv sync --extra sql # sqlite + postgres
|
|
232
|
+
uv sync --extra optim # prompt optimization (GEPA)
|
|
233
|
+
uv sync --extra viz # workflow diagrams (graphviz)
|
|
234
|
+
uv sync --extra research # research tools
|
|
228
235
|
```
|
|
229
236
|
|
|
230
237
|
### Install in another project (pip / uv add)
|
|
@@ -38,17 +38,16 @@ webui = [
|
|
|
38
38
|
"fastapi>=0.135.2",
|
|
39
39
|
"uvicorn[standard]>=0.44.0",
|
|
40
40
|
]
|
|
41
|
-
|
|
42
|
-
"aiosqlite>=0.22.1",
|
|
43
|
-
]
|
|
44
|
-
workflow-sqlite = [
|
|
41
|
+
sqlite = [
|
|
45
42
|
"aiosqlite>=0.22.1",
|
|
46
43
|
]
|
|
47
|
-
|
|
48
|
-
"sqlalchemy>=2.0.43",
|
|
44
|
+
postgres = [
|
|
45
|
+
"sqlalchemy[asyncio]>=2.0.43",
|
|
49
46
|
"sqlmodel>=0.0.38",
|
|
50
47
|
"asyncpg>=0.31.0",
|
|
51
|
-
|
|
48
|
+
]
|
|
49
|
+
sql = [
|
|
50
|
+
"agentbyte[sqlite,postgres]",
|
|
52
51
|
]
|
|
53
52
|
optim = [
|
|
54
53
|
"gepa>=0.1",
|
|
@@ -89,7 +88,7 @@ all = [
|
|
|
89
88
|
"openai>=1.107.1",
|
|
90
89
|
"azure-identity>=1.25.1",
|
|
91
90
|
"aioboto3>=15.5.0",
|
|
92
|
-
"sqlalchemy>=2.0.43",
|
|
91
|
+
"sqlalchemy[asyncio]>=2.0.43",
|
|
93
92
|
"sqlmodel>=0.0.38",
|
|
94
93
|
"asyncpg>=0.31.0",
|
|
95
94
|
"aiosqlite>=0.22.1",
|
|
@@ -197,7 +196,7 @@ all = [
|
|
|
197
196
|
"openai>=1.107.1",
|
|
198
197
|
"azure-identity>=1.25.1",
|
|
199
198
|
"aioboto3>=15.5.0",
|
|
200
|
-
"sqlalchemy>=2.0.43",
|
|
199
|
+
"sqlalchemy[asyncio]>=2.0.43",
|
|
201
200
|
"sqlmodel>=0.0.38",
|
|
202
201
|
"asyncpg>=0.31.0",
|
|
203
202
|
"aiosqlite>=0.22.1",
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Durable evaluation history (spec 0051).
|
|
2
|
+
|
|
3
|
+
``SQLiteEvalRunStore`` needs the ``sqlite`` extra (``aiosqlite``); the driver
|
|
4
|
+
is imported only when a store is opened. ``SqlEvalRunStore`` (PostgreSQL through a
|
|
5
|
+
caller-owned SQLAlchemy session factory) needs the ``postgres`` extra and is loaded on
|
|
6
|
+
first access.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from .errors import (
|
|
12
|
+
EvalHistoryConflictError,
|
|
13
|
+
EvalHistoryError,
|
|
14
|
+
EvalPersistenceError,
|
|
15
|
+
EvalQueueFullError,
|
|
16
|
+
EvalRedactionError,
|
|
17
|
+
EvalRunNotFoundError,
|
|
18
|
+
EvalSchemaVersionError,
|
|
19
|
+
EvalSerializationError,
|
|
20
|
+
EvalStoreOwnershipError,
|
|
21
|
+
)
|
|
22
|
+
from .models import (
|
|
23
|
+
EVIDENCE_VERSION,
|
|
24
|
+
SCHEMA_VERSION,
|
|
25
|
+
CaptureMode,
|
|
26
|
+
EvalItemRecord,
|
|
27
|
+
EvalRunRecord,
|
|
28
|
+
EvidenceStatus,
|
|
29
|
+
ItemState,
|
|
30
|
+
Redactor,
|
|
31
|
+
RunStatus,
|
|
32
|
+
StructuredPayload,
|
|
33
|
+
)
|
|
34
|
+
from .recorder import EvalRunRecorder
|
|
35
|
+
from .sqlite import SQLiteEvalRunStore
|
|
36
|
+
from .store import EvalRunStore, MemoryEvalRunStore
|
|
37
|
+
|
|
38
|
+
_SQL_EXPORTS = {"SqlEvalRunStore", "history_metadata"}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def __getattr__(name: str) -> Any:
|
|
42
|
+
if name in _SQL_EXPORTS:
|
|
43
|
+
from . import sql
|
|
44
|
+
|
|
45
|
+
return getattr(sql, name)
|
|
46
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
__all__ = [
|
|
50
|
+
"EVIDENCE_VERSION",
|
|
51
|
+
"SCHEMA_VERSION",
|
|
52
|
+
"CaptureMode",
|
|
53
|
+
"EvalHistoryConflictError",
|
|
54
|
+
"EvalHistoryError",
|
|
55
|
+
"EvalItemRecord",
|
|
56
|
+
"EvalPersistenceError",
|
|
57
|
+
"EvalQueueFullError",
|
|
58
|
+
"EvalRedactionError",
|
|
59
|
+
"EvalRunNotFoundError",
|
|
60
|
+
"EvalRunRecord",
|
|
61
|
+
"EvalRunRecorder",
|
|
62
|
+
"EvalRunStore",
|
|
63
|
+
"EvalSchemaVersionError",
|
|
64
|
+
"EvalSerializationError",
|
|
65
|
+
"EvalStoreOwnershipError",
|
|
66
|
+
"EvidenceStatus",
|
|
67
|
+
"ItemState",
|
|
68
|
+
"MemoryEvalRunStore",
|
|
69
|
+
"Redactor",
|
|
70
|
+
"RunStatus",
|
|
71
|
+
"SQLiteEvalRunStore",
|
|
72
|
+
"SqlEvalRunStore",
|
|
73
|
+
"StructuredPayload",
|
|
74
|
+
"history_metadata",
|
|
75
|
+
]
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
"""Behavioral checks every ``EvalRunStore`` backend must pass.
|
|
2
|
+
|
|
3
|
+
Framework-free: each check is an async function that receives a fresh, empty,
|
|
4
|
+
open store and raises ``AssertionError`` on a contract violation. Use
|
|
5
|
+
``run_conformance`` or parametrize your own test runner over ``CHECKS``::
|
|
6
|
+
|
|
7
|
+
from agentbyte.eval.history.conformance import CHECKS
|
|
8
|
+
|
|
9
|
+
@pytest.mark.parametrize("check", CHECKS.values(), ids=CHECKS.keys())
|
|
10
|
+
async def test_my_store(check):
|
|
11
|
+
async with open_my_empty_store() as store:
|
|
12
|
+
await check(store)
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import asyncio
|
|
18
|
+
from collections.abc import Awaitable, Callable
|
|
19
|
+
from contextlib import AbstractAsyncContextManager
|
|
20
|
+
|
|
21
|
+
from pydantic import BaseModel
|
|
22
|
+
|
|
23
|
+
from agentbyte.eval.base import BaseEvalJudge, BaseEvalTarget, JudgeScoringError
|
|
24
|
+
from agentbyte.eval.runner import EvalRunner
|
|
25
|
+
from agentbyte.eval.types import EvalScore, EvalTask, EvalTrajectory, WorkflowEvalTask
|
|
26
|
+
from agentbyte.execution_trace.models import ExecutionEvent, ExecutionSpan, ExecutionTrace
|
|
27
|
+
from agentbyte.messages import AssistantMessage, UserMessage, Usage
|
|
28
|
+
|
|
29
|
+
from .errors import (
|
|
30
|
+
EvalHistoryConflictError,
|
|
31
|
+
EvalQueueFullError,
|
|
32
|
+
EvalRunNotFoundError,
|
|
33
|
+
EvalSerializationError,
|
|
34
|
+
)
|
|
35
|
+
from .models import EvalItemRecord, EvalRunRecord, StructuredPayload
|
|
36
|
+
from .recorder import EvalRunRecorder
|
|
37
|
+
from .store import EvalRunStore
|
|
38
|
+
|
|
39
|
+
Check = Callable[[EvalRunStore], Awaitable[None]]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# -- fixtures -----------------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class _Answer(BaseModel):
|
|
46
|
+
city: str
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class _Target(BaseEvalTarget):
|
|
50
|
+
def __init__(self) -> None:
|
|
51
|
+
super().__init__("conformance")
|
|
52
|
+
self.active = 0
|
|
53
|
+
self.max_active = 0
|
|
54
|
+
|
|
55
|
+
async def run(self, task, cancellation_token=None):
|
|
56
|
+
self.active += 1
|
|
57
|
+
self.max_active = max(self.max_active, self.active)
|
|
58
|
+
try:
|
|
59
|
+
await asyncio.sleep(task.metadata.get("delay", 0))
|
|
60
|
+
if task.metadata.get("target_fails"):
|
|
61
|
+
raise RuntimeError("target failed")
|
|
62
|
+
span = ExecutionSpan(kind="agent", name="conformance", status="completed")
|
|
63
|
+
trace = ExecutionTrace(spans=[span], events=[ExecutionEvent(span_id=span.id, kind="step")])
|
|
64
|
+
return EvalTrajectory(
|
|
65
|
+
task=task,
|
|
66
|
+
messages=[
|
|
67
|
+
UserMessage(content=task.input, source="user"),
|
|
68
|
+
AssistantMessage(content="answer", source="a", structured_content=_Answer(city="Rome")),
|
|
69
|
+
],
|
|
70
|
+
success=True,
|
|
71
|
+
usage=Usage(tokens_input=3, tokens_output=2),
|
|
72
|
+
trace=trace,
|
|
73
|
+
metadata={"execution_status": "completed"},
|
|
74
|
+
)
|
|
75
|
+
finally:
|
|
76
|
+
self.active -= 1
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class _Judge(BaseEvalJudge):
|
|
80
|
+
def __init__(self) -> None:
|
|
81
|
+
super().__init__("conformance")
|
|
82
|
+
|
|
83
|
+
async def score(self, trajectory, criteria=None, cancellation_token=None):
|
|
84
|
+
if trajectory.task.metadata.get("judge_fails"):
|
|
85
|
+
raise JudgeScoringError("provider_error")
|
|
86
|
+
return EvalScore(
|
|
87
|
+
overall=float(trajectory.task.metadata.get("score", 7.0)),
|
|
88
|
+
dimensions={"quality": 7.0},
|
|
89
|
+
trajectory=trajectory,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _run(**kwargs) -> EvalRunRecord:
|
|
94
|
+
return EvalRunRecord(dataset_id="d", target_id="t", judge_name="j", judge_type="J", **kwargs)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _items(run: EvalRunRecord, n: int) -> list[EvalItemRecord]:
|
|
98
|
+
return [EvalItemRecord(run_id=run.id, item_index=i, task_name=f"t{i}") for i in range(n)]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _outcome(run: EvalRunRecord, index: int, overall: float = 5.0, **kwargs) -> EvalItemRecord:
|
|
102
|
+
return EvalItemRecord(
|
|
103
|
+
run_id=run.id, item_index=index, task_name=f"t{index}", state="finished",
|
|
104
|
+
scoring_status="scored", overall=overall, **kwargs,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
async def _started(store: EvalRunStore, n: int, **kwargs) -> EvalRunRecord:
|
|
109
|
+
run = _run(**kwargs)
|
|
110
|
+
await store.create_run(run, _items(run, n))
|
|
111
|
+
return await store.start_run(run.id, worker_id=kwargs.get("worker_id"))
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
async def _raises(exc: type[BaseException], awaitable: Awaitable[object]) -> None:
|
|
115
|
+
try:
|
|
116
|
+
await awaitable
|
|
117
|
+
except exc:
|
|
118
|
+
return
|
|
119
|
+
raise AssertionError(f"expected {exc.__name__}")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# -- checks -------------------------------------------------------------------------
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
async def check_admission_is_idempotent_and_bounded(store: EvalRunStore) -> None:
|
|
126
|
+
first = _run(owner="alice", idempotency_key="k1")
|
|
127
|
+
admitted = await store.create_run(first, _items(first, 1))
|
|
128
|
+
assert (admitted.status, admitted.revision, admitted.planned_count) == ("queued", 1, 1)
|
|
129
|
+
again = _run(owner="alice", idempotency_key="k1")
|
|
130
|
+
assert (await store.create_run(again, _items(again, 1))).id == admitted.id
|
|
131
|
+
other = _run(owner="bob", idempotency_key="k1")
|
|
132
|
+
assert (await store.create_run(other, _items(other, 1))).id == other.id
|
|
133
|
+
different = _run(owner="alice", idempotency_key="k1")
|
|
134
|
+
await _raises(EvalHistoryConflictError, store.create_run(different, _items(different, 2)))
|
|
135
|
+
same_id = admitted.model_copy(update={"idempotency_key": None})
|
|
136
|
+
await _raises(EvalHistoryConflictError, store.create_run(same_id, _items(same_id, 1)))
|
|
137
|
+
full = _run()
|
|
138
|
+
await _raises(EvalQueueFullError, store.create_run(full, _items(full, 1), max_active_runs=2))
|
|
139
|
+
assert len(await store.list_runs()) == 2
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
async def check_lifecycle_updates_counters_and_revisions(store: EvalRunStore) -> None:
|
|
143
|
+
run = await _started(store, 3, worker_id="w1")
|
|
144
|
+
assert (run.status, run.revision, run.worker_id) == ("running", 2, "w1")
|
|
145
|
+
await _raises(EvalHistoryConflictError, store.start_run(run.id))
|
|
146
|
+
|
|
147
|
+
running = await store.mark_item_running(run.id, 0)
|
|
148
|
+
assert (running.state, running.revision) == ("running", 3) and running.started_at is not None
|
|
149
|
+
await _raises(EvalHistoryConflictError, store.mark_item_running(run.id, 0))
|
|
150
|
+
|
|
151
|
+
saved = await store.save_item(_outcome(run, 0, 6.0))
|
|
152
|
+
assert (saved.state, saved.revision, saved.overall) == ("finished", 4, 6.0)
|
|
153
|
+
assert saved.started_at == running.started_at and saved.finished_at is not None
|
|
154
|
+
failed = await store.save_item(_outcome(run, 1).model_copy(update={
|
|
155
|
+
"scoring_status": "failed", "overall": None, "failure_reason": "target_error",
|
|
156
|
+
}))
|
|
157
|
+
assert failed.revision == 5
|
|
158
|
+
|
|
159
|
+
current = await store.get_run(run.id)
|
|
160
|
+
assert (current.revision, current.finished_count, current.scored_count, current.failed_count) == (5, 2, 1, 1)
|
|
161
|
+
closed = await store.finish_run(run.id, "completed")
|
|
162
|
+
assert (closed.status, closed.revision, closed.not_started_count) == ("completed", 6, 1)
|
|
163
|
+
assert closed.finished_at is not None and closed.incomplete
|
|
164
|
+
await _raises(EvalHistoryConflictError, store.save_item(_outcome(run, 2)))
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
async def check_replays_are_idempotent_and_conflicts_explicit(store: EvalRunStore) -> None:
|
|
168
|
+
run = await _started(store, 1)
|
|
169
|
+
outcome = _outcome(run, 0)
|
|
170
|
+
first = await store.save_item(outcome)
|
|
171
|
+
assert await store.save_item(outcome) == first
|
|
172
|
+
assert (await store.get_run(run.id)).finished_count == 1
|
|
173
|
+
await _raises(EvalHistoryConflictError, store.save_item(outcome.model_copy(update={"overall": 1.0})))
|
|
174
|
+
assert (await store.get_item(run.id, 0)).overall == 5.0
|
|
175
|
+
|
|
176
|
+
closed = await store.finish_run(run.id, "completed")
|
|
177
|
+
assert await store.finish_run(run.id, "completed") == closed
|
|
178
|
+
await _raises(EvalHistoryConflictError, store.finish_run(run.id, "cancelled"))
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
async def check_evidence_conflict_is_explicit(store: EvalRunStore) -> None:
|
|
182
|
+
run = await _started(store, 1)
|
|
183
|
+
score = EvalScore(overall=5.0)
|
|
184
|
+
await store.save_item(_outcome(run, 0, evidence=score, evidence_status="captured"))
|
|
185
|
+
other = EvalScore(overall=5.0, reasoning={"q": "different"})
|
|
186
|
+
await _raises(
|
|
187
|
+
EvalHistoryConflictError,
|
|
188
|
+
store.save_item(_outcome(run, 0, evidence=other, evidence_status="captured")),
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
async def check_finish_accounts_for_every_item(store: EvalRunStore) -> None:
|
|
193
|
+
run = await _started(store, 3)
|
|
194
|
+
await store.mark_item_running(run.id, 0)
|
|
195
|
+
await store.save_item(_outcome(run, 0))
|
|
196
|
+
await store.mark_item_running(run.id, 1)
|
|
197
|
+
closed = await store.finish_run(run.id, "cancelled")
|
|
198
|
+
items = await store.list_items(run.id)
|
|
199
|
+
assert [i.state for i in items] == ["finished", "cancelled", "not_started"]
|
|
200
|
+
assert items[1].failure_reason == "cancelled" and items[1].overall is None
|
|
201
|
+
assert (closed.finished_count, closed.cancelled_count, closed.not_started_count) == (1, 1, 1)
|
|
202
|
+
await _raises(ValueError, store.finish_run(run.id, "running"))
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
async def check_recovery_is_explicit_and_scoped(store: EvalRunStore) -> None:
|
|
206
|
+
mine = await _started(store, 2, worker_id="w1")
|
|
207
|
+
theirs = await _started(store, 1, worker_id="w2")
|
|
208
|
+
await store.mark_item_running(mine.id, 0)
|
|
209
|
+
assert (await store.get_run(mine.id)).status == "running"
|
|
210
|
+
|
|
211
|
+
(recovered,) = await store.recover_interrupted(worker_id="w1")
|
|
212
|
+
assert (recovered.id, recovered.status, recovered.error) == (mine.id, "interrupted", "interrupted")
|
|
213
|
+
assert [i.state for i in await store.list_items(mine.id)] == ["cancelled", "not_started"]
|
|
214
|
+
assert (await store.get_run(theirs.id)).status == "running"
|
|
215
|
+
assert [r.id for r in await store.recover_interrupted()] == [theirs.id]
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
async def check_full_evidence_round_trips_as_data(store: EvalRunStore) -> None:
|
|
219
|
+
turn = [UserMessage(content="same", source="user"), AssistantMessage(content="same", source="a")]
|
|
220
|
+
task = WorkflowEvalTask(name="wf", input="judge", workflow_input={"order": {"id": 7}})
|
|
221
|
+
trajectory = EvalTrajectory(
|
|
222
|
+
task=task,
|
|
223
|
+
messages=[*turn, *turn, AssistantMessage(content="", source="a", structured_content=_Answer(city="Rome"))],
|
|
224
|
+
success=True,
|
|
225
|
+
trace=ExecutionTrace(spans=[ExecutionSpan(kind="agent", name="a")]),
|
|
226
|
+
)
|
|
227
|
+
score = EvalScore(overall=8.0, reasoning={"q": "why"}, trajectory=trajectory)
|
|
228
|
+
run = await _started(store, 1)
|
|
229
|
+
await store.save_item(_outcome(run, 0, 8.0, evidence=score, evidence_status="captured"))
|
|
230
|
+
|
|
231
|
+
listed = (await store.list_items(run.id))[0]
|
|
232
|
+
assert listed.evidence is None
|
|
233
|
+
loaded = (await store.get_item(run.id, 0)).evidence
|
|
234
|
+
assert isinstance(loaded.trajectory.task, WorkflowEvalTask)
|
|
235
|
+
assert loaded.trajectory.task.workflow_input == {"order": {"id": 7}}
|
|
236
|
+
assert [(m.role, m.content) for m in loaded.trajectory.messages[:4]] == [
|
|
237
|
+
("user", "same"), ("assistant", "same"), ("user", "same"), ("assistant", "same"),
|
|
238
|
+
]
|
|
239
|
+
structured = loaded.trajectory.messages[4].structured_content
|
|
240
|
+
assert isinstance(structured, StructuredPayload) and structured.model_dump() == {"city": "Rome"}
|
|
241
|
+
assert loaded.trajectory.trace.id == trajectory.trace.id and loaded.reasoning == {"q": "why"}
|
|
242
|
+
assert (await store.list_items(run.id, include_evidence=True))[0].evidence == loaded
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
async def check_unserializable_evidence_changes_nothing(store: EvalRunStore) -> None:
|
|
246
|
+
run = await _started(store, 1)
|
|
247
|
+
await store.mark_item_running(run.id, 0)
|
|
248
|
+
before = await store.get_run(run.id)
|
|
249
|
+
bad = EvalScore(overall=5.0, metadata={"handle": object()})
|
|
250
|
+
try:
|
|
251
|
+
await store.save_item(_outcome(run, 0, evidence=bad, evidence_status="captured"))
|
|
252
|
+
except EvalSerializationError as exc:
|
|
253
|
+
assert exc.path == "evidence.metadata.handle"
|
|
254
|
+
else:
|
|
255
|
+
raise AssertionError("expected EvalSerializationError")
|
|
256
|
+
assert await store.get_run(run.id) == before
|
|
257
|
+
assert (await store.get_item(run.id, 0)).state == "running"
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
async def check_queries_paginate_filter_and_delete(store: EvalRunStore) -> None:
|
|
261
|
+
runs = []
|
|
262
|
+
for index in range(3):
|
|
263
|
+
run = _run(owner="alice" if index else "bob")
|
|
264
|
+
run = run.model_copy(update={"dataset_id": f"d{index}"})
|
|
265
|
+
await store.create_run(run, _items(run, 5))
|
|
266
|
+
await store.start_run(run.id)
|
|
267
|
+
runs.append(await store.finish_run(run.id, "cancelled"))
|
|
268
|
+
assert [r.id for r in await store.list_runs(limit=2, offset=1)] == [runs[1].id, runs[0].id]
|
|
269
|
+
assert [r.id for r in await store.list_runs(dataset_id="d2")] == [runs[2].id]
|
|
270
|
+
assert [r.id for r in await store.list_runs(owner="bob")] == [runs[0].id]
|
|
271
|
+
assert [r.id for r in await store.list_runs(status="cancelled", limit=1)] == [runs[2].id]
|
|
272
|
+
assert [i.item_index for i in await store.list_items(runs[0].id, limit=2, offset=3)] == [3, 4]
|
|
273
|
+
|
|
274
|
+
active = _run()
|
|
275
|
+
await store.create_run(active, _items(active, 1))
|
|
276
|
+
await _raises(EvalHistoryConflictError, store.delete_run(active.id))
|
|
277
|
+
assert await store.delete_run(runs[0].id) is True
|
|
278
|
+
assert await store.get_run(runs[0].id) is None
|
|
279
|
+
assert await store.list_items(runs[0].id) == []
|
|
280
|
+
assert await store.get_item(runs[0].id, 0) is None
|
|
281
|
+
assert await store.delete_run(runs[0].id) is False
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
async def check_unknown_run_is_reported(store: EvalRunStore) -> None:
|
|
285
|
+
assert await store.get_run("missing") is None
|
|
286
|
+
await _raises(EvalRunNotFoundError, store.start_run("missing"))
|
|
287
|
+
await _raises(EvalRunNotFoundError, store.finish_run("missing", "failed"))
|
|
288
|
+
run = await _started(store, 1)
|
|
289
|
+
await _raises(EvalRunNotFoundError, store.mark_item_running(run.id, 5))
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
async def check_recorder_keeps_duplicates_and_failures(store: EvalRunStore) -> None:
|
|
293
|
+
tasks = [
|
|
294
|
+
EvalTask(name="case-1", input="a"),
|
|
295
|
+
EvalTask(name="case-1", input="b"),
|
|
296
|
+
EvalTask(name="target", input="c", metadata={"target_fails": True}),
|
|
297
|
+
EvalTask(name="judge", input="d", metadata={"judge_fails": True}),
|
|
298
|
+
]
|
|
299
|
+
run = await EvalRunRecorder(store).evaluate(
|
|
300
|
+
EvalRunner(_Judge()), _Target(), tasks, dataset_id="d", target_id="t",
|
|
301
|
+
)
|
|
302
|
+
items = await store.list_items(run.id)
|
|
303
|
+
assert run.status == "completed"
|
|
304
|
+
assert (run.planned_count, run.finished_count, run.scored_count, run.failed_count) == (4, 4, 2, 2)
|
|
305
|
+
assert [(i.item_index, i.task_name) for i in items[:2]] == [(0, "case-1"), (1, "case-1")]
|
|
306
|
+
assert (items[2].failure_reason, items[2].error_type) == ("target_error", "RuntimeError")
|
|
307
|
+
assert items[3].failure_reason == "provider_error"
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
async def check_recorder_bounds_concurrency_without_lost_writes(store: EvalRunStore) -> None:
|
|
311
|
+
tasks = [
|
|
312
|
+
EvalTask(name=f"c{i}", input="x", metadata={"delay": (i % 4) * 0.003, "score": i % 10})
|
|
313
|
+
for i in range(16)
|
|
314
|
+
]
|
|
315
|
+
target = _Target()
|
|
316
|
+
run = await EvalRunRecorder(store, concurrency=4).evaluate(
|
|
317
|
+
EvalRunner(_Judge()), target, tasks, dataset_id="d", target_id="t",
|
|
318
|
+
)
|
|
319
|
+
items = await store.list_items(run.id, limit=50)
|
|
320
|
+
assert target.max_active <= 4
|
|
321
|
+
assert (run.finished_count, run.scored_count, run.revision) == (16, 16, 1 + 1 + 16 * 2 + 1)
|
|
322
|
+
assert [i.overall for i in items] == [float(i % 10) for i in range(16)]
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
CHECKS: dict[str, Check] = {
|
|
326
|
+
name.removeprefix("check_"): check
|
|
327
|
+
for name, check in dict(globals()).items()
|
|
328
|
+
if name.startswith("check_")
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
async def run_conformance(
|
|
333
|
+
open_store: Callable[[], AbstractAsyncContextManager[EvalRunStore]],
|
|
334
|
+
) -> None:
|
|
335
|
+
"""Run every check, each against a fresh empty store from ``open_store``."""
|
|
336
|
+
for check in CHECKS.values():
|
|
337
|
+
async with open_store() as store:
|
|
338
|
+
await check(store)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
__all__ = ["CHECKS", "Check", "run_conformance"]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Errors raised by evaluation history stores and the recorder."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class EvalHistoryError(Exception):
|
|
7
|
+
"""Base class for evaluation history failures."""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class EvalPersistenceError(EvalHistoryError):
|
|
11
|
+
"""A history write or read failed; durable success must not be assumed.
|
|
12
|
+
|
|
13
|
+
``run_id`` names the affected run when one is known.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, message: str, *, run_id: str | None = None) -> None:
|
|
17
|
+
super().__init__(f"{message} (run {run_id})" if run_id else message)
|
|
18
|
+
self.run_id = run_id
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class EvalRedactionError(EvalPersistenceError):
|
|
22
|
+
"""A supplied redaction hook failed; nothing was persisted for the item."""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class EvalHistoryConflictError(EvalHistoryError):
|
|
26
|
+
"""A write contradicts stored state, such as a different terminal outcome."""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class EvalSchemaVersionError(EvalHistoryError):
|
|
30
|
+
"""Stored data uses a schema or evidence version this code does not support."""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class EvalSerializationError(EvalHistoryError):
|
|
34
|
+
"""A value cannot be stored as JSON; ``path`` names the offending field."""
|
|
35
|
+
|
|
36
|
+
def __init__(self, path: str, reason: str) -> None:
|
|
37
|
+
super().__init__(f"{path}: {reason}")
|
|
38
|
+
self.path = path
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class EvalRunNotFoundError(EvalHistoryError, KeyError):
|
|
42
|
+
"""The run or item does not exist in this store."""
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class EvalQueueFullError(EvalHistoryError):
|
|
46
|
+
"""Admission refused because the active-run capacity is reached."""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class EvalStoreOwnershipError(EvalHistoryError):
|
|
50
|
+
"""Another process already owns this history database as its writer."""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
"EvalHistoryConflictError",
|
|
55
|
+
"EvalHistoryError",
|
|
56
|
+
"EvalPersistenceError",
|
|
57
|
+
"EvalQueueFullError",
|
|
58
|
+
"EvalRedactionError",
|
|
59
|
+
"EvalRunNotFoundError",
|
|
60
|
+
"EvalSchemaVersionError",
|
|
61
|
+
"EvalSerializationError",
|
|
62
|
+
"EvalStoreOwnershipError",
|
|
63
|
+
]
|