You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Create and execute a graph defined by a list of edges
23
23
24
24
25
-
## Generic Typing Parameters
25
+
## Generic Typing
26
+
The graph supports different state management strategies through generic parameters:
26
27
27
-
Use protocols or classes that extend **StateProtocol** and **SharedProtocol** or **State** and **Shared** to define the supported state types.
28
+
* **Simple Inheritance (Covariance):** Extend `State` and `Shared` classes.
29
+
Ideal for smaller projects with minimal boilerplate.
30
+
* **Protocol-based (Duck Typing):** Implement `StateProtocol` and `SharedProtocol`.
31
+
Recommended for scalable projects where multiple state types are merged.
32
+
* **Disabled Type Checking:** Use `typing.Any` to bypass strict typing.
28
33
29
-
### Inheritance with Variance
34
+
---
30
35
31
-
With covariance its possible to use nodes that use more specific State and Shared classes as the generic typing parameters. Requires an inheritance structure.
36
+
## Branching & Edge Logic
37
+
A graph consists of one or more **branches**. A branch is defined as a tuple:
This is recommended for smaller projects because it needs less boilerplate.
34
-
35
-
### Duck Typing
36
-
37
-
For the more flexible approach with better scaling use protocols to define the supported state types. Remember to always extend `typing.Protocol` in the child classes for typing.
38
-
39
-
This is recommended for scalable projects where many different state types need to be joined in one graph. See [edgynodes](https://github.com/mathisxy/edgynodes/) for an example.
40
-
41
-
### Disable Type Checking
42
-
43
-
If you want to disable type checking for the graph, you can use `typing.Any` as generic typing parameters in the graph.
44
-
45
-
46
-
## Branches
47
-
48
-
A graph is defined by a number of branches, with at least one branch having `START` as their first source element.
49
-
50
-
A branch consists of a tuple of `Source` or/and `Next` elements. The first element of the tuple is the source of the branch, the last element is the join element of the branch.
51
-
52
-
### Edges
53
-
54
-
The edges of a branch are defined by a tuple of elements, which resolve to edges.
55
-
56
-
An edge consists of a `Source` and a `Next` element.
57
-
58
-
The edges are calculated as follows:
40
+
### Edge Generation
41
+
Edges are automatically generated between adjacent elements in the tuple, **excluding the final JoinParameter**:
59
42
60
43
```
61
44
T = (E_0, …, E_{n−1})
62
45
63
46
∀ x ∈ {0, …, n−3}: # n−3 because the last element is the join element
64
47
65
-
{(a, b) ∈ E_x × E_{x+1} | a is a Source ∧ b is a Next}
48
+
Edges = {(a, b) ∈ E_x × E_{x+1} | a is a Source ∧ b is a Next}
66
49
67
50
where × denotes the Cartesian product.
68
51
69
52
```
70
53
71
-
Therefore the tuple must include at least a `Source`, a `Next`, and the join parameter, which is `element_{n-1}` and excluded from the edge calculation.
54
+
**Example:**
55
+
`edges = [(START, node1, node2, node3)]`
56
+
1. (START -> node1)
57
+
2. (node1 -> node2)
72
58
73
-
This example would resolve to the following edges:
59
+
*Note: `node3` is the join point, not a target of `node2`.*
74
60
75
-
```python
76
-
edges=[(
77
-
START,
78
-
node1,
79
-
node2,
80
-
81
-
node3
82
-
)]
83
-
84
-
(START, node1),
85
-
(node1, node2)
86
-
# NOT (node2, node3), see chapter 'Joining'
87
-
```
61
+
---
88
62
89
-
### Spawning
63
+
## Synchronization
90
64
91
-
A branch is spawned when the source of the branch is triggered.
65
+
The graph manages state consistency on two levels:
92
66
93
-
The source of the branch can be a node or `START` or a list of that.
67
+
- **Internal (Step Sync)**
68
+
Parallel executing nodes in branches are synchronized at each step.
69
+
The state is merged after each step.
94
70
95
-
In this example it would be on `START`:
71
+
- **External (Branch Sync)**
72
+
Branches are synchronized at the `join` point.
96
73
97
-
```python
98
-
edges=[(
99
-
START,
100
-
node1,
101
-
node2,
102
-
103
-
END
104
-
)]
105
-
```
106
74
107
-
In this example it would be on `START` and on `node1` each, spawning two branches total:
108
-
109
-
```python
110
-
edges=[(
111
-
[START, node1],
112
-
node2,
75
+
### Spawning
76
+
A branch is triggered **immediately before** its `Source` is executed in another branch.
77
+
* `START`: Initial execution point.
78
+
* `Node`: Spawns when a specific node is executed in another branch.
79
+
* `List[Node]`: Spawns when any node in the list is executed in another branch.
113
80
114
-
node3 # join node
115
-
)]
116
-
```
117
81
118
82
### Joining
83
+
Joining synchronizes multiple branches before moving to the next step.
84
+
* `None`: No synchronization and no merge of the state.
85
+
* `END`: Joins all branches at the graph's conclusion to return the merged state.
86
+
* `Node`: Other branches wait until all branches targeting this node have arrived and then merge the states before executing the node.
119
87
120
-
Joining describes the process of merging the states of multiple branches into one.
121
-
122
-
The join parameter defines the node, exactly before which the branches will be joined. Other branches will wait in each step for all other branches that aim to join on its next node.
123
-
124
-
The join parameter can be of the following types:
125
-
126
-
- `None`: The branch will not be joined.
127
-
- `END`: The branch will be joined at the end of the graph, the merged state will be returned as the result of the graph.
128
-
- A single node instance: The branch will be joined directly before another branch executes this specific node.
88
+
---
129
89
130
-
### Notation
90
+
## Notation Reference
131
91
132
-
`Source` and `Next` parameters allow the following types:
133
-
- A single node instance.
134
-
135
-
`Source` can also be:
136
-
- `START`: The start of the graph.
137
-
- `Exception`: Triggers when an exception occurs in the graph in an edge located BEFORE this in the tuple.
138
-
- `(Exception, node)` or `(Exception, [node1, node2])`: Triggers when an exception occurs in the graph in an edge located BEFORE this in the tuple and the exception occuredd in the node `node` or one of the nodes `node1` and `node2`.
139
-
- A list of all allowed types.
140
-
141
-
`Next` can also be:
142
-
- A list of all allowed types.
143
-
- A function (sync/async) that takes the state and shared and returns any of the allowed types.
144
-
145
-
146
-
The following notations are allowed for edges:
147
-
148
-
- `node1, node2`: A single edge from node1 to node2.
149
-
- `START, node1`: A single edge from the start of the graph to node1. START is only called when the branch has `START` as source.
150
-
- `node, None`: A redundant edge that does nothing.
151
-
- `[source1, source2], target`: Multiple edges from source1 and source2 to target.
152
-
- `(source, [target1, target2])`: Multiple edges from source to target1 and target2.
153
-
- `([source1, source2], [target1, target2])`: Multiple edges from source1 and source2 to target1 and target2. This will create 4 edges in total.
154
-
- `(source, lambda st, sh: [target1, target2] if sh.x)`: A dynamic edge from source to target. The function takes the state and the shared state as arguments. It must return a node, a list of nodes, END or None. Async functions are also supported. They are executed sequentially so there are no race conditions.
155
-
- `(source, target, Config(instant=True))`: An instant edge from source to target. The target nodes are collected recursively and executed parallel to the source node. Make sure not to create cycles.
156
-
- `(ValueError, target)`: An error edge from ValueError to target. The edge is traversed if a node, which is executed by an incoming edge located BEFORE this error edge in the edge list, throws a ValueError.
157
-
- `((source, Exception), target)`: An error edge from Exception to target. The edge is traversed if the source node is executed by an incoming edge which is located BEFORE this error edge in the edge list throws an Exception. Source node lists are also supported.
158
-
- `(Exception, target, ErrorConfig(propagate=True))`: If propagate is `True`, the exception is propagated to the next error edges in the edge list. If the exception is not handled by any error edge, it is ultimately raised.
0 commit comments