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.
Files changed (167) hide show
  1. autobyteus/agent/context/__init__.py +4 -2
  2. autobyteus/agent/context/agent_config.py +0 -4
  3. autobyteus/agent/context/agent_context_registry.py +73 -0
  4. autobyteus/agent/events/notifiers.py +4 -0
  5. autobyteus/agent/handlers/inter_agent_message_event_handler.py +7 -2
  6. autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +19 -19
  7. autobyteus/agent/handlers/user_input_message_event_handler.py +15 -0
  8. autobyteus/agent/message/send_message_to.py +29 -23
  9. autobyteus/agent/runtime/agent_runtime.py +10 -2
  10. autobyteus/agent/sender_type.py +15 -0
  11. autobyteus/agent/streaming/agent_event_stream.py +6 -0
  12. autobyteus/agent/streaming/stream_event_payloads.py +12 -0
  13. autobyteus/agent/streaming/stream_events.py +3 -0
  14. autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +7 -4
  15. autobyteus/agent_team/__init__.py +1 -0
  16. autobyteus/agent_team/agent_team.py +93 -0
  17. autobyteus/agent_team/agent_team_builder.py +184 -0
  18. autobyteus/agent_team/base_agent_team.py +86 -0
  19. autobyteus/agent_team/bootstrap_steps/__init__.py +24 -0
  20. autobyteus/agent_team/bootstrap_steps/agent_configuration_preparation_step.py +73 -0
  21. autobyteus/agent_team/bootstrap_steps/agent_team_bootstrapper.py +54 -0
  22. autobyteus/agent_team/bootstrap_steps/agent_team_runtime_queue_initialization_step.py +25 -0
  23. autobyteus/agent_team/bootstrap_steps/base_agent_team_bootstrap_step.py +23 -0
  24. autobyteus/agent_team/bootstrap_steps/coordinator_initialization_step.py +41 -0
  25. autobyteus/agent_team/bootstrap_steps/coordinator_prompt_preparation_step.py +85 -0
  26. autobyteus/agent_team/bootstrap_steps/task_notifier_initialization_step.py +51 -0
  27. autobyteus/agent_team/bootstrap_steps/team_context_initialization_step.py +45 -0
  28. autobyteus/agent_team/context/__init__.py +17 -0
  29. autobyteus/agent_team/context/agent_team_config.py +33 -0
  30. autobyteus/agent_team/context/agent_team_context.py +61 -0
  31. autobyteus/agent_team/context/agent_team_runtime_state.py +56 -0
  32. autobyteus/agent_team/context/team_manager.py +147 -0
  33. autobyteus/agent_team/context/team_node_config.py +76 -0
  34. autobyteus/agent_team/events/__init__.py +29 -0
  35. autobyteus/agent_team/events/agent_team_event_dispatcher.py +39 -0
  36. autobyteus/agent_team/events/agent_team_events.py +53 -0
  37. autobyteus/agent_team/events/agent_team_input_event_queue_manager.py +21 -0
  38. autobyteus/agent_team/exceptions.py +8 -0
  39. autobyteus/agent_team/factory/__init__.py +9 -0
  40. autobyteus/agent_team/factory/agent_team_factory.py +99 -0
  41. autobyteus/agent_team/handlers/__init__.py +19 -0
  42. autobyteus/agent_team/handlers/agent_team_event_handler_registry.py +23 -0
  43. autobyteus/agent_team/handlers/base_agent_team_event_handler.py +16 -0
  44. autobyteus/agent_team/handlers/inter_agent_message_request_event_handler.py +61 -0
  45. autobyteus/agent_team/handlers/lifecycle_agent_team_event_handler.py +27 -0
  46. autobyteus/agent_team/handlers/process_user_message_event_handler.py +46 -0
  47. autobyteus/agent_team/handlers/tool_approval_team_event_handler.py +48 -0
  48. autobyteus/agent_team/phases/__init__.py +11 -0
  49. autobyteus/agent_team/phases/agent_team_operational_phase.py +19 -0
  50. autobyteus/agent_team/phases/agent_team_phase_manager.py +48 -0
  51. autobyteus/agent_team/runtime/__init__.py +13 -0
  52. autobyteus/agent_team/runtime/agent_team_runtime.py +82 -0
  53. autobyteus/agent_team/runtime/agent_team_worker.py +117 -0
  54. autobyteus/agent_team/shutdown_steps/__init__.py +17 -0
  55. autobyteus/agent_team/shutdown_steps/agent_team_shutdown_orchestrator.py +35 -0
  56. autobyteus/agent_team/shutdown_steps/agent_team_shutdown_step.py +42 -0
  57. autobyteus/agent_team/shutdown_steps/base_agent_team_shutdown_step.py +16 -0
  58. autobyteus/agent_team/shutdown_steps/bridge_cleanup_step.py +28 -0
  59. autobyteus/agent_team/shutdown_steps/sub_team_shutdown_step.py +41 -0
  60. autobyteus/agent_team/streaming/__init__.py +26 -0
  61. autobyteus/agent_team/streaming/agent_event_bridge.py +48 -0
  62. autobyteus/agent_team/streaming/agent_event_multiplexer.py +70 -0
  63. autobyteus/agent_team/streaming/agent_team_event_notifier.py +64 -0
  64. autobyteus/agent_team/streaming/agent_team_event_stream.py +33 -0
  65. autobyteus/agent_team/streaming/agent_team_stream_event_payloads.py +32 -0
  66. autobyteus/agent_team/streaming/agent_team_stream_events.py +56 -0
  67. autobyteus/agent_team/streaming/team_event_bridge.py +50 -0
  68. autobyteus/agent_team/task_notification/__init__.py +11 -0
  69. autobyteus/agent_team/task_notification/system_event_driven_agent_task_notifier.py +164 -0
  70. autobyteus/agent_team/task_notification/task_notification_mode.py +24 -0
  71. autobyteus/agent_team/utils/__init__.py +9 -0
  72. autobyteus/agent_team/utils/wait_for_idle.py +46 -0
  73. autobyteus/cli/agent_team_tui/__init__.py +4 -0
  74. autobyteus/cli/agent_team_tui/app.py +210 -0
  75. autobyteus/cli/agent_team_tui/state.py +180 -0
  76. autobyteus/cli/agent_team_tui/widgets/__init__.py +6 -0
  77. autobyteus/cli/agent_team_tui/widgets/agent_list_sidebar.py +149 -0
  78. autobyteus/cli/agent_team_tui/widgets/focus_pane.py +320 -0
  79. autobyteus/cli/agent_team_tui/widgets/logo.py +20 -0
  80. autobyteus/cli/agent_team_tui/widgets/renderables.py +77 -0
  81. autobyteus/cli/agent_team_tui/widgets/shared.py +60 -0
  82. autobyteus/cli/agent_team_tui/widgets/status_bar.py +14 -0
  83. autobyteus/cli/agent_team_tui/widgets/task_board_panel.py +82 -0
  84. autobyteus/events/event_types.py +7 -2
  85. autobyteus/llm/api/autobyteus_llm.py +11 -12
  86. autobyteus/llm/api/lmstudio_llm.py +10 -13
  87. autobyteus/llm/api/ollama_llm.py +8 -13
  88. autobyteus/llm/autobyteus_provider.py +73 -46
  89. autobyteus/llm/llm_factory.py +102 -140
  90. autobyteus/llm/lmstudio_provider.py +63 -48
  91. autobyteus/llm/models.py +83 -53
  92. autobyteus/llm/ollama_provider.py +69 -61
  93. autobyteus/llm/ollama_provider_resolver.py +1 -0
  94. autobyteus/llm/providers.py +13 -13
  95. autobyteus/llm/runtimes.py +11 -0
  96. autobyteus/task_management/__init__.py +43 -0
  97. autobyteus/task_management/base_task_board.py +68 -0
  98. autobyteus/task_management/converters/__init__.py +11 -0
  99. autobyteus/task_management/converters/task_board_converter.py +64 -0
  100. autobyteus/task_management/converters/task_plan_converter.py +48 -0
  101. autobyteus/task_management/deliverable.py +16 -0
  102. autobyteus/task_management/deliverables/__init__.py +8 -0
  103. autobyteus/task_management/deliverables/file_deliverable.py +15 -0
  104. autobyteus/task_management/events.py +27 -0
  105. autobyteus/task_management/in_memory_task_board.py +126 -0
  106. autobyteus/task_management/schemas/__init__.py +15 -0
  107. autobyteus/task_management/schemas/deliverable_schema.py +13 -0
  108. autobyteus/task_management/schemas/plan_definition.py +35 -0
  109. autobyteus/task_management/schemas/task_status_report.py +27 -0
  110. autobyteus/task_management/task_plan.py +110 -0
  111. autobyteus/task_management/tools/__init__.py +14 -0
  112. autobyteus/task_management/tools/get_task_board_status.py +68 -0
  113. autobyteus/task_management/tools/publish_task_plan.py +113 -0
  114. autobyteus/task_management/tools/update_task_status.py +135 -0
  115. autobyteus/tools/bash/bash_executor.py +59 -14
  116. autobyteus/tools/mcp/config_service.py +63 -58
  117. autobyteus/tools/mcp/server/http_managed_mcp_server.py +14 -2
  118. autobyteus/tools/mcp/server/stdio_managed_mcp_server.py +14 -2
  119. autobyteus/tools/mcp/server_instance_manager.py +30 -4
  120. autobyteus/tools/mcp/tool_registrar.py +103 -50
  121. autobyteus/tools/parameter_schema.py +17 -11
  122. autobyteus/tools/registry/tool_definition.py +24 -29
  123. autobyteus/tools/tool_category.py +1 -0
  124. autobyteus/tools/usage/formatters/default_json_example_formatter.py +78 -3
  125. autobyteus/tools/usage/formatters/default_xml_example_formatter.py +23 -3
  126. autobyteus/tools/usage/formatters/gemini_json_example_formatter.py +6 -0
  127. autobyteus/tools/usage/formatters/google_json_example_formatter.py +7 -0
  128. autobyteus/tools/usage/formatters/openai_json_example_formatter.py +6 -4
  129. autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +23 -7
  130. autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +14 -25
  131. autobyteus/tools/usage/providers/__init__.py +2 -12
  132. autobyteus/tools/usage/providers/tool_manifest_provider.py +36 -29
  133. autobyteus/tools/usage/registries/__init__.py +7 -12
  134. autobyteus/tools/usage/registries/tool_formatter_pair.py +15 -0
  135. autobyteus/tools/usage/registries/tool_formatting_registry.py +58 -0
  136. autobyteus/tools/usage/registries/tool_usage_parser_registry.py +55 -0
  137. {autobyteus-1.1.4.dist-info → autobyteus-1.1.5.dist-info}/METADATA +3 -3
  138. {autobyteus-1.1.4.dist-info → autobyteus-1.1.5.dist-info}/RECORD +146 -72
  139. examples/agent_team/__init__.py +1 -0
  140. examples/run_browser_agent.py +17 -15
  141. examples/run_google_slides_agent.py +17 -16
  142. examples/run_poem_writer.py +22 -12
  143. examples/run_sqlite_agent.py +17 -15
  144. autobyteus/tools/mcp/call_handlers/__init__.py +0 -16
  145. autobyteus/tools/mcp/call_handlers/base_handler.py +0 -40
  146. autobyteus/tools/mcp/call_handlers/stdio_handler.py +0 -76
  147. autobyteus/tools/mcp/call_handlers/streamable_http_handler.py +0 -55
  148. autobyteus/tools/usage/providers/json_example_provider.py +0 -32
  149. autobyteus/tools/usage/providers/json_schema_provider.py +0 -35
  150. autobyteus/tools/usage/providers/json_tool_usage_parser_provider.py +0 -28
  151. autobyteus/tools/usage/providers/xml_example_provider.py +0 -28
  152. autobyteus/tools/usage/providers/xml_schema_provider.py +0 -29
  153. autobyteus/tools/usage/providers/xml_tool_usage_parser_provider.py +0 -26
  154. autobyteus/tools/usage/registries/json_example_formatter_registry.py +0 -51
  155. autobyteus/tools/usage/registries/json_schema_formatter_registry.py +0 -51
  156. autobyteus/tools/usage/registries/json_tool_usage_parser_registry.py +0 -42
  157. autobyteus/tools/usage/registries/xml_example_formatter_registry.py +0 -30
  158. autobyteus/tools/usage/registries/xml_schema_formatter_registry.py +0 -33
  159. autobyteus/tools/usage/registries/xml_tool_usage_parser_registry.py +0 -30
  160. examples/workflow/__init__.py +0 -1
  161. examples/workflow/run_basic_research_workflow.py +0 -189
  162. examples/workflow/run_code_review_workflow.py +0 -269
  163. examples/workflow/run_debate_workflow.py +0 -212
  164. examples/workflow/run_workflow_with_tui.py +0 -153
  165. {autobyteus-1.1.4.dist-info → autobyteus-1.1.5.dist-info}/WHEEL +0 -0
  166. {autobyteus-1.1.4.dist-info → autobyteus-1.1.5.dist-info}/licenses/LICENSE +0 -0
  167. {autobyteus-1.1.4.dist-info → autobyteus-1.1.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,45 @@
1
+ # file: autobyteus/autobyteus/agent_team/bootstrap_steps/team_context_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.task_management import TaskBoard
7
+ from autobyteus.events.event_types import EventType
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 TeamContextInitializationStep(BaseAgentTeamBootstrapStep):
16
+ """
17
+ Bootstrap step to initialize shared team context components, such as the
18
+ TaskBoard, and bridges its events to the team's notifier.
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 TeamContextInitializationStep.")
23
+ try:
24
+ if context.state.task_board is None:
25
+ task_board = TaskBoard(team_id=team_id)
26
+ context.state.task_board = task_board
27
+ logger.info(f"Team '{team_id}': TaskBoard initialized and attached to team state.")
28
+
29
+ notifier = phase_manager.notifier
30
+ if notifier:
31
+ # The notifier, a long-lived component, subscribes to events
32
+ # from the task_board, another long-lived component.
33
+ notifier.subscribe_from(sender=task_board, event=EventType.TASK_BOARD_PLAN_PUBLISHED, listener=notifier.handle_and_publish_task_board_event)
34
+ notifier.subscribe_from(sender=task_board, event=EventType.TASK_BOARD_STATUS_UPDATED, listener=notifier.handle_and_publish_task_board_event)
35
+ logger.info(f"Team '{team_id}': Successfully bridged TaskBoard events to the team notifier.")
36
+ else:
37
+ logger.warning(f"Team '{team_id}': Notifier not found in PhaseManager. Cannot bridge TaskBoard events.")
38
+
39
+ else:
40
+ logger.warning(f"Team '{team_id}': TaskBoard already exists. Skipping initialization.")
41
+
42
+ return True
43
+ except Exception as e:
44
+ logger.error(f"Team '{team_id}': Critical failure during team context initialization: {e}", exc_info=True)
45
+ return False
@@ -0,0 +1,17 @@
1
+ # file: autobyteus/autobyteus/agent_team/context/__init__.py
2
+ """
3
+ Components related to the agent team's runtime context, state, and configuration.
4
+ """
5
+ from autobyteus.agent_team.context.team_manager import TeamManager
6
+ from autobyteus.agent_team.context.agent_team_config import AgentTeamConfig
7
+ from autobyteus.agent_team.context.agent_team_context import AgentTeamContext
8
+ from autobyteus.agent_team.context.team_node_config import TeamNodeConfig
9
+ from autobyteus.agent_team.context.agent_team_runtime_state import AgentTeamRuntimeState
10
+
11
+ __all__ = [
12
+ "TeamManager",
13
+ "AgentTeamConfig",
14
+ "AgentTeamContext",
15
+ "TeamNodeConfig",
16
+ "AgentTeamRuntimeState",
17
+ ]
@@ -0,0 +1,33 @@
1
+ # file: autobyteus/autobyteus/agent_team/context/agent_team_config.py
2
+ import logging
3
+ from dataclasses import dataclass, field
4
+ from typing import List, Optional, Tuple
5
+
6
+ from autobyteus.agent_team.context.team_node_config import TeamNodeConfig
7
+ from autobyteus.agent_team.task_notification.task_notification_mode import TaskNotificationMode
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ @dataclass(frozen=True)
12
+ class AgentTeamConfig:
13
+ """
14
+ Represents the complete, static configuration for an AgentTeam instance.
15
+ This is the user's primary input for defining an agent team.
16
+ """
17
+ name: str
18
+ description: str
19
+ nodes: Tuple[TeamNodeConfig, ...]
20
+ coordinator_node: TeamNodeConfig
21
+ role: Optional[str] = None
22
+ task_notification_mode: TaskNotificationMode = TaskNotificationMode.AGENT_MANUAL_NOTIFICATION
23
+
24
+ def __post_init__(self):
25
+ if not self.name or not isinstance(self.name, str):
26
+ raise ValueError("The 'name' in AgentTeamConfig must be a non-empty string.")
27
+ if not self.nodes:
28
+ raise ValueError("The 'nodes' collection in AgentTeamConfig cannot be empty.")
29
+ if self.coordinator_node not in self.nodes:
30
+ raise ValueError("The 'coordinator_node' must be one of the nodes in the 'nodes' collection.")
31
+ if not isinstance(self.task_notification_mode, TaskNotificationMode):
32
+ raise TypeError("The 'task_notification_mode' must be an instance of TaskNotificationMode enum.")
33
+ logger.debug(f"AgentTeamConfig validated for team: '{self.name}'.")
@@ -0,0 +1,61 @@
1
+ # file: autobyteus/autobyteus/agent_team/context/agent_team_context.py
2
+ import logging
3
+ from typing import TYPE_CHECKING, List, Optional, Dict
4
+
5
+ if TYPE_CHECKING:
6
+ from autobyteus.agent_team.context.agent_team_config import AgentTeamConfig
7
+ from autobyteus.agent_team.context.agent_team_runtime_state import AgentTeamRuntimeState
8
+ from autobyteus.agent.agent import Agent
9
+ from autobyteus.agent_team.phases.agent_team_phase_manager import AgentTeamPhaseManager
10
+ from autobyteus.agent_team.context.team_manager import TeamManager
11
+ from autobyteus.agent_team.streaming.agent_event_multiplexer import AgentEventMultiplexer
12
+ from autobyteus.agent.context import AgentConfig
13
+ from autobyteus.agent_team.context.team_node_config import TeamNodeConfig
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ class AgentTeamContext:
18
+ """Represents the complete operational context for a single agent team instance."""
19
+ def __init__(self, team_id: str, config: 'AgentTeamConfig', state: 'AgentTeamRuntimeState'):
20
+ if not team_id or not isinstance(team_id, str):
21
+ raise ValueError("AgentTeamContext requires a non-empty string 'team_id'.")
22
+
23
+ self.team_id: str = team_id
24
+ self.config: 'AgentTeamConfig' = config
25
+ self.state: 'AgentTeamRuntimeState' = state
26
+ self._node_config_map: Optional[Dict[str, 'TeamNodeConfig']] = None
27
+
28
+ logger.info(f"AgentTeamContext composed for team_id '{self.team_id}'.")
29
+
30
+ def get_node_config_by_name(self, name: str) -> Optional['TeamNodeConfig']:
31
+ """Efficiently retrieves a node's config by its friendly name."""
32
+ if self._node_config_map is None:
33
+ # Build cache on first access
34
+ self._node_config_map = {node.name: node for node in self.config.nodes}
35
+ return self._node_config_map.get(name)
36
+
37
+ @property
38
+ def agents(self) -> List['Agent']:
39
+ """Returns all agents managed by the TeamManager."""
40
+ if self.state.team_manager:
41
+ return self.state.team_manager.get_all_agents()
42
+ return []
43
+
44
+ @property
45
+ def coordinator_agent(self) -> Optional['Agent']:
46
+ """Returns the coordinator agent from the TeamManager."""
47
+ if self.state.team_manager:
48
+ return self.state.team_manager.coordinator_agent
49
+ return None
50
+
51
+ @property
52
+ def phase_manager(self) -> Optional['AgentTeamPhaseManager']:
53
+ return self.state.phase_manager_ref
54
+
55
+ @property
56
+ def team_manager(self) -> Optional['TeamManager']:
57
+ return self.state.team_manager
58
+
59
+ @property
60
+ def multiplexer(self) -> Optional['AgentEventMultiplexer']:
61
+ return self.state.multiplexer_ref
@@ -0,0 +1,56 @@
1
+ # file: autobyteus/autobyteus/agent_team/context/agent_team_runtime_state.py
2
+ import logging
3
+ from typing import List, Optional, TYPE_CHECKING, Dict
4
+ from dataclasses import dataclass, field
5
+
6
+ from autobyteus.agent_team.phases.agent_team_operational_phase import AgentTeamOperationalPhase
7
+ from autobyteus.agent.context import AgentConfig
8
+
9
+ if TYPE_CHECKING:
10
+ from autobyteus.agent.agent import Agent
11
+ from autobyteus.agent_team.events.agent_team_input_event_queue_manager import AgentTeamInputEventQueueManager
12
+ from autobyteus.agent_team.phases.agent_team_phase_manager import AgentTeamPhaseManager
13
+ from autobyteus.agent_team.context.team_node_config import TeamNodeConfig
14
+ from autobyteus.agent_team.context.team_manager import TeamManager
15
+ from autobyteus.agent_team.streaming.agent_event_multiplexer import AgentEventMultiplexer
16
+ from autobyteus.task_management.base_task_board import BaseTaskBoard
17
+ from autobyteus.task_management.artifacts.artifact_manifest import ArtifactManifest
18
+ from autobyteus.agent_team.task_notification.system_event_driven_agent_task_notifier import SystemEventDrivenAgentTaskNotifier
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+ @dataclass
23
+ class AgentTeamRuntimeState:
24
+ """Encapsulates the dynamic, stateful data of a running agent team instance."""
25
+ team_id: str
26
+ current_phase: AgentTeamOperationalPhase = AgentTeamOperationalPhase.UNINITIALIZED
27
+
28
+ # State populated by bootstrap steps
29
+ prepared_coordinator_prompt: Optional[str] = None
30
+ final_agent_configs: Dict[str, 'AgentConfig'] = field(default_factory=dict)
31
+
32
+ # Core services
33
+ team_manager: Optional['TeamManager'] = None
34
+ task_notifier: Optional['SystemEventDrivenAgentTaskNotifier'] = None
35
+
36
+ # Runtime components and references
37
+ input_event_queues: Optional['AgentTeamInputEventQueueManager'] = None
38
+ phase_manager_ref: Optional['AgentTeamPhaseManager'] = None
39
+ multiplexer_ref: Optional['AgentEventMultiplexer'] = None
40
+
41
+ # Dynamic planning and artifact state
42
+ task_board: Optional['BaseTaskBoard'] = None
43
+ artifact_registry: Dict[str, 'ArtifactManifest'] = field(default_factory=dict)
44
+
45
+ def __post_init__(self):
46
+ if not self.team_id or not isinstance(self.team_id, str):
47
+ raise ValueError("AgentTeamRuntimeState requires a non-empty string 'team_id'.")
48
+ logger.info(f"AgentTeamRuntimeState initialized for team_id '{self.team_id}'.")
49
+
50
+ def __repr__(self) -> str:
51
+ agents_count = len(self.team_manager.get_all_agents()) if self.team_manager else 0
52
+ coordinator_set = self.team_manager.coordinator_agent is not None if self.team_manager else False
53
+ return (f"<AgentTeamRuntimeState id='{self.team_id}', phase='{self.current_phase.value}', "
54
+ f"agents_count={agents_count}, coordinator_set={coordinator_set}, "
55
+ f"final_configs_count={len(self.final_agent_configs)}, "
56
+ f"team_manager_set={self.team_manager is not None}>")
@@ -0,0 +1,147 @@
1
+ # file: autobyteus/autobyteus/agent_team/context/team_manager.py
2
+ import asyncio
3
+ import logging
4
+ from typing import List, Dict, Optional, TYPE_CHECKING, Union
5
+
6
+ from autobyteus.agent.factory import AgentFactory
7
+ from autobyteus.agent.utils.wait_for_idle import wait_for_agent_to_be_idle
8
+ from autobyteus.agent_team.utils.wait_for_idle import wait_for_team_to_be_idle
9
+ from autobyteus.agent_team.exceptions import TeamNodeNotFoundException
10
+
11
+ if TYPE_CHECKING:
12
+ from autobyteus.agent.agent import Agent
13
+ from autobyteus.agent_team.agent_team import AgentTeam
14
+ from autobyteus.agent_team.events.agent_team_events import InterAgentMessageRequestEvent, ProcessUserMessageEvent
15
+ from autobyteus.agent_team.runtime.agent_team_runtime import AgentTeamRuntime
16
+ from autobyteus.agent_team.streaming.agent_event_multiplexer import AgentEventMultiplexer
17
+ from autobyteus.agent_team.context.agent_team_config import AgentTeamConfig
18
+
19
+ ManagedNode = Union['Agent', 'AgentTeam']
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+ class TeamManager:
24
+ """
25
+ Manages all nodes (agents and sub-teams) within an agent team. It handles
26
+ lazy creation, on-demand startup, and provides access to managed instances.
27
+ It assumes all node names are unique within the team.
28
+ """
29
+ def __init__(self, team_id: str, runtime: 'AgentTeamRuntime', multiplexer: 'AgentEventMultiplexer'):
30
+ self.team_id = team_id
31
+ self._runtime = runtime
32
+ self._multiplexer = multiplexer
33
+ self._agent_factory = AgentFactory()
34
+ self._nodes_cache: Dict[str, ManagedNode] = {}
35
+ self._agent_id_to_name_map: Dict[str, str] = {}
36
+ self._coordinator_agent: Optional['Agent'] = None
37
+ logger.info(f"TeamManager created for team '{self.team_id}'.")
38
+
39
+ async def dispatch_inter_agent_message_request(self, event: 'InterAgentMessageRequestEvent'):
40
+ await self._runtime.submit_event(event)
41
+
42
+ async def dispatch_user_message_to_agent(self, event: 'ProcessUserMessageEvent'):
43
+ """Submits a user message event (potentially system-generated) to the team's runtime."""
44
+ await self._runtime.submit_event(event)
45
+
46
+ async def ensure_node_is_ready(self, name_or_agent_id: str) -> ManagedNode:
47
+ """
48
+ Retrieves a node by its unique name or ID. If not yet created, it
49
+ instantiates and starts it on-demand.
50
+ """
51
+ unique_name: str
52
+ if name_or_agent_id in self._agent_id_to_name_map:
53
+ unique_name = self._agent_id_to_name_map[name_or_agent_id]
54
+ else:
55
+ unique_name = name_or_agent_id
56
+
57
+ node_instance = self._nodes_cache.get(unique_name)
58
+
59
+ was_created = False
60
+ if not node_instance:
61
+ logger.debug(f"Node '{unique_name}' not in cache for team '{self.team_id}'. Attempting lazy creation.")
62
+
63
+ node_config_wrapper = self._runtime.context.get_node_config_by_name(unique_name)
64
+ if not node_config_wrapper:
65
+ raise TeamNodeNotFoundException(node_name=name_or_agent_id, team_id=self.team_id)
66
+
67
+ if node_config_wrapper.is_sub_team:
68
+ from autobyteus.agent_team.factory.agent_team_factory import AgentTeamFactory
69
+ from autobyteus.agent_team.context.agent_team_config import AgentTeamConfig
70
+
71
+ team_factory = AgentTeamFactory()
72
+ node_definition = node_config_wrapper.node_definition
73
+ if not isinstance(node_definition, AgentTeamConfig):
74
+ raise TypeError(f"Expected AgentTeamConfig for node '{unique_name}', but found {type(node_definition)}")
75
+ logger.info(f"Lazily creating sub-team node '{unique_name}' in team '{self.team_id}'.")
76
+ node_instance = team_factory.create_team(config=node_definition)
77
+ else:
78
+ # Agent creation is now simpler: just retrieve the pre-made config.
79
+ final_config = self._runtime.context.state.final_agent_configs.get(unique_name)
80
+ if not final_config:
81
+ raise RuntimeError(f"No pre-prepared agent configuration found for '{unique_name}'. "
82
+ "Bootstrap step may have failed or skipped this agent.")
83
+
84
+ logger.info(f"Lazily creating agent node '{unique_name}' using pre-prepared configuration.")
85
+ node_instance = self._agent_factory.create_agent(config=final_config)
86
+
87
+ self._nodes_cache[unique_name] = node_instance
88
+ was_created = True
89
+
90
+ from autobyteus.agent.agent import Agent
91
+ if isinstance(node_instance, Agent):
92
+ self._agent_id_to_name_map[node_instance.agent_id] = unique_name
93
+
94
+
95
+ if was_created and node_instance:
96
+ from autobyteus.agent_team.agent_team import AgentTeam
97
+ from autobyteus.agent.agent import Agent
98
+ if isinstance(node_instance, AgentTeam):
99
+ self._multiplexer.start_bridging_team_events(node_instance, unique_name)
100
+ elif isinstance(node_instance, Agent):
101
+ self._multiplexer.start_bridging_agent_events(node_instance, unique_name)
102
+
103
+ # On-Demand Startup Logic
104
+ if not node_instance.is_running:
105
+ from autobyteus.agent_team.agent_team import AgentTeam
106
+ logger.info(f"Team '{self.team_id}': Node '{unique_name}' is not running. Starting on-demand.")
107
+ await self._start_node(node_instance, unique_name)
108
+
109
+ return node_instance
110
+
111
+ async def _start_node(self, node: ManagedNode, name: str):
112
+ """Starts a node and waits for it to be idle."""
113
+ try:
114
+ node.start()
115
+ from autobyteus.agent_team.agent_team import AgentTeam
116
+ if isinstance(node, AgentTeam):
117
+ await wait_for_team_to_be_idle(node, timeout=120.0)
118
+ else:
119
+ await wait_for_agent_to_be_idle(node, timeout=60.0)
120
+ except Exception as e:
121
+ logger.error(f"Team '{self.team_id}': Failed to start node '{name}' on-demand: {e}", exc_info=True)
122
+ raise RuntimeError(f"Failed to start node '{name}' on-demand.") from e
123
+
124
+ def get_all_agents(self) -> List['Agent']:
125
+ from autobyteus.agent.agent import Agent
126
+ return [node for node in self._nodes_cache.values() if isinstance(node, Agent)]
127
+
128
+ def get_all_sub_teams(self) -> List['AgentTeam']:
129
+ from autobyteus.agent_team.agent_team import AgentTeam
130
+ return [node for node in self._nodes_cache.values() if isinstance(node, AgentTeam)]
131
+
132
+ @property
133
+ def coordinator_agent(self) -> Optional['Agent']:
134
+ return self._coordinator_agent
135
+
136
+ async def ensure_coordinator_is_ready(self, coordinator_name: str) -> 'Agent':
137
+ """
138
+ Ensures the coordinator agent is created, started, and ready, then
139
+ designates it as the coordinator.
140
+ """
141
+ from autobyteus.agent.agent import Agent
142
+ node = await self.ensure_node_is_ready(name_or_agent_id=coordinator_name)
143
+ if not isinstance(node, Agent):
144
+ raise TypeError(f"Coordinator node '{coordinator_name}' resolved to a non-agent type: {type(node).__name__}")
145
+
146
+ self._coordinator_agent = node
147
+ return node
@@ -0,0 +1,76 @@
1
+ # file: autobyteus/autobyteus/agent_team/context/team_node_config.py
2
+ from __future__ import annotations
3
+ import logging
4
+ import uuid
5
+ from dataclasses import dataclass, field
6
+ from typing import List, TYPE_CHECKING, Union, Tuple
7
+
8
+ # The import is moved into the TYPE_CHECKING block to break the circular dependency at module load time.
9
+ if TYPE_CHECKING:
10
+ from autobyteus.agent.context import AgentConfig
11
+ from autobyteus.agent_team.context.agent_team_config import AgentTeamConfig
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ @dataclass
16
+ class TeamNodeConfig:
17
+ """
18
+ Represents a node in an agent team graph.
19
+
20
+ This is the core building block for defining agent teams. A node can be either
21
+ a single agent (defined by an AgentConfig) or an entire sub-team
22
+ (defined by an AgentTeamConfig).
23
+
24
+ Attributes:
25
+ node_definition: The configuration for the agent or sub-team at this node.
26
+ dependencies: A tuple of other TeamNodeConfig objects that must be
27
+ successfully executed before this node can be executed.
28
+ node_id: A unique identifier for this node instance.
29
+ """
30
+ node_definition: Union["AgentConfig", "AgentTeamConfig"]
31
+ dependencies: Tuple[TeamNodeConfig, ...] = field(default_factory=tuple)
32
+ node_id: str = field(default_factory=lambda: f"node_{uuid.uuid4().hex}", init=False, repr=False)
33
+
34
+ def __post_init__(self):
35
+ """Validates the node configuration."""
36
+ from autobyteus.agent.context import AgentConfig
37
+ from autobyteus.agent_team.context.agent_team_config import AgentTeamConfig
38
+
39
+ if not isinstance(self.node_definition, (AgentConfig, AgentTeamConfig)):
40
+ raise TypeError("The 'node_definition' attribute must be an instance of AgentConfig or AgentTeamConfig.")
41
+
42
+ if not all(isinstance(dep, TeamNodeConfig) for dep in self.dependencies):
43
+ raise TypeError("All items in 'dependencies' must be instances of TeamNodeConfig.")
44
+
45
+ logger.debug(f"TeamNodeConfig created for: '{self.name}' (NodeID: {self.node_id}). Dependencies: {[dep.name for dep in self.dependencies]}")
46
+
47
+ @property
48
+ def name(self) -> str:
49
+ """A convenience property to get the node's name from its definition."""
50
+ return self.node_definition.name
51
+
52
+ @property
53
+ def effective_config(self) -> Union["AgentConfig", "AgentTeamConfig"]:
54
+ """Returns the underlying AgentConfig or AgentTeamConfig."""
55
+ return self.node_definition
56
+
57
+ @property
58
+ def is_sub_team(self) -> bool:
59
+ """Returns True if this node represents a sub-team."""
60
+ from autobyteus.agent_team.context.agent_team_config import AgentTeamConfig
61
+ return isinstance(self.node_definition, AgentTeamConfig)
62
+
63
+ def __hash__(self):
64
+ """
65
+ Makes the node hashable based on its unique node_id, allowing it to be
66
+ used in sets and as dictionary keys.
67
+ """
68
+ return hash(self.node_id)
69
+
70
+ def __eq__(self, other):
71
+ """
72
+ Compares two nodes based on their unique node_id.
73
+ """
74
+ if isinstance(other, TeamNodeConfig):
75
+ return self.node_id == other.node_id
76
+ return False
@@ -0,0 +1,29 @@
1
+ # file: autobyteus/autobyteus/agent_team/events/__init__.py
2
+ """
3
+ This package contains event definitions and dispatchers for the agent team runtime.
4
+ """
5
+ from autobyteus.agent_team.events.agent_team_events import (
6
+ BaseAgentTeamEvent,
7
+ LifecycleAgentTeamEvent,
8
+ OperationalAgentTeamEvent,
9
+ AgentTeamReadyEvent,
10
+ AgentTeamErrorEvent,
11
+ ProcessUserMessageEvent,
12
+ InterAgentMessageRequestEvent,
13
+ ToolApprovalTeamEvent,
14
+ )
15
+ from autobyteus.agent_team.events.agent_team_event_dispatcher import AgentTeamEventDispatcher
16
+ from autobyteus.agent_team.events.agent_team_input_event_queue_manager import AgentTeamInputEventQueueManager
17
+
18
+ __all__ = [
19
+ "BaseAgentTeamEvent",
20
+ "LifecycleAgentTeamEvent",
21
+ "OperationalAgentTeamEvent",
22
+ "AgentTeamReadyEvent",
23
+ "AgentTeamErrorEvent",
24
+ "ProcessUserMessageEvent",
25
+ "InterAgentMessageRequestEvent",
26
+ "ToolApprovalTeamEvent",
27
+ "AgentTeamEventDispatcher",
28
+ "AgentTeamInputEventQueueManager",
29
+ ]
@@ -0,0 +1,39 @@
1
+ # file: autobyteus/autobyteus/agent_team/events/agent_team_event_dispatcher.py
2
+ import logging
3
+ import traceback
4
+ from typing import TYPE_CHECKING
5
+
6
+ from autobyteus.agent_team.events.agent_team_events import BaseAgentTeamEvent, AgentTeamReadyEvent, ProcessUserMessageEvent
7
+
8
+ if TYPE_CHECKING:
9
+ from autobyteus.agent_team.context.agent_team_context import AgentTeamContext
10
+ from autobyteus.agent_team.handlers.agent_team_event_handler_registry import AgentTeamEventHandlerRegistry
11
+ from autobyteus.agent_team.phases.agent_team_phase_manager import AgentTeamPhaseManager
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ class AgentTeamEventDispatcher:
16
+ """Dispatches agent team events to their appropriate handlers."""
17
+
18
+ def __init__(self,
19
+ event_handler_registry: 'AgentTeamEventHandlerRegistry',
20
+ phase_manager: 'AgentTeamPhaseManager'):
21
+ self.registry = event_handler_registry
22
+ self.phase_manager = phase_manager
23
+
24
+ async def dispatch(self, event: BaseAgentTeamEvent, context: 'AgentTeamContext'):
25
+ handler = self.registry.get_handler(type(event))
26
+ team_id = context.team_id
27
+
28
+ if not handler:
29
+ logger.warning(f"Team '{team_id}': No handler for event '{type(event).__name__}'.")
30
+ return
31
+
32
+ try:
33
+ await handler.handle(event, context)
34
+ if isinstance(event, AgentTeamReadyEvent):
35
+ await self.phase_manager.notify_initialization_complete()
36
+ except Exception as e:
37
+ error_msg = f"Error handling '{type(event).__name__}' in team '{team_id}': {e}"
38
+ logger.error(error_msg, exc_info=True)
39
+ await self.phase_manager.notify_error_occurred(error_msg, traceback.format_exc())
@@ -0,0 +1,53 @@
1
+ # file: autobyteus/autobyteus/agent_team/events/agent_team_events.py
2
+ from dataclasses import dataclass
3
+ from typing import Dict, Any, Optional
4
+
5
+ from autobyteus.agent.message.agent_input_user_message import AgentInputUserMessage
6
+
7
+ @dataclass
8
+ class BaseAgentTeamEvent:
9
+ """Base class for all agent team events."""
10
+
11
+ @dataclass
12
+ class LifecycleAgentTeamEvent(BaseAgentTeamEvent):
13
+ """Base class for events related to the agent team's lifecycle."""
14
+
15
+ @dataclass
16
+ class OperationalAgentTeamEvent(BaseAgentTeamEvent):
17
+ """Base class for events related to the agent team's operational logic."""
18
+
19
+ # Specific Events
20
+ @dataclass
21
+ class AgentTeamReadyEvent(LifecycleAgentTeamEvent):
22
+ """Indicates the agent team has completed bootstrapping and is ready for tasks."""
23
+
24
+ @dataclass
25
+ class AgentTeamErrorEvent(LifecycleAgentTeamEvent):
26
+ """Indicates a significant error occurred within the agent team."""
27
+ error_message: str
28
+ exception_details: Optional[str] = None
29
+
30
+ @dataclass
31
+ class ProcessUserMessageEvent(OperationalAgentTeamEvent):
32
+ """Carries a user's message to be processed by a specific agent in the team."""
33
+ user_message: AgentInputUserMessage
34
+ target_agent_name: str
35
+
36
+ @dataclass
37
+ class InterAgentMessageRequestEvent(OperationalAgentTeamEvent):
38
+ """
39
+ An internal request within the agent team to post a message from one agent to another.
40
+ This triggers on-demand startup logic if needed.
41
+ """
42
+ sender_agent_id: str
43
+ recipient_name: str
44
+ content: str
45
+ message_type: str
46
+
47
+ @dataclass
48
+ class ToolApprovalTeamEvent(OperationalAgentTeamEvent):
49
+ """Carries a user's approval/denial for a tool execution to a specific agent."""
50
+ agent_name: str
51
+ tool_invocation_id: str
52
+ is_approved: bool
53
+ reason: Optional[str] = None
@@ -0,0 +1,21 @@
1
+ # file: autobyteus/autobyteus/agent_team/events/agent_team_input_event_queue_manager.py
2
+ import asyncio
3
+ import logging
4
+ from typing import Any
5
+
6
+ from autobyteus.agent_team.events.agent_team_events import ProcessUserMessageEvent
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ class AgentTeamInputEventQueueManager:
11
+ """Manages asyncio.Queue instances for events consumed by the AgentTeamWorker."""
12
+ def __init__(self, queue_size: int = 0):
13
+ self.user_message_queue: asyncio.Queue[ProcessUserMessageEvent] = asyncio.Queue(maxsize=queue_size)
14
+ self.internal_system_event_queue: asyncio.Queue[Any] = asyncio.Queue(maxsize=queue_size)
15
+ logger.info("AgentTeamInputEventQueueManager initialized.")
16
+
17
+ async def enqueue_user_message(self, event: ProcessUserMessageEvent):
18
+ await self.user_message_queue.put(event)
19
+
20
+ async def enqueue_internal_system_event(self, event: Any):
21
+ await self.internal_system_event_queue.put(event)
@@ -0,0 +1,8 @@
1
+ # file: autobyteus/autobyteus/agent_team/exceptions.py
2
+
3
+ class TeamNodeNotFoundException(Exception):
4
+ """Raised when a node (agent or sub-team) cannot be found in the agent team."""
5
+ def __init__(self, node_name: str, team_id: str):
6
+ super().__init__(f"Node '{node_name}' not found in agent team '{team_id}'.")
7
+ self.node_name = node_name
8
+ self.team_id = team_id
@@ -0,0 +1,9 @@
1
+ # file: autobyteus/autobyteus/agent_team/factory/__init__.py
2
+ """
3
+ Agent team factory for creating AgentTeam instances.
4
+ """
5
+ from autobyteus.agent_team.factory.agent_team_factory import AgentTeamFactory
6
+
7
+ __all__ = [
8
+ "AgentTeamFactory",
9
+ ]