autobyteus 1.0.5__py3-none-any.whl → 1.1.0__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 (256) 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 +18 -0
  9. autobyteus/agent/context/agent_config.py +80 -0
  10. autobyteus/agent/context/agent_context.py +132 -0
  11. autobyteus/agent/context/agent_phase_manager.py +164 -0
  12. autobyteus/agent/context/agent_runtime_state.py +89 -0
  13. autobyteus/agent/context/phases.py +47 -0
  14. autobyteus/agent/events/__init__.py +63 -0
  15. autobyteus/agent/events/agent_events.py +147 -0
  16. autobyteus/agent/events/agent_input_event_queue_manager.py +174 -0
  17. autobyteus/agent/events/notifiers.py +104 -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 +126 -79
  21. autobyteus/agent/group/agent_group.py +155 -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 +134 -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 +136 -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 +186 -0
  34. autobyteus/agent/handlers/tool_result_event_handler.py +96 -0
  35. autobyteus/agent/handlers/user_input_message_event_handler.py +77 -0
  36. autobyteus/agent/hooks/__init__.py +9 -0
  37. autobyteus/agent/hooks/base_phase_hook.py +52 -0
  38. autobyteus/agent/input_processor/__init__.py +18 -0
  39. autobyteus/agent/input_processor/base_user_input_processor.py +51 -0
  40. autobyteus/agent/input_processor/content_prefixing_input_processor.py +41 -0
  41. autobyteus/agent/input_processor/metadata_appending_input_processor.py +34 -0
  42. autobyteus/agent/input_processor/passthrough_input_processor.py +32 -0
  43. autobyteus/agent/input_processor/processor_definition.py +42 -0
  44. autobyteus/agent/input_processor/processor_meta.py +46 -0
  45. autobyteus/agent/input_processor/processor_registry.py +98 -0
  46. autobyteus/agent/llm_response_processor/__init__.py +16 -0
  47. autobyteus/agent/llm_response_processor/base_processor.py +50 -0
  48. autobyteus/agent/llm_response_processor/processor_definition.py +36 -0
  49. autobyteus/agent/llm_response_processor/processor_meta.py +37 -0
  50. autobyteus/agent/llm_response_processor/processor_registry.py +94 -0
  51. autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +53 -0
  52. autobyteus/agent/message/__init__.py +20 -0
  53. autobyteus/agent/message/agent_input_user_message.py +96 -0
  54. autobyteus/agent/message/context_file.py +82 -0
  55. autobyteus/agent/message/context_file_type.py +64 -0
  56. autobyteus/agent/message/{message.py → inter_agent_message.py} +12 -12
  57. autobyteus/agent/message/{message_types.py → inter_agent_message_type.py} +8 -6
  58. autobyteus/agent/message/send_message_to.py +142 -36
  59. autobyteus/agent/remote_agent.py +240 -5
  60. autobyteus/agent/runtime/__init__.py +15 -0
  61. autobyteus/agent/runtime/agent_runtime.py +139 -0
  62. autobyteus/agent/runtime/agent_thread_pool_manager.py +88 -0
  63. autobyteus/agent/runtime/agent_worker.py +200 -0
  64. autobyteus/agent/streaming/__init__.py +15 -0
  65. autobyteus/agent/streaming/agent_event_stream.py +120 -0
  66. autobyteus/agent/streaming/queue_streamer.py +58 -0
  67. autobyteus/agent/streaming/stream_event_payloads.py +156 -0
  68. autobyteus/agent/streaming/stream_events.py +123 -0
  69. autobyteus/agent/system_prompt_processor/__init__.py +14 -0
  70. autobyteus/agent/system_prompt_processor/base_processor.py +45 -0
  71. autobyteus/agent/system_prompt_processor/processor_definition.py +40 -0
  72. autobyteus/agent/system_prompt_processor/processor_meta.py +47 -0
  73. autobyteus/agent/system_prompt_processor/processor_registry.py +119 -0
  74. autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +65 -0
  75. autobyteus/agent/tool_invocation.py +28 -5
  76. autobyteus/agent/utils/__init__.py +9 -0
  77. autobyteus/agent/utils/wait_for_idle.py +59 -0
  78. autobyteus/agent/workflow/__init__.py +11 -0
  79. autobyteus/agent/workflow/agentic_workflow.py +89 -0
  80. autobyteus/agent/workflow/base_agentic_workflow.py +98 -0
  81. autobyteus/agent/workspace/__init__.py +9 -0
  82. autobyteus/agent/workspace/base_workspace.py +55 -0
  83. autobyteus/cli/__init__.py +10 -0
  84. autobyteus/cli/agent_cli.py +299 -0
  85. autobyteus/events/event_emitter.py +33 -56
  86. autobyteus/events/event_manager.py +133 -66
  87. autobyteus/events/event_types.py +41 -14
  88. autobyteus/llm/api/autobyteus_llm.py +13 -15
  89. autobyteus/llm/api/bedrock_llm.py +9 -3
  90. autobyteus/llm/api/claude_llm.py +10 -5
  91. autobyteus/llm/api/deepseek_llm.py +53 -91
  92. autobyteus/llm/api/gemini_llm.py +10 -4
  93. autobyteus/llm/api/grok_llm.py +53 -77
  94. autobyteus/llm/api/groq_llm.py +10 -5
  95. autobyteus/llm/api/mistral_llm.py +10 -5
  96. autobyteus/llm/api/nvidia_llm.py +9 -4
  97. autobyteus/llm/api/ollama_llm.py +56 -48
  98. autobyteus/llm/api/openai_llm.py +20 -14
  99. autobyteus/llm/base_llm.py +95 -34
  100. autobyteus/llm/extensions/base_extension.py +3 -4
  101. autobyteus/llm/extensions/token_usage_tracking_extension.py +2 -3
  102. autobyteus/llm/llm_factory.py +12 -13
  103. autobyteus/llm/models.py +87 -8
  104. autobyteus/llm/user_message.py +73 -0
  105. autobyteus/llm/utils/llm_config.py +124 -27
  106. autobyteus/llm/utils/response_types.py +3 -2
  107. autobyteus/llm/utils/token_usage.py +7 -4
  108. autobyteus/rpc/__init__.py +73 -0
  109. autobyteus/rpc/client/__init__.py +17 -0
  110. autobyteus/rpc/client/abstract_client_connection.py +124 -0
  111. autobyteus/rpc/client/client_connection_manager.py +153 -0
  112. autobyteus/rpc/client/sse_client_connection.py +306 -0
  113. autobyteus/rpc/client/stdio_client_connection.py +280 -0
  114. autobyteus/rpc/config/__init__.py +13 -0
  115. autobyteus/rpc/config/agent_server_config.py +153 -0
  116. autobyteus/rpc/config/agent_server_registry.py +152 -0
  117. autobyteus/rpc/hosting.py +244 -0
  118. autobyteus/rpc/protocol.py +244 -0
  119. autobyteus/rpc/server/__init__.py +20 -0
  120. autobyteus/rpc/server/agent_server_endpoint.py +181 -0
  121. autobyteus/rpc/server/base_method_handler.py +40 -0
  122. autobyteus/rpc/server/method_handlers.py +259 -0
  123. autobyteus/rpc/server/sse_server_handler.py +182 -0
  124. autobyteus/rpc/server/stdio_server_handler.py +151 -0
  125. autobyteus/rpc/server_main.py +198 -0
  126. autobyteus/rpc/transport_type.py +13 -0
  127. autobyteus/tools/__init__.py +75 -0
  128. autobyteus/tools/ask_user_input.py +34 -77
  129. autobyteus/tools/base_tool.py +66 -37
  130. autobyteus/tools/bash/__init__.py +2 -0
  131. autobyteus/tools/bash/bash_executor.py +42 -79
  132. autobyteus/tools/browser/__init__.py +2 -0
  133. autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +50 -42
  134. autobyteus/tools/browser/session_aware/browser_session_aware_tool.py +7 -4
  135. autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +117 -125
  136. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +75 -22
  137. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +94 -28
  138. autobyteus/tools/browser/session_aware/factory/browser_session_aware_web_element_trigger_factory.py +10 -2
  139. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_reader_factory.py +18 -2
  140. autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_screenshot_taker_factory.py +10 -2
  141. autobyteus/tools/browser/session_aware/shared_browser_session_manager.py +4 -3
  142. autobyteus/tools/browser/standalone/__init__.py +7 -0
  143. autobyteus/tools/browser/standalone/factory/google_search_factory.py +17 -2
  144. autobyteus/tools/browser/standalone/factory/webpage_reader_factory.py +17 -2
  145. autobyteus/tools/browser/standalone/factory/webpage_screenshot_taker_factory.py +10 -2
  146. autobyteus/tools/browser/standalone/google_search_ui.py +104 -67
  147. autobyteus/tools/browser/standalone/navigate_to.py +52 -28
  148. autobyteus/tools/browser/standalone/web_page_pdf_generator.py +94 -0
  149. autobyteus/tools/browser/standalone/webpage_image_downloader.py +146 -61
  150. autobyteus/tools/browser/standalone/webpage_reader.py +80 -61
  151. autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +91 -45
  152. autobyteus/tools/factory/__init__.py +9 -0
  153. autobyteus/tools/factory/tool_factory.py +25 -4
  154. autobyteus/tools/file/file_reader.py +22 -51
  155. autobyteus/tools/file/file_writer.py +25 -56
  156. autobyteus/tools/functional_tool.py +234 -0
  157. autobyteus/tools/image_downloader.py +49 -71
  158. autobyteus/tools/mcp/__init__.py +47 -0
  159. autobyteus/tools/mcp/call_handlers/__init__.py +18 -0
  160. autobyteus/tools/mcp/call_handlers/base_handler.py +40 -0
  161. autobyteus/tools/mcp/call_handlers/sse_handler.py +22 -0
  162. autobyteus/tools/mcp/call_handlers/stdio_handler.py +62 -0
  163. autobyteus/tools/mcp/call_handlers/streamable_http_handler.py +55 -0
  164. autobyteus/tools/mcp/config_service.py +258 -0
  165. autobyteus/tools/mcp/factory.py +70 -0
  166. autobyteus/tools/mcp/registrar.py +135 -0
  167. autobyteus/tools/mcp/schema_mapper.py +131 -0
  168. autobyteus/tools/mcp/tool.py +101 -0
  169. autobyteus/tools/mcp/types.py +96 -0
  170. autobyteus/tools/parameter_schema.py +268 -0
  171. autobyteus/tools/pdf_downloader.py +78 -79
  172. autobyteus/tools/registry/__init__.py +0 -2
  173. autobyteus/tools/registry/tool_definition.py +106 -34
  174. autobyteus/tools/registry/tool_registry.py +46 -22
  175. autobyteus/tools/timer.py +150 -102
  176. autobyteus/tools/tool_config.py +117 -0
  177. autobyteus/tools/tool_meta.py +48 -26
  178. autobyteus/tools/usage/__init__.py +6 -0
  179. autobyteus/tools/usage/formatters/__init__.py +31 -0
  180. autobyteus/tools/usage/formatters/anthropic_json_example_formatter.py +18 -0
  181. autobyteus/tools/usage/formatters/anthropic_json_schema_formatter.py +25 -0
  182. autobyteus/tools/usage/formatters/base_formatter.py +42 -0
  183. autobyteus/tools/usage/formatters/default_json_example_formatter.py +42 -0
  184. autobyteus/tools/usage/formatters/default_json_schema_formatter.py +28 -0
  185. autobyteus/tools/usage/formatters/default_xml_example_formatter.py +55 -0
  186. autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +46 -0
  187. autobyteus/tools/usage/formatters/gemini_json_example_formatter.py +34 -0
  188. autobyteus/tools/usage/formatters/gemini_json_schema_formatter.py +25 -0
  189. autobyteus/tools/usage/formatters/google_json_example_formatter.py +34 -0
  190. autobyteus/tools/usage/formatters/google_json_schema_formatter.py +25 -0
  191. autobyteus/tools/usage/formatters/openai_json_example_formatter.py +49 -0
  192. autobyteus/tools/usage/formatters/openai_json_schema_formatter.py +28 -0
  193. autobyteus/tools/usage/parsers/__init__.py +22 -0
  194. autobyteus/tools/usage/parsers/anthropic_xml_tool_usage_parser.py +10 -0
  195. autobyteus/tools/usage/parsers/base_parser.py +41 -0
  196. autobyteus/tools/usage/parsers/default_json_tool_usage_parser.py +106 -0
  197. autobyteus/tools/usage/parsers/default_xml_tool_usage_parser.py +135 -0
  198. autobyteus/tools/usage/parsers/exceptions.py +13 -0
  199. autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +68 -0
  200. autobyteus/tools/usage/parsers/openai_json_tool_usage_parser.py +147 -0
  201. autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +67 -0
  202. autobyteus/tools/usage/providers/__init__.py +22 -0
  203. autobyteus/tools/usage/providers/json_example_provider.py +32 -0
  204. autobyteus/tools/usage/providers/json_schema_provider.py +35 -0
  205. autobyteus/tools/usage/providers/json_tool_usage_parser_provider.py +28 -0
  206. autobyteus/tools/usage/providers/tool_manifest_provider.py +68 -0
  207. autobyteus/tools/usage/providers/xml_example_provider.py +28 -0
  208. autobyteus/tools/usage/providers/xml_schema_provider.py +29 -0
  209. autobyteus/tools/usage/providers/xml_tool_usage_parser_provider.py +26 -0
  210. autobyteus/tools/usage/registries/__init__.py +20 -0
  211. autobyteus/tools/usage/registries/json_example_formatter_registry.py +51 -0
  212. autobyteus/tools/usage/registries/json_schema_formatter_registry.py +51 -0
  213. autobyteus/tools/usage/registries/json_tool_usage_parser_registry.py +42 -0
  214. autobyteus/tools/usage/registries/xml_example_formatter_registry.py +30 -0
  215. autobyteus/tools/usage/registries/xml_schema_formatter_registry.py +33 -0
  216. autobyteus/tools/usage/registries/xml_tool_usage_parser_registry.py +30 -0
  217. {autobyteus-1.0.5.dist-info → autobyteus-1.1.0.dist-info}/METADATA +21 -3
  218. autobyteus-1.1.0.dist-info/RECORD +279 -0
  219. {autobyteus-1.0.5.dist-info → autobyteus-1.1.0.dist-info}/WHEEL +1 -1
  220. autobyteus/agent/async_agent.py +0 -175
  221. autobyteus/agent/async_group_aware_agent.py +0 -136
  222. autobyteus/agent/group/async_group_aware_agent.py +0 -122
  223. autobyteus/agent/group/coordinator_agent.py +0 -36
  224. autobyteus/agent/group/group_aware_agent.py +0 -121
  225. autobyteus/agent/orchestrator/__init__.py +0 -0
  226. autobyteus/agent/orchestrator/base_agent_orchestrator.py +0 -82
  227. autobyteus/agent/orchestrator/multi_replica_agent_orchestrator.py +0 -72
  228. autobyteus/agent/orchestrator/single_replica_agent_orchestrator.py +0 -43
  229. autobyteus/agent/registry/__init__.py +0 -11
  230. autobyteus/agent/registry/agent_definition.py +0 -94
  231. autobyteus/agent/registry/agent_registry.py +0 -114
  232. autobyteus/agent/response_parser/__init__.py +0 -0
  233. autobyteus/agent/response_parser/tool_usage_command_parser.py +0 -100
  234. autobyteus/agent/status.py +0 -12
  235. autobyteus/conversation/__init__.py +0 -0
  236. autobyteus/conversation/conversation.py +0 -54
  237. autobyteus/conversation/user_message.py +0 -59
  238. autobyteus/events/decorators.py +0 -29
  239. autobyteus/prompt/prompt_version_manager.py +0 -58
  240. autobyteus/prompt/storage/__init__.py +0 -0
  241. autobyteus/prompt/storage/prompt_version_model.py +0 -29
  242. autobyteus/prompt/storage/prompt_version_repository.py +0 -83
  243. autobyteus/tools/bash/factory/__init__.py +0 -0
  244. autobyteus/tools/bash/factory/bash_executor_factory.py +0 -6
  245. autobyteus/tools/factory/ask_user_input_factory.py +0 -6
  246. autobyteus/tools/factory/image_downloader_factory.py +0 -9
  247. autobyteus/tools/factory/pdf_downloader_factory.py +0 -9
  248. autobyteus/tools/factory/webpage_image_downloader_factory.py +0 -6
  249. autobyteus/tools/file/factory/__init__.py +0 -0
  250. autobyteus/tools/file/factory/file_reader_factory.py +0 -6
  251. autobyteus/tools/file/factory/file_writer_factory.py +0 -6
  252. autobyteus/tools/mcp_remote_tool.py +0 -82
  253. autobyteus/tools/web_page_pdf_generator.py +0 -90
  254. autobyteus-1.0.5.dist-info/RECORD +0 -163
  255. {autobyteus-1.0.5.dist-info → autobyteus-1.1.0.dist-info}/licenses/LICENSE +0 -0
  256. {autobyteus-1.0.5.dist-info → autobyteus-1.1.0.dist-info}/top_level.txt +0 -0
