autobyteus 1.0.4__tar.gz → 1.0.5__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 (171) hide show
  1. {autobyteus-1.0.4 → autobyteus-1.0.5}/PKG-INFO +1 -1
  2. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/agent.py +1 -1
  3. autobyteus-1.0.5/autobyteus/agent/factory/agent_factory.py +94 -0
  4. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/message/send_message_to.py +0 -3
  5. autobyteus-1.0.5/autobyteus/agent/registry/__init__.py +11 -0
  6. autobyteus-1.0.5/autobyteus/agent/registry/agent_definition.py +94 -0
  7. autobyteus-1.0.5/autobyteus/agent/registry/agent_registry.py +114 -0
  8. autobyteus-1.0.5/autobyteus/agent/remote_agent.py +9 -0
  9. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/autobyteus_provider.py +2 -1
  10. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/llm_factory.py +33 -13
  11. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/models.py +12 -0
  12. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/ollama_provider.py +1 -0
  13. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/ask_user_input.py +8 -19
  14. autobyteus-1.0.5/autobyteus/tools/base_tool.py +77 -0
  15. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/bash/bash_executor.py +3 -15
  16. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +8 -4
  17. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +12 -55
  18. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +9 -5
  19. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +8 -4
  20. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/standalone/google_search_ui.py +6 -32
  21. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/standalone/navigate_to.py +8 -16
  22. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/standalone/webpage_image_downloader.py +9 -60
  23. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/standalone/webpage_reader.py +8 -6
  24. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +9 -6
  25. autobyteus-1.0.5/autobyteus/tools/factory/tool_factory.py +10 -0
  26. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/file/file_reader.py +6 -8
  27. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/file/file_writer.py +6 -9
  28. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/image_downloader.py +18 -41
  29. autobyteus-1.0.5/autobyteus/tools/mcp_remote_tool.py +82 -0
  30. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/pdf_downloader.py +8 -13
  31. autobyteus-1.0.5/autobyteus/tools/registry/__init__.py +11 -0
  32. autobyteus-1.0.5/autobyteus/tools/registry/tool_definition.py +60 -0
  33. autobyteus-1.0.5/autobyteus/tools/registry/tool_registry.py +106 -0
  34. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/timer.py +16 -18
  35. autobyteus-1.0.5/autobyteus/tools/tool_meta.py +52 -0
  36. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/utils.py +1 -1
  37. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/web_page_pdf_generator.py +8 -4
  38. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus.egg-info/PKG-INFO +1 -1
  39. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus.egg-info/SOURCES.txt +10 -0
  40. {autobyteus-1.0.4 → autobyteus-1.0.5}/setup.py +1 -1
  41. autobyteus-1.0.4/autobyteus/tools/base_tool.py +0 -49
  42. autobyteus-1.0.4/autobyteus/tools/factory/tool_factory.py +0 -8
  43. {autobyteus-1.0.4 → autobyteus-1.0.5}/LICENSE +0 -0
  44. {autobyteus-1.0.4 → autobyteus-1.0.5}/README.md +0 -0
  45. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/__init__.py +0 -0
  46. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/__init__.py +0 -0
  47. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/async_agent.py +0 -0
  48. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/async_group_aware_agent.py +0 -0
  49. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/exceptions.py +0 -0
  50. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/factory/__init__.py +0 -0
  51. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/group/__init__.py +0 -0
  52. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/group/async_group_aware_agent.py +0 -0
  53. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/group/coordinator_agent.py +0 -0
  54. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/group/group_aware_agent.py +0 -0
  55. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/message/__init__.py +0 -0
  56. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/message/message.py +0 -0
  57. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/message/message_types.py +0 -0
  58. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/orchestrator/__init__.py +0 -0
  59. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/orchestrator/base_agent_orchestrator.py +0 -0
  60. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/orchestrator/multi_replica_agent_orchestrator.py +0 -0
  61. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/orchestrator/single_replica_agent_orchestrator.py +0 -0
  62. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/response_parser/__init__.py +0 -0
  63. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/response_parser/tool_usage_command_parser.py +0 -0
  64. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/status.py +0 -0
  65. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/agent/tool_invocation.py +0 -0
  66. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/check_requirements.py +0 -0
  67. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/conversation/__init__.py +0 -0
  68. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/conversation/conversation.py +0 -0
  69. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/conversation/user_message.py +0 -0
  70. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/events/__init__.py +0 -0
  71. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/events/decorators.py +0 -0
  72. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/events/event_emitter.py +0 -0
  73. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/events/event_manager.py +0 -0
  74. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/events/event_types.py +0 -0
  75. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/__init__.py +0 -0
  76. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/api/__init__.py +0 -0
  77. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/api/autobyteus_llm.py +0 -0
  78. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/api/bedrock_llm.py +0 -0
  79. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/api/claude_llm.py +0 -0
  80. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/api/deepseek_llm.py +0 -0
  81. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/api/gemini_llm.py +0 -0
  82. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/api/grok_llm.py +0 -0
  83. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/api/groq_llm.py +0 -0
  84. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/api/mistral_llm.py +0 -0
  85. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/api/nvidia_llm.py +0 -0
  86. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/api/ollama_llm.py +0 -0
  87. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/api/openai_llm.py +0 -0
  88. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/base_llm.py +0 -0
  89. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/extensions/__init__.py +0 -0
  90. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/extensions/base_extension.py +0 -0
  91. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/extensions/extension_registry.py +0 -0
  92. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/extensions/token_usage_tracking_extension.py +0 -0
  93. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/providers.py +0 -0
  94. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/token_counter/__init__.py +0 -0
  95. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/token_counter/base_token_counter.py +0 -0
  96. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/token_counter/claude_token_counter.py +0 -0
  97. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/token_counter/deepseek_token_counter.py +0 -0
  98. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/token_counter/mistral_token_counter.py +0 -0
  99. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/token_counter/openai_token_counter.py +0 -0
  100. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/token_counter/token_counter_factory.py +0 -0
  101. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/utils/__init__.py +0 -0
  102. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/utils/image_payload_formatter.py +0 -0
  103. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/utils/llm_config.py +0 -0
  104. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/utils/messages.py +0 -0
  105. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/utils/rate_limiter.py +0 -0
  106. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/utils/response_types.py +0 -0
  107. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/utils/token_pricing_config.py +0 -0
  108. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/utils/token_usage.py +0 -0
  109. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/llm/utils/token_usage_tracker.py +0 -0
  110. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/person/__init__.py +0 -0
  111. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/person/examples/__init__.py +0 -0
  112. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/person/examples/sample_persons.py +0 -0
  113. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/person/examples/sample_roles.py +0 -0
  114. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/person/person.py +0 -0
  115. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/person/role.py +0 -0
  116. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/prompt/__init__.py +0 -0
  117. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/prompt/prompt_builder.py +0 -0
  118. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/prompt/prompt_template.py +0 -0
  119. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/prompt/prompt_version_manager.py +0 -0
  120. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/prompt/storage/__init__.py +0 -0
  121. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/prompt/storage/prompt_version_model.py +0 -0
  122. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/prompt/storage/prompt_version_repository.py +0 -0
  123. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/__init__.py +0 -0
  124. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/bash/__init__.py +0 -0
  125. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/bash/factory/__init__.py +0 -0
  126. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/bash/factory/bash_executor_factory.py +0 -0
  127. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/__init__.py +0 -0
  128. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/session_aware/__init__.py +0 -0
  129. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/session_aware/browser_session_aware_tool.py +0 -0
  130. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/session_aware/factory/__init__.py +0 -0
  131. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/session_aware/factory/browser_session_aware_web_element_trigger_factory.py +0 -0
  132. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_reader_factory.py +0 -0
  133. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_screenshot_taker_factory.py +0 -0
  134. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/session_aware/shared_browser_session.py +0 -0
  135. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/session_aware/shared_browser_session_manager.py +0 -0
  136. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/session_aware/web_element_action.py +0 -0
  137. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/standalone/__init__.py +0 -0
  138. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/standalone/factory/__init__.py +0 -0
  139. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/standalone/factory/google_search_factory.py +0 -0
  140. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/standalone/factory/webpage_reader_factory.py +0 -0
  141. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/browser/standalone/factory/webpage_screenshot_taker_factory.py +0 -0
  142. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/factory/__init__.py +0 -0
  143. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/factory/ask_user_input_factory.py +0 -0
  144. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/factory/image_downloader_factory.py +0 -0
  145. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/factory/pdf_downloader_factory.py +0 -0
  146. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/factory/webpage_image_downloader_factory.py +0 -0
  147. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/file/__init__.py +0 -0
  148. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/file/factory/__init__.py +0 -0
  149. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/file/factory/file_reader_factory.py +0 -0
  150. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/file/factory/file_writer_factory.py +0 -0
  151. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/handlers/__init__.py +0 -0
  152. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/handlers/shell_handler.py +0 -0
  153. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/operation/__init__.py +0 -0
  154. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/operation/file_operation.py +0 -0
  155. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/operation/file_rename_operation.py +0 -0
  156. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/operation/operation.py +0 -0
  157. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/tools/operation/shell_operation.py +0 -0
  158. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/utils/__init__.py +0 -0
  159. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/utils/dynamic_enum.py +0 -0
  160. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/utils/file_utils.py +0 -0
  161. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/utils/html_cleaner.py +0 -0
  162. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/utils/singleton.py +0 -0
  163. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/workflow/__init__.py +0 -0
  164. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/workflow/simple_task.py +0 -0
  165. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/workflow/task.py +0 -0
  166. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus/workflow/workflow.py +0 -0
  167. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus.egg-info/dependency_links.txt +0 -0
  168. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus.egg-info/requires.txt +0 -0
  169. {autobyteus-1.0.4 → autobyteus-1.0.5}/autobyteus.egg-info/top_level.txt +0 -0
  170. {autobyteus-1.0.4 → autobyteus-1.0.5}/pyproject.toml +0 -0
  171. {autobyteus-1.0.4 → autobyteus-1.0.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autobyteus
3
- Version: 1.0.4
3
+ Version: 1.0.5
4
4
  Summary: Multi-Agent framework
5
5
  Home-page: https://github.com/AutoByteus/autobyteus
6
6
  Author: Ryan Zheng
@@ -223,7 +223,7 @@ class Agent(EventEmitter):
223
223
 
224
224
  external_tools_section = ""
225
225
  for i, tool in enumerate(self.tools):
226
- external_tools_section += f" {i + 1} {tool.tool_usage_xml()}\n\n"
226
+ external_tools_section += f" {i + 1} {tool.tool_usage()}\n\n"
227
227
  return external_tools_section.strip()
228
228
 
229
229
  def on_task_completed(self, *args, **kwargs):
@@ -0,0 +1,94 @@
1
+ # file: autobyteus/agent/factory/agent_factory.py
2
+ import logging
3
+ from autobyteus.agent.agent import Agent
4
+ from autobyteus.agent.group.group_aware_agent import GroupAwareAgent
5
+ from autobyteus.llm.llm_factory import LLMFactory
6
+ from autobyteus.tools.factory.tool_factory import ToolFactory
7
+ from autobyteus.prompt.prompt_builder import PromptBuilder
8
+ from autobyteus.llm.models import LLMModel
9
+ from typing import List, Union
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ class AgentFactory:
14
+ """
15
+ Factory class for creating different types of agents.
16
+
17
+ This factory simplifies the creation of Agent instances by encapsulating
18
+ the necessary dependencies and configurations.
19
+ """
20
+ def __init__(self,
21
+ role: str,
22
+ agent_type: str,
23
+ tool_factory: ToolFactory,
24
+ llm_factory: LLMFactory,
25
+ prompt_builder: PromptBuilder, # Agent requires prompt_builder or initial_user_message
26
+ llm_model: LLMModel,
27
+ tool_names: List[str]):
28
+ """
29
+ Initializes the AgentFactory.
30
+
31
+ Args:
32
+ role: The role the created agents will fulfill.
33
+ agent_type: The type of agent to create ("standalone" or "group_aware").
34
+ tool_factory: A factory to create tool instances.
35
+ llm_factory: A factory to create LLM instances.
36
+ prompt_builder: The PromptBuilder instance to configure the agent's system prompt.
37
+ llm_model: The specific LLM model configuration to use.
38
+ tool_names: A list of tool names the agent should be equipped with.
39
+ """
40
+ self.role = role
41
+ self.agent_type = agent_type
42
+ self.tool_factory = tool_factory
43
+ self.llm_factory = llm_factory
44
+ self.prompt_builder = prompt_builder
45
+ self.llm_model = llm_model
46
+ self.tool_names = tool_names
47
+ logger.info(f"AgentFactory initialized for role '{role}' and type '{agent_type}'")
48
+
49
+ def create_agent(self, agent_id: str) -> Union[Agent, GroupAwareAgent]:
50
+ """
51
+ Creates an agent instance based on the factory's configuration.
52
+
53
+ Args:
54
+ agent_id: The unique identifier for the agent being created.
55
+
56
+ Returns:
57
+ An instance of Agent or GroupAwareAgent.
58
+
59
+ Raises:
60
+ ValueError: If the configured agent_type is unsupported.
61
+ """
62
+ logger.info(f"Creating agent with id '{agent_id}' for role '{self.role}' and type '{self.agent_type}'")
63
+ try:
64
+ tools = [self.tool_factory.create_tool(name) for name in self.tool_names]
65
+ logger.debug(f"Tools created for agent '{agent_id}': {[tool.get_name() for tool in tools]}")
66
+ except Exception as e:
67
+ logger.error(f"Error creating tools for agent '{agent_id}': {e}")
68
+ raise ValueError(f"Failed to create tools for agent {agent_id}: {e}") from e
69
+
70
+ try:
71
+ llm = self.llm_factory.create_llm(self.llm_model)
72
+ logger.debug(f"LLM instance created for agent '{agent_id}' using model '{self.llm_model.model_name}'")
73
+ except Exception as e:
74
+ logger.error(f"Error creating LLM for agent '{agent_id}': {e}")
75
+ raise ValueError(f"Failed to create LLM for agent {agent_id}: {e}") from e
76
+
77
+ agent_args = {
78
+ "agent_id": agent_id,
79
+ "role": self.role,
80
+ "prompt_builder": self.prompt_builder,
81
+ "llm": llm,
82
+ "tools": tools
83
+ }
84
+
85
+ if self.agent_type == "standalone":
86
+ logger.debug(f"Instantiating Agent with args: {agent_args}")
87
+ return Agent(**agent_args)
88
+ elif self.agent_type == "group_aware":
89
+ logger.debug(f"Instantiating GroupAwareAgent with args: {agent_args}")
90
+ return GroupAwareAgent(**agent_args)
91
+ else:
92
+ logger.error(f"Unsupported agent type specified in factory: {self.agent_type}")
93
+ raise ValueError(f"Unsupported agent type: {self.agent_type}")
94
+
@@ -18,9 +18,6 @@ class SendMessageTo(BaseTool):
18
18
  except ValueError as e:
19
19
  return f"Error: {str(e)}"
20
20
 
21
- def tool_usage(self) -> str:
22
- return self.tool_usage_xml()
23
-
24
21
  def tool_usage_xml(self) -> str:
25
22
  return '''SendMessageTo: Sends a message to another agent in the group. Usage:
26
23
  <command name="SendMessageTo">
@@ -0,0 +1,11 @@
1
+ # file: autobyteus/autobyteus/agent/registry/__init__.py
2
+ from .agent_definition import AgentDefinition
3
+ from .agent_registry import AgentRegistry, default_agent_registry
4
+ from autobyteus.agent.factory.agent_factory import AgentFactory
5
+
6
+ __all__ = [
7
+ "AgentDefinition",
8
+ "AgentRegistry",
9
+ "default_agent_registry",
10
+ "AgentFactory"
11
+ ]
@@ -0,0 +1,94 @@
1
+ import logging
2
+ from typing import Dict, List, Any, Optional
3
+
4
+ logger = logging.getLogger(__name__)
5
+
6
+ class AgentDefinition:
7
+ """
8
+ Represents the static definition of an agent, containing its role, description,
9
+ tools, optional system prompt, and optional initial user message.
10
+ """
11
+ def __init__(self,
12
+ role: str,
13
+ description: str,
14
+ tools: List[str],
15
+ system_prompt: Optional[str] = None,
16
+ initial_user_message: Optional[str] = None):
17
+ """
18
+ Initializes the AgentDefinition.
19
+
20
+ Args:
21
+ role: The unique role identifier of the agent (e.g., 'coordinator', 'worker').
22
+ description: A human-readable description of the agent's purpose.
23
+ tools: A list of tool names the agent can use.
24
+ system_prompt: An optional system prompt to configure the LLM's behavior.
25
+ initial_user_message: An optional initial user message to start the agent's conversation.
26
+
27
+ Raises:
28
+ ValueError: If role, description, or tools are invalid, or if system_prompt or
29
+ initial_user_message are not strings when provided.
30
+ """
31
+ if not role or not isinstance(role, str):
32
+ raise ValueError("AgentDefinition requires a non-empty string 'role'.")
33
+ if not description or not isinstance(description, str):
34
+ raise ValueError(f"AgentDefinition '{role}' requires a non-empty string 'description'.")
35
+ if not isinstance(tools, list) or not all(isinstance(t, str) and t for t in tools):
36
+ raise ValueError(f"AgentDefinition '{role}' requires a non-empty list of tool name strings.")
37
+ if system_prompt is not None and not isinstance(system_prompt, str):
38
+ raise ValueError(f"AgentDefinition '{role}' system_prompt must be a string or None.")
39
+ if initial_user_message is not None and not isinstance(initial_user_message, str):
40
+ raise ValueError(f"AgentDefinition '{role}' initial_user_message must be a string or None.")
41
+
42
+ self._role = role
43
+ self._description = description
44
+ self._tools = tools
45
+ self._system_prompt = system_prompt
46
+ self._initial_user_message = initial_user_message
47
+
48
+ logger.debug(f"AgentDefinition created for role '{self.role}'.")
49
+
50
+ @property
51
+ def role(self) -> str:
52
+ """The unique role identifier of the agent."""
53
+ return self._role
54
+
55
+ @property
56
+ def description(self) -> str:
57
+ """The human-readable description of the agent's purpose."""
58
+ return self._description
59
+
60
+ @property
61
+ def tools(self) -> List[str]:
62
+ """The list of tool names the agent can use."""
63
+ return self._tools
64
+
65
+ @property
66
+ def system_prompt(self) -> Optional[str]:
67
+ """The optional system prompt for the agent."""
68
+ return self._system_prompt
69
+
70
+ @property
71
+ def initial_user_message(self) -> Optional[str]:
72
+ """The optional initial user message for the agent."""
73
+ return self._initial_user_message
74
+
75
+ def __repr__(self) -> str:
76
+ """Provides a developer-friendly string representation."""
77
+ desc_repr = self.description
78
+ if len(desc_repr) > 70:
79
+ desc_repr = desc_repr[:67] + "..."
80
+ # Remove newlines/tabs for cleaner logging
81
+ desc_repr = desc_repr.replace('\n', '\\n').replace('\t', '\\t')
82
+ return (f"AgentDefinition(role='{self.role}', description='{desc_repr}', "
83
+ f"tools={self.tools}, system_prompt='{self.system_prompt}', "
84
+ f"initial_user_message='{self.initial_user_message}')")
85
+
86
+ def to_dict(self) -> Dict[str, Any]:
87
+ """Returns a dictionary representation of the agent definition."""
88
+ return {
89
+ "role": self.role,
90
+ "description": self.description,
91
+ "tools": self.tools,
92
+ "system_prompt": self.system_prompt,
93
+ "initial_user_message": self.initial_user_message
94
+ }
@@ -0,0 +1,114 @@
1
+ # file: autobyteus/autobyteus/agent/registry/agent_registry.py
2
+ import logging
3
+ from typing import Dict, List, Optional
4
+
5
+ from autobyteus.utils.singleton import SingletonMeta
6
+ from autobyteus.agent.factory.agent_factory import AgentFactory
7
+ from .agent_definition import AgentDefinition
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ class AgentRegistry(metaclass=SingletonMeta):
12
+ """
13
+ Manages AgentDefinitions (role, description, tools, initial_user_message, agent_class),
14
+ populated exclusively via programmatic registration. Uses AgentFactory to create agent instances.
15
+ """
16
+ _definitions: Dict[str, AgentDefinition] = {}
17
+
18
+ def __init__(self, agent_factory: AgentFactory):
19
+ """
20
+ Initializes the AgentRegistry with an AgentFactory.
21
+
22
+ Args:
23
+ agent_factory: The AgentFactory instance used to create agent instances.
24
+ """
25
+ self.agent_factory = agent_factory
26
+ logger.info("AgentRegistry initialized with AgentFactory.")
27
+
28
+ def register_agent(self, definition: AgentDefinition):
29
+ """
30
+ Registers an agent definition (role, description, tools, initial_user_message, agent_class) programmatically.
31
+
32
+ Args:
33
+ definition: The AgentDefinition object to register.
34
+
35
+ Raises:
36
+ ValueError: If the definition is invalid. Overwrites existing definitions with the same role.
37
+ """
38
+ if not isinstance(definition, AgentDefinition):
39
+ raise ValueError("Attempted to register an object that is not an AgentDefinition.")
40
+
41
+ role = definition.role
42
+ if role in self._definitions:
43
+ logger.warning(f"Overwriting existing agent definition for role: '{role}'")
44
+ AgentRegistry._definitions[role] = definition
45
+ logger.info(f"Successfully registered agent definition: '{role}'")
46
+
47
+ def get_agent_definition(self, role: str) -> Optional[AgentDefinition]:
48
+ """
49
+ Retrieves the definition for a specific agent role.
50
+
51
+ Args:
52
+ role: The unique role of the agent definition to retrieve.
53
+
54
+ Returns:
55
+ The AgentDefinition object if found, otherwise None.
56
+ """
57
+ definition = self._definitions.get(role)
58
+ if not definition:
59
+ logger.debug(f"Agent definition not found for role: '{role}'")
60
+ return definition
61
+
62
+ def create_agent(self, role: str, agent_id: str):
63
+ """
64
+ Creates an agent instance using the AgentFactory based on the agent definition.
65
+
66
+ Args:
67
+ role: The role of the agent to create.
68
+ agent_id: The unique identifier for the agent instance.
69
+
70
+ Returns:
71
+ The agent instance if the definition exists, otherwise None.
72
+
73
+ Raises:
74
+ ValueError: If the agent definition is not found.
75
+ """
76
+ definition = self.get_agent_definition(role)
77
+ if not definition:
78
+ logger.error(f"Cannot create agent: No definition found for role '{role}'")
79
+ raise ValueError(f"No agent definition found for role '{role}'")
80
+
81
+ logger.info(f"Creating agent instance for role '{role}' with id '{agent_id}' using AgentFactory")
82
+ return self.agent_factory.create_agent(agent_id)
83
+
84
+ def list_agents(self) -> List[AgentDefinition]:
85
+ """
86
+ Returns a list of all registered agent definitions.
87
+
88
+ Returns:
89
+ A list of AgentDefinition objects.
90
+ """
91
+ return list(self._definitions.values())
92
+
93
+ def list_agent_roles(self) -> List[str]:
94
+ """
95
+ Returns a list of the roles of all registered agents.
96
+
97
+ Returns:
98
+ A list of agent role strings.
99
+ """
100
+ return list(self._definitions.keys())
101
+
102
+ def get_all_definitions(self) -> Dict[str, AgentDefinition]:
103
+ """Returns the internal dictionary of definitions."""
104
+ return dict(AgentRegistry._definitions)
105
+
106
+ default_agent_registry = AgentRegistry(agent_factory=AgentFactory(
107
+ role="default",
108
+ agent_type="group_aware",
109
+ tool_factory=ToolFactory(),
110
+ llm_factory=LLMFactory(),
111
+ prompt_builder=PromptBuilder(),
112
+ llm_model=LLMModel(),
113
+ tool_names=[]
114
+ ))
@@ -0,0 +1,9 @@
1
+ # file: autobyteus/autobyteus/agent/remote_agent.py
2
+ from autobyteus.agent.agent import Agent
3
+
4
+ class RemoteAgent(Agent):
5
+ """
6
+ A placeholder class for remote agents that will interact with external systems
7
+ (e.g., via MCP or HTTP protocols). To be implemented in the future.
8
+ """
9
+ pass
@@ -56,12 +56,13 @@ class AutobyteusModelProvider:
56
56
  value=model_info["value"],
57
57
  provider=LLMProvider(model_info["provider"]), # Convert string to enum
58
58
  llm_class=AutobyteusLLM,
59
+ canonical_name=model_info["canonical_name"], # Add canonical_name
59
60
  default_config=llm_config
60
61
  )
61
62
 
62
63
  LLMFactory.register_model(llm_model)
63
64
  registered_count += 1
64
- logger.debug(f"Registered model: {model_info['name']}")
65
+ logger.debug(f"Registered model: {model_info['name']} with canonical name: {model_info['canonical_name']}")
65
66
 
66
67
  except Exception as e:
67
68
  logger.error(f"Model registration failed: {str(e)}")
@@ -98,6 +98,7 @@ class LLMFactory:
98
98
  value="gpt-4o",
99
99
  provider=LLMProvider.OPENAI,
100
100
  llm_class=OpenAILLM,
101
+ canonical_name="gpt-4o",
101
102
  default_config=LLMConfig(
102
103
  rate_limit=40,
103
104
  token_limit=8192,
@@ -105,38 +106,32 @@ class LLMFactory:
105
106
  )
106
107
  ),
107
108
  LLMModel(
108
- name="o1_API",
109
- value="o1",
109
+ name="o3_API",
110
+ value="o3",
110
111
  provider=LLMProvider.OPENAI,
111
112
  llm_class=OpenAILLM,
113
+ canonical_name="o3",
112
114
  default_config=LLMConfig(
113
115
  pricing_config=TokenPricingConfig(15.00, 60.00)
114
116
  )
115
117
  ),
116
118
  LLMModel(
117
- name="o1_MINI_API",
118
- value="o3-mini",
119
+ name="o4_MINI_API",
120
+ value="o4-mini",
119
121
  provider=LLMProvider.OPENAI,
120
122
  llm_class=OpenAILLM,
123
+ canonical_name="o4-mini",
121
124
  default_config=LLMConfig(
122
125
  pricing_config=TokenPricingConfig(1.0, 4.00)
123
126
  )
124
127
  ),
125
- LLMModel(
126
- name="GPT_3_5_TURBO_API",
127
- value="gpt-3.5-turbo",
128
- provider=LLMProvider.OPENAI,
129
- llm_class=OpenAILLM,
130
- default_config=LLMConfig(
131
- pricing_config=TokenPricingConfig(1.50, 2.00)
132
- )
133
- ),
134
128
  # MISTRAL Provider Models
135
129
  LLMModel(
136
130
  name="MISTRAL_LARGE_API",
137
131
  value="mistral-large-latest",
138
132
  provider=LLMProvider.MISTRAL,
139
133
  llm_class=MistralLLM,
134
+ canonical_name="mistral-large",
140
135
  default_config=LLMConfig(
141
136
  pricing_config=TokenPricingConfig(2.00, 6.00)
142
137
  )
@@ -147,6 +142,7 @@ class LLMFactory:
147
142
  value="claude-3-7-sonnet-20250219",
148
143
  provider=LLMProvider.ANTHROPIC,
149
144
  llm_class=ClaudeLLM,
145
+ canonical_name="claude-3.7",
150
146
  default_config=LLMConfig(
151
147
  pricing_config=TokenPricingConfig(3.00, 15.00)
152
148
  )
@@ -156,6 +152,7 @@ class LLMFactory:
156
152
  value="anthropic.claude-3-7-sonnet-20250219-v1:0",
157
153
  provider=LLMProvider.ANTHROPIC,
158
154
  llm_class=ClaudeLLM,
155
+ canonical_name="claude-3.7",
159
156
  default_config=LLMConfig(
160
157
  pricing_config=TokenPricingConfig(3.00, 15.00)
161
158
  )
@@ -166,6 +163,7 @@ class LLMFactory:
166
163
  value="deepseek-chat",
167
164
  provider=LLMProvider.DEEPSEEK,
168
165
  llm_class=DeepSeekLLM,
166
+ canonical_name="deepseek-chat",
169
167
  default_config=LLMConfig(
170
168
  rate_limit=60,
171
169
  token_limit=8000,
@@ -178,6 +176,7 @@ class LLMFactory:
178
176
  value="deepseek-reasoner",
179
177
  provider=LLMProvider.DEEPSEEK,
180
178
  llm_class=DeepSeekLLM,
179
+ canonical_name="deepseek-reasoner",
181
180
  default_config=LLMConfig(
182
181
  rate_limit=60,
183
182
  token_limit=8000,
@@ -190,6 +189,7 @@ class LLMFactory:
190
189
  value="gemini-1-5-pro",
191
190
  provider=LLMProvider.GEMINI,
192
191
  llm_class=OpenAILLM,
192
+ canonical_name="gemini-1.5-pro",
193
193
  default_config=LLMConfig(
194
194
  pricing_config=TokenPricingConfig(1.25, 5.00)
195
195
  )
@@ -199,6 +199,7 @@ class LLMFactory:
199
199
  value="gemini-1-5-flash",
200
200
  provider=LLMProvider.GEMINI,
201
201
  llm_class=OpenAILLM,
202
+ canonical_name="gemini-1.5-flash",
202
203
  default_config=LLMConfig(
203
204
  pricing_config=TokenPricingConfig(0.075, 0.30)
204
205
  )
@@ -209,6 +210,7 @@ class LLMFactory:
209
210
  value="grok-2-1212",
210
211
  provider=LLMProvider.GROK,
211
212
  llm_class=GrokLLM,
213
+ canonical_name="grok-2",
212
214
  default_config=LLMConfig(
213
215
  rate_limit=60,
214
216
  token_limit=8000,
@@ -290,3 +292,21 @@ class LLMFactory:
290
292
  """
291
293
  LLMFactory.ensure_initialized()
292
294
  return LLMFactory._models_by_provider.get(provider, [])
295
+
296
+ @staticmethod
297
+ def get_canonical_name(model_name: str) -> Optional[str]:
298
+ """
299
+ Get the canonical name for a model by its name.
300
+
301
+ Args:
302
+ model_name (str): The model name (e.g., "GPT_4o_API")
303
+
304
+ Returns:
305
+ Optional[str]: The canonical name if found, None otherwise
306
+ """
307
+ LLMFactory.ensure_initialized()
308
+ for models in LLMFactory._models_by_provider.values():
309
+ for model_instance in models:
310
+ if model_instance.name == model_name:
311
+ return model_instance.canonical_name
312
+ return None
@@ -13,6 +13,7 @@ class LLMModel:
13
13
  Represents a single model's metadata:
14
14
  - name (str): A human-readable label, e.g. "GPT-4 Official"
15
15
  - value (str): A unique identifier used in code or APIs, e.g. "gpt-4o"
16
+ - canonical_name (str): A shorter, standardized reference name for prompts, e.g. "gpt-4o" or "claude-3.7"
16
17
  - provider (LLMProvider): The provider enum
17
18
  - llm_class (Type[BaseLLM]): Which Python class to instantiate
18
19
  - default_config (LLMConfig): Default configuration (token limit, etc.)
@@ -26,6 +27,7 @@ class LLMModel:
26
27
  value: str,
27
28
  provider: LLMProvider,
28
29
  llm_class: Type["BaseLLM"],
30
+ canonical_name: str,
29
31
  default_config: Optional[LLMConfig] = None
30
32
  ):
31
33
  # Validate name doesn't already exist as a class attribute
@@ -36,6 +38,7 @@ class LLMModel:
36
38
 
37
39
  self._name = name
38
40
  self._value = value
41
+ self._canonical_name = canonical_name
39
42
  self.provider = provider
40
43
  self.llm_class = llm_class
41
44
  self.default_config = default_config if default_config else LLMConfig()
@@ -58,6 +61,14 @@ class LLMModel:
58
61
  """
59
62
  return self._value
60
63
 
64
+ @property
65
+ def canonical_name(self) -> str:
66
+ """
67
+ A standardized, shorter reference name for this model.
68
+ Useful for prompt engineering and cross-referencing similar models.
69
+ """
70
+ return self._canonical_name
71
+
61
72
  def create_llm(self, custom_config: Optional[LLMConfig] = None) -> "BaseLLM":
62
73
  """
63
74
  Instantiate the LLM class for this model, applying
@@ -69,5 +80,6 @@ class LLMModel:
69
80
  def __repr__(self):
70
81
  return (
71
82
  f"LLMModel(name='{self._name}', value='{self._value}', "
83
+ f"canonical_name='{self._canonical_name}', "
72
84
  f"provider='{self.provider.name}', llm_class='{self.llm_class.__name__}')"
73
85
  )
@@ -79,6 +79,7 @@ class OllamaModelProvider:
79
79
  value=model_name,
80
80
  provider=LLMProvider.OLLAMA,
81
81
  llm_class=OllamaLLM,
82
+ canonical_name=model_name, # Use model_name as the canonical_name
82
83
  default_config=LLMConfig(
83
84
  rate_limit=60,
84
85
  token_limit=8192,
@@ -12,27 +12,16 @@ class AskUserInput(BaseTool):
12
12
  super().__init__()
13
13
  self.logger = logging.getLogger(__name__)
14
14
 
15
- def tool_usage(self):
15
+ @classmethod
16
+ def tool_usage_xml(cls):
16
17
  """
17
- Return a string describing the usage of the AskUserInput tool.
18
+ Return an XML string describing the usage of the AskUserInput tool.
19
+
20
+ Returns:
21
+ str: An XML description of how to use the AskUserInput tool.
18
22
  """
19
- return '''AskUserInput: Requests input from the user based on LLM's prompt.
20
- Usage: <<<AskUserInput(request="[Your request here]")>>>
21
-
22
- Examples:
23
- 1. When needing to request user for search input:
24
- <<<AskUserInput(request="What would you like to search for?")>>>
25
-
26
- 2. When needing to request user for form input:
27
- <<<AskUserInput(request="Please enter your full name:")>>>
28
-
29
- 3. When needing to request user for a choice:
30
- <<<AskUserInput(request="Select an option (1, 2, or 3):")>>>
31
- '''
32
-
33
- def tool_usage_xml(self):
34
23
  return '''AskUserInput: Requests input from the user based on a given context or prompt.
35
- <command name="AskUserInput"
24
+ <command name="AskUserInput">
36
25
  <arg name="request">[Your request here]</arg>
37
26
  </command>
38
27
 
@@ -90,4 +79,4 @@ class AskUserInput(BaseTool):
90
79
  except Exception as e:
91
80
  error_message = f"An error occurred while getting user input: {str(e)}"
92
81
  self.logger.error(error_message)
93
- return f"[Error: {error_message}]"
82
+ return f"[Error: {error_message}]"
@@ -0,0 +1,77 @@
1
+ # File: autobyteus/tools/base_tool.py
2
+
3
+ import logging
4
+ from abc import ABC, abstractmethod
5
+ from typing import Optional, Any
6
+
7
+ from autobyteus.events.event_emitter import EventEmitter
8
+ from autobyteus.events.event_types import EventType
9
+
10
+ from .tool_meta import ToolMeta
11
+
12
+ logger = logging.getLogger('autobyteus')
13
+
14
+ class BaseTool(ABC, EventEmitter, metaclass=ToolMeta):
15
+ """
16
+ Abstract base class for all tools, with auto-registration via ToolMeta.
17
+
18
+ Subclasses inherit a default `get_name` (the class name) and MUST implement
19
+ the abstract class method `tool_usage_xml`, and the abstract instance
20
+ method `_execute`.
21
+ """
22
+ def __init__(self):
23
+ super().__init__()
24
+ self.agent_id: Optional[str] = None
25
+ logger.debug(f"BaseTool instance initializing for potential class {self.__class__.__name__}")
26
+
27
+ @classmethod
28
+ def get_name(cls) -> str:
29
+ """
30
+ Return the name of the tool. Defaults to the class name.
31
+ Can be overridden by child classes if a different registration name is needed.
32
+ """
33
+ return cls.__name__
34
+
35
+ @classmethod
36
+ def tool_usage_xml(cls) -> str:
37
+ """
38
+ Return the static usage description string for the tool in XML format.
39
+ Must be implemented by subclasses.
40
+ """
41
+ pass
42
+
43
+ def set_agent_id(self, agent_id: str):
44
+ """Sets the ID of the agent using this tool instance."""
45
+ self.agent_id = agent_id
46
+ logger.debug(f"Agent ID '{agent_id}' set for tool instance '{self.__class__.get_name()}'")
47
+
48
+ async def execute(self, **kwargs):
49
+ """
50
+ Execute the tool's main functionality by calling _execute.
51
+ Argument validation must be handled within _execute.
52
+ """
53
+ tool_name = self.__class__.get_name()
54
+ logger.info(f"Executing tool '{tool_name}' for agent '{self.agent_id}' with args: {kwargs}")
55
+ try:
56
+ result = await self._execute(**kwargs)
57
+ logger.info(f"Tool '{tool_name}' execution completed successfully.")
58
+ return result
59
+ except Exception as e:
60
+ logger.error(f"Tool '{tool_name}' execution failed: {str(e)}", exc_info=True)
61
+ return f"Error executing tool '{tool_name}': {str(e)}"
62
+
63
+ @abstractmethod
64
+ async def _execute(self, **kwargs) -> Any:
65
+ """
66
+ Implement the actual execution logic in subclasses.
67
+ MUST handle own argument validation.
68
+ """
69
+ pass
70
+
71
+ @classmethod
72
+ def tool_usage(cls) -> str:
73
+ """
74
+ Returns the tool's static XML usage description by calling the class method tool_usage_xml.
75
+ This is a convenience class method.
76
+ """
77
+ return cls.tool_usage_xml()