from ai_orchestrator.application.services.execution import ( DefaultFinalizer, FinalizerNodeRunner, GraphExecutionEngine, NoOpReviewer, PlannerNodeRunner, RunnerRegistry, ) from ai_orchestrator.domain.enums import NodeStatus, NodeType, TaskStatus from ai_orchestrator.domain.models import ExecutionGraph, ExecutionNode, Task from ai_orchestrator.infrastructure.storage.memory import InMemoryEventStore def test_execution_engine_runs_ready_nodes_and_records_events() -> None: task = Task(project_id="default", goal="Run planner", inputs={}) planner = ExecutionNode(task_id=task.task_id, node_type=NodeType.PLANNER, input_data={}) finalizer = ExecutionNode( task_id=task.task_id, node_type=NodeType.FINALIZER, input_data={}, dependencies=[planner.node_id], ) graph = ExecutionGraph(task_id=task.task_id, nodes=[planner, finalizer]) event_store = InMemoryEventStore() registry = RunnerRegistry() registry.register(PlannerNodeRunner()) registry.register(FinalizerNodeRunner(finalizer=DefaultFinalizer())) engine = GraphExecutionEngine( event_store=event_store, runner_registry=registry, reviewer=NoOpReviewer(), ) first_pass = engine.execute_ready_nodes(task=task, graph=graph) second_pass = engine.execute_ready_nodes(task=task, graph=graph) assert len(first_pass) == 1 assert len(second_pass) == 1 assert planner.status == NodeStatus.COMPLETED assert finalizer.status == NodeStatus.COMPLETED assert task.status == TaskStatus.RUNNING assert [event.event_type for event in event_store.items] == [ "node_started", "node_completed", "node_started", "node_completed", ]