update flow doc
This commit is contained in:
parent
60e6a1ec98
commit
3f91b0adbd
48
docs/flow.md
48
docs/flow.md
|
|
@ -7,30 +7,30 @@ nav_order: 2
|
||||||
|
|
||||||
# Flow
|
# Flow
|
||||||
|
|
||||||
A **Flow** orchestrates how Nodes connect and run, based on **Actions** returned from each Node’s `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
|
## 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:
|
You define transitions with the syntax:
|
||||||
|
|
||||||
1. Basic default transition: `node_a >> node_b`
|
1. **Basic default transition**: `node_a >> node_b`
|
||||||
This means if `node_a.post()` returns `"default"` (or `None`), go to `node_b`.
|
This means if `node_a.post()` returns `"default"`, go to `node_b`.
|
||||||
(Equivalent to `node_a - "default" >> 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`.
|
This means if `node_a.post()` returns `"action_name"`, go to `node_b`.
|
||||||
|
|
||||||
It’s possible to create loops, branching, or multi-step flows.
|
It's possible to create loops, branching, or multi-step flows.
|
||||||
|
|
||||||
## 2. Creating a Flow
|
## 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 there’s 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
|
### Example: Simple Sequence
|
||||||
|
|
||||||
Here’s a minimal flow of two nodes in a chain:
|
Here's a minimal flow of two nodes in a chain:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
node_a >> node_b
|
node_a >> node_b
|
||||||
|
|
@ -41,7 +41,7 @@ flow.run(shared)
|
||||||
- When you run the flow, it executes `node_a`.
|
- When you run the flow, it executes `node_a`.
|
||||||
- Suppose `node_a.post()` returns `"default"`.
|
- Suppose `node_a.post()` returns `"default"`.
|
||||||
- The flow then sees `"default"` Action is linked to `node_b` and runs `node_b`.
|
- The flow then sees `"default"` Action is linked to `node_b` and runs `node_b`.
|
||||||
- If `node_b.post()` returns `"default"` but we didn’t 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
|
### Example: Branching & Looping
|
||||||
|
|
||||||
|
|
@ -67,9 +67,9 @@ flow = Flow(start=review)
|
||||||
|
|
||||||
Let's see how it flows:
|
Let's see how it flows:
|
||||||
|
|
||||||
1. If `review.post()` returns `"approved"`, the expense moves to `payment` node
|
1. If `review.post()` returns `"approved"`, the expense moves to the `payment` node
|
||||||
2. If `review.post()` returns `"needs_revision"`, it goes to `revise` node, which then loops back to `review`
|
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 `finish` node and stops
|
3. If `review.post()` returns `"rejected"`, it moves to the `finish` node and stops
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart TD
|
flowchart TD
|
||||||
|
|
@ -83,12 +83,13 @@ flowchart TD
|
||||||
|
|
||||||
### Running Individual Nodes vs. Running a Flow
|
### Running Individual Nodes vs. Running a Flow
|
||||||
|
|
||||||
- `node.run(shared)`: Just runs that node alone (calls `prep()`, `exec()`, `post()`), returns an 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 (no next node or no next 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.
|
> This is mainly for debugging or testing a single node.
|
||||||
|
>
|
||||||
> Always use `flow.run(...)` in production to ensure the full pipeline runs correctly.
|
> Always use `flow.run(...)` in production to ensure the full pipeline runs correctly.
|
||||||
{: .warning }
|
{: .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.
|
2. Combine multiple smaller Flows into a larger Flow for reuse.
|
||||||
3. Node `params` will be a merging of **all** parents' `params`.
|
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
|
### Basic Flow Nesting
|
||||||
|
|
||||||
Here's how to connect a flow to another node:
|
Here's how to connect a flow to another node:
|
||||||
|
|
@ -125,7 +119,7 @@ parent_flow = Flow(start=subflow)
|
||||||
|
|
||||||
When `parent_flow.run()` executes:
|
When `parent_flow.run()` executes:
|
||||||
1. It starts `subflow`
|
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`
|
3. After `subflow` completes, execution continues to `node_c`
|
||||||
|
|
||||||
### Example: Order Processing Pipeline
|
### Example: Order Processing Pipeline
|
||||||
|
|
@ -176,3 +170,11 @@ flowchart LR
|
||||||
inventoryFlow --> shippingFlow
|
inventoryFlow --> shippingFlow
|
||||||
end
|
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.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue