agentbyte 0.42.3__tar.gz → 0.43.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.42.3 → agentbyte-0.43.0}/CHANGELOG.md +31 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/PKG-INFO +2 -2
- {agentbyte-0.42.3 → agentbyte-0.43.0}/README.md +1 -1
- agentbyte-0.43.0/src/agentbyte/__about__.py +2 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/agents/agent.py +16 -1
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/agents/base.py +18 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/orchestration/ai.py +4 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/orchestration/base.py +50 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/orchestration/handoff.py +6 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/orchestration/plan.py +4 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/orchestration/policies.py +5 -1
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/orchestration/round_robin.py +4 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/agent.py +1 -0
- agentbyte-0.43.0/tests/agents/test_agent_stop_at_tools.py +170 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/orchestration/test_orchestrator_agent_contract.py +44 -12
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/orchestration/test_orchestrator_synthesis.py +90 -1
- agentbyte-0.42.3/src/agentbyte/__about__.py +0 -2
- {agentbyte-0.42.3 → agentbyte-0.43.0}/.gitignore +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/LICENSE +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/pyproject.toml +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/_optional.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/agents/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/agents/agent_as_tool.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/agents/embedding_agent.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/agents/types.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/cancellation_token.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/catalog.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/cli/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/cli/__main__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/cli/eval_commands.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/cli/loading.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/cli/main.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/compaction/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/compaction/counters.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/compaction/errors.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/compaction/grouping.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/compaction/strategies.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/component.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/context.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/context_providers/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/context_providers/base.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/context_providers/skill_tools.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/context_providers/skills.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/dataset/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/dataset/_aiosqlite.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/dataset/base.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/dataset/config.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/dataset/importer.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/dataset/json.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/dataset/loader.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/dataset/publish.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/dataset/publish_config.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/dataset/publishers.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/dataset/s3.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/dataset/sources.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/dataset/sqlite.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/dataset/sqlite_db.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/dataset/write_config.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/dataset/writers.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/entity.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/base.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/checks/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/checks/decorator.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/checks/keyword.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/checks/local.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/checks/process.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/checks/tool.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/checks/types.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/comparison.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/eval_dataset.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/history/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/history/conformance.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/history/errors.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/history/models.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/history/recorder.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/history/sql.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/history/sqlite.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/history/store.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/history/transitions.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/judges/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/judges/base.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/judges/composite.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/judges/llm.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/judges/pairwise.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/judges/reference.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/judges/trajectory.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/judges/validation.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/pairwise.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/report.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/runner.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/splitting.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/targets/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/targets/agent.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/targets/model.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/targets/multi_turn.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/targets/orchestrator.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/targets/runtime.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/targets/workflow.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/types.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/workbench/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/workbench/coordinator.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/workbench/jobs.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/workbench/smoke.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/workbench/smoke_tasks.json +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/workbench/suite.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/eval/workbench/verdict.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/execution_trace/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/execution_trace/collector.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/execution_trace/models.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/_retry_observability.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/auth.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/azure/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/azure/auth.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/azure/chat.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/azure/embedding.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/azure/settings.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/azure_openai.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/azure_openai_embedding.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/base.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/embeddings_base.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/openai/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/openai/chat.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/openai/embedding.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/openai/settings.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/openai_embedding.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/pricing.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/retry_policy.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/settings.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/llm/types.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/logger.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/memory/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/memory/base.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/messages.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/middleware/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/middleware/base.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/middleware/otel.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/middleware/retry.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/middleware/sql_usage.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/middleware/usage_logger.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/notebook.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/optim/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/optim/base.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/optim/config.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/optim/gepa.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/optim/mipro.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/optim/pareto.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/optim/reflective.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/optim/spec.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/optim/trace.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/orchestration/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/agents.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/clients.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/instruction_registry.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/instructions/orchestrator.yaml +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/instructions/query_rewriter.yaml +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/instructions/researcher.yaml +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/instructions/reviewer.yaml +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/instructions/writer.yaml +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/orchestration.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/skills/contracts-analyst/SKILL.md +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/skills/hr-analyst/SKILL.md +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/skills/hr-analyst/resources/departments.md +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/skills/hr-analyst/resources/employees.md +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/skills/hr-analyst/resources/payroll.md +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/streaming.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/presets/workflow.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/session_store.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/skills/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/skills/base.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/skills/resources.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/skills/scripts.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/skills/sources.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/skills/validation.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/termination/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/termination/base.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/termination/cancellation.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/termination/composite.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/termination/consecutive_agent.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/termination/external.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/termination/function_call.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/termination/handoff.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/termination/max_message.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/termination/predicate.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/termination/source.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/termination/text_mention.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/termination/timeout.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/termination/token_usage.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/tools/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/tools/base.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/tools/coding_tools.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/tools/core_tools.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/tools/decorator.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/tools/memory_tool.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/tools/research_tools.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/types.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/webui/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/webui/discovery.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/webui/eval_routes.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/webui/execution.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/webui/models.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/webui/registry.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/webui/server.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/webui/session_store.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/webui/sessions.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/webui/ui/assets/index-BsS4WYZu.css +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/webui/ui/assets/index-tGvO1yue.js +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/webui/ui/index.html +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/webui/ui/vite.svg +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/core/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/core/_structure_hash.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/core/checkpoint.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/core/models.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/core/runner.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/core/workflow.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/defaults.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/errors.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/loader.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/schema.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/schema_utils.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/sqlite_checkpoint.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/steps/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/steps/agent.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/steps/echo.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/steps/function.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/steps/http.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/steps/step.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/steps/subworkflow.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/steps/transform.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/src/agentbyte/workflow/visualizer.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/agents/test_agent_as_tool.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/agents/test_agent_basic.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/agents/test_agent_context_providers.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/agents/test_agent_error_response.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/agents/test_agent_event_types.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/agents/test_agent_memory_integration.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/agents/test_agent_middleware_integration.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/agents/test_agent_response_accessors.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/agents/test_agent_retry_middleware.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/agents/test_agent_stream_events.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/agents/test_embedding_agent.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/agents/test_tool_approval.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/agents/test_tool_batch_resolution.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/agents/test_tool_metadata.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/cli/test_loading.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/cli/test_registry_check.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/compaction/test_compaction.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/context_providers/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/context_providers/test_skill_tools.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/context_providers/test_skills_provider.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/dataset/fake_s3.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/dataset/test_dataset_exit.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/dataset/test_loader.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/dataset/test_multi_table.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/dataset/test_publish.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/dataset/test_sqlite_db.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/eval/test_eval_dataset.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/eval/test_eval_history.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/eval/test_eval_history_backends.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/eval/test_eval_jobs.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/eval/test_eval_workbench.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/eval/test_execution_trajectories.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/eval/test_multi_turn.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/eval/test_pairwise.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/eval/test_phase1_runner_and_targets.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/eval/test_phase2_checks_and_reports.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/eval/test_score_integrity.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/eval/test_splitting.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/eval/test_types_and_judges.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/examples/test_compaction_webapp.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/llm/test_azure_client.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/llm/test_azure_embedding_client.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/llm/test_llm_types.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/llm/test_openai_client.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/llm/test_openai_embedding_client.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/llm/test_pricing.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/llm/test_retry_observability.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/llm/test_retry_policy_api.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/llm/test_retryable_error_substrings.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/memory/test_memory.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/middleware/test_context_compaction.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/middleware/test_deduplicate_tool_result.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/middleware/test_middleware_chain.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/middleware/test_otel.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/middleware/test_retry_middleware.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/middleware/test_sql_usage.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/middleware/test_usage_logger.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/optim/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/optim/test_base.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/optim/test_base_integration.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/optim/test_config.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/optim/test_description_tunable.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/optim/test_gepa.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/optim/test_mipro.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/optim/test_orchestrator_optim.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/optim/test_pareto.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/optim/test_reflective.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/optim/test_score_integrity.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/optim/test_spec.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/optim/test_trace.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/orchestration/test_ai_orchestrator.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/orchestration/test_base_orchestrator.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/orchestration/test_handoff_orchestrator.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/orchestration/test_history_tool_call_pairing.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/orchestration/test_orchestration_usage_breakdown.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/orchestration/test_orchestrator_finalization.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/orchestration/test_orchestrator_member_events.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/orchestration/test_orchestrator_otel.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/orchestration/test_plan_orchestrator.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/orchestration/test_round_robin.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/presets/test_agents.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/presets/test_clients.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/presets/test_instruction_registry.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/presets/test_orchestration.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/presets/test_streaming.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/presets/test_workflow.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/skills/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/skills/test_base.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/skills/test_resources.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/skills/test_scripts.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/skills/test_sources.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/termination/test_base.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/termination/test_cancellation.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/termination/test_composite.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/termination/test_consecutive_agent.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/termination/test_external.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/termination/test_function_call.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/termination/test_handoff.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/termination/test_max_message.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/termination/test_predicate.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/termination/test_source.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/termination/test_text_mention.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/termination/test_timeout.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/termination/test_token_usage.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/test_cancellation_token.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/test_context.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/test_logger.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/test_messages.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/test_optional_extras.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/test_package_api.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/test_session_store.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/test_types.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/test_vanilla_chunker.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/tools/test_coding_tools.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/tools/test_memory_tool.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/tools/test_research_tools.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/tools/test_tools.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/webui/__init__.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/webui/helpers.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/webui/test_eval_routes.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/webui/test_execution.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/webui/test_package_api.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/webui/test_registry.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/webui/test_server.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/webui/test_sessions.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/webui/test_workflow_streaming.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/workflow/recovery_worker.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/workflow/test_agent_step_imports.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/workflow/test_checkpoint.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/workflow/test_subworkflow_step.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/workflow/test_workflow_agent.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/workflow/test_workflow_class.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/workflow/test_workflow_models.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/workflow/test_workflow_reliability.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/workflow/test_workflow_runner.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/workflow/test_workflow_schema.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/workflow/test_workflow_steps.py +0 -0
- {agentbyte-0.42.3 → agentbyte-0.43.0}/tests/workflow/test_workflow_visualizer.py +0 -0
|
@@ -6,6 +6,37 @@ The format follows Keep a Changelog principles and semantic versioning.
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.43.0] - 2026-10-05
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Agents: `stop_at_tools=[...]` ends the run with `finish_reason="tool_executed"`, without a
|
|
14
|
+
final model call, once a call to a named tool succeeds. Multi-step tool discovery and retries
|
|
15
|
+
after a failed call still run; a failed stop tool does not stop the run; the budget-exhaustion
|
|
16
|
+
finalization still applies. Names are validated against the agent's tools at construction.
|
|
17
|
+
Meant for team specialists whose raw tool results a synthesizer turns into the answer.
|
|
18
|
+
- Orchestration: `AgentHistoryPolicy(window="run")` sends this run's messages in full and
|
|
19
|
+
condenses earlier session turns to each user message plus the answer that closed it (no prior
|
|
20
|
+
tool calls, tool results, or worker notes). Use it as `FinalResultPolicy.synthesis_history` so a
|
|
21
|
+
synthesizer's input stays bounded across follow-up turns without losing their context.
|
|
22
|
+
- Orchestration: workers that end with `max_iterations` / `max_iterations_finalized` are reported to
|
|
23
|
+
the synthesizer as a separate completion fact (partial findings), next to error turns.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- Design guide: `summarize_tool_result` was documented as a summarization knob; it actually ends
|
|
28
|
+
the run after the first tool batch. The agent topic now describes it and `stop_at_tools`.
|
|
29
|
+
|
|
30
|
+
## [0.42.4] - 2026-10-05
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- Orchestration (spec 0066 follow-up): `PlanBasedOrchestrator`, `AIOrchestrator`,
|
|
35
|
+
`RoundRobinOrchestrator`, and `HandoffOrchestrator` now accept `name=` and `description=` and
|
|
36
|
+
forward them to `BaseOrchestrator`. Previously a team could not be named at construction, so
|
|
37
|
+
`response.source` was always the class name (e.g. `"PlanBasedOrchestrator"`) unless `name` was
|
|
38
|
+
set on the instance afterwards.
|
|
39
|
+
|
|
9
40
|
## [0.42.3] - 2026-10-05
|
|
10
41
|
|
|
11
42
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agentbyte
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.43.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.
|
|
80
|
+
Current release: **0.43.0**
|
|
81
81
|
|
|
82
82
|
## Building an Agent
|
|
83
83
|
|
|
@@ -372,6 +372,14 @@ class Agent(BaseAgent):
|
|
|
372
372
|
and working_context.get_approval_response(tool_call.call_id) is None
|
|
373
373
|
)
|
|
374
374
|
|
|
375
|
+
def _is_stop_tool_success(self, item: object) -> bool:
|
|
376
|
+
"""Whether *item* is a successful result of a ``stop_at_tools`` tool."""
|
|
377
|
+
return (
|
|
378
|
+
isinstance(item, ToolMessage)
|
|
379
|
+
and item.success
|
|
380
|
+
and item.tool_name in self.stop_at_tools
|
|
381
|
+
)
|
|
382
|
+
|
|
375
383
|
async def _resolve_tool_batch(
|
|
376
384
|
self,
|
|
377
385
|
working_context: AgentContext,
|
|
@@ -560,6 +568,7 @@ class Agent(BaseAgent):
|
|
|
560
568
|
# not-yet-run siblings, in order) before asking the model again.
|
|
561
569
|
if self._unresolved_tail_calls(working_context):
|
|
562
570
|
outcome: dict[str, int | bool] = {"executed": 0, "paused": False}
|
|
571
|
+
stop_tool_succeeded = False
|
|
563
572
|
async for item in self._resolve_tool_batch(
|
|
564
573
|
working_context,
|
|
565
574
|
cancellation_token,
|
|
@@ -567,11 +576,15 @@ class Agent(BaseAgent):
|
|
|
567
576
|
provider_tools,
|
|
568
577
|
outcome,
|
|
569
578
|
):
|
|
579
|
+
stop_tool_succeeded |= self._is_stop_tool_success(item)
|
|
570
580
|
yield item
|
|
571
581
|
tool_calls += int(outcome["executed"])
|
|
572
582
|
if outcome["paused"]:
|
|
573
583
|
finish_reason = "approval_needed"
|
|
574
584
|
break
|
|
585
|
+
if stop_tool_succeeded:
|
|
586
|
+
finish_reason = "tool_executed"
|
|
587
|
+
break
|
|
575
588
|
|
|
576
589
|
llm_messages = await self._prepare_llm_messages([], working_context, extra_instructions=extra_instructions)
|
|
577
590
|
if self.memory is not None:
|
|
@@ -773,6 +786,7 @@ class Agent(BaseAgent):
|
|
|
773
786
|
break
|
|
774
787
|
|
|
775
788
|
outcome = {"executed": 0, "paused": False}
|
|
789
|
+
stop_tool_succeeded = False
|
|
776
790
|
async for item in self._resolve_tool_batch(
|
|
777
791
|
working_context,
|
|
778
792
|
cancellation_token,
|
|
@@ -780,13 +794,14 @@ class Agent(BaseAgent):
|
|
|
780
794
|
provider_tools,
|
|
781
795
|
outcome,
|
|
782
796
|
):
|
|
797
|
+
stop_tool_succeeded |= self._is_stop_tool_success(item)
|
|
783
798
|
yield item
|
|
784
799
|
tool_calls += int(outcome["executed"])
|
|
785
800
|
if outcome["paused"]:
|
|
786
801
|
finish_reason = "approval_needed"
|
|
787
802
|
break
|
|
788
803
|
|
|
789
|
-
if not self.summarize_tool_result:
|
|
804
|
+
if stop_tool_succeeded or not self.summarize_tool_result:
|
|
790
805
|
finish_reason = "tool_executed"
|
|
791
806
|
break
|
|
792
807
|
|
|
@@ -59,6 +59,7 @@ class BaseAgent(ABC):
|
|
|
59
59
|
required_tools: Optional[List[str]] = None,
|
|
60
60
|
example_tasks: Optional[List[str]] = None,
|
|
61
61
|
context_providers: Optional[List[ContextProvider]] = None,
|
|
62
|
+
stop_at_tools: Optional[List[str]] = None,
|
|
62
63
|
**kwargs: Any,
|
|
63
64
|
) -> None:
|
|
64
65
|
"""Initialize the agent.
|
|
@@ -69,6 +70,15 @@ class BaseAgent(ABC):
|
|
|
69
70
|
``max_iterations >= 2``: with ``max_iterations=1`` the only turn keeps
|
|
70
71
|
its tools, so a run that calls a tool ends with
|
|
71
72
|
``finish_reason="max_iterations"`` and no final answer.
|
|
73
|
+
|
|
74
|
+
``summarize_tool_result=False`` ends the run right after the first tool
|
|
75
|
+
batch executes, with no further model call
|
|
76
|
+
(``finish_reason="tool_executed"``). ``stop_at_tools`` is the selective
|
|
77
|
+
form: the agent keeps its tool loop (multi-step discovery, retries after a
|
|
78
|
+
failed call) and ends the same way once a call to one of the named tools
|
|
79
|
+
succeeds. The names must be the agent's own tools. Use either when another
|
|
80
|
+
component, such as an orchestrator's synthesizer, writes the answer from
|
|
81
|
+
the raw tool results.
|
|
72
82
|
"""
|
|
73
83
|
self.name = name
|
|
74
84
|
self.description = description
|
|
@@ -84,6 +94,7 @@ class BaseAgent(ABC):
|
|
|
84
94
|
self.required_tools = required_tools or []
|
|
85
95
|
self.example_tasks = example_tasks or []
|
|
86
96
|
self.context_providers: List[ContextProvider] = list(context_providers) if context_providers else []
|
|
97
|
+
self.stop_at_tools: List[str] = list(stop_at_tools) if stop_at_tools else []
|
|
87
98
|
self.extra_config = kwargs
|
|
88
99
|
|
|
89
100
|
self._validate_configuration()
|
|
@@ -100,6 +111,13 @@ class BaseAgent(ABC):
|
|
|
100
111
|
raise AgentConfigurationError("Model client is required")
|
|
101
112
|
if self.max_iterations <= 0:
|
|
102
113
|
raise AgentConfigurationError("max_iterations must be > 0")
|
|
114
|
+
tool_names = {tool.name for tool in self.tools}
|
|
115
|
+
unknown = [name for name in self.stop_at_tools if name not in tool_names]
|
|
116
|
+
if unknown:
|
|
117
|
+
raise AgentConfigurationError(
|
|
118
|
+
f"stop_at_tools names unknown tools {unknown}; "
|
|
119
|
+
f"available: {sorted(tool_names)}"
|
|
120
|
+
)
|
|
103
121
|
|
|
104
122
|
def _process_tools(self, tools: List[Union[BaseTool, Callable]]) -> List[BaseTool]:
|
|
105
123
|
"""Normalize mixed tool list into BaseTool instances."""
|
|
@@ -54,11 +54,15 @@ class AIOrchestrator(BaseOrchestrator):
|
|
|
54
54
|
history_policy: HistoryContextPolicy | None = None,
|
|
55
55
|
selector_policy: SelectorContextPolicy | None = None,
|
|
56
56
|
final_result_policy: FinalResultPolicy | None = None,
|
|
57
|
+
name: str | None = None,
|
|
58
|
+
description: str | None = None,
|
|
57
59
|
):
|
|
58
60
|
super().__init__(
|
|
59
61
|
agents,
|
|
60
62
|
termination,
|
|
61
63
|
max_iterations,
|
|
64
|
+
name=name,
|
|
65
|
+
description=description,
|
|
62
66
|
history_policy=history_policy,
|
|
63
67
|
final_result_policy=final_result_policy,
|
|
64
68
|
)
|
|
@@ -51,6 +51,8 @@ _SYNTHESIS_INSTRUCTION = (
|
|
|
51
51
|
)
|
|
52
52
|
_SYNTHESIS_SELECTION_REASON = "Synthesis"
|
|
53
53
|
_SYNTHESIS_FAILED_FINISH_REASONS = frozenset({"error", "approval_needed", "cancelled"})
|
|
54
|
+
# A worker that hit its iteration budget returned at most a partial result.
|
|
55
|
+
_EXHAUSTED_FINISH_REASONS = frozenset({"max_iterations", "max_iterations_finalized"})
|
|
54
56
|
|
|
55
57
|
# Stop source -> agent finish_reason (spec 0066); every other source, termination
|
|
56
58
|
# conditions included, maps to "stop".
|
|
@@ -128,6 +130,7 @@ class BaseOrchestrator(ABC):
|
|
|
128
130
|
|
|
129
131
|
# Runtime state
|
|
130
132
|
self.shared_messages: List[Message] = []
|
|
133
|
+
self._run_start_index = 0
|
|
131
134
|
self.iteration_count = 0
|
|
132
135
|
self.start_time: Optional[float] = None
|
|
133
136
|
self._last_termination_check_count = 0
|
|
@@ -154,6 +157,7 @@ class BaseOrchestrator(ABC):
|
|
|
154
157
|
self._turn_usage: list[tuple[str, Usage]] = []
|
|
155
158
|
self._run_task_messages: list[Message] = []
|
|
156
159
|
self._worker_error_agents: list[str] = []
|
|
160
|
+
self._worker_exhausted_agents: list[str] = []
|
|
157
161
|
self._synthesis_usage: Usage | None = None
|
|
158
162
|
self._synthesis_message: Message | None = None
|
|
159
163
|
self._synthesis_meta: dict[str, Any] | None = None
|
|
@@ -307,6 +311,10 @@ class BaseOrchestrator(ABC):
|
|
|
307
311
|
# Seed shared_messages from prior session history when context is provided
|
|
308
312
|
if context is not None and context.messages:
|
|
309
313
|
self.shared_messages.extend(list(context.messages))
|
|
314
|
+
# Where this run's messages begin; earlier ones are prior session turns.
|
|
315
|
+
self._run_start_index = len(self.shared_messages) - (
|
|
316
|
+
len(initial_messages) if task_in_context else 0
|
|
317
|
+
)
|
|
310
318
|
|
|
311
319
|
# Initialize stop_message
|
|
312
320
|
stop_message: Optional[StopMessage] = None
|
|
@@ -419,6 +427,8 @@ class BaseOrchestrator(ABC):
|
|
|
419
427
|
if self._synthesizer is not None:
|
|
420
428
|
if result.finish_reason == "error":
|
|
421
429
|
self._worker_error_agents.append(next_agent.name)
|
|
430
|
+
elif result.finish_reason in _EXHAUSTED_FINISH_REASONS:
|
|
431
|
+
self._worker_exhausted_agents.append(next_agent.name)
|
|
422
432
|
approval_stop = self._get_approval_stop_message(next_agent, result)
|
|
423
433
|
if approval_stop is not None:
|
|
424
434
|
# Synthesis cannot resolve a pending approval; stop here.
|
|
@@ -888,6 +898,12 @@ class BaseOrchestrator(ABC):
|
|
|
888
898
|
"- Worker turns that ended in an error: "
|
|
889
899
|
+ ", ".join(dict.fromkeys(self._worker_error_agents))
|
|
890
900
|
)
|
|
901
|
+
if self._worker_exhausted_agents:
|
|
902
|
+
facts.append(
|
|
903
|
+
"- Worker turns that ran out of iterations before completing (treat their "
|
|
904
|
+
"findings as partial): "
|
|
905
|
+
+ ", ".join(dict.fromkeys(self._worker_exhausted_agents))
|
|
906
|
+
)
|
|
891
907
|
facts.extend(f"- {fact}" for fact in self._get_synthesis_facts())
|
|
892
908
|
return (
|
|
893
909
|
f"Original request:\n{request}\n\n"
|
|
@@ -1057,7 +1073,9 @@ class BaseOrchestrator(ABC):
|
|
|
1057
1073
|
self._last_context_was_text = False
|
|
1058
1074
|
self._turn_usage = []
|
|
1059
1075
|
self._run_task_messages = []
|
|
1076
|
+
self._run_start_index = 0
|
|
1060
1077
|
self._worker_error_agents = []
|
|
1078
|
+
self._worker_exhausted_agents = []
|
|
1061
1079
|
self._synthesis_usage = None
|
|
1062
1080
|
self._synthesis_message = None
|
|
1063
1081
|
self._synthesis_meta = None
|
|
@@ -1260,8 +1278,40 @@ class BaseOrchestrator(ABC):
|
|
|
1260
1278
|
"""Return the relevant shared-message slice for a history policy."""
|
|
1261
1279
|
if policy.window == "recent" and policy.message_limit is not None:
|
|
1262
1280
|
return self._select_recent_messages(policy.message_limit)
|
|
1281
|
+
if policy.window == "run":
|
|
1282
|
+
prior = self.shared_messages[: self._run_start_index]
|
|
1283
|
+
return [
|
|
1284
|
+
*self._condense_prior_turns(prior),
|
|
1285
|
+
*self.shared_messages[self._run_start_index :],
|
|
1286
|
+
]
|
|
1263
1287
|
return list(self.shared_messages)
|
|
1264
1288
|
|
|
1289
|
+
@staticmethod
|
|
1290
|
+
def _condense_prior_turns(messages: list[Message]) -> list[Message]:
|
|
1291
|
+
"""Each earlier turn as its user message(s) plus the answer that closed it.
|
|
1292
|
+
|
|
1293
|
+
The closing answer is the turn's last assistant message with content and
|
|
1294
|
+
no tool calls (for a team with a synthesizer, the synthesized answer).
|
|
1295
|
+
Tool calls, tool results, and intermediate replies are dropped.
|
|
1296
|
+
"""
|
|
1297
|
+
condensed: list[Message] = []
|
|
1298
|
+
answer: Message | None = None
|
|
1299
|
+
for message in messages:
|
|
1300
|
+
if isinstance(message, UserMessage):
|
|
1301
|
+
if answer is not None:
|
|
1302
|
+
condensed.append(answer)
|
|
1303
|
+
answer = None
|
|
1304
|
+
condensed.append(message)
|
|
1305
|
+
elif (
|
|
1306
|
+
isinstance(message, AssistantMessage)
|
|
1307
|
+
and message.content
|
|
1308
|
+
and not message.tool_calls
|
|
1309
|
+
):
|
|
1310
|
+
answer = message
|
|
1311
|
+
if answer is not None:
|
|
1312
|
+
condensed.append(answer)
|
|
1313
|
+
return condensed
|
|
1314
|
+
|
|
1265
1315
|
def _select_recent_messages(self, message_limit: int) -> list[Message]:
|
|
1266
1316
|
"""Last `message_limit` messages, never splitting a tool-call exchange.
|
|
1267
1317
|
|
|
@@ -104,6 +104,8 @@ class HandoffOrchestrator(BaseOrchestrator):
|
|
|
104
104
|
max_iterations: int = 50,
|
|
105
105
|
history_policy: HistoryContextPolicy | None = None,
|
|
106
106
|
final_result_policy: FinalResultPolicy | None = None,
|
|
107
|
+
name: str | None = None,
|
|
108
|
+
description: str | None = None,
|
|
107
109
|
):
|
|
108
110
|
"""
|
|
109
111
|
Initialise the handoff orchestrator.
|
|
@@ -124,11 +126,15 @@ class HandoffOrchestrator(BaseOrchestrator):
|
|
|
124
126
|
max_iterations: Safety cap on orchestration iterations.
|
|
125
127
|
history_policy: History window/format configuration.
|
|
126
128
|
final_result_policy: Final-message selection and finalization config.
|
|
129
|
+
name: Team name; reported as ``response.source`` (defaults to the class name).
|
|
130
|
+
description: Optional description of the team's purpose.
|
|
127
131
|
"""
|
|
128
132
|
super().__init__(
|
|
129
133
|
agents,
|
|
130
134
|
termination,
|
|
131
135
|
max_iterations,
|
|
136
|
+
name=name,
|
|
137
|
+
description=description,
|
|
132
138
|
history_policy=history_policy,
|
|
133
139
|
final_result_policy=final_result_policy,
|
|
134
140
|
)
|
|
@@ -78,11 +78,15 @@ class PlanBasedOrchestrator(BaseOrchestrator):
|
|
|
78
78
|
history_policy: HistoryContextPolicy | None = None,
|
|
79
79
|
review_gate_policy: ReviewGatePolicy | None = None,
|
|
80
80
|
final_result_policy: FinalResultPolicy | None = None,
|
|
81
|
+
name: str | None = None,
|
|
82
|
+
description: str | None = None,
|
|
81
83
|
):
|
|
82
84
|
super().__init__(
|
|
83
85
|
agents,
|
|
84
86
|
termination,
|
|
85
87
|
max_iterations,
|
|
88
|
+
name=name,
|
|
89
|
+
description=description,
|
|
86
90
|
history_policy=history_policy,
|
|
87
91
|
final_result_policy=final_result_policy,
|
|
88
92
|
)
|
|
@@ -12,7 +12,11 @@ class AgentHistoryPolicy(BaseModel):
|
|
|
12
12
|
|
|
13
13
|
model_config = ConfigDict(extra="forbid")
|
|
14
14
|
|
|
15
|
-
window: Literal["full", "recent"]
|
|
15
|
+
window: Literal["full", "recent", "run"]
|
|
16
|
+
"""``full``: the whole shared conversation. ``recent``: the last
|
|
17
|
+
``message_limit`` messages. ``run``: this run's messages in full, with earlier
|
|
18
|
+
turns of the session condensed to each user message and the answer that
|
|
19
|
+
closed its turn (no tool calls, tool results, or intermediate replies)."""
|
|
16
20
|
message_limit: int | None = None
|
|
17
21
|
format: Literal["messages", "text", "markdown", "json"]
|
|
18
22
|
include_turn_prompt: bool = True
|
|
@@ -32,11 +32,15 @@ class RoundRobinOrchestrator(BaseOrchestrator):
|
|
|
32
32
|
max_iterations: int = 50,
|
|
33
33
|
history_policy: HistoryContextPolicy | None = None,
|
|
34
34
|
final_result_policy: FinalResultPolicy | None = None,
|
|
35
|
+
name: str | None = None,
|
|
36
|
+
description: str | None = None,
|
|
35
37
|
):
|
|
36
38
|
super().__init__(
|
|
37
39
|
agents,
|
|
38
40
|
termination,
|
|
39
41
|
max_iterations,
|
|
42
|
+
name=name,
|
|
43
|
+
description=description,
|
|
40
44
|
history_policy=history_policy,
|
|
41
45
|
final_result_policy=final_result_policy,
|
|
42
46
|
)
|
|
@@ -79,6 +79,7 @@ class WorkflowAgent(BaseAgent):
|
|
|
79
79
|
self.max_iterations = 1
|
|
80
80
|
self.output_format = None
|
|
81
81
|
self.summarize_tool_result = False
|
|
82
|
+
self.stop_at_tools = []
|
|
82
83
|
self.required_tools = []
|
|
83
84
|
self.example_tasks = list(workflow.config.metadata.get("example_tasks", []))
|
|
84
85
|
self.extra_config = {}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""``stop_at_tools``: end the run, without a final model call, once a named tool succeeds."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import AsyncGenerator
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from agentbyte.agents import Agent
|
|
11
|
+
from agentbyte.agents.base import AgentConfigurationError
|
|
12
|
+
from agentbyte.llm.base import BaseChatCompletionClient, BaseChatCompletionClientConfig
|
|
13
|
+
from agentbyte.llm.types import ChatCompletionChunk, ChatCompletionResult
|
|
14
|
+
from agentbyte.messages import AssistantMessage, ToolMessage, Usage, UserMessage
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class _Config(BaseChatCompletionClientConfig):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class FakeModelClient(BaseChatCompletionClient):
|
|
22
|
+
"""Returns scripted completions in order."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, responses: list[ChatCompletionResult]) -> None:
|
|
25
|
+
super().__init__(model="fake", client=object())
|
|
26
|
+
self._responses = list(responses)
|
|
27
|
+
|
|
28
|
+
async def create(self, messages, tools=None, output_format=None, **kwargs: Any) -> ChatCompletionResult:
|
|
29
|
+
return self._responses.pop(0)
|
|
30
|
+
|
|
31
|
+
async def create_stream(self, *args: Any, **kwargs: Any) -> AsyncGenerator[ChatCompletionChunk, None]:
|
|
32
|
+
yield ChatCompletionChunk(content="", model="fake", is_complete=True)
|
|
33
|
+
|
|
34
|
+
def _to_config(self) -> BaseChatCompletionClientConfig:
|
|
35
|
+
return _Config(model=self.model, config=self.config)
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def _from_config(cls, config: BaseChatCompletionClientConfig) -> FakeModelClient:
|
|
39
|
+
return cls([])
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def discover_schema() -> str:
|
|
43
|
+
"""Return the table schema."""
|
|
44
|
+
return "orders(id, amount)"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def run_query(sql: str) -> str:
|
|
48
|
+
"""Run a read-only SQL query."""
|
|
49
|
+
if sql == "bad":
|
|
50
|
+
raise ValueError("unknown column")
|
|
51
|
+
return "rows: 3"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _calls(*calls: tuple[str, dict]) -> ChatCompletionResult:
|
|
55
|
+
return ChatCompletionResult(
|
|
56
|
+
message=AssistantMessage(
|
|
57
|
+
content="",
|
|
58
|
+
source="fake",
|
|
59
|
+
tool_calls=[
|
|
60
|
+
{"tool_name": name, "parameters": params, "call_id": f"c-{name}-{i}"}
|
|
61
|
+
for i, (name, params) in enumerate(calls)
|
|
62
|
+
],
|
|
63
|
+
),
|
|
64
|
+
usage=Usage(tokens_input=1, tokens_output=1),
|
|
65
|
+
model="fake",
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _answer(text: str) -> ChatCompletionResult:
|
|
70
|
+
return ChatCompletionResult(
|
|
71
|
+
message=AssistantMessage(content=text, source="fake"),
|
|
72
|
+
usage=Usage(tokens_input=1, tokens_output=1),
|
|
73
|
+
model="fake",
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _agent(client: FakeModelClient, **kwargs) -> Agent:
|
|
78
|
+
return Agent(
|
|
79
|
+
name="analyst",
|
|
80
|
+
description="desc",
|
|
81
|
+
instructions="help",
|
|
82
|
+
model_client=client,
|
|
83
|
+
tools=[discover_schema, run_query],
|
|
84
|
+
**kwargs,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@pytest.mark.asyncio
|
|
89
|
+
async def test_stops_after_multi_step_discovery_without_final_answer() -> None:
|
|
90
|
+
client = FakeModelClient(
|
|
91
|
+
[_calls(("discover_schema", {})), _calls(("run_query", {"sql": "ok"}))]
|
|
92
|
+
)
|
|
93
|
+
agent = _agent(client, stop_at_tools=["run_query"])
|
|
94
|
+
|
|
95
|
+
response = await agent.run(UserMessage(content="how many orders?", source="user"))
|
|
96
|
+
|
|
97
|
+
assert response.finish_reason == "tool_executed"
|
|
98
|
+
assert response.usage.llm_calls == 2
|
|
99
|
+
assert response.usage.tool_calls == 2
|
|
100
|
+
last = response.messages[-1]
|
|
101
|
+
assert isinstance(last, ToolMessage)
|
|
102
|
+
assert (last.tool_name, last.success, last.content) == ("run_query", True, "rows: 3")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@pytest.mark.asyncio
|
|
106
|
+
async def test_failed_stop_tool_does_not_stop_so_the_agent_can_retry() -> None:
|
|
107
|
+
client = FakeModelClient(
|
|
108
|
+
[_calls(("run_query", {"sql": "bad"})), _calls(("run_query", {"sql": "ok"}))]
|
|
109
|
+
)
|
|
110
|
+
agent = _agent(client, stop_at_tools=["run_query"])
|
|
111
|
+
|
|
112
|
+
response = await agent.run(UserMessage(content="how many orders?", source="user"))
|
|
113
|
+
|
|
114
|
+
assert response.finish_reason == "tool_executed"
|
|
115
|
+
results = [m for m in response.messages if isinstance(m, ToolMessage)]
|
|
116
|
+
assert [m.success for m in results] == [False, True]
|
|
117
|
+
assert response.usage.llm_calls == 2
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@pytest.mark.asyncio
|
|
121
|
+
async def test_stop_tool_in_a_parallel_batch_runs_the_whole_batch() -> None:
|
|
122
|
+
client = FakeModelClient(
|
|
123
|
+
[_calls(("run_query", {"sql": "ok"}), ("discover_schema", {}))]
|
|
124
|
+
)
|
|
125
|
+
agent = _agent(client, stop_at_tools=["run_query"])
|
|
126
|
+
|
|
127
|
+
response = await agent.run(UserMessage(content="q", source="user"))
|
|
128
|
+
|
|
129
|
+
assert response.finish_reason == "tool_executed"
|
|
130
|
+
assert [m.tool_name for m in response.messages if isinstance(m, ToolMessage)] == [
|
|
131
|
+
"run_query",
|
|
132
|
+
"discover_schema",
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@pytest.mark.asyncio
|
|
137
|
+
async def test_without_a_stop_tool_call_the_agent_answers_normally() -> None:
|
|
138
|
+
client = FakeModelClient([_calls(("discover_schema", {})), _answer("no query needed")])
|
|
139
|
+
agent = _agent(client, stop_at_tools=["run_query"])
|
|
140
|
+
|
|
141
|
+
response = await agent.run(UserMessage(content="what tables exist?", source="user"))
|
|
142
|
+
|
|
143
|
+
assert response.finish_reason == "stop"
|
|
144
|
+
assert response.final_content == "no query needed"
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@pytest.mark.asyncio
|
|
148
|
+
async def test_stop_tool_never_succeeding_finalizes_on_exhaustion() -> None:
|
|
149
|
+
client = FakeModelClient(
|
|
150
|
+
[
|
|
151
|
+
_calls(("run_query", {"sql": "bad"})),
|
|
152
|
+
_calls(("run_query", {"sql": "bad"})),
|
|
153
|
+
_answer("The query failed: unknown column."),
|
|
154
|
+
]
|
|
155
|
+
)
|
|
156
|
+
agent = _agent(client, stop_at_tools=["run_query"], max_iterations=3)
|
|
157
|
+
|
|
158
|
+
response = await agent.run(UserMessage(content="q", source="user"))
|
|
159
|
+
|
|
160
|
+
assert response.finish_reason == "max_iterations_finalized"
|
|
161
|
+
assert response.final_content == "The query failed: unknown column."
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def test_unknown_stop_tool_is_rejected() -> None:
|
|
165
|
+
with pytest.raises(AgentConfigurationError, match="run_qeury"):
|
|
166
|
+
_agent(FakeModelClient([]), stop_at_tools=["run_qeury"])
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def test_stop_at_tools_defaults_to_empty() -> None:
|
|
170
|
+
assert _agent(FakeModelClient([])).stop_at_tools == []
|
{agentbyte-0.42.3 → agentbyte-0.43.0}/tests/orchestration/test_orchestrator_agent_contract.py
RENAMED
|
@@ -123,26 +123,58 @@ def _never() -> TextMentionTermination:
|
|
|
123
123
|
return TextMentionTermination("NEVER_SAID")
|
|
124
124
|
|
|
125
125
|
|
|
126
|
-
def _team(
|
|
126
|
+
def _team(
|
|
127
|
+
pattern: str,
|
|
128
|
+
*agents: BaseAgent,
|
|
129
|
+
client: CoordinatorClient | None = None,
|
|
130
|
+
**identity: str,
|
|
131
|
+
):
|
|
127
132
|
members = list(agents) or [ScriptAgent("worker")]
|
|
128
133
|
client = client or CoordinatorClient()
|
|
134
|
+
if not identity:
|
|
135
|
+
identity = {"name": "team"}
|
|
129
136
|
if pattern == "round_robin":
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
raise AssertionError(pattern)
|
|
139
|
-
team.name = "team"
|
|
140
|
-
return team
|
|
137
|
+
return RoundRobinOrchestrator(members, _never(), max_iterations=1, **identity)
|
|
138
|
+
if pattern == "handoff":
|
|
139
|
+
return HandoffOrchestrator(members, _never(), max_iterations=1, **identity)
|
|
140
|
+
if pattern == "ai":
|
|
141
|
+
return AIOrchestrator(members, _never(), client, max_iterations=1, **identity)
|
|
142
|
+
if pattern == "plan":
|
|
143
|
+
return PlanBasedOrchestrator(members, _never(), client, max_iterations=1, **identity)
|
|
144
|
+
raise AssertionError(pattern)
|
|
141
145
|
|
|
142
146
|
|
|
143
147
|
PATTERNS = ["round_robin", "handoff", "ai", "plan"]
|
|
144
148
|
|
|
145
149
|
|
|
150
|
+
_PATTERN_CLASSES = {
|
|
151
|
+
"round_robin": "RoundRobinOrchestrator",
|
|
152
|
+
"handoff": "HandoffOrchestrator",
|
|
153
|
+
"ai": "AIOrchestrator",
|
|
154
|
+
"plan": "PlanBasedOrchestrator",
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@pytest.mark.asyncio
|
|
159
|
+
class TestTeamIdentity:
|
|
160
|
+
@pytest.mark.parametrize("pattern", PATTERNS)
|
|
161
|
+
async def test_name_and_description_are_constructor_arguments(self, pattern: str) -> None:
|
|
162
|
+
team = _team(pattern, name="procurement", description="Procurement specialists")
|
|
163
|
+
|
|
164
|
+
response = await team.run("fix it")
|
|
165
|
+
|
|
166
|
+
assert team.name == "procurement"
|
|
167
|
+
assert team.description == "Procurement specialists"
|
|
168
|
+
assert response.source == "procurement"
|
|
169
|
+
|
|
170
|
+
@pytest.mark.parametrize("pattern", PATTERNS)
|
|
171
|
+
async def test_name_defaults_to_class_name(self, pattern: str) -> None:
|
|
172
|
+
team = _team(pattern, description="unnamed")
|
|
173
|
+
|
|
174
|
+
assert team.name == _PATTERN_CLASSES[pattern]
|
|
175
|
+
assert team.description == "unnamed"
|
|
176
|
+
|
|
177
|
+
|
|
146
178
|
@pytest.mark.asyncio
|
|
147
179
|
class TestStreamInvariant:
|
|
148
180
|
@pytest.mark.parametrize("pattern", PATTERNS)
|