update flow doc

This commit is contained in:
zachary62 2025-02-16 13:40:05 -05:00
parent 60e6a1ec98
commit 3f91b0adbd
1 changed files with 27 additions and 25 deletions

View File

@ -7,30 +7,30 @@ nav_order: 2
# Flow
A **Flow** orchestrates how Nodes connect and run, based on **Actions** returned from each Nodes `post()` method. You can chain Nodes in a sequence or create branching logic depending on the **Action** string.
A **Flow** orchestrates a graph of Nodes. You can chain Nodes in a sequence or create branching depending on the **Actions** returned from each Node's `post()`.
## 1. Action-based Transitions
Each Node's `post(shared, prep_res, exec_res)` method returns an **Action** string. By default, if `post()` doesn't explicitly return anything, we treat that as `"default"`.
Each Node's `post()` returns an **Action** string. By default, if `post()` doesn't return anything, we treat that as `"default"`.
You define transitions with the syntax:
1. Basic default transition: `node_a >> node_b`
This means if `node_a.post()` returns `"default"` (or `None`), go to `node_b`.
1. **Basic default transition**: `node_a >> node_b`
This means if `node_a.post()` returns `"default"`, go to `node_b`.
(Equivalent to `node_a - "default" >> node_b`)
2. Named action transition: `node_a - "action_name" >> node_b`
2. **Named action transition**: `node_a - "action_name" >> node_b`
This means if `node_a.post()` returns `"action_name"`, go to `node_b`.
Its possible to create loops, branching, or multi-step flows.
It's possible to create loops, branching, or multi-step flows.
## 2. Creating a Flow
A **Flow** begins with a **start** node (or flow). You call `Flow(start=some_node)` to specify the entry point. When you call `flow.run(shared)`, it executes the first node, looks at its `post()` return Action, follows the corresponding transition, and continues until theres no next node or you explicitly stop.
A **Flow** begins with a **start** node. You call `Flow(start=some_node)` to specify the entry point. When you call `flow.run(shared)`, it executes the start node, looks at its returned Action from `post()`, follows the transition, and continues until there's no next node.
### Example: Simple Sequence
Heres a minimal flow of two nodes in a chain:
Here's a minimal flow of two nodes in a chain:
```python
node_a >> node_b
@ -41,7 +41,7 @@ flow.run(shared)
- When you run the flow, it executes `node_a`.
- Suppose `node_a.post()` returns `"default"`.
- The flow then sees `"default"` Action is linked to `node_b` and runs `node_b`.
- If `node_b.post()` returns `"default"` but we didnt define `node_b >> something_else`, the flow ends there.
- `node_b.post()` returns `"default"` but we didn't define `node_b >> something_else`. So the flow ends there.
### Example: Branching & Looping
@ -57,19 +57,19 @@ We can wire them like this:
# Define the flow connections
review - "approved" >> payment # If approved, process payment
review - "needs_revision" >> revise # If needs changes, go to revision
review - "rejected" >> finish # If rejected, finish the process
review - "rejected" >> finish # If rejected, finish the process
revise >> review # After revision, go back for another review
payment >> finish # After payment, finish the process
payment >> finish # After payment, finish the process
flow = Flow(start=review)
```
Let's see how it flows:
1. If `review.post()` returns `"approved"`, the expense moves to `payment` node
2. If `review.post()` returns `"needs_revision"`, it goes to `revise` node, which then loops back to `review`
3. If `review.post()` returns `"rejected"`, it moves to `finish` node and stops
1. If `review.post()` returns `"approved"`, the expense moves to the `payment` node
2. If `review.post()` returns `"needs_revision"`, it goes to the `revise` node, which then loops back to `review`
3. If `review.post()` returns `"rejected"`, it moves to the `finish` node and stops
```mermaid
flowchart TD
@ -83,12 +83,13 @@ flowchart TD
### Running Individual Nodes vs. Running a Flow
- `node.run(shared)`: Just runs that node alone (calls `prep()`, `exec()`, `post()`), returns an Action.
- `flow.run(shared)`: Executes from the start node, follows Actions to the next node, and so on until the flow cant continue (no next node or no next Action).
- `node.run(shared)`: Just runs that node alone (calls `prep->exec->post()`), returns an Action.
- `flow.run(shared)`: Executes from the start node, follows Actions to the next node, and so on until the flow can't continue.
> node.run(shared) **does not** proceed automatically to the successor and may use incorrect parameters.
> `node.run(shared)` **does not** proceed to the successor.
> This is mainly for debugging or testing a single node.
>
> Always use `flow.run(...)` in production to ensure the full pipeline runs correctly.
{: .warning }
@ -100,13 +101,6 @@ A **Flow** can act like a Node, which enables powerful composition patterns. Thi
2. Combine multiple smaller Flows into a larger Flow for reuse.
3. Node `params` will be a merging of **all** parents' `params`.
> While **Flow** is also a **Node**, it won't run `exec()`.
>
> It will run `prep()` and `post()`, before and after calling the nodes within the flow.
>
> However, `post()` always receives None for exec_res, and should instead get the flow execution results from the shared store.
{: .warning }
### Basic Flow Nesting
Here's how to connect a flow to another node:
@ -125,7 +119,7 @@ parent_flow = Flow(start=subflow)
When `parent_flow.run()` executes:
1. It starts `subflow`
2. `subflow` runs through its nodes (`node_a` then `node_b`)
2. `subflow` runs through its nodes (`node_a->node_b`)
3. After `subflow` completes, execution continues to `node_c`
### Example: Order Processing Pipeline
@ -176,3 +170,11 @@ flowchart LR
inventoryFlow --> shippingFlow
end
```
### Flow's Node Methods
A **Flow** is also a **Node**, so it will run `prep()` and `post()`. However:
- It **won't** run `exec()`, as its main logic is to orchestrate other nodes.
- `post()` always receives None for exec_res and should instead get the flow execution results from the shared store.