flowcraft 1.0.0-beta.2 → 1.0.0-beta.20
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.
- package/README.md +136 -26
- package/dist/index.d.ts +475 -233
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/package.json +9 -12
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ Build complex, multi-step processes, from simple sequences to dynamic, graph-dri
|
|
|
10
10
|
|
|
11
11
|
- **Extensible Execution Engine**: A pluggable `Executor` pattern enables in-memory or distributed flows.
|
|
12
12
|
|
|
13
|
-
- **Type-Safe**: Written in TypeScript to provide strong typing for your workflow definitions and
|
|
13
|
+
- **Type-Safe**: Written in TypeScript to provide strong typing for your workflow definitions, context, and node parameters.
|
|
14
14
|
|
|
15
15
|
- **Async by Default**: Built on an asynchronous foundation to handle I/O-bound and CPU-bound tasks.
|
|
16
16
|
|
|
@@ -39,12 +39,11 @@ npm install flowcraft
|
|
|
39
39
|
Create and run a simple workflow in a few lines of code.
|
|
40
40
|
|
|
41
41
|
```typescript
|
|
42
|
-
import { Flow,
|
|
42
|
+
import { Flow, mapNode } from 'flowcraft' // Use mapNode for simple functions
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
// Functional helpers make common tasks easy.
|
|
44
|
+
// Create a node from a simple function that takes params and returns a value.
|
|
45
|
+
const greetNode = mapNode(() => 'Hello, World!')
|
|
46
|
+
// Functional helpers make common tasks easy.
|
|
48
47
|
.tap(console.log)
|
|
49
48
|
|
|
50
49
|
const flow = new Flow(greetNode)
|
|
@@ -68,7 +67,7 @@ graph LR
|
|
|
68
67
|
```
|
|
69
68
|
|
|
70
69
|
- **Demonstrates**: `Node` chaining, passing data via `Context`, and a simple `BatchFlow`.
|
|
71
|
-
- **[Explore the Basic example »](
|
|
70
|
+
- **[Explore the Basic example »](https://github.com/gorango/flowcraft/tree/main/sandbox/1.basic/)**
|
|
72
71
|
|
|
73
72
|
### 2. Conditional Branching: Research Agent
|
|
74
73
|
|
|
@@ -82,7 +81,7 @@ graph TD
|
|
|
82
81
|
```
|
|
83
82
|
|
|
84
83
|
- **Demonstrates**: Conditional branching with custom actions, creating loops, and building simple state machines.
|
|
85
|
-
- **[Explore the Research Agent example »](
|
|
84
|
+
- **[Explore the Research Agent example »](https://github.com/gorango/flowcraft/tree/main/sandbox/2.research/)**
|
|
86
85
|
|
|
87
86
|
### 3. Parallel Batch Processing: Document Translator
|
|
88
87
|
|
|
@@ -102,7 +101,7 @@ graph TD
|
|
|
102
101
|
```
|
|
103
102
|
|
|
104
103
|
- **Demonstrates**: `ParallelBatchFlow` for high-throughput concurrent processing of I/O-bound tasks.
|
|
105
|
-
- **[Explore the Parallel Translation example »](
|
|
104
|
+
- **[Explore the Parallel Translation example »](https://github.com/gorango/flowcraft/tree/main/sandbox/3.parallel/)**
|
|
106
105
|
|
|
107
106
|
### 4. Dynamic Graph Engine: AI Agent Runtime
|
|
108
107
|
|
|
@@ -134,7 +133,7 @@ graph TD
|
|
|
134
133
|
- Parallel fan-in and fan-out (mid-flow branching).
|
|
135
134
|
- Reusable, data-driven nodes (e.g., an LLM-powered router).
|
|
136
135
|
- Complex sub-workflow composition.
|
|
137
|
-
- **[Explore the Dynamic AI Agent example »](
|
|
136
|
+
- **[Explore the Dynamic AI Agent example »](https://github.com/gorango/flowcraft/tree/main/sandbox/4.dag/)**
|
|
138
137
|
|
|
139
138
|
### 5. Distributed Execution: AI Agent with BullMQ
|
|
140
139
|
|
|
@@ -145,7 +144,7 @@ This example takes the same type-safe graph definition from the previous example
|
|
|
145
144
|
- Client-worker architecture with state serialization.
|
|
146
145
|
- Mid-flight, distributed cancellation of long-running jobs.
|
|
147
146
|
- How business logic (the graph) remains unchanged when the execution environment changes.
|
|
148
|
-
- **[Explore the Distributed AI Agent example »](
|
|
147
|
+
- **[Explore the Distributed AI Agent example »](https://github.com/gorango/flowcraft/tree/main/sandbox/5.distributed/)**
|
|
149
148
|
|
|
150
149
|
### 6. Advanced RAG Agent: Complex Data & Serialization
|
|
151
150
|
|
|
@@ -164,28 +163,127 @@ graph TD
|
|
|
164
163
|
- A mix of custom, single-responsibility nodes.
|
|
165
164
|
- Handling complex data types (`Map`, `Date`, custom classes) in the `Context`.
|
|
166
165
|
- The necessity of robust serialization (using `superjson`) for state management.
|
|
167
|
-
- **[Explore the RAG Agent example »](
|
|
166
|
+
- **[Explore the RAG Agent example »](https://github.com/gorango/flowcraft/tree/main/sandbox/6.rag/)**
|
|
168
167
|
|
|
169
168
|
## Core Concepts
|
|
170
169
|
|
|
171
170
|
### Node
|
|
172
171
|
|
|
173
|
-
The `Node` is the fundamental building block of a workflow. It represents a single
|
|
172
|
+
The `Node` is the fundamental building block of a workflow. It represents a single unit of work and is fully generic, allowing you to define types for its lifecycle results and its static parameters.
|
|
174
173
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
174
|
+
The class signature is: `Node<PrepRes, ExecRes, PostRes, TParams>`
|
|
175
|
+
|
|
176
|
+
- `PrepRes`: The type of data returned by the `prep` phase.
|
|
177
|
+
- `ExecRes`: The type of data returned by the `exec` phase.
|
|
178
|
+
- `PostRes`: The type of the "action" returned by the `post` phase.
|
|
179
|
+
- `TParams`: The type of the static parameters object for the node, accessible via `.withParams()`.
|
|
180
|
+
|
|
181
|
+
**Example: A Type-Safe GreetNode**
|
|
182
|
+
|
|
183
|
+
For nodes that do require static configuration, you can provide a type for the parameters to get full autocompletion and compile-time safety.
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
// 1. Define the shape of the node's parameters.
|
|
187
|
+
interface GreetParams {
|
|
188
|
+
greeting: string
|
|
189
|
+
loudly: boolean
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// 2. Define the node with the TParams generic.
|
|
193
|
+
class GreetNode extends Node<void, string, any, GreetParams> {
|
|
194
|
+
// 3. The 'exec' method can safely access typed parameters.
|
|
195
|
+
async exec({ params }: NodeArgs<GreetParams>): Promise<string> {
|
|
196
|
+
let message = `${params.greeting}, World!`
|
|
197
|
+
if (params.loudly) {
|
|
198
|
+
message = message.toUpperCase()
|
|
199
|
+
}
|
|
200
|
+
return message
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// 4. Instantiate and configure with type-safe .withParams()
|
|
205
|
+
const greetNode = new GreetNode()
|
|
206
|
+
.withParams({ greeting: 'Hello', loudly: true }) // Autocompletes and type-checks!
|
|
207
|
+
.tap(console.log) // "HELLO, WORLD!"
|
|
208
|
+
|
|
209
|
+
// TypeScript would throw an error on this line:
|
|
210
|
+
// greetNode.withParams({ greting: 'Hi', loudly: false }); // Property 'greting' does not exist.
|
|
211
|
+
```
|
|
178
212
|
|
|
179
213
|
A chainable API on the `Node` class has a set of functional helpers:
|
|
180
214
|
|
|
215
|
+
- `.withParams(params)`: Sets type-safe static parameters for the node.
|
|
181
216
|
- `.map(fn)`: Transform the output of a node.
|
|
182
217
|
- `.filter(predicate)`: Conditionally proceed based on a node's output.
|
|
183
218
|
- `.tap(fn)`: Perform a side-effect without changing the output.
|
|
184
219
|
- `.toContext(key)`: Store a node's result in the context.
|
|
220
|
+
- `.withLens(lens, value)`: Applies a context mutation before the node executes
|
|
221
|
+
|
|
222
|
+
### Simplified Node Base Classes
|
|
223
|
+
|
|
224
|
+
To reduce boilerplate for common patterns, Flowcraft provides specialized abstract base classes.
|
|
225
|
+
|
|
226
|
+
#### `ExecNode`
|
|
227
|
+
|
|
228
|
+
For nodes that only need to perform a core action and return a value. This is the most common pattern.
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
// 1. Define params and the node, extending ExecNode<ExecRes, TParams>
|
|
232
|
+
interface GreetParams { name: string }
|
|
233
|
+
|
|
234
|
+
class GreetNode extends ExecNode<string, GreetParams> {
|
|
235
|
+
// 2. You only need to implement the 'exec' method.
|
|
236
|
+
async exec({ params }: NodeArgs<void, void, GreetParams>): Promise<string> {
|
|
237
|
+
return `Hello, ${params.name}!`
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Usage:
|
|
242
|
+
const greetNode = new GreetNode().withParams({ name: 'World' })
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
#### `PreNode`
|
|
246
|
+
|
|
247
|
+
For nodes that only modify state (e.g., in the `Context`) and don't produce an output. Their logic can be placed in the `prep` phase.
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
const COUNTER = contextKey<number>('counter')
|
|
251
|
+
|
|
252
|
+
class IncrementCounterNode extends PreNode {
|
|
253
|
+
// You only need to implement the 'prep' method for context mutations.
|
|
254
|
+
async prep({ ctx }: NodeArgs): Promise<void> {
|
|
255
|
+
const current = ctx.get(COUNTER) ?? 0
|
|
256
|
+
ctx.set(COUNTER, current + 1)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
#### `PostNode`
|
|
262
|
+
|
|
263
|
+
For nodes that route the workflow by returning a custom action string from their `post` method.
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
const USER_ROLE = contextKey<'admin' | 'guest'>('user_role')
|
|
267
|
+
|
|
268
|
+
type UserAction = 'grant_access' | 'deny_access'
|
|
269
|
+
|
|
270
|
+
class CheckAdminNode extends PostNode<UserAction> {
|
|
271
|
+
// You only need to implement the 'post' method for branching logic.
|
|
272
|
+
async post({ ctx }: NodeArgs): Promise<UserAction> {
|
|
273
|
+
const role = ctx.get(USER_ROLE)
|
|
274
|
+
return role === 'admin' ? 'grant_access' : 'deny_access'
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Usage in a flow:
|
|
279
|
+
const checkAdmin = new CheckAdminNode()
|
|
280
|
+
checkAdmin.next(new AdminPanelNode(), 'grant_access')
|
|
281
|
+
checkAdmin.next(new GuestPageNode(), 'deny_access')
|
|
282
|
+
```
|
|
185
283
|
|
|
186
284
|
### Flow
|
|
187
285
|
|
|
188
|
-
A `Flow` is a special type of `Node` that orchestrates a sequence of other nodes. It contains the logic for traversing its own graph of operations, making it a powerful, self-contained unit of work.
|
|
286
|
+
A `Flow` is a special type of `Node` that orchestrates a sequence of other nodes. It is also generic (`Flow<PrepRes, ExecRes, TParams>`) and can be configured with its own parameters and middleware. It contains the logic for traversing its own graph of operations, making it a powerful, self-contained unit of work.
|
|
189
287
|
|
|
190
288
|
### Executor
|
|
191
289
|
|
|
@@ -216,16 +314,16 @@ To simplify the creation of common and complex patterns, the framework provides
|
|
|
216
314
|
> [!TIP]
|
|
217
315
|
> For clear, focused examples of specific, individual features (like retries, middleware, cancellation, and composition), the unit tests are an excellent resource.
|
|
218
316
|
|
|
219
|
-
- Core workflow tests: [`src/workflow.test.ts`](
|
|
220
|
-
-
|
|
221
|
-
- Graph builder tests: [`src/builder/graph.test.ts`](
|
|
317
|
+
- Core workflow tests: [`src/workflow.test.ts`](https://github.com/gorango/flowcraft/tree/main/workflow.test.ts)
|
|
318
|
+
- Patterns tests: [`src/builder/patterns.test.ts`](https://github.com/gorango/flowcraft/tree/main/builder/patterns.test.ts)
|
|
319
|
+
- Graph builder tests: [`src/builder/graph.test.ts`](https://github.com/gorango/flowcraft/tree/main/builder/graph.test.ts)
|
|
222
320
|
|
|
223
321
|
## API Reference
|
|
224
322
|
|
|
225
323
|
### Core Classes
|
|
226
324
|
|
|
227
|
-
- `Node`: The base class for a unit of work
|
|
228
|
-
- `Flow`: Orchestrates a sequence of nodes
|
|
325
|
+
- `Node`: The base class for a unit of work: `Node<PrepRes, ExecRes, PostRes, TParams>`. It has built-in retry logic and a fluent API (`.map`, `.filter`, etc.).
|
|
326
|
+
- `Flow`: Orchestrates a sequence of nodes: `Flow<PrepRes, ExecRes, TParams>`. Supports middleware via `.use()`.
|
|
229
327
|
- `InMemoryExecutor`: The default `IExecutor` implementation for running flows in-memory.
|
|
230
328
|
- `TypedContext`: The standard `Map`-based implementation for the `Context` interface.
|
|
231
329
|
- `ConsoleLogger`, `NullLogger`: Pre-built logger implementations.
|
|
@@ -234,16 +332,28 @@ To simplify the creation of common and complex patterns, the framework provides
|
|
|
234
332
|
|
|
235
333
|
A collection of functions for creating nodes and pipelines in a more functional style.
|
|
236
334
|
|
|
237
|
-
- `mapNode`: Creates a `Node` from a simple, pure function.
|
|
238
|
-
- `contextNode`: Creates a `Node` from a function that requires access to the `Context`.
|
|
335
|
+
- `mapNode`: Creates a `Node` from a simple, pure function: `mapNode<TIn extends Params, TOut>(fn)`. The function receives the node's `params` as its input.
|
|
336
|
+
- `contextNode`: Creates a `Node` from a function that requires access to the `Context`: `contextNode<TIn extends Params, TOut>(fn)`. The function receives the context and the node's `params`.
|
|
337
|
+
- `transformNode`: Creates a `Node` that applies one or more `ContextTransform` functions (often created with a `lens`). This is ideal for declarative state management.
|
|
239
338
|
- `pipeline`: A functional alias for creating a linear sequence of nodes.
|
|
339
|
+
- `mapCollection`: Creates a `Flow` that applies a function to each item in a collection in parallel, returning an array of the results.
|
|
340
|
+
- `filterCollection`: Creates a `Flow` that filters a collection in parallel based on a predicate function.
|
|
341
|
+
- `reduceCollection`: Creates a `Flow` that reduces a collection to a single value by applying a reducer function sequentially.
|
|
240
342
|
|
|
241
343
|
### Builder Classes
|
|
242
344
|
|
|
243
345
|
- `SequenceFlow`: A `Flow` that creates a linear flow from a sequence of nodes.
|
|
244
346
|
- `BatchFlow`: A `Flow` that processes a collection of items sequentially.
|
|
245
347
|
- `ParallelBatchFlow`: A `Flow` that processes a collection of items in parallel.
|
|
246
|
-
- `GraphBuilder`: Constructs a `Flow` from a declarative graph definition.
|
|
348
|
+
- `GraphBuilder`: Constructs a `Flow` from a declarative graph definition. Its `.build()` method returns a `BuildResult` object containing:
|
|
349
|
+
- `flow`: The executable `Flow` instance.
|
|
350
|
+
- `nodeMap`: A `Map` of all instantiated nodes, keyed by their ID.
|
|
351
|
+
- `predecessorCountMap`: A `Map` of node IDs to their total number of incoming connections.
|
|
352
|
+
- `predecessorIdMap`: A `Map` of node IDs to an array of their direct predecessor IDs, useful for advanced executors.
|
|
353
|
+
|
|
354
|
+
## Documentation
|
|
355
|
+
|
|
356
|
+
The complete [Flowcraft documentation](https://flowcraft-docs.netlify.app) is available on the website.
|
|
247
357
|
|
|
248
358
|
---
|
|
249
|
-
Licensed under the [MIT License](
|
|
359
|
+
Licensed under the [MIT License](https://github.com/gorango/flowcraft/tree/main/LICENSE).
|