autobyteus 1.1.3__py3-none-any.whl → 1.1.5__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 +1 -1
- autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +4 -2
- autobyteus/agent/context/__init__.py +4 -2
- autobyteus/agent/context/agent_config.py +35 -8
- autobyteus/agent/context/agent_context_registry.py +73 -0
- autobyteus/agent/events/notifiers.py +4 -0
- autobyteus/agent/events/worker_event_dispatcher.py +1 -2
- autobyteus/agent/handlers/inter_agent_message_event_handler.py +8 -3
- autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +19 -19
- autobyteus/agent/handlers/llm_user_message_ready_event_handler.py +2 -2
- autobyteus/agent/handlers/tool_result_event_handler.py +48 -20
- autobyteus/agent/handlers/user_input_message_event_handler.py +16 -1
- autobyteus/agent/input_processor/__init__.py +1 -7
- autobyteus/agent/message/context_file_type.py +6 -0
- autobyteus/agent/message/send_message_to.py +74 -99
- autobyteus/agent/phases/discover.py +2 -1
- autobyteus/agent/runtime/agent_runtime.py +10 -2
- autobyteus/agent/runtime/agent_worker.py +1 -0
- autobyteus/agent/sender_type.py +15 -0
- autobyteus/agent/streaming/agent_event_stream.py +6 -0
- autobyteus/agent/streaming/stream_event_payloads.py +12 -0
- autobyteus/agent/streaming/stream_events.py +3 -0
- autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +7 -4
- autobyteus/agent/tool_execution_result_processor/__init__.py +9 -0
- autobyteus/agent/tool_execution_result_processor/base_processor.py +46 -0
- autobyteus/agent/tool_execution_result_processor/processor_definition.py +36 -0
- autobyteus/agent/tool_execution_result_processor/processor_meta.py +36 -0
- autobyteus/agent/tool_execution_result_processor/processor_registry.py +70 -0
- autobyteus/agent/workspace/base_workspace.py +17 -2
- autobyteus/agent_team/__init__.py +1 -0
- autobyteus/agent_team/agent_team.py +93 -0
- autobyteus/agent_team/agent_team_builder.py +184 -0
- autobyteus/agent_team/base_agent_team.py +86 -0
- autobyteus/agent_team/bootstrap_steps/__init__.py +24 -0
- autobyteus/agent_team/bootstrap_steps/agent_configuration_preparation_step.py +73 -0
- autobyteus/agent_team/bootstrap_steps/agent_team_bootstrapper.py +54 -0
- autobyteus/agent_team/bootstrap_steps/agent_team_runtime_queue_initialization_step.py +25 -0
- autobyteus/agent_team/bootstrap_steps/base_agent_team_bootstrap_step.py +23 -0
- autobyteus/agent_team/bootstrap_steps/coordinator_initialization_step.py +41 -0
- autobyteus/agent_team/bootstrap_steps/coordinator_prompt_preparation_step.py +85 -0
- autobyteus/agent_team/bootstrap_steps/task_notifier_initialization_step.py +51 -0
- autobyteus/agent_team/bootstrap_steps/team_context_initialization_step.py +45 -0
- autobyteus/agent_team/context/__init__.py +17 -0
- autobyteus/agent_team/context/agent_team_config.py +33 -0
- autobyteus/agent_team/context/agent_team_context.py +61 -0
- autobyteus/agent_team/context/agent_team_runtime_state.py +56 -0
- autobyteus/agent_team/context/team_manager.py +147 -0
- autobyteus/agent_team/context/team_node_config.py +76 -0
- autobyteus/agent_team/events/__init__.py +29 -0
- autobyteus/agent_team/events/agent_team_event_dispatcher.py +39 -0
- autobyteus/agent_team/events/agent_team_events.py +53 -0
- autobyteus/agent_team/events/agent_team_input_event_queue_manager.py +21 -0
- autobyteus/agent_team/exceptions.py +8 -0
- autobyteus/agent_team/factory/__init__.py +9 -0
- autobyteus/agent_team/factory/agent_team_factory.py +99 -0
- autobyteus/agent_team/handlers/__init__.py +19 -0
- autobyteus/agent_team/handlers/agent_team_event_handler_registry.py +23 -0
- autobyteus/agent_team/handlers/base_agent_team_event_handler.py +16 -0
- autobyteus/agent_team/handlers/inter_agent_message_request_event_handler.py +61 -0
- autobyteus/agent_team/handlers/lifecycle_agent_team_event_handler.py +27 -0
- autobyteus/agent_team/handlers/process_user_message_event_handler.py +46 -0
- autobyteus/agent_team/handlers/tool_approval_team_event_handler.py +48 -0
- autobyteus/agent_team/phases/__init__.py +11 -0
- autobyteus/agent_team/phases/agent_team_operational_phase.py +19 -0
- autobyteus/agent_team/phases/agent_team_phase_manager.py +48 -0
- autobyteus/agent_team/runtime/__init__.py +13 -0
- autobyteus/agent_team/runtime/agent_team_runtime.py +82 -0
- autobyteus/agent_team/runtime/agent_team_worker.py +117 -0
- autobyteus/agent_team/shutdown_steps/__init__.py +17 -0
- autobyteus/agent_team/shutdown_steps/agent_team_shutdown_orchestrator.py +35 -0
- autobyteus/agent_team/shutdown_steps/agent_team_shutdown_step.py +42 -0
- autobyteus/agent_team/shutdown_steps/base_agent_team_shutdown_step.py +16 -0
- autobyteus/agent_team/shutdown_steps/bridge_cleanup_step.py +28 -0
- autobyteus/agent_team/shutdown_steps/sub_team_shutdown_step.py +41 -0
- autobyteus/agent_team/streaming/__init__.py +26 -0
- autobyteus/agent_team/streaming/agent_event_bridge.py +48 -0
- autobyteus/agent_team/streaming/agent_event_multiplexer.py +70 -0
- autobyteus/agent_team/streaming/agent_team_event_notifier.py +64 -0
- autobyteus/agent_team/streaming/agent_team_event_stream.py +33 -0
- autobyteus/agent_team/streaming/agent_team_stream_event_payloads.py +32 -0
- autobyteus/agent_team/streaming/agent_team_stream_events.py +56 -0
- autobyteus/agent_team/streaming/team_event_bridge.py +50 -0
- autobyteus/agent_team/task_notification/__init__.py +11 -0
- autobyteus/agent_team/task_notification/system_event_driven_agent_task_notifier.py +164 -0
- autobyteus/agent_team/task_notification/task_notification_mode.py +24 -0
- autobyteus/agent_team/utils/__init__.py +9 -0
- autobyteus/agent_team/utils/wait_for_idle.py +46 -0
- autobyteus/cli/__init__.py +1 -1
- autobyteus/cli/agent_team_tui/__init__.py +4 -0
- autobyteus/cli/agent_team_tui/app.py +210 -0
- autobyteus/cli/agent_team_tui/state.py +180 -0
- autobyteus/cli/agent_team_tui/widgets/__init__.py +6 -0
- autobyteus/cli/agent_team_tui/widgets/agent_list_sidebar.py +149 -0
- autobyteus/cli/agent_team_tui/widgets/focus_pane.py +320 -0
- autobyteus/cli/agent_team_tui/widgets/logo.py +20 -0
- autobyteus/cli/agent_team_tui/widgets/renderables.py +77 -0
- autobyteus/cli/agent_team_tui/widgets/shared.py +60 -0
- autobyteus/cli/agent_team_tui/widgets/status_bar.py +14 -0
- autobyteus/cli/agent_team_tui/widgets/task_board_panel.py +82 -0
- autobyteus/cli/cli_display.py +1 -1
- autobyteus/cli/workflow_tui/__init__.py +4 -0
- autobyteus/cli/workflow_tui/app.py +210 -0
- autobyteus/cli/workflow_tui/state.py +189 -0
- autobyteus/cli/workflow_tui/widgets/__init__.py +6 -0
- autobyteus/cli/workflow_tui/widgets/agent_list_sidebar.py +149 -0
- autobyteus/cli/workflow_tui/widgets/focus_pane.py +335 -0
- autobyteus/cli/workflow_tui/widgets/logo.py +27 -0
- autobyteus/cli/workflow_tui/widgets/renderables.py +70 -0
- autobyteus/cli/workflow_tui/widgets/shared.py +51 -0
- autobyteus/cli/workflow_tui/widgets/status_bar.py +14 -0
- autobyteus/events/event_types.py +8 -0
- autobyteus/llm/api/autobyteus_llm.py +11 -12
- autobyteus/llm/api/lmstudio_llm.py +34 -0
- autobyteus/llm/api/ollama_llm.py +8 -13
- autobyteus/llm/api/openai_compatible_llm.py +20 -3
- autobyteus/llm/autobyteus_provider.py +73 -46
- autobyteus/llm/llm_factory.py +103 -139
- autobyteus/llm/lmstudio_provider.py +104 -0
- autobyteus/llm/models.py +83 -53
- autobyteus/llm/ollama_provider.py +69 -61
- autobyteus/llm/ollama_provider_resolver.py +1 -0
- autobyteus/llm/providers.py +13 -12
- autobyteus/llm/runtimes.py +11 -0
- autobyteus/llm/token_counter/token_counter_factory.py +2 -0
- autobyteus/task_management/__init__.py +43 -0
- autobyteus/task_management/base_task_board.py +68 -0
- autobyteus/task_management/converters/__init__.py +11 -0
- autobyteus/task_management/converters/task_board_converter.py +64 -0
- autobyteus/task_management/converters/task_plan_converter.py +48 -0
- autobyteus/task_management/deliverable.py +16 -0
- autobyteus/task_management/deliverables/__init__.py +8 -0
- autobyteus/task_management/deliverables/file_deliverable.py +15 -0
- autobyteus/task_management/events.py +27 -0
- autobyteus/task_management/in_memory_task_board.py +126 -0
- autobyteus/task_management/schemas/__init__.py +15 -0
- autobyteus/task_management/schemas/deliverable_schema.py +13 -0
- autobyteus/task_management/schemas/plan_definition.py +35 -0
- autobyteus/task_management/schemas/task_status_report.py +27 -0
- autobyteus/task_management/task_plan.py +110 -0
- autobyteus/task_management/tools/__init__.py +14 -0
- autobyteus/task_management/tools/get_task_board_status.py +68 -0
- autobyteus/task_management/tools/publish_task_plan.py +113 -0
- autobyteus/task_management/tools/update_task_status.py +135 -0
- autobyteus/tools/__init__.py +2 -0
- autobyteus/tools/ask_user_input.py +2 -1
- autobyteus/tools/bash/bash_executor.py +61 -15
- autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +2 -0
- autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +3 -0
- autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +3 -0
- autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +3 -0
- autobyteus/tools/browser/standalone/google_search_ui.py +2 -0
- autobyteus/tools/browser/standalone/navigate_to.py +2 -0
- autobyteus/tools/browser/standalone/web_page_pdf_generator.py +3 -0
- autobyteus/tools/browser/standalone/webpage_image_downloader.py +3 -0
- autobyteus/tools/browser/standalone/webpage_reader.py +2 -0
- autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +3 -0
- autobyteus/tools/file/file_reader.py +36 -9
- autobyteus/tools/file/file_writer.py +37 -9
- autobyteus/tools/functional_tool.py +5 -4
- autobyteus/tools/image_downloader.py +2 -0
- autobyteus/tools/mcp/config_service.py +63 -58
- autobyteus/tools/mcp/server/http_managed_mcp_server.py +14 -2
- autobyteus/tools/mcp/server/stdio_managed_mcp_server.py +14 -2
- autobyteus/tools/mcp/server_instance_manager.py +30 -4
- autobyteus/tools/mcp/tool_registrar.py +106 -51
- autobyteus/tools/parameter_schema.py +17 -11
- autobyteus/tools/pdf_downloader.py +2 -1
- autobyteus/tools/registry/tool_definition.py +36 -37
- autobyteus/tools/registry/tool_registry.py +50 -2
- autobyteus/tools/timer.py +2 -0
- autobyteus/tools/tool_category.py +15 -4
- autobyteus/tools/tool_meta.py +6 -1
- autobyteus/tools/tool_origin.py +10 -0
- autobyteus/tools/usage/formatters/default_json_example_formatter.py +78 -3
- autobyteus/tools/usage/formatters/default_xml_example_formatter.py +23 -3
- autobyteus/tools/usage/formatters/gemini_json_example_formatter.py +6 -0
- autobyteus/tools/usage/formatters/google_json_example_formatter.py +7 -0
- autobyteus/tools/usage/formatters/openai_json_example_formatter.py +6 -4
- autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +23 -7
- autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +14 -25
- autobyteus/tools/usage/providers/__init__.py +2 -12
- autobyteus/tools/usage/providers/tool_manifest_provider.py +36 -29
- autobyteus/tools/usage/registries/__init__.py +7 -12
- autobyteus/tools/usage/registries/tool_formatter_pair.py +15 -0
- autobyteus/tools/usage/registries/tool_formatting_registry.py +58 -0
- autobyteus/tools/usage/registries/tool_usage_parser_registry.py +55 -0
- autobyteus/workflow/agentic_workflow.py +93 -0
- autobyteus/{agent/workflow → workflow}/base_agentic_workflow.py +19 -27
- autobyteus/workflow/bootstrap_steps/__init__.py +20 -0
- autobyteus/workflow/bootstrap_steps/agent_tool_injection_step.py +34 -0
- autobyteus/workflow/bootstrap_steps/base_workflow_bootstrap_step.py +23 -0
- autobyteus/workflow/bootstrap_steps/coordinator_initialization_step.py +41 -0
- autobyteus/workflow/bootstrap_steps/coordinator_prompt_preparation_step.py +108 -0
- autobyteus/workflow/bootstrap_steps/workflow_bootstrapper.py +50 -0
- autobyteus/workflow/bootstrap_steps/workflow_runtime_queue_initialization_step.py +25 -0
- autobyteus/workflow/context/__init__.py +17 -0
- autobyteus/workflow/context/team_manager.py +147 -0
- autobyteus/workflow/context/workflow_config.py +30 -0
- autobyteus/workflow/context/workflow_context.py +61 -0
- autobyteus/workflow/context/workflow_node_config.py +76 -0
- autobyteus/workflow/context/workflow_runtime_state.py +53 -0
- autobyteus/workflow/events/__init__.py +29 -0
- autobyteus/workflow/events/workflow_event_dispatcher.py +39 -0
- autobyteus/workflow/events/workflow_events.py +53 -0
- autobyteus/workflow/events/workflow_input_event_queue_manager.py +21 -0
- autobyteus/workflow/exceptions.py +8 -0
- autobyteus/workflow/factory/__init__.py +9 -0
- autobyteus/workflow/factory/workflow_factory.py +99 -0
- autobyteus/workflow/handlers/__init__.py +19 -0
- autobyteus/workflow/handlers/base_workflow_event_handler.py +16 -0
- autobyteus/workflow/handlers/inter_agent_message_request_event_handler.py +61 -0
- autobyteus/workflow/handlers/lifecycle_workflow_event_handler.py +27 -0
- autobyteus/workflow/handlers/process_user_message_event_handler.py +46 -0
- autobyteus/workflow/handlers/tool_approval_workflow_event_handler.py +39 -0
- autobyteus/workflow/handlers/workflow_event_handler_registry.py +23 -0
- autobyteus/workflow/phases/__init__.py +11 -0
- autobyteus/workflow/phases/workflow_operational_phase.py +19 -0
- autobyteus/workflow/phases/workflow_phase_manager.py +48 -0
- autobyteus/workflow/runtime/__init__.py +13 -0
- autobyteus/workflow/runtime/workflow_runtime.py +82 -0
- autobyteus/workflow/runtime/workflow_worker.py +117 -0
- autobyteus/workflow/shutdown_steps/__init__.py +17 -0
- autobyteus/workflow/shutdown_steps/agent_team_shutdown_step.py +42 -0
- autobyteus/workflow/shutdown_steps/base_workflow_shutdown_step.py +16 -0
- autobyteus/workflow/shutdown_steps/bridge_cleanup_step.py +28 -0
- autobyteus/workflow/shutdown_steps/sub_workflow_shutdown_step.py +41 -0
- autobyteus/workflow/shutdown_steps/workflow_shutdown_orchestrator.py +35 -0
- autobyteus/workflow/streaming/__init__.py +26 -0
- autobyteus/workflow/streaming/agent_event_bridge.py +48 -0
- autobyteus/workflow/streaming/agent_event_multiplexer.py +70 -0
- autobyteus/workflow/streaming/workflow_event_bridge.py +50 -0
- autobyteus/workflow/streaming/workflow_event_notifier.py +83 -0
- autobyteus/workflow/streaming/workflow_event_stream.py +33 -0
- autobyteus/workflow/streaming/workflow_stream_event_payloads.py +28 -0
- autobyteus/workflow/streaming/workflow_stream_events.py +45 -0
- autobyteus/workflow/utils/__init__.py +9 -0
- autobyteus/workflow/utils/wait_for_idle.py +46 -0
- autobyteus/workflow/workflow_builder.py +151 -0
- {autobyteus-1.1.3.dist-info → autobyteus-1.1.5.dist-info}/METADATA +16 -14
- autobyteus-1.1.5.dist-info/RECORD +455 -0
- {autobyteus-1.1.3.dist-info → autobyteus-1.1.5.dist-info}/top_level.txt +1 -0
- examples/__init__.py +1 -0
- examples/agent_team/__init__.py +1 -0
- examples/discover_phase_transitions.py +104 -0
- examples/run_browser_agent.py +262 -0
- examples/run_google_slides_agent.py +287 -0
- examples/run_mcp_browser_client.py +174 -0
- examples/run_mcp_google_slides_client.py +270 -0
- examples/run_mcp_list_tools.py +189 -0
- examples/run_poem_writer.py +284 -0
- examples/run_sqlite_agent.py +295 -0
- autobyteus/agent/context/agent_phase_manager.py +0 -264
- autobyteus/agent/context/phases.py +0 -49
- autobyteus/agent/group/__init__.py +0 -0
- autobyteus/agent/group/agent_group.py +0 -164
- autobyteus/agent/group/agent_group_context.py +0 -81
- autobyteus/agent/input_processor/content_prefixing_input_processor.py +0 -41
- autobyteus/agent/input_processor/metadata_appending_input_processor.py +0 -34
- autobyteus/agent/input_processor/passthrough_input_processor.py +0 -33
- autobyteus/agent/workflow/__init__.py +0 -11
- autobyteus/agent/workflow/agentic_workflow.py +0 -89
- autobyteus/tools/mcp/call_handlers/__init__.py +0 -16
- autobyteus/tools/mcp/call_handlers/base_handler.py +0 -40
- autobyteus/tools/mcp/call_handlers/stdio_handler.py +0 -76
- autobyteus/tools/mcp/call_handlers/streamable_http_handler.py +0 -55
- autobyteus/tools/mcp/registrar.py +0 -202
- autobyteus/tools/usage/providers/json_example_provider.py +0 -32
- autobyteus/tools/usage/providers/json_schema_provider.py +0 -35
- autobyteus/tools/usage/providers/json_tool_usage_parser_provider.py +0 -28
- autobyteus/tools/usage/providers/xml_example_provider.py +0 -28
- autobyteus/tools/usage/providers/xml_schema_provider.py +0 -29
- autobyteus/tools/usage/providers/xml_tool_usage_parser_provider.py +0 -26
- autobyteus/tools/usage/registries/json_example_formatter_registry.py +0 -51
- autobyteus/tools/usage/registries/json_schema_formatter_registry.py +0 -51
- autobyteus/tools/usage/registries/json_tool_usage_parser_registry.py +0 -42
- autobyteus/tools/usage/registries/xml_example_formatter_registry.py +0 -30
- autobyteus/tools/usage/registries/xml_schema_formatter_registry.py +0 -33
- autobyteus/tools/usage/registries/xml_tool_usage_parser_registry.py +0 -30
- autobyteus/workflow/simple_task.py +0 -98
- autobyteus/workflow/task.py +0 -147
- autobyteus/workflow/workflow.py +0 -49
- autobyteus-1.1.3.dist-info/RECORD +0 -312
- {autobyteus-1.1.3.dist-info → autobyteus-1.1.5.dist-info}/WHEEL +0 -0
- {autobyteus-1.1.3.dist-info → autobyteus-1.1.5.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# file: autobyteus/autobyteus/agent/workspace/base_workspace.py
|
|
2
2
|
import logging
|
|
3
|
+
import uuid
|
|
3
4
|
from abc import ABC, abstractmethod
|
|
4
5
|
from typing import Optional, Any, Dict, TYPE_CHECKING
|
|
5
6
|
from autobyteus.tools.parameter_schema import ParameterSchema
|
|
@@ -29,7 +30,8 @@ class BaseAgentWorkspace(ABC, metaclass=WorkspaceMeta):
|
|
|
29
30
|
"""
|
|
30
31
|
self._config: WorkspaceConfig = config or WorkspaceConfig()
|
|
31
32
|
self.context: Optional['AgentContext'] = None
|
|
32
|
-
|
|
33
|
+
self.workspace_id: str = str(uuid.uuid4())
|
|
34
|
+
logger.debug(f"{self.__class__.__name__} instance initialized with ID {self.workspace_id}. Context pending injection.")
|
|
33
35
|
|
|
34
36
|
def set_context(self, context: 'AgentContext'):
|
|
35
37
|
"""
|
|
@@ -53,6 +55,19 @@ class BaseAgentWorkspace(ABC, metaclass=WorkspaceMeta):
|
|
|
53
55
|
"""Configuration for the workspace. Implementations can use this as needed."""
|
|
54
56
|
return self._config
|
|
55
57
|
|
|
58
|
+
@abstractmethod
|
|
59
|
+
def get_base_path(self) -> str:
|
|
60
|
+
"""Returns the base path for the workspace, which can be used to resolve relative paths."""
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
def get_name(self) -> str:
|
|
64
|
+
"""
|
|
65
|
+
Returns a user-friendly name for this workspace instance.
|
|
66
|
+
By default, it returns the unique workspace ID.
|
|
67
|
+
Subclasses can override this to provide a more descriptive name (e.g., a directory name).
|
|
68
|
+
"""
|
|
69
|
+
return self.workspace_id
|
|
70
|
+
|
|
56
71
|
# --- Methods for self-description ---
|
|
57
72
|
|
|
58
73
|
@classmethod
|
|
@@ -74,4 +89,4 @@ class BaseAgentWorkspace(ABC, metaclass=WorkspaceMeta):
|
|
|
74
89
|
pass
|
|
75
90
|
|
|
76
91
|
def __repr__(self) -> str:
|
|
77
|
-
return f"<{self.__class__.__name__} agent_id='{self.agent_id or 'N/A'}>"
|
|
92
|
+
return f"<{self.__class__.__name__} workspace_id='{self.workspace_id}' agent_id='{self.agent_id or 'N/A'}>"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/agent_team/__init__.py
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/agent_team/agent_team.py
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from autobyteus.agent_team.runtime.agent_team_runtime import AgentTeamRuntime
|
|
6
|
+
from autobyteus.agent_team.events.agent_team_events import ProcessUserMessageEvent, ToolApprovalTeamEvent
|
|
7
|
+
from autobyteus.agent.message.agent_input_user_message import AgentInputUserMessage
|
|
8
|
+
from autobyteus.agent_team.phases.agent_team_operational_phase import AgentTeamOperationalPhase
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
class AgentTeam:
|
|
13
|
+
"""
|
|
14
|
+
User-facing facade for interacting with a managed agent team.
|
|
15
|
+
This class is a lightweight wrapper around an AgentTeamRuntime instance
|
|
16
|
+
and is typically created by an AgentTeamFactory.
|
|
17
|
+
"""
|
|
18
|
+
def __init__(self, runtime: AgentTeamRuntime):
|
|
19
|
+
"""
|
|
20
|
+
Initializes the AgentTeam facade.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
runtime: The pre-configured and ready-to-use runtime for the agent team.
|
|
24
|
+
"""
|
|
25
|
+
if not isinstance(runtime, AgentTeamRuntime):
|
|
26
|
+
raise TypeError(f"AgentTeam requires an AgentTeamRuntime instance, got {type(runtime).__name__}")
|
|
27
|
+
|
|
28
|
+
self._runtime = runtime
|
|
29
|
+
self.team_id: str = self._runtime.context.team_id
|
|
30
|
+
logger.info(f"AgentTeam facade created for team ID '{self.team_id}'.")
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def name(self) -> str:
|
|
34
|
+
return self._runtime.context.config.name
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def role(self) -> Optional[str]:
|
|
38
|
+
"""The role of the team, for when it's used as a sub-team."""
|
|
39
|
+
return self._runtime.context.config.role
|
|
40
|
+
|
|
41
|
+
async def post_message(self, message: AgentInputUserMessage, target_agent_name: Optional[str] = None) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Submits a message to the agent team, routing it to a specific node (agent or sub-team).
|
|
44
|
+
If `target_agent_name` is not provided, the message is sent to the team's coordinator.
|
|
45
|
+
"""
|
|
46
|
+
final_target_name = target_agent_name or self._runtime.context.config.coordinator_node.name
|
|
47
|
+
logger.info(f"Agent Team '{self.team_id}': post_message called. Target: '{final_target_name}'.")
|
|
48
|
+
|
|
49
|
+
if not self._runtime.is_running:
|
|
50
|
+
self.start()
|
|
51
|
+
|
|
52
|
+
event = ProcessUserMessageEvent(
|
|
53
|
+
user_message=message,
|
|
54
|
+
target_agent_name=final_target_name
|
|
55
|
+
)
|
|
56
|
+
await self._runtime.submit_event(event)
|
|
57
|
+
|
|
58
|
+
async def post_tool_execution_approval(
|
|
59
|
+
self,
|
|
60
|
+
agent_name: str,
|
|
61
|
+
tool_invocation_id: str,
|
|
62
|
+
is_approved: bool,
|
|
63
|
+
reason: Optional[str] = None
|
|
64
|
+
):
|
|
65
|
+
"""Submits a tool execution approval/denial to a specific agent in the team."""
|
|
66
|
+
logger.info(f"Agent Team '{self.team_id}': post_tool_execution_approval called for agent '{agent_name}'. Approved: {is_approved}.")
|
|
67
|
+
if not self._runtime.is_running:
|
|
68
|
+
logger.warning(f"Agent Team '{self.team_id}' is not running. Cannot post approval.")
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
event = ToolApprovalTeamEvent(
|
|
72
|
+
agent_name=agent_name,
|
|
73
|
+
tool_invocation_id=tool_invocation_id,
|
|
74
|
+
is_approved=is_approved,
|
|
75
|
+
reason=reason,
|
|
76
|
+
)
|
|
77
|
+
await self._runtime.submit_event(event)
|
|
78
|
+
|
|
79
|
+
def start(self) -> None:
|
|
80
|
+
"""Starts the agent team's background worker thread."""
|
|
81
|
+
self._runtime.start()
|
|
82
|
+
|
|
83
|
+
async def stop(self, timeout: float = 10.0) -> None:
|
|
84
|
+
"""Stops the agent team and all its agents."""
|
|
85
|
+
await self._runtime.stop(timeout)
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def is_running(self) -> bool:
|
|
89
|
+
"""Checks if the agent team's worker is running."""
|
|
90
|
+
return self._runtime.is_running
|
|
91
|
+
|
|
92
|
+
def get_current_phase(self) -> AgentTeamOperationalPhase:
|
|
93
|
+
return self._runtime.context.state.current_phase
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/agent_team/agent_team_builder.py
|
|
2
|
+
import logging
|
|
3
|
+
from typing import List, Optional, Dict, Union, Set
|
|
4
|
+
|
|
5
|
+
from autobyteus.agent_team.agent_team import AgentTeam
|
|
6
|
+
from autobyteus.agent_team.context.agent_team_config import AgentTeamConfig
|
|
7
|
+
from autobyteus.agent_team.context.team_node_config import TeamNodeConfig
|
|
8
|
+
from autobyteus.agent.context.agent_config import AgentConfig
|
|
9
|
+
from autobyteus.agent_team.factory.agent_team_factory import AgentTeamFactory
|
|
10
|
+
from autobyteus.agent_team.task_notification.task_notification_mode import TaskNotificationMode
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
# Define a type hint for the possible definition types for clarity
|
|
15
|
+
NodeDefinition = Union[AgentConfig, AgentTeamConfig]
|
|
16
|
+
|
|
17
|
+
class AgentTeamBuilder:
|
|
18
|
+
"""
|
|
19
|
+
A fluent API for constructing and configuring an AgentTeam.
|
|
20
|
+
|
|
21
|
+
This builder simplifies creating an agent team by abstracting away the manual
|
|
22
|
+
creation of config objects and providing an intuitive way to define the
|
|
23
|
+
agent and sub-team graph. It enforces that all nodes within the team have
|
|
24
|
+
a unique name.
|
|
25
|
+
"""
|
|
26
|
+
def __init__(self, name: str, description: str, role: Optional[str] = None):
|
|
27
|
+
"""
|
|
28
|
+
Initializes the AgentTeamBuilder.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
name: A unique name for the agent team.
|
|
32
|
+
description: A high-level description of the team's goal.
|
|
33
|
+
role: An optional role description for when this team is used
|
|
34
|
+
as a sub-team within a parent.
|
|
35
|
+
"""
|
|
36
|
+
if not name or not isinstance(name, str):
|
|
37
|
+
raise ValueError("Agent team name must be a non-empty string.")
|
|
38
|
+
if not description or not isinstance(description, str):
|
|
39
|
+
raise ValueError("Agent team description must be a non-empty string.")
|
|
40
|
+
|
|
41
|
+
self._name = name
|
|
42
|
+
self._description = description
|
|
43
|
+
self._role = role
|
|
44
|
+
self._nodes: Dict[NodeDefinition, List[NodeDefinition]] = {}
|
|
45
|
+
self._coordinator_config: Optional[AgentConfig] = None
|
|
46
|
+
self._added_node_names: Set[str] = set()
|
|
47
|
+
self._task_notification_mode: TaskNotificationMode = TaskNotificationMode.AGENT_MANUAL_NOTIFICATION
|
|
48
|
+
logger.info(f"AgentTeamBuilder initialized for team: '{self._name}'.")
|
|
49
|
+
|
|
50
|
+
def add_agent_node(self, agent_config: AgentConfig, dependencies: Optional[List[NodeDefinition]] = None) -> 'AgentTeamBuilder':
|
|
51
|
+
"""
|
|
52
|
+
Adds a regular agent node to the agent team.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
agent_config: The configuration for the agent at this node.
|
|
56
|
+
dependencies: A list of AgentConfig or AgentTeamConfig objects for nodes
|
|
57
|
+
that this node depends on. These must have been added previously.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
The builder instance for fluent chaining.
|
|
61
|
+
"""
|
|
62
|
+
self._add_node_internal(agent_config, dependencies)
|
|
63
|
+
return self
|
|
64
|
+
|
|
65
|
+
def add_sub_team_node(self, team_config: AgentTeamConfig, dependencies: Optional[List[NodeDefinition]] = None) -> 'AgentTeamBuilder':
|
|
66
|
+
"""
|
|
67
|
+
Adds a sub-team node to the agent team.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
team_config: The configuration for the sub-team.
|
|
71
|
+
dependencies: A list of AgentConfig or AgentTeamConfig objects for nodes
|
|
72
|
+
that this node depends on. These must have been added previously.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
The builder instance for fluent chaining.
|
|
76
|
+
"""
|
|
77
|
+
self._add_node_internal(team_config, dependencies)
|
|
78
|
+
return self
|
|
79
|
+
|
|
80
|
+
def _add_node_internal(self, node_definition: NodeDefinition, dependencies: Optional[List[NodeDefinition]]):
|
|
81
|
+
"""Internal helper to add a node of any type."""
|
|
82
|
+
if not isinstance(node_definition, (AgentConfig, AgentTeamConfig)):
|
|
83
|
+
raise TypeError("node_definition must be an instance of AgentConfig or AgentTeamConfig.")
|
|
84
|
+
|
|
85
|
+
node_name = node_definition.name
|
|
86
|
+
if node_name in self._added_node_names:
|
|
87
|
+
# Enforce unique names. This is the new, simpler validation.
|
|
88
|
+
raise ValueError(f"Duplicate node name '{node_name}' detected. All nodes in a team must have a unique name.")
|
|
89
|
+
|
|
90
|
+
if node_definition in self._nodes or node_definition == self._coordinator_config:
|
|
91
|
+
raise ValueError(f"The exact same node definition object for '{node_name}' has already been added to the team.")
|
|
92
|
+
|
|
93
|
+
if dependencies:
|
|
94
|
+
for dep_config in dependencies:
|
|
95
|
+
if dep_config not in self._nodes and dep_config != self._coordinator_config:
|
|
96
|
+
raise ValueError(f"Dependency node '{dep_config.name}' must be added to the builder before being used as a dependency.")
|
|
97
|
+
|
|
98
|
+
self._nodes[node_definition] = dependencies or []
|
|
99
|
+
self._added_node_names.add(node_name)
|
|
100
|
+
|
|
101
|
+
node_type = "Sub-Team" if isinstance(node_definition, AgentTeamConfig) else "Agent"
|
|
102
|
+
logger.debug(f"Added {node_type} node '{node_name}' to builder with {len(dependencies or [])} dependencies.")
|
|
103
|
+
|
|
104
|
+
def set_coordinator(self, agent_config: AgentConfig) -> 'AgentTeamBuilder':
|
|
105
|
+
"""
|
|
106
|
+
Sets the coordinator agent for the team. A coordinator must be an agent.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
agent_config: The configuration for the coordinator agent.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
The builder instance for fluent chaining.
|
|
113
|
+
"""
|
|
114
|
+
if self._coordinator_config is not None:
|
|
115
|
+
raise ValueError("A coordinator has already been set for this team.")
|
|
116
|
+
|
|
117
|
+
if not isinstance(agent_config, AgentConfig):
|
|
118
|
+
raise TypeError("Coordinator must be an instance of AgentConfig.")
|
|
119
|
+
|
|
120
|
+
node_name = agent_config.name
|
|
121
|
+
if node_name in self._added_node_names:
|
|
122
|
+
raise ValueError(f"Duplicate node name '{node_name}' detected. The coordinator's name must also be unique within the team.")
|
|
123
|
+
|
|
124
|
+
self._coordinator_config = agent_config
|
|
125
|
+
self._added_node_names.add(node_name)
|
|
126
|
+
logger.debug(f"Set coordinator for team to '{agent_config.name}'.")
|
|
127
|
+
return self
|
|
128
|
+
|
|
129
|
+
def set_task_notification_mode(self, mode: TaskNotificationMode) -> 'AgentTeamBuilder':
|
|
130
|
+
"""
|
|
131
|
+
Sets the task notification mode for the team.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
mode: The desired TaskNotificationMode (AGENT_MANUAL_NOTIFICATION or SYSTEM_EVENT_DRIVEN).
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
The builder instance for fluent chaining.
|
|
138
|
+
"""
|
|
139
|
+
if not isinstance(mode, TaskNotificationMode):
|
|
140
|
+
raise TypeError("mode must be an instance of TaskNotificationMode.")
|
|
141
|
+
self._task_notification_mode = mode
|
|
142
|
+
logger.debug(f"Task notification mode set to '{mode.value}'.")
|
|
143
|
+
return self
|
|
144
|
+
|
|
145
|
+
def build(self) -> AgentTeam:
|
|
146
|
+
"""
|
|
147
|
+
Constructs and returns the final AgentTeam instance using the
|
|
148
|
+
singleton AgentTeamFactory.
|
|
149
|
+
"""
|
|
150
|
+
logger.info("Building AgentTeam from builder...")
|
|
151
|
+
if self._coordinator_config is None:
|
|
152
|
+
raise ValueError("Cannot build team: A coordinator must be set.")
|
|
153
|
+
|
|
154
|
+
node_map: Dict[NodeDefinition, TeamNodeConfig] = {}
|
|
155
|
+
# Ensure the coordinator config is also in the set of definitions to process
|
|
156
|
+
all_definitions = list(self._nodes.keys())
|
|
157
|
+
if self._coordinator_config not in all_definitions:
|
|
158
|
+
all_definitions.append(self._coordinator_config)
|
|
159
|
+
|
|
160
|
+
for definition in all_definitions:
|
|
161
|
+
node_map[definition] = TeamNodeConfig(node_definition=definition)
|
|
162
|
+
|
|
163
|
+
for node_def, dep_defs in self._nodes.items():
|
|
164
|
+
if node_def in node_map and dep_defs:
|
|
165
|
+
current_node = node_map[node_def]
|
|
166
|
+
dependency_nodes = [node_map[dep_def] for dep_def in dep_defs]
|
|
167
|
+
current_node.dependencies = tuple(dependency_nodes)
|
|
168
|
+
|
|
169
|
+
final_nodes = list(node_map.values())
|
|
170
|
+
coordinator_node_instance = node_map[self._coordinator_config]
|
|
171
|
+
|
|
172
|
+
team_config = AgentTeamConfig(
|
|
173
|
+
name=self._name,
|
|
174
|
+
description=self._description,
|
|
175
|
+
role=self._role,
|
|
176
|
+
nodes=tuple(final_nodes),
|
|
177
|
+
coordinator_node=coordinator_node_instance,
|
|
178
|
+
task_notification_mode=self._task_notification_mode
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
logger.info(f"AgentTeamConfig created successfully. Name: '{team_config.name}'. Total nodes: {len(final_nodes)}. Coordinator: '{coordinator_node_instance.name}'.")
|
|
182
|
+
|
|
183
|
+
factory = AgentTeamFactory()
|
|
184
|
+
return factory.create_team(config=team_config)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/agent_team/base_agent_team.py
|
|
2
|
+
import logging
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import Optional, Any, TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
# These are forward declarations that might be used by subclasses.
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from autobyteus.agent_team.agent_team import AgentTeam
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
class BaseAgentTeam(ABC):
|
|
13
|
+
"""
|
|
14
|
+
Optional abstract base class for creating domain-specific, type-safe
|
|
15
|
+
APIs for agent teams.
|
|
16
|
+
|
|
17
|
+
Users can subclass BaseAgentTeam to create a more structured and
|
|
18
|
+
specific interface for their multi-agent tasks, rather than using the
|
|
19
|
+
generic `AgentTeam.process(**kwargs)` method directly.
|
|
20
|
+
|
|
21
|
+
Subclasses would typically encapsulate an `AgentTeam` instance and define
|
|
22
|
+
methods that map domain-specific inputs to the underlying team's execution.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self,
|
|
26
|
+
name: str,
|
|
27
|
+
wrapped_team_instance: Optional['AgentTeam'] = None):
|
|
28
|
+
"""
|
|
29
|
+
Initializes the BaseAgentTeam.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
name: A descriptive name for this specific team implementation.
|
|
33
|
+
wrapped_team_instance: Optional. An instance of AgentTeam that this class
|
|
34
|
+
will wrap and delegate to. If not provided, the subclass
|
|
35
|
+
is responsible for initializing its own team instance.
|
|
36
|
+
"""
|
|
37
|
+
self.name: str = name
|
|
38
|
+
self._wrapped_team: Optional[Any] = wrapped_team_instance
|
|
39
|
+
|
|
40
|
+
if self._wrapped_team:
|
|
41
|
+
logger.info(f"BaseAgentTeam '{self.name}' initialized, wrapping an instance of "
|
|
42
|
+
f"'{self._wrapped_team.__class__.__name__}'.")
|
|
43
|
+
else:
|
|
44
|
+
logger.info(f"BaseAgentTeam '{self.name}' initialized without a pre-wrapped instance. "
|
|
45
|
+
"Subclass should handle team setup.")
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def wrapped_team(self) -> Optional[Any]:
|
|
49
|
+
"""Provides access to the wrapped AgentTeam instance."""
|
|
50
|
+
return self._wrapped_team
|
|
51
|
+
|
|
52
|
+
@abstractmethod
|
|
53
|
+
async def start(self) -> None:
|
|
54
|
+
"""
|
|
55
|
+
Starts the team. Subclasses should implement this to delegate
|
|
56
|
+
to the start method of their wrapped AgentTeam.
|
|
57
|
+
"""
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
@abstractmethod
|
|
61
|
+
async def stop(self, timeout: float = 10.0) -> None:
|
|
62
|
+
"""
|
|
63
|
+
Stops the team. Subclasses should implement this to delegate
|
|
64
|
+
to the stop method of their wrapped AgentTeam.
|
|
65
|
+
"""
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
@abstractmethod
|
|
70
|
+
def is_running(self) -> bool:
|
|
71
|
+
"""
|
|
72
|
+
Checks if the team is currently running. Subclasses should implement
|
|
73
|
+
this to delegate to the is_running property of their wrapped instance.
|
|
74
|
+
"""
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
def __repr__(self) -> str:
|
|
78
|
+
running_status = "N/A (not implemented by subclass)"
|
|
79
|
+
try:
|
|
80
|
+
running_status = str(self.is_running)
|
|
81
|
+
except NotImplementedError:
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
return (f"<{self.__class__.__name__} name='{self.name}', "
|
|
85
|
+
f"wraps='{self._wrapped_team.__class__.__name__ if self._wrapped_team else 'NoneInternal'}', "
|
|
86
|
+
f"is_running={running_status}>")
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/agent_team/bootstrap_steps/__init__.py
|
|
2
|
+
"""
|
|
3
|
+
Defines individual, self-contained steps for the agent team bootstrapping process.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from autobyteus.agent_team.bootstrap_steps.base_agent_team_bootstrap_step import BaseAgentTeamBootstrapStep
|
|
7
|
+
from autobyteus.agent_team.bootstrap_steps.agent_team_runtime_queue_initialization_step import AgentTeamRuntimeQueueInitializationStep
|
|
8
|
+
from autobyteus.agent_team.bootstrap_steps.team_context_initialization_step import TeamContextInitializationStep
|
|
9
|
+
from autobyteus.agent_team.bootstrap_steps.task_notifier_initialization_step import TaskNotifierInitializationStep
|
|
10
|
+
from autobyteus.agent_team.bootstrap_steps.coordinator_prompt_preparation_step import CoordinatorPromptPreparationStep
|
|
11
|
+
from autobyteus.agent_team.bootstrap_steps.agent_configuration_preparation_step import AgentConfigurationPreparationStep
|
|
12
|
+
from autobyteus.agent_team.bootstrap_steps.coordinator_initialization_step import CoordinatorInitializationStep
|
|
13
|
+
from autobyteus.agent_team.bootstrap_steps.agent_team_bootstrapper import AgentTeamBootstrapper
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"BaseAgentTeamBootstrapStep",
|
|
17
|
+
"AgentTeamRuntimeQueueInitializationStep",
|
|
18
|
+
"TeamContextInitializationStep",
|
|
19
|
+
"TaskNotifierInitializationStep",
|
|
20
|
+
"CoordinatorPromptPreparationStep",
|
|
21
|
+
"AgentConfigurationPreparationStep",
|
|
22
|
+
"CoordinatorInitializationStep",
|
|
23
|
+
"AgentTeamBootstrapper",
|
|
24
|
+
]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/agent_team/bootstrap_steps/agent_configuration_preparation_step.py
|
|
2
|
+
import logging
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from autobyteus.agent_team.bootstrap_steps.base_agent_team_bootstrap_step import BaseAgentTeamBootstrapStep
|
|
6
|
+
from autobyteus.agent.context import AgentConfig
|
|
7
|
+
from autobyteus.agent.message.send_message_to import SendMessageTo
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from autobyteus.agent_team.context.agent_team_context import AgentTeamContext
|
|
11
|
+
from autobyteus.agent_team.phases.agent_team_phase_manager import AgentTeamPhaseManager
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
class AgentConfigurationPreparationStep(BaseAgentTeamBootstrapStep):
|
|
16
|
+
"""
|
|
17
|
+
Bootstrap step to prepare the final, immutable configuration for every
|
|
18
|
+
agent in the team. It injects team-specific context and applies the final
|
|
19
|
+
coordinator prompt. It no longer injects tools.
|
|
20
|
+
"""
|
|
21
|
+
async def execute(self, context: 'AgentTeamContext', phase_manager: 'AgentTeamPhaseManager') -> bool:
|
|
22
|
+
team_id = context.team_id
|
|
23
|
+
logger.info(f"Team '{team_id}': Executing AgentConfigurationPreparationStep to prepare all agent configurations.")
|
|
24
|
+
|
|
25
|
+
team_manager = context.team_manager
|
|
26
|
+
if not team_manager:
|
|
27
|
+
logger.error(f"Team '{team_id}': TeamManager not found in context during agent config preparation.")
|
|
28
|
+
return False
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
coordinator_node_config = context.config.coordinator_node
|
|
32
|
+
|
|
33
|
+
for node_config_wrapper in context.config.nodes:
|
|
34
|
+
# This step only configures direct agent members, not sub-teams.
|
|
35
|
+
if node_config_wrapper.is_sub_team:
|
|
36
|
+
continue
|
|
37
|
+
|
|
38
|
+
unique_name = node_config_wrapper.name
|
|
39
|
+
node_definition = node_config_wrapper.node_definition
|
|
40
|
+
|
|
41
|
+
if not isinstance(node_definition, AgentConfig):
|
|
42
|
+
logger.warning(f"Team '{team_id}': Node '{unique_name}' has an unexpected definition type and will be skipped: {type(node_definition)}")
|
|
43
|
+
continue
|
|
44
|
+
|
|
45
|
+
final_config = node_definition.copy()
|
|
46
|
+
|
|
47
|
+
# --- Shared Context Injection ---
|
|
48
|
+
# The shared context is injected into the initial_custom_data dictionary,
|
|
49
|
+
# which is then used by the AgentFactory to create the AgentRuntimeState.
|
|
50
|
+
if final_config.initial_custom_data is None:
|
|
51
|
+
final_config.initial_custom_data = {}
|
|
52
|
+
final_config.initial_custom_data["team_context"] = context
|
|
53
|
+
logger.debug(f"Team '{team_id}': Injected shared team_context into initial_custom_data for agent '{unique_name}'.")
|
|
54
|
+
|
|
55
|
+
# --- Tool Injection Logic Removed ---
|
|
56
|
+
# The user is now fully responsible for defining all tools an agent needs
|
|
57
|
+
# in its AgentConfig. The framework no longer implicitly injects SendMessageTo.
|
|
58
|
+
|
|
59
|
+
# If this is the coordinator, apply the prompt that was prepared in the previous step.
|
|
60
|
+
if node_config_wrapper == coordinator_node_config:
|
|
61
|
+
coordinator_prompt = context.state.prepared_coordinator_prompt
|
|
62
|
+
if coordinator_prompt:
|
|
63
|
+
final_config.system_prompt = coordinator_prompt
|
|
64
|
+
logger.info(f"Team '{team_id}': Applied dynamic prompt to coordinator '{unique_name}'.")
|
|
65
|
+
|
|
66
|
+
# Store the final, ready-to-use config in the team's state
|
|
67
|
+
context.state.final_agent_configs[unique_name] = final_config
|
|
68
|
+
logger.info(f"Team '{team_id}': Prepared final config for agent '{unique_name}' with user-defined tools: {[t.get_name() for t in final_config.tools]}")
|
|
69
|
+
|
|
70
|
+
return True
|
|
71
|
+
except Exception as e:
|
|
72
|
+
logger.error(f"Team '{team_id}': Failed during agent configuration preparation: {e}", exc_info=True)
|
|
73
|
+
return False
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/agent_team/bootstrap_steps/agent_team_bootstrapper.py
|
|
2
|
+
import logging
|
|
3
|
+
from typing import TYPE_CHECKING, List, Optional
|
|
4
|
+
|
|
5
|
+
from autobyteus.agent_team.bootstrap_steps.base_agent_team_bootstrap_step import BaseAgentTeamBootstrapStep
|
|
6
|
+
from autobyteus.agent_team.bootstrap_steps.agent_team_runtime_queue_initialization_step import AgentTeamRuntimeQueueInitializationStep
|
|
7
|
+
from autobyteus.agent_team.bootstrap_steps.team_context_initialization_step import TeamContextInitializationStep
|
|
8
|
+
from autobyteus.agent_team.bootstrap_steps.task_notifier_initialization_step import TaskNotifierInitializationStep
|
|
9
|
+
from autobyteus.agent_team.bootstrap_steps.coordinator_prompt_preparation_step import CoordinatorPromptPreparationStep
|
|
10
|
+
from autobyteus.agent_team.bootstrap_steps.agent_configuration_preparation_step import AgentConfigurationPreparationStep
|
|
11
|
+
from autobyteus.agent_team.bootstrap_steps.coordinator_initialization_step import CoordinatorInitializationStep
|
|
12
|
+
from autobyteus.agent_team.events.agent_team_events import AgentTeamReadyEvent
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from autobyteus.agent_team.context.agent_team_context import AgentTeamContext
|
|
16
|
+
from autobyteus.agent_team.phases.agent_team_phase_manager import AgentTeamPhaseManager
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
class AgentTeamBootstrapper:
|
|
21
|
+
"""Orchestrates the agent team's bootstrapping process."""
|
|
22
|
+
def __init__(self, steps: Optional[List[BaseAgentTeamBootstrapStep]] = None):
|
|
23
|
+
self.bootstrap_steps = steps or [
|
|
24
|
+
AgentTeamRuntimeQueueInitializationStep(),
|
|
25
|
+
TeamContextInitializationStep(),
|
|
26
|
+
TaskNotifierInitializationStep(),
|
|
27
|
+
CoordinatorPromptPreparationStep(),
|
|
28
|
+
AgentConfigurationPreparationStep(),
|
|
29
|
+
CoordinatorInitializationStep(),
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
async def run(self, context: 'AgentTeamContext', phase_manager: 'AgentTeamPhaseManager') -> bool:
|
|
33
|
+
team_id = context.team_id
|
|
34
|
+
await phase_manager.notify_bootstrapping_started()
|
|
35
|
+
logger.info(f"Team '{team_id}': Bootstrapper starting.")
|
|
36
|
+
|
|
37
|
+
for step in self.bootstrap_steps:
|
|
38
|
+
step_name = step.__class__.__name__
|
|
39
|
+
logger.debug(f"Team '{team_id}': Executing bootstrap step: {step_name}")
|
|
40
|
+
if not await step.execute(context, phase_manager):
|
|
41
|
+
error_message = f"Bootstrap step {step_name} failed."
|
|
42
|
+
logger.error(f"Team '{team_id}': {error_message}")
|
|
43
|
+
await phase_manager.notify_error_occurred(error_message, f"Failed during bootstrap step '{step_name}'.")
|
|
44
|
+
return False
|
|
45
|
+
|
|
46
|
+
logger.info(f"Team '{team_id}': All bootstrap steps completed successfully.")
|
|
47
|
+
if context.state.input_event_queues:
|
|
48
|
+
await context.state.input_event_queues.enqueue_internal_system_event(AgentTeamReadyEvent())
|
|
49
|
+
else:
|
|
50
|
+
logger.critical(f"Team '{team_id}': Bootstrap succeeded but queues not available.")
|
|
51
|
+
await phase_manager.notify_error_occurred("Queues unavailable after bootstrap.", "")
|
|
52
|
+
return False
|
|
53
|
+
|
|
54
|
+
return True
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/agent_team/bootstrap_steps/agent_team_runtime_queue_initialization_step.py
|
|
2
|
+
import logging
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from autobyteus.agent_team.bootstrap_steps.base_agent_team_bootstrap_step import BaseAgentTeamBootstrapStep
|
|
6
|
+
from autobyteus.agent_team.events.agent_team_input_event_queue_manager import AgentTeamInputEventQueueManager
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from autobyteus.agent_team.context.agent_team_context import AgentTeamContext
|
|
10
|
+
from autobyteus.agent_team.phases.agent_team_phase_manager import AgentTeamPhaseManager
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
class AgentTeamRuntimeQueueInitializationStep(BaseAgentTeamBootstrapStep):
|
|
15
|
+
"""Bootstrap step for initializing the agent team's runtime event queues."""
|
|
16
|
+
async def execute(self, context: 'AgentTeamContext', phase_manager: 'AgentTeamPhaseManager') -> bool:
|
|
17
|
+
team_id = context.team_id
|
|
18
|
+
logger.info(f"Team '{team_id}': Executing AgentTeamRuntimeQueueInitializationStep.")
|
|
19
|
+
try:
|
|
20
|
+
context.state.input_event_queues = AgentTeamInputEventQueueManager()
|
|
21
|
+
logger.info(f"Team '{team_id}': AgentTeamInputEventQueueManager initialized.")
|
|
22
|
+
return True
|
|
23
|
+
except Exception as e:
|
|
24
|
+
logger.error(f"Team '{team_id}': Critical failure during queue initialization: {e}", exc_info=True)
|
|
25
|
+
return False
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/agent_team/bootstrap_steps/base_agent_team_bootstrap_step.py
|
|
2
|
+
import logging
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from autobyteus.agent_team.context.agent_team_context import AgentTeamContext
|
|
8
|
+
from autobyteus.agent_team.phases.agent_team_phase_manager import AgentTeamPhaseManager
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
class BaseAgentTeamBootstrapStep(ABC):
|
|
13
|
+
"""Abstract base class for individual steps in the agent team bootstrapping process."""
|
|
14
|
+
|
|
15
|
+
@abstractmethod
|
|
16
|
+
async def execute(self, context: 'AgentTeamContext', phase_manager: 'AgentTeamPhaseManager') -> bool:
|
|
17
|
+
"""
|
|
18
|
+
Executes the bootstrap step.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
True if the step completed successfully, False otherwise.
|
|
22
|
+
"""
|
|
23
|
+
raise NotImplementedError("Subclasses must implement the 'execute' method.")
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/agent_team/bootstrap_steps/coordinator_initialization_step.py
|
|
2
|
+
import logging
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from autobyteus.agent_team.bootstrap_steps.base_agent_team_bootstrap_step import BaseAgentTeamBootstrapStep
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from autobyteus.agent_team.context.agent_team_context import AgentTeamContext
|
|
9
|
+
from autobyteus.agent_team.phases.agent_team_phase_manager import AgentTeamPhaseManager
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
class CoordinatorInitializationStep(BaseAgentTeamBootstrapStep):
|
|
14
|
+
"""
|
|
15
|
+
Bootstrap step that eagerly instantiates and starts the coordinator agent
|
|
16
|
+
using the TeamManager. This ensures the coordinator is ready before the
|
|
17
|
+
agent team becomes idle.
|
|
18
|
+
"""
|
|
19
|
+
async def execute(self, context: 'AgentTeamContext', phase_manager: 'AgentTeamPhaseManager') -> bool:
|
|
20
|
+
team_id = context.team_id
|
|
21
|
+
logger.info(f"Team '{team_id}': Executing CoordinatorInitializationStep.")
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
team_manager = context.team_manager
|
|
25
|
+
if not team_manager:
|
|
26
|
+
raise RuntimeError("TeamManager not found in team context. It should be created by the factory.")
|
|
27
|
+
|
|
28
|
+
coordinator_name = context.config.coordinator_node.name
|
|
29
|
+
|
|
30
|
+
# This call now ensures the coordinator agent is fully created and ready.
|
|
31
|
+
coordinator = await team_manager.ensure_coordinator_is_ready(coordinator_name)
|
|
32
|
+
|
|
33
|
+
if not coordinator:
|
|
34
|
+
raise RuntimeError(f"TeamManager failed to return a ready coordinator agent for '{coordinator_name}'.")
|
|
35
|
+
|
|
36
|
+
logger.info(f"Team '{team_id}': Coordinator '{coordinator_name}' initialized and started via TeamManager.")
|
|
37
|
+
return True
|
|
38
|
+
|
|
39
|
+
except Exception as e:
|
|
40
|
+
logger.error(f"Team '{team_id}': Failed to initialize coordinator agent: {e}", exc_info=True)
|
|
41
|
+
return False
|