update flow doc
This commit is contained in:
parent
60e6a1ec98
commit
3f91b0adbd
52
docs/flow.md
52
docs/flow.md
|
|
@ -7,30 +7,30 @@ nav_order: 2
|
|||
|
||||
# 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
|
||||
|
||||
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`.
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
Here’s 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 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
|
||||
|
||||
|
|
@ -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 can’t 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.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue