Flows

Flow Execution

How the flow engine executes flows — managing active runs, step dispatch, branching, error handling, and integration with the task system.

The flow engine is a singleton service that manages all active flow runs across the platform. It handles step dispatch, branching, error handling, conversation integration, and state tracking.

Execution lifecycle

When a flow is triggered, it goes through the following lifecycle:

1. Task creation

Every flow run is tracked as a task. The task records:

  • Flow ID and version
  • Input parameters
  • Execution state (running, completed, failed)
  • Step-by-step results
  • Timing information

2. Step resolution

The engine walks through the flow's step graph starting from the start step. For each step:

  1. Resolve the action — determine what to call based on the step's action identifier
  2. Prepare input — evaluate the step's input configuration, resolving references to previous step outputs
  3. Execute — call the action through CallAction
  4. Evaluate output — check the result against the step's output options to determine which edge to follow
  5. Continue — move to the next step(s) via the selected edge

3. Group execution

Steps within groups execute according to the group's kind:

  • Sequential — one step at a time, in order
  • Parallel — multiple steps concurrently, with configured concurrency limits
  • Loop — repeated execution with iteration tracking

4. Completion

When the end step is reached or all paths complete, the flow run finishes. The task is marked as completed (or failed if an unhandled error occurred) and a completion event is published.

Error handling

Each step can be configured with error handling behavior:

ConfigurationBehavior
continueOnError: false (default)The flow stops immediately on step failure
continueOnError: trueExecution continues to the error edge or next step
retryCount > 0The step is retried the specified number of times before failing
timeoutIf the step exceeds the timeout, it is terminated and treated as a failure

When a step fails and continueOnError is enabled, the engine follows the error edge if one is defined. This allows you to build error handling logic directly in the flow — logging errors, sending notifications, or executing fallback steps.

Conversation integration

Flows have deep integration with the conversation system. This is how agents work:

Auto-triggering

The flow engine subscribes to conversation events:

  • conversation.created — when a new conversation is created with an agent participant that has autoRespond enabled, the agent's default flow is started automatically
  • conversation.message_posted — when a message is posted in a conversation with an auto-responding agent, the flow engine notifies any running flow that is waiting for input

Conversation steps

When a flow contains a conversation or assistant step:

  1. The engine subscribes to message events for the relevant conversation
  2. Incoming messages are forwarded to the running assistant step
  3. The assistant generates a response (streamed to the conversation)
  4. The flow continues after the response is complete

This enables interactive flows where the agent can have multi-turn conversations, ask follow-up questions, and process user responses before continuing with the next step.

Deduplication

The engine prevents duplicate flow runs — if an agent already has an active flow run for a conversation, new messages are routed to the existing run rather than starting a new one.

Async and long-running flows

Flows can include steps that take a long time to complete:

  • Event steps wait for external events (webhooks, polling) with timeouts up to 24 hours
  • Conversation steps wait for user responses indefinitely
  • Long-running action steps execute in the background

For async flows, the task ID is returned immediately. Callers can:

  • Poll the task status
  • Subscribe to the task completion event
  • Check the task's step-by-step results

Nested flows

Actions can call other actions, which can trigger other flows. The task system tracks parent-child relationships between tasks, creating a tree of execution that can be traced for debugging and auditing.