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.
- autobyteus/agent/agent.py +97 -222
- autobyteus/agent/bootstrap_steps/__init__.py +19 -0
- autobyteus/agent/bootstrap_steps/agent_bootstrapper.py +88 -0
- autobyteus/agent/bootstrap_steps/agent_runtime_queue_initialization_step.py +57 -0
- autobyteus/agent/bootstrap_steps/base_bootstrap_step.py +38 -0
- autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +93 -0
- autobyteus/agent/bootstrap_steps/workspace_context_initialization_step.py +47 -0
- autobyteus/agent/context/__init__.py +18 -0
- autobyteus/agent/context/agent_config.py +80 -0
- autobyteus/agent/context/agent_context.py +132 -0
- autobyteus/agent/context/agent_phase_manager.py +164 -0
- autobyteus/agent/context/agent_runtime_state.py +89 -0
- autobyteus/agent/context/phases.py +47 -0
- autobyteus/agent/events/__init__.py +63 -0
- autobyteus/agent/events/agent_events.py +147 -0
- autobyteus/agent/events/agent_input_event_queue_manager.py +174 -0
- autobyteus/agent/events/notifiers.py +104 -0
- autobyteus/agent/events/worker_event_dispatcher.py +118 -0
- autobyteus/agent/factory/__init__.py +9 -0
- autobyteus/agent/factory/agent_factory.py +126 -79
- autobyteus/agent/group/agent_group.py +155 -0
- autobyteus/agent/group/agent_group_context.py +81 -0
- autobyteus/agent/handlers/__init__.py +36 -0
- autobyteus/agent/handlers/approved_tool_invocation_event_handler.py +134 -0
- autobyteus/agent/handlers/base_event_handler.py +36 -0
- autobyteus/agent/handlers/event_handler_registry.py +76 -0
- autobyteus/agent/handlers/generic_event_handler.py +46 -0
- autobyteus/agent/handlers/inter_agent_message_event_handler.py +76 -0
- autobyteus/agent/handlers/lifecycle_event_logger.py +64 -0
- autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +136 -0
- autobyteus/agent/handlers/llm_user_message_ready_event_handler.py +140 -0
- autobyteus/agent/handlers/tool_execution_approval_event_handler.py +85 -0
- autobyteus/agent/handlers/tool_invocation_request_event_handler.py +186 -0
- autobyteus/agent/handlers/tool_result_event_handler.py +96 -0
- autobyteus/agent/handlers/user_input_message_event_handler.py +77 -0
- autobyteus/agent/hooks/__init__.py +9 -0
- autobyteus/agent/hooks/base_phase_hook.py +52 -0
- autobyteus/agent/input_processor/__init__.py +18 -0
- autobyteus/agent/input_processor/base_user_input_processor.py +51 -0
- autobyteus/agent/input_processor/content_prefixing_input_processor.py +41 -0
- autobyteus/agent/input_processor/metadata_appending_input_processor.py +34 -0
- autobyteus/agent/input_processor/passthrough_input_processor.py +32 -0
- autobyteus/agent/input_processor/processor_definition.py +42 -0
- autobyteus/agent/input_processor/processor_meta.py +46 -0
- autobyteus/agent/input_processor/processor_registry.py +98 -0
- autobyteus/agent/llm_response_processor/__init__.py +16 -0
- autobyteus/agent/llm_response_processor/base_processor.py +50 -0
- autobyteus/agent/llm_response_processor/processor_definition.py +36 -0
- autobyteus/agent/llm_response_processor/processor_meta.py +37 -0
- autobyteus/agent/llm_response_processor/processor_registry.py +94 -0
- autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +53 -0
- autobyteus/agent/message/__init__.py +20 -0
- autobyteus/agent/message/agent_input_user_message.py +96 -0
- autobyteus/agent/message/context_file.py +82 -0
- autobyteus/agent/message/context_file_type.py +64 -0
- autobyteus/agent/message/{message.py → inter_agent_message.py} +12 -12
- autobyteus/agent/message/{message_types.py → inter_agent_message_type.py} +8 -6
- autobyteus/agent/message/send_message_to.py +142 -36
- autobyteus/agent/remote_agent.py +240 -5
- autobyteus/agent/runtime/__init__.py +15 -0
- autobyteus/agent/runtime/agent_runtime.py +139 -0
- autobyteus/agent/runtime/agent_thread_pool_manager.py +88 -0
- autobyteus/agent/runtime/agent_worker.py +200 -0
- autobyteus/agent/streaming/__init__.py +15 -0
- autobyteus/agent/streaming/agent_event_stream.py +120 -0
- autobyteus/agent/streaming/queue_streamer.py +58 -0
- autobyteus/agent/streaming/stream_event_payloads.py +156 -0
- autobyteus/agent/streaming/stream_events.py +123 -0
- autobyteus/agent/system_prompt_processor/__init__.py +14 -0
- autobyteus/agent/system_prompt_processor/base_processor.py +45 -0
- autobyteus/agent/system_prompt_processor/processor_definition.py +40 -0
- autobyteus/agent/system_prompt_processor/processor_meta.py +47 -0
- autobyteus/agent/system_prompt_processor/processor_registry.py +119 -0
- autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +65 -0
- autobyteus/agent/tool_invocation.py +28 -5
- autobyteus/agent/utils/__init__.py +9 -0
- autobyteus/agent/utils/wait_for_idle.py +59 -0
- autobyteus/agent/workflow/__init__.py +11 -0
- autobyteus/agent/workflow/agentic_workflow.py +89 -0
- autobyteus/agent/workflow/base_agentic_workflow.py +98 -0
- autobyteus/agent/workspace/__init__.py +9 -0
- autobyteus/agent/workspace/base_workspace.py +55 -0
- autobyteus/cli/__init__.py +10 -0
- autobyteus/cli/agent_cli.py +299 -0
- autobyteus/events/event_emitter.py +33 -56
- autobyteus/events/event_manager.py +133 -66
- autobyteus/events/event_types.py +41 -14
- autobyteus/llm/api/autobyteus_llm.py +13 -15
- autobyteus/llm/api/bedrock_llm.py +9 -3
- autobyteus/llm/api/claude_llm.py +10 -5
- autobyteus/llm/api/deepseek_llm.py +53 -91
- autobyteus/llm/api/gemini_llm.py +10 -4
- autobyteus/llm/api/grok_llm.py +53 -77
- autobyteus/llm/api/groq_llm.py +10 -5
- autobyteus/llm/api/mistral_llm.py +10 -5
- autobyteus/llm/api/nvidia_llm.py +9 -4
- autobyteus/llm/api/ollama_llm.py +56 -48
- autobyteus/llm/api/openai_llm.py +20 -14
- autobyteus/llm/base_llm.py +95 -34
- autobyteus/llm/extensions/base_extension.py +3 -4
- autobyteus/llm/extensions/token_usage_tracking_extension.py +2 -3
- autobyteus/llm/llm_factory.py +12 -13
- autobyteus/llm/models.py +87 -8
- autobyteus/llm/user_message.py +73 -0
- autobyteus/llm/utils/llm_config.py +124 -27
- autobyteus/llm/utils/response_types.py +3 -2
- autobyteus/llm/utils/token_usage.py +7 -4
- autobyteus/rpc/__init__.py +73 -0
- autobyteus/rpc/client/__init__.py +17 -0
- autobyteus/rpc/client/abstract_client_connection.py +124 -0
- autobyteus/rpc/client/client_connection_manager.py +153 -0
- autobyteus/rpc/client/sse_client_connection.py +306 -0
- autobyteus/rpc/client/stdio_client_connection.py +280 -0
- autobyteus/rpc/config/__init__.py +13 -0
- autobyteus/rpc/config/agent_server_config.py +153 -0
- autobyteus/rpc/config/agent_server_registry.py +152 -0
- autobyteus/rpc/hosting.py +244 -0
- autobyteus/rpc/protocol.py +244 -0
- autobyteus/rpc/server/__init__.py +20 -0
- autobyteus/rpc/server/agent_server_endpoint.py +181 -0
- autobyteus/rpc/server/base_method_handler.py +40 -0
- autobyteus/rpc/server/method_handlers.py +259 -0
- autobyteus/rpc/server/sse_server_handler.py +182 -0
- autobyteus/rpc/server/stdio_server_handler.py +151 -0
- autobyteus/rpc/server_main.py +198 -0
- autobyteus/rpc/transport_type.py +13 -0
- autobyteus/tools/__init__.py +75 -0
- autobyteus/tools/ask_user_input.py +34 -77
- autobyteus/tools/base_tool.py +66 -37
- autobyteus/tools/bash/__init__.py +2 -0
- autobyteus/tools/bash/bash_executor.py +42 -79
- autobyteus/tools/browser/__init__.py +2 -0
- autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +50 -42
- autobyteus/tools/browser/session_aware/browser_session_aware_tool.py +7 -4
- autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +117 -125
- autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +75 -22
- autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +94 -28
- autobyteus/tools/browser/session_aware/factory/browser_session_aware_web_element_trigger_factory.py +10 -2
- autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_reader_factory.py +18 -2
- autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_screenshot_taker_factory.py +10 -2
- autobyteus/tools/browser/session_aware/shared_browser_session_manager.py +4 -3
- autobyteus/tools/browser/standalone/__init__.py +7 -0
- autobyteus/tools/browser/standalone/factory/google_search_factory.py +17 -2
- autobyteus/tools/browser/standalone/factory/webpage_reader_factory.py +17 -2
- autobyteus/tools/browser/standalone/factory/webpage_screenshot_taker_factory.py +10 -2
- autobyteus/tools/browser/standalone/google_search_ui.py +104 -67
- autobyteus/tools/browser/standalone/navigate_to.py +52 -28
- autobyteus/tools/browser/standalone/web_page_pdf_generator.py +94 -0
- autobyteus/tools/browser/standalone/webpage_image_downloader.py +146 -61
- autobyteus/tools/browser/standalone/webpage_reader.py +80 -61
- autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +91 -45
- autobyteus/tools/factory/__init__.py +9 -0
- autobyteus/tools/factory/tool_factory.py +25 -4
- autobyteus/tools/file/file_reader.py +22 -51
- autobyteus/tools/file/file_writer.py +25 -56
- autobyteus/tools/functional_tool.py +234 -0
- autobyteus/tools/image_downloader.py +49 -71
- autobyteus/tools/mcp/__init__.py +47 -0
- autobyteus/tools/mcp/call_handlers/__init__.py +18 -0
- autobyteus/tools/mcp/call_handlers/base_handler.py +40 -0
- autobyteus/tools/mcp/call_handlers/sse_handler.py +22 -0
- autobyteus/tools/mcp/call_handlers/stdio_handler.py +62 -0
- autobyteus/tools/mcp/call_handlers/streamable_http_handler.py +55 -0
- autobyteus/tools/mcp/config_service.py +258 -0
- autobyteus/tools/mcp/factory.py +70 -0
- autobyteus/tools/mcp/registrar.py +135 -0
- autobyteus/tools/mcp/schema_mapper.py +131 -0
- autobyteus/tools/mcp/tool.py +101 -0
- autobyteus/tools/mcp/types.py +96 -0
- autobyteus/tools/parameter_schema.py +268 -0
- autobyteus/tools/pdf_downloader.py +78 -79
- autobyteus/tools/registry/__init__.py +0 -2
- autobyteus/tools/registry/tool_definition.py +106 -34
- autobyteus/tools/registry/tool_registry.py +46 -22
- autobyteus/tools/timer.py +150 -102
- autobyteus/tools/tool_config.py +117 -0
- autobyteus/tools/tool_meta.py +48 -26
- autobyteus/tools/usage/__init__.py +6 -0
- autobyteus/tools/usage/formatters/__init__.py +31 -0
- autobyteus/tools/usage/formatters/anthropic_json_example_formatter.py +18 -0
- autobyteus/tools/usage/formatters/anthropic_json_schema_formatter.py +25 -0
- autobyteus/tools/usage/formatters/base_formatter.py +42 -0
- autobyteus/tools/usage/formatters/default_json_example_formatter.py +42 -0
- autobyteus/tools/usage/formatters/default_json_schema_formatter.py +28 -0
- autobyteus/tools/usage/formatters/default_xml_example_formatter.py +55 -0
- autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +46 -0
- autobyteus/tools/usage/formatters/gemini_json_example_formatter.py +34 -0
- autobyteus/tools/usage/formatters/gemini_json_schema_formatter.py +25 -0
- autobyteus/tools/usage/formatters/google_json_example_formatter.py +34 -0
- autobyteus/tools/usage/formatters/google_json_schema_formatter.py +25 -0
- autobyteus/tools/usage/formatters/openai_json_example_formatter.py +49 -0
- autobyteus/tools/usage/formatters/openai_json_schema_formatter.py +28 -0
- autobyteus/tools/usage/parsers/__init__.py +22 -0
- autobyteus/tools/usage/parsers/anthropic_xml_tool_usage_parser.py +10 -0
- autobyteus/tools/usage/parsers/base_parser.py +41 -0
- autobyteus/tools/usage/parsers/default_json_tool_usage_parser.py +106 -0
- autobyteus/tools/usage/parsers/default_xml_tool_usage_parser.py +135 -0
- autobyteus/tools/usage/parsers/exceptions.py +13 -0
- autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +68 -0
- autobyteus/tools/usage/parsers/openai_json_tool_usage_parser.py +147 -0
- autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +67 -0
- autobyteus/tools/usage/providers/__init__.py +22 -0
- autobyteus/tools/usage/providers/json_example_provider.py +32 -0
- autobyteus/tools/usage/providers/json_schema_provider.py +35 -0
- autobyteus/tools/usage/providers/json_tool_usage_parser_provider.py +28 -0
- autobyteus/tools/usage/providers/tool_manifest_provider.py +68 -0
- autobyteus/tools/usage/providers/xml_example_provider.py +28 -0
- autobyteus/tools/usage/providers/xml_schema_provider.py +29 -0
- autobyteus/tools/usage/providers/xml_tool_usage_parser_provider.py +26 -0
- autobyteus/tools/usage/registries/__init__.py +20 -0
- autobyteus/tools/usage/registries/json_example_formatter_registry.py +51 -0
- autobyteus/tools/usage/registries/json_schema_formatter_registry.py +51 -0
- autobyteus/tools/usage/registries/json_tool_usage_parser_registry.py +42 -0
- autobyteus/tools/usage/registries/xml_example_formatter_registry.py +30 -0
- autobyteus/tools/usage/registries/xml_schema_formatter_registry.py +33 -0
- autobyteus/tools/usage/registries/xml_tool_usage_parser_registry.py +30 -0
- {autobyteus-1.0.5.dist-info → autobyteus-1.1.0.dist-info}/METADATA +21 -3
- autobyteus-1.1.0.dist-info/RECORD +279 -0
- {autobyteus-1.0.5.dist-info → autobyteus-1.1.0.dist-info}/WHEEL +1 -1
- autobyteus/agent/async_agent.py +0 -175
- autobyteus/agent/async_group_aware_agent.py +0 -136
- autobyteus/agent/group/async_group_aware_agent.py +0 -122
- autobyteus/agent/group/coordinator_agent.py +0 -36
- autobyteus/agent/group/group_aware_agent.py +0 -121
- autobyteus/agent/orchestrator/__init__.py +0 -0
- autobyteus/agent/orchestrator/base_agent_orchestrator.py +0 -82
- autobyteus/agent/orchestrator/multi_replica_agent_orchestrator.py +0 -72
- autobyteus/agent/orchestrator/single_replica_agent_orchestrator.py +0 -43
- autobyteus/agent/registry/__init__.py +0 -11
- autobyteus/agent/registry/agent_definition.py +0 -94
- autobyteus/agent/registry/agent_registry.py +0 -114
- autobyteus/agent/response_parser/__init__.py +0 -0
- autobyteus/agent/response_parser/tool_usage_command_parser.py +0 -100
- autobyteus/agent/status.py +0 -12
- autobyteus/conversation/__init__.py +0 -0
- autobyteus/conversation/conversation.py +0 -54
- autobyteus/conversation/user_message.py +0 -59
- autobyteus/events/decorators.py +0 -29
- autobyteus/prompt/prompt_version_manager.py +0 -58
- autobyteus/prompt/storage/__init__.py +0 -0
- autobyteus/prompt/storage/prompt_version_model.py +0 -29
- autobyteus/prompt/storage/prompt_version_repository.py +0 -83
- autobyteus/tools/bash/factory/__init__.py +0 -0
- autobyteus/tools/bash/factory/bash_executor_factory.py +0 -6
- autobyteus/tools/factory/ask_user_input_factory.py +0 -6
- autobyteus/tools/factory/image_downloader_factory.py +0 -9
- autobyteus/tools/factory/pdf_downloader_factory.py +0 -9
- autobyteus/tools/factory/webpage_image_downloader_factory.py +0 -6
- autobyteus/tools/file/factory/__init__.py +0 -0
- autobyteus/tools/file/factory/file_reader_factory.py +0 -6
- autobyteus/tools/file/factory/file_writer_factory.py +0 -6
- autobyteus/tools/mcp_remote_tool.py +0 -82
- autobyteus/tools/web_page_pdf_generator.py +0 -90
- autobyteus-1.0.5.dist-info/RECORD +0 -163
- {autobyteus-1.0.5.dist-info → autobyteus-1.1.0.dist-info}/licenses/LICENSE +0 -0
- {autobyteus-1.0.5.dist-info → autobyteus-1.1.0.dist-info}/top_level.txt +0 -0
autobyteus/agent/async_agent.py
DELETED
|
@@ -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
|