agentbyte 0.25.0__tar.gz → 0.26.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.25.0 → agentbyte-0.26.0}/CHANGELOG.md +16 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/PKG-INFO +2 -2
- {agentbyte-0.25.0 → agentbyte-0.26.0}/README.md +1 -1
- agentbyte-0.26.0/src/agentbyte/__about__.py +2 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/tools/base.py +117 -144
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/tools/test_tools.py +183 -3
- agentbyte-0.25.0/src/agentbyte/__about__.py +0 -2
- {agentbyte-0.25.0 → agentbyte-0.26.0}/.gitignore +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/LICENSE +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/pyproject.toml +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/agents/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/agents/agent.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/agents/agent_as_tool.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/agents/base.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/agents/embedding_agent.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/agents/types.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/cancellation_token.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/catalog.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/cli/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/cli/main.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/component.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/context.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/context_providers/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/context_providers/base.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/context_providers/skill_tools.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/context_providers/skills.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/base.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/config.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/importer.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/json.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/loader.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/publish.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/publish_config.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/publishers.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/sources.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/sqlite.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/sqlite_db.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/write_config.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/writers.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/entity.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/base.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/checks/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/checks/decorator.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/checks/keyword.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/checks/local.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/checks/tool.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/checks/types.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/comparison.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/eval_dataset.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/judges/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/judges/base.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/judges/composite.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/judges/llm.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/judges/pairwise.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/judges/reference.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/pairwise.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/report.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/runner.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/splitting.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/targets/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/targets/agent.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/targets/model.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/targets/multi_turn.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/targets/orchestrator.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/types.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/_retry_observability.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/auth.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/azure/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/azure/auth.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/azure/chat.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/azure/embedding.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/azure/settings.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/azure_openai.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/azure_openai_embedding.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/base.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/embeddings_base.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/openai/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/openai/chat.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/openai/embedding.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/openai/settings.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/openai_embedding.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/pricing.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/retry_policy.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/settings.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/types.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/logger.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/memory/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/memory/base.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/messages.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/middleware/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/middleware/base.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/middleware/otel.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/middleware/retry.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/middleware/sql_usage.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/middleware/usage_logger.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/notebook.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/base.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/config.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/gepa.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/mipro.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/pareto.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/reflective.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/spec.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/trace.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/orchestration/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/orchestration/ai.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/orchestration/base.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/orchestration/handoff.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/orchestration/plan.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/orchestration/policies.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/orchestration/round_robin.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/agents.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/clients.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/instruction_registry.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/instructions/orchestrator.yaml +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/instructions/query_rewriter.yaml +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/instructions/researcher.yaml +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/instructions/reviewer.yaml +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/instructions/writer.yaml +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/orchestration.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/skills/contracts-analyst/SKILL.md +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/skills/hr-analyst/SKILL.md +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/skills/hr-analyst/resources/departments.md +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/skills/hr-analyst/resources/employees.md +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/skills/hr-analyst/resources/payroll.md +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/streaming.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/workflow.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/session_store.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/skills/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/skills/base.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/skills/resources.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/skills/scripts.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/skills/sources.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/skills/validation.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/base.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/cancellation.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/composite.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/consecutive_agent.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/external.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/function_call.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/handoff.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/max_message.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/predicate.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/source.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/text_mention.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/timeout.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/token_usage.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/tools/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/tools/coding_tools.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/tools/core_tools.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/tools/decorator.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/tools/memory_tool.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/tools/research_tools.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/types.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/discovery.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/execution.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/models.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/registry.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/server.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/session_store.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/sessions.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/ui/assets/index-BF3DwXaF.js +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/ui/assets/index-ar5tOeqt.css +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/ui/index.html +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/ui/vite.svg +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/agent.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/core/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/core/_structure_hash.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/core/checkpoint.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/core/models.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/core/runner.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/core/workflow.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/defaults.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/loader.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/schema.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/schema_utils.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/steps/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/steps/agentbyte_agent.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/steps/echo.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/steps/function.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/steps/http.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/steps/step.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/steps/subworkflow.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/steps/transform.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/visualizer.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_as_tool.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_basic.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_context_providers.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_event_types.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_memory_integration.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_middleware_integration.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_response_accessors.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_retry_middleware.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_stream_events.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_embedding_agent.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_tool_approval.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/cli/test_registry_check.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/context_providers/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/context_providers/test_skill_tools.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/context_providers/test_skills_provider.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/dataset/test_loader.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/dataset/test_multi_table.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/dataset/test_publish.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/dataset/test_sqlite_db.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/eval/test_eval_dataset.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/eval/test_multi_turn.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/eval/test_pairwise.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/eval/test_phase1_runner_and_targets.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/eval/test_phase2_checks_and_reports.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/eval/test_splitting.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/eval/test_types_and_judges.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/llm/test_azure_client.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/llm/test_azure_embedding_client.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/llm/test_llm_types.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/llm/test_openai_client.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/llm/test_openai_embedding_client.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/llm/test_pricing.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/llm/test_retry_observability.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/llm/test_retry_policy_api.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/memory/test_memory.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/middleware/test_middleware_chain.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/middleware/test_otel.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/middleware/test_retry_middleware.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/middleware/test_sql_usage.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/middleware/test_usage_logger.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_base.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_base_integration.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_config.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_gepa.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_mipro.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_pareto.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_reflective.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_spec.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_trace.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/orchestration/test_ai_orchestrator.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/orchestration/test_base_orchestrator.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/orchestration/test_handoff_orchestrator.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/orchestration/test_plan_orchestrator.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/orchestration/test_round_robin.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/presets/test_agents.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/presets/test_clients.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/presets/test_instruction_registry.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/presets/test_orchestration.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/presets/test_streaming.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/presets/test_workflow.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/skills/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/skills/test_base.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/skills/test_resources.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/skills/test_scripts.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/skills/test_sources.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_base.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_cancellation.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_composite.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_consecutive_agent.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_external.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_function_call.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_handoff.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_max_message.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_predicate.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_source.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_text_mention.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_timeout.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_token_usage.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/test_cancellation_token.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/test_context.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/test_logger.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/test_messages.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/test_package_api.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/test_session_store.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/test_types.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/tools/test_coding_tools.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/tools/test_memory_tool.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/tools/test_research_tools.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/webui/__init__.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/webui/helpers.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/webui/test_execution.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/webui/test_package_api.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/webui/test_registry.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/webui/test_server.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/webui/test_sessions.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_checkpoint.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_subworkflow_step.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_workflow_agent.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_workflow_class.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_workflow_models.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_workflow_runner.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_workflow_schema.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_workflow_steps.py +0 -0
- {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_workflow_visualizer.py +0 -0
|
@@ -4,6 +4,22 @@ All notable changes to Agentbyte are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format follows Keep a Changelog principles and semantic versioning.
|
|
6
6
|
|
|
7
|
+
## [0.26.0] - 2026-09-04
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `FunctionTool` now supports structured parameters backed by Pydantic models, including nested models, optional collections, typed dictionaries, tuples, unions, field constraints, and `Annotated` parameter descriptions.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Function-tool schema generation and execution now share one strict Pydantic validation model. Validated object arguments reach Pydantic-annotated functions as model instances, dictionary annotations remain dictionaries, and JSON arrays are converted to declared tuple types.
|
|
16
|
+
- Function tools now reject unexpected arguments and unsupported annotations at the boundary instead of silently accepting or flattening them.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Fixed optional and model-shaped tool parameters being incorrectly advertised as strings, which caused valid object-shaped LLM tool calls to fail with `Invalid parameters provided` before tool execution.
|
|
21
|
+
- Parameter schemas now use author-provided `Field` or string `Annotated` descriptions instead of leaking Python builtin and typing documentation.
|
|
22
|
+
|
|
7
23
|
## [0.25.0] - 2026-09-01
|
|
8
24
|
|
|
9
25
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agentbyte
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.26.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
|
|
@@ -86,7 +86,7 @@ Description-Content-Type: text/markdown
|
|
|
86
86
|
|
|
87
87
|
Agentbyte is an observability-first agentic AI framework for building and studying multiagent systems with a learning-first, implementation-oriented workflow.
|
|
88
88
|
|
|
89
|
-
Current release: **0.
|
|
89
|
+
Current release: **0.26.0**
|
|
90
90
|
|
|
91
91
|
## Building an Agent
|
|
92
92
|
|
|
@@ -10,10 +10,24 @@ Includes:
|
|
|
10
10
|
- FunctionTool: Tool that wraps Python functions
|
|
11
11
|
"""
|
|
12
12
|
import inspect
|
|
13
|
+
import json
|
|
13
14
|
from abc import ABC, abstractmethod
|
|
14
15
|
from collections.abc import AsyncGenerator
|
|
15
16
|
from enum import Enum
|
|
16
|
-
from typing import
|
|
17
|
+
from typing import (
|
|
18
|
+
Annotated,
|
|
19
|
+
Any,
|
|
20
|
+
Callable,
|
|
21
|
+
Dict,
|
|
22
|
+
Optional,
|
|
23
|
+
Union,
|
|
24
|
+
get_args,
|
|
25
|
+
get_origin,
|
|
26
|
+
get_type_hints,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
from pydantic import BaseModel, ConfigDict, Field, ValidationError, create_model
|
|
30
|
+
from pydantic.fields import FieldInfo
|
|
17
31
|
|
|
18
32
|
from ..types import ToolResult
|
|
19
33
|
|
|
@@ -365,10 +379,17 @@ class FunctionTool(BaseTool):
|
|
|
365
379
|
|
|
366
380
|
super().__init__(tool_name, tool_description, version, approval_mode)
|
|
367
381
|
|
|
368
|
-
# Extract function metadata for schema generation
|
|
382
|
+
# Extract function metadata for schema generation and validation.
|
|
369
383
|
self.signature = inspect.signature(func)
|
|
370
|
-
|
|
371
|
-
|
|
384
|
+
try:
|
|
385
|
+
self.type_hints = get_type_hints(func, include_extras=True)
|
|
386
|
+
self._parameters_model = self._build_parameters_model()
|
|
387
|
+
self._parameters_schema = self._parameters_model.model_json_schema()
|
|
388
|
+
except Exception as exc:
|
|
389
|
+
raise TypeError(
|
|
390
|
+
f"Unable to generate a parameter schema for tool {tool_name!r}: {exc}"
|
|
391
|
+
) from exc
|
|
392
|
+
self._parameters_schema.pop("title", None)
|
|
372
393
|
|
|
373
394
|
@property
|
|
374
395
|
def parameters(self) -> Dict[str, Any]:
|
|
@@ -405,20 +426,34 @@ class FunctionTool(BaseTool):
|
|
|
405
426
|
ToolResult with function execution outcome
|
|
406
427
|
"""
|
|
407
428
|
try:
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
429
|
+
validated_parameters = self._validate_and_convert_parameters(parameters)
|
|
430
|
+
except ValidationError as exc:
|
|
431
|
+
return ToolResult(
|
|
432
|
+
success=False,
|
|
433
|
+
result=None,
|
|
434
|
+
error=self._format_validation_error(exc),
|
|
435
|
+
metadata={
|
|
436
|
+
"tool_name": self.name,
|
|
437
|
+
"exception_type": type(exc).__name__,
|
|
438
|
+
},
|
|
439
|
+
)
|
|
440
|
+
except (TypeError, ValueError) as exc:
|
|
441
|
+
return ToolResult(
|
|
442
|
+
success=False,
|
|
443
|
+
result=None,
|
|
444
|
+
error=f"Invalid parameters provided: {exc}",
|
|
445
|
+
metadata={
|
|
446
|
+
"tool_name": self.name,
|
|
447
|
+
"exception_type": type(exc).__name__,
|
|
448
|
+
},
|
|
449
|
+
)
|
|
416
450
|
|
|
451
|
+
try:
|
|
417
452
|
# Execute function (handle both sync and async)
|
|
418
453
|
if inspect.iscoroutinefunction(self.func):
|
|
419
|
-
result = await self.func(**
|
|
454
|
+
result = await self.func(**validated_parameters)
|
|
420
455
|
else:
|
|
421
|
-
result = self.func(**
|
|
456
|
+
result = self.func(**validated_parameters)
|
|
422
457
|
|
|
423
458
|
return ToolResult(
|
|
424
459
|
success=True,
|
|
@@ -438,145 +473,83 @@ class FunctionTool(BaseTool):
|
|
|
438
473
|
},
|
|
439
474
|
)
|
|
440
475
|
|
|
441
|
-
def
|
|
442
|
-
"""
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
2. Extracts type hints for each parameter
|
|
449
|
-
3. Converts Python types to JSON Schema types
|
|
450
|
-
4. Identifies required vs optional parameters
|
|
451
|
-
5. Extracts enum values from Literal types
|
|
452
|
-
|
|
453
|
-
Returns:
|
|
454
|
-
JSON schema dictionary
|
|
455
|
-
"""
|
|
456
|
-
schema = {
|
|
457
|
-
"type": "object",
|
|
458
|
-
"properties": {},
|
|
459
|
-
"required": []
|
|
460
|
-
}
|
|
476
|
+
def validate_parameters(self, params: Dict[str, Any]) -> bool:
|
|
477
|
+
"""Return whether parameters satisfy the wrapped function contract."""
|
|
478
|
+
try:
|
|
479
|
+
self._validate_and_convert_parameters(params)
|
|
480
|
+
except (TypeError, ValueError, ValidationError):
|
|
481
|
+
return False
|
|
482
|
+
return True
|
|
461
483
|
|
|
484
|
+
def _build_parameters_model(self) -> type[BaseModel]:
|
|
485
|
+
"""Build the shared Pydantic schema and validation model."""
|
|
486
|
+
fields: dict[str, tuple[Any, Any]] = {}
|
|
462
487
|
for param_name, param in self.signature.parameters.items():
|
|
463
|
-
# Skip 'self' parameter for methods
|
|
464
488
|
if param_name == "self":
|
|
465
489
|
continue
|
|
490
|
+
if param.kind in {
|
|
491
|
+
inspect.Parameter.POSITIONAL_ONLY,
|
|
492
|
+
inspect.Parameter.VAR_POSITIONAL,
|
|
493
|
+
inspect.Parameter.VAR_KEYWORD,
|
|
494
|
+
}:
|
|
495
|
+
raise TypeError(
|
|
496
|
+
f"Tool parameter {param_name!r} uses unsupported kind "
|
|
497
|
+
f"{param.kind.description!r}"
|
|
498
|
+
)
|
|
466
499
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
property_schema = {"type": json_type}
|
|
472
|
-
|
|
473
|
-
# Add enum constraint for Literal types or Enum classes
|
|
474
|
-
enum_values = self._extract_enum_values(param_type)
|
|
475
|
-
if enum_values:
|
|
476
|
-
property_schema["enum"] = enum_values
|
|
477
|
-
|
|
478
|
-
# Add description from docstring if available
|
|
479
|
-
# (Simplified - full implementation would parse docstrings)
|
|
480
|
-
if hasattr(param, "annotation") and hasattr(
|
|
481
|
-
param.annotation, "__doc__"
|
|
482
|
-
):
|
|
483
|
-
property_schema["description"] = param.annotation.__doc__
|
|
484
|
-
|
|
485
|
-
schema["properties"][param_name] = property_schema
|
|
486
|
-
|
|
487
|
-
# Add to required if no default value
|
|
488
|
-
if param.default == inspect.Parameter.empty:
|
|
489
|
-
schema["required"].append(param_name)
|
|
490
|
-
|
|
491
|
-
return schema
|
|
492
|
-
|
|
493
|
-
def _python_type_to_json_type(self, python_type: Any) -> str:
|
|
494
|
-
"""
|
|
495
|
-
Convert Python type hints to JSON schema types.
|
|
496
|
-
|
|
497
|
-
Type mapping:
|
|
498
|
-
- str -> "string"
|
|
499
|
-
- int -> "integer"
|
|
500
|
-
- float -> "number"
|
|
501
|
-
- bool -> "boolean"
|
|
502
|
-
- list/List -> "array"
|
|
503
|
-
- dict/Dict -> "object"
|
|
504
|
-
- None/Optional -> "null"
|
|
505
|
-
- Unknown/Union -> "string" (fallback)
|
|
506
|
-
|
|
507
|
-
Args:
|
|
508
|
-
python_type: Python type annotation
|
|
509
|
-
|
|
510
|
-
Returns:
|
|
511
|
-
JSON schema type string
|
|
512
|
-
"""
|
|
513
|
-
if python_type is None or python_type is type(None):
|
|
514
|
-
return "null"
|
|
515
|
-
elif python_type is str:
|
|
516
|
-
return "string"
|
|
517
|
-
elif python_type is int:
|
|
518
|
-
return "integer"
|
|
519
|
-
elif python_type is float:
|
|
520
|
-
return "number"
|
|
521
|
-
elif python_type is bool:
|
|
522
|
-
return "boolean"
|
|
523
|
-
elif python_type is list or (
|
|
524
|
-
hasattr(python_type, "__origin__") and
|
|
525
|
-
python_type.__origin__ is list
|
|
526
|
-
):
|
|
527
|
-
return "array"
|
|
528
|
-
elif python_type is dict or (
|
|
529
|
-
hasattr(python_type, "__origin__") and
|
|
530
|
-
python_type.__origin__ is dict
|
|
531
|
-
):
|
|
532
|
-
return "object"
|
|
533
|
-
else:
|
|
534
|
-
# For Union types, complex types, etc., default to string
|
|
535
|
-
return "string"
|
|
536
|
-
|
|
537
|
-
def _extract_enum_values(self, param_type: Any) -> Optional[List[Any]]:
|
|
538
|
-
"""
|
|
539
|
-
Extract enum values from Literal types or Enum classes.
|
|
540
|
-
|
|
541
|
-
Supports:
|
|
542
|
-
- typing.Literal["a", "b", "c"]
|
|
543
|
-
- enum.Enum classes
|
|
500
|
+
annotation = self.type_hints.get(param_name, str)
|
|
501
|
+
annotation = self._with_string_description(annotation)
|
|
502
|
+
default = ... if param.default is inspect.Parameter.empty else param.default
|
|
503
|
+
fields[param_name] = (annotation, default)
|
|
544
504
|
|
|
545
|
-
|
|
546
|
-
|
|
505
|
+
model_name = f"{self.name.title().replace('_', '')}Parameters"
|
|
506
|
+
return create_model(
|
|
507
|
+
model_name,
|
|
508
|
+
__config__=ConfigDict(extra="forbid", strict=True),
|
|
509
|
+
**fields,
|
|
510
|
+
)
|
|
547
511
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
"""
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
origin = getattr(param_type, "__origin__", None)
|
|
554
|
-
|
|
555
|
-
# Check for Literal type
|
|
556
|
-
try:
|
|
557
|
-
from typing import Literal, get_args, get_origin
|
|
558
|
-
|
|
559
|
-
if get_origin(param_type) is Literal:
|
|
560
|
-
return list(get_args(param_type))
|
|
561
|
-
except (ImportError, AttributeError):
|
|
562
|
-
pass
|
|
563
|
-
|
|
564
|
-
# Fallback for older Python or typing_extensions
|
|
565
|
-
if hasattr(param_type, "__args__"):
|
|
566
|
-
type_name = str(origin) if origin else str(param_type)
|
|
567
|
-
if "Literal" in type_name:
|
|
568
|
-
return list(param_type.__args__)
|
|
569
|
-
|
|
570
|
-
# Handle Enum classes
|
|
571
|
-
try:
|
|
572
|
-
from enum import Enum
|
|
512
|
+
@staticmethod
|
|
513
|
+
def _with_string_description(annotation: Any) -> Any:
|
|
514
|
+
"""Promote string ``Annotated`` metadata to a field description."""
|
|
515
|
+
if get_origin(annotation) is not Annotated:
|
|
516
|
+
return annotation
|
|
573
517
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
518
|
+
annotated_type, *metadata = get_args(annotation)
|
|
519
|
+
has_description = any(
|
|
520
|
+
isinstance(item, FieldInfo) and item.description for item in metadata
|
|
521
|
+
)
|
|
522
|
+
description = next(
|
|
523
|
+
(item for item in metadata if isinstance(item, str) and item.strip()),
|
|
524
|
+
None,
|
|
525
|
+
)
|
|
526
|
+
if has_description or description is None:
|
|
527
|
+
return annotation
|
|
528
|
+
return Annotated[annotated_type, *metadata, Field(description=description)]
|
|
529
|
+
|
|
530
|
+
def _validate_and_convert_parameters(
|
|
531
|
+
self, parameters: Dict[str, Any]
|
|
532
|
+
) -> dict[str, Any]:
|
|
533
|
+
"""Validate JSON-compatible parameters and preserve declared types."""
|
|
534
|
+
encoded_parameters = json.dumps(parameters)
|
|
535
|
+
validated = self._parameters_model.model_validate_json(
|
|
536
|
+
encoded_parameters,
|
|
537
|
+
strict=True,
|
|
538
|
+
)
|
|
539
|
+
return {
|
|
540
|
+
name: getattr(validated, name)
|
|
541
|
+
for name in self._parameters_model.model_fields
|
|
542
|
+
}
|
|
578
543
|
|
|
579
|
-
|
|
544
|
+
@staticmethod
|
|
545
|
+
def _format_validation_error(exc: ValidationError) -> str:
|
|
546
|
+
"""Format Pydantic errors as concise tool-call feedback."""
|
|
547
|
+
details = []
|
|
548
|
+
for error in exc.errors(include_url=False, include_context=False):
|
|
549
|
+
location = ".".join(str(part) for part in error["loc"])
|
|
550
|
+
prefix = f"{location}: " if location else ""
|
|
551
|
+
details.append(f"{prefix}{error['msg']}")
|
|
552
|
+
return "Invalid parameters provided: " + "; ".join(details)
|
|
580
553
|
|
|
581
554
|
|
|
582
555
|
__all__ = ["ApprovalMode", "BaseTool", "FunctionTool"]
|
|
@@ -14,9 +14,10 @@ Run with: uv run pytest tests/tools/test_tools.py -v
|
|
|
14
14
|
"""
|
|
15
15
|
import asyncio
|
|
16
16
|
from enum import Enum
|
|
17
|
-
from typing import Literal
|
|
17
|
+
from typing import Annotated, Any, Literal
|
|
18
18
|
|
|
19
19
|
import pytest
|
|
20
|
+
from pydantic import BaseModel, Field
|
|
20
21
|
|
|
21
22
|
from agentbyte.tools import ApprovalMode, FunctionTool, tool
|
|
22
23
|
|
|
@@ -33,6 +34,19 @@ class Color(Enum):
|
|
|
33
34
|
BLUE = "blue"
|
|
34
35
|
|
|
35
36
|
|
|
37
|
+
class DocumentScope(BaseModel):
|
|
38
|
+
"""Document included in a search scope."""
|
|
39
|
+
|
|
40
|
+
internal_document_id: str
|
|
41
|
+
project_id: str | None = None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class SearchDocumentFilters(BaseModel):
|
|
45
|
+
"""Structured document search filters."""
|
|
46
|
+
|
|
47
|
+
documents: list[DocumentScope] = Field(description="Documents to search")
|
|
48
|
+
|
|
49
|
+
|
|
36
50
|
def simple_add(a: int, b: int) -> int:
|
|
37
51
|
"""Add two numbers."""
|
|
38
52
|
return a + b
|
|
@@ -221,9 +235,9 @@ class TestParameterValidation:
|
|
|
221
235
|
assert tool_instance.validate_parameters({"name": "Alice"}) is True
|
|
222
236
|
|
|
223
237
|
def test_validate_parameters_extra_params(self):
|
|
224
|
-
"""Test validation
|
|
238
|
+
"""Test validation rejects unexpected function parameters."""
|
|
225
239
|
tool_instance = FunctionTool(simple_add)
|
|
226
|
-
assert tool_instance.validate_parameters({"a": 5, "b": 3, "extra": "ignored"}) is
|
|
240
|
+
assert tool_instance.validate_parameters({"a": 5, "b": 3, "extra": "ignored"}) is False
|
|
227
241
|
|
|
228
242
|
|
|
229
243
|
# ============================================================================
|
|
@@ -406,6 +420,172 @@ class TestTypeConversion:
|
|
|
406
420
|
schema = tool_func.parameters
|
|
407
421
|
assert schema["properties"]["data"]["type"] == "object"
|
|
408
422
|
|
|
423
|
+
def test_optional_typed_collections_have_structural_schemas(self):
|
|
424
|
+
"""Optional containers retain their JSON structure and item types."""
|
|
425
|
+
@tool
|
|
426
|
+
def tool_func(
|
|
427
|
+
filters: dict[str, Any] | None = None,
|
|
428
|
+
items: list[str] | None = None,
|
|
429
|
+
identifiers: tuple[str, ...] | None = None,
|
|
430
|
+
) -> None:
|
|
431
|
+
return None
|
|
432
|
+
|
|
433
|
+
properties = tool_func.parameters["properties"]
|
|
434
|
+
assert {item["type"] for item in properties["filters"]["anyOf"]} == {
|
|
435
|
+
"object",
|
|
436
|
+
"null",
|
|
437
|
+
}
|
|
438
|
+
array_schema = next(
|
|
439
|
+
item for item in properties["items"]["anyOf"] if item["type"] == "array"
|
|
440
|
+
)
|
|
441
|
+
assert array_schema["items"] == {"type": "string"}
|
|
442
|
+
tuple_schema = next(
|
|
443
|
+
item
|
|
444
|
+
for item in properties["identifiers"]["anyOf"]
|
|
445
|
+
if item["type"] == "array"
|
|
446
|
+
)
|
|
447
|
+
assert tuple_schema["items"] == {"type": "string"}
|
|
448
|
+
|
|
449
|
+
def test_pydantic_model_schema_preserves_nested_contract(self):
|
|
450
|
+
"""Pydantic parameters publish nested fields and descriptions."""
|
|
451
|
+
@tool
|
|
452
|
+
def tool_func(
|
|
453
|
+
filters: Annotated[
|
|
454
|
+
SearchDocumentFilters | None,
|
|
455
|
+
Field(description="Optional search override"),
|
|
456
|
+
] = None,
|
|
457
|
+
) -> None:
|
|
458
|
+
return None
|
|
459
|
+
|
|
460
|
+
schema = tool_func.parameters
|
|
461
|
+
filters_schema = schema["properties"]["filters"]
|
|
462
|
+
assert filters_schema["description"] == "Optional search override"
|
|
463
|
+
assert any("$ref" in item for item in filters_schema["anyOf"])
|
|
464
|
+
model_schema = schema["$defs"]["SearchDocumentFilters"]
|
|
465
|
+
assert model_schema["type"] == "object"
|
|
466
|
+
assert model_schema["properties"]["documents"]["type"] == "array"
|
|
467
|
+
assert model_schema["properties"]["documents"]["description"] == (
|
|
468
|
+
"Documents to search"
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
def test_annotated_string_is_used_as_description(self):
|
|
472
|
+
"""String Annotated metadata becomes the parameter description."""
|
|
473
|
+
@tool
|
|
474
|
+
def tool_func(filters: Annotated[dict[str, Any], "Search scope"]) -> None:
|
|
475
|
+
return None
|
|
476
|
+
|
|
477
|
+
assert tool_func.parameters["properties"]["filters"]["description"] == (
|
|
478
|
+
"Search scope"
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
def test_builtin_annotation_docs_are_not_parameter_descriptions(self):
|
|
482
|
+
"""Schema descriptions never leak Python builtin documentation."""
|
|
483
|
+
@tool
|
|
484
|
+
def tool_func(text: str, values: list[str]) -> None:
|
|
485
|
+
return None
|
|
486
|
+
|
|
487
|
+
properties = tool_func.parameters["properties"]
|
|
488
|
+
assert "description" not in properties["text"]
|
|
489
|
+
assert "description" not in properties["values"]
|
|
490
|
+
|
|
491
|
+
@pytest.mark.asyncio
|
|
492
|
+
async def test_structured_inputs_are_converted_to_declared_runtime_types(self):
|
|
493
|
+
"""Validated objects and arrays reach the function as declared types."""
|
|
494
|
+
received: dict[str, Any] = {}
|
|
495
|
+
|
|
496
|
+
@tool
|
|
497
|
+
def tool_func(
|
|
498
|
+
filters: SearchDocumentFilters,
|
|
499
|
+
raw_filters: dict[str, Any],
|
|
500
|
+
identifiers: tuple[str, ...],
|
|
501
|
+
) -> str:
|
|
502
|
+
received.update(
|
|
503
|
+
filters=filters,
|
|
504
|
+
raw_filters=raw_filters,
|
|
505
|
+
identifiers=identifiers,
|
|
506
|
+
)
|
|
507
|
+
return "ok"
|
|
508
|
+
|
|
509
|
+
result = await tool_func.execute(
|
|
510
|
+
{
|
|
511
|
+
"filters": {
|
|
512
|
+
"documents": [{"internal_document_id": "Doc1"}],
|
|
513
|
+
},
|
|
514
|
+
"raw_filters": {"project_id": "Project1"},
|
|
515
|
+
"identifiers": ["Doc1"],
|
|
516
|
+
}
|
|
517
|
+
)
|
|
518
|
+
|
|
519
|
+
assert result.success is True
|
|
520
|
+
assert isinstance(received["filters"], SearchDocumentFilters)
|
|
521
|
+
assert isinstance(received["filters"].documents[0], DocumentScope)
|
|
522
|
+
assert isinstance(received["raw_filters"], dict)
|
|
523
|
+
assert received["identifiers"] == ("Doc1",)
|
|
524
|
+
|
|
525
|
+
@pytest.mark.asyncio
|
|
526
|
+
async def test_nested_validation_error_identifies_field_path(self):
|
|
527
|
+
"""Invalid nested model input fails before function execution."""
|
|
528
|
+
executed = False
|
|
529
|
+
|
|
530
|
+
@tool
|
|
531
|
+
def tool_func(filters: SearchDocumentFilters) -> None:
|
|
532
|
+
nonlocal executed
|
|
533
|
+
executed = True
|
|
534
|
+
|
|
535
|
+
result = await tool_func.execute({"filters": {"documents": [{}]}})
|
|
536
|
+
|
|
537
|
+
assert result.success is False
|
|
538
|
+
assert executed is False
|
|
539
|
+
assert result.error is not None
|
|
540
|
+
assert "filters.documents.0.internal_document_id" in result.error
|
|
541
|
+
assert "Field required" in result.error
|
|
542
|
+
|
|
543
|
+
@pytest.mark.asyncio
|
|
544
|
+
async def test_extra_parameter_error_is_actionable(self):
|
|
545
|
+
"""Unexpected arguments fail before invoking the function."""
|
|
546
|
+
result = await FunctionTool(simple_add).execute(
|
|
547
|
+
{"a": 1, "b": 2, "unexpected": True}
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
assert result.success is False
|
|
551
|
+
assert result.error is not None
|
|
552
|
+
assert "unexpected" in result.error
|
|
553
|
+
assert "Extra inputs are not permitted" in result.error
|
|
554
|
+
|
|
555
|
+
def test_required_nullable_parameter_remains_required(self):
|
|
556
|
+
"""Nullability does not make a parameter optional without a default."""
|
|
557
|
+
@tool
|
|
558
|
+
def tool_func(value: str | None) -> None:
|
|
559
|
+
return None
|
|
560
|
+
|
|
561
|
+
assert tool_func.parameters["required"] == ["value"]
|
|
562
|
+
assert tool_func.validate_parameters({"value": None}) is True
|
|
563
|
+
assert tool_func.validate_parameters({}) is False
|
|
564
|
+
|
|
565
|
+
def test_unsupported_annotation_fails_during_tool_construction(self):
|
|
566
|
+
"""Arbitrary classes do not silently degrade to string schemas."""
|
|
567
|
+
class Unsupported:
|
|
568
|
+
pass
|
|
569
|
+
|
|
570
|
+
def tool_func(value: Unsupported) -> None:
|
|
571
|
+
return None
|
|
572
|
+
|
|
573
|
+
with pytest.raises(TypeError, match="Unable to generate a parameter schema"):
|
|
574
|
+
FunctionTool(tool_func)
|
|
575
|
+
|
|
576
|
+
@pytest.mark.asyncio
|
|
577
|
+
async def test_function_value_error_is_not_reported_as_invalid_parameters(self):
|
|
578
|
+
"""Errors raised by valid tool calls retain their original meaning."""
|
|
579
|
+
@tool
|
|
580
|
+
def tool_func(value: int) -> None:
|
|
581
|
+
raise ValueError(f"Cannot process {value}")
|
|
582
|
+
|
|
583
|
+
result = await tool_func.execute({"value": 3})
|
|
584
|
+
|
|
585
|
+
assert result.success is False
|
|
586
|
+
assert result.error == "Cannot process 3"
|
|
587
|
+
assert result.metadata["exception_type"] == "ValueError"
|
|
588
|
+
|
|
409
589
|
|
|
410
590
|
# ============================================================================
|
|
411
591
|
# Tests: Integration
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|