autobyteus 1.0.6__py3-none-any.whl → 1.1.1__py3-none-any.whl

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 (270) hide show
  1. autobyteus/agent/agent.py +97 -222
  2. autobyteus/agent/bootstrap_steps/__init__.py +19 -0
  3. autobyteus/agent/bootstrap_steps/agent_bootstrapper.py +88 -0
  4. autobyteus/agent/bootstrap_steps/agent_runtime_queue_initialization_step.py +57 -0
  5. autobyteus/agent/bootstrap_steps/base_bootstrap_step.py +38 -0
  6. autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +93 -0
  7. autobyteus/agent/bootstrap_steps/workspace_context_initialization_step.py +47 -0
  8. autobyteus/agent/context/__init__.py +13 -0
  9. autobyteus/agent/context/agent_config.py +84 -0
  10. autobyteus/agent/context/agent_context.py +129 -0
  11. autobyteus/agent/context/agent_phase_manager.py +264 -0
  12. autobyteus/agent/context/agent_runtime_state.py +89 -0
  13. autobyteus/agent/context/phases.py +49 -0
  14. autobyteus/agent/events/__init__.py +52 -0
  15. autobyteus/agent/events/agent_events.py +110 -0
  16. autobyteus/agent/events/agent_input_event_queue_manager.py +174 -0
  17. autobyteus/agent/events/notifiers.py +122 -0
  18. autobyteus/agent/events/worker_event_dispatcher.py +118 -0
  19. autobyteus/agent/factory/__init__.py +9 -0
  20. autobyteus/agent/factory/agent_factory.py +145 -0
  21. autobyteus/agent/group/agent_group.py +164 -0
  22. autobyteus/agent/group/agent_group_context.py +81 -0
  23. autobyteus/agent/handlers/__init__.py +36 -0
  24. autobyteus/agent/handlers/approved_tool_invocation_event_handler.py +148 -0
  25. autobyteus/agent/handlers/base_event_handler.py +36 -0
  26. autobyteus/agent/handlers/event_handler_registry.py +76 -0
  27. autobyteus/agent/handlers/generic_event_handler.py +46 -0
  28. autobyteus/agent/handlers/inter_agent_message_event_handler.py +76 -0
  29. autobyteus/agent/handlers/lifecycle_event_logger.py +64 -0
  30. autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +138 -0
  31. autobyteus/agent/handlers/llm_user_message_ready_event_handler.py +140 -0
  32. autobyteus/agent/handlers/tool_execution_approval_event_handler.py +85 -0
  33. autobyteus/agent/handlers/tool_invocation_request_event_handler.py +211 -0
  34. autobyteus/agent/handlers/tool_result_event_handler.py +101 -0
  35. autobyteus/agent/handlers/user_input_message_event_handler.py +77 -0
  36. autobyteus/agent/hooks/__init__.py +16 -0
  37. autobyteus/agent/hooks/base_phase_hook.py +61 -0
  38. autobyteus/agent/hooks/hook_definition.py +36 -0
  39. autobyteus/agent/hooks/hook_meta.py +37 -0
  40. autobyteus/agent/hooks/hook_registry.py +118 -0
  41. autobyteus/agent/input_processor/__init__.py +18 -0
  42. autobyteus/agent/input_processor/base_user_input_processor.py +54 -0
  43. autobyteus/agent/input_processor/content_prefixing_input_processor.py +41 -0
  44. autobyteus/agent/input_processor/metadata_appending_input_processor.py +34 -0
  45. autobyteus/agent/input_processor/passthrough_input_processor.py +33 -0
  46. autobyteus/agent/input_processor/processor_definition.py +42 -0
  47. autobyteus/agent/input_processor/processor_meta.py +46 -0
  48. autobyteus/agent/input_processor/processor_registry.py +117 -0
  49. autobyteus/agent/llm_response_processor/__init__.py +16 -0
  50. autobyteus/agent/llm_response_processor/base_processor.py +53 -0
  51. autobyteus/agent/llm_response_processor/processor_definition.py +36 -0
  52. autobyteus/agent/llm_response_processor/processor_meta.py +37 -0
  53. autobyteus/agent/llm_response_processor/processor_registry.py +113 -0
  54. autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +54 -0
  55. autobyteus/agent/message/__init__.py +20 -0
  56. autobyteus/agent/message/agent_input_user_message.py +96 -0
  57. autobyteus/agent/message/context_file.py +82 -0
  58. autobyteus/agent/message/context_file_type.py +63 -0
  59. autobyteus/agent/message/{message.py → inter_agent_message.py} +12 -12
  60. autobyteus/agent/message/{message_types.py → inter_agent_message_type.py} +8 -6
  61. autobyteus/agent/message/send_message_to.py +142 -36
  62. autobyteus/agent/phases/__init__.py +18 -0
  63. autobyteus/agent/phases/discover.py +52 -0
  64. autobyteus/agent/phases/manager.py +265 -0
  65. autobyteus/agent/phases/phase_enum.py +49 -0
  66. autobyteus/agent/phases/transition_decorator.py +40 -0
  67. autobyteus/agent/phases/transition_info.py +33 -0
  68. autobyteus/agent/remote_agent.py +244 -0
  69. autobyteus/agent/runtime/__init__.py +15 -0
  70. autobyteus/agent/runtime/agent_runtime.py +137 -0
  71. autobyteus/agent/runtime/agent_thread_pool_manager.py +88 -0
  72. autobyteus/agent/runtime/agent_worker.py +200 -0
  73. autobyteus/agent/streaming/__init__.py +15 -0
  74. autobyteus/agent/streaming/agent_event_stream.py +173 -0
  75. autobyteus/agent/streaming/queue_streamer.py +58 -0
  76. autobyteus/agent/streaming/stream_event_payloads.py +167 -0
  77. autobyteus/agent/streaming/stream_events.py +126 -0
  78. autobyteus/agent/system_prompt_processor/__init__.py +14 -0
  79. autobyteus/agent/system_prompt_processor/base_processor.py +48 -0
  80. autobyteus/agent/system_prompt_processor/processor_definition.py +40 -0
  81. autobyteus/agent/system_prompt_processor/processor_meta.py +47 -0
  82. autobyteus/agent/system_prompt_processor/processor_registry.py +119 -0
  83. autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +79 -0
  84. autobyteus/agent/tool_invocation.py +54 -5
  85. autobyteus/agent/utils/__init__.py +9 -0
  86. autobyteus/agent/utils/wait_for_idle.py +59 -0
  87. autobyteus/agent/workflow/__init__.py +11 -0
  88. autobyteus/agent/workflow/agentic_workflow.py +89 -0
  89. autobyteus/agent/workflow/base_agentic_workflow.py +98 -0
  90. autobyteus/agent/workspace/__init__.py +11 -0
  91. autobyteus/agent/workspace/base_workspace.py +77 -0
  92. autobyteus/agent/workspace/workspace_config.py +160 -0
  93. autobyteus/agent/workspace/workspace_definition.py +36 -0
  94. autobyteus/agent/workspace/workspace_meta.py +37 -0
  95. autobyteus/agent/workspace/workspace_registry.py +72 -0
  96. autobyteus/cli/__init__.py +11 -0
  97. autobyteus/cli/agent_cli.py +117 -0
  98. autobyteus/cli/cli_display.py +205 -0
  99. autobyteus/events/event_emitter.py +33 -56
  100. autobyteus/events/event_manager.py +134 -66
  101. autobyteus/events/event_types.py +43 -14
  102. autobyteus/llm/api/autobyteus_llm.py +13 -25
  103. autobyteus/llm/api/bedrock_llm.py +9 -3
  104. autobyteus/llm/api/claude_llm.py +10 -5
  105. autobyteus/llm/api/deepseek_llm.py +55 -93
  106. autobyteus/llm/api/gemini_llm.py +10 -4
  107. autobyteus/llm/api/grok_llm.py +55 -79
  108. autobyteus/llm/api/groq_llm.py +10 -5
  109. autobyteus/llm/api/mistral_llm.py +13 -8
  110. autobyteus/llm/api/nvidia_llm.py +9 -4
  111. autobyteus/llm/api/ollama_llm.py +58 -50
  112. autobyteus/llm/api/openai_llm.py +20 -14
  113. autobyteus/llm/base_llm.py +95 -34
  114. autobyteus/llm/extensions/base_extension.py +3 -4
  115. autobyteus/llm/extensions/token_usage_tracking_extension.py +13 -4
  116. autobyteus/llm/llm_factory.py +116 -53
  117. autobyteus/llm/models.py +92 -17
  118. autobyteus/llm/ollama_provider.py +6 -2
  119. autobyteus/llm/ollama_provider_resolver.py +44 -0
  120. autobyteus/llm/user_message.py +73 -0
  121. autobyteus/llm/utils/llm_config.py +124 -27
  122. autobyteus/llm/utils/response_types.py +3 -2
  123. autobyteus/llm/utils/token_usage.py +7 -4
  124. autobyteus/rpc/__init__.py +73 -0
  125. autobyteus/rpc/client/__init__.py +17 -0
  126. autobyteus/rpc/client/abstract_client_connection.py +124 -0
  127. autobyteus/rpc/client/client_connection_manager.py +153 -0
  128. autobyteus/rpc/client/sse_client_connection.py +306 -0
  129. autobyteus/rpc/client/stdio_client_connection.py +280 -0
  130. autobyteus/rpc/config/__init__.py +13 -0
  131. autobyteus/rpc/config/agent_server_config.py +153 -0
  132. autobyteus/rpc/config/agent_server_registry.py +152 -0
  133. autobyteus/rpc/hosting.py +244 -0
  134. autobyteus/rpc/protocol.py +244 -0
  135. autobyteus/rpc/server/__init__.py +20 -0
  136. autobyteus/rpc/server/agent_server_endpoint.py +181 -0
  137. autobyteus/rpc/server/base_method_handler.py +40 -0
  138. autobyteus/rpc/server/method_handlers.py +259 -0
  139. autobyteus/rpc/server/sse_server_handler.py +182 -0
  140. autobyteus/rpc/server/stdio_server_handler.py +151 -0
  141. autobyteus/rpc/server_main.py +198 -0
  142. autobyteus/rpc/transport_type.py +13 -0
  143. autobyteus/tools/__init__.py +77 -0
  144. autobyteus/tools/ask_user_input.py +34 -77
  145. autobyteus/tools/base_tool.py +73 -38
  146. autobyteus/tools/bash/__init__.py +2 -0
  147. autobyteus/tools/bash/bash_executor.py +42 -79
  148. autobyteus/tools/browser/__init__.py +2 -0
  149. autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +50 -42
  150. autobyteus/tools/browser/session_aware/browser_session_aware_tool.py +7 -4
  151. autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +117 -125
  152. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +75 -22
  153. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +94 -28
  154. autobyteus/tools/browser/session_aware/factory/browser_session_aware_web_element_trigger_factory.py +10 -2
  155. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_reader_factory.py +18 -2
  156. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_screenshot_taker_factory.py +10 -2
  157. autobyteus/tools/browser/session_aware/shared_browser_session_manager.py +4 -3
  158. autobyteus/tools/browser/standalone/__init__.py +7 -0
  159. autobyteus/tools/browser/standalone/factory/google_search_factory.py +17 -2
  160. autobyteus/tools/browser/standalone/factory/webpage_reader_factory.py +17 -2
  161. autobyteus/tools/browser/standalone/factory/webpage_screenshot_taker_factory.py +10 -2
  162. autobyteus/tools/browser/standalone/google_search_ui.py +104 -67
  163. autobyteus/tools/browser/standalone/navigate_to.py +52 -28
  164. autobyteus/tools/browser/standalone/web_page_pdf_generator.py +94 -0
  165. autobyteus/tools/browser/standalone/webpage_image_downloader.py +146 -61
  166. autobyteus/tools/browser/standalone/webpage_reader.py +80 -61
  167. autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +91 -45
  168. autobyteus/tools/factory/__init__.py +9 -0
  169. autobyteus/tools/factory/tool_factory.py +25 -4
  170. autobyteus/tools/file/file_reader.py +22 -51
  171. autobyteus/tools/file/file_writer.py +25 -56
  172. autobyteus/tools/functional_tool.py +249 -0
  173. autobyteus/tools/image_downloader.py +49 -71
  174. autobyteus/tools/mcp/__init__.py +47 -0
  175. autobyteus/tools/mcp/call_handlers/__init__.py +18 -0
  176. autobyteus/tools/mcp/call_handlers/base_handler.py +40 -0
  177. autobyteus/tools/mcp/call_handlers/sse_handler.py +22 -0
  178. autobyteus/tools/mcp/call_handlers/stdio_handler.py +76 -0
  179. autobyteus/tools/mcp/call_handlers/streamable_http_handler.py +55 -0
  180. autobyteus/tools/mcp/config_service.py +237 -0
  181. autobyteus/tools/mcp/factory.py +70 -0
  182. autobyteus/tools/mcp/registrar.py +323 -0
  183. autobyteus/tools/mcp/schema_mapper.py +131 -0
  184. autobyteus/tools/mcp/tool.py +101 -0
  185. autobyteus/tools/mcp/types.py +98 -0
  186. autobyteus/tools/parameter_schema.py +268 -0
  187. autobyteus/tools/pdf_downloader.py +78 -79
  188. autobyteus/tools/registry/__init__.py +0 -2
  189. autobyteus/tools/registry/tool_definition.py +113 -34
  190. autobyteus/tools/registry/tool_registry.py +64 -22
  191. autobyteus/tools/timer.py +150 -102
  192. autobyteus/tools/tool_category.py +11 -0
  193. autobyteus/tools/tool_config.py +117 -0
  194. autobyteus/tools/tool_meta.py +50 -26
  195. autobyteus/tools/tool_state.py +20 -0
  196. autobyteus/tools/usage/__init__.py +6 -0
  197. autobyteus/tools/usage/formatters/__init__.py +31 -0
  198. autobyteus/tools/usage/formatters/anthropic_json_example_formatter.py +18 -0
  199. autobyteus/tools/usage/formatters/anthropic_json_schema_formatter.py +25 -0
  200. autobyteus/tools/usage/formatters/base_formatter.py +42 -0
  201. autobyteus/tools/usage/formatters/default_json_example_formatter.py +42 -0
  202. autobyteus/tools/usage/formatters/default_json_schema_formatter.py +28 -0
  203. autobyteus/tools/usage/formatters/default_xml_example_formatter.py +55 -0
  204. autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +46 -0
  205. autobyteus/tools/usage/formatters/gemini_json_example_formatter.py +34 -0
  206. autobyteus/tools/usage/formatters/gemini_json_schema_formatter.py +25 -0
  207. autobyteus/tools/usage/formatters/google_json_example_formatter.py +34 -0
  208. autobyteus/tools/usage/formatters/google_json_schema_formatter.py +25 -0
  209. autobyteus/tools/usage/formatters/openai_json_example_formatter.py +49 -0
  210. autobyteus/tools/usage/formatters/openai_json_schema_formatter.py +28 -0
  211. autobyteus/tools/usage/parsers/__init__.py +22 -0
  212. autobyteus/tools/usage/parsers/anthropic_xml_tool_usage_parser.py +10 -0
  213. autobyteus/tools/usage/parsers/base_parser.py +41 -0
  214. autobyteus/tools/usage/parsers/default_json_tool_usage_parser.py +106 -0
  215. autobyteus/tools/usage/parsers/default_xml_tool_usage_parser.py +136 -0
  216. autobyteus/tools/usage/parsers/exceptions.py +13 -0
  217. autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +66 -0
  218. autobyteus/tools/usage/parsers/openai_json_tool_usage_parser.py +196 -0
  219. autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +67 -0
  220. autobyteus/tools/usage/providers/__init__.py +22 -0
  221. autobyteus/tools/usage/providers/json_example_provider.py +32 -0
  222. autobyteus/tools/usage/providers/json_schema_provider.py +35 -0
  223. autobyteus/tools/usage/providers/json_tool_usage_parser_provider.py +28 -0
  224. autobyteus/tools/usage/providers/tool_manifest_provider.py +68 -0
  225. autobyteus/tools/usage/providers/xml_example_provider.py +28 -0
  226. autobyteus/tools/usage/providers/xml_schema_provider.py +29 -0
  227. autobyteus/tools/usage/providers/xml_tool_usage_parser_provider.py +26 -0
  228. autobyteus/tools/usage/registries/__init__.py +20 -0
  229. autobyteus/tools/usage/registries/json_example_formatter_registry.py +51 -0
  230. autobyteus/tools/usage/registries/json_schema_formatter_registry.py +51 -0
  231. autobyteus/tools/usage/registries/json_tool_usage_parser_registry.py +42 -0
  232. autobyteus/tools/usage/registries/xml_example_formatter_registry.py +30 -0
  233. autobyteus/tools/usage/registries/xml_schema_formatter_registry.py +33 -0
  234. autobyteus/tools/usage/registries/xml_tool_usage_parser_registry.py +30 -0
  235. {autobyteus-1.0.6.dist-info → autobyteus-1.1.1.dist-info}/METADATA +23 -5
  236. autobyteus-1.1.1.dist-info/RECORD +296 -0
  237. {autobyteus-1.0.6.dist-info → autobyteus-1.1.1.dist-info}/WHEEL +1 -1
  238. autobyteus/agent/async_agent.py +0 -175
  239. autobyteus/agent/async_group_aware_agent.py +0 -136
  240. autobyteus/agent/group/async_group_aware_agent.py +0 -122
  241. autobyteus/agent/group/coordinator_agent.py +0 -36
  242. autobyteus/agent/group/group_aware_agent.py +0 -121
  243. autobyteus/agent/orchestrator/__init__.py +0 -0
  244. autobyteus/agent/orchestrator/base_agent_orchestrator.py +0 -82
  245. autobyteus/agent/orchestrator/multi_replica_agent_orchestrator.py +0 -72
  246. autobyteus/agent/orchestrator/single_replica_agent_orchestrator.py +0 -43
  247. autobyteus/agent/response_parser/__init__.py +0 -0
  248. autobyteus/agent/response_parser/tool_usage_command_parser.py +0 -100
  249. autobyteus/agent/status.py +0 -12
  250. autobyteus/conversation/__init__.py +0 -0
  251. autobyteus/conversation/conversation.py +0 -54
  252. autobyteus/conversation/user_message.py +0 -59
  253. autobyteus/events/decorators.py +0 -29
  254. autobyteus/prompt/prompt_version_manager.py +0 -58
  255. autobyteus/prompt/storage/__init__.py +0 -0
  256. autobyteus/prompt/storage/prompt_version_model.py +0 -29
  257. autobyteus/prompt/storage/prompt_version_repository.py +0 -83
  258. autobyteus/tools/bash/factory/__init__.py +0 -0
  259. autobyteus/tools/bash/factory/bash_executor_factory.py +0 -6
  260. autobyteus/tools/factory/ask_user_input_factory.py +0 -6
  261. autobyteus/tools/factory/image_downloader_factory.py +0 -9
  262. autobyteus/tools/factory/pdf_downloader_factory.py +0 -9
  263. autobyteus/tools/factory/webpage_image_downloader_factory.py +0 -6
  264. autobyteus/tools/file/factory/__init__.py +0 -0
  265. autobyteus/tools/file/factory/file_reader_factory.py +0 -6
  266. autobyteus/tools/file/factory/file_writer_factory.py +0 -6
  267. autobyteus/tools/web_page_pdf_generator.py +0 -90
  268. autobyteus-1.0.6.dist-info/RECORD +0 -157
  269. {autobyteus-1.0.6.dist-info → autobyteus-1.1.1.dist-info}/licenses/LICENSE +0 -0
  270. {autobyteus-1.0.6.dist-info → autobyteus-1.1.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,54 @@
1
+ # file: autobyteus/autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py
2
+ import logging
3
+ from typing import TYPE_CHECKING
4
+
5
+ from .base_processor import BaseLLMResponseProcessor
6
+ from autobyteus.tools.usage.parsers import ProviderAwareToolUsageParser
7
+ from autobyteus.tools.usage.parsers.exceptions import ToolUsageParseException
8
+ from autobyteus.agent.events import PendingToolInvocationEvent
9
+
10
+ if TYPE_CHECKING:
11
+ from autobyteus.agent.context import AgentContext
12
+ from autobyteus.agent.events import LLMCompleteResponseReceivedEvent
13
+ from autobyteus.llm.utils.response_types import CompleteResponse
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ class ProviderAwareToolUsageProcessor(BaseLLMResponseProcessor):
18
+ """
19
+ A "master" tool usage processor that uses a high-level parser from the
20
+ `tools` module to extract tool invocations, and then enqueues the
21
+ necessary agent events based on the parsed results.
22
+ """
23
+ def __init__(self):
24
+ self._parser = ProviderAwareToolUsageParser()
25
+ logger.debug("ProviderAwareToolUsageProcessor initialized.")
26
+
27
+ @classmethod
28
+ def get_name(cls) -> str:
29
+ return "provider_aware_tool_usage"
30
+
31
+ async def process_response(self, response: 'CompleteResponse', context: 'AgentContext', triggering_event: 'LLMCompleteResponseReceivedEvent') -> bool:
32
+ """
33
+ Uses a ProviderAwareToolUsageParser to get a list of tool invocations,
34
+ and then enqueues a PendingToolInvocationEvent for each one.
35
+ Propagates ToolUsageParseException if parsing fails.
36
+ """
37
+ try:
38
+ # Delegate parsing to the high-level parser
39
+ tool_invocations = self._parser.parse(response, context)
40
+ except ToolUsageParseException:
41
+ # Re-raise the exception to be caught by the event handler
42
+ raise
43
+
44
+ if not tool_invocations:
45
+ return False
46
+
47
+ logger.info(f"Agent '{context.agent_id}': Parsed {len(tool_invocations)} tool invocations. Enqueuing events.")
48
+ for invocation in tool_invocations:
49
+ logger.info(f"Agent '{context.agent_id}' ({self.get_name()}) identified tool invocation: {invocation.name}. Enqueuing event.")
50
+ await context.input_event_queues.enqueue_tool_invocation_request(
51
+ PendingToolInvocationEvent(tool_invocation=invocation)
52
+ )
53
+
54
+ return True
@@ -0,0 +1,20 @@
1
+ # file: autobyteus/autobyteus/agent/message/__init__.py
2
+ """
3
+ Components related to messaging for and between agents.
4
+ Includes inter-agent messages, user input messages, context files, and related tools.
5
+ """
6
+ from .inter_agent_message_type import InterAgentMessageType
7
+ from .inter_agent_message import InterAgentMessage
8
+ from .agent_input_user_message import AgentInputUserMessage
9
+ from .send_message_to import SendMessageTo
10
+ from .context_file import ContextFile
11
+ from .context_file_type import ContextFileType
12
+
13
+ __all__ = [
14
+ "InterAgentMessage",
15
+ "InterAgentMessageType",
16
+ "AgentInputUserMessage",
17
+ "SendMessageTo",
18
+ "ContextFile",
19
+ "ContextFileType",
20
+ ]
@@ -0,0 +1,96 @@
1
+ # file: autobyteus/autobyteus/agent/message/agent_input_user_message.py
2
+ import logging
3
+ from typing import Optional, List, Dict, Any
4
+ from dataclasses import dataclass, field
5
+
6
+ from .context_file import ContextFile # Import the new ContextFile dataclass
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ @dataclass
11
+ class AgentInputUserMessage:
12
+ """
13
+ Represents a message received from an external user interacting with the agent system.
14
+ This is a simple dataclass. It includes support for a list of ContextFile objects,
15
+ allowing users to provide various documents as context.
16
+ """
17
+ content: str
18
+ image_urls: Optional[List[str]] = field(default=None) # Basic list of strings
19
+ context_files: Optional[List[ContextFile]] = field(default=None)
20
+ metadata: Dict[str, Any] = field(default_factory=dict)
21
+
22
+ def __post_init__(self):
23
+ # Basic type validation that dataclasses don't do automatically for mutable defaults or complex types
24
+ if self.image_urls is not None and not (isinstance(self.image_urls, list) and all(isinstance(url, str) for url in self.image_urls)):
25
+ raise TypeError("AgentInputUserMessage 'image_urls' must be a list of strings if provided.")
26
+ if self.context_files is not None and not (isinstance(self.context_files, list) and all(isinstance(cf, ContextFile) for cf in self.context_files)):
27
+ raise TypeError("AgentInputUserMessage 'context_files' must be a list of ContextFile objects if provided.")
28
+ if not isinstance(self.metadata, dict): # Should be caught by default_factory, but good practice
29
+ raise TypeError("AgentInputUserMessage 'metadata' must be a dictionary.")
30
+ if not isinstance(self.content, str):
31
+ raise TypeError("AgentInputUserMessage 'content' must be a string.")
32
+
33
+ if logger.isEnabledFor(logging.DEBUG):
34
+ num_context_files = len(self.context_files) if self.context_files else 0
35
+ logger.debug(
36
+ f"AgentInputUserMessage initialized. Content: '{self.content[:50]}...', "
37
+ f"Image URLs: {self.image_urls}, Num ContextFiles: {num_context_files}, "
38
+ f"Metadata keys: {list(self.metadata.keys())}"
39
+ )
40
+
41
+ def to_dict(self) -> Dict[str, Any]:
42
+ """Serializes the AgentInputUserMessage to a dictionary."""
43
+ # Manually handle serialization of list of ContextFile objects
44
+ context_files_dict_list = None
45
+ if self.context_files:
46
+ context_files_dict_list = [cf.to_dict() for cf in self.context_files]
47
+
48
+ return {
49
+ "content": self.content,
50
+ "image_urls": self.image_urls,
51
+ "context_files": context_files_dict_list,
52
+ "metadata": self.metadata,
53
+ }
54
+
55
+ @classmethod
56
+ def from_dict(cls, data: Dict[str, Any]) -> 'AgentInputUserMessage':
57
+ """Deserializes an AgentInputUserMessage from a dictionary."""
58
+ content = data.get("content")
59
+ if not isinstance(content, str): # Ensure content is string
60
+ raise ValueError("AgentInputUserMessage 'content' in dictionary must be a string.")
61
+
62
+ image_urls = data.get("image_urls")
63
+ if image_urls is not None and not (isinstance(image_urls, list) and all(isinstance(url, str) for url in image_urls)):
64
+ raise ValueError("AgentInputUserMessage 'image_urls' in dictionary must be a list of strings if provided.")
65
+
66
+ context_files_data = data.get("context_files")
67
+ context_files_list: Optional[List[ContextFile]] = None
68
+ if context_files_data is not None:
69
+ if not isinstance(context_files_data, list):
70
+ raise ValueError("AgentInputUserMessage 'context_files' in dictionary must be a list if provided.")
71
+ context_files_list = [ContextFile.from_dict(cf_data) for cf_data in context_files_data]
72
+
73
+ metadata = data.get("metadata", {})
74
+ if not isinstance(metadata, dict):
75
+ raise ValueError("AgentInputUserMessage 'metadata' in dictionary must be a dict if provided.")
76
+
77
+ return cls(
78
+ content=content,
79
+ image_urls=image_urls,
80
+ context_files=context_files_list,
81
+ metadata=metadata
82
+ )
83
+
84
+ def __repr__(self) -> str:
85
+ content_preview = f"{self.content[:100]}..." if len(self.content) > 100 else self.content
86
+ images_repr = f", image_urls={self.image_urls}" if self.image_urls else ""
87
+
88
+ if self.context_files:
89
+ context_repr = f", context_files=[{len(self.context_files)} ContextFile(s)]"
90
+ else:
91
+ context_repr = ""
92
+
93
+ meta_repr = f", metadata_keys={list(self.metadata.keys())}" if self.metadata else ""
94
+
95
+ return (f"AgentInputUserMessage(content='{content_preview}'"
96
+ f"{images_repr}{context_repr}{meta_repr})")
@@ -0,0 +1,82 @@
1
+ # file: autobyteus/autobyteus/agent/message/context_file.py
2
+ import os
3
+ import logging
4
+ from typing import Optional, Dict, Any
5
+ from dataclasses import dataclass, field
6
+
7
+ from .context_file_type import ContextFileType
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ @dataclass
12
+ class ContextFile:
13
+ """
14
+ Represents a single context file provided to an agent.
15
+ This is a simple dataclass, deferring path validation and file access
16
+ to input processors.
17
+ """
18
+ path: str
19
+ file_type: ContextFileType = ContextFileType.UNKNOWN
20
+ file_name: Optional[str] = None
21
+ metadata: Dict[str, Any] = field(default_factory=dict)
22
+
23
+ def __post_init__(self):
24
+ """
25
+ Called after the dataclass's __init__ method.
26
+ Used here to infer file_name and file_type if not provided or UNKNOWN.
27
+ """
28
+ if self.file_name is None and self.path:
29
+ try:
30
+ self.file_name = os.path.basename(self.path)
31
+ except Exception as e:
32
+ logger.warning(f"Could not determine basename for path '{self.path}': {e}")
33
+ self.file_name = "unknown_file"
34
+
35
+ if self.file_type == ContextFileType.UNKNOWN and self.path:
36
+ inferred_type = ContextFileType.from_path(self.path)
37
+ if inferred_type != ContextFileType.UNKNOWN:
38
+ self.file_type = inferred_type
39
+ logger.debug(f"Inferred file type for '{self.path}' as {self.file_type.value}")
40
+ else:
41
+ logger.debug(f"Could not infer specific file type for '{self.path}', remaining UNKNOWN.")
42
+
43
+ # Ensure path is a string
44
+ if not isinstance(self.path, str):
45
+ # This ideally should be caught by type hints earlier, but as a runtime safeguard:
46
+ raise TypeError(f"ContextFile path must be a string, got {type(self.path)}")
47
+
48
+ if logger.isEnabledFor(logging.DEBUG):
49
+ logger.debug(f"ContextFile initialized: path='{self.path}', type='{self.file_type.value}', name='{self.file_name}'")
50
+
51
+ def to_dict(self) -> Dict[str, Any]:
52
+ """Serializes the ContextFile to a dictionary."""
53
+ return {
54
+ "path": self.path,
55
+ "file_type": self.file_type.value, # Serialize enum to its value
56
+ "file_name": self.file_name,
57
+ "metadata": self.metadata,
58
+ }
59
+
60
+ @classmethod
61
+ def from_dict(cls, data: Dict[str, Any]) -> 'ContextFile':
62
+ """Deserializes a ContextFile from a dictionary."""
63
+ if not isinstance(data.get("path"), str):
64
+ raise ValueError("ContextFile 'path' in dictionary must be a string.")
65
+
66
+ file_type_str = data.get("file_type", ContextFileType.UNKNOWN.value)
67
+ try:
68
+ file_type = ContextFileType(file_type_str)
69
+ except ValueError:
70
+ logger.warning(f"Invalid file_type string '{file_type_str}' in ContextFile data. Defaulting to UNKNOWN.")
71
+ file_type = ContextFileType.UNKNOWN
72
+
73
+ return cls(
74
+ path=data["path"],
75
+ file_type=file_type,
76
+ file_name=data.get("file_name"),
77
+ metadata=data.get("metadata", {})
78
+ )
79
+
80
+ def __repr__(self) -> str:
81
+ return (f"ContextFile(path='{self.path}', file_name='{self.file_name}', "
82
+ f"file_type='{self.file_type.value}', metadata_keys={list(self.metadata.keys())})")
@@ -0,0 +1,63 @@
1
+ from enum import Enum
2
+ import os
3
+
4
+ class ContextFileType(str, Enum):
5
+ """
6
+ Enumerates the types of context files that can be provided to an agent.
7
+ """
8
+ TEXT = "text" # .txt, .md (if treated as plain text initially)
9
+ MARKDOWN = "markdown" # .md (if specific markdown processing is intended)
10
+ PDF = "pdf" # .pdf
11
+ DOCX = "docx" # .docx (Microsoft Word)
12
+ PPTX = "pptx" # .pptx (Microsoft PowerPoint)
13
+ XLSX = "xlsx" # .xlsx (Microsoft Excel)
14
+ CSV = "csv" # .csv
15
+ JSON = "json" # .json
16
+ XML = "xml" # .xml
17
+ HTML = "html" # .html, .htm
18
+ PYTHON = "python" # .py
19
+ JAVASCRIPT = "javascript" # .js
20
+ IMAGE = "image" # .png, .jpg, .jpeg, .gif, .webp (when image is for contextual analysis, not direct LLM vision input)
21
+ UNKNOWN = "unknown" # Fallback for unrecognized types
22
+
23
+ @classmethod
24
+ def from_path(cls, file_path: str) -> 'ContextFileType':
25
+ """
26
+ Infers the ContextFileType from a file path based on its extension.
27
+ """
28
+ if not file_path or not isinstance(file_path, str):
29
+ return cls.UNKNOWN
30
+
31
+ _, extension = os.path.splitext(file_path.lower())
32
+
33
+ if extension == ".txt":
34
+ return cls.TEXT
35
+ elif extension == ".md":
36
+ return cls.MARKDOWN
37
+ elif extension == ".pdf":
38
+ return cls.PDF
39
+ elif extension == ".docx":
40
+ return cls.DOCX
41
+ elif extension == ".pptx":
42
+ return cls.PPTX
43
+ elif extension == ".xlsx":
44
+ return cls.XLSX
45
+ elif extension == ".csv":
46
+ return cls.CSV
47
+ elif extension == ".json":
48
+ return cls.JSON
49
+ elif extension == ".xml":
50
+ return cls.XML
51
+ elif extension in [".html", ".htm"]:
52
+ return cls.HTML
53
+ elif extension == ".py":
54
+ return cls.PYTHON
55
+ elif extension == ".js":
56
+ return cls.JAVASCRIPT
57
+ elif extension in [".png", ".jpg", ".jpeg", ".gif", ".webp"]:
58
+ return cls.IMAGE
59
+ else:
60
+ return cls.UNKNOWN
61
+
62
+ def __str__(self) -> str:
63
+ return self.value
@@ -1,16 +1,16 @@
1
- from autobyteus.agent.message.message_types import MessageType
1
+ from autobyteus.agent.message.inter_agent_message_type import InterAgentMessageType
2
2
 
3
- class Message:
3
+ class InterAgentMessage:
4
4
  def __init__(self, recipient_role_name: str, recipient_agent_id: str, content: str,
5
- message_type: MessageType, sender_agent_id: str):
5
+ message_type: InterAgentMessageType, sender_agent_id: str): # Updated type hint for message_type
6
6
  self.recipient_role_name = recipient_role_name
