pipeai 0.2.0 → 0.3.0
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 +28 -4
- package/dist/index.cjs +84 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -12
- package/dist/index.d.ts +40 -12
- package/dist/index.js +84 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -5,11 +5,12 @@ declare const TOOL_PROVIDER_BRAND: unique symbol;
|
|
|
5
5
|
type ToolExecuteOptions = ToolExecutionOptions & {
|
|
6
6
|
writer?: UIMessageStreamWriter;
|
|
7
7
|
};
|
|
8
|
+
type ToolProviderOptions = NonNullable<Tool["providerOptions"]>;
|
|
8
9
|
type ToolProviderConfig<TContext, TInput, TOutput> = {
|
|
9
10
|
description?: string;
|
|
10
11
|
input: FlexibleSchema<TInput>;
|
|
11
|
-
|
|
12
|
-
providerOptions?:
|
|
12
|
+
outputSchema?: FlexibleSchema<TOutput>;
|
|
13
|
+
providerOptions?: ToolProviderOptions;
|
|
13
14
|
execute: (input: TInput, ctx: Readonly<TContext>, options: ToolExecuteOptions) => Promise<TOutput>;
|
|
14
15
|
};
|
|
15
16
|
interface IToolProvider<TContext> {
|
|
@@ -85,13 +86,13 @@ declare class Agent<TContext, TInput = void, TOutput = void> {
|
|
|
85
86
|
private readonly _onStepFinish;
|
|
86
87
|
private readonly _onFinish;
|
|
87
88
|
constructor(config: AgentConfig<TContext, TInput, TOutput>);
|
|
88
|
-
generate(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<GenerateTextResult
|
|
89
|
-
stream(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<StreamTextResult
|
|
89
|
+
generate(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<GenerateTextResult<ToolSet, OutputType<TOutput>>>;
|
|
90
|
+
stream(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<StreamTextResult<ToolSet, OutputType<TOutput>>>;
|
|
90
91
|
asTool(ctx: TContext, options?: {
|
|
91
|
-
mapOutput?: (result: GenerateTextResult) => MaybePromise<TOutput>;
|
|
92
|
+
mapOutput?: (result: GenerateTextResult<ToolSet, OutputType<TOutput>>) => MaybePromise<TOutput>;
|
|
92
93
|
}): Tool;
|
|
93
94
|
asToolProvider(options?: {
|
|
94
|
-
mapOutput?: (result: GenerateTextResult) => MaybePromise<TOutput>;
|
|
95
|
+
mapOutput?: (result: GenerateTextResult<ToolSet, OutputType<TOutput>>) => MaybePromise<TOutput>;
|
|
95
96
|
}): IToolProvider<TContext>;
|
|
96
97
|
private createToolInstance;
|
|
97
98
|
private buildCallOptions;
|
|
@@ -122,27 +123,27 @@ declare class WorkflowSuspended extends Error {
|
|
|
122
123
|
}
|
|
123
124
|
interface AgentStepHooks<TContext, TOutput, TNextOutput> {
|
|
124
125
|
mapGenerateResult?: (params: {
|
|
125
|
-
result: GenerateTextResult
|
|
126
|
+
result: GenerateTextResult<ToolSet, OutputType<TNextOutput>>;
|
|
126
127
|
ctx: Readonly<TContext>;
|
|
127
128
|
input: TOutput;
|
|
128
129
|
}) => MaybePromise<TNextOutput>;
|
|
129
130
|
mapStreamResult?: (params: {
|
|
130
|
-
result: StreamTextResult
|
|
131
|
+
result: StreamTextResult<ToolSet, OutputType<TNextOutput>>;
|
|
131
132
|
ctx: Readonly<TContext>;
|
|
132
133
|
input: TOutput;
|
|
133
134
|
}) => MaybePromise<TNextOutput>;
|
|
134
135
|
onGenerateResult?: (params: {
|
|
135
|
-
result: GenerateTextResult
|
|
136
|
+
result: GenerateTextResult<ToolSet, OutputType<TNextOutput>>;
|
|
136
137
|
ctx: Readonly<TContext>;
|
|
137
138
|
input: TOutput;
|
|
138
139
|
}) => MaybePromise<void>;
|
|
139
140
|
onStreamResult?: (params: {
|
|
140
|
-
result: StreamTextResult
|
|
141
|
+
result: StreamTextResult<ToolSet, OutputType<TNextOutput>>;
|
|
141
142
|
ctx: Readonly<TContext>;
|
|
142
143
|
input: TOutput;
|
|
143
144
|
}) => MaybePromise<void>;
|
|
144
145
|
handleStream?: (params: {
|
|
145
|
-
result: StreamTextResult
|
|
146
|
+
result: StreamTextResult<ToolSet, OutputType<TNextOutput>>;
|
|
146
147
|
writer: UIMessageStreamWriter;
|
|
147
148
|
ctx: Readonly<TContext>;
|
|
148
149
|
}) => MaybePromise<void>;
|
|
@@ -253,6 +254,12 @@ declare class ResumedWorkflow<TContext, TResponse = unknown, TOutput = void> ext
|
|
|
253
254
|
stream(ctx: TContext, ...args: TResponse extends void ? [response?: TResponse, options?: WorkflowStreamOptions] : [response: TResponse, options?: WorkflowStreamOptions]): WorkflowStreamResult<TOutput>;
|
|
254
255
|
}
|
|
255
256
|
declare class Workflow<TContext, TInput = void, TOutput = void, TGates extends Record<string, unknown> = {}> extends SealedWorkflow<TContext, TInput, TOutput, TGates> {
|
|
257
|
+
/**
|
|
258
|
+
* Sentinel value for `foreach`'s `onError` handler. Returning `Workflow.SKIP`
|
|
259
|
+
* from `onError` omits the failed item's index from the output array,
|
|
260
|
+
* shortening it relative to the input array.
|
|
261
|
+
*/
|
|
262
|
+
static readonly SKIP: unique symbol;
|
|
256
263
|
private constructor();
|
|
257
264
|
static create<TContext, TInput = void>(options?: {
|
|
258
265
|
id?: string;
|
|
@@ -283,8 +290,29 @@ declare class Workflow<TContext, TInput = void, TOutput = void, TGates extends R
|
|
|
283
290
|
branch<TKeys extends string, TNextOutput>(config: BranchSelect<TContext, TOutput, TKeys, TNextOutput>): Workflow<TContext, TInput, TNextOutput, TGates>;
|
|
284
291
|
private branchPredicate;
|
|
285
292
|
private branchSelect;
|
|
293
|
+
/**
|
|
294
|
+
* Map each item of an array through an agent or sub-workflow.
|
|
295
|
+
*
|
|
296
|
+
* @param target Agent or `SealedWorkflow` invoked once per item.
|
|
297
|
+
* @param options.concurrency Max items in flight at any moment (default 1).
|
|
298
|
+
* Backed by a semaphore: as soon as one item completes, the next launches —
|
|
299
|
+
* no lockstep batching.
|
|
300
|
+
* @param options.onError Per-iteration error handler. When provided, a single
|
|
301
|
+
* item's failure no longer aborts the foreach. Return a `TNextOutput` value
|
|
302
|
+
* to substitute for the failed item, return `Workflow.SKIP` to omit the
|
|
303
|
+
* index (shortening the output array), or throw / return a rejected promise
|
|
304
|
+
* to abort the foreach step (the thrown error is caught by any downstream
|
|
305
|
+
* `.catch()`). When omitted, the existing fail-fast behavior is preserved.
|
|
306
|
+
* `onError` is invoked sequentially in index order after all items settle.
|
|
307
|
+
*/
|
|
286
308
|
foreach<TNextOutput>(target: Agent<TContext, ElementOf<TOutput>, TNextOutput> | SealedWorkflow<TContext, ElementOf<TOutput>, TNextOutput>, options?: {
|
|
287
309
|
concurrency?: number;
|
|
310
|
+
onError?: (params: {
|
|
311
|
+
error: unknown;
|
|
312
|
+
item: ElementOf<TOutput>;
|
|
313
|
+
index: number;
|
|
314
|
+
ctx: Readonly<TContext>;
|
|
315
|
+
}) => MaybePromise<TNextOutput | typeof Workflow.SKIP>;
|
|
288
316
|
}): Workflow<TContext, TInput, TNextOutput[], TGates>;
|
|
289
317
|
repeat(target: Agent<TContext, TOutput, TOutput> | SealedWorkflow<TContext, TOutput, TOutput>, options: RepeatOptions<TContext, TOutput>): Workflow<TContext, TInput, TOutput, TGates>;
|
|
290
318
|
catch(id: string, fn: (params: {
|
|
@@ -298,4 +326,4 @@ declare class Workflow<TContext, TInput = void, TOutput = void, TGates extends R
|
|
|
298
326
|
}) => MaybePromise<void>): SealedWorkflow<TContext, TInput, TOutput, TGates>;
|
|
299
327
|
}
|
|
300
328
|
|
|
301
|
-
export { Agent, type AgentConfig, type AgentStepHooks, type BranchCase, type BranchSelect, type GenerateTextResult, type IToolProvider, type MaybePromise, type RepeatOptions, type Resolvable, ResumedWorkflow, SealedWorkflow, type StepOptions, type StreamTextResult, type ToolExecuteOptions, type ToolProviderConfig, Workflow, WorkflowBranchError, WorkflowLoopError, type WorkflowResult, type WorkflowSnapshot, type WorkflowStreamOptions, type WorkflowStreamResult, WorkflowSuspended, defineTool };
|
|
329
|
+
export { Agent, type AgentConfig, type AgentStepHooks, type BranchCase, type BranchSelect, type GenerateTextResult, type IToolProvider, type MaybePromise, type OutputType, type RepeatOptions, type Resolvable, ResumedWorkflow, SealedWorkflow, type StepOptions, type StreamTextResult, type ToolExecuteOptions, type ToolProviderConfig, Workflow, WorkflowBranchError, WorkflowLoopError, type WorkflowResult, type WorkflowSnapshot, type WorkflowStreamOptions, type WorkflowStreamResult, WorkflowSuspended, defineTool };
|
package/dist/index.d.ts
CHANGED
|
@@ -5,11 +5,12 @@ declare const TOOL_PROVIDER_BRAND: unique symbol;
|
|
|
5
5
|
type ToolExecuteOptions = ToolExecutionOptions & {
|
|
6
6
|
writer?: UIMessageStreamWriter;
|
|
7
7
|
};
|
|
8
|
+
type ToolProviderOptions = NonNullable<Tool["providerOptions"]>;
|
|
8
9
|
type ToolProviderConfig<TContext, TInput, TOutput> = {
|
|
9
10
|
description?: string;
|
|
10
11
|
input: FlexibleSchema<TInput>;
|
|
11
|
-
|
|
12
|
-
providerOptions?:
|
|
12
|
+
outputSchema?: FlexibleSchema<TOutput>;
|
|
13
|
+
providerOptions?: ToolProviderOptions;
|
|
13
14
|
execute: (input: TInput, ctx: Readonly<TContext>, options: ToolExecuteOptions) => Promise<TOutput>;
|
|
14
15
|
};
|
|
15
16
|
interface IToolProvider<TContext> {
|
|
@@ -85,13 +86,13 @@ declare class Agent<TContext, TInput = void, TOutput = void> {
|
|
|
85
86
|
private readonly _onStepFinish;
|
|
86
87
|
private readonly _onFinish;
|
|
87
88
|
constructor(config: AgentConfig<TContext, TInput, TOutput>);
|
|
88
|
-
generate(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<GenerateTextResult
|
|
89
|
-
stream(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<StreamTextResult
|
|
89
|
+
generate(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<GenerateTextResult<ToolSet, OutputType<TOutput>>>;
|
|
90
|
+
stream(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<StreamTextResult<ToolSet, OutputType<TOutput>>>;
|
|
90
91
|
asTool(ctx: TContext, options?: {
|
|
91
|
-
mapOutput?: (result: GenerateTextResult) => MaybePromise<TOutput>;
|
|
92
|
+
mapOutput?: (result: GenerateTextResult<ToolSet, OutputType<TOutput>>) => MaybePromise<TOutput>;
|
|
92
93
|
}): Tool;
|
|
93
94
|
asToolProvider(options?: {
|
|
94
|
-
mapOutput?: (result: GenerateTextResult) => MaybePromise<TOutput>;
|
|
95
|
+
mapOutput?: (result: GenerateTextResult<ToolSet, OutputType<TOutput>>) => MaybePromise<TOutput>;
|
|
95
96
|
}): IToolProvider<TContext>;
|
|
96
97
|
private createToolInstance;
|
|
97
98
|
private buildCallOptions;
|
|
@@ -122,27 +123,27 @@ declare class WorkflowSuspended extends Error {
|
|
|
122
123
|
}
|
|
123
124
|
interface AgentStepHooks<TContext, TOutput, TNextOutput> {
|
|
124
125
|
mapGenerateResult?: (params: {
|
|
125
|
-
result: GenerateTextResult
|
|
126
|
+
result: GenerateTextResult<ToolSet, OutputType<TNextOutput>>;
|
|
126
127
|
ctx: Readonly<TContext>;
|
|
127
128
|
input: TOutput;
|
|
128
129
|
}) => MaybePromise<TNextOutput>;
|
|
129
130
|
mapStreamResult?: (params: {
|
|
130
|
-
result: StreamTextResult
|
|
131
|
+
result: StreamTextResult<ToolSet, OutputType<TNextOutput>>;
|
|
131
132
|
ctx: Readonly<TContext>;
|
|
132
133
|
input: TOutput;
|
|
133
134
|
}) => MaybePromise<TNextOutput>;
|
|
134
135
|
onGenerateResult?: (params: {
|
|
135
|
-
result: GenerateTextResult
|
|
136
|
+
result: GenerateTextResult<ToolSet, OutputType<TNextOutput>>;
|
|
136
137
|
ctx: Readonly<TContext>;
|
|
137
138
|
input: TOutput;
|
|
138
139
|
}) => MaybePromise<void>;
|
|
139
140
|
onStreamResult?: (params: {
|
|
140
|
-
result: StreamTextResult
|
|
141
|
+
result: StreamTextResult<ToolSet, OutputType<TNextOutput>>;
|
|
141
142
|
ctx: Readonly<TContext>;
|
|
142
143
|
input: TOutput;
|
|
143
144
|
}) => MaybePromise<void>;
|
|
144
145
|
handleStream?: (params: {
|
|
145
|
-
result: StreamTextResult
|
|
146
|
+
result: StreamTextResult<ToolSet, OutputType<TNextOutput>>;
|
|
146
147
|
writer: UIMessageStreamWriter;
|
|
147
148
|
ctx: Readonly<TContext>;
|
|
148
149
|
}) => MaybePromise<void>;
|
|
@@ -253,6 +254,12 @@ declare class ResumedWorkflow<TContext, TResponse = unknown, TOutput = void> ext
|
|
|
253
254
|
stream(ctx: TContext, ...args: TResponse extends void ? [response?: TResponse, options?: WorkflowStreamOptions] : [response: TResponse, options?: WorkflowStreamOptions]): WorkflowStreamResult<TOutput>;
|
|
254
255
|
}
|
|
255
256
|
declare class Workflow<TContext, TInput = void, TOutput = void, TGates extends Record<string, unknown> = {}> extends SealedWorkflow<TContext, TInput, TOutput, TGates> {
|
|
257
|
+
/**
|
|
258
|
+
* Sentinel value for `foreach`'s `onError` handler. Returning `Workflow.SKIP`
|
|
259
|
+
* from `onError` omits the failed item's index from the output array,
|
|
260
|
+
* shortening it relative to the input array.
|
|
261
|
+
*/
|
|
262
|
+
static readonly SKIP: unique symbol;
|
|
256
263
|
private constructor();
|
|
257
264
|
static create<TContext, TInput = void>(options?: {
|
|
258
265
|
id?: string;
|
|
@@ -283,8 +290,29 @@ declare class Workflow<TContext, TInput = void, TOutput = void, TGates extends R
|
|
|
283
290
|
branch<TKeys extends string, TNextOutput>(config: BranchSelect<TContext, TOutput, TKeys, TNextOutput>): Workflow<TContext, TInput, TNextOutput, TGates>;
|
|
284
291
|
private branchPredicate;
|
|
285
292
|
private branchSelect;
|
|
293
|
+
/**
|
|
294
|
+
* Map each item of an array through an agent or sub-workflow.
|
|
295
|
+
*
|
|
296
|
+
* @param target Agent or `SealedWorkflow` invoked once per item.
|
|
297
|
+
* @param options.concurrency Max items in flight at any moment (default 1).
|
|
298
|
+
* Backed by a semaphore: as soon as one item completes, the next launches —
|
|
299
|
+
* no lockstep batching.
|
|
300
|
+
* @param options.onError Per-iteration error handler. When provided, a single
|
|
301
|
+
* item's failure no longer aborts the foreach. Return a `TNextOutput` value
|
|
302
|
+
* to substitute for the failed item, return `Workflow.SKIP` to omit the
|
|
303
|
+
* index (shortening the output array), or throw / return a rejected promise
|
|
304
|
+
* to abort the foreach step (the thrown error is caught by any downstream
|
|
305
|
+
* `.catch()`). When omitted, the existing fail-fast behavior is preserved.
|
|
306
|
+
* `onError` is invoked sequentially in index order after all items settle.
|
|
307
|
+
*/
|
|
286
308
|
foreach<TNextOutput>(target: Agent<TContext, ElementOf<TOutput>, TNextOutput> | SealedWorkflow<TContext, ElementOf<TOutput>, TNextOutput>, options?: {
|
|
287
309
|
concurrency?: number;
|
|
310
|
+
onError?: (params: {
|
|
311
|
+
error: unknown;
|
|
312
|
+
item: ElementOf<TOutput>;
|
|
313
|
+
index: number;
|
|
314
|
+
ctx: Readonly<TContext>;
|
|
315
|
+
}) => MaybePromise<TNextOutput | typeof Workflow.SKIP>;
|
|
288
316
|
}): Workflow<TContext, TInput, TNextOutput[], TGates>;
|
|
289
317
|
repeat(target: Agent<TContext, TOutput, TOutput> | SealedWorkflow<TContext, TOutput, TOutput>, options: RepeatOptions<TContext, TOutput>): Workflow<TContext, TInput, TOutput, TGates>;
|
|
290
318
|
catch(id: string, fn: (params: {
|
|
@@ -298,4 +326,4 @@ declare class Workflow<TContext, TInput = void, TOutput = void, TGates extends R
|
|
|
298
326
|
}) => MaybePromise<void>): SealedWorkflow<TContext, TInput, TOutput, TGates>;
|
|
299
327
|
}
|
|
300
328
|
|
|
301
|
-
export { Agent, type AgentConfig, type AgentStepHooks, type BranchCase, type BranchSelect, type GenerateTextResult, type IToolProvider, type MaybePromise, type RepeatOptions, type Resolvable, ResumedWorkflow, SealedWorkflow, type StepOptions, type StreamTextResult, type ToolExecuteOptions, type ToolProviderConfig, Workflow, WorkflowBranchError, WorkflowLoopError, type WorkflowResult, type WorkflowSnapshot, type WorkflowStreamOptions, type WorkflowStreamResult, WorkflowSuspended, defineTool };
|
|
329
|
+
export { Agent, type AgentConfig, type AgentStepHooks, type BranchCase, type BranchSelect, type GenerateTextResult, type IToolProvider, type MaybePromise, type OutputType, type RepeatOptions, type Resolvable, ResumedWorkflow, SealedWorkflow, type StepOptions, type StreamTextResult, type ToolExecuteOptions, type ToolProviderConfig, Workflow, WorkflowBranchError, WorkflowLoopError, type WorkflowResult, type WorkflowSnapshot, type WorkflowStreamOptions, type WorkflowStreamResult, WorkflowSuspended, defineTool };
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,28 @@ function resolveValue(value, ctx, input) {
|
|
|
23
23
|
}
|
|
24
24
|
return value;
|
|
25
25
|
}
|
|
26
|
+
var Semaphore = class {
|
|
27
|
+
available;
|
|
28
|
+
waiters = [];
|
|
29
|
+
constructor(permits) {
|
|
30
|
+
if (!Number.isInteger(permits) || permits < 1) {
|
|
31
|
+
throw new Error(`Semaphore: permits must be a positive integer, got ${permits}`);
|
|
32
|
+
}
|
|
33
|
+
this.available = permits;
|
|
34
|
+
}
|
|
35
|
+
async acquire() {
|
|
36
|
+
if (this.available > 0) {
|
|
37
|
+
this.available--;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
await new Promise((resolve) => this.waiters.push(resolve));
|
|
41
|
+
}
|
|
42
|
+
release() {
|
|
43
|
+
const next = this.waiters.shift();
|
|
44
|
+
if (next) next();
|
|
45
|
+
else this.available++;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
26
48
|
async function extractOutput(result, hasStructuredOutput) {
|
|
27
49
|
if (hasStructuredOutput) {
|
|
28
50
|
const output = await result.output;
|
|
@@ -43,9 +65,8 @@ var ToolProvider = class {
|
|
|
43
65
|
const { execute, input: inputSchema, ...toolDef } = this.config;
|
|
44
66
|
return tool({
|
|
45
67
|
...toolDef,
|
|
46
|
-
|
|
68
|
+
inputSchema,
|
|
47
69
|
execute: (input, options) => execute(input, context, { ...options, writer: getActiveWriter() })
|
|
48
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
49
70
|
});
|
|
50
71
|
}
|
|
51
72
|
};
|
|
@@ -152,7 +173,7 @@ var Agent = class {
|
|
|
152
173
|
}
|
|
153
174
|
return tool2({
|
|
154
175
|
description: this.description,
|
|
155
|
-
|
|
176
|
+
inputSchema: this.config.input,
|
|
156
177
|
execute: async (toolInput) => {
|
|
157
178
|
const writer = getActiveWriter();
|
|
158
179
|
if (writer) {
|
|
@@ -165,7 +186,8 @@ var Agent = class {
|
|
|
165
186
|
if (options?.mapOutput) return options.mapOutput(result);
|
|
166
187
|
return extractOutput(result, this.hasOutput);
|
|
167
188
|
}
|
|
168
|
-
//
|
|
189
|
+
// TS cannot simplify the SDK's `NeverOptional<TOutput, ...>` conditional in a
|
|
190
|
+
// generic context, so we cast through `unknown` instead of `any`.
|
|
169
191
|
});
|
|
170
192
|
}
|
|
171
193
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -521,6 +543,12 @@ var ResumedWorkflow = class extends SealedWorkflow {
|
|
|
521
543
|
}
|
|
522
544
|
};
|
|
523
545
|
var Workflow = class _Workflow extends SealedWorkflow {
|
|
546
|
+
/**
|
|
547
|
+
* Sentinel value for `foreach`'s `onError` handler. Returning `Workflow.SKIP`
|
|
548
|
+
* from `onError` omits the failed item's index from the output array,
|
|
549
|
+
* shortening it relative to the input array.
|
|
550
|
+
*/
|
|
551
|
+
static SKIP = /* @__PURE__ */ Symbol("pipeai.foreach.skip");
|
|
524
552
|
constructor(steps = [], id) {
|
|
525
553
|
super(steps, id);
|
|
526
554
|
}
|
|
@@ -647,8 +675,24 @@ var Workflow = class _Workflow extends SealedWorkflow {
|
|
|
647
675
|
return new _Workflow([...this.steps, node], this.id);
|
|
648
676
|
}
|
|
649
677
|
// ── foreach: array iteration ─────────────────────────────────
|
|
678
|
+
/**
|
|
679
|
+
* Map each item of an array through an agent or sub-workflow.
|
|
680
|
+
*
|
|
681
|
+
* @param target Agent or `SealedWorkflow` invoked once per item.
|
|
682
|
+
* @param options.concurrency Max items in flight at any moment (default 1).
|
|
683
|
+
* Backed by a semaphore: as soon as one item completes, the next launches —
|
|
684
|
+
* no lockstep batching.
|
|
685
|
+
* @param options.onError Per-iteration error handler. When provided, a single
|
|
686
|
+
* item's failure no longer aborts the foreach. Return a `TNextOutput` value
|
|
687
|
+
* to substitute for the failed item, return `Workflow.SKIP` to omit the
|
|
688
|
+
* index (shortening the output array), or throw / return a rejected promise
|
|
689
|
+
* to abort the foreach step (the thrown error is caught by any downstream
|
|
690
|
+
* `.catch()`). When omitted, the existing fail-fast behavior is preserved.
|
|
691
|
+
* `onError` is invoked sequentially in index order after all items settle.
|
|
692
|
+
*/
|
|
650
693
|
foreach(target, options) {
|
|
651
694
|
const concurrency = options?.concurrency ?? 1;
|
|
695
|
+
const onError = options?.onError;
|
|
652
696
|
const isWorkflow = target instanceof SealedWorkflow;
|
|
653
697
|
const id = isWorkflow ? target.id ?? "foreach" : `foreach:${target.id}`;
|
|
654
698
|
const node = {
|
|
@@ -661,6 +705,7 @@ var Workflow = class _Workflow extends SealedWorkflow {
|
|
|
661
705
|
}
|
|
662
706
|
const ctx = state.ctx;
|
|
663
707
|
const results = new Array(items.length);
|
|
708
|
+
const skipped = /* @__PURE__ */ new Set();
|
|
664
709
|
const executeItem = async (item, index) => {
|
|
665
710
|
const itemState = { ctx: state.ctx, output: item, mode: "generate" };
|
|
666
711
|
if (isWorkflow) {
|
|
@@ -670,17 +715,47 @@ var Workflow = class _Workflow extends SealedWorkflow {
|
|
|
670
715
|
}
|
|
671
716
|
results[index] = itemState.output;
|
|
672
717
|
};
|
|
718
|
+
const handleRejection = async (error, item, index) => {
|
|
719
|
+
if (!onError) throw error;
|
|
720
|
+
const recovered = await onError({
|
|
721
|
+
error,
|
|
722
|
+
item,
|
|
723
|
+
index,
|
|
724
|
+
ctx: state.ctx
|
|
725
|
+
});
|
|
726
|
+
if (recovered === _Workflow.SKIP) {
|
|
727
|
+
skipped.add(index);
|
|
728
|
+
} else {
|
|
729
|
+
results[index] = recovered;
|
|
730
|
+
}
|
|
731
|
+
};
|
|
673
732
|
if (concurrency <= 1) {
|
|
674
733
|
for (let i = 0; i < items.length; i++) {
|
|
675
|
-
|
|
734
|
+
try {
|
|
735
|
+
await executeItem(items[i], i);
|
|
736
|
+
} catch (error) {
|
|
737
|
+
await handleRejection(error, items[i], i);
|
|
738
|
+
}
|
|
676
739
|
}
|
|
677
740
|
} else {
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
741
|
+
const sem = new Semaphore(concurrency);
|
|
742
|
+
const failures = [];
|
|
743
|
+
await Promise.all(items.map(async (item, i) => {
|
|
744
|
+
await sem.acquire();
|
|
745
|
+
try {
|
|
746
|
+
await executeItem(item, i);
|
|
747
|
+
} catch (error) {
|
|
748
|
+
failures.push({ index: i, error });
|
|
749
|
+
} finally {
|
|
750
|
+
sem.release();
|
|
751
|
+
}
|
|
752
|
+
}));
|
|
753
|
+
failures.sort((a, b) => a.index - b.index);
|
|
754
|
+
for (const { index, error } of failures) {
|
|
755
|
+
await handleRejection(error, items[index], index);
|
|
681
756
|
}
|
|
682
757
|
}
|
|
683
|
-
state.output = results;
|
|
758
|
+
state.output = skipped.size === 0 ? results : results.filter((_, i) => !skipped.has(i));
|
|
684
759
|
}
|
|
685
760
|
};
|
|
686
761
|
return new _Workflow([...this.steps, node], this.id);
|