@@ -1,175 +0,0 @@
1
- import asyncio
2
- import logging
3
- from typing import (
4
- List,
5
- Optional,
6
- AsyncGenerator,
7
- Any,
8
- NoReturn,
9
- Union,
10
- AsyncIterator
11
- )
12
- from autobyteus.agent.agent import Agent
13
- from autobyteus.llm.base_llm import BaseLLM
14
- from autobyteus.tools.base_tool import BaseTool
15
- from autobyteus.prompt.prompt_builder import PromptBuilder
16
- from autobyteus.events.event_types import EventType
17
- from autobyteus.agent.status import AgentStatus
18
- from autobyteus.conversation.user_message import UserMessage
19
- from autobyteus.conversation.conversation import Conversation
20
- from autobyteus.agent.tool_invocation import ToolInvocation
21
-
22
- logger = logging.getLogger(__name__)
23
-
24
- class AsyncAgent(Agent):
25
- """
26
- An asynchronous agent that supports streaming LLM responses while maintaining
27
- compatibility with the base agent functionality.
28
- """
29
-
30
- def __init__(
31
- self,
32
- role: str,
33
- llm: BaseLLM,
34
- tools: Optional[List[BaseTool]] = None,
35
- agent_id: Optional[str] = None,
36
- prompt_builder: Optional[PromptBuilder] = None,
37
- initial_user_message: Optional[UserMessage] = None
38
- ) -> None:
39
- """
40
- Initialize the AsyncAgent with the given parameters.
41
-
42
- Args:
43
- role: The role of the agent
44
- llm: The language model instance
45
- tools: List of available tools
46
- use_xml_parser: Whether to use XML parser for responses
47
- agent_id: Optional unique identifier for the agent
48
- prompt_builder: Optional prompt builder instance
49
- initial_user_message: Optional initial message to start the conversation
50
- """
51
- super().__init__(
52
- role,
53
- llm,
54
- tools,
55
- agent_id,
56
- prompt_builder,
57
- initial_user_message
58
- )
59
-
60
- async def initialize_conversation(self) -> None:
61
- """Initialize the conversation with initial message or prompt."""
62
- logger.info(f"Initializing conversation for agent: {self.role}")
63
- self.conversation = Conversation(self.llm)
64
-
65
- if self.initial_user_message:
66
- initial_message = self.initial_user_message
67
- else:
68
- prompt_content = self.prompt_builder.set_variable_value(
69
- "external_tools",
70
- self._get_external_tools_section()
71
- ).build()
72
- initial_message = UserMessage(content=prompt_content)
73
-
74
- logger.debug(f"Initial user message for agent {self.role}: {initial_message}")
75
- await self.process_streaming_response(
76
- self.conversation.stream_user_message(
77
- initial_message.content,
78
- initial_message.file_paths
79
- )
80
- )
81
-
82
- async def handle_user_messages(self) -> NoReturn:
83
- """
84
- Handle incoming user messages continuously.
85
- Processes messages using streaming responses.
86
- """
87
- logger.info(f"Agent {self.role} started handling user messages")
88
- while not self.task_completed.is_set() and self.status == AgentStatus.RUNNING:
89
- try:
90
- user_message: UserMessage = await asyncio.wait_for(
91
- self.user_messages.get(),
92
- timeout=1.0
93
- )
94
- logger.info(f"Agent {self.role} handling user message")
95
- await self.process_streaming_response(
96
- self.conversation.stream_user_message(
97
- user_message.content,
98
- user_message.file_paths
99
- )
100
- )
101
- except asyncio.TimeoutError:
102
- continue
103
- except asyncio.CancelledError:
104
- logger.info(f"User message handler for agent {self.role} cancelled")
105
- break
106
- except Exception as e:
107
- logger.error(f"Error handling user message for agent {self.role}: {str(e)}")
108
-
109
- async def handle_tool_result_messages(self) -> NoReturn:
110
- """
111
- Handle tool execution result messages continuously.
112
- Processes messages using streaming responses.
113
- """
114
- logger.info(f"Agent {self.role} started handling tool result messages")
115
- while not self.task_completed.is_set() and self.status == AgentStatus.RUNNING:
116
- try:
117
- message: str = await asyncio.wait_for(
118
- self.tool_result_messages.get(),
119
- timeout=1.0
120
- )
121
- logger.info(f"Agent {self.role} handling tool result message: {message}")
122
- await self.process_streaming_response(
123
- self.conversation.stream_user_message(
124
- f"Tool execution result: {message}"
125
- )
126
- )
127
- except asyncio.TimeoutError:
128
- continue
129
- except asyncio.CancelledError:
130
- logger.info(f"Tool result handler for agent {self.role} cancelled")
131
- break
132
- except Exception as e:
133
- logger.error(f"Error handling tool result for agent {self.role}: {str(e)}")
134
-
135
- async def process_streaming_response(
136
- self,
137
- response_stream: AsyncIterator[str]
138
- ) -> None:
139
- """
140
- Process streaming responses from the LLM, emitting each chunk and handling
141
- tool invocations after receiving the complete response.
142
-
143
- Args:
144
- response_stream: AsyncIterator yielding response tokens
145
- """
146
- complete_response: str = ""
147
- try:
148
- async for chunk in response_stream:
149
- # Emit each chunk as it arrives
150
- self.emit(
151
- EventType.ASSISTANT_RESPONSE,
152
- response=chunk,
153
- is_complete=False
154
- )
155
- complete_response += chunk
156
- # Emit the complete response
157
- self.emit(
158
- EventType.ASSISTANT_RESPONSE,
159
- response=complete_response,
160
- is_complete=True
161
- )
162
-
163
- if self.tools and self.tool_usage_response_parser:
164
- tool_invocation: ToolInvocation = self.tool_usage_response_parser.parse_response(complete_response)
165
- if tool_invocation.is_valid():
166
- await self.execute_tool(tool_invocation)
167
- return
168
-
169
- logger.info(f"Assistant response for agent {self.role}: {complete_response}")
170
-
171
- except Exception as e:
172
- logger.error(f"Error processing streaming response for agent {self.role}: {str(e)}")
173
- self.emit(
174
- EventType.ERROR,
175
- error=str(e))
@@ -1,136 +0,0 @@
1
-
2
- import asyncio
3
- import logging
4
- from typing import TYPE_CHECKING, Optional, AsyncIterator
5
- from autobyteus.agent.async_agent import AsyncAgent
6
- from autobyteus.agent.message.message import Message
7
- from autobyteus.agent.message.message_types import MessageType
8
- from autobyteus.agent.message.send_message_to import SendMessageTo
9
- from autobyteus.agent.status import AgentStatus
10
- from autobyteus.events.event_types import EventType
11
-
12
- if TYPE_CHECKING:
13
- from autobyteus.agent.orchestrator.base_agent_orchestrator import BaseAgentOrchestrator
14
-
15
- logger = logging.getLogger(__name__)
16
-
17
- class AsyncGroupAwareAgent(AsyncAgent):
18
- def __init__(self, *args, **kwargs):
19
- super().__init__(*args, **kwargs)
20
- self.agent_orchestrator: Optional['BaseAgentOrchestrator'] = None
21
- self.incoming_agent_messages: Optional[asyncio.Queue] = None
22
- logger.info(f"AsyncGroupAwareAgent initialized with role: {self.role}")
23
-
24
- def _initialize_queues(self):
25
- if not self._queues_initialized:
26
- super()._initialize_queues()
27
- self.incoming_agent_messages = asyncio.Queue()
28
- logger.info(f"Queues initialized for agent {self.role}")
29
-
30
- def set_agent_orchestrator(self, agent_orchestrator: 'BaseAgentOrchestrator'):
31
- self.agent_orchestrator = agent_orchestrator
32
- if not any(isinstance(tool, SendMessageTo) for tool in self.tools):
33
- self.tools.append(SendMessageTo(agent_orchestrator))
34
- self.register_task_completion_listener()
35
- logger.info(f"Agent orchestrator set for agent {self.role}")
36
-
37
- def register_task_completion_listener(self):
38
- """Register to listen for task completion events from the orchestrator specifically"""
39
- logger.info(f"Registering task completion listener for agent: {self.role}")
40
- if self.agent_orchestrator:
41
- self.subscribe_from(
42
- self.agent_orchestrator,
43
- EventType.TASK_COMPLETED,
44
- self.on_task_completed
45
- )
46
- else:
47
- logger.warning(f"Cannot register task completion listener for agent {self.role}: orchestrator not set")
48
-
49
- async def receive_agent_message(self, message: Message):
50
- logger.info(f"Agent {self.agent_id} received message from {message.sender_agent_id}")
51
- if not self._queues_initialized:
52
- self._initialize_queues()
53
- await self.incoming_agent_messages.put(message)
54
- if self.status != AgentStatus.RUNNING:
55
- self.start()
56
-
57
- async def run(self):
58
- try:
59
- logger.info(f"Agent {self.role} entering running state")
60
- self._initialize_queues()
61
- self._initialize_task_completed()
62
- await self.initialize_conversation()
63
-
64
- self.status = AgentStatus.RUNNING
65
-
66
- user_message_handler = asyncio.create_task(self.handle_user_messages())
67
- tool_result_handler = asyncio.create_task(self.handle_tool_result_messages())
68
- agent_message_handler = asyncio.create_task(self.handle_agent_messages())
69
-
70
- done, pending = await asyncio.wait(
71
- [agent_message_handler, tool_result_handler, user_message_handler, self.task_completed.wait()],
72
- return_when=asyncio.FIRST_COMPLETED
73
- )
74
-
75
- for task in pending:
76
- task.cancel()
77
-
78
- await asyncio.gather(*pending, return_exceptions=True)
79
-
80
- except Exception as e:
81
- logger.error(f"Error in agent {self.role} execution: {str(e)}")
82
- self.status = AgentStatus.ERROR
83
- finally:
84
- self.status = AgentStatus.ENDED
85
- await self.cleanup()
86
-
87
- async def handle_agent_messages(self):
88
- logger.info(f"Agent {self.role} started handling agent messages")
89
- while not self.task_completed.is_set() and self.status == AgentStatus.RUNNING:
90
- try:
91
- message = await asyncio.wait_for(self.incoming_agent_messages.get(), timeout=1.0)
92
- logger.info(f"{self.role} processing message from {message.sender_agent_id}")
93
-
94
- if message.message_type == MessageType.TASK_RESULT:
95
- self.agent_orchestrator.handle_task_completed(message.sender_agent_id)
96
-
97
- await self.process_streaming_response(
98
- self.conversation.stream_user_message(
99
- f"Message from sender_agent_id {message.sender_agent_id}, content {message.content}"
100
- )
101
- )
102
- except asyncio.TimeoutError:
103
- continue
104
- except asyncio.CancelledError:
105
- logger.info(f"Agent message handler for agent {self.role} cancelled")
106
- break
107
- except Exception as e:
108
- logger.error(f"Error handling agent message for agent {self.role}: {str(e)}")
109
-
110
- async def execute_tool(self, tool_invocation):
111
- name = tool_invocation.name
112
- arguments = tool_invocation.arguments
113
- logger.info(f"Agent {self.role} attempting to execute tool: {name}")
114
-
115
- tool = next((t for t in self.tools if t.get_name() == name), None)
116
- if tool:
117
- try:
118
- result = await tool.execute(**arguments)
119
- logger.info(f"Tool '{name}' executed successfully by agent {self.role}. Result: {result}")
120
- if not isinstance(tool, SendMessageTo):
121
- await self.tool_result_messages.put(result)
122
- else:
123
- logger.info(f"SendMessageTo tool executed by agent {self.role}: {result}")
124
- except Exception as e:
125
- error_message = str(e)
126
- logger.error(f"Error executing tool '{name}' by agent {self.role}: {error_message}")
127
- if not isinstance(tool, SendMessageTo):
128
- await self.tool_result_messages.put(f"Error: {error_message}")
129
- else:
130
- logger.warning(f"Tool '{name}' not found for agent {self.role}.")
131
-
132
- async def cleanup(self):
133
- await super().cleanup()
134
- while not self.incoming_agent_messages.empty():
135
- self.incoming_agent_messages.get_nowait()
136
- logger.info(f"Cleanup completed for async group-aware agent: {self.role}")
@@ -1,122 +0,0 @@
1
- import asyncio
2
- import logging
3
- from typing import TYPE_CHECKING, Optional, AsyncIterator
4
- from autobyteus.agent.async_agent import AsyncAgent
5
- from autobyteus.agent.message.message import Message
6
- from autobyteus.agent.message.message_types import MessageType
7
- from autobyteus.agent.message.send_message_to import SendMessageTo
8
- from autobyteus.agent.status import AgentStatus
9
- from autobyteus.events.event_types import EventType
10
-
11
- if TYPE_CHECKING:
12
- from autobyteus.agent.orchestrator.base_agent_orchestrator import BaseAgentOrchestrator
13
-
14
- logger = logging.getLogger(__name__)
15
-
16
- class AsyncGroupAwareAgent(AsyncAgent):
17
- def __init__(self, *args, **kwargs):
18
- super().__init__(*args, **kwargs)
19
- self.agent_orchestrator: Optional['BaseAgentOrchestrator'] = None
20
- self.incoming_agent_messages: Optional[asyncio.Queue] = None
21
- logger.info(f"AsyncGroupAwareAgent initialized with role: {self.role}")
22
-
23
- def _initialize_queues(self):
24
- if not self._queues_initialized:
25
- super()._initialize_queues()
26
- self.incoming_agent_messages = asyncio.Queue()
27
- logger.info(f"Queues initialized for agent {self.role}")
28
-
29
- def set_agent_orchestrator(self, agent_orchestrator: 'BaseAgentOrchestrator'):
30
- self.agent_orchestrator = agent_orchestrator
31
- if not any(isinstance(tool, SendMessageTo) for tool in self.tools):
32
- self.tools.append(SendMessageTo(agent_orchestrator))
33
- logger.info(f"Agent orchestrator set for agent {self.role}")
34
-
35
- async def receive_agent_message(self, message: Message):
36
- logger.info(f"Agent {self.agent_id} received message from {message.sender_agent_id}")
37
- if not self._queues_initialized:
38
- self._initialize_queues()
39
- await self.incoming_agent_messages.put(message)
40
- if self.status != AgentStatus.RUNNING:
41
- self.start()
42
-
43
- async def run(self):
44
- try:
45
- logger.info(f"Agent {self.role} entering running state")
46
- self._initialize_queues()
47
- self._initialize_task_completed()
48
- await self.initialize_conversation()
49
-
50
- self.status = AgentStatus.RUNNING
51
-
52
- user_message_handler = asyncio.create_task(self.handle_user_messages())
53
- tool_result_handler = asyncio.create_task(self.handle_tool_result_messages())
54
- agent_message_handler = asyncio.create_task(self.handle_agent_messages())
55
-
56
- done, pending = await asyncio.wait(
57
- [agent_message_handler, tool_result_handler, user_message_handler, self.task_completed.wait()],
58
- return_when=asyncio.FIRST_COMPLETED
59
- )
60
-
61
- for task in pending:
62
- task.cancel()
63
-
64
- await asyncio.gather(*pending, return_exceptions=True)
65
-
66
- except Exception as e:
67
- logger.error(f"Error in agent {self.role} execution: {str(e)}")
68
- self.status = AgentStatus.ERROR
69
- finally:
70
- self.status = AgentStatus.ENDED
71
- await self.cleanup()
72
-
73
- async def handle_agent_messages(self):
74
- logger.info(f"Agent {self.role} started handling agent messages")
75
- while not self.task_completed.is_set() and self.status == AgentStatus.RUNNING:
76
- try:
77
- message = await asyncio.wait_for(self.incoming_agent_messages.get(), timeout=1.0)
78
- logger.info(f"{self.role} processing message from {message.sender_agent_id}")
79
-
80
- if message.message_type == MessageType.TASK_RESULT:
81
- self.agent_orchestrator.handle_task_completed(message.sender_agent_id)
82
-
83
- await self.process_streaming_response(
84
- self.conversation.stream_user_message(
85
- f"Message from sender_agent_id {message.sender_agent_id}, content {message.content}"
86
- )
87
- )
88
- except asyncio.TimeoutError:
89
- continue
90
- except asyncio.CancelledError:
91
- logger.info(f"Agent message handler for agent {self.role} cancelled")
92
- break
93
- except Exception as e:
94
- logger.error(f"Error handling agent message for agent {self.role}: {str(e)}")
95
-
96
- async def execute_tool(self, tool_invocation):
97
- name = tool_invocation.name
98
- arguments = tool_invocation.arguments
99
- logger.info(f"Agent {self.role} attempting to execute tool: {name}")
100
-
101
- tool = next((t for t in self.tools if t.get_name() == name), None)
102
- if tool:
103
- try:
104
- result = await tool.execute(**arguments)
105
- logger.info(f"Tool '{name}' executed successfully by agent {self.role}. Result: {result}")
106
- if not isinstance(tool, SendMessageTo):
107
- await self.tool_result_messages.put(result)
108
- else:
109
- logger.info(f"SendMessageTo tool executed by agent {self.role}: {result}")
110
- except Exception as e:
111
- error_message = str(e)
112
- logger.error(f"Error executing tool '{name}' by agent {self.role}: {error_message}")
113
- if not isinstance(tool, SendMessageTo):
114
- await self.tool_result_messages.put(f"Error: {error_message}")
115
- else:
116
- logger.warning(f"Tool '{name}' not found for agent {self.role}.")
117
-
118
- async def cleanup(self):
119
- await super().cleanup()
120
- while not self.incoming_agent_messages.empty():
121
- self.incoming_agent_messages.get_nowait()
122
- logger.info(f"Cleanup completed for async group-aware agent: {self.role}")
@@ -1,36 +0,0 @@
1
- # File: autobyteus/agent/group/coordinator_agent.py
2
-
3
- import asyncio
4
- import os
5
- import logging
6
- from autobyteus.agent.group.group_aware_agent import GroupAwareAgent, AgentStatus
7
- from autobyteus.agent.message.message_types import MessageType
8
- from autobyteus.agent.message.message import Message
9
-
10
- from autobyteus.events.event_types import EventType
11
- from autobyteus.prompt.prompt_builder import PromptBuilder
12
- from autobyteus.llm.base_llm import BaseLLM
13
- from typing import List
14
- from autobyteus.tools.base_tool import BaseTool
15
-
16
- logger = logging.getLogger(__name__)
17
-
18
- class CoordinatorAgent(GroupAwareAgent):
19
- def __init__(self, *args, **kwargs):
20
- super().__init__(*args, **kwargs)
21
- logger.info(f"CoordinatorAgent initialized with role: {self.role}")
22
-
23
-
24
- async def process_llm_response(self, llm_response):
25
- """
26
- Process the LLM response for the CoordinatorAgent.
27
- """
28
- logger.info(f"CoordinatorAgent {self.role} processing LLM response")
29
- tool_invocation = self.response_parser.parse_response(llm_response)
30
-
31
- if tool_invocation.is_valid():
32
- await self.execute_tool(tool_invocation)
33
- else:
34
- logger.info(f"Coordinator Response for agent {self.role}: {llm_response}")
35
- logger.info(f"CoordinatorAgent {self.role} task completed, emitting TASK_COMPLETED event")
36
- self.emit(EventType.TASK_COMPLETED)
@@ -1,121 +0,0 @@
1
- import asyncio
2
- import logging
3
- from autobyteus.agent.agent import Agent, AgentStatus
4
- from autobyteus.agent.message.send_message_to import SendMessageTo
5
- from autobyteus.events.event_types import EventType
6
- from autobyteus.agent.message.message_types import MessageType
7
- from autobyteus.agent.message.message import Message
8
- from typing import TYPE_CHECKING, Optional
9
-
10
- if TYPE_CHECKING:
11
- from autobyteus.agent.orchestrator.base_agent_orchestrator import BaseAgentOrchestrator
12
-
13
- logger = logging.getLogger(__name__)
14
-
15
- class GroupAwareAgent(Agent):
16
- def __init__(self, *args, **kwargs):
17
- super().__init__(*args, **kwargs)
18
- self.agent_orchestrator: Optional['BaseAgentOrchestrator'] = None
19
- self.incoming_agent_messages: Optional[asyncio.Queue] = None
20
- logger.info(f"GroupAwareAgent initialized with role: {self.role}")
21
-
22
- def _initialize_queues(self):
23
- if not self._queues_initialized:
24
- self.tool_result_messages = asyncio.Queue()
25
- self.user_messages = asyncio.Queue()
26
- self._queues_initialized = True
27
- self.incoming_agent_messages = asyncio.Queue()
28
- logger.info(f"Queues initialized for agent {self.role}")
29
-
30
- def set_agent_orchestrator(self, agent_orchestrator: 'BaseAgentOrchestrator'):
31
- self.agent_orchestrator = agent_orchestrator
32
- if not any(isinstance(tool, SendMessageTo) for tool in self.tools):
33
- self.tools.append(SendMessageTo(agent_orchestrator))
34
- logger.info(f"Agent orchestrator set for agent {self.role}")
35
-
36
- async def receive_agent_message(self, message: Message):
37
- logger.info(f"Agent {self.agent_id} received message from {message.sender_agent_id}")
38
- if not self._queues_initialized:
39
- logger.warning(f"Agent {self.agent_id} received message before queues were initialized. Initializing now.")
40
- self._initialize_queues()
41
- await self.incoming_agent_messages.put(message)
42
- if self.status != AgentStatus.RUNNING:
43
- self.start()
44
-
45
- async def run(self):
46
- try:
47
- logger.info(f"Agent {self.role} entering running state")
48
- self._initialize_queues()
49
- self._initialize_task_completed()
50
- await self.initialize_conversation()
51
-
52
- self.status = AgentStatus.RUNNING
53
-
54
- user_message_handler = asyncio.create_task(self.handle_user_messages())
55
- tool_result_handler = asyncio.create_task(self.handle_tool_result_messages())
56
- agent_message_handler = asyncio.create_task(self.handle_agent_messages())
57
-
58
- done, pending = await asyncio.wait(
59
- [agent_message_handler, tool_result_handler, user_message_handler, self.task_completed.wait()],
60
- return_when=asyncio.FIRST_COMPLETED
61
- )
62
-
63
- for task in pending:
64
- task.cancel()
65
-
66
- await asyncio.gather(*pending, return_exceptions=True)
67
-
68
- except Exception as e:
69
- logger.error(f"Error in agent {self.role} execution: {str(e)}")
70
- self.status = AgentStatus.ERROR
71
- finally:
72
- self.status = AgentStatus.ENDED
73
- await self.cleanup()
74
-
75
- async def handle_agent_messages(self):
76
- logger.info(f"Agent {self.role} started handling agent messages")
77
- while not self.task_completed.is_set() and self.status == AgentStatus.RUNNING:
78
- try:
79
- message = await asyncio.wait_for(self.incoming_agent_messages.get(), timeout=1.0)
80
- logger.info(f"{self.role} processing message from {message.sender_agent_id}")
81
-
82
- if message.message_type == MessageType.TASK_RESULT:
83
- self.agent_orchestrator.handle_task_completed(message.sender_agent_id)
84
-
85
- llm_response = await self.conversation.send_user_message(f"Message from sender_agent_id {message.sender_agent_id}, content {message.content}")
86
- await self.process_llm_response(llm_response)
87
- except asyncio.TimeoutError:
88
- continue
89
- except asyncio.CancelledError:
90
- logger.info(f"Agent message handler for agent {self.role} cancelled")
91
- break
92
- except Exception as e:
93
- logger.error(f"Error handling agent message for agent {self.role}: {str(e)}")
94
-
95
- async def execute_tool(self, tool_invocation):
96
- name = tool_invocation.name
97
- arguments = tool_invocation.arguments
98
- logger.info(f"Agent {self.role} attempting to execute tool: {name}")
99
-
100
- tool = next((t for t in self.tools if t.get_name() == name), None)
101
- if tool:
102
- try:
103
- result = await tool.execute(**arguments)
104
- logger.info(f"Tool '{name}' executed successfully by agent {self.role}. Result: {result}")
105
- if not isinstance(tool, SendMessageTo):
106
- await self.tool_result_messages.put(result)
107
- else:
108
- logger.info(f"SendMessageTo tool executed by agent {self.role}: {result}")
109
- except Exception as e:
110
- error_message = str(e)
111
- logger.error(f"Error executing tool '{name}' by agent {self.role}: {error_message}")
112
- if not isinstance(tool, SendMessageTo):
113
- await self.tool_result_messages.put(f"Error: {error_message}")
114
- else:
115
- logger.warning(f"Tool '{name}' not found for agent {self.role}.")
116
-
117
- async def cleanup(self):
118
- await super().cleanup()
119
- while not self.incoming_agent_messages.empty():
120
- self.incoming_agent_messages.get_nowait()
121
- logger.info(f"Cleanup completed for group-aware agent: {self.role}")
File without changes
@@ -1,82 +0,0 @@
1
- from abc import ABC, abstractmethod
2
- import logging
3
- from typing import Dict, Optional
4
- from autobyteus.agent.exceptions import AgentNotFoundException
5
- from autobyteus.agent.group.group_aware_agent import GroupAwareAgent
6
- from autobyteus.agent.message.message import Message
7
- from autobyteus.events.event_emitter import EventEmitter
8
- from autobyteus.events.event_types import EventType
9
-
10
- logger = logging.getLogger(__name__)
11
-
12
- class BaseAgentOrchestrator(EventEmitter):
13
- def __init__(self):
14
- super().__init__()
15
- self.agents: Dict[str, GroupAwareAgent] = {} # Keyed by agent_id
16
- self.coordinator_agent = None
17
-
18
- @abstractmethod
19
- def add_agent(self, agent: GroupAwareAgent):
20
- pass
21
-
22
- @abstractmethod
23
- def get_agent(self, agent_id: str) -> Optional[GroupAwareAgent]:
24
- pass
25
-
26
- @abstractmethod
27
- def create_agent_if_needed(self, role: str) -> GroupAwareAgent:
28
- pass
29
-
30
- def set_coordinator_agent(self, agent: GroupAwareAgent):
31
- self.coordinator_agent = agent
32
- self.add_agent(agent)
33
-
34
- async def route_message(self, message: Message):
35
- target_agent = None
36
- if message.recipient_agent_id != "unknown":
37
- target_agent = self.get_agent(message.recipient_agent_id)
38
- if not target_agent:
39
- raise AgentNotFoundException(message.recipient_agent_id)
40
- else:
41
- target_agent = self.create_agent_if_needed(message.recipient_role_name)
42
-
43
- if not target_agent:
44
- logger.error(f"Unable to find or create agent for role: {message.recipient_role_name}")
45
- return None
46
-
47
- logger.info(f"Routing message: from={message.sender_agent_id}, to={message.recipient_role_name} (id={target_agent.agent_id})")
48
- return await target_agent.receive_agent_message(message)
49
-
50
- def start_agent(self, agent: GroupAwareAgent):
51
- self.add_agent(agent)
52
- agent.start()
53
-
54
- def remove_agent(self, agent_id: str):
55
- if agent_id in self.agents:
56
- agent = self.agents[agent_id]
57
- del self.agents[agent_id]
58
- logger.info(f"Agent removed: role={agent.role}, id={agent_id}")
59
-
60
- def handle_task_completed(self, agent_id: str):
61
- """
62
- Handle task completion for a specific agent. This emits the event directly to the target agent,
63
- ensuring only the relevant agent receives the completion notification.
64
- """
65
- logger.info(f"Handling task completion for agent: {agent_id}")
66
- #self.remove_agent(agent_id)
67
-
68
- # Get the target agent
69
- target_agent = self.get_agent(agent_id)
70
- if target_agent:
71
- # Emit the event directly to the target agent
72
- self.emit(EventType.TASK_COMPLETED, target=target_agent)
73
- else:
74
- logger.warning(f"Could not find agent {agent_id} to notify of task completion")
75
-
76
- @abstractmethod
77
- async def run(self):
78
- pass
79
-
80
- @abstractmethod
81
- async def cleanup(self):
82
- pass