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.
Files changed (299) hide show
  1. {agentbyte-0.25.0 → agentbyte-0.26.0}/CHANGELOG.md +16 -0
  2. {agentbyte-0.25.0 → agentbyte-0.26.0}/PKG-INFO +2 -2
  3. {agentbyte-0.25.0 → agentbyte-0.26.0}/README.md +1 -1
  4. agentbyte-0.26.0/src/agentbyte/__about__.py +2 -0
  5. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/tools/base.py +117 -144
  6. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/tools/test_tools.py +183 -3
  7. agentbyte-0.25.0/src/agentbyte/__about__.py +0 -2
  8. {agentbyte-0.25.0 → agentbyte-0.26.0}/.gitignore +0 -0
  9. {agentbyte-0.25.0 → agentbyte-0.26.0}/LICENSE +0 -0
  10. {agentbyte-0.25.0 → agentbyte-0.26.0}/pyproject.toml +0 -0
  11. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/__init__.py +0 -0
  12. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/agents/__init__.py +0 -0
  13. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/agents/agent.py +0 -0
  14. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/agents/agent_as_tool.py +0 -0
  15. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/agents/base.py +0 -0
  16. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/agents/embedding_agent.py +0 -0
  17. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/agents/types.py +0 -0
  18. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/cancellation_token.py +0 -0
  19. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/catalog.py +0 -0
  20. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/cli/__init__.py +0 -0
  21. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/cli/main.py +0 -0
  22. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/component.py +0 -0
  23. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/context.py +0 -0
  24. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/context_providers/__init__.py +0 -0
  25. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/context_providers/base.py +0 -0
  26. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/context_providers/skill_tools.py +0 -0
  27. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/context_providers/skills.py +0 -0
  28. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/__init__.py +0 -0
  29. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/base.py +0 -0
  30. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/config.py +0 -0
  31. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/importer.py +0 -0
  32. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/json.py +0 -0
  33. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/loader.py +0 -0
  34. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/publish.py +0 -0
  35. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/publish_config.py +0 -0
  36. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/publishers.py +0 -0
  37. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/sources.py +0 -0
  38. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/sqlite.py +0 -0
  39. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/sqlite_db.py +0 -0
  40. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/write_config.py +0 -0
  41. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/dataset/writers.py +0 -0
  42. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/entity.py +0 -0
  43. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/__init__.py +0 -0
  44. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/base.py +0 -0
  45. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/checks/__init__.py +0 -0
  46. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/checks/decorator.py +0 -0
  47. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/checks/keyword.py +0 -0
  48. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/checks/local.py +0 -0
  49. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/checks/tool.py +0 -0
  50. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/checks/types.py +0 -0
  51. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/comparison.py +0 -0
  52. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/eval_dataset.py +0 -0
  53. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/judges/__init__.py +0 -0
  54. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/judges/base.py +0 -0
  55. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/judges/composite.py +0 -0
  56. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/judges/llm.py +0 -0
  57. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/judges/pairwise.py +0 -0
  58. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/judges/reference.py +0 -0
  59. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/pairwise.py +0 -0
  60. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/report.py +0 -0
  61. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/runner.py +0 -0
  62. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/splitting.py +0 -0
  63. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/targets/__init__.py +0 -0
  64. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/targets/agent.py +0 -0
  65. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/targets/model.py +0 -0
  66. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/targets/multi_turn.py +0 -0
  67. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/targets/orchestrator.py +0 -0
  68. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/eval/types.py +0 -0
  69. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/__init__.py +0 -0
  70. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/_retry_observability.py +0 -0
  71. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/auth.py +0 -0
  72. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/azure/__init__.py +0 -0
  73. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/azure/auth.py +0 -0
  74. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/azure/chat.py +0 -0
  75. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/azure/embedding.py +0 -0
  76. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/azure/settings.py +0 -0
  77. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/azure_openai.py +0 -0
  78. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/azure_openai_embedding.py +0 -0
  79. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/base.py +0 -0
  80. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/embeddings_base.py +0 -0
  81. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/openai/__init__.py +0 -0
  82. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/openai/chat.py +0 -0
  83. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/openai/embedding.py +0 -0
  84. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/openai/settings.py +0 -0
  85. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/openai_embedding.py +0 -0
  86. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/pricing.py +0 -0
  87. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/retry_policy.py +0 -0
  88. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/settings.py +0 -0
  89. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/llm/types.py +0 -0
  90. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/logger.py +0 -0
  91. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/memory/__init__.py +0 -0
  92. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/memory/base.py +0 -0
  93. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/messages.py +0 -0
  94. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/middleware/__init__.py +0 -0
  95. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/middleware/base.py +0 -0
  96. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/middleware/otel.py +0 -0
  97. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/middleware/retry.py +0 -0
  98. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/middleware/sql_usage.py +0 -0
  99. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/middleware/usage_logger.py +0 -0
  100. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/notebook.py +0 -0
  101. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/__init__.py +0 -0
  102. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/base.py +0 -0
  103. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/config.py +0 -0
  104. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/gepa.py +0 -0
  105. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/mipro.py +0 -0
  106. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/pareto.py +0 -0
  107. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/reflective.py +0 -0
  108. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/spec.py +0 -0
  109. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/optim/trace.py +0 -0
  110. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/orchestration/__init__.py +0 -0
  111. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/orchestration/ai.py +0 -0
  112. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/orchestration/base.py +0 -0
  113. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/orchestration/handoff.py +0 -0
  114. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/orchestration/plan.py +0 -0
  115. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/orchestration/policies.py +0 -0
  116. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/orchestration/round_robin.py +0 -0
  117. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/__init__.py +0 -0
  118. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/agents.py +0 -0
  119. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/clients.py +0 -0
  120. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/instruction_registry.py +0 -0
  121. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/instructions/orchestrator.yaml +0 -0
  122. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/instructions/query_rewriter.yaml +0 -0
  123. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/instructions/researcher.yaml +0 -0
  124. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/instructions/reviewer.yaml +0 -0
  125. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/instructions/writer.yaml +0 -0
  126. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/orchestration.py +0 -0
  127. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/skills/contracts-analyst/SKILL.md +0 -0
  128. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/skills/hr-analyst/SKILL.md +0 -0
  129. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/skills/hr-analyst/resources/departments.md +0 -0
  130. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/skills/hr-analyst/resources/employees.md +0 -0
  131. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/skills/hr-analyst/resources/payroll.md +0 -0
  132. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/streaming.py +0 -0
  133. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/presets/workflow.py +0 -0
  134. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/session_store.py +0 -0
  135. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/skills/__init__.py +0 -0
  136. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/skills/base.py +0 -0
  137. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/skills/resources.py +0 -0
  138. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/skills/scripts.py +0 -0
  139. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/skills/sources.py +0 -0
  140. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/skills/validation.py +0 -0
  141. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/__init__.py +0 -0
  142. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/base.py +0 -0
  143. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/cancellation.py +0 -0
  144. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/composite.py +0 -0
  145. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/consecutive_agent.py +0 -0
  146. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/external.py +0 -0
  147. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/function_call.py +0 -0
  148. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/handoff.py +0 -0
  149. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/max_message.py +0 -0
  150. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/predicate.py +0 -0
  151. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/source.py +0 -0
  152. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/text_mention.py +0 -0
  153. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/timeout.py +0 -0
  154. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/termination/token_usage.py +0 -0
  155. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/tools/__init__.py +0 -0
  156. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/tools/coding_tools.py +0 -0
  157. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/tools/core_tools.py +0 -0
  158. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/tools/decorator.py +0 -0
  159. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/tools/memory_tool.py +0 -0
  160. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/tools/research_tools.py +0 -0
  161. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/types.py +0 -0
  162. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/__init__.py +0 -0
  163. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/discovery.py +0 -0
  164. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/execution.py +0 -0
  165. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/models.py +0 -0
  166. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/registry.py +0 -0
  167. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/server.py +0 -0
  168. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/session_store.py +0 -0
  169. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/sessions.py +0 -0
  170. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/ui/assets/index-BF3DwXaF.js +0 -0
  171. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/ui/assets/index-ar5tOeqt.css +0 -0
  172. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/ui/index.html +0 -0
  173. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/webui/ui/vite.svg +0 -0
  174. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/__init__.py +0 -0
  175. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/agent.py +0 -0
  176. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/core/__init__.py +0 -0
  177. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/core/_structure_hash.py +0 -0
  178. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/core/checkpoint.py +0 -0
  179. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/core/models.py +0 -0
  180. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/core/runner.py +0 -0
  181. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/core/workflow.py +0 -0
  182. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/defaults.py +0 -0
  183. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/loader.py +0 -0
  184. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/schema.py +0 -0
  185. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/schema_utils.py +0 -0
  186. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/steps/__init__.py +0 -0
  187. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/steps/agentbyte_agent.py +0 -0
  188. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/steps/echo.py +0 -0
  189. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/steps/function.py +0 -0
  190. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/steps/http.py +0 -0
  191. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/steps/step.py +0 -0
  192. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/steps/subworkflow.py +0 -0
  193. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/steps/transform.py +0 -0
  194. {agentbyte-0.25.0 → agentbyte-0.26.0}/src/agentbyte/workflow/visualizer.py +0 -0
  195. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_as_tool.py +0 -0
  196. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_basic.py +0 -0
  197. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_context_providers.py +0 -0
  198. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_event_types.py +0 -0
  199. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_memory_integration.py +0 -0
  200. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_middleware_integration.py +0 -0
  201. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_response_accessors.py +0 -0
  202. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_retry_middleware.py +0 -0
  203. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_agent_stream_events.py +0 -0
  204. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_embedding_agent.py +0 -0
  205. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/agents/test_tool_approval.py +0 -0
  206. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/cli/test_registry_check.py +0 -0
  207. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/context_providers/__init__.py +0 -0
  208. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/context_providers/test_skill_tools.py +0 -0
  209. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/context_providers/test_skills_provider.py +0 -0
  210. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/dataset/test_loader.py +0 -0
  211. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/dataset/test_multi_table.py +0 -0
  212. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/dataset/test_publish.py +0 -0
  213. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/dataset/test_sqlite_db.py +0 -0
  214. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/eval/test_eval_dataset.py +0 -0
  215. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/eval/test_multi_turn.py +0 -0
  216. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/eval/test_pairwise.py +0 -0
  217. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/eval/test_phase1_runner_and_targets.py +0 -0
  218. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/eval/test_phase2_checks_and_reports.py +0 -0
  219. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/eval/test_splitting.py +0 -0
  220. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/eval/test_types_and_judges.py +0 -0
  221. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/llm/test_azure_client.py +0 -0
  222. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/llm/test_azure_embedding_client.py +0 -0
  223. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/llm/test_llm_types.py +0 -0
  224. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/llm/test_openai_client.py +0 -0
  225. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/llm/test_openai_embedding_client.py +0 -0
  226. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/llm/test_pricing.py +0 -0
  227. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/llm/test_retry_observability.py +0 -0
  228. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/llm/test_retry_policy_api.py +0 -0
  229. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/memory/test_memory.py +0 -0
  230. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/middleware/test_middleware_chain.py +0 -0
  231. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/middleware/test_otel.py +0 -0
  232. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/middleware/test_retry_middleware.py +0 -0
  233. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/middleware/test_sql_usage.py +0 -0
  234. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/middleware/test_usage_logger.py +0 -0
  235. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/__init__.py +0 -0
  236. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_base.py +0 -0
  237. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_base_integration.py +0 -0
  238. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_config.py +0 -0
  239. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_gepa.py +0 -0
  240. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_mipro.py +0 -0
  241. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_pareto.py +0 -0
  242. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_reflective.py +0 -0
  243. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_spec.py +0 -0
  244. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/optim/test_trace.py +0 -0
  245. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/orchestration/test_ai_orchestrator.py +0 -0
  246. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/orchestration/test_base_orchestrator.py +0 -0
  247. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/orchestration/test_handoff_orchestrator.py +0 -0
  248. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/orchestration/test_plan_orchestrator.py +0 -0
  249. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/orchestration/test_round_robin.py +0 -0
  250. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/presets/test_agents.py +0 -0
  251. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/presets/test_clients.py +0 -0
  252. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/presets/test_instruction_registry.py +0 -0
  253. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/presets/test_orchestration.py +0 -0
  254. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/presets/test_streaming.py +0 -0
  255. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/presets/test_workflow.py +0 -0
  256. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/skills/__init__.py +0 -0
  257. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/skills/test_base.py +0 -0
  258. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/skills/test_resources.py +0 -0
  259. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/skills/test_scripts.py +0 -0
  260. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/skills/test_sources.py +0 -0
  261. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_base.py +0 -0
  262. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_cancellation.py +0 -0
  263. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_composite.py +0 -0
  264. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_consecutive_agent.py +0 -0
  265. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_external.py +0 -0
  266. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_function_call.py +0 -0
  267. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_handoff.py +0 -0
  268. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_max_message.py +0 -0
  269. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_predicate.py +0 -0
  270. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_source.py +0 -0
  271. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_text_mention.py +0 -0
  272. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_timeout.py +0 -0
  273. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/termination/test_token_usage.py +0 -0
  274. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/test_cancellation_token.py +0 -0
  275. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/test_context.py +0 -0
  276. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/test_logger.py +0 -0
  277. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/test_messages.py +0 -0
  278. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/test_package_api.py +0 -0
  279. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/test_session_store.py +0 -0
  280. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/test_types.py +0 -0
  281. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/tools/test_coding_tools.py +0 -0
  282. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/tools/test_memory_tool.py +0 -0
  283. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/tools/test_research_tools.py +0 -0
  284. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/webui/__init__.py +0 -0
  285. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/webui/helpers.py +0 -0
  286. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/webui/test_execution.py +0 -0
  287. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/webui/test_package_api.py +0 -0
  288. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/webui/test_registry.py +0 -0
  289. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/webui/test_server.py +0 -0
  290. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/webui/test_sessions.py +0 -0
  291. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_checkpoint.py +0 -0
  292. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_subworkflow_step.py +0 -0
  293. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_workflow_agent.py +0 -0
  294. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_workflow_class.py +0 -0
  295. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_workflow_models.py +0 -0
  296. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_workflow_runner.py +0 -0
  297. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_workflow_schema.py +0 -0
  298. {agentbyte-0.25.0 → agentbyte-0.26.0}/tests/workflow/test_workflow_steps.py +0 -0
  299. {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.25.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.25.0**
89
+ Current release: **0.26.0**
90
90
 
91
91
  ## Building an Agent
92
92
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Agentbyte is an observability-first agentic AI framework for building and studying multiagent systems with a learning-first, implementation-oriented workflow.
4
4
 
5
- Current release: **0.25.0**
5
+ Current release: **0.26.0**
6
6
 
7
7
  ## Building an Agent
8
8
 
@@ -0,0 +1,2 @@
1
+ __version__ = "0.26.0"
2
+ VERSION = __version__
@@ -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 Any, Callable, Dict, List, Optional, Union, get_type_hints
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
- self.type_hints = get_type_hints(func)
371
- self._parameters_schema = self._build_parameters_schema()
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
- # Validate parameters before execution
409
- if not self.validate_parameters(parameters):
410
- return ToolResult(
411
- success=False,
412
- result=None,
413
- error="Invalid parameters provided",
414
- metadata={"tool_name": self.name},
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(**parameters)
454
+ result = await self.func(**validated_parameters)
420
455
  else:
421
- result = self.func(**parameters)
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 _build_parameters_schema(self) -> Dict[str, Any]:
442
- """
443
- Build JSON schema from function signature and type hints.
444
-
445
- This is the core schema generation logic that converts Python
446
- type hints into JSON Schema format for LLMs. It:
447
- 1. Iterates through function parameters
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
- # Get parameter type from type hints
468
- param_type = self.type_hints.get(param_name)
469
- json_type = self._python_type_to_json_type(param_type)
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
- Args:
546
- param_type: Python type annotation
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
- Returns:
549
- List of enum values or None
550
- """
551
- # Handle typing.Literal (Python 3.8+)
552
- if hasattr(param_type, "__origin__"):
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
- if isinstance(param_type, type) and issubclass(param_type, Enum):
575
- return [e.value for e in param_type]
576
- except (TypeError, AttributeError):
577
- pass
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
- return None
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 with extra parameters (should still pass)."""
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 True
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
@@ -1,2 +0,0 @@
1
- __version__ = "0.25.0"
2
- VERSION = __version__
File without changes
File without changes
File without changes