in the folders 3
This commit is contained in:
@@ -1,343 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping
|
||||
from typing import Any
|
||||
|
||||
from .errors import WorkflowExecutionError
|
||||
from .foreach_ops import step_foreach
|
||||
from .flow_ops import advance_frame, append_step_result_trace, finalize_run
|
||||
from .frame_ops import collapse_completed_frames
|
||||
from .interrupt_ops import resume_interrupt
|
||||
from .model import (
|
||||
ConditionNode,
|
||||
ForeachNode,
|
||||
InterruptNode,
|
||||
JoinNode,
|
||||
NodeUse,
|
||||
Workflow,
|
||||
)
|
||||
from .node_exec import (
|
||||
AsyncNodeHandler,
|
||||
NodeHandler,
|
||||
coerce_node_result,
|
||||
execute_node_use,
|
||||
execute_node_use_async,
|
||||
)
|
||||
from .run_factory import create_run_state
|
||||
from .run_state import (
|
||||
FrameStatus,
|
||||
RunState,
|
||||
RunStatus,
|
||||
)
|
||||
from .schema_tools import validate_payload_against_schema
|
||||
from .step_handlers import (
|
||||
handle_condition_step,
|
||||
handle_interrupt_step,
|
||||
handle_join_step,
|
||||
)
|
||||
from .tokens import END
|
||||
from .workflow_index import WorkflowIndex, build_workflow_index
|
||||
|
||||
__all__ = [
|
||||
"AsyncNodeHandler",
|
||||
"NodeHandler",
|
||||
"coerce_node_result",
|
||||
"execute_workflow_async",
|
||||
"execute_workflow",
|
||||
"resume_workflow_async",
|
||||
"resume_workflow",
|
||||
"step_workflow_async",
|
||||
"step_workflow",
|
||||
]
|
||||
|
||||
|
||||
def _prepare_new_run(workflow: Workflow, workflow_input: dict[str, Any]) -> RunState:
|
||||
run = create_run_state(workflow, workflow_input)
|
||||
workflow.validate_structure().raise_for_errors()
|
||||
validate_payload_against_schema(
|
||||
workflow.input_schema, workflow_input, "workflow input"
|
||||
)
|
||||
return run
|
||||
|
||||
|
||||
def _prepare_resume(
|
||||
workflow: Workflow,
|
||||
run: RunState,
|
||||
*,
|
||||
resume_payload: dict[str, Any] | None,
|
||||
resume_outcome: str,
|
||||
) -> WorkflowIndex | None:
|
||||
if run.workflow_name != workflow.name:
|
||||
raise WorkflowExecutionError(
|
||||
f"run state belongs to workflow {run.workflow_name!r}, not {workflow.name!r}"
|
||||
)
|
||||
|
||||
if run.current_frame_id is None:
|
||||
raise WorkflowExecutionError("run has no current frame")
|
||||
collapse_completed_frames(run)
|
||||
|
||||
if run.current_node_id is None:
|
||||
raise WorkflowExecutionError("run has no current node")
|
||||
|
||||
if run.status == RunStatus.COMPLETED:
|
||||
return None
|
||||
|
||||
index = build_workflow_index(workflow)
|
||||
|
||||
if run.status == RunStatus.INTERRUPTED:
|
||||
if resume_payload is None:
|
||||
return None
|
||||
resume_interrupt(
|
||||
workflow,
|
||||
run,
|
||||
index=index,
|
||||
resume_payload=resume_payload,
|
||||
resume_outcome=resume_outcome,
|
||||
)
|
||||
collapse_completed_frames(run)
|
||||
if run.current_node_id == END:
|
||||
return None
|
||||
|
||||
run.status = RunStatus.RUNNING
|
||||
run.error = None
|
||||
run.current_frame().status = FrameStatus.RUNNING
|
||||
return index
|
||||
|
||||
|
||||
def _prepare_step(
|
||||
workflow: Workflow,
|
||||
run: RunState,
|
||||
index: WorkflowIndex | None,
|
||||
) -> tuple[WorkflowIndex, object] | None:
|
||||
if run.current_frame_id is None:
|
||||
raise WorkflowExecutionError("run has no current frame")
|
||||
|
||||
collapse_completed_frames(run)
|
||||
if run.current_node_id is None or run.current_node_id == END:
|
||||
return None
|
||||
if run.status == RunStatus.INTERRUPTED:
|
||||
return None
|
||||
|
||||
if run.status == RunStatus.PENDING:
|
||||
run.status = RunStatus.RUNNING
|
||||
run.error = None
|
||||
|
||||
resolved_index = index or build_workflow_index(workflow)
|
||||
frame = run.current_frame()
|
||||
if frame.status == FrameStatus.PENDING:
|
||||
frame.status = FrameStatus.RUNNING
|
||||
step = resolved_index.nodes_by_id[frame.node_id]
|
||||
return resolved_index, step
|
||||
|
||||
|
||||
def _complete_step(
|
||||
*,
|
||||
run: RunState,
|
||||
index: WorkflowIndex,
|
||||
outcome: str,
|
||||
frame_id: str,
|
||||
node_id: str,
|
||||
step_type: str,
|
||||
step_result: Any,
|
||||
) -> RunState:
|
||||
next_node_id = index.next_node_id(node_id, outcome)
|
||||
|
||||
append_step_result_trace(
|
||||
run,
|
||||
frame_id=frame_id,
|
||||
node_id=node_id,
|
||||
step_type=step_type,
|
||||
next_node_id=next_node_id,
|
||||
result=step_result,
|
||||
)
|
||||
advance_frame(
|
||||
run,
|
||||
run.frames[frame_id],
|
||||
outcome=outcome,
|
||||
next_node_id=next_node_id,
|
||||
)
|
||||
return run
|
||||
|
||||
|
||||
def execute_workflow(
|
||||
workflow: Workflow,
|
||||
workflow_input: dict[str, Any],
|
||||
registry: Mapping[str, NodeHandler],
|
||||
) -> RunState:
|
||||
run = create_run_state(workflow, workflow_input)
|
||||
|
||||
try:
|
||||
run = _prepare_new_run(workflow, workflow_input)
|
||||
return resume_workflow(workflow, run, registry)
|
||||
except Exception as exc:
|
||||
run.status = RunStatus.FAILED
|
||||
run.error = str(exc)
|
||||
raise
|
||||
|
||||
|
||||
async def execute_workflow_async(
|
||||
workflow: Workflow,
|
||||
workflow_input: dict[str, Any],
|
||||
registry: Mapping[str, AsyncNodeHandler],
|
||||
) -> RunState:
|
||||
run = create_run_state(workflow, workflow_input)
|
||||
|
||||
try:
|
||||
run = _prepare_new_run(workflow, workflow_input)
|
||||
return await resume_workflow_async(workflow, run, registry)
|
||||
except Exception as exc:
|
||||
run.status = RunStatus.FAILED
|
||||
run.error = str(exc)
|
||||
raise
|
||||
|
||||
|
||||
def resume_workflow(
|
||||
workflow: Workflow,
|
||||
run: RunState,
|
||||
registry: Mapping[str, NodeHandler],
|
||||
*,
|
||||
resume_payload: dict[str, Any] | None = None,
|
||||
resume_outcome: str = "submitted",
|
||||
) -> RunState:
|
||||
index = _prepare_resume(
|
||||
workflow,
|
||||
run,
|
||||
resume_payload=resume_payload,
|
||||
resume_outcome=resume_outcome,
|
||||
)
|
||||
if index is None:
|
||||
if run.current_node_id == END:
|
||||
return finalize_run(workflow, run)
|
||||
return run
|
||||
|
||||
while True:
|
||||
collapse_completed_frames(run)
|
||||
if run.current_node_id == END:
|
||||
break
|
||||
step_workflow(
|
||||
workflow,
|
||||
run,
|
||||
registry,
|
||||
index=index,
|
||||
)
|
||||
if run.status == RunStatus.INTERRUPTED:
|
||||
return run
|
||||
|
||||
return finalize_run(workflow, run)
|
||||
|
||||
|
||||
async def resume_workflow_async(
|
||||
workflow: Workflow,
|
||||
run: RunState,
|
||||
registry: Mapping[str, AsyncNodeHandler],
|
||||
*,
|
||||
resume_payload: dict[str, Any] | None = None,
|
||||
resume_outcome: str = "submitted",
|
||||
) -> RunState:
|
||||
index = _prepare_resume(
|
||||
workflow,
|
||||
run,
|
||||
resume_payload=resume_payload,
|
||||
resume_outcome=resume_outcome,
|
||||
)
|
||||
if index is None:
|
||||
if run.current_node_id == END:
|
||||
return finalize_run(workflow, run)
|
||||
return run
|
||||
|
||||
while True:
|
||||
collapse_completed_frames(run)
|
||||
if run.current_node_id == END:
|
||||
break
|
||||
await step_workflow_async(
|
||||
workflow,
|
||||
run,
|
||||
registry,
|
||||
index=index,
|
||||
)
|
||||
if run.status == RunStatus.INTERRUPTED:
|
||||
return run
|
||||
|
||||
return finalize_run(workflow, run)
|
||||
|
||||
|
||||
def step_workflow(
|
||||
workflow: Workflow,
|
||||
run: RunState,
|
||||
registry: Mapping[str, NodeHandler],
|
||||
*,
|
||||
index: WorkflowIndex | None = None,
|
||||
) -> RunState:
|
||||
prepared = _prepare_step(workflow, run, index)
|
||||
if prepared is None:
|
||||
return run
|
||||
index, step = prepared
|
||||
frame = run.current_frame()
|
||||
|
||||
if isinstance(step, NodeUse):
|
||||
node_def = index.node_defs[step.node]
|
||||
step_result = execute_node_use(workflow, run, step, node_def, registry)
|
||||
elif isinstance(step, ConditionNode):
|
||||
step_result = handle_condition_step(run, step)
|
||||
elif isinstance(step, JoinNode):
|
||||
step_result = handle_join_step()
|
||||
elif isinstance(step, InterruptNode):
|
||||
return handle_interrupt_step(run, step)
|
||||
elif isinstance(step, ForeachNode):
|
||||
return step_foreach(workflow, run, step, index)
|
||||
else:
|
||||
raise WorkflowExecutionError(
|
||||
f"unsupported step type {getattr(step, 'type', type(step).__name__)!r}"
|
||||
)
|
||||
|
||||
return _complete_step(
|
||||
run=run,
|
||||
index=index,
|
||||
outcome=step_result.outcome,
|
||||
frame_id=frame.id,
|
||||
node_id=frame.node_id,
|
||||
step_type=step.type,
|
||||
step_result=step_result,
|
||||
)
|
||||
|
||||
|
||||
async def step_workflow_async(
|
||||
workflow: Workflow,
|
||||
run: RunState,
|
||||
registry: Mapping[str, AsyncNodeHandler],
|
||||
*,
|
||||
index: WorkflowIndex | None = None,
|
||||
) -> RunState:
|
||||
prepared = _prepare_step(workflow, run, index)
|
||||
if prepared is None:
|
||||
return run
|
||||
index, step = prepared
|
||||
frame = run.current_frame()
|
||||
|
||||
if isinstance(step, NodeUse):
|
||||
node_def = index.node_defs[step.node]
|
||||
step_result = await execute_node_use_async(
|
||||
workflow, run, step, node_def, registry
|
||||
)
|
||||
elif isinstance(step, ConditionNode):
|
||||
step_result = handle_condition_step(run, step)
|
||||
elif isinstance(step, JoinNode):
|
||||
step_result = handle_join_step()
|
||||
elif isinstance(step, InterruptNode):
|
||||
return handle_interrupt_step(run, step)
|
||||
elif isinstance(step, ForeachNode):
|
||||
return step_foreach(workflow, run, step, index)
|
||||
else:
|
||||
raise WorkflowExecutionError(
|
||||
f"unsupported step type {getattr(step, 'type', type(step).__name__)!r}"
|
||||
)
|
||||
|
||||
return _complete_step(
|
||||
run=run,
|
||||
index=index,
|
||||
outcome=step_result.outcome,
|
||||
frame_id=frame.id,
|
||||
node_id=frame.node_id,
|
||||
step_type=step.type,
|
||||
step_result=step_result,
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
from wf_core.errors import WorkflowExecutionError
|
||||
from wf_core.node_exec import (
|
||||
AsyncNodeHandler,
|
||||
NodeHandler,
|
||||
coerce_node_result,
|
||||
execute_node_use,
|
||||
execute_node_use_async,
|
||||
)
|
||||
|
||||
from .engine import (
|
||||
execute_workflow,
|
||||
execute_workflow_async,
|
||||
resume_workflow,
|
||||
resume_workflow_async,
|
||||
)
|
||||
from .step import complete_step, step_workflow, step_workflow_async
|
||||
|
||||
__all__ = [
|
||||
"AsyncNodeHandler",
|
||||
"NodeHandler",
|
||||
"WorkflowExecutionError",
|
||||
"coerce_node_result",
|
||||
"complete_step",
|
||||
"execute_node_use",
|
||||
"execute_node_use_async",
|
||||
"execute_workflow",
|
||||
"execute_workflow_async",
|
||||
"resume_workflow",
|
||||
"resume_workflow_async",
|
||||
"step_workflow",
|
||||
"step_workflow_async",
|
||||
]
|
||||
@@ -0,0 +1,121 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping
|
||||
from typing import Any
|
||||
|
||||
from wf_core.flow_ops import finalize_run
|
||||
from wf_core.frame_ops import collapse_completed_frames
|
||||
from wf_core.model import Workflow
|
||||
from wf_core.node_exec import AsyncNodeHandler, NodeHandler
|
||||
from wf_core.run_factory import create_run_state
|
||||
from wf_core.run_state import RunState, RunStatus
|
||||
from wf_core.tokens import END
|
||||
|
||||
from .preparation import prepare_new_run, prepare_resume
|
||||
from .step import step_workflow, step_workflow_async
|
||||
|
||||
|
||||
def execute_workflow(
|
||||
workflow: Workflow,
|
||||
workflow_input: dict[str, Any],
|
||||
registry: Mapping[str, NodeHandler],
|
||||
) -> RunState:
|
||||
"""Create a run and execute a workflow synchronously until it stops."""
|
||||
run = create_run_state(workflow, workflow_input)
|
||||
|
||||
try:
|
||||
run = prepare_new_run(workflow, workflow_input)
|
||||
return resume_workflow(workflow, run, registry)
|
||||
except Exception as exc:
|
||||
run.status = RunStatus.FAILED
|
||||
run.error = str(exc)
|
||||
raise
|
||||
|
||||
|
||||
async def execute_workflow_async(
|
||||
workflow: Workflow,
|
||||
workflow_input: dict[str, Any],
|
||||
registry: Mapping[str, AsyncNodeHandler],
|
||||
) -> RunState:
|
||||
"""Create a run and execute a workflow asynchronously until it stops."""
|
||||
run = create_run_state(workflow, workflow_input)
|
||||
|
||||
try:
|
||||
run = prepare_new_run(workflow, workflow_input)
|
||||
return await resume_workflow_async(workflow, run, registry)
|
||||
except Exception as exc:
|
||||
run.status = RunStatus.FAILED
|
||||
run.error = str(exc)
|
||||
raise
|
||||
|
||||
|
||||
def resume_workflow(
|
||||
workflow: Workflow,
|
||||
run: RunState,
|
||||
registry: Mapping[str, NodeHandler],
|
||||
*,
|
||||
resume_payload: dict[str, Any] | None = None,
|
||||
resume_outcome: str = "submitted",
|
||||
) -> RunState:
|
||||
"""Resume a synchronous run from its current state."""
|
||||
index = prepare_resume(
|
||||
workflow,
|
||||
run,
|
||||
resume_payload=resume_payload,
|
||||
resume_outcome=resume_outcome,
|
||||
)
|
||||
if index is None:
|
||||
if run.current_node_id == END:
|
||||
return finalize_run(workflow, run)
|
||||
return run
|
||||
|
||||
while True:
|
||||
collapse_completed_frames(run)
|
||||
if run.current_node_id == END:
|
||||
break
|
||||
step_workflow(
|
||||
workflow,
|
||||
run,
|
||||
registry,
|
||||
index=index,
|
||||
)
|
||||
if run.status == RunStatus.INTERRUPTED:
|
||||
return run
|
||||
|
||||
return finalize_run(workflow, run)
|
||||
|
||||
|
||||
async def resume_workflow_async(
|
||||
workflow: Workflow,
|
||||
run: RunState,
|
||||
registry: Mapping[str, AsyncNodeHandler],
|
||||
*,
|
||||
resume_payload: dict[str, Any] | None = None,
|
||||
resume_outcome: str = "submitted",
|
||||
) -> RunState:
|
||||
"""Resume an async run from its current state."""
|
||||
index = prepare_resume(
|
||||
workflow,
|
||||
run,
|
||||
resume_payload=resume_payload,
|
||||
resume_outcome=resume_outcome,
|
||||
)
|
||||
if index is None:
|
||||
if run.current_node_id == END:
|
||||
return finalize_run(workflow, run)
|
||||
return run
|
||||
|
||||
while True:
|
||||
collapse_completed_frames(run)
|
||||
if run.current_node_id == END:
|
||||
break
|
||||
await step_workflow_async(
|
||||
workflow,
|
||||
run,
|
||||
registry,
|
||||
index=index,
|
||||
)
|
||||
if run.status == RunStatus.INTERRUPTED:
|
||||
return run
|
||||
|
||||
return finalize_run(workflow, run)
|
||||
@@ -0,0 +1,95 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from wf_core.errors import WorkflowExecutionError
|
||||
from wf_core.frame_ops import collapse_completed_frames
|
||||
from wf_core.interrupt_ops import resume_interrupt
|
||||
from wf_core.model import Workflow
|
||||
from wf_core.run_factory import create_run_state
|
||||
from wf_core.run_state import FrameStatus, RunState, RunStatus
|
||||
from wf_core.schema_tools import validate_payload_against_schema
|
||||
from wf_core.tokens import END
|
||||
from wf_core.workflow_index import WorkflowIndex, build_workflow_index
|
||||
|
||||
|
||||
def prepare_new_run(workflow: Workflow, workflow_input: dict[str, Any]) -> RunState:
|
||||
"""Create and validate a fresh run state for a workflow invocation."""
|
||||
run = create_run_state(workflow, workflow_input)
|
||||
workflow.validate_structure().raise_for_errors()
|
||||
validate_payload_against_schema(
|
||||
workflow.input_schema, workflow_input, "workflow input"
|
||||
)
|
||||
return run
|
||||
|
||||
|
||||
def prepare_resume(
|
||||
workflow: Workflow,
|
||||
run: RunState,
|
||||
*,
|
||||
resume_payload: dict[str, Any] | None,
|
||||
resume_outcome: str,
|
||||
) -> WorkflowIndex | None:
|
||||
"""Validate and normalize a run state before resume execution."""
|
||||
if run.workflow_name != workflow.name:
|
||||
raise WorkflowExecutionError(
|
||||
f"run state belongs to workflow {run.workflow_name!r}, not {workflow.name!r}"
|
||||
)
|
||||
|
||||
if run.current_frame_id is None:
|
||||
raise WorkflowExecutionError("run has no current frame")
|
||||
collapse_completed_frames(run)
|
||||
|
||||
if run.current_node_id is None:
|
||||
raise WorkflowExecutionError("run has no current node")
|
||||
|
||||
if run.status == RunStatus.COMPLETED:
|
||||
return None
|
||||
|
||||
index = build_workflow_index(workflow)
|
||||
|
||||
if run.status == RunStatus.INTERRUPTED:
|
||||
if resume_payload is None:
|
||||
return None
|
||||
resume_interrupt(
|
||||
workflow,
|
||||
run,
|
||||
index=index,
|
||||
resume_payload=resume_payload,
|
||||
resume_outcome=resume_outcome,
|
||||
)
|
||||
collapse_completed_frames(run)
|
||||
if run.current_node_id == END:
|
||||
return None
|
||||
|
||||
run.status = RunStatus.RUNNING
|
||||
run.error = None
|
||||
run.current_frame().status = FrameStatus.RUNNING
|
||||
return index
|
||||
|
||||
|
||||
def prepare_step(
|
||||
workflow: Workflow,
|
||||
run: RunState,
|
||||
index: WorkflowIndex | None,
|
||||
) -> tuple[WorkflowIndex, object] | None:
|
||||
"""Resolve the next executable workflow step for the current run frame."""
|
||||
if run.current_frame_id is None:
|
||||
raise WorkflowExecutionError("run has no current frame")
|
||||
|
||||
collapse_completed_frames(run)
|
||||
if run.current_node_id is None or run.current_node_id == END:
|
||||
return None
|
||||
if run.status == RunStatus.INTERRUPTED:
|
||||
return None
|
||||
|
||||
if run.status == RunStatus.PENDING:
|
||||
run.status = RunStatus.RUNNING
|
||||
run.error = None
|
||||
|
||||
resolved_index = index or build_workflow_index(workflow)
|
||||
frame = run.current_frame()
|
||||
if frame.status == FrameStatus.PENDING:
|
||||
frame.status = FrameStatus.RUNNING
|
||||
step = resolved_index.nodes_by_id[frame.node_id]
|
||||
return resolved_index, step
|
||||
@@ -0,0 +1,145 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping
|
||||
from typing import Any
|
||||
|
||||
from wf_core.errors import WorkflowExecutionError
|
||||
from wf_core.flow_ops import advance_frame, append_step_result_trace
|
||||
from wf_core.foreach_ops import step_foreach
|
||||
from wf_core.model import (
|
||||
ConditionNode,
|
||||
ForeachNode,
|
||||
InterruptNode,
|
||||
JoinNode,
|
||||
NodeUse,
|
||||
Workflow,
|
||||
)
|
||||
from wf_core.node_exec import (
|
||||
AsyncNodeHandler,
|
||||
NodeHandler,
|
||||
execute_node_use,
|
||||
execute_node_use_async,
|
||||
)
|
||||
from wf_core.run_state import RunState
|
||||
from wf_core.step_handlers import (
|
||||
handle_condition_step,
|
||||
handle_interrupt_step,
|
||||
handle_join_step,
|
||||
)
|
||||
from wf_core.workflow_index import WorkflowIndex
|
||||
|
||||
from .preparation import prepare_step
|
||||
|
||||
|
||||
def complete_step(
|
||||
*,
|
||||
run: RunState,
|
||||
index: WorkflowIndex,
|
||||
outcome: str,
|
||||
frame_id: str,
|
||||
node_id: str,
|
||||
step_type: str,
|
||||
step_result: Any,
|
||||
) -> RunState:
|
||||
"""Record a completed step and advance the active frame."""
|
||||
next_node_id = index.next_node_id(node_id, outcome)
|
||||
|
||||
append_step_result_trace(
|
||||
run,
|
||||
frame_id=frame_id,
|
||||
node_id=node_id,
|
||||
step_type=step_type,
|
||||
next_node_id=next_node_id,
|
||||
result=step_result,
|
||||
)
|
||||
advance_frame(
|
||||
run,
|
||||
run.frames[frame_id],
|
||||
outcome=outcome,
|
||||
next_node_id=next_node_id,
|
||||
)
|
||||
return run
|
||||
|
||||
|
||||
def step_workflow(
|
||||
workflow: Workflow,
|
||||
run: RunState,
|
||||
registry: Mapping[str, NodeHandler],
|
||||
*,
|
||||
index: WorkflowIndex | None = None,
|
||||
) -> RunState:
|
||||
"""Execute at most one synchronous workflow step."""
|
||||
prepared = prepare_step(workflow, run, index)
|
||||
if prepared is None:
|
||||
return run
|
||||
index, step = prepared
|
||||
frame = run.current_frame()
|
||||
|
||||
if isinstance(step, NodeUse):
|
||||
node_def = index.node_defs[step.node]
|
||||
step_result = execute_node_use(workflow, run, step, node_def, registry)
|
||||
elif isinstance(step, ConditionNode):
|
||||
step_result = handle_condition_step(run, step)
|
||||
elif isinstance(step, JoinNode):
|
||||
step_result = handle_join_step()
|
||||
elif isinstance(step, InterruptNode):
|
||||
return handle_interrupt_step(run, step)
|
||||
elif isinstance(step, ForeachNode):
|
||||
return step_foreach(workflow, run, step, index)
|
||||
else:
|
||||
raise WorkflowExecutionError(
|
||||
f"unsupported step type {getattr(step, 'type', type(step).__name__)!r}"
|
||||
)
|
||||
|
||||
return complete_step(
|
||||
run=run,
|
||||
index=index,
|
||||
outcome=step_result.outcome,
|
||||
frame_id=frame.id,
|
||||
node_id=frame.node_id,
|
||||
step_type=step.type,
|
||||
step_result=step_result,
|
||||
)
|
||||
|
||||
|
||||
async def step_workflow_async(
|
||||
workflow: Workflow,
|
||||
run: RunState,
|
||||
registry: Mapping[str, AsyncNodeHandler],
|
||||
*,
|
||||
index: WorkflowIndex | None = None,
|
||||
) -> RunState:
|
||||
"""Execute at most one async workflow step."""
|
||||
prepared = prepare_step(workflow, run, index)
|
||||
if prepared is None:
|
||||
return run
|
||||
index, step = prepared
|
||||
frame = run.current_frame()
|
||||
|
||||
if isinstance(step, NodeUse):
|
||||
node_def = index.node_defs[step.node]
|
||||
step_result = await execute_node_use_async(
|
||||
workflow, run, step, node_def, registry
|
||||
)
|
||||
elif isinstance(step, ConditionNode):
|
||||
step_result = handle_condition_step(run, step)
|
||||
elif isinstance(step, JoinNode):
|
||||
step_result = handle_join_step()
|
||||
elif isinstance(step, InterruptNode):
|
||||
return handle_interrupt_step(run, step)
|
||||
elif isinstance(step, ForeachNode):
|
||||
return step_foreach(workflow, run, step, index)
|
||||
else:
|
||||
raise WorkflowExecutionError(
|
||||
f"unsupported step type {getattr(step, 'type', type(step).__name__)!r}"
|
||||
)
|
||||
|
||||
return complete_step(
|
||||
run=run,
|
||||
index=index,
|
||||
outcome=step_result.outcome,
|
||||
frame_id=frame.id,
|
||||
node_id=frame.node_id,
|
||||
step_type=step.type,
|
||||
step_result=step_result,
|
||||
)
|
||||
Reference in New Issue
Block a user