7
7
  self.recipient_agent_id = recipient_agent_id
8
8
  self.content = content
9
- self.message_type = message_type
9
+ self.message_type: InterAgentMessageType = message_type # Updated type hint for attribute
10
10
  self.sender_agent_id = sender_agent_id
11
11
 
12
12
  def __eq__(self, other):
13
- if not isinstance(other, Message):
13
+ if not isinstance(other, InterAgentMessage): # Updated class check
14
14
  return False
15
15
  return (self.recipient_role_name == other.recipient_role_name and
16
16
  self.recipient_agent_id == other.recipient_agent_id and
@@ -19,23 +19,23 @@ class Message:
19
19
  self.sender_agent_id == other.sender_agent_id)
20
20
 
21
21
  def __repr__(self):
22
- return (f"Message(recipient_role_name='{self.recipient_role_name}', "
22
+ return (f"InterAgentMessage(recipient_role_name='{self.recipient_role_name}', " # Updated class name
23
23
  f"recipient_agent_id='{self.recipient_agent_id}', "
24
24
  f"content='{self.content}', "
25
- f"message_type=<{self.message_type.__class__.__name__}.{self.message_type.name}: '{self.message_type.value}'>, "
25
+ f"message_type=<{self.message_type.__class__.__name__}.{self.message_type.name}: '{self.message_type.value}'>, " # message_type class name will be InterAgentMessageType
26
26
  f"sender_agent_id='{self.sender_agent_id}')")
27
27
 
28
28
  @classmethod
29
29
  def create_with_dynamic_message_type(cls, recipient_role_name: str, recipient_agent_id: str,
30
- content: str, message_type: str, sender_agent_id: str):
30
+ content: str, message_type: str, sender_agent_id: str) -> 'InterAgentMessage': # Updated return type hint
31
31
  if not message_type:
