autobyteus 1.1.3__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.
- autobyteus/agent/agent.py +1 -1
- autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +4 -2
- autobyteus/agent/context/agent_config.py +36 -5
- autobyteus/agent/events/worker_event_dispatcher.py +1 -2
- autobyteus/agent/handlers/inter_agent_message_event_handler.py +1 -1
- autobyteus/agent/handlers/llm_user_message_ready_event_handler.py +2 -2
- autobyteus/agent/handlers/tool_result_event_handler.py +48 -20
- autobyteus/agent/handlers/user_input_message_event_handler.py +1 -1
- autobyteus/agent/input_processor/__init__.py +1 -7
- autobyteus/agent/message/context_file_type.py +6 -0
- autobyteus/agent/message/send_message_to.py +68 -99
- autobyteus/agent/phases/discover.py +2 -1
- autobyteus/agent/runtime/agent_worker.py +1 -0
- autobyteus/agent/tool_execution_result_processor/__init__.py +9 -0
- autobyteus/agent/tool_execution_result_processor/base_processor.py +46 -0
- autobyteus/agent/tool_execution_result_processor/processor_definition.py +36 -0
- autobyteus/agent/tool_execution_result_processor/processor_meta.py +36 -0
- autobyteus/agent/tool_execution_result_processor/processor_registry.py +70 -0
- autobyteus/agent/workspace/base_workspace.py +17 -2
- autobyteus/cli/__init__.py +1 -1
- autobyteus/cli/cli_display.py +1 -1
- autobyteus/cli/workflow_tui/__init__.py +4 -0
- autobyteus/cli/workflow_tui/app.py +210 -0
- autobyteus/cli/workflow_tui/state.py +189 -0
- autobyteus/cli/workflow_tui/widgets/__init__.py +6 -0
- autobyteus/cli/workflow_tui/widgets/agent_list_sidebar.py +149 -0
- autobyteus/cli/workflow_tui/widgets/focus_pane.py +335 -0
- autobyteus/cli/workflow_tui/widgets/logo.py +27 -0
- autobyteus/cli/workflow_tui/widgets/renderables.py +70 -0
- autobyteus/cli/workflow_tui/widgets/shared.py +51 -0
- autobyteus/cli/workflow_tui/widgets/status_bar.py +14 -0
- autobyteus/events/event_types.py +3 -0
- autobyteus/llm/api/lmstudio_llm.py +37 -0
- autobyteus/llm/api/openai_compatible_llm.py +20 -3
- autobyteus/llm/llm_factory.py +2 -0
- autobyteus/llm/lmstudio_provider.py +89 -0
- autobyteus/llm/providers.py +1 -0
- autobyteus/llm/token_counter/token_counter_factory.py +2 -0
- autobyteus/tools/__init__.py +2 -0
- autobyteus/tools/ask_user_input.py +2 -1
- autobyteus/tools/bash/bash_executor.py +2 -1
- autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +2 -0
- autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +3 -0
- autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +3 -0
- autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +3 -0
- autobyteus/tools/browser/standalone/google_search_ui.py +2 -0
- autobyteus/tools/browser/standalone/navigate_to.py +2 -0
- autobyteus/tools/browser/standalone/web_page_pdf_generator.py +3 -0
- autobyteus/tools/browser/standalone/webpage_image_downloader.py +3 -0
- autobyteus/tools/browser/standalone/webpage_reader.py +2 -0
- autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +3 -0
- autobyteus/tools/file/file_reader.py +36 -9
- autobyteus/tools/file/file_writer.py +37 -9
- autobyteus/tools/functional_tool.py +5 -4
- autobyteus/tools/image_downloader.py +2 -0
- autobyteus/tools/mcp/tool_registrar.py +3 -1
- autobyteus/tools/pdf_downloader.py +2 -1
- autobyteus/tools/registry/tool_definition.py +12 -8
- autobyteus/tools/registry/tool_registry.py +50 -2
- autobyteus/tools/timer.py +2 -0
- autobyteus/tools/tool_category.py +14 -4
- autobyteus/tools/tool_meta.py +6 -1
- autobyteus/tools/tool_origin.py +10 -0
- autobyteus/workflow/agentic_workflow.py +93 -0
- autobyteus/{agent/workflow → workflow}/base_agentic_workflow.py +19 -27
- autobyteus/workflow/bootstrap_steps/__init__.py +20 -0
- autobyteus/workflow/bootstrap_steps/agent_tool_injection_step.py +34 -0
- autobyteus/workflow/bootstrap_steps/base_workflow_bootstrap_step.py +23 -0
- autobyteus/workflow/bootstrap_steps/coordinator_initialization_step.py +41 -0
- autobyteus/workflow/bootstrap_steps/coordinator_prompt_preparation_step.py +108 -0
- autobyteus/workflow/bootstrap_steps/workflow_bootstrapper.py +50 -0
- autobyteus/workflow/bootstrap_steps/workflow_runtime_queue_initialization_step.py +25 -0
- autobyteus/workflow/context/__init__.py +17 -0
- autobyteus/workflow/context/team_manager.py +147 -0
- autobyteus/workflow/context/workflow_config.py +30 -0
- autobyteus/workflow/context/workflow_context.py +61 -0
- autobyteus/workflow/context/workflow_node_config.py +76 -0
- autobyteus/workflow/context/workflow_runtime_state.py +53 -0
- autobyteus/workflow/events/__init__.py +29 -0
- autobyteus/workflow/events/workflow_event_dispatcher.py +39 -0
- autobyteus/workflow/events/workflow_events.py +53 -0
- autobyteus/workflow/events/workflow_input_event_queue_manager.py +21 -0
- autobyteus/workflow/exceptions.py +8 -0
- autobyteus/workflow/factory/__init__.py +9 -0
- autobyteus/workflow/factory/workflow_factory.py +99 -0
- autobyteus/workflow/handlers/__init__.py +19 -0
- autobyteus/workflow/handlers/base_workflow_event_handler.py +16 -0
- autobyteus/workflow/handlers/inter_agent_message_request_event_handler.py +61 -0
- autobyteus/workflow/handlers/lifecycle_workflow_event_handler.py +27 -0
- autobyteus/workflow/handlers/process_user_message_event_handler.py +46 -0
- autobyteus/workflow/handlers/tool_approval_workflow_event_handler.py +39 -0
- autobyteus/workflow/handlers/workflow_event_handler_registry.py +23 -0
- autobyteus/workflow/phases/__init__.py +11 -0
- autobyteus/workflow/phases/workflow_operational_phase.py +19 -0
- autobyteus/workflow/phases/workflow_phase_manager.py +48 -0
- autobyteus/workflow/runtime/__init__.py +13 -0
- autobyteus/workflow/runtime/workflow_runtime.py +82 -0
- autobyteus/workflow/runtime/workflow_worker.py +117 -0
- autobyteus/workflow/shutdown_steps/__init__.py +17 -0
- autobyteus/workflow/shutdown_steps/agent_team_shutdown_step.py +42 -0
- autobyteus/workflow/shutdown_steps/base_workflow_shutdown_step.py +16 -0
- autobyteus/workflow/shutdown_steps/bridge_cleanup_step.py +28 -0
- autobyteus/workflow/shutdown_steps/sub_workflow_shutdown_step.py +41 -0
- autobyteus/workflow/shutdown_steps/workflow_shutdown_orchestrator.py +35 -0
- autobyteus/workflow/streaming/__init__.py +26 -0
- autobyteus/workflow/streaming/agent_event_bridge.py +48 -0
- autobyteus/workflow/streaming/agent_event_multiplexer.py +70 -0
- autobyteus/workflow/streaming/workflow_event_bridge.py +50 -0
- autobyteus/workflow/streaming/workflow_event_notifier.py +83 -0
- autobyteus/workflow/streaming/workflow_event_stream.py +33 -0
- autobyteus/workflow/streaming/workflow_stream_event_payloads.py +28 -0
- autobyteus/workflow/streaming/workflow_stream_events.py +45 -0
- autobyteus/workflow/utils/__init__.py +9 -0
- autobyteus/workflow/utils/wait_for_idle.py +46 -0
- autobyteus/workflow/workflow_builder.py +151 -0
- {autobyteus-1.1.3.dist-info → autobyteus-1.1.4.dist-info}/METADATA +16 -14
- {autobyteus-1.1.3.dist-info → autobyteus-1.1.4.dist-info}/RECORD +134 -65
- {autobyteus-1.1.3.dist-info → autobyteus-1.1.4.dist-info}/top_level.txt +1 -0
- examples/__init__.py +1 -0
- examples/discover_phase_transitions.py +104 -0
- examples/run_browser_agent.py +260 -0
- examples/run_google_slides_agent.py +286 -0
- examples/run_mcp_browser_client.py +174 -0
- examples/run_mcp_google_slides_client.py +270 -0
- examples/run_mcp_list_tools.py +189 -0
- examples/run_poem_writer.py +274 -0
- examples/run_sqlite_agent.py +293 -0
- examples/workflow/__init__.py +1 -0
- examples/workflow/run_basic_research_workflow.py +189 -0
- examples/workflow/run_code_review_workflow.py +269 -0
- examples/workflow/run_debate_workflow.py +212 -0
- examples/workflow/run_workflow_with_tui.py +153 -0
- autobyteus/agent/context/agent_phase_manager.py +0 -264
- autobyteus/agent/context/phases.py +0 -49
- autobyteus/agent/group/__init__.py +0 -0
- autobyteus/agent/group/agent_group.py +0 -164
- autobyteus/agent/group/agent_group_context.py +0 -81
- autobyteus/agent/input_processor/content_prefixing_input_processor.py +0 -41
- autobyteus/agent/input_processor/metadata_appending_input_processor.py +0 -34
- autobyteus/agent/input_processor/passthrough_input_processor.py +0 -33
- autobyteus/agent/workflow/__init__.py +0 -11
- autobyteus/agent/workflow/agentic_workflow.py +0 -89
- autobyteus/tools/mcp/registrar.py +0 -202
- autobyteus/workflow/simple_task.py +0 -98
- autobyteus/workflow/task.py +0 -147
- autobyteus/workflow/workflow.py +0 -49
- {autobyteus-1.1.3.dist-info → autobyteus-1.1.4.dist-info}/WHEEL +0 -0
- {autobyteus-1.1.3.dist-info → autobyteus-1.1.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/workflow/bootstrap_steps/workflow_bootstrapper.py
|
|
2
|
+
import logging
|
|
3
|
+
from typing import TYPE_CHECKING, List, Optional
|
|
4
|
+
|
|
5
|
+
from autobyteus.workflow.bootstrap_steps.base_workflow_bootstrap_step import BaseWorkflowBootstrapStep
|
|
6
|
+
from autobyteus.workflow.bootstrap_steps.workflow_runtime_queue_initialization_step import WorkflowRuntimeQueueInitializationStep
|
|
7
|
+
from autobyteus.workflow.bootstrap_steps.coordinator_prompt_preparation_step import CoordinatorPromptPreparationStep
|
|
8
|
+
from autobyteus.workflow.bootstrap_steps.agent_tool_injection_step import AgentToolInjectionStep
|
|
9
|
+
from autobyteus.workflow.bootstrap_steps.coordinator_initialization_step import CoordinatorInitializationStep
|
|
10
|
+
from autobyteus.workflow.events.workflow_events import WorkflowReadyEvent
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from autobyteus.workflow.context.workflow_context import WorkflowContext
|
|
14
|
+
from autobyteus.workflow.phases.workflow_phase_manager import WorkflowPhaseManager
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
class WorkflowBootstrapper:
|
|
19
|
+
"""Orchestrates the workflow's bootstrapping process."""
|
|
20
|
+
def __init__(self, steps: Optional[List[BaseWorkflowBootstrapStep]] = None):
|
|
21
|
+
self.bootstrap_steps = steps or [
|
|
22
|
+
WorkflowRuntimeQueueInitializationStep(),
|
|
23
|
+
CoordinatorPromptPreparationStep(),
|
|
24
|
+
AgentToolInjectionStep(),
|
|
25
|
+
CoordinatorInitializationStep(),
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
async def run(self, context: 'WorkflowContext', phase_manager: 'WorkflowPhaseManager') -> bool:
|
|
29
|
+
workflow_id = context.workflow_id
|
|
30
|
+
await phase_manager.notify_bootstrapping_started()
|
|
31
|
+
logger.info(f"Workflow '{workflow_id}': Bootstrapper starting.")
|
|
32
|
+
|
|
33
|
+
for step in self.bootstrap_steps:
|
|
34
|
+
step_name = step.__class__.__name__
|
|
35
|
+
logger.debug(f"Workflow '{workflow_id}': Executing bootstrap step: {step_name}")
|
|
36
|
+
if not await step.execute(context, phase_manager):
|
|
37
|
+
error_message = f"Bootstrap step {step_name} failed."
|
|
38
|
+
logger.error(f"Workflow '{workflow_id}': {error_message}")
|
|
39
|
+
await phase_manager.notify_error_occurred(error_message, f"Failed during bootstrap step '{step_name}'.")
|
|
40
|
+
return False
|
|
41
|
+
|
|
42
|
+
logger.info(f"Workflow '{workflow_id}': All bootstrap steps completed successfully.")
|
|
43
|
+
if context.state.input_event_queues:
|
|
44
|
+
await context.state.input_event_queues.enqueue_internal_system_event(WorkflowReadyEvent())
|
|
45
|
+
else:
|
|
46
|
+
logger.critical(f"Workflow '{workflow_id}': Bootstrap succeeded but queues not available.")
|
|
47
|
+
await phase_manager.notify_error_occurred("Queues unavailable after bootstrap.", "")
|
|
48
|
+
return False
|
|
49
|
+
|
|
50
|
+
return True
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/workflow/bootstrap_steps/workflow_runtime_queue_initialization_step.py
|
|
2
|
+
import logging
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from autobyteus.workflow.bootstrap_steps.base_workflow_bootstrap_step import BaseWorkflowBootstrapStep
|
|
6
|
+
from autobyteus.workflow.events.workflow_input_event_queue_manager import WorkflowInputEventQueueManager
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from autobyteus.workflow.context.workflow_context import WorkflowContext
|
|
10
|
+
from autobyteus.workflow.phases.workflow_phase_manager import WorkflowPhaseManager
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
class WorkflowRuntimeQueueInitializationStep(BaseWorkflowBootstrapStep):
|
|
15
|
+
"""Bootstrap step for initializing the workflow's runtime event queues."""
|
|
16
|
+
async def execute(self, context: 'WorkflowContext', phase_manager: 'WorkflowPhaseManager') -> bool:
|
|
17
|
+
workflow_id = context.workflow_id
|
|
18
|
+
logger.info(f"Workflow '{workflow_id}': Executing WorkflowRuntimeQueueInitializationStep.")
|
|
19
|
+
try:
|
|
20
|
+
context.state.input_event_queues = WorkflowInputEventQueueManager()
|
|
21
|
+
logger.info(f"Workflow '{workflow_id}': WorkflowInputEventQueueManager initialized.")
|
|
22
|
+
return True
|
|
23
|
+
except Exception as e:
|
|
24
|
+
logger.error(f"Workflow '{workflow_id}': Critical failure during queue initialization: {e}", exc_info=True)
|
|
25
|
+
return False
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/workflow/context/__init__.py
|
|
2
|
+
"""
|
|
3
|
+
Components related to the workflow's runtime context, state, and configuration.
|
|
4
|
+
"""
|
|
5
|
+
from autobyteus.workflow.context.team_manager import TeamManager
|
|
6
|
+
from autobyteus.workflow.context.workflow_config import WorkflowConfig
|
|
7
|
+
from autobyteus.workflow.context.workflow_context import WorkflowContext
|
|
8
|
+
from autobyteus.workflow.context.workflow_node_config import WorkflowNodeConfig
|
|
9
|
+
from autobyteus.workflow.context.workflow_runtime_state import WorkflowRuntimeState
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"TeamManager",
|
|
13
|
+
"WorkflowConfig",
|
|
14
|
+
"WorkflowContext",
|
|
15
|
+
"WorkflowNodeConfig",
|
|
16
|
+
"WorkflowRuntimeState",
|
|
17
|
+
]
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/workflow/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.workflow.utils.wait_for_idle import wait_for_workflow_to_be_idle
|
|
9
|
+
from autobyteus.workflow.exceptions import WorkflowNodeNotFoundException
|
|
10
|
+
from autobyteus.agent.message.send_message_to import SendMessageTo
|
|
11
|
+
from autobyteus.tools.registry import default_tool_registry
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from autobyteus.agent.agent import Agent
|
|
15
|
+
from autobyteus.workflow.agentic_workflow import AgenticWorkflow
|
|
16
|
+
from autobyteus.workflow.events.workflow_events import InterAgentMessageRequestEvent
|
|
17
|
+
from autobyteus.workflow.runtime.workflow_runtime import WorkflowRuntime
|
|
18
|
+
from autobyteus.workflow.streaming.agent_event_multiplexer import AgentEventMultiplexer
|
|
19
|
+
from autobyteus.agent.context.agent_config import AgentConfig
|
|
20
|
+
from autobyteus.workflow.context.workflow_config import WorkflowConfig
|
|
21
|
+
|
|
22
|
+
ManagedNode = Union['Agent', 'AgenticWorkflow']
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
class TeamManager:
|
|
27
|
+
"""
|
|
28
|
+
Manages all nodes (agents and sub-workflows) within a workflow. It handles
|
|
29
|
+
lazy creation, on-demand startup, and provides access to managed instances.
|
|
30
|
+
"""
|
|
31
|
+
def __init__(self, workflow_id: str, runtime: 'WorkflowRuntime', multiplexer: 'AgentEventMultiplexer'):
|
|
32
|
+
self.workflow_id = workflow_id
|
|
33
|
+
self._runtime = runtime
|
|
34
|
+
self._multiplexer = multiplexer
|
|
35
|
+
self._agent_factory = AgentFactory()
|
|
36
|
+
self._nodes_cache: Dict[str, ManagedNode] = {}
|
|
37
|
+
self._coordinator_agent: Optional['Agent'] = None
|
|
38
|
+
logger.info(f"TeamManager created for workflow '{self.workflow_id}'.")
|
|
39
|
+
|
|
40
|
+
async def dispatch_inter_agent_message_request(self, event: 'InterAgentMessageRequestEvent'):
|
|
41
|
+
await self._runtime.submit_event(event)
|
|
42
|
+
|
|
43
|
+
async def ensure_node_is_ready(self, name: str) -> ManagedNode:
|
|
44
|
+
"""
|
|
45
|
+
Retrieves a node (agent or sub-workflow) by its unique friendly name.
|
|
46
|
+
If the node has not been created yet, it is instantiated. If it is not
|
|
47
|
+
running, it is started and awaited until idle.
|
|
48
|
+
Returns a fully ready node instance or raises an exception.
|
|
49
|
+
"""
|
|
50
|
+
node_instance = self._nodes_cache.get(name)
|
|
51
|
+
|
|
52
|
+
was_created = False
|
|
53
|
+
if not node_instance:
|
|
54
|
+
logger.debug(f"Node '{name}' not in cache for workflow '{self.workflow_id}'. Attempting lazy creation.")
|
|
55
|
+
|
|
56
|
+
node_config_wrapper = self._runtime.context.get_node_config_by_name(name)
|
|
57
|
+
if not node_config_wrapper:
|
|
58
|
+
raise WorkflowNodeNotFoundException(node_name=name, workflow_id=self.workflow_id)
|
|
59
|
+
|
|
60
|
+
node_definition = node_config_wrapper.node_definition
|
|
61
|
+
|
|
62
|
+
if node_config_wrapper.is_subworkflow:
|
|
63
|
+
from autobyteus.workflow.factory.workflow_factory import WorkflowFactory
|
|
64
|
+
from autobyteus.workflow.context.workflow_config import WorkflowConfig
|
|
65
|
+
|
|
66
|
+
workflow_factory = WorkflowFactory() # Get singleton instance
|
|
67
|
+
if not isinstance(node_definition, WorkflowConfig):
|
|
68
|
+
raise TypeError(f"Expected WorkflowConfig for node '{name}', but found {type(node_definition)}")
|
|
69
|
+
logger.info(f"Lazily creating sub-workflow node '{name}' in workflow '{self.workflow_id}'.")
|
|
70
|
+
node_instance = workflow_factory.create_workflow(config=node_definition)
|
|
71
|
+
else:
|
|
72
|
+
from autobyteus.agent.context.agent_config import AgentConfig
|
|
73
|
+
if not isinstance(node_definition, AgentConfig):
|
|
74
|
+
raise TypeError(f"Expected AgentConfig for node '{name}', but found {type(node_definition)}")
|
|
75
|
+
|
|
76
|
+
# --- Apply Deferred Logic from Bootstrap Step ---
|
|
77
|
+
final_config = node_definition.copy()
|
|
78
|
+
|
|
79
|
+
# 1. Inject SendMessageTo tool
|
|
80
|
+
send_message_tool = default_tool_registry.create_tool(SendMessageTo.get_name())
|
|
81
|
+
if isinstance(send_message_tool, SendMessageTo):
|
|
82
|
+
send_message_tool.set_team_manager(self)
|
|
83
|
+
final_config.tools = [t for t in final_config.tools if not isinstance(t, SendMessageTo)]
|
|
84
|
+
final_config.tools.append(send_message_tool)
|
|
85
|
+
|
|
86
|
+
# 2. Apply coordinator prompt if this is the coordinator
|
|
87
|
+
coordinator_node_name = self._runtime.context.config.coordinator_node.name
|
|
88
|
+
if name == coordinator_node_name:
|
|
89
|
+
coordinator_prompt = self._runtime.context.state.prepared_coordinator_prompt
|
|
90
|
+
if coordinator_prompt:
|
|
91
|
+
final_config.system_prompt = coordinator_prompt
|
|
92
|
+
logger.info(f"Applied dynamic prompt to coordinator '{name}'.")
|
|
93
|
+
|
|
94
|
+
logger.info(f"Lazily creating agent node '{name}' in workflow '{self.workflow_id}'.")
|
|
95
|
+
node_instance = self._agent_factory.create_agent(config=final_config)
|
|
96
|
+
|
|
97
|
+
self._nodes_cache[name] = node_instance
|
|
98
|
+
was_created = True
|
|
99
|
+
|
|
100
|
+
if was_created and node_instance:
|
|
101
|
+
from autobyteus.workflow.agentic_workflow import AgenticWorkflow
|
|
102
|
+
from autobyteus.agent.agent import Agent
|
|
103
|
+
if isinstance(node_instance, AgenticWorkflow):
|
|
104
|
+
self._multiplexer.start_bridging_workflow_events(node_instance, name)
|
|
105
|
+
elif isinstance(node_instance, Agent):
|
|
106
|
+
self._multiplexer.start_bridging_agent_events(node_instance, name)
|
|
107
|
+
|
|
108
|
+
# On-Demand Startup Logic
|
|
109
|
+
if not node_instance.is_running:
|
|
110
|
+
from autobyteus.workflow.agentic_workflow import AgenticWorkflow
|
|
111
|
+
logger.info(f"Workflow '{self.workflow_id}': Node '{name}' is not running. Starting on-demand.")
|
|
112
|
+
try:
|
|
113
|
+
node_instance.start()
|
|
114
|
+
if isinstance(node_instance, AgenticWorkflow):
|
|
115
|
+
await wait_for_workflow_to_be_idle(node_instance, timeout=120.0)
|
|
116
|
+
else:
|
|
117
|
+
await wait_for_agent_to_be_idle(node_instance, timeout=60.0)
|
|
118
|
+
except Exception as e:
|
|
119
|
+
logger.error(f"Workflow '{self.workflow_id}': Failed to start node '{name}' on-demand: {e}", exc_info=True)
|
|
120
|
+
raise RuntimeError(f"Failed to start node '{name}' on-demand.") from e
|
|
121
|
+
|
|
122
|
+
return node_instance
|
|
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_workflows(self) -> List['AgenticWorkflow']:
|
|
129
|
+
from autobyteus.workflow.agentic_workflow import AgenticWorkflow
|
|
130
|
+
return [node for node in self._nodes_cache.values() if isinstance(node, AgenticWorkflow)]
|
|
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(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,30 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/workflow/context/workflow_config.py
|
|
2
|
+
import logging
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import List, Optional, Tuple
|
|
5
|
+
|
|
6
|
+
from autobyteus.workflow.context.workflow_node_config import WorkflowNodeConfig
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class WorkflowConfig:
|
|
12
|
+
"""
|
|
13
|
+
Represents the complete, static configuration for an AgenticWorkflow instance.
|
|
14
|
+
This is the user's primary input for defining a workflow.
|
|
15
|
+
"""
|
|
16
|
+
name: str
|
|
17
|
+
description: str
|
|
18
|
+
nodes: Tuple[WorkflowNodeConfig, ...]
|
|
19
|
+
coordinator_node: WorkflowNodeConfig
|
|
20
|
+
role: Optional[str] = None
|
|
21
|
+
|
|
22
|
+
def __post_init__(self):
|
|
23
|
+
if not self.name or not isinstance(self.name, str):
|
|
24
|
+
raise ValueError("The 'name' in WorkflowConfig must be a non-empty string.")
|
|
25
|
+
if not self.nodes:
|
|
26
|
+
raise ValueError("The 'nodes' collection in WorkflowConfig cannot be empty.")
|
|
27
|
+
if self.coordinator_node not in self.nodes:
|
|
28
|
+
raise ValueError("The 'coordinator_node' must be one of the nodes in the 'nodes' collection.")
|
|
29
|
+
logger.debug(f"WorkflowConfig validated for workflow: '{self.name}'.")
|
|
30
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/workflow/context/workflow_context.py
|
|
2
|
+
import logging
|
|
3
|
+
from typing import TYPE_CHECKING, List, Optional, Dict
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from autobyteus.workflow.context.workflow_config import WorkflowConfig
|
|
7
|
+
from autobyteus.workflow.context.workflow_runtime_state import WorkflowRuntimeState
|
|
8
|
+
from autobyteus.agent.agent import Agent
|
|
9
|
+
from autobyteus.workflow.phases.workflow_phase_manager import WorkflowPhaseManager
|
|
10
|
+
from autobyteus.workflow.context.team_manager import TeamManager
|
|
11
|
+
from autobyteus.workflow.streaming.agent_event_multiplexer import AgentEventMultiplexer
|
|
12
|
+
from autobyteus.agent.context import AgentConfig
|
|
13
|
+
from autobyteus.workflow.context.workflow_node_config import WorkflowNodeConfig
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
class WorkflowContext:
|
|
18
|
+
"""Represents the complete operational context for a single workflow instance."""
|
|
19
|
+
def __init__(self, workflow_id: str, config: 'WorkflowConfig', state: 'WorkflowRuntimeState'):
|
|
20
|
+
if not workflow_id or not isinstance(workflow_id, str):
|
|
21
|
+
raise ValueError("WorkflowContext requires a non-empty string 'workflow_id'.")
|
|
22
|
+
|
|
23
|
+
self.workflow_id: str = workflow_id
|
|
24
|
+
self.config: 'WorkflowConfig' = config
|
|
25
|
+
self.state: 'WorkflowRuntimeState' = state
|
|
26
|
+
self._node_config_map: Optional[Dict[str, 'WorkflowNodeConfig']] = None
|
|
27
|
+
|
|
28
|
+
logger.info(f"WorkflowContext composed for workflow_id '{self.workflow_id}'.")
|
|
29
|
+
|
|
30
|
+
def get_node_config_by_name(self, name: str) -> Optional['WorkflowNodeConfig']:
|
|
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['WorkflowPhaseManager']:
|
|
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,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
|