"""Node executor protocol and registry.""" from __future__ import annotations from typing import Any, Protocol, runtime_checkable from deerflow.workflows.errors import WorkflowError from deerflow.workflows.ports import ACTIVE_PORTS from deerflow.workflows.runtime.context import RunContext from deerflow.workflows.schemas import NodeResult, NodeType, WorkflowNode @runtime_checkable class NodeExecutor(Protocol): async def execute(self, node: WorkflowNode, ctx: RunContext) -> NodeResult: ... class NodeRegistry: """Maps node type → executor. Unknown types fail with a typed error.""" def __init__(self) -> None: self._executors: dict[str, NodeExecutor] = {} def register(self, node_type: NodeType | str, executor: NodeExecutor) -> None: self._executors[str(node_type)] = executor def get(self, node_type: str) -> NodeExecutor: executor = self._executors.get(node_type) if executor is None: raise WorkflowError( "WORKFLOW_RESOURCE_MISSING", f"节点类型暂不支持执行:{node_type}", details={"nodeType": node_type}, ) return executor def supported(self) -> list[str]: return sorted(self._executors) def require_dep(value: Any, *, node: WorkflowNode, what: str) -> Any: if value is None: raise WorkflowError( "WORKFLOW_RESOURCE_MISSING", f"运行环境缺少{what}能力,无法执行该节点", node_id=node.id, details={"capability": what}, ) return value __all__ = ["ACTIVE_PORTS", "NodeExecutor", "NodeRegistry", "require_dep"]