32
32
  raise ValueError("message_type cannot be empty")
33
33
 
34
34
  try:
35
- msg_type = MessageType(message_type.lower())
35
+ msg_type = InterAgentMessageType(message_type.lower()) # Use renamed InterAgentMessageType
36
36
  except ValueError:
37
- msg_type = MessageType.add_type(message_type.upper(), message_type.lower())
37
+ msg_type = InterAgentMessageType.add_type(message_type.upper(), message_type.lower()) # Use renamed InterAgentMessageType
38
38
  if msg_type is None:
39
- raise ValueError(f"Failed to create or find MessageType: {message_type}")
39
+ raise ValueError(f"Failed to create or find InterAgentMessageType: {message_type}") # Updated message
40
40
 
41
- return cls(recipient_role_name, recipient_agent_id, content, msg_type, sender_agent_id)
41
+ return cls(recipient_role_name, recipient_agent_id, content, msg_type, sender_agent_id)
@@ -1,6 +1,6 @@
1
1
  from autobyteus.utils.dynamic_enum import DynamicEnum
2
2
 
3
- class MessageType(DynamicEnum):
3
+ class InterAgentMessageType(DynamicEnum):
4
4
  TASK_ASSIGNMENT = "task_assignment"
5
5
  TASK_RESULT = "task_result"
6
6
  TASK_COMPLETED = "task_completed"
@@ -8,16 +8,16 @@ class MessageType(DynamicEnum):
8
8
  ERROR = "error"
9
9
 
10
10
  @classmethod
11
- def add_type(cls, name: str, value: str) -> 'MessageType':
11
+ def add_type(cls, name: str, value: str) -> 'InterAgentMessageType': # Updated return type hint
12
12
  """
13
- Add a new message type dynamically.
13
+ Add a new inter-agent message type dynamically.
14
14
 
15
15
  Args:
16
16
  name (str): The name of the new message type.
17
17
  value (str): The value of the new message type.
18
18
 
19
19
  Returns:
20
- MessageType: The newly created MessageType.
20
+ InterAgentMessageType: The newly created InterAgentMessageType. # Updated return type in docstring
21
21
 
22
22
  Raises:
23
23
  ValueError: If the name or value already exists.
@@ -25,5 +25,7 @@ class MessageType(DynamicEnum):
25
25
  try:
26
26
  return cls.add(name, value)
27
27
  except ValueError as e:
28
- print(f"Warning: Failed to add new message type. {str(e)}")
29
- return None
28
+ # Consider logging a warning here if a logger is available and appropriate
29
+ # For now, print as in original code
30
+ print(f"Warning: Failed to add new inter-agent message type. {str(e)}")
31
+ return None
@@ -1,44 +1,150 @@
1
- # file: autobyteus/agent/group/send_message_to.py
2
- from autobyteus.agent.message.message import Message
1
+ # file: autobyteus/autobyteus/agent/message/send_message_to.py
2
+ import logging
3
+ from typing import TYPE_CHECKING, Any, Optional
4
+
5
+ from autobyteus.agent.message.inter_agent_message import InterAgentMessage
3
6
  from autobyteus.tools.base_tool import BaseTool
4
- from typing import TYPE_CHECKING, Any
7
+ from autobyteus.agent.group.agent_group_context import AgentGroupContext
8
+ # Updated imports for schema
9
+ from autobyteus.tools.parameter_schema import ParameterSchema, ParameterDefinition, ParameterType
5
10
 
6
11
  if TYPE_CHECKING:
7
- from autobyteus.agent.orchestrator.base_agent_orchestrator import BaseAgentOrchestrator
12
+ from autobyteus.agent.context import AgentContext
13
+ from autobyteus.agent.agent import Agent
14
+
15
+ logger = logging.getLogger(__name__)
8
16
 
9
17
  class SendMessageTo(BaseTool):
10
- def __init__(self, orchestrator: 'BaseAgentOrchestrator'):
18
+ """
19
+ A tool for sending messages to other agents within the same AgentGroup.
20
+ It utilizes AgentGroupContext injected into the calling agent's AgentContext
21
+ to resolve recipient agents.
22
+ """
23
+ TOOL_NAME = "SendMessageTo" # Class attribute for the name
24
+
25
+ def __init__(self):
11
26
  super().__init__()
12
- self.orchestrator = orchestrator
27
+ logger.debug(f"{self.get_name()} tool initialized.") # Use get_name()
28
+
29
+ @classmethod
30
+ def get_name(cls) -> str: # Implemented as per BaseTool requirement
31
+ return cls.TOOL_NAME
32
+
33
+ @classmethod
34
+ def get_description(cls) -> str:
35
+ return ("Sends a message to another agent within the same group. "
36
+ "Can target by role or specific agent ID.")
37
+
38
+ @classmethod
39
+ def get_argument_schema(cls) -> Optional[ParameterSchema]:
40
+ schema = ParameterSchema()
41
+ schema.add_parameter(ParameterDefinition(
42
+ name="recipient_role_name",
43
+ param_type=ParameterType.STRING,
44
+ description="The general role name of the recipient agent (e.g., 'worker', 'reviewer').",
45
+ required=True
46
+ ))
47
+ schema.add_parameter(ParameterDefinition(
48
+ name="content",
49
+ param_type=ParameterType.STRING,
50
+ description="The actual message text.",
51
+ required=True
52
+ ))
53
+ schema.add_parameter(ParameterDefinition(
54
+ name="message_type",
55
+ param_type=ParameterType.STRING, # Or ENUM if InterAgentMessageType values are known and fixed for schema
56
+ description="Type of the message (e.g., TASK_ASSIGNMENT, CLARIFICATION). Custom types allowed.",
57
+ required=True
58
+ ))
59
+ schema.add_parameter(ParameterDefinition(
60
+ name="recipient_agent_id",
61
+ param_type=ParameterType.STRING,
62
+ description='Optional. Specific ID of the recipient agent. If "unknown" or omitted, resolves by role.',
63
+ required=False,
64
+ default_value=None # Explicitly no default, truly optional
65
+ ))
66
+ return schema
67
+
68
+ # tool_usage_xml() and tool_usage_json() are inherited from BaseTool
69
+ # get_config_schema() for instantiation defaults to None
70
+
71
+ async def _execute(self,
72
+ context: 'AgentContext',
73
+ recipient_role_name: str,
74
+ content: str,
75
+ message_type: str,
76
+ recipient_agent_id: Optional[str] = None) -> str: # Named parameters
77
+ """
78
+ Sends a message to another agent in the group.
79
+ Arguments are validated by BaseTool.execute().
80
+ """
81
+ sender_agent_id = context.agent_id
82
+ logger.info(f"Tool '{self.get_name()}': Sender '{sender_agent_id}' attempting to send message. "
83
+ f"Recipient Role: '{recipient_role_name}', Recipient ID: '{recipient_agent_id}', Type: '{message_type}'.")
84
+
85
+ group_context_any = context.custom_data.get('agent_group_context')
86
+
87
+ if not isinstance(group_context_any, AgentGroupContext):
88
+ error_msg = f"Tool '{self.get_name()}' critical error: AgentGroupContext not found or invalid in AgentContext.custom_data for agent '{sender_agent_id}'. Cannot send message."
89
+ logger.error(error_msg)
90
+ return f"Error: {error_msg}"
91
+
92
+ group_context: AgentGroupContext = group_context_any # Type cast after check
93
+
94
+ target_agent: Optional['Agent'] = None
95
+
96
+ # Use recipient_agent_id if provided and not explicitly "unknown" (case-insensitive)
97
+ if recipient_agent_id and recipient_agent_id.lower() != "unknown":
98
+ target_agent = group_context.get_agent(recipient_agent_id)
99
+ if not target_agent:
100
+ logger.warning(f"Tool '{self.get_name()}': Agent with ID '{recipient_agent_id}' not found in group '{group_context.group_id}'. "
101
+ f"Attempting to find by role '{recipient_role_name}'.")
102
+
103
+ if not target_agent:
104
+ agents_with_role = group_context.get_agents_by_role(recipient_role_name)
105
+ if not agents_with_role:
106
+ error_msg = f"No agent found with role '{recipient_role_name}' (and specific ID '{recipient_agent_id}' if provided was not found) in group '{group_context.group_id}'."
107
+ logger.error(f"Tool '{self.get_name()}': {error_msg}")
108
+ return f"Error: {error_msg}"
109
+
110
+ if len(agents_with_role) > 1:
111
+ logger.warning(f"Tool '{self.get_name()}': Multiple agents ({len(agents_with_role)}) found for role '{recipient_role_name}'. "
112
+ f"Sending to the first one: {agents_with_role[0].agent_id}. "
113
+ "Consider using specific recipient_agent_id for clarity.")
114
+ target_agent = agents_with_role[0]
115
+ # Update recipient_agent_id to the one resolved by role if it was initially None or "unknown"
116
+ recipient_agent_id = target_agent.agent_id
117
+
118
+
119
+ if not target_agent:
120
+ error_msg = f"Could not resolve recipient agent with role '{recipient_role_name}' or ID '{recipient_agent_id}'." # recipient_agent_id would be updated here
121
+ logger.error(f"Tool '{self.get_name()}': {error_msg}")
122
+ return f"Error: {error_msg}"
13
123
 
14
- async def _execute(self, recipient_role_name: str, recipient_agent_id: str, content: str, message_type: str, sender_agent_id: str) -> Any:
15
124
  try:
16
- message = Message.create_with_dynamic_message_type(recipient_role_name, recipient_agent_id, content, message_type, sender_agent_id)
17
- return await self.orchestrator.route_message(message)
18
- except ValueError as e:
19
- return f"Error: {str(e)}"
20
-
21
- def tool_usage_xml(self) -> str:
22
- return '''SendMessageTo: Sends a message to another agent in the group. Usage:
23
- <command name="SendMessageTo">
24
- <arg name="recipient_role_name">GeneralRoleName</arg>
25
- <arg name="recipient_agent_id">SpecificAgentId or "unknown"</arg>
26
- <arg name="content">Your message here</arg>
27
- <arg name="message_type">TASK_ASSIGNMENT|TASK_RESULT|TASK_COMPLETED|CLARIFICATION|ERROR</arg>
28
- <arg name="sender_agent_id">YourSpecificAgentId</arg>
29
- </command>
30
- where:
31
- - "recipient_role_name" is the general role name of the recipient agent
32
- - "recipient_agent_id" is the specific ID of the recipient agent, or "unknown" if not known
33
- - "content" is the actual message text
34
- - "message_type" is one of: TASK_ASSIGNMENT, TASK_RESULT, TASK_COMPLETED, CLARIFICATION, or ERROR
35
- - "sender_agent_id" is the specific ID of the sender agent
36
- Example:
37
- <command name="SendMessageTo">
38
- <arg name="recipient_role_name">worker</arg>
39
- <arg name="recipient_agent_id">worker_001</arg>
40
- <arg name="content">Please provide more details about the task output.</arg>
41
- <arg name="message_type">CLARIFICATION</arg>
42
- <arg name="sender_agent_id">coordinator_001</arg>
43
- </command>
44
- '''
125
+ message_to_send = InterAgentMessage.create_with_dynamic_message_type(
126
+ recipient_role_name=target_agent.context.config.role,
127
+ recipient_agent_id=target_agent.agent_id, # Use the definitively resolved agent ID
128
+ content=content,
129
+ message_type=message_type,
130
+ sender_agent_id=sender_agent_id
131
+ )
132
+
133
+ await target_agent.post_inter_agent_message(message_to_send)
134
+ success_msg = (f"Message successfully sent from '{sender_agent_id}' to agent "
135
+ f"'{target_agent.agent_id}' (Role: '{target_agent.context.config.role}').")
136
+ logger.info(f"Tool '{self.get_name()}': {success_msg}")
137
+ return success_msg
138
+ except ValueError as ve:
139
+ error_msg = f"Error creating message: {str(ve)}"
140
+ logger.error(f"Tool '{self.get_name()}': {error_msg}", exc_info=True)
141
+ return f"Error: {error_msg}"
142
+ except Exception as e:
143
+ error_msg = f"An unexpected error occurred while sending message: {str(e)}"
144
+ logger.error(f"Tool '{self.get_name()}': {error_msg}", exc_info=True)
145
+ return f"Error: {error_msg}"
146
+
147
+ # tool_usage_xml was defined directly here, this is now inherited from BaseTool
148
+ # BaseTool.tool_usage_xml() will use get_argument_schema() to generate it.
149
+ # If a custom XML format was desired that differs from the auto-generated one,
150
+ # then this method could be overridden. For now, assume auto-generated is fine.
@@ -0,0 +1,18 @@
1
+ # file: autobyteus/autobyteus/agent/phases/__init__.py
2
+ """
3
+ This package contains components for defining and describing agent operational phases
4
+ and their transitions.
5
+ """
6
+ from .phase_enum import AgentOperationalPhase
7
+ from .transition_info import PhaseTransitionInfo
8
+ from .transition_decorator import phase_transition
9
+ from .discover import PhaseTransitionDiscoverer
10
+ from .manager import AgentPhaseManager
11
+
12
+ __all__ = [
13
+ "AgentOperationalPhase",
14
+ "PhaseTransitionInfo",
15
+ "phase_transition",
16
+ "PhaseTransitionDiscoverer",
17
+ "AgentPhaseManager",
18
+ ]