autobyteus 1.1.2__py3-none-any.whl → 1.1.4__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 (171) hide show
  1. autobyteus/agent/agent.py +1 -1
  2. autobyteus/agent/bootstrap_steps/__init__.py +2 -0
  3. autobyteus/agent/bootstrap_steps/agent_bootstrapper.py +2 -0
  4. autobyteus/agent/bootstrap_steps/mcp_server_prewarming_step.py +71 -0
  5. autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +4 -2
  6. autobyteus/agent/context/agent_config.py +36 -5
  7. autobyteus/agent/events/worker_event_dispatcher.py +1 -2
  8. autobyteus/agent/handlers/inter_agent_message_event_handler.py +1 -1
  9. autobyteus/agent/handlers/llm_user_message_ready_event_handler.py +2 -2
  10. autobyteus/agent/handlers/tool_result_event_handler.py +48 -20
  11. autobyteus/agent/handlers/user_input_message_event_handler.py +1 -1
  12. autobyteus/agent/input_processor/__init__.py +1 -7
  13. autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +41 -12
  14. autobyteus/agent/message/context_file_type.py +6 -0
  15. autobyteus/agent/message/send_message_to.py +68 -99
  16. autobyteus/agent/phases/discover.py +2 -1
  17. autobyteus/agent/runtime/agent_worker.py +25 -34
  18. autobyteus/agent/shutdown_steps/__init__.py +17 -0
  19. autobyteus/agent/shutdown_steps/agent_shutdown_orchestrator.py +63 -0
  20. autobyteus/agent/shutdown_steps/base_shutdown_step.py +33 -0
  21. autobyteus/agent/shutdown_steps/llm_instance_cleanup_step.py +45 -0
  22. autobyteus/agent/shutdown_steps/mcp_server_cleanup_step.py +32 -0
  23. autobyteus/agent/tool_execution_result_processor/__init__.py +9 -0
  24. autobyteus/agent/tool_execution_result_processor/base_processor.py +46 -0
  25. autobyteus/agent/tool_execution_result_processor/processor_definition.py +36 -0
  26. autobyteus/agent/tool_execution_result_processor/processor_meta.py +36 -0
  27. autobyteus/agent/tool_execution_result_processor/processor_registry.py +70 -0
  28. autobyteus/agent/workspace/base_workspace.py +17 -2
  29. autobyteus/cli/__init__.py +1 -1
  30. autobyteus/cli/cli_display.py +1 -1
  31. autobyteus/cli/workflow_tui/__init__.py +4 -0
  32. autobyteus/cli/workflow_tui/app.py +210 -0
  33. autobyteus/cli/workflow_tui/state.py +189 -0
  34. autobyteus/cli/workflow_tui/widgets/__init__.py +6 -0
  35. autobyteus/cli/workflow_tui/widgets/agent_list_sidebar.py +149 -0
  36. autobyteus/cli/workflow_tui/widgets/focus_pane.py +335 -0
  37. autobyteus/cli/workflow_tui/widgets/logo.py +27 -0
  38. autobyteus/cli/workflow_tui/widgets/renderables.py +70 -0
  39. autobyteus/cli/workflow_tui/widgets/shared.py +51 -0
  40. autobyteus/cli/workflow_tui/widgets/status_bar.py +14 -0
  41. autobyteus/events/event_types.py +3 -0
  42. autobyteus/llm/api/lmstudio_llm.py +37 -0
  43. autobyteus/llm/api/openai_compatible_llm.py +20 -3
  44. autobyteus/llm/llm_factory.py +2 -0
  45. autobyteus/llm/lmstudio_provider.py +89 -0
  46. autobyteus/llm/providers.py +1 -0
  47. autobyteus/llm/token_counter/token_counter_factory.py +2 -0
  48. autobyteus/tools/__init__.py +2 -0
  49. autobyteus/tools/ask_user_input.py +2 -1
  50. autobyteus/tools/base_tool.py +2 -0
  51. autobyteus/tools/bash/bash_executor.py +2 -1
  52. autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +2 -0
  53. autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +3 -0
  54. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +3 -0
  55. autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +3 -0
  56. autobyteus/tools/browser/standalone/google_search_ui.py +2 -0
  57. autobyteus/tools/browser/standalone/navigate_to.py +2 -0
  58. autobyteus/tools/browser/standalone/web_page_pdf_generator.py +3 -0
  59. autobyteus/tools/browser/standalone/webpage_image_downloader.py +3 -0
  60. autobyteus/tools/browser/standalone/webpage_reader.py +2 -0
  61. autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +3 -0
  62. autobyteus/tools/file/file_reader.py +36 -9
  63. autobyteus/tools/file/file_writer.py +37 -9
  64. autobyteus/tools/functional_tool.py +5 -4
  65. autobyteus/tools/image_downloader.py +2 -0
  66. autobyteus/tools/mcp/__init__.py +10 -7
  67. autobyteus/tools/mcp/call_handlers/__init__.py +0 -2
  68. autobyteus/tools/mcp/config_service.py +1 -6
  69. autobyteus/tools/mcp/factory.py +12 -26
  70. autobyteus/tools/mcp/server/__init__.py +16 -0
  71. autobyteus/tools/mcp/server/base_managed_mcp_server.py +139 -0
  72. autobyteus/tools/mcp/server/http_managed_mcp_server.py +29 -0
  73. autobyteus/tools/mcp/server/proxy.py +36 -0
  74. autobyteus/tools/mcp/server/stdio_managed_mcp_server.py +33 -0
  75. autobyteus/tools/mcp/server_instance_manager.py +93 -0
  76. autobyteus/tools/mcp/tool.py +28 -46
  77. autobyteus/tools/mcp/tool_registrar.py +179 -0
  78. autobyteus/tools/mcp/types.py +10 -21
  79. autobyteus/tools/pdf_downloader.py +2 -1
  80. autobyteus/tools/registry/tool_definition.py +20 -7
  81. autobyteus/tools/registry/tool_registry.py +75 -28
  82. autobyteus/tools/timer.py +2 -0
  83. autobyteus/tools/tool_category.py +14 -4
  84. autobyteus/tools/tool_meta.py +6 -1
  85. autobyteus/tools/tool_origin.py +10 -0
  86. autobyteus/workflow/agentic_workflow.py +93 -0
  87. autobyteus/{agent/workflow → workflow}/base_agentic_workflow.py +19 -27
  88. autobyteus/workflow/bootstrap_steps/__init__.py +20 -0
  89. autobyteus/workflow/bootstrap_steps/agent_tool_injection_step.py +34 -0
  90. autobyteus/workflow/bootstrap_steps/base_workflow_bootstrap_step.py +23 -0
  91. autobyteus/workflow/bootstrap_steps/coordinator_initialization_step.py +41 -0
  92. autobyteus/workflow/bootstrap_steps/coordinator_prompt_preparation_step.py +108 -0
  93. autobyteus/workflow/bootstrap_steps/workflow_bootstrapper.py +50 -0
  94. autobyteus/workflow/bootstrap_steps/workflow_runtime_queue_initialization_step.py +25 -0
  95. autobyteus/workflow/context/__init__.py +17 -0
  96. autobyteus/workflow/context/team_manager.py +147 -0
  97. autobyteus/workflow/context/workflow_config.py +30 -0
  98. autobyteus/workflow/context/workflow_context.py +61 -0
  99. autobyteus/workflow/context/workflow_node_config.py +76 -0
  100. autobyteus/workflow/context/workflow_runtime_state.py +53 -0
  101. autobyteus/workflow/events/__init__.py +29 -0
  102. autobyteus/workflow/events/workflow_event_dispatcher.py +39 -0
  103. autobyteus/workflow/events/workflow_events.py +53 -0
  104. autobyteus/workflow/events/workflow_input_event_queue_manager.py +21 -0
  105. autobyteus/workflow/exceptions.py +8 -0
  106. autobyteus/workflow/factory/__init__.py +9 -0
  107. autobyteus/workflow/factory/workflow_factory.py +99 -0
  108. autobyteus/workflow/handlers/__init__.py +19 -0
  109. autobyteus/workflow/handlers/base_workflow_event_handler.py +16 -0
  110. autobyteus/workflow/handlers/inter_agent_message_request_event_handler.py +61 -0
  111. autobyteus/workflow/handlers/lifecycle_workflow_event_handler.py +27 -0
  112. autobyteus/workflow/handlers/process_user_message_event_handler.py +46 -0
  113. autobyteus/workflow/handlers/tool_approval_workflow_event_handler.py +39 -0
  114. autobyteus/workflow/handlers/workflow_event_handler_registry.py +23 -0
  115. autobyteus/workflow/phases/__init__.py +11 -0
  116. autobyteus/workflow/phases/workflow_operational_phase.py +19 -0
  117. autobyteus/workflow/phases/workflow_phase_manager.py +48 -0
  118. autobyteus/workflow/runtime/__init__.py +13 -0
  119. autobyteus/workflow/runtime/workflow_runtime.py +82 -0
  120. autobyteus/workflow/runtime/workflow_worker.py +117 -0
  121. autobyteus/workflow/shutdown_steps/__init__.py +17 -0
  122. autobyteus/workflow/shutdown_steps/agent_team_shutdown_step.py +42 -0
  123. autobyteus/workflow/shutdown_steps/base_workflow_shutdown_step.py +16 -0
  124. autobyteus/workflow/shutdown_steps/bridge_cleanup_step.py +28 -0
  125. autobyteus/workflow/shutdown_steps/sub_workflow_shutdown_step.py +41 -0
  126. autobyteus/workflow/shutdown_steps/workflow_shutdown_orchestrator.py +35 -0
  127. autobyteus/workflow/streaming/__init__.py +26 -0
  128. autobyteus/workflow/streaming/agent_event_bridge.py +48 -0
  129. autobyteus/workflow/streaming/agent_event_multiplexer.py +70 -0
  130. autobyteus/workflow/streaming/workflow_event_bridge.py +50 -0
  131. autobyteus/workflow/streaming/workflow_event_notifier.py +83 -0
  132. autobyteus/workflow/streaming/workflow_event_stream.py +33 -0
  133. autobyteus/workflow/streaming/workflow_stream_event_payloads.py +28 -0
  134. autobyteus/workflow/streaming/workflow_stream_events.py +45 -0
  135. autobyteus/workflow/utils/__init__.py +9 -0
  136. autobyteus/workflow/utils/wait_for_idle.py +46 -0
  137. autobyteus/workflow/workflow_builder.py +151 -0
  138. {autobyteus-1.1.2.dist-info → autobyteus-1.1.4.dist-info}/METADATA +16 -13
  139. {autobyteus-1.1.2.dist-info → autobyteus-1.1.4.dist-info}/RECORD +156 -75
  140. {autobyteus-1.1.2.dist-info → autobyteus-1.1.4.dist-info}/top_level.txt +1 -0
  141. examples/__init__.py +1 -0
  142. examples/discover_phase_transitions.py +104 -0
  143. examples/run_browser_agent.py +260 -0
  144. examples/run_google_slides_agent.py +286 -0
  145. examples/run_mcp_browser_client.py +174 -0
  146. examples/run_mcp_google_slides_client.py +270 -0
  147. examples/run_mcp_list_tools.py +189 -0
  148. examples/run_poem_writer.py +274 -0
  149. examples/run_sqlite_agent.py +293 -0
  150. examples/workflow/__init__.py +1 -0
  151. examples/workflow/run_basic_research_workflow.py +189 -0
  152. examples/workflow/run_code_review_workflow.py +269 -0
  153. examples/workflow/run_debate_workflow.py +212 -0
  154. examples/workflow/run_workflow_with_tui.py +153 -0
  155. autobyteus/agent/context/agent_phase_manager.py +0 -264
  156. autobyteus/agent/context/phases.py +0 -49
  157. autobyteus/agent/group/__init__.py +0 -0
  158. autobyteus/agent/group/agent_group.py +0 -164
  159. autobyteus/agent/group/agent_group_context.py +0 -81
  160. autobyteus/agent/input_processor/content_prefixing_input_processor.py +0 -41
  161. autobyteus/agent/input_processor/metadata_appending_input_processor.py +0 -34
  162. autobyteus/agent/input_processor/passthrough_input_processor.py +0 -33
  163. autobyteus/agent/workflow/__init__.py +0 -11
  164. autobyteus/agent/workflow/agentic_workflow.py +0 -89
  165. autobyteus/tools/mcp/call_handlers/sse_handler.py +0 -22
  166. autobyteus/tools/mcp/registrar.py +0 -323
  167. autobyteus/workflow/simple_task.py +0 -98
  168. autobyteus/workflow/task.py +0 -147
  169. autobyteus/workflow/workflow.py +0 -49
  170. {autobyteus-1.1.2.dist-info → autobyteus-1.1.4.dist-info}/WHEEL +0 -0
  171. {autobyteus-1.1.2.dist-info → autobyteus-1.1.4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,76 @@
1
+ # file: autobyteus/autobyteus/workflow/context/workflow_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.workflow.context.workflow_config import WorkflowConfig
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ @dataclass
16
+ class WorkflowNodeConfig:
17
+ """
18
+ Represents a node in an agentic workflow graph.
19
+
20
+ This is the core building block for defining workflows. A node can be either
21
+ a single agent (defined by an AgentConfig) or an entire sub-workflow
22
+ (defined by a WorkflowConfig).
23
+
24
+ Attributes:
25
+ node_definition: The configuration for the agent or sub-workflow at this node.
26
+ dependencies: A tuple of other WorkflowNodeConfig 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", "WorkflowConfig"]
31
+ dependencies: Tuple[WorkflowNodeConfig, ...] = 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.workflow.context.workflow_config import WorkflowConfig
38
+
39
+ if not isinstance(self.node_definition, (AgentConfig, WorkflowConfig)):
40
+ raise TypeError("The 'node_definition' attribute must be an instance of AgentConfig or WorkflowConfig.")
41
+
42
+ if not all(isinstance(dep, WorkflowNodeConfig) for dep in self.dependencies):
43
+ raise TypeError("All items in 'dependencies' must be instances of WorkflowNodeConfig.")
44
+
45
+ logger.debug(f"WorkflowNodeConfig 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", "WorkflowConfig"]:
54
+ """Returns the underlying AgentConfig or WorkflowConfig."""
55
+ return self.node_definition
56
+
57
+ @property
58
+ def is_subworkflow(self) -> bool:
59
+ """Returns True if this node represents a sub-workflow."""
60
+ from autobyteus.workflow.context.workflow_config import WorkflowConfig
61
+ return isinstance(self.node_definition, WorkflowConfig)
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, WorkflowNodeConfig):
75
+ return self.node_id == other.node_id
76
+ return False
@@ -0,0 +1,53 @@
1
+ # file: autobyteus/autobyteus/workflow/context/workflow_runtime_state.py
2
+ import logging
3
+ from typing import List, Optional, TYPE_CHECKING, Dict
4
+
5
+ from autobyteus.workflow.phases.workflow_operational_phase import WorkflowOperationalPhase
6
+ from autobyteus.agent.context import AgentConfig
7
+
8
+ if TYPE_CHECKING:
9
+ from autobyteus.agent.agent import Agent
10
+ from autobyteus.workflow.events.workflow_input_event_queue_manager import WorkflowInputEventQueueManager
11
+ from autobyteus.workflow.phases.workflow_phase_manager import WorkflowPhaseManager
12
+ from autobyteus.workflow.context.workflow_node_config import WorkflowNodeConfig
13
+ from autobyteus.workflow.context.team_manager import TeamManager
14
+ from autobyteus.workflow.streaming.agent_event_multiplexer import AgentEventMultiplexer
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+ class WorkflowRuntimeState:
19
+ """Encapsulates the dynamic, stateful data of a running workflow instance."""
20
+ def __init__(self, workflow_id: str):
21
+ if not workflow_id or not isinstance(workflow_id, str):
22
+ raise ValueError("WorkflowRuntimeState requires a non-empty string 'workflow_id'.")
23
+
24
+ self.workflow_id: str = workflow_id
25
+ self.current_phase: WorkflowOperationalPhase = WorkflowOperationalPhase.UNINITIALIZED
26
+
27
+ # State populated by bootstrap steps
28
+ self.prepared_coordinator_prompt: Optional[str] = None
29
+ # This is now deprecated in favor of just-in-time resolution by TeamManager
30
+ # self.resolved_agent_configs: Optional[Dict[str, 'AgentConfig']] = None
31
+
32
+ # Core services
33
+ self.team_manager: Optional['TeamManager'] = None
34
+
35
+ # Runtime components and references
36
+ self.input_event_queues: Optional['WorkflowInputEventQueueManager'] = None
37
+ self.phase_manager_ref: Optional['WorkflowPhaseManager'] = None
38
+ self.multiplexer_ref: Optional['AgentEventMultiplexer'] = None
39
+
40
+ logger.info(f"WorkflowRuntimeState initialized for workflow_id '{self.workflow_id}'.")
41
+
42
+ @property
43
+ def resolved_agent_configs(self) -> Optional[Dict[str, 'AgentConfig']]:
44
+ """This property is now DEPRECATED as configs are resolved just-in-time."""
45
+ logger.warning("'resolved_agent_configs' is deprecated. Node configs are resolved by TeamManager as needed.")
46
+ return None
47
+
48
+ def __repr__(self) -> str:
49
+ agents_count = len(self.team_manager.get_all_agents()) if self.team_manager else 0
50
+ coordinator_set = self.team_manager.coordinator_agent is not None if self.team_manager else False
51
+ return (f"<WorkflowRuntimeState id='{self.workflow_id}', phase='{self.current_phase.value}', "
52
+ f"agents_count={agents_count}, coordinator_set={coordinator_set}, "
53
+ f"team_manager_set={self.team_manager is not None}>")
@@ -0,0 +1,29 @@
1
+ # file: autobyteus/autobyteus/workflow/events/__init__.py
2
+ """
3
+ This package contains event definitions and dispatchers for the workflow runtime.
4
+ """
5
+ from autobyteus.workflow.events.workflow_events import (
6
+ BaseWorkflowEvent,
7
+ LifecycleWorkflowEvent,
8
+ OperationalWorkflowEvent,
9
+ WorkflowReadyEvent,
10
+ WorkflowErrorEvent,
11
+ ProcessUserMessageEvent,
12
+ InterAgentMessageRequestEvent,
13
+ ToolApprovalWorkflowEvent,
14
+ )
15
+ from autobyteus.workflow.events.workflow_event_dispatcher import WorkflowEventDispatcher
16
+ from autobyteus.workflow.events.workflow_input_event_queue_manager import WorkflowInputEventQueueManager
17
+
18
+ __all__ = [
19
+ "BaseWorkflowEvent",
20
+ "LifecycleWorkflowEvent",
21
+ "OperationalWorkflowEvent",
22
+ "WorkflowReadyEvent",
23
+ "WorkflowErrorEvent",
24
+ "ProcessUserMessageEvent",
25
+ "InterAgentMessageRequestEvent",
26
+ "ToolApprovalWorkflowEvent",
27
+ "WorkflowEventDispatcher",
28
+ "WorkflowInputEventQueueManager",
29
+ ]
@@ -0,0 +1,39 @@
1
+ # file: autobyteus/autobyteus/workflow/events/workflow_event_dispatcher.py
2
+ import logging
3
+ import traceback
4
+ from typing import TYPE_CHECKING
5
+
6
+ from autobyteus.workflow.events.workflow_events import BaseWorkflowEvent, WorkflowReadyEvent, ProcessUserMessageEvent
7
+
8
+ if TYPE_CHECKING:
9
+ from autobyteus.workflow.context.workflow_context import WorkflowContext
10
+ from autobyteus.workflow.handlers.workflow_event_handler_registry import WorkflowEventHandlerRegistry
11
+ from autobyteus.workflow.phases.workflow_phase_manager import WorkflowPhaseManager
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ class WorkflowEventDispatcher:
16
+ """Dispatches workflow events to their appropriate handlers."""
17
+
18
+ def __init__(self,
19
+ event_handler_registry: 'WorkflowEventHandlerRegistry',
20
+ phase_manager: 'WorkflowPhaseManager'):
21
+ self.registry = event_handler_registry
22
+ self.phase_manager = phase_manager
23
+
24
+ async def dispatch(self, event: BaseWorkflowEvent, context: 'WorkflowContext'):
25
+ handler = self.registry.get_handler(type(event))
26
+ workflow_id = context.workflow_id
27
+
28
+ if not handler:
29
+ logger.warning(f"Workflow '{workflow_id}': No handler for event '{type(event).__name__}'.")
30
+ return
31
+
32
+ try:
33
+ await handler.handle(event, context)
34
+ if isinstance(event, WorkflowReadyEvent):
35
+ await self.phase_manager.notify_initialization_complete()
36
+ except Exception as e:
37
+ error_msg = f"Error handling '{type(event).__name__}' in workflow '{workflow_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/workflow/events/workflow_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 BaseWorkflowEvent:
9
+ """Base class for all workflow events."""
10
+
11
+ @dataclass
12
+ class LifecycleWorkflowEvent(BaseWorkflowEvent):
13
+ """Base class for events related to the workflow's lifecycle."""
14
+
15
+ @dataclass
16
+ class OperationalWorkflowEvent(BaseWorkflowEvent):
17
+ """Base class for events related to the workflow's operational logic."""
18
+
19
+ # Specific Events
20
+ @dataclass
21
+ class WorkflowReadyEvent(LifecycleWorkflowEvent):
22
+ """Indicates the workflow has completed bootstrapping and is ready for tasks."""
23
+
24
+ @dataclass
25
+ class WorkflowErrorEvent(LifecycleWorkflowEvent):
26
+ """Indicates a significant error occurred within the workflow."""
27
+ error_message: str
28
+ exception_details: Optional[str] = None
29
+
30
+ @dataclass
31
+ class ProcessUserMessageEvent(OperationalWorkflowEvent):
32
+ """Carries a user's message to be processed by a specific agent in the workflow."""
33
+ user_message: AgentInputUserMessage
34
+ target_agent_name: str
35
+
36
+ @dataclass
37
+ class InterAgentMessageRequestEvent(OperationalWorkflowEvent):
38
+ """
39
+ An internal request within the workflow 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 ToolApprovalWorkflowEvent(OperationalWorkflowEvent):
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/workflow/events/workflow_input_event_queue_manager.py
2
+ import asyncio
3
+ import logging
4
+ from typing import Any
5
+
6
+ from autobyteus.workflow.events.workflow_events import ProcessUserMessageEvent
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ class WorkflowInputEventQueueManager:
11
+ """Manages asyncio.Queue instances for events consumed by the WorkflowWorker."""
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("WorkflowInputEventQueueManager 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/workflow/exceptions.py
2
+
3
+ class WorkflowNodeNotFoundException(Exception):
4
+ """Raised when a node (agent or sub-workflow) cannot be found in the workflow."""
5
+ def __init__(self, node_name: str, workflow_id: str):
6
+ super().__init__(f"Node '{node_name}' not found in workflow '{workflow_id}'.")
7
+ self.node_name = node_name
8
+ self.workflow_id = workflow_id
@@ -0,0 +1,9 @@
1
+ # file: autobyteus/autobyteus/workflow/factory/__init__.py
2
+ """
3
+ Workflow factory for creating AgenticWorkflow instances.
4
+ """
5
+ from autobyteus.workflow.factory.workflow_factory import WorkflowFactory
6
+
7
+ __all__ = [
8
+ "WorkflowFactory",
9
+ ]
@@ -0,0 +1,99 @@
1
+ # file: autobyteus/autobyteus/workflow/factory/workflow_factory.py
2
+ import logging
3
+ import uuid
4
+ from typing import Optional, Dict, List
5
+
6
+ from autobyteus.utils.singleton import SingletonMeta
7
+ from autobyteus.workflow.agentic_workflow import AgenticWorkflow
8
+ from autobyteus.workflow.context.workflow_config import WorkflowConfig
9
+ from autobyteus.workflow.context.workflow_context import WorkflowContext
10
+ from autobyteus.workflow.context.workflow_runtime_state import WorkflowRuntimeState
11
+ from autobyteus.workflow.context.team_manager import TeamManager
12
+ from autobyteus.workflow.runtime.workflow_runtime import WorkflowRuntime
13
+ from autobyteus.workflow.handlers.workflow_event_handler_registry import WorkflowEventHandlerRegistry
14
+ from autobyteus.workflow.handlers.process_user_message_event_handler import ProcessUserMessageEventHandler
15
+ from autobyteus.workflow.handlers.lifecycle_workflow_event_handler import LifecycleWorkflowEventHandler
16
+ from autobyteus.workflow.handlers.inter_agent_message_request_event_handler import InterAgentMessageRequestEventHandler
17
+ from autobyteus.workflow.handlers.tool_approval_workflow_event_handler import ToolApprovalWorkflowEventHandler
18
+ from autobyteus.workflow.events.workflow_events import (
19
+ ProcessUserMessageEvent,
20
+ WorkflowReadyEvent,
21
+ WorkflowErrorEvent,
22
+ InterAgentMessageRequestEvent,
23
+ ToolApprovalWorkflowEvent
24
+ )
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+ class WorkflowFactory(metaclass=SingletonMeta):
29
+ """
30
+ A singleton factory for creating and managing AgenticWorkflow instances.
31
+ It orchestrates the assembly of all core workflow components.
32
+ """
33
+ def __init__(self):
34
+ self._active_workflows: Dict[str, AgenticWorkflow] = {}
35
+ logger.info("WorkflowFactory (Singleton) initialized.")
36
+
37
+ def _get_default_event_handler_registry(self) -> WorkflowEventHandlerRegistry:
38
+ """Returns a registry with default handlers for a new workflow."""
39
+ registry = WorkflowEventHandlerRegistry()
40
+ registry.register(ProcessUserMessageEvent, ProcessUserMessageEventHandler())
41
+ registry.register(InterAgentMessageRequestEvent, InterAgentMessageRequestEventHandler())
42
+ registry.register(ToolApprovalWorkflowEvent, ToolApprovalWorkflowEventHandler())
43
+ lifecycle_handler = LifecycleWorkflowEventHandler()
44
+ registry.register(WorkflowReadyEvent, lifecycle_handler)
45
+ registry.register(WorkflowErrorEvent, lifecycle_handler)
46
+ return registry
47
+
48
+ def create_workflow(self, config: WorkflowConfig) -> AgenticWorkflow:
49
+ """
50
+ Creates a new workflow based on the provided WorkflowConfig, stores it,
51
+ and returns its facade (AgenticWorkflow).
52
+ """
53
+ if not isinstance(config, WorkflowConfig):
54
+ raise TypeError(f"Expected WorkflowConfig instance, got {type(config).__name__}.")
55
+
56
+ workflow_id = f"workflow_{uuid.uuid4().hex[:8]}"
57
+ while workflow_id in self._active_workflows:
58
+ workflow_id = f"workflow_{uuid.uuid4().hex[:8]}"
59
+
60
+ # --- Component Assembly as per new architecture ---
61
+ state = WorkflowRuntimeState(workflow_id=workflow_id)
62
+ context = WorkflowContext(workflow_id=workflow_id, config=config, state=state)
63
+
64
+ handler_registry = self._get_default_event_handler_registry()
65
+ runtime = WorkflowRuntime(context=context, event_handler_registry=handler_registry)
66
+
67
+ team_manager = TeamManager(
68
+ workflow_id=workflow_id,
69
+ runtime=runtime,
70
+ multiplexer=runtime.multiplexer # Pass multiplexer created in runtime
71
+ )
72
+
73
+ context.state.team_manager = team_manager
74
+
75
+ workflow = AgenticWorkflow(runtime=runtime)
76
+
77
+ self._active_workflows[workflow_id] = workflow
78
+ logger.info(f"Workflow '{workflow_id}' created and stored successfully.")
79
+ return workflow
80
+
81
+ def get_workflow(self, workflow_id: str) -> Optional[AgenticWorkflow]:
82
+ """Retrieves an active workflow instance by its ID."""
83
+ return self._active_workflows.get(workflow_id)
84
+
85
+ async def remove_workflow(self, workflow_id: str, shutdown_timeout: float = 10.0) -> bool:
86
+ """
87
+ Removes a workflow from the factory's management and gracefully stops it.
88
+ """
89
+ workflow = self._active_workflows.pop(workflow_id, None)
90
+ if workflow:
91
+ logger.info(f"Removing workflow '{workflow_id}'. Attempting graceful shutdown.")
92
+ await workflow.stop(timeout=shutdown_timeout)
93
+ return True
94
+ logger.warning(f"Workflow with ID '{workflow_id}' not found for removal.")
95
+ return False
96
+
97
+ def list_active_workflow_ids(self) -> List[str]:
98
+ """Returns a list of IDs of all active workflows managed by this factory."""
99
+ return list(self._active_workflows.keys())
@@ -0,0 +1,19 @@
1
+ # file: autobyteus/autobyteus/workflow/handlers/__init__.py
2
+ """
3
+ Event handlers for the workflow runtime.
4
+ """
5
+ from autobyteus.workflow.handlers.base_workflow_event_handler import BaseWorkflowEventHandler
6
+ from autobyteus.workflow.handlers.lifecycle_workflow_event_handler import LifecycleWorkflowEventHandler
7
+ from autobyteus.workflow.handlers.inter_agent_message_request_event_handler import InterAgentMessageRequestEventHandler
8
+ from autobyteus.workflow.handlers.process_user_message_event_handler import ProcessUserMessageEventHandler
9
+ from autobyteus.workflow.handlers.tool_approval_workflow_event_handler import ToolApprovalWorkflowEventHandler
10
+ from autobyteus.workflow.handlers.workflow_event_handler_registry import WorkflowEventHandlerRegistry
11
+
12
+ __all__ = [
13
+ "BaseWorkflowEventHandler",
14
+ "LifecycleWorkflowEventHandler",
15
+ "InterAgentMessageRequestEventHandler",
16
+ "ProcessUserMessageEventHandler",
17
+ "ToolApprovalWorkflowEventHandler",
18
+ "WorkflowEventHandlerRegistry",
19
+ ]
@@ -0,0 +1,16 @@
1
+ # file: autobyteus/autobyteus/workflow/handlers/base_workflow_event_handler.py
2
+ import logging
3
+ from abc import ABC, abstractmethod
4
+ from typing import Any, TYPE_CHECKING
5
+
6
+ if TYPE_CHECKING:
7
+ from autobyteus.workflow.context.workflow_context import WorkflowContext
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ class BaseWorkflowEventHandler(ABC):
12
+ """Abstract base class for workflow event handlers."""
13
+
14
+ @abstractmethod
15
+ async def handle(self, event: Any, context: 'WorkflowContext') -> None:
16
+ raise NotImplementedError("Subclasses must implement the 'handle' method.")
@@ -0,0 +1,61 @@
1
+ # file: autobyteus/autobyteus/workflow/handlers/inter_agent_message_request_event_handler.py
2
+ import logging
3
+ from typing import TYPE_CHECKING
4
+
5
+ from autobyteus.workflow.handlers.base_workflow_event_handler import BaseWorkflowEventHandler
6
+ from autobyteus.workflow.events.workflow_events import InterAgentMessageRequestEvent
7
+ from autobyteus.agent.message.inter_agent_message import InterAgentMessage
8
+ from autobyteus.agent.message.agent_input_user_message import AgentInputUserMessage
9
+ from autobyteus.workflow.agentic_workflow import AgenticWorkflow
10
+ from autobyteus.agent.agent import Agent
11
+
12
+ if TYPE_CHECKING:
13
+ from autobyteus.workflow.context.workflow_context import WorkflowContext
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ class InterAgentMessageRequestEventHandler(BaseWorkflowEventHandler):
18
+ """
19
+ Handles requests to send messages between nodes (agents or sub-workflows).
20
+ It relies on the TeamManager to handle on-demand startup of the recipient.
21
+ """
22
+ async def handle(self, event: InterAgentMessageRequestEvent, context: 'WorkflowContext') -> None:
23
+ workflow_id = context.workflow_id
24
+ team_manager = context.team_manager
25
+
26
+ if not team_manager:
27
+ logger.error(f"Workflow '{workflow_id}': TeamManager not found. Cannot route message from '{event.sender_agent_id}' to '{event.recipient_name}'.")
28
+ return
29
+
30
+ try:
31
+ target_node = await team_manager.ensure_node_is_ready(event.recipient_name)
32
+ except Exception as e:
33
+ msg = f"Recipient node '{event.recipient_name}' not found or failed to start for message from '{event.sender_agent_id}'. Error: {e}"
34
+ logger.error(f"Workflow '{workflow_id}': {msg}", exc_info=True)
35
+ return
36
+
37
+ try:
38
+ if isinstance(target_node, AgenticWorkflow):
39
+ # If target is a sub-workflow, post a user message to it.
40
+ # The sub-workflow will route it to its own coordinator.
41
+ message_for_workflow = AgentInputUserMessage(content=event.content)
42
+ await target_node.post_message(message_for_workflow)
43
+ logger.info(f"Workflow '{workflow_id}': Successfully posted message from '{event.sender_agent_id}' to sub-workflow '{event.recipient_name}'.")
44
+
45
+ elif isinstance(target_node, Agent):
46
+ # If target is a regular agent, create and post an InterAgentMessage.
47
+ message_for_agent = InterAgentMessage.create_with_dynamic_message_type(
48
+ recipient_role_name=target_node.context.config.role,
49
+ recipient_agent_id=target_node.agent_id,
50
+ content=event.content,
51
+ message_type=event.message_type,
52
+ sender_agent_id=event.sender_agent_id
53
+ )
54
+ await target_node.post_inter_agent_message(message_for_agent)
55
+ logger.info(f"Workflow '{workflow_id}': Successfully posted message from '{event.sender_agent_id}' to agent '{event.recipient_name}'.")
56
+ else:
57
+ raise TypeError(f"Target node '{event.recipient_name}' is of an unsupported type: {type(target_node).__name__}")
58
+
59
+ except Exception as e:
60
+ msg = f"Error posting message to node '{event.recipient_name}': {e}"
61
+ logger.error(f"Workflow '{workflow_id}': {msg}", exc_info=True)
@@ -0,0 +1,27 @@
1
+ # file: autobyteus/autobyteus/workflow/handlers/lifecycle_workflow_event_handler.py
2
+ import logging
3
+ from typing import TYPE_CHECKING
4
+
5
+ from autobyteus.workflow.handlers.base_workflow_event_handler import BaseWorkflowEventHandler
6
+ from autobyteus.workflow.events.workflow_events import BaseWorkflowEvent, WorkflowReadyEvent, WorkflowErrorEvent
7
+
8
+ if TYPE_CHECKING:
9
+ from autobyteus.workflow.context.workflow_context import WorkflowContext
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ class LifecycleWorkflowEventHandler(BaseWorkflowEventHandler):
14
+ """Logs various lifecycle events for a workflow."""
15
+ async def handle(self, event: BaseWorkflowEvent, context: 'WorkflowContext') -> None:
16
+ workflow_id = context.workflow_id
17
+ current_phase = context.state.current_phase.value
18
+
19
+ if isinstance(event, WorkflowReadyEvent):
20
+ logger.info(f"Workflow '{workflow_id}' Logged WorkflowReadyEvent. Current phase: {current_phase}")
21
+ elif isinstance(event, WorkflowErrorEvent):
22
+ logger.error(
23
+ f"Workflow '{workflow_id}' Logged WorkflowErrorEvent: {event.error_message}. "
24
+ f"Details: {event.exception_details}. Current phase: {current_phase}"
25
+ )
26
+ else:
27
+ logger.warning(f"LifecycleWorkflowEventHandler received unhandled event type: {type(event).__name__}")
@@ -0,0 +1,46 @@
1
+ # file: autobyteus/autobyteus/workflow/handlers/process_user_message_event_handler.py
2
+ import logging
3
+ from typing import TYPE_CHECKING
4
+ from autobyteus.workflow.handlers.base_workflow_event_handler import BaseWorkflowEventHandler
5
+ from autobyteus.workflow.events.workflow_events import ProcessUserMessageEvent
6
+ from autobyteus.agent.agent import Agent
7
+ from autobyteus.workflow.agentic_workflow import AgenticWorkflow
8
+ from autobyteus.agent.message.agent_input_user_message import AgentInputUserMessage
9
+
10
+ if TYPE_CHECKING:
11
+ from autobyteus.workflow.context.workflow_context import WorkflowContext
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ class ProcessUserMessageEventHandler(BaseWorkflowEventHandler):
16
+ """Handles user messages by routing them to the specified target agent or sub-workflow."""
17
+ async def handle(self, event: ProcessUserMessageEvent, context: 'WorkflowContext') -> None:
18
+ await context.phase_manager.notify_processing_started()
19
+
20
+ team_manager = context.team_manager
21
+ if not team_manager:
22
+ msg = f"Workflow '{context.workflow_id}': TeamManager not found. Cannot route message."
23
+ logger.error(msg)
24
+ await context.phase_manager.notify_error_occurred(msg, "TeamManager is not initialized.")
25
+ return
26
+
27
+ try:
28
+ target_node = await team_manager.ensure_node_is_ready(event.target_agent_name)
29
+ except Exception as e:
30
+ msg = f"Workflow '{context.workflow_id}': Node '{event.target_agent_name}' not found or failed to start. Cannot route message. Error: {e}"
31
+ logger.error(msg, exc_info=True)
32
+ await context.phase_manager.notify_error_occurred(msg, f"Node '{event.target_agent_name}' not found or failed to start.")
33
+ return
34
+
35
+ if isinstance(target_node, Agent):
36
+ await target_node.post_user_message(event.user_message)
37
+ logger.info(f"Workflow '{context.workflow_id}': Routed user message to agent node '{event.target_agent_name}'.")
38
+ elif isinstance(target_node, AgenticWorkflow):
39
+ await target_node.post_message(event.user_message)
40
+ logger.info(f"Workflow '{context.workflow_id}': Routed user message to sub-workflow node '{event.target_agent_name}'.")
41
+ else:
42
+ msg = f"Target node '{event.target_agent_name}' is of an unsupported type: {type(target_node).__name__}"
43
+ logger.error(f"Workflow '{context.workflow_id}': {msg}")
44
+ await context.phase_manager.notify_error_occurred(msg, "")
45
+
46
+ await context.phase_manager.notify_processing_complete_and_idle()
@@ -0,0 +1,39 @@
1
+ # file: autobyteus/autobyteus/workflow/handlers/tool_approval_workflow_event_handler.py
2
+ import logging
3
+ from typing import TYPE_CHECKING
4
+
5
+ from autobyteus.workflow.handlers.base_workflow_event_handler import BaseWorkflowEventHandler
6
+ from autobyteus.workflow.events.workflow_events import ToolApprovalWorkflowEvent
7
+
8
+ if TYPE_CHECKING:
9
+ from autobyteus.workflow.context.workflow_context import WorkflowContext
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ class ToolApprovalWorkflowEventHandler(BaseWorkflowEventHandler):
14
+ """
15
+ Handles tool approval events by routing them to the correct agent.
16
+ """
17
+ async def handle(self, event: ToolApprovalWorkflowEvent, context: 'WorkflowContext') -> None:
18
+ workflow_id = context.workflow_id
19
+ team_manager = context.team_manager
20
+
21
+ if not team_manager:
22
+ msg = f"Workflow '{workflow_id}': TeamManager not found. Cannot route approval for agent '{event.agent_name}'."
23
+ logger.error(msg)
24
+ await context.phase_manager.notify_error_occurred(msg, "TeamManager is not initialized.")
25
+ return
26
+
27
+ target_agent = await team_manager.ensure_agent_is_ready(event.agent_name)
28
+ if not target_agent:
29
+ msg = f"Workflow '{workflow_id}': Target agent '{event.agent_name}' for approval not found or failed to start."
30
+ logger.error(msg)
31
+ await context.phase_manager.notify_error_occurred(msg, f"Agent '{event.agent_name}' not found or failed to start.")
32
+ return
33
+
34
+ logger.info(f"Workflow '{workflow_id}': Posting tool approval (Approved: {event.is_approved}) to agent '{event.agent_name}' for invocation '{event.tool_invocation_id}'.")
35
+ await target_agent.post_tool_execution_approval(
36
+ tool_invocation_id=event.tool_invocation_id,
37
+ is_approved=event.is_approved,
38
+ reason=event.reason
39
+ )
@@ -0,0 +1,23 @@
1
+ # file: autobyteus/autobyteus/workflow/handlers/workflow_event_handler_registry.py
2
+ import logging
3
+ from typing import Dict, Type, Optional
4
+
5
+ from autobyteus.workflow.handlers.base_workflow_event_handler import BaseWorkflowEventHandler
6
+ from autobyteus.workflow.events.workflow_events import BaseWorkflowEvent
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ class WorkflowEventHandlerRegistry:
11
+ """Manages registration and retrieval of workflow event handlers."""
12
+ def __init__(self):
13
+ self._handlers: Dict[Type[BaseWorkflowEvent], BaseWorkflowEventHandler] = {}
14
+ logger.info("WorkflowEventHandlerRegistry initialized.")
15
+
16
+ def register(self, event_class: Type[BaseWorkflowEvent], handler_instance: BaseWorkflowEventHandler):
17
+ if not issubclass(event_class, BaseWorkflowEvent):
18
+ raise TypeError("Can only register handlers for BaseWorkflowEvent subclasses.")
19
+ self._handlers[event_class] = handler_instance
20
+ logger.info(f"Handler '{type(handler_instance).__name__}' registered for event '{event_class.__name__}'.")
21
+
22
+ def get_handler(self, event_class: Type[BaseWorkflowEvent]) -> Optional[BaseWorkflowEventHandler]:
23
+ return self._handlers.get(event_class)
@@ -0,0 +1,11 @@
1
+ # file: autobyteus/autobyteus/workflow/phases/__init__.py
2
+ """
3
+ This package contains components for defining and managing workflow operational phases.
4
+ """
5
+ from autobyteus.workflow.phases.workflow_operational_phase import WorkflowOperationalPhase
6
+ from autobyteus.workflow.phases.workflow_phase_manager import WorkflowPhaseManager
7
+
8
+ __all__ = [
9
+ "WorkflowOperationalPhase",
10
+ "WorkflowPhaseManager",
11
+ ]