open-orbyt 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- open_orbyt-0.1.0/.gitignore +14 -0
- open_orbyt-0.1.0/PKG-INFO +227 -0
- open_orbyt-0.1.0/README.md +202 -0
- open_orbyt-0.1.0/pyproject.toml +42 -0
- open_orbyt-0.1.0/src/orbyt/__init__.py +76 -0
- open_orbyt-0.1.0/src/orbyt/_async_batch.py +297 -0
- open_orbyt-0.1.0/src/orbyt/_async_flow.py +181 -0
- open_orbyt-0.1.0/src/orbyt/_async_node.py +410 -0
- open_orbyt-0.1.0/src/orbyt/_batch.py +380 -0
- open_orbyt-0.1.0/src/orbyt/_flow.py +177 -0
- open_orbyt-0.1.0/src/orbyt/_node.py +527 -0
- open_orbyt-0.1.0/src/orbyt/_pool.py +77 -0
- open_orbyt-0.1.0/src/orbyt/_result.py +283 -0
- open_orbyt-0.1.0/src/orbyt/_store.py +221 -0
- open_orbyt-0.1.0/src/orbyt/_utils.py +24 -0
- open_orbyt-0.1.0/src/orbyt/py.typed +0 -0
- open_orbyt-0.1.0/tests/__init__.py +0 -0
- open_orbyt-0.1.0/tests/test_async.py +347 -0
- open_orbyt-0.1.0/tests/test_batch.py +212 -0
- open_orbyt-0.1.0/tests/test_flow.py +134 -0
- open_orbyt-0.1.0/tests/test_integration.py +131 -0
- open_orbyt-0.1.0/tests/test_node.py +166 -0
- open_orbyt-0.1.0/tests/test_pool.py +77 -0
- open_orbyt-0.1.0/tests/test_result.py +236 -0
- open_orbyt-0.1.0/tests/test_store.py +237 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: open_orbyt
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A workflow framework for Python. Build AI agents, data pipelines, and orchestration flows with nodes, graphs, and a shared store.
|
|
5
|
+
Project-URL: Homepage, https://github.com/erickweyunga/orbyt
|
|
6
|
+
Project-URL: Repository, https://github.com/erickweyunga/orbyt
|
|
7
|
+
Project-URL: Documentation, https://github.com/erickweyunga/orbyt#readme
|
|
8
|
+
Project-URL: Issues, https://github.com/erickweyunga/orbyt/issues
|
|
9
|
+
Author-email: Maverick Weyunga <maverickweyunga@gmail.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
Keywords: agent,ai,dag,flow,graph,orchestration,pipeline,workflow
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: pydantic>=2.0
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# orbyt
|
|
27
|
+
|
|
28
|
+
A workflow framework for Python. Build AI agents, data pipelines, and orchestration flows with nodes, graphs, and a shared store.
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install orbyt
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from orbyt import Flow, SharedStore, Result, new_node, run, DEFAULT_ACTION
|
|
40
|
+
|
|
41
|
+
# Create nodes
|
|
42
|
+
fetch = (
|
|
43
|
+
new_node()
|
|
44
|
+
.with_name("fetch")
|
|
45
|
+
.with_exec_func(lambda r: Result({"users": ["Alice", "Bob", "Charlie"]}))
|
|
46
|
+
.with_post_func(lambda shared, p, e: shared.set("data", e.value) or DEFAULT_ACTION)
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
transform = (
|
|
50
|
+
new_node()
|
|
51
|
+
.with_name("transform")
|
|
52
|
+
.with_prep_func(lambda shared: Result(shared.get_dict("data")))
|
|
53
|
+
.with_exec_func(lambda r: Result([name.upper() for name in r.must_dict()["users"]]))
|
|
54
|
+
.with_post_func(lambda shared, p, e: shared.set("result", e.value) or DEFAULT_ACTION)
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Connect into a flow
|
|
58
|
+
flow = Flow(fetch)
|
|
59
|
+
flow.connect(fetch, DEFAULT_ACTION, transform)
|
|
60
|
+
|
|
61
|
+
# Run
|
|
62
|
+
shared = SharedStore()
|
|
63
|
+
flow.run_flow(shared)
|
|
64
|
+
print(shared.get_list("result")) # ['ALICE', 'BOB', 'CHARLIE']
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Core Concepts
|
|
68
|
+
|
|
69
|
+
### Nodes
|
|
70
|
+
|
|
71
|
+
Every node runs three phases: **prep** (read inputs) → **exec** (do the work, retryable) → **post** (write results, return an action).
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
node = (
|
|
75
|
+
new_node()
|
|
76
|
+
.with_max_retries(3)
|
|
77
|
+
.with_wait(1.0)
|
|
78
|
+
.with_prep_func(lambda shared: Result(shared.get_string("input")))
|
|
79
|
+
.with_exec_func(lambda r: Result(r.must_string().upper()))
|
|
80
|
+
.with_post_func(lambda shared, p, e: shared.set("output", e.value) or DEFAULT_ACTION)
|
|
81
|
+
)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Or subclass for stateful nodes:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
class MyNode(BaseNode):
|
|
88
|
+
def __init__(self):
|
|
89
|
+
super().__init__(max_retries=3, wait=0.5)
|
|
90
|
+
|
|
91
|
+
def prep(self, shared):
|
|
92
|
+
return shared.get_string("input")
|
|
93
|
+
|
|
94
|
+
def exec(self, prep_result):
|
|
95
|
+
return prep_result.upper()
|
|
96
|
+
|
|
97
|
+
def post(self, shared, prep_result, exec_result):
|
|
98
|
+
shared.set("output", exec_result)
|
|
99
|
+
return DEFAULT_ACTION
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Flows
|
|
103
|
+
|
|
104
|
+
Connect nodes with action-based routing to build directed graphs:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
flow = Flow(start_node)
|
|
108
|
+
flow.connect(start_node, "success", next_node)
|
|
109
|
+
flow.connect(start_node, "error", error_node)
|
|
110
|
+
flow.connect(next_node, DEFAULT_ACTION, final_node)
|
|
111
|
+
flow.run_flow(shared)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Flows implement the Node interface - nest them inside other flows.
|
|
115
|
+
|
|
116
|
+
### SharedStore
|
|
117
|
+
|
|
118
|
+
Thread-safe key-value store with typed getters:
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
shared = SharedStore()
|
|
122
|
+
shared.set("count", 42)
|
|
123
|
+
shared.get_int("count") # 42
|
|
124
|
+
shared.get_int_or("missing", -1) # -1
|
|
125
|
+
shared.bind("user", UserModel) # pydantic or dataclass
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Batch Processing
|
|
129
|
+
|
|
130
|
+
Process lists of items with configurable concurrency:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
from orbyt import new_batch_node
|
|
134
|
+
|
|
135
|
+
batch = (
|
|
136
|
+
new_batch_node()
|
|
137
|
+
.with_batch_concurrency(5)
|
|
138
|
+
.with_batch_error_handling(True)
|
|
139
|
+
.with_prep_func(lambda shared: [Result(url) for url in shared.get_list("urls")])
|
|
140
|
+
.with_exec_func(lambda r: Result(fetch(r.must_string())))
|
|
141
|
+
.with_post_func(lambda shared, items, results: ...)
|
|
142
|
+
)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Retry + Fallback
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
node = (
|
|
149
|
+
new_node()
|
|
150
|
+
.with_max_retries(3)
|
|
151
|
+
.with_wait(1.0)
|
|
152
|
+
.with_exec_func(call_flaky_api)
|
|
153
|
+
.with_exec_fallback_func(lambda prep, err: {"status": "cached"})
|
|
154
|
+
)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Async
|
|
158
|
+
|
|
159
|
+
Every primitive has an async counterpart. Phase functions may be sync or
|
|
160
|
+
async, and async flows can contain plain sync nodes — each phase is awaited
|
|
161
|
+
only when it returns a coroutine.
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
import asyncio
|
|
165
|
+
from orbyt import AsyncFlow, new_async_node, run_async, Result, SharedStore, DEFAULT_ACTION
|
|
166
|
+
|
|
167
|
+
fetch = (
|
|
168
|
+
new_async_node()
|
|
169
|
+
.with_name("fetch")
|
|
170
|
+
.with_exec_func(async_fetch_users) # a coroutine function
|
|
171
|
+
.with_post_func(lambda s, p, e: s.set("data", e.value) or DEFAULT_ACTION)
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
flow = AsyncFlow(fetch, max_steps=50) # max_steps guards against runaway cycles
|
|
175
|
+
flow.connect(fetch, DEFAULT_ACTION, transform)
|
|
176
|
+
|
|
177
|
+
await flow.run_flow(SharedStore())
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
`run_async` mirrors `run` (retries sleep via `asyncio.sleep`, same fallback
|
|
181
|
+
behavior). `new_async_batch_node()` runs items concurrently with an
|
|
182
|
+
`asyncio.Semaphore` instead of a thread pool — the right model for I/O-bound
|
|
183
|
+
work. `AsyncFlow.max_steps` turns infinite loops into a loud `RuntimeError`.
|
|
184
|
+
|
|
185
|
+
### Mermaid Graph Export
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
flow = Flow(node_a, name="My Flow")
|
|
189
|
+
flow.connect(node_a, DEFAULT_ACTION, node_b)
|
|
190
|
+
print(flow.to_mermaid())
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## API Reference
|
|
194
|
+
|
|
195
|
+
### Core Types
|
|
196
|
+
|
|
197
|
+
| Type | Description |
|
|
198
|
+
|---|---|
|
|
199
|
+
| `Node` | Abstract base class - implement `prep`, `exec`, `post` |
|
|
200
|
+
| `BaseNode` | Default implementation with retry/batch config |
|
|
201
|
+
| `CustomNode` | Node with function fields |
|
|
202
|
+
| `NodeBuilder` | Fluent builder from `new_node()` |
|
|
203
|
+
| `Flow` | Directed graph of nodes (also a Node) |
|
|
204
|
+
| `SharedStore` | Thread-safe key-value store |
|
|
205
|
+
| `Result` | Value wrapper with typed accessors |
|
|
206
|
+
| `BatchNode` | Node for processing lists |
|
|
207
|
+
| `WorkerPool` | Fixed-size thread pool |
|
|
208
|
+
| `AsyncNode` | Abstract async node - `async prep`/`exec`/`post` |
|
|
209
|
+
| `AsyncBaseNode` | Default async node with retry/batch config |
|
|
210
|
+
| `AsyncFlow` | Async directed graph (also an `AsyncNode`); `max_steps` loop guard |
|
|
211
|
+
| `AsyncBatchNode` | Async list processing, concurrency via `asyncio.Semaphore` |
|
|
212
|
+
|
|
213
|
+
### Factory Functions
|
|
214
|
+
|
|
215
|
+
| Function | Description |
|
|
216
|
+
|---|---|
|
|
217
|
+
| `new_node()` | Create a `NodeBuilder` |
|
|
218
|
+
| `new_batch_node()` | Create a `BatchNodeBuilder` |
|
|
219
|
+
| `run(node, shared)` | Execute a node through prep→exec→post |
|
|
220
|
+
| `new_async_node()` | Create an `AsyncNodeBuilder` |
|
|
221
|
+
| `new_async_batch_node()` | Create an `AsyncBatchNodeBuilder` |
|
|
222
|
+
| `run_async(node, shared)` | Await a node through prep→exec→post (sync nodes too) |
|
|
223
|
+
| `to_slice(v)` | Convert any value to `list` |
|
|
224
|
+
|
|
225
|
+
## License
|
|
226
|
+
|
|
227
|
+
MIT
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# orbyt
|
|
2
|
+
|
|
3
|
+
A workflow framework for Python. Build AI agents, data pipelines, and orchestration flows with nodes, graphs, and a shared store.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install orbyt
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from orbyt import Flow, SharedStore, Result, new_node, run, DEFAULT_ACTION
|
|
15
|
+
|
|
16
|
+
# Create nodes
|
|
17
|
+
fetch = (
|
|
18
|
+
new_node()
|
|
19
|
+
.with_name("fetch")
|
|
20
|
+
.with_exec_func(lambda r: Result({"users": ["Alice", "Bob", "Charlie"]}))
|
|
21
|
+
.with_post_func(lambda shared, p, e: shared.set("data", e.value) or DEFAULT_ACTION)
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
transform = (
|
|
25
|
+
new_node()
|
|
26
|
+
.with_name("transform")
|
|
27
|
+
.with_prep_func(lambda shared: Result(shared.get_dict("data")))
|
|
28
|
+
.with_exec_func(lambda r: Result([name.upper() for name in r.must_dict()["users"]]))
|
|
29
|
+
.with_post_func(lambda shared, p, e: shared.set("result", e.value) or DEFAULT_ACTION)
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# Connect into a flow
|
|
33
|
+
flow = Flow(fetch)
|
|
34
|
+
flow.connect(fetch, DEFAULT_ACTION, transform)
|
|
35
|
+
|
|
36
|
+
# Run
|
|
37
|
+
shared = SharedStore()
|
|
38
|
+
flow.run_flow(shared)
|
|
39
|
+
print(shared.get_list("result")) # ['ALICE', 'BOB', 'CHARLIE']
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Core Concepts
|
|
43
|
+
|
|
44
|
+
### Nodes
|
|
45
|
+
|
|
46
|
+
Every node runs three phases: **prep** (read inputs) → **exec** (do the work, retryable) → **post** (write results, return an action).
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
node = (
|
|
50
|
+
new_node()
|
|
51
|
+
.with_max_retries(3)
|
|
52
|
+
.with_wait(1.0)
|
|
53
|
+
.with_prep_func(lambda shared: Result(shared.get_string("input")))
|
|
54
|
+
.with_exec_func(lambda r: Result(r.must_string().upper()))
|
|
55
|
+
.with_post_func(lambda shared, p, e: shared.set("output", e.value) or DEFAULT_ACTION)
|
|
56
|
+
)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Or subclass for stateful nodes:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
class MyNode(BaseNode):
|
|
63
|
+
def __init__(self):
|
|
64
|
+
super().__init__(max_retries=3, wait=0.5)
|
|
65
|
+
|
|
66
|
+
def prep(self, shared):
|
|
67
|
+
return shared.get_string("input")
|
|
68
|
+
|
|
69
|
+
def exec(self, prep_result):
|
|
70
|
+
return prep_result.upper()
|
|
71
|
+
|
|
72
|
+
def post(self, shared, prep_result, exec_result):
|
|
73
|
+
shared.set("output", exec_result)
|
|
74
|
+
return DEFAULT_ACTION
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Flows
|
|
78
|
+
|
|
79
|
+
Connect nodes with action-based routing to build directed graphs:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
flow = Flow(start_node)
|
|
83
|
+
flow.connect(start_node, "success", next_node)
|
|
84
|
+
flow.connect(start_node, "error", error_node)
|
|
85
|
+
flow.connect(next_node, DEFAULT_ACTION, final_node)
|
|
86
|
+
flow.run_flow(shared)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Flows implement the Node interface - nest them inside other flows.
|
|
90
|
+
|
|
91
|
+
### SharedStore
|
|
92
|
+
|
|
93
|
+
Thread-safe key-value store with typed getters:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
shared = SharedStore()
|
|
97
|
+
shared.set("count", 42)
|
|
98
|
+
shared.get_int("count") # 42
|
|
99
|
+
shared.get_int_or("missing", -1) # -1
|
|
100
|
+
shared.bind("user", UserModel) # pydantic or dataclass
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Batch Processing
|
|
104
|
+
|
|
105
|
+
Process lists of items with configurable concurrency:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from orbyt import new_batch_node
|
|
109
|
+
|
|
110
|
+
batch = (
|
|
111
|
+
new_batch_node()
|
|
112
|
+
.with_batch_concurrency(5)
|
|
113
|
+
.with_batch_error_handling(True)
|
|
114
|
+
.with_prep_func(lambda shared: [Result(url) for url in shared.get_list("urls")])
|
|
115
|
+
.with_exec_func(lambda r: Result(fetch(r.must_string())))
|
|
116
|
+
.with_post_func(lambda shared, items, results: ...)
|
|
117
|
+
)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Retry + Fallback
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
node = (
|
|
124
|
+
new_node()
|
|
125
|
+
.with_max_retries(3)
|
|
126
|
+
.with_wait(1.0)
|
|
127
|
+
.with_exec_func(call_flaky_api)
|
|
128
|
+
.with_exec_fallback_func(lambda prep, err: {"status": "cached"})
|
|
129
|
+
)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Async
|
|
133
|
+
|
|
134
|
+
Every primitive has an async counterpart. Phase functions may be sync or
|
|
135
|
+
async, and async flows can contain plain sync nodes — each phase is awaited
|
|
136
|
+
only when it returns a coroutine.
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
import asyncio
|
|
140
|
+
from orbyt import AsyncFlow, new_async_node, run_async, Result, SharedStore, DEFAULT_ACTION
|
|
141
|
+
|
|
142
|
+
fetch = (
|
|
143
|
+
new_async_node()
|
|
144
|
+
.with_name("fetch")
|
|
145
|
+
.with_exec_func(async_fetch_users) # a coroutine function
|
|
146
|
+
.with_post_func(lambda s, p, e: s.set("data", e.value) or DEFAULT_ACTION)
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
flow = AsyncFlow(fetch, max_steps=50) # max_steps guards against runaway cycles
|
|
150
|
+
flow.connect(fetch, DEFAULT_ACTION, transform)
|
|
151
|
+
|
|
152
|
+
await flow.run_flow(SharedStore())
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`run_async` mirrors `run` (retries sleep via `asyncio.sleep`, same fallback
|
|
156
|
+
behavior). `new_async_batch_node()` runs items concurrently with an
|
|
157
|
+
`asyncio.Semaphore` instead of a thread pool — the right model for I/O-bound
|
|
158
|
+
work. `AsyncFlow.max_steps` turns infinite loops into a loud `RuntimeError`.
|
|
159
|
+
|
|
160
|
+
### Mermaid Graph Export
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
flow = Flow(node_a, name="My Flow")
|
|
164
|
+
flow.connect(node_a, DEFAULT_ACTION, node_b)
|
|
165
|
+
print(flow.to_mermaid())
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## API Reference
|
|
169
|
+
|
|
170
|
+
### Core Types
|
|
171
|
+
|
|
172
|
+
| Type | Description |
|
|
173
|
+
|---|---|
|
|
174
|
+
| `Node` | Abstract base class - implement `prep`, `exec`, `post` |
|
|
175
|
+
| `BaseNode` | Default implementation with retry/batch config |
|
|
176
|
+
| `CustomNode` | Node with function fields |
|
|
177
|
+
| `NodeBuilder` | Fluent builder from `new_node()` |
|
|
178
|
+
| `Flow` | Directed graph of nodes (also a Node) |
|
|
179
|
+
| `SharedStore` | Thread-safe key-value store |
|
|
180
|
+
| `Result` | Value wrapper with typed accessors |
|
|
181
|
+
| `BatchNode` | Node for processing lists |
|
|
182
|
+
| `WorkerPool` | Fixed-size thread pool |
|
|
183
|
+
| `AsyncNode` | Abstract async node - `async prep`/`exec`/`post` |
|
|
184
|
+
| `AsyncBaseNode` | Default async node with retry/batch config |
|
|
185
|
+
| `AsyncFlow` | Async directed graph (also an `AsyncNode`); `max_steps` loop guard |
|
|
186
|
+
| `AsyncBatchNode` | Async list processing, concurrency via `asyncio.Semaphore` |
|
|
187
|
+
|
|
188
|
+
### Factory Functions
|
|
189
|
+
|
|
190
|
+
| Function | Description |
|
|
191
|
+
|---|---|
|
|
192
|
+
| `new_node()` | Create a `NodeBuilder` |
|
|
193
|
+
| `new_batch_node()` | Create a `BatchNodeBuilder` |
|
|
194
|
+
| `run(node, shared)` | Execute a node through prep→exec→post |
|
|
195
|
+
| `new_async_node()` | Create an `AsyncNodeBuilder` |
|
|
196
|
+
| `new_async_batch_node()` | Create an `AsyncBatchNodeBuilder` |
|
|
197
|
+
| `run_async(node, shared)` | Await a node through prep→exec→post (sync nodes too) |
|
|
198
|
+
| `to_slice(v)` | Convert any value to `list` |
|
|
199
|
+
|
|
200
|
+
## License
|
|
201
|
+
|
|
202
|
+
MIT
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "open_orbyt"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A workflow framework for Python. Build AI agents, data pipelines, and orchestration flows with nodes, graphs, and a shared store."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Maverick Weyunga", email = "maverickweyunga@gmail.com" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["workflow", "pipeline", "dag", "flow", "orchestration", "agent", "ai", "graph"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
25
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
26
|
+
"Typing :: Typed",
|
|
27
|
+
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"pydantic>=2.0",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Homepage = "https://github.com/erickweyunga/orbyt"
|
|
34
|
+
Repository = "https://github.com/erickweyunga/orbyt"
|
|
35
|
+
Documentation = "https://github.com/erickweyunga/orbyt#readme"
|
|
36
|
+
Issues = "https://github.com/erickweyunga/orbyt/issues"
|
|
37
|
+
|
|
38
|
+
[tool.hatch.build.targets.wheel]
|
|
39
|
+
packages = ["src/orbyt"]
|
|
40
|
+
|
|
41
|
+
[tool.pytest.ini_options]
|
|
42
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""orbyt - A workflow framework for Python.
|
|
2
|
+
|
|
3
|
+
Build AI agents, data pipelines, and orchestration flows
|
|
4
|
+
with nodes, graphs, and a shared store.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from ._async_batch import (
|
|
8
|
+
AsyncBatchNode,
|
|
9
|
+
AsyncBatchNodeBuilder,
|
|
10
|
+
new_async_batch_node,
|
|
11
|
+
run_batch_async,
|
|
12
|
+
)
|
|
13
|
+
from ._async_flow import AsyncFlow
|
|
14
|
+
from ._async_node import (
|
|
15
|
+
AsyncBaseNode,
|
|
16
|
+
AsyncCustomNode,
|
|
17
|
+
AsyncNode,
|
|
18
|
+
AsyncNodeBuilder,
|
|
19
|
+
new_async_node,
|
|
20
|
+
run_async,
|
|
21
|
+
)
|
|
22
|
+
from ._batch import BatchError, BatchNode, BatchNodeBuilder, new_batch_node
|
|
23
|
+
from ._flow import Flow
|
|
24
|
+
from ._node import (
|
|
25
|
+
DEFAULT_ACTION,
|
|
26
|
+
Action,
|
|
27
|
+
BaseNode,
|
|
28
|
+
CustomNode,
|
|
29
|
+
FallbackNode,
|
|
30
|
+
Node,
|
|
31
|
+
NodeBuilder,
|
|
32
|
+
NodeConfig,
|
|
33
|
+
RetryableNode,
|
|
34
|
+
new_node,
|
|
35
|
+
run,
|
|
36
|
+
)
|
|
37
|
+
from ._pool import WorkerPool
|
|
38
|
+
from ._result import Result
|
|
39
|
+
from ._store import SharedStore
|
|
40
|
+
from ._utils import to_slice
|
|
41
|
+
|
|
42
|
+
__all__ = [
|
|
43
|
+
"Action",
|
|
44
|
+
"AsyncBaseNode",
|
|
45
|
+
"AsyncBatchNode",
|
|
46
|
+
"AsyncBatchNodeBuilder",
|
|
47
|
+
"AsyncCustomNode",
|
|
48
|
+
"AsyncFlow",
|
|
49
|
+
"AsyncNode",
|
|
50
|
+
"AsyncNodeBuilder",
|
|
51
|
+
"BaseNode",
|
|
52
|
+
"BatchError",
|
|
53
|
+
"BatchNode",
|
|
54
|
+
"BatchNodeBuilder",
|
|
55
|
+
"CustomNode",
|
|
56
|
+
"DEFAULT_ACTION",
|
|
57
|
+
"FallbackNode",
|
|
58
|
+
"Flow",
|
|
59
|
+
"Node",
|
|
60
|
+
"NodeBuilder",
|
|
61
|
+
"NodeConfig",
|
|
62
|
+
"Result",
|
|
63
|
+
"RetryableNode",
|
|
64
|
+
"SharedStore",
|
|
65
|
+
"WorkerPool",
|
|
66
|
+
"new_async_batch_node",
|
|
67
|
+
"new_async_node",
|
|
68
|
+
"new_batch_node",
|
|
69
|
+
"new_node",
|
|
70
|
+
"run",
|
|
71
|
+
"run_async",
|
|
72
|
+
"run_batch_async",
|
|
73
|
+
"to_slice",
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
__version__ = "0.1.0"
|