autobyteus 1.1.4__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/context/__init__.py +4 -2
- autobyteus/agent/context/agent_config.py +0 -4
- autobyteus/agent/context/agent_context_registry.py +73 -0
- autobyteus/agent/events/notifiers.py +4 -0
- autobyteus/agent/handlers/inter_agent_message_event_handler.py +7 -2
- autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +19 -19
- autobyteus/agent/handlers/user_input_message_event_handler.py +15 -0
- autobyteus/agent/message/send_message_to.py +29 -23
- autobyteus/agent/runtime/agent_runtime.py +10 -2
- 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_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/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/events/event_types.py +7 -2
- autobyteus/llm/api/autobyteus_llm.py +11 -12
- autobyteus/llm/api/lmstudio_llm.py +10 -13
- autobyteus/llm/api/ollama_llm.py +8 -13
- autobyteus/llm/autobyteus_provider.py +73 -46
- autobyteus/llm/llm_factory.py +102 -140
- autobyteus/llm/lmstudio_provider.py +63 -48
- 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 -13
- autobyteus/llm/runtimes.py +11 -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/bash/bash_executor.py +59 -14
- 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 +103 -50
- autobyteus/tools/parameter_schema.py +17 -11
- autobyteus/tools/registry/tool_definition.py +24 -29
- autobyteus/tools/tool_category.py +1 -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-1.1.4.dist-info → autobyteus-1.1.5.dist-info}/METADATA +3 -3
- {autobyteus-1.1.4.dist-info → autobyteus-1.1.5.dist-info}/RECORD +146 -72
- examples/agent_team/__init__.py +1 -0
- examples/run_browser_agent.py +17 -15
- examples/run_google_slides_agent.py +17 -16
- examples/run_poem_writer.py +22 -12
- examples/run_sqlite_agent.py +17 -15
- 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/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
- examples/workflow/__init__.py +0 -1
- examples/workflow/run_basic_research_workflow.py +0 -189
- examples/workflow/run_code_review_workflow.py +0 -269
- examples/workflow/run_debate_workflow.py +0 -212
- examples/workflow/run_workflow_with_tui.py +0 -153
- {autobyteus-1.1.4.dist-info → autobyteus-1.1.5.dist-info}/WHEEL +0 -0
- {autobyteus-1.1.4.dist-info → autobyteus-1.1.5.dist-info}/licenses/LICENSE +0 -0
- {autobyteus-1.1.4.dist-info → autobyteus-1.1.5.dist-info}/top_level.txt +0 -0
|
@@ -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
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/agent_team/bootstrap_steps/coordinator_prompt_preparation_step.py
|
|
2
|
+
import logging
|
|
3
|
+
from typing import TYPE_CHECKING, List
|
|
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_team.context import AgentTeamConfig
|
|
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 CoordinatorPromptPreparationStep(BaseAgentTeamBootstrapStep):
|
|
16
|
+
"""
|
|
17
|
+
Bootstrap step to finalize the coordinator's system prompt by injecting a
|
|
18
|
+
dynamically generated team manifest into a user-defined prompt template.
|
|
19
|
+
The user is expected to provide a `system_prompt` in the coordinator's
|
|
20
|
+
AgentConfig with a `{{team}}` placeholder.
|
|
21
|
+
"""
|
|
22
|
+
async def execute(self, context: 'AgentTeamContext', phase_manager: 'AgentTeamPhaseManager') -> bool:
|
|
23
|
+
team_id = context.team_id
|
|
24
|
+
logger.info(f"Team '{team_id}': Executing CoordinatorPromptPreparationStep.")
|
|
25
|
+
try:
|
|
26
|
+
coordinator_node_config_wrapper = context.config.coordinator_node
|
|
27
|
+
|
|
28
|
+
# The coordinator must be an agent with a defined config.
|
|
29
|
+
if not isinstance(coordinator_node_config_wrapper.node_definition, AgentConfig):
|
|
30
|
+
logger.error(f"Team '{team_id}': Coordinator node '{coordinator_node_config_wrapper.name}' is not defined by an AgentConfig. Cannot prepare prompt.")
|
|
31
|
+
return False
|
|
32
|
+
|
|
33
|
+
coordinator_agent_config: AgentConfig = coordinator_node_config_wrapper.node_definition
|
|
34
|
+
|
|
35
|
+
# Start with the user's provided prompt template.
|
|
36
|
+
prompt_template = coordinator_agent_config.system_prompt
|
|
37
|
+
if not prompt_template:
|
|
38
|
+
logger.warning(f"Team '{team_id}': Coordinator '{coordinator_agent_config.name}' has no system_prompt defined. No prompt will be applied.")
|
|
39
|
+
context.state.prepared_coordinator_prompt = ""
|
|
40
|
+
return True
|
|
41
|
+
|
|
42
|
+
team_manifest = self._generate_team_manifest(context)
|
|
43
|
+
|
|
44
|
+
# Inject the manifest into the template.
|
|
45
|
+
if "{{team}}" in prompt_template:
|
|
46
|
+
final_prompt = prompt_template.replace("{{team}}", team_manifest)
|
|
47
|
+
logger.debug(f"Team '{team_id}': Injected team manifest into coordinator's system prompt.")
|
|
48
|
+
else:
|
|
49
|
+
final_prompt = prompt_template
|
|
50
|
+
logger.warning(f"Team '{team_id}': The coordinator's system prompt does not contain a '{{team}}' placeholder. The team manifest will not be injected.")
|
|
51
|
+
|
|
52
|
+
# Store the finalized prompt in the state for the AgentToolInjectionStep to use.
|
|
53
|
+
context.state.prepared_coordinator_prompt = final_prompt
|
|
54
|
+
|
|
55
|
+
logger.info(f"Team '{team_id}': Coordinator prompt prepared successfully and stored in state.")
|
|
56
|
+
return True
|
|
57
|
+
except Exception as e:
|
|
58
|
+
logger.error(f"Team '{team_id}': Failed to prepare coordinator prompt: {e}", exc_info=True)
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
def _generate_team_manifest(self, context: 'AgentTeamContext') -> str:
|
|
62
|
+
"""Generates a string manifest of all non-coordinator team members."""
|
|
63
|
+
prompt_parts: List[str] = []
|
|
64
|
+
coordinator_node = context.config.coordinator_node
|
|
65
|
+
member_nodes = {node for node in context.config.nodes if node != coordinator_node}
|
|
66
|
+
|
|
67
|
+
if not member_nodes:
|
|
68
|
+
return "You are working alone. You have no team members to delegate to."
|
|
69
|
+
|
|
70
|
+
# Sort for deterministic prompt generation
|
|
71
|
+
for node in sorted(list(member_nodes), key=lambda n: n.name):
|
|
72
|
+
node_def = node.node_definition
|
|
73
|
+
description = "No description available."
|
|
74
|
+
|
|
75
|
+
# --- THE FIX ---
|
|
76
|
+
# Use the 'description' for an AgentConfig and the 'role' for an AgentTeamConfig (sub-team).
|
|
77
|
+
if isinstance(node_def, AgentConfig):
|
|
78
|
+
description = node_def.description
|
|
79
|
+
elif isinstance(node_def, AgentTeamConfig):
|
|
80
|
+
# A sub-team's role is its most concise and relevant description for a parent coordinator.
|
|
81
|
+
description = node_def.role or node_def.description
|
|
82
|
+
|
|
83
|
+
prompt_parts.append(f"- name: {node.name}\n description: {description}")
|
|
84
|
+
|
|
85
|
+
return "\n".join(prompt_parts)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/agent_team/bootstrap_steps/task_notifier_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.task_notification.task_notification_mode import TaskNotificationMode
|
|
7
|
+
from autobyteus.agent_team.task_notification.system_event_driven_agent_task_notifier import SystemEventDrivenAgentTaskNotifier
|
|
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 TaskNotifierInitializationStep(BaseAgentTeamBootstrapStep):
|
|
16
|
+
"""
|
|
17
|
+
Bootstrap step to initialize the SystemEventDrivenAgentTaskNotifier if the
|
|
18
|
+
team is configured for event-driven notifications.
|
|
19
|
+
"""
|
|
20
|
+
async def execute(self, context: 'AgentTeamContext', phase_manager: 'AgentTeamPhaseManager') -> bool:
|
|
21
|
+
team_id = context.team_id
|
|
22
|
+
logger.info(f"Team '{team_id}': Executing TaskNotifierInitializationStep.")
|
|
23
|
+
|
|
24
|
+
if context.config.task_notification_mode != TaskNotificationMode.SYSTEM_EVENT_DRIVEN:
|
|
25
|
+
logger.info(f"Team '{team_id}': Task notification mode is '{context.config.task_notification_mode.value}'. Skipping event-driven notifier setup.")
|
|
26
|
+
return True
|
|
27
|
+
|
|
28
|
+
logger.info(f"Team '{team_id}': Mode is SYSTEM_EVENT_DRIVEN. Initializing and activating task notifier.")
|
|
29
|
+
try:
|
|
30
|
+
task_board = context.state.task_board
|
|
31
|
+
if not task_board:
|
|
32
|
+
logger.error(f"Team '{team_id}': TaskBoard not found. Cannot initialize task notifier. This step should run after TeamContextInitializationStep.")
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
team_manager = context.team_manager
|
|
36
|
+
if not team_manager:
|
|
37
|
+
logger.error(f"Team '{team_id}': TeamManager not found. Cannot initialize task notifier.")
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
notifier = SystemEventDrivenAgentTaskNotifier(
|
|
41
|
+
task_board=task_board,
|
|
42
|
+
team_manager=team_manager
|
|
43
|
+
)
|
|
44
|
+
notifier.start_monitoring()
|
|
45
|
+
|
|
46
|
+
context.state.task_notifier = notifier
|
|
47
|
+
logger.info(f"Team '{team_id}': SystemEventDrivenAgentTaskNotifier initialized and monitoring started.")
|
|
48
|
+
return True
|
|
49
|
+
except Exception as e:
|
|
50
|
+
logger.error(f"Team '{team_id}': Critical failure during task notifier initialization: {e}", exc_info=True)
|
|
51
|
+
return False
|