Skip to main content

Control Flow

This document describes the implementation of control flow features in Step Flow, including conditional execution, error handling, and nested workflow evaluation.

Overview

Step Flow supports advanced control flow patterns through:

  • Conditional Execution: Steps can be skipped based on runtime conditions
  • Error Handling: Steps can handle failures gracefully with fallback values
  • Nested Workflows: Sub-workflows can be executed within steps

Step States

Steps in Step Flow have the following states:

Execution States (tracked by execution engine)

  • Pending: Not yet executed, waiting for inputs or resources
  • Running: Currently executing

Terminal States (returned in FlowResult)

  • Success: Completed successfully and produced output
  • Skipped: Skipped due to conditions or dependencies, with optional reason
  • Failed: Completed with a business logic error (FlowError)

Note: Internal errors (infrastructure failures, plugin communication issues) are handled by the workflow runtime and are not represented as step failures.

Conditional Execution

Steps can be conditionally skipped using the skip field:

steps:
- id: expensive_analysis
component: /ai/analyze
skip: { $from: { workflow: input }, path: is_premium_user }
input:
data: { $from: { step: previous_step } }

Skip Conditions

  • Reference: Must be a workflow input or output from an earlier step
  • Evaluation: Evaluated at runtime when step dependencies are ready
  • Logic: If the referenced value is truthy, the step is skipped
  • Default: skip: false (step executes normally)

Skip Propagation

By default, if any inputs to a step are unavailable because the producing step was skipped, the consuming step is also skipped. This propagation can be interrupted by configuring how an input should be computed when the producer was skipped:

steps:
- id: consumer_step
component: /data/process
input:
required_data: { $from: { step: step1 } }
optional_enhancement:
$from: { step: step2 }
$on_skip: "use_default"
$default: "no_enhancement"

The $on_skip field configures what to do when the referenced step was skipped. It defaults to skip_step which causes the entire consuming step to be skipped. It can be set to use_default which causes a default value to be used instead.

The $default field is required if $on_skip is set to use_default and the type of the argument does not have a natural default value.

Error Handling

Steps can handle their own failures using the on_error field:

steps:
- id: risky_operation
component: /external/api_call
on_error:
action: continue
default_output:
result: "fallback_value"
status: "error_handled"
input:
endpoint: "https://api.example.com"

Error Actions

  • terminate: Terminate the workflow (default behavior)
  • continue: Use default_output as the step result (Success state)
  • skip: Mark the step as Skipped

Default Output Requirements

  • Must conform to the component's output schema
  • Required fields must be present
  • Optional fields may be omitted
  • Type compatibility is enforced during validation

Nested Workflows (Eval)

Sub-workflows can be executed using the built-in eval component:

steps:
- id: sub_process
component: /builtin/eval
input:
workflow:
$literal:
inputs:
data: { type: string }
steps:
- id: process
component: /data/transform
input:
input: { $from: { workflow: input }, path: data }
output:
result: { $from: { step: process } }
input:
data: { $from: { step: previous_step }, path: processed_data }

Sub-workflow Execution

  • Isolation: Each sub-workflow gets a unique execution ID
  • Context: Completely isolated from parent workflow state
  • Resources: Count against parent workflow resource limits
  • Errors: Sub-workflow failures propagate as eval step failures

Use Cases

  • Factoring complex workflows into reusable components
  • Dynamic workflow execution based on runtime data
  • Implementing complex looping and branching logic

Resource Management

  • Sub-workflows inherit resource limits from parent
  • Failed sub-workflows don't consume additional resources
  • Skipped steps don't consume execution resources

Future Enhancements

  • Retry Logic: on_error: {action: retry, max_attempts: 3}
  • Time Limits: Step- or edge-level timeouts with skip behavior
  • Loop Primitives: Tail-eval for iterative workflows
  • Fuel/Resource System: Execution step limits for loop termination