flowneer 0.7.0 → 0.7.1
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 +4 -0
- package/dist/{FlowBuilder-C3B91Fzo.d.ts → FlowBuilder-DJkzGH5l.d.ts} +170 -56
- package/dist/index.d.ts +1 -1
- package/dist/index.js +369 -246
- package/dist/{patterns-C3oKxgYZ.d.ts → patterns-CCtG27Gv.d.ts} +1 -1
- package/dist/plugins/agent/index.d.ts +2 -2
- package/dist/plugins/agent/index.js +373 -249
- package/dist/plugins/dev/index.d.ts +4 -1
- package/dist/plugins/eval/index.d.ts +1 -1
- package/dist/plugins/graph/index.d.ts +1 -1
- package/dist/plugins/index.d.ts +2 -2
- package/dist/plugins/index.js +374 -249
- package/dist/plugins/llm/index.d.ts +1 -1
- package/dist/plugins/memory/index.d.ts +1 -1
- package/dist/plugins/messaging/index.d.ts +1 -1
- package/dist/plugins/observability/index.d.ts +1 -1
- package/dist/plugins/output/index.d.ts +1 -1
- package/dist/plugins/persistence/index.d.ts +1 -1
- package/dist/plugins/resilience/index.d.ts +5 -6
- package/dist/plugins/resilience/index.js +24 -14
- package/dist/plugins/telemetry/index.d.ts +1 -1
- package/dist/plugins/tools/index.d.ts +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.js +370 -246
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -22,6 +22,10 @@ A tiny, zero-dependency fluent flow builder for TypeScript. Chain steps, branch
|
|
|
22
22
|
bun add flowneer
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
## For LLM Agents
|
|
26
|
+
[llms.txt](https://fanna1119.github.io/flowneer/llms.txt)
|
|
27
|
+
[llms-full.txt](https://fanna1119.github.io/flowneer/llms-full.txt)
|
|
28
|
+
|
|
25
29
|
## Quick start
|
|
26
30
|
|
|
27
31
|
```typescript
|
|
@@ -53,6 +53,8 @@ interface NodeOptions<S = any, P extends Record<string, unknown> = Record<string
|
|
|
53
53
|
retries?: NumberOrFn<S, P>;
|
|
54
54
|
delaySec?: NumberOrFn<S, P>;
|
|
55
55
|
timeoutMs?: NumberOrFn<S, P>;
|
|
56
|
+
/** Human-readable label for this step, shown in error messages and hook metadata. */
|
|
57
|
+
label?: string;
|
|
56
58
|
}
|
|
57
59
|
interface RunOptions {
|
|
58
60
|
signal?: AbortSignal;
|
|
@@ -95,6 +97,31 @@ interface FlowHooks<S = any, P extends Record<string, unknown> = Record<string,
|
|
|
95
97
|
* ```
|
|
96
98
|
*/
|
|
97
99
|
type FlowneerPlugin = Record<string, (this: FlowBuilder<any, any>, ...args: any[]) => any>;
|
|
100
|
+
/**
|
|
101
|
+
* An instance-scoped plugin. Called immediately when passed to `flow.use()`;
|
|
102
|
+
* registers hooks and/or performs setup on the specific `FlowBuilder` instance.
|
|
103
|
+
*
|
|
104
|
+
* Write plugins as factories so settings are captured in a closure:
|
|
105
|
+
* ```ts
|
|
106
|
+
* function withTiming(): InstancePlugin<any> {
|
|
107
|
+
* return (flow) => {
|
|
108
|
+
* const starts = new Map<number, number>();
|
|
109
|
+
* flow.addHooks({
|
|
110
|
+
* beforeStep: (meta) => { starts.set(meta.index, Date.now()); },
|
|
111
|
+
* afterStep: (meta, shared) => { shared.__timings ??= {}; shared.__timings[meta.index] = Date.now() - starts.get(meta.index)!; },
|
|
112
|
+
* });
|
|
113
|
+
* };
|
|
114
|
+
* }
|
|
115
|
+
*
|
|
116
|
+
* const flow = new FlowBuilder<MyState>()
|
|
117
|
+
* .with([withTiming(), withRateLimit({ rps: 10 })])
|
|
118
|
+
* .then(myStep);
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* Order matters: plugins are applied left-to-right, so earlier plugins wrap
|
|
122
|
+
* later ones (the first plugin's `wrapStep` runs outermost).
|
|
123
|
+
*/
|
|
124
|
+
type InstancePlugin<S = any, P extends Record<string, unknown> = Record<string, unknown>> = (flow: FlowBuilder<S, P>) => void;
|
|
98
125
|
|
|
99
126
|
interface FnStep<S, P extends Record<string, unknown>> {
|
|
100
127
|
type: "fn";
|
|
@@ -102,6 +129,7 @@ interface FnStep<S, P extends Record<string, unknown>> {
|
|
|
102
129
|
retries: NumberOrFn<S, P>;
|
|
103
130
|
delaySec: NumberOrFn<S, P>;
|
|
104
131
|
timeoutMs: NumberOrFn<S, P>;
|
|
132
|
+
label?: string;
|
|
105
133
|
}
|
|
106
134
|
interface BranchStep<S, P extends Record<string, unknown>> {
|
|
107
135
|
type: "branch";
|
|
@@ -110,17 +138,20 @@ interface BranchStep<S, P extends Record<string, unknown>> {
|
|
|
110
138
|
retries: NumberOrFn<S, P>;
|
|
111
139
|
delaySec: NumberOrFn<S, P>;
|
|
112
140
|
timeoutMs: NumberOrFn<S, P>;
|
|
141
|
+
label?: string;
|
|
113
142
|
}
|
|
114
143
|
interface LoopStep<S, P extends Record<string, unknown>> {
|
|
115
144
|
type: "loop";
|
|
116
145
|
condition: (shared: S, params: P) => Promise<boolean> | boolean;
|
|
117
|
-
body:
|
|
146
|
+
body: CoreFlowBuilder<S, P>;
|
|
147
|
+
label?: string;
|
|
118
148
|
}
|
|
119
149
|
interface BatchStep<S, P extends Record<string, unknown>> {
|
|
120
150
|
type: "batch";
|
|
121
151
|
itemsExtractor: (shared: S, params: P) => Promise<any[]> | any[];
|
|
122
|
-
processor:
|
|
152
|
+
processor: CoreFlowBuilder<S, P>;
|
|
123
153
|
key: string;
|
|
154
|
+
label?: string;
|
|
124
155
|
}
|
|
125
156
|
interface ParallelStep<S, P extends Record<string, unknown>> {
|
|
126
157
|
type: "parallel";
|
|
@@ -129,13 +160,119 @@ interface ParallelStep<S, P extends Record<string, unknown>> {
|
|
|
129
160
|
delaySec: NumberOrFn<S, P>;
|
|
130
161
|
timeoutMs: NumberOrFn<S, P>;
|
|
131
162
|
reducer?: (shared: S, drafts: S[]) => void;
|
|
163
|
+
label?: string;
|
|
132
164
|
}
|
|
133
165
|
interface AnchorStep {
|
|
134
166
|
type: "anchor";
|
|
135
167
|
name: string;
|
|
168
|
+
/** Maximum number of times a goto may jump to this anchor per run. */
|
|
169
|
+
maxVisits?: number;
|
|
136
170
|
}
|
|
137
171
|
type Step<S, P extends Record<string, unknown>> = FnStep<S, P> | BranchStep<S, P> | LoopStep<S, P> | BatchStep<S, P> | ParallelStep<S, P> | AnchorStep;
|
|
138
172
|
|
|
173
|
+
type ResolvedHooks<S, P extends Record<string, unknown>> = {
|
|
174
|
+
beforeFlow: NonNullable<FlowHooks<S, P>["beforeFlow"]>[];
|
|
175
|
+
beforeStep: NonNullable<FlowHooks<S, P>["beforeStep"]>[];
|
|
176
|
+
wrapStep: NonNullable<FlowHooks<S, P>["wrapStep"]>[];
|
|
177
|
+
afterStep: NonNullable<FlowHooks<S, P>["afterStep"]>[];
|
|
178
|
+
wrapParallelFn: NonNullable<FlowHooks<S, P>["wrapParallelFn"]>[];
|
|
179
|
+
onError: NonNullable<FlowHooks<S, P>["onError"]>[];
|
|
180
|
+
afterFlow: NonNullable<FlowHooks<S, P>["afterFlow"]>[];
|
|
181
|
+
};
|
|
182
|
+
/**
|
|
183
|
+
* Runtime context passed to every registered step handler.
|
|
184
|
+
* Full access to the builder so handlers can run sub-flows etc.
|
|
185
|
+
*/
|
|
186
|
+
interface StepContext<S, P extends Record<string, unknown> = Record<string, unknown>> {
|
|
187
|
+
shared: S;
|
|
188
|
+
params: P;
|
|
189
|
+
signal?: AbortSignal;
|
|
190
|
+
hooks: ResolvedHooks<S, P>;
|
|
191
|
+
meta: StepMeta;
|
|
192
|
+
builder: CoreFlowBuilder<S, P>;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Signature for step type execution handlers registered via
|
|
196
|
+
* `CoreFlowBuilder.registerStepType()`.
|
|
197
|
+
*
|
|
198
|
+
* Return a goto anchor name (without `#`) to jump, or `undefined` to continue.
|
|
199
|
+
*/
|
|
200
|
+
type StepHandler = (step: any, ctx: StepContext<any, any>) => Promise<string | undefined>;
|
|
201
|
+
/**
|
|
202
|
+
* Minimal orchestration engine. Knows nothing about specific step types —
|
|
203
|
+
* those are registered as plugins via `CoreFlowBuilder.registerStepType()`.
|
|
204
|
+
*
|
|
205
|
+
* Use this as a base when you want a completely fresh, zero-assumption builder.
|
|
206
|
+
* The exported `FlowBuilder` extends this with all primitive step types
|
|
207
|
+
* (fn, branch, loop, batch, parallel, anchor) pre-registered.
|
|
208
|
+
*/
|
|
209
|
+
declare class CoreFlowBuilder<S = any, P extends Record<string, unknown> = Record<string, unknown>> {
|
|
210
|
+
/** @internal Ordered list of step descriptors. */
|
|
211
|
+
steps: Step<S, P>[];
|
|
212
|
+
/** @internal Cached anchor-name → index map; null when stale. */
|
|
213
|
+
protected _anchorMap: Map<string, number> | null;
|
|
214
|
+
private _hooksList;
|
|
215
|
+
private _hooksCache;
|
|
216
|
+
private static _stepHandlers;
|
|
217
|
+
/**
|
|
218
|
+
* Register a handler for a custom step type.
|
|
219
|
+
* Called once at module load time from each step plugin.
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* CoreFlowBuilder.registerStepType("myStep", async (step, ctx) => {
|
|
223
|
+
* await doWork(ctx.shared);
|
|
224
|
+
* return undefined;
|
|
225
|
+
* });
|
|
226
|
+
*/
|
|
227
|
+
static registerStepType(type: string, handler: StepHandler): void;
|
|
228
|
+
private _hooks;
|
|
229
|
+
/**
|
|
230
|
+
* Register lifecycle hooks (called by plugin methods, not by consumers).
|
|
231
|
+
* Returns a dispose function that removes these hooks when called.
|
|
232
|
+
*/
|
|
233
|
+
protected _setHooks(hooks: Partial<FlowHooks<S, P>>): () => void;
|
|
234
|
+
/**
|
|
235
|
+
* Register a plugin — copies its methods onto `FlowBuilder.prototype`.
|
|
236
|
+
*/
|
|
237
|
+
static use(plugin: FlowneerPlugin): void;
|
|
238
|
+
/**
|
|
239
|
+
* Apply one or more instance-scoped plugins to this builder.
|
|
240
|
+
* Each plugin is called immediately; plugins are applied in array order
|
|
241
|
+
* so the first plugin's hooks wrap the later ones.
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* const flow = new FlowBuilder<MyState>()
|
|
245
|
+
* .with([withTiming(), withRateLimit({ rps: 10 })])
|
|
246
|
+
* .then(myStep);
|
|
247
|
+
*/
|
|
248
|
+
with(plugins: InstancePlugin<S, P> | Array<InstancePlugin<S, P>>): this;
|
|
249
|
+
/**
|
|
250
|
+
* Register lifecycle hooks directly on this instance.
|
|
251
|
+
* Returns a dispose function that removes these hooks when called.
|
|
252
|
+
*/
|
|
253
|
+
addHooks(hooks: Partial<FlowHooks<S, P>>): () => void;
|
|
254
|
+
/** Execute the flow. */
|
|
255
|
+
run(shared: S, params?: P, options?: RunOptions): Promise<void>;
|
|
256
|
+
/**
|
|
257
|
+
* Execute the flow and yield `StreamEvent`s as an async generator.
|
|
258
|
+
*/
|
|
259
|
+
stream(shared: S, params?: P, options?: RunOptions): AsyncGenerator<StreamEvent<S>>;
|
|
260
|
+
/** @internal Core execution loop, bypasses beforeFlow/afterFlow hooks. */
|
|
261
|
+
_execute(shared: S, params: P, signal?: AbortSignal): Promise<void>;
|
|
262
|
+
private _runStep;
|
|
263
|
+
/** @internal Run a sub-flow, wrapping errors with context. */
|
|
264
|
+
_runSub(label: string, fn: () => Promise<void>): Promise<void>;
|
|
265
|
+
/** @internal Resolve NodeOptions into their stored defaults. */
|
|
266
|
+
_resolveOptions(options?: NodeOptions<S, P>): {
|
|
267
|
+
retries: NumberOrFn<S, P>;
|
|
268
|
+
delaySec: NumberOrFn<S, P>;
|
|
269
|
+
timeoutMs: NumberOrFn<S, P>;
|
|
270
|
+
label: string | undefined;
|
|
271
|
+
};
|
|
272
|
+
/** @internal Push a step and invalidate the anchor-map cache. */
|
|
273
|
+
protected _pushStep(step: Step<S, P>): void;
|
|
274
|
+
}
|
|
275
|
+
|
|
139
276
|
/**
|
|
140
277
|
* Fluent builder for composable flows.
|
|
141
278
|
*
|
|
@@ -143,15 +280,18 @@ type Step<S, P extends Record<string, unknown>> = FnStep<S, P> | BranchStep<S, P
|
|
|
143
280
|
*
|
|
144
281
|
* **Shared-state safety**: all steps operate on the same shared object.
|
|
145
282
|
* Mutate it directly; avoid spreading/replacing the entire object.
|
|
283
|
+
*
|
|
284
|
+
* Built on top of {@link CoreFlowBuilder} which exposes the raw engine for
|
|
285
|
+
* advanced use cases (custom step types, zero-assumption base class, etc.).
|
|
146
286
|
*/
|
|
147
|
-
declare class FlowBuilder<S = any, P extends Record<string, unknown> = Record<string, unknown>> {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
287
|
+
declare class FlowBuilder<S = any, P extends Record<string, unknown> = Record<string, unknown>> extends CoreFlowBuilder<S, P> {
|
|
288
|
+
/**
|
|
289
|
+
* Register a plugin — copies its methods onto `FlowBuilder.prototype`.
|
|
290
|
+
*
|
|
291
|
+
* Plugins should also call `FlowBuilder.use()` (not just `CoreFlowBuilder.use()`)
|
|
292
|
+
* so TypeScript module-augmentation on `interface FlowBuilder` resolves
|
|
293
|
+
* correctly and the method appears on `FlowBuilder` instances specifically.
|
|
294
|
+
*/
|
|
155
295
|
static use(plugin: FlowneerPlugin): void;
|
|
156
296
|
/** Set the first step, resetting any prior chain. */
|
|
157
297
|
startWith(fn: NodeFn<S, P>, options?: NodeOptions<S, P>): this;
|
|
@@ -161,19 +301,12 @@ declare class FlowBuilder<S = any, P extends Record<string, unknown> = Record<st
|
|
|
161
301
|
* Splice all steps from a `Fragment` into this flow at the current position.
|
|
162
302
|
*
|
|
163
303
|
* Fragments are reusable partial flows created with the `fragment()` factory.
|
|
164
|
-
* Steps are copied by reference (same semantics as `loop` / `batch` inners).
|
|
165
304
|
*
|
|
166
305
|
* @example
|
|
167
306
|
* ```ts
|
|
168
|
-
* const enrich = fragment<S>()
|
|
169
|
-
* .then(fetchUser)
|
|
170
|
-
* .then(enrichProfile);
|
|
307
|
+
* const enrich = fragment<S>().then(fetchUser).then(enrichProfile);
|
|
171
308
|
*
|
|
172
|
-
* new FlowBuilder<S>()
|
|
173
|
-
* .then(init)
|
|
174
|
-
* .add(enrich)
|
|
175
|
-
* .then(finalize)
|
|
176
|
-
* .run(shared);
|
|
309
|
+
* new FlowBuilder<S>().then(init).add(enrich).then(finalize).run(shared);
|
|
177
310
|
* ```
|
|
178
311
|
*/
|
|
179
312
|
add(frag: FlowBuilder<S, P>): this;
|
|
@@ -186,25 +319,19 @@ declare class FlowBuilder<S = any, P extends Record<string, unknown> = Record<st
|
|
|
186
319
|
* Append a looping step.
|
|
187
320
|
* Repeatedly runs `body` while `condition` returns true.
|
|
188
321
|
*/
|
|
189
|
-
loop(condition: (shared: S, params: P) => Promise<boolean> | boolean, body: (b: FlowBuilder<S, P>) => void
|
|
322
|
+
loop(condition: (shared: S, params: P) => Promise<boolean> | boolean, body: (b: FlowBuilder<S, P>) => void, options?: {
|
|
323
|
+
label?: string;
|
|
324
|
+
}): this;
|
|
190
325
|
/**
|
|
191
326
|
* Append a batch step.
|
|
192
327
|
* Runs `processor` once per item extracted by `items`, setting
|
|
193
328
|
* `shared[key]` each time (defaults to `"__batchItem"`).
|
|
194
329
|
*
|
|
195
|
-
* Use a unique `key` when nesting batches so each level has its own
|
|
196
|
-
* namespace:
|
|
197
|
-
* ```ts
|
|
198
|
-
* .batch(s => s.users, b => b
|
|
199
|
-
* .startWith(s => { console.log(s.__batch_user); })
|
|
200
|
-
* .batch(s => s.__batch_user.posts, p => p
|
|
201
|
-
* .startWith(s => { console.log(s.__batch_post); })
|
|
202
|
-
* , { key: '__batch_post' })
|
|
203
|
-
* , { key: '__batch_user' })
|
|
204
|
-
* ```
|
|
330
|
+
* Use a unique `key` when nesting batches so each level has its own namespace.
|
|
205
331
|
*/
|
|
206
332
|
batch(items: (shared: S, params: P) => Promise<any[]> | any[], processor: (b: FlowBuilder<S, P>) => void, options?: {
|
|
207
333
|
key?: string;
|
|
334
|
+
label?: string;
|
|
208
335
|
}): this;
|
|
209
336
|
/**
|
|
210
337
|
* Append a parallel step.
|
|
@@ -218,36 +345,23 @@ declare class FlowBuilder<S = any, P extends Record<string, unknown> = Record<st
|
|
|
218
345
|
/**
|
|
219
346
|
* Insert a named anchor. Anchors are no-op markers that can be jumped to
|
|
220
347
|
* from any `NodeFn` by returning `"#anchorName"`.
|
|
221
|
-
*/
|
|
222
|
-
anchor(name: string): this;
|
|
223
|
-
/** Execute the flow. */
|
|
224
|
-
run(shared: S, params?: P, options?: RunOptions): Promise<void>;
|
|
225
|
-
/**
|
|
226
|
-
* Execute the flow and yield `StreamEvent`s as an async generator.
|
|
227
348
|
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
349
|
+
* @param name - Anchor identifier, referenced as `"#name"` in goto returns.
|
|
350
|
+
* @param maxVisits - Optional cycle guard: throws after this many gotos to
|
|
351
|
+
* this anchor per `run()`. Replaces the need for a separate `withCycles`
|
|
352
|
+
* plugin call.
|
|
230
353
|
*
|
|
231
354
|
* @example
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
* Apply timeout and `wrapStep` middleware around a single step, then
|
|
240
|
-
* delegate to `_dispatchStep`. Returns an anchor target if the step
|
|
241
|
-
* issued a goto, otherwise `undefined`.
|
|
242
|
-
*/
|
|
243
|
-
private _runStep;
|
|
244
|
-
/**
|
|
245
|
-
* Pure step dispatch — no timeout, no `wrapStep`. Returns goto target if any.
|
|
355
|
+
* ```ts
|
|
356
|
+
* flow
|
|
357
|
+
* .anchor("refine", 5) // allow up to 5 refinement iterations
|
|
358
|
+
* .then(generateDraft)
|
|
359
|
+
* .then(s => s.score < 0.9 ? "#refine" : undefined)
|
|
360
|
+
* .then(publish);
|
|
361
|
+
* ```
|
|
246
362
|
*/
|
|
247
|
-
|
|
248
|
-
private _runParallel;
|
|
363
|
+
anchor(name: string, maxVisits?: number): this;
|
|
249
364
|
private _addFn;
|
|
250
|
-
private _runSub;
|
|
251
365
|
}
|
|
252
366
|
|
|
253
|
-
export { type AnchorStep as A, type BatchStep as B, FlowBuilder as F, type LoopStep as L, type NodeFn as N, type ParallelStep as P, type
|
|
367
|
+
export { type AnchorStep as A, type BatchStep as B, CoreFlowBuilder as C, FlowBuilder as F, type InstancePlugin as I, type LoopStep as L, type NodeFn as N, type ParallelStep as P, type ResolvedHooks as R, type StepMeta as S, type Validator as V, type FlowneerPlugin as a, type NodeOptions as b, type FlowHooks as c, type BranchStep as d, type FnStep as e, type NumberOrFn as f, type RunOptions as g, type Step as h, type StepContext as i, type StepHandler as j, type StreamEvent as k };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { F as FlowBuilder, c as FlowHooks, a as FlowneerPlugin, N as NodeFn, b as NodeOptions, f as NumberOrFn,
|
|
1
|
+
export { F as FlowBuilder, c as FlowHooks, a as FlowneerPlugin, N as NodeFn, b as NodeOptions, f as NumberOrFn, g as RunOptions, S as StepMeta, k as StreamEvent, V as Validator } from './FlowBuilder-DJkzGH5l.js';
|
|
2
2
|
export { FlowError, Fragment, InterruptError, fragment } from './src/index.js';
|