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/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
- output?: FlexibleSchema<unknown>;
12
- providerOptions?: unknown;
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
- output?: FlexibleSchema<unknown>;
12
- providerOptions?: unknown;
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
- parameters: inputSchema,
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
- parameters: this.config.input,
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
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
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
- await executeItem(items[i], i);
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
- for (let i = 0; i < items.length; i += concurrency) {
679
- const batch = items.slice(i, i + concurrency);
680
- await Promise.all(batch.map((item, j) => executeItem(item, i + j)));
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);