pipeai 0.1.0 → 0.1.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 CHANGED
@@ -117,15 +117,17 @@ const agent = new Agent<Ctx>({
117
117
 
118
118
  ### AI SDK callbacks
119
119
 
120
- Same callback names as AI SDK v6, extended with `ctx` and `input`. The AI SDK event payload is available as `result`:
120
+ Same callback names as AI SDK v6, extended with `ctx`, `input`, and `writer`. The AI SDK event payload is available as `result`. When the agent runs inside a streaming workflow, `writer` is available for writing metadata or custom stream parts:
121
121
 
122
122
  ```ts
123
123
  const agent = new Agent<Ctx>({
124
124
  id: "monitored",
125
125
  model: openai("gpt-4o"),
126
126
  prompt: (ctx, input) => input,
127
- onStepFinish: ({ result, ctx }) => {
127
+ onStepFinish: ({ result, ctx, writer }) => {
128
128
  console.log(`Step done, used ${result.usage.totalTokens} tokens`);
129
+ // Stream progress metadata to the client
130
+ writer?.write({ type: "metadata", value: { tokensUsed: result.usage.totalTokens } });
129
131
  },
130
132
  onFinish: ({ result, ctx }) => {
131
133
  console.log(`Total: ${result.totalUsage.totalTokens} tokens`);
@@ -152,9 +154,9 @@ const agent = new Agent<Ctx>({
152
154
  | `activeTools` | `Resolvable` | Subset of tool names to enable. |
153
155
  | `toolChoice` | `Resolvable` | Tool choice strategy. Static or `(ctx, input) => toolChoice`. |
154
156
  | `stopWhen` | `Resolvable` | Condition for stopping the tool loop. Static or `(ctx, input) => condition`. |
155
- | `onStepFinish`| `({ result, ctx, input })`| Called after each step. |
156
- | `onFinish` | `({ result, ctx, input })`| Called when all steps complete. |
157
- | `onError` | `({ error, ctx, input })` | Called on error. |
157
+ | `onStepFinish`| `({ result, ctx, input, writer? })`| Called after each step. `writer` available in streaming workflows. |
158
+ | `onFinish` | `({ result, ctx, input, writer? })`| Called when all steps complete. |
159
+ | `onError` | `({ error, ctx, input, writer? })` | Called on error. |
158
160
  | `...` | AI SDK options | All other `streamText`/`generateText` options pass through (e.g. `temperature`, `maxTokens`, `maxRetries`, `headers`, `prepareStep`, `onChunk`, etc.). |
159
161
 
160
162
  ## `asTool()` — Agent as Tool
@@ -212,7 +214,7 @@ codingAgent.asTool(ctx, {
212
214
  });
213
215
  ```
214
216
 
215
- **Note:** `asTool()` uses `generate()` internally — sub-agent execution is non-streaming. This is an AI SDK tool loop constraint. For streaming multi-agent workflows, use `step()` with `branch()` instead.
217
+ **Automatic streaming:** When `asTool()` is used inside a streaming workflow, sub-agents automatically use `stream()` and merge their output to the parent's stream the user sees sub-agent responses in real-time. Outside of a streaming context (standalone use or generate mode), `asTool()` falls back to `generate()`. This is handled invisibly — no configuration needed.
216
218
 
217
219
  ## `asToolProvider()` — Deferred Context
218
220
 
@@ -236,11 +238,10 @@ This is useful when the agent is defined at module scope but the context isn't a
236
238
 
237
239
  ## defineTool — Context-Aware Tools
238
240
 
239
- `defineTool` wraps a tool definition so the agent's runtime context is injected into every `execute` call. The `input` field maps to AI SDK's `parameters`:
241
+ `defineTool` wraps a tool definition so the agent's runtime context is injected into every `execute` call. The `input` field maps to AI SDK's `parameters`. When running inside a streaming workflow, the `writer` is automatically available in the third parameter for streaming metadata or progress updates to the client:
240
242
 
241
243
  ```ts
242
244
  import { defineTool } from "pipeai";
243
- import { tool } from "ai";
244
245
 
245
246
  type Ctx = { db: Database; userId: string };
246
247
 
@@ -249,8 +250,11 @@ const define = defineTool<Ctx>();
249
250
  const searchOrders = define({
250
251
  description: "Search user orders",
251
252
  input: z.object({ query: z.string() }),
252
- execute: async ({ query }, ctx) => {
253
- return ctx.db.orders.search(ctx.userId, query);
253
+ execute: async ({ query }, ctx, { writer }) => {
254
+ writer?.write({ type: "metadata", value: { status: "searching" } });
255
+ const results = await ctx.db.orders.search(ctx.userId, query);
256
+ writer?.write({ type: "metadata", value: { status: "done", count: results.length } });
257
+ return results;
254
258
  },
255
259
  });
256
260
 
@@ -271,6 +275,8 @@ const agent = new Agent<Ctx>({
271
275
  });
272
276
  ```
273
277
 
278
+ The `writer` is `undefined` when running in generate mode or standalone — `?.` handles both cases naturally.
279
+
274
280
  ## Workflow
275
281
 
276
282
  A `Workflow` chains agents and transformation steps into a typed pipeline. Context is read-only — agents communicate through outputs.
@@ -313,6 +319,7 @@ Workflows can be passed as steps into other workflows. The nested workflow's ste
313
319
  // A reusable sub-workflow
314
320
  const classifyAndRoute = Workflow.create<Ctx>()
315
321
  .step(classifier, {
322
+ // Suppress the classifier's stream — only route the result
316
323
  handleStream: async ({ result }) => { await result.text; },
317
324
  })
318
325
  .branch({
@@ -402,7 +409,10 @@ const pipeline = Workflow.create<Ctx>()
402
409
  // Called during workflow.stream() — StreamTextResult (async access)
403
410
  mapStreamResult: async ({ result }) => ({
404
411
  text: await result.text,
405
- files: [],
412
+ files: (await result.steps)
413
+ .flatMap(s => s.toolResults)
414
+ .filter(tr => tr.toolName === "writeFile")
415
+ .map(tr => tr.args.path),
406
416
  }),
407
417
  });
408
418
  ```
@@ -423,10 +433,11 @@ const pipeline = Workflow.create<Ctx>()
423
433
  });
424
434
  },
425
435
  // Called during workflow.stream()
426
- onStreamResult: async ({ result, ctx, input }) => {
436
+ onStreamResult: async ({ result, ctx }) => {
427
437
  await ctx.db.conversations.save(ctx.userId, {
428
438
  role: "assistant",
429
439
  content: await result.text,
440
+ toolCalls: await result.toolCalls,
430
441
  });
431
442
  },
432
443
  });
@@ -434,7 +445,7 @@ const pipeline = Workflow.create<Ctx>()
434
445
 
435
446
  ### Fine-grained stream control
436
447
 
437
- Override how each agent's stream is merged into the workflow stream. By default, every agent's output is merged into the workflow stream via `writer.merge(result.toUIMessageStream())`. Use `handleStream` to change thisfor example, to suppress intermediate agents so only the final response streams to the client:
448
+ Override how each agent's stream is merged into the workflow stream. By default, every agent's output is merged via `writer.merge(result.toUIMessageStream())`. Use `handleStream` to take controlthe callback receives `{ result, writer, ctx }`:
438
449
 
439
450
  ```ts
440
451
  const pipeline = Workflow.create<Ctx>()
@@ -442,14 +453,16 @@ const pipeline = Workflow.create<Ctx>()
442
453
  // the structured classification output, only the final response
443
454
  .step(classifier, {
444
455
  handleStream: async ({ result }) => {
445
- await result.text; // consume the stream without forwarding it
456
+ await result.text; // consume without forwarding to the client
446
457
  },
447
458
  })
448
- .branch({
449
- select: ({ input }) => input.agent,
450
- agents: { bug: bugAgent, feature: featureAgent, question: questionAgent },
459
+ // Custom merging — e.g. add metadata annotations to the stream
460
+ .step(supportAgent, {
461
+ handleStream: async ({ result, writer, ctx }) => {
462
+ writer.write({ type: "metadata", value: { agentId: "support", userId: ctx.userId } });
463
+ writer.merge(result.toUIMessageStream());
464
+ },
451
465
  });
452
- // Only the selected agent's response streams to the client
453
466
  ```
454
467
 
455
468
  ### Array iteration via `foreach()`
@@ -485,7 +498,9 @@ const processItem = Workflow.create<Ctx, string>()
485
498
  .step(analyzeAgent)
486
499
  .step(enrichAgent);
487
500
 
488
- pipeline.foreach(processItem, { concurrency: 5 });
501
+ const pipeline = Workflow.create<Ctx>()
502
+ .step("fetch-items", async ({ ctx }) => ctx.db.items.getAll())
503
+ .foreach(processItem, { concurrency: 5 });
489
504
  ```
490
505
 
491
506
  **Type safety:** `foreach()` uses `ElementOf<TOutput>` to extract the array element type. If the previous step doesn't produce an array, the call is rejected at compile time.
@@ -671,11 +686,9 @@ const questionAgent = new Agent<Ctx>({
671
686
 
672
687
  // 4. Compose workflow
673
688
  const pipeline = Workflow.create<Ctx>()
674
- // Classify silently — don't stream the structured JSON to the client
689
+ // Classify silently — consume the stream without forwarding to client
675
690
  .step(classifier, {
676
- handleStream: async ({ result }) => {
677
- await result.text;
678
- },
691
+ handleStream: async ({ result }) => { await result.text; },
679
692
  })
680
693
  // Route to the right specialist based on classification
681
694
  .branch({
package/dist/index.cjs CHANGED
@@ -33,6 +33,31 @@ var import_ai2 = require("ai");
33
33
 
34
34
  // src/tool-provider.ts
35
35
  var import_ai = require("ai");
36
+
37
+ // src/utils.ts
38
+ var import_node_async_hooks = require("async_hooks");
39
+ var writerStorage = new import_node_async_hooks.AsyncLocalStorage();
40
+ function runWithWriter(writer, fn) {
41
+ return writerStorage.run(writer, fn);
42
+ }
43
+ function getActiveWriter() {
44
+ return writerStorage.getStore();
45
+ }
46
+ function resolveValue(value, ctx, input) {
47
+ if (typeof value === "function") {
48
+ return value(ctx, input);
49
+ }
50
+ return value;
51
+ }
52
+ async function extractOutput(result, hasStructuredOutput) {
53
+ if (hasStructuredOutput) {
54
+ const output = await result.output;
55
+ if (output !== void 0) return output;
56
+ }
57
+ return await result.text;
58
+ }
59
+
60
+ // src/tool-provider.ts
36
61
  var TOOL_PROVIDER_BRAND = /* @__PURE__ */ Symbol.for("agent-workflow.ToolProvider");
37
62
  var ToolProvider = class {
38
63
  [TOOL_PROVIDER_BRAND] = true;
@@ -45,7 +70,7 @@ var ToolProvider = class {
45
70
  return (0, import_ai.tool)({
46
71
  ...toolDef,
47
72
  parameters: inputSchema,
48
- execute: (input, options) => execute(input, context, options)
73
+ execute: (input, options) => execute(input, context, { ...options, writer: getActiveWriter() })
49
74
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
75
  });
51
76
  }
@@ -57,21 +82,6 @@ function isToolProvider(obj) {
57
82
  return typeof obj === "object" && obj !== null && TOOL_PROVIDER_BRAND in obj;
58
83
  }
59
84
 
60
- // src/utils.ts
61
- function resolveValue(value, ctx, input) {
62
- if (typeof value === "function") {
63
- return value(ctx, input);
64
- }
65
- return value;
66
- }
67
- async function extractOutput(result, hasStructuredOutput) {
68
- if (hasStructuredOutput) {
69
- const output = await result.output;
70
- if (output !== void 0) return output;
71
- }
72
- return await result.text;
73
- }
74
-
75
85
  // src/agent.ts
76
86
  var Agent = class {
77
87
  id;
@@ -136,7 +146,7 @@ var Agent = class {
136
146
  return await (0, import_ai2.generateText)(options);
137
147
  } catch (error) {
138
148
  if (this.config.onError) {
139
- await this.config.onError({ error, ctx, input });
149
+ await this.config.onError({ error, ctx, input, writer: getActiveWriter() });
140
150
  }
141
151
  throw error;
142
152
  }
@@ -147,7 +157,7 @@ var Agent = class {
147
157
  const options = this.buildCallOptions(resolved, ctx, input);
148
158
  return (0, import_ai2.streamText)({
149
159
  ...options,
150
- onError: this.config.onError ? ({ error }) => this.config.onError({ error, ctx, input }) : void 0
160
+ onError: this.config.onError ? ({ error }) => this.config.onError({ error, ctx, input, writer: getActiveWriter() }) : void 0
151
161
  });
152
162
  }
153
163
  asTool(ctx, options) {
@@ -170,6 +180,13 @@ var Agent = class {
170
180
  description: this.description,
171
181
  parameters: this.config.input,
172
182
  execute: async (toolInput) => {
183
+ const writer = getActiveWriter();
184
+ if (writer) {
185
+ const result2 = await this.stream(ctx, toolInput);
186
+ writer.merge(result2.toUIMessageStream());
187
+ if (options?.mapOutput) return options.mapOutput(result2);
188
+ return extractOutput(result2, this.hasOutput);
189
+ }
173
190
  const result = await this.generate(ctx, toolInput);
174
191
  if (options?.mapOutput) return options.mapOutput(result);
175
192
  return extractOutput(result, this.hasOutput);
@@ -189,8 +206,8 @@ var Agent = class {
189
206
  ...resolved.messages ? { messages: resolved.messages } : { prompt: resolved.prompt ?? "" },
190
207
  ...resolved.system ? { system: resolved.system } : {},
191
208
  ...this.config.output ? { output: this.config.output } : {},
192
- onStepFinish: this._onStepFinish ? (event) => this._onStepFinish({ result: event, ctx, input }) : void 0,
193
- onFinish: this._onFinish ? (event) => this._onFinish({ result: event, ctx, input }) : void 0
209
+ onStepFinish: this._onStepFinish ? (event) => this._onStepFinish({ result: event, ctx, input, writer: getActiveWriter() }) : void 0,
210
+ onFinish: this._onFinish ? (event) => this._onFinish({ result: event, ctx, input, writer: getActiveWriter() }) : void 0
194
211
  };
195
212
  }
196
213
  resolveConfig(ctx, input) {
@@ -363,20 +380,23 @@ var SealedWorkflow = class {
363
380
  const input = state.output;
364
381
  const hasStructuredOutput = agent.hasOutput;
365
382
  if (state.mode === "stream" && state.writer) {
366
- const result = await agent.stream(ctx, state.output);
367
- if (options?.handleStream) {
368
- await options.handleStream({ result, writer: state.writer, ctx });
369
- } else {
370
- state.writer.merge(result.toUIMessageStream());
371
- }
372
- if (options?.onStreamResult) {
373
- await options.onStreamResult({ result, ctx, input });
374
- }
375
- if (options?.mapStreamResult) {
376
- state.output = await options.mapStreamResult({ result, ctx, input });
377
- } else {
378
- state.output = await extractOutput(result, hasStructuredOutput);
379
- }
383
+ const writer = state.writer;
384
+ await runWithWriter(writer, async () => {
385
+ const result = await agent.stream(ctx, state.output);
386
+ if (options?.handleStream) {
387
+ await options.handleStream({ result, writer, ctx });
388
+ } else {
389
+ writer.merge(result.toUIMessageStream());
390
+ }
391
+ if (options?.onStreamResult) {
392
+ await options.onStreamResult({ result, ctx, input });
393
+ }
394
+ if (options?.mapStreamResult) {
395
+ state.output = await options.mapStreamResult({ result, ctx, input });
396
+ } else {
397
+ state.output = await extractOutput(result, hasStructuredOutput);
398
+ }
399
+ });
380
400
  } else {
381
401
  const result = await agent.generate(ctx, state.output);
382
402
  if (options?.onGenerateResult) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/agent.ts","../src/tool-provider.ts","../src/utils.ts","../src/workflow.ts"],"sourcesContent":["export { Agent } from \"./agent\";\nexport type {\n AgentConfig,\n GenerateTextResult,\n StreamTextResult,\n} from \"./agent\";\n\nexport { Workflow, WorkflowBranchError, WorkflowLoopError } from \"./workflow\";\nexport type { SealedWorkflow } from \"./workflow\";\nexport type {\n AgentStepHooks,\n StepOptions,\n BranchCase,\n BranchSelect,\n RepeatOptions,\n WorkflowResult,\n WorkflowStreamResult,\n WorkflowStreamOptions,\n} from \"./workflow\";\n\nexport { defineTool } from \"./tool-provider\";\nexport type { ToolProviderConfig, IToolProvider } from \"./tool-provider\";\n\nexport type { MaybePromise, Resolvable } from \"./utils\";\n","import {\n generateText,\n streamText,\n tool,\n Output,\n type GenerateTextResult as AIGenerateTextResult,\n type StreamTextResult as AIStreamTextResult,\n type ModelMessage,\n type LanguageModel,\n type Tool,\n type ToolSet,\n type StopCondition,\n type ToolChoice,\n type OnStepFinishEvent,\n type OnFinishEvent,\n} from \"ai\";\n\n// Extract the Output interface type from the Output.object return type\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype OutputType<T = any> = ReturnType<typeof Output.object<T>>;\nimport type { ZodType } from \"zod\";\nimport { isToolProvider, TOOL_PROVIDER_BRAND, type IToolProvider } from \"./tool-provider\";\nimport { extractOutput, resolveValue, type MaybePromise, type Resolvable } from \"./utils\";\n\n// Tools config accepts both AI SDK tools and context-aware ToolProviders\ntype AgentToolSet<TContext> = Record<string, Tool | IToolProvider<TContext>>;\n\n// ── Result type aliases ─────────────────────────────────────────────\n\nexport type GenerateTextResult<TOOLS extends ToolSet = ToolSet, OUTPUT extends OutputType = OutputType> = AIGenerateTextResult<TOOLS, OUTPUT>;\nexport type StreamTextResult<TOOLS extends ToolSet = ToolSet, OUTPUT extends OutputType = OutputType> = AIStreamTextResult<TOOLS, OUTPUT>;\n\n// ── AI SDK passthrough types ────────────────────────────────────────\n\n// Extract options types from both AI SDK entry points\ntype StreamTextOptions = Parameters<typeof streamText>[0];\ntype GenerateTextOptions = Parameters<typeof generateText>[0];\n\n// Keys we replace with resolvable or context-enriched versions\ntype ManagedKeys =\n | 'model' | 'system' | 'prompt' | 'messages'\n | 'tools' | 'activeTools' | 'toolChoice' | 'stopWhen'\n | 'output' | 'onFinish' | 'onStepFinish' | 'onError';\n\n// Combine options from both streamText and generateText.\n// Each side contributes its unique props; shared props merge naturally.\n// Stream-only props (onChunk, onAbort) are ignored by generateText.\n// Generate-only props (experimental_include.responseBody) are ignored by streamText.\ntype AIPassthroughOptions =\n Omit<StreamTextOptions, ManagedKeys> &\n Omit<GenerateTextOptions, ManagedKeys>;\n\n// ── Resolved config (output of resolveConfig / resolveConfigAsync) ──\n\ninterface ResolvedAgentConfig {\n model: LanguageModel;\n prompt: string | undefined;\n system: string | undefined;\n messages: ModelMessage[] | undefined;\n tools: Record<string, Tool>;\n activeTools: string[] | undefined;\n toolChoice: ToolChoice<ToolSet> | undefined;\n stopWhen: StopCondition<ToolSet> | Array<StopCondition<ToolSet>> | undefined;\n}\n\n// ── Agent Configuration ─────────────────────────────────────────────\n\nexport interface AgentConfig<\n TContext,\n TInput = void,\n TOutput = void,\n> extends AIPassthroughOptions {\n // ── Custom (not in AI SDK) ──\n id: string;\n description?: string;\n input?: ZodType<TInput>;\n output?: OutputType<TOutput>;\n\n // ── Resolvable (our versions of AI SDK properties) ──\n model: Resolvable<TContext, TInput, LanguageModel>;\n system?: Resolvable<TContext, TInput, string>;\n prompt?: Resolvable<TContext, TInput, string>;\n messages?: Resolvable<TContext, TInput, ModelMessage[]>;\n tools?: Resolvable<TContext, TInput, AgentToolSet<TContext>>;\n activeTools?: Resolvable<TContext, TInput, string[]>;\n toolChoice?: Resolvable<TContext, TInput, ToolChoice<ToolSet>>;\n stopWhen?: Resolvable<TContext, TInput, StopCondition<ToolSet> | Array<StopCondition<ToolSet>>>;\n\n // ── Context-enriched callbacks (replace AI SDK versions) ──\n onStepFinish?: (params: { result: OnStepFinishEvent; ctx: Readonly<TContext>; input: TInput }) => MaybePromise<void>;\n onFinish?: (params: { result: OnFinishEvent; ctx: Readonly<TContext>; input: TInput }) => MaybePromise<void>;\n onError?: (params: { error: unknown; ctx: Readonly<TContext>; input: TInput }) => MaybePromise<void>;\n}\n\n// ── Agent ───────────────────────────────────────────────────────────\n\nexport class Agent<\n TContext,\n TInput = void,\n TOutput = void,\n> {\n readonly id: string;\n readonly description: string;\n readonly hasOutput: boolean;\n private readonly config: AgentConfig<TContext, TInput, TOutput>;\n private readonly _hasDynamicConfig: boolean;\n private readonly _resolvedStaticTools: Record<string, Tool> | null = null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private readonly _passthrough: Record<string, any>;\n private readonly _onStepFinish: AgentConfig<TContext, TInput, TOutput>['onStepFinish'];\n private readonly _onFinish: AgentConfig<TContext, TInput, TOutput>['onFinish'];\n\n constructor(config: AgentConfig<TContext, TInput, TOutput>) {\n this.id = config.id;\n this.description = config.description ?? \"\";\n this.hasOutput = config.output !== undefined;\n this.config = config;\n this._hasDynamicConfig = [\n config.model, config.system, config.prompt,\n config.messages, config.tools, config.activeTools,\n config.toolChoice, config.stopWhen,\n ].some(v => typeof v === \"function\");\n\n // Cache tools when config is static and contains no ToolProviders.\n // Avoids re-iterating the tools map on every generate()/stream() call.\n if (!this._hasDynamicConfig) {\n const rawTools = (config.tools as AgentToolSet<TContext> | undefined) ?? {};\n const hasProvider = Object.values(rawTools).some(v => isToolProvider(v));\n if (!hasProvider) {\n this._resolvedStaticTools = rawTools as Record<string, Tool>;\n }\n }\n\n // Pre-compute the passthrough (AI SDK options we don't manage) once,\n // rather than destructuring on every generate()/stream() call.\n const {\n id: _id, description: _desc, input: _inputSchema, output: _output,\n model: _m, system: _s, prompt: _p, messages: _msg,\n tools: _t, activeTools: _at, toolChoice: _tc, stopWhen: _sw,\n onStepFinish, onFinish, onError: _onError,\n ...passthrough\n } = config;\n this._passthrough = passthrough;\n this._onStepFinish = onStepFinish;\n this._onFinish = onFinish;\n }\n\n async generate(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<GenerateTextResult> {\n const input = args[0] as TInput;\n const resolved = await this.resolveConfig(ctx, input);\n const options = this.buildCallOptions(resolved, ctx, input);\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return await generateText(options as any);\n } catch (error: unknown) {\n if (this.config.onError) {\n await this.config.onError({ error, ctx, input });\n }\n throw error;\n }\n }\n\n async stream(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<StreamTextResult> {\n const input = args[0] as TInput;\n const resolved = await this.resolveConfig(ctx, input);\n const options = this.buildCallOptions(resolved, ctx, input);\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return streamText({\n ...options,\n onError: this.config.onError\n ? ({ error }: { error: unknown }) => this.config.onError!({ error, ctx, input })\n : undefined,\n } as any);\n }\n\n asTool(ctx: TContext, options?: {\n mapOutput?: (result: GenerateTextResult) => MaybePromise<TOutput>;\n }): Tool {\n return this.createToolInstance(ctx, options);\n }\n\n asToolProvider(options?: {\n mapOutput?: (result: GenerateTextResult) => MaybePromise<TOutput>;\n }): IToolProvider<TContext> {\n if (!this.config.input) {\n throw new Error(`Agent \"${this.id}\": asToolProvider() requires an input schema`);\n }\n\n return {\n [TOOL_PROVIDER_BRAND]: true as const,\n createTool: (ctx: Readonly<TContext>) => this.createToolInstance(ctx as TContext, options),\n };\n }\n\n private createToolInstance(ctx: TContext, options?: {\n mapOutput?: (result: GenerateTextResult) => MaybePromise<TOutput>;\n }): Tool {\n if (!this.config.input) {\n throw new Error(`Agent \"${this.id}\": asTool() requires an input schema`);\n }\n\n return tool({\n description: this.description,\n parameters: this.config.input,\n execute: async (toolInput: TInput) => {\n const result = await (this.generate as (ctx: TContext, input: TInput) => Promise<GenerateTextResult>)(ctx, toolInput);\n if (options?.mapOutput) return options.mapOutput(result);\n return extractOutput(result, this.hasOutput);\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private buildCallOptions(resolved: ResolvedAgentConfig, ctx: TContext, input: TInput): Record<string, any> {\n return {\n ...this._passthrough,\n model: resolved.model,\n tools: resolved.tools,\n activeTools: resolved.activeTools,\n toolChoice: resolved.toolChoice,\n stopWhen: resolved.stopWhen,\n ...(resolved.messages\n ? { messages: resolved.messages }\n : { prompt: resolved.prompt ?? \"\" }),\n ...(resolved.system ? { system: resolved.system } : {}),\n ...(this.config.output ? { output: this.config.output } : {}),\n onStepFinish: this._onStepFinish\n ? (event: OnStepFinishEvent) => this._onStepFinish!({ result: event, ctx, input })\n : undefined,\n onFinish: this._onFinish\n ? (event: OnFinishEvent) => this._onFinish!({ result: event, ctx, input })\n : undefined,\n };\n }\n\n private resolveConfig(ctx: TContext, input: TInput): ResolvedAgentConfig | Promise<ResolvedAgentConfig> {\n if (!this._hasDynamicConfig) {\n return {\n model: this.config.model as LanguageModel,\n prompt: this.config.prompt as string | undefined,\n system: this.config.system as string | undefined,\n messages: this.config.messages as ModelMessage[] | undefined,\n tools: this._resolvedStaticTools ?? this.resolveTools(\n (this.config.tools as AgentToolSet<TContext> | undefined) ?? {}, ctx\n ),\n activeTools: this.config.activeTools as string[] | undefined,\n toolChoice: this.config.toolChoice as ToolChoice<ToolSet> | undefined,\n stopWhen: this.config.stopWhen as StopCondition<ToolSet> | Array<StopCondition<ToolSet>> | undefined,\n };\n }\n return this.resolveConfigAsync(ctx, input);\n }\n\n private async resolveConfigAsync(ctx: TContext, input: TInput): Promise<ResolvedAgentConfig> {\n const [model, prompt, system, messages, rawTools, activeTools, toolChoice, stopWhen] = await Promise.all([\n resolveValue(this.config.model, ctx, input),\n resolveValue(this.config.prompt, ctx, input),\n resolveValue(this.config.system, ctx, input),\n resolveValue(this.config.messages, ctx, input),\n resolveValue(this.config.tools, ctx, input),\n resolveValue(this.config.activeTools, ctx, input),\n resolveValue(this.config.toolChoice, ctx, input),\n resolveValue(this.config.stopWhen, ctx, input),\n ]);\n const tools = this.resolveTools(rawTools ?? {}, ctx);\n return { model, prompt, system, messages, tools, activeTools, toolChoice, stopWhen };\n }\n\n private resolveTools(\n tools: AgentToolSet<TContext>,\n ctx: TContext\n ): Record<string, Tool> {\n const entries = Object.entries(tools);\n if (entries.length === 0) return tools as Record<string, Tool>;\n let hasProvider = false;\n const resolved: Record<string, Tool> = {};\n for (const [key, toolOrProvider] of entries) {\n if (isToolProvider<TContext>(toolOrProvider)) {\n hasProvider = true;\n resolved[key] = toolOrProvider.createTool(ctx as Readonly<TContext>);\n } else {\n resolved[key] = toolOrProvider as Tool;\n }\n }\n return hasProvider ? resolved : (tools as Record<string, Tool>);\n }\n}\n","import { tool, type Tool, type ToolExecutionOptions, type FlexibleSchema } from \"ai\";\n\nexport const TOOL_PROVIDER_BRAND = Symbol.for(\"agent-workflow.ToolProvider\");\n\nexport type ToolProviderConfig<TContext, TInput, TOutput> = {\n description?: string;\n input: FlexibleSchema<TInput>;\n output?: FlexibleSchema<unknown>;\n providerOptions?: unknown;\n execute: (input: TInput, ctx: Readonly<TContext>, options?: ToolExecutionOptions) => Promise<TOutput>;\n};\n\nexport interface IToolProvider<TContext> {\n readonly [TOOL_PROVIDER_BRAND]: true;\n createTool(context: Readonly<TContext>): Tool;\n}\n\nexport class ToolProvider<\n TContext,\n TInput = unknown,\n TOutput = unknown,\n> implements IToolProvider<TContext> {\n readonly [TOOL_PROVIDER_BRAND] = true as const;\n private readonly config: ToolProviderConfig<TContext, TInput, TOutput>;\n\n constructor(config: ToolProviderConfig<TContext, TInput, TOutput>) {\n this.config = config;\n }\n\n createTool(context: Readonly<TContext>): Tool {\n const { execute, input: inputSchema, ...toolDef } = this.config;\n return tool({\n ...toolDef,\n parameters: inputSchema,\n execute: (input: TInput, options?: ToolExecutionOptions) => execute(input, context, options),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any);\n }\n}\n\nexport function defineTool<TContext>() {\n return <TInput, TOutput>(\n config: ToolProviderConfig<TContext, TInput, TOutput>\n ): ToolProvider<TContext, TInput, TOutput> => new ToolProvider(config);\n}\n\nexport function isToolProvider<TContext>(obj: unknown): obj is IToolProvider<TContext> {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n TOOL_PROVIDER_BRAND in obj\n );\n}\n","export type MaybePromise<T> = T | Promise<T>;\n\n/**\n * A value that can be static or derived from context and input.\n * Used for agent config fields that may need runtime resolution.\n *\n * Functions may return a Promise for async resolution; static values are always sync.\n */\nexport type Resolvable<TCtx, TInput, TValue> =\n | TValue\n | ((ctx: Readonly<TCtx>, input: TInput) => TValue | Promise<TValue>);\n\nexport function resolveValue<TCtx, TInput, TValue>(\n value: Resolvable<TCtx, TInput, TValue>,\n ctx: TCtx,\n input: TInput\n): TValue | Promise<TValue>;\nexport function resolveValue<TCtx, TInput, TValue>(\n value: Resolvable<TCtx, TInput, TValue> | undefined,\n ctx: TCtx,\n input: TInput\n): TValue | Promise<TValue> | undefined {\n if (typeof value === \"function\") {\n return (value as (ctx: TCtx, input: TInput) => TValue | Promise<TValue>)(ctx, input);\n }\n return value;\n}\n\n/**\n * Extract structured output from an AI SDK result, falling back to text.\n * Works for both generate (sync .output/.text) and stream (async .output/.text) results.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function extractOutput(result: any, hasStructuredOutput: boolean): Promise<unknown> {\n if (hasStructuredOutput) {\n const output = await result.output;\n if (output !== undefined) return output;\n }\n return await result.text;\n}\n","import {\n createUIMessageStream,\n type UIMessageStreamWriter,\n} from \"ai\";\nimport { type Agent, type GenerateTextResult, type StreamTextResult } from \"./agent\";\nimport { extractOutput, type MaybePromise } from \"./utils\";\n\n// ── Error Types ─────────────────────────────────────────────────────\n\nexport class WorkflowBranchError extends Error {\n constructor(\n public readonly branchType: \"predicate\" | \"select\",\n message: string,\n ) {\n super(message);\n this.name = \"WorkflowBranchError\";\n }\n}\n\nexport class WorkflowLoopError extends Error {\n constructor(\n public readonly iterations: number,\n public readonly maxIterations: number,\n ) {\n super(`Loop exceeded maximum iterations (${maxIterations})`);\n this.name = \"WorkflowLoopError\";\n }\n}\n\n// ── Shared Agent Step Hooks ─────────────────────────────────────────\n\nexport interface AgentStepHooks<TContext, TOutput, TNextOutput> {\n mapGenerateResult?: (params: { result: GenerateTextResult; ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>;\n mapStreamResult?: (params: { result: StreamTextResult; ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>;\n onGenerateResult?: (params: { result: GenerateTextResult; ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<void>;\n onStreamResult?: (params: { result: StreamTextResult; ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<void>;\n handleStream?: (params: {\n result: StreamTextResult;\n writer: UIMessageStreamWriter;\n ctx: Readonly<TContext>;\n }) => MaybePromise<void>;\n}\n\n// ── Step Options ────────────────────────────────────────────────────\n\nexport type StepOptions<TContext, TOutput, TNextOutput> = AgentStepHooks<TContext, TOutput, TNextOutput>;\n\n// ── Branch Types ────────────────────────────────────────────────────\n\nexport interface BranchCase<TContext, TOutput, TNextOutput> extends AgentStepHooks<TContext, TOutput, TNextOutput> {\n when?: (params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<boolean>;\n agent: Agent<TContext, TOutput, TNextOutput>;\n}\n\nexport interface BranchSelect<TContext, TOutput, TKeys extends string, TNextOutput> extends AgentStepHooks<TContext, TOutput, TNextOutput> {\n select: (params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TKeys>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n agents: Record<TKeys, Agent<TContext, any, TNextOutput>>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n fallback?: Agent<TContext, any, TNextOutput>;\n}\n\n// ── Result Types ────────────────────────────────────────────────────\n\nexport interface WorkflowResult<TOutput> {\n output: TOutput;\n}\n\nexport interface WorkflowStreamResult<TOutput> {\n stream: ReadableStream;\n output: Promise<TOutput>;\n}\n\nexport interface WorkflowStreamOptions {\n onError?: (error: unknown) => string;\n onFinish?: () => MaybePromise<void>;\n}\n\n// ── Loop Types ──────────────────────────────────────────────────────\n\ntype LoopPredicate<TContext, TOutput> = (params: {\n output: TOutput;\n ctx: Readonly<TContext>;\n iterations: number;\n}) => MaybePromise<boolean>;\n\n// Exactly one of `until` or `while` — never both.\nexport type RepeatOptions<TContext, TOutput> =\n | { until: LoopPredicate<TContext, TOutput>; while?: never; maxIterations?: number }\n | { while: LoopPredicate<TContext, TOutput>; until?: never; maxIterations?: number };\n\n// Extracts the element type from an array type. Resolves to `never` for non-arrays,\n// making foreach uncallable at compile time when the previous step doesn't produce an array.\ntype ElementOf<T> = T extends readonly (infer E)[] ? E : never;\n\n// ── Step Node ───────────────────────────────────────────────────────\n\ntype StepNode =\n | { readonly type: \"step\"; readonly id: string; readonly execute: (state: RuntimeState) => MaybePromise<void> }\n | { readonly type: \"catch\"; readonly id: string; readonly catchFn: (params: { error: unknown; ctx: unknown; lastOutput: unknown; stepId: string }) => MaybePromise<unknown> }\n | { readonly type: \"finally\"; readonly id: string; readonly execute: (state: RuntimeState) => MaybePromise<void> };\n\ninterface RuntimeState {\n ctx: unknown;\n output: unknown;\n mode: \"generate\" | \"stream\";\n writer?: UIMessageStreamWriter;\n}\n\n// ── Sealed Workflow (returned by finally — execution only) ───────────\n\nexport class SealedWorkflow<\n TContext,\n TInput = void,\n TOutput = void,\n> {\n readonly id?: string;\n protected readonly steps: ReadonlyArray<StepNode>;\n\n protected constructor(steps: ReadonlyArray<StepNode>, id?: string) {\n this.steps = steps;\n this.id = id;\n }\n\n // ── Execution ─────────────────────────────────────────────────\n\n async generate(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<WorkflowResult<TOutput>> {\n const input = args[0];\n const state: RuntimeState = {\n ctx,\n output: input,\n mode: \"generate\",\n };\n\n await this.execute(state);\n\n return {\n output: state.output as TOutput,\n };\n }\n\n stream(\n ctx: TContext,\n ...args: TInput extends void\n ? [input?: TInput, options?: WorkflowStreamOptions]\n : [input: TInput, options?: WorkflowStreamOptions]\n ): WorkflowStreamResult<TOutput> {\n const input = args[0];\n const options = args[1] as WorkflowStreamOptions | undefined;\n\n let resolveOutput: (value: TOutput) => void;\n let rejectOutput: (error: unknown) => void;\n const outputPromise = new Promise<TOutput>((res, rej) => {\n resolveOutput = res;\n rejectOutput = rej;\n });\n\n // Prevent unhandled rejection warning if the consumer never awaits `output`.\n // The original promise still rejects normally when awaited.\n outputPromise.catch(() => {});\n\n const stream = createUIMessageStream({\n execute: async ({ writer }) => {\n const state: RuntimeState = {\n ctx,\n output: input,\n mode: \"stream\",\n writer,\n };\n\n try {\n await this.execute(state);\n resolveOutput(state.output as TOutput);\n } catch (error) {\n rejectOutput!(error);\n throw error;\n }\n },\n ...(options?.onError ? { onError: options.onError } : {}),\n ...(options?.onFinish ? { onFinish: options.onFinish } : {}),\n });\n\n return {\n stream,\n output: outputPromise,\n };\n }\n\n // ── Internal: execute pipeline ────────────────────────────────\n\n protected async execute(state: RuntimeState): Promise<void> {\n if (this.steps.length === 0) {\n throw new Error(\"Workflow has no steps. Add at least one step before calling generate() or stream().\");\n }\n\n let pendingError: { error: unknown; stepId: string } | null = null;\n\n for (const node of this.steps) {\n if (node.type === \"finally\") {\n await node.execute(state);\n continue;\n }\n\n if (node.type === \"catch\") {\n if (!pendingError) continue;\n try {\n state.output = await node.catchFn({\n error: pendingError.error,\n ctx: state.ctx,\n lastOutput: state.output,\n stepId: pendingError.stepId,\n });\n pendingError = null;\n } catch (catchError) {\n pendingError = { error: catchError, stepId: node.id };\n }\n continue;\n }\n\n // type === \"step\" — skip while in error state\n if (pendingError) continue;\n\n try {\n await node.execute(state);\n } catch (error) {\n pendingError = { error, stepId: node.id };\n }\n }\n\n if (pendingError) throw pendingError.error;\n }\n\n // ── Internal: execute a nested workflow within a step/loop ─────\n // Defined on SealedWorkflow (not Workflow) because TypeScript's protected\n // access rules only allow calling workflow.execute() from the same class.\n\n protected async executeNestedWorkflow(\n state: RuntimeState,\n workflow: SealedWorkflow<TContext, unknown, unknown>,\n ): Promise<void> {\n await workflow.execute(state);\n }\n\n // ── Internal: execute an agent within a step/branch ───────────\n // In stream mode, output extraction awaits the full stream before returning.\n // Streaming benefits the client (incremental output), not pipeline throughput —\n // each step still runs sequentially.\n\n protected async executeAgent<TAgentInput, TNextOutput>(\n state: RuntimeState,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n agent: Agent<TContext, any, TNextOutput>,\n ctx: TContext,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options?: AgentStepHooks<TContext, any, TNextOutput>,\n ): Promise<void> {\n const input = state.output as TAgentInput;\n const hasStructuredOutput = agent.hasOutput;\n\n if (state.mode === \"stream\" && state.writer) {\n const result = await (agent.stream as (ctx: TContext, input: unknown) => Promise<StreamTextResult>)(ctx, state.output);\n\n if (options?.handleStream) {\n await options.handleStream({ result, writer: state.writer, ctx });\n } else {\n state.writer.merge(result.toUIMessageStream());\n }\n\n if (options?.onStreamResult) {\n await options.onStreamResult({ result, ctx, input });\n }\n\n if (options?.mapStreamResult) {\n state.output = await options.mapStreamResult({ result, ctx, input });\n } else {\n state.output = await extractOutput(result, hasStructuredOutput);\n }\n } else {\n const result = await (agent.generate as (ctx: TContext, input: unknown) => Promise<GenerateTextResult>)(ctx, state.output);\n\n if (options?.onGenerateResult) {\n await options.onGenerateResult({ result, ctx, input });\n }\n\n if (options?.mapGenerateResult) {\n state.output = await options.mapGenerateResult({ result, ctx, input });\n } else {\n state.output = await extractOutput(result, hasStructuredOutput);\n }\n }\n }\n}\n\n// ── Workflow ────────────────────────────────────────────────────────\n\nexport class Workflow<\n TContext,\n TInput = void,\n TOutput = void,\n> extends SealedWorkflow<TContext, TInput, TOutput> {\n\n private constructor(steps: ReadonlyArray<StepNode> = [], id?: string) {\n super(steps, id);\n }\n\n static create<TContext, TInput = void>(options?: { id?: string }): Workflow<TContext, TInput, TInput> {\n return new Workflow<TContext, TInput, TInput>([], options?.id);\n }\n\n static from<TContext, TInput, TOutput>(\n agent: Agent<TContext, TInput, TOutput>,\n options?: StepOptions<TContext, TInput, TOutput>\n ): Workflow<TContext, TInput, TOutput> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, any>([]).step(agent, options);\n }\n\n // ── step: agent overload ──────────────────────────────────────\n\n step<TNextOutput>(\n agent: Agent<TContext, TOutput, TNextOutput>,\n options?: StepOptions<TContext, TOutput, TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── step: nested workflow overload ─────────────────────────────\n\n step<TNextOutput>(\n workflow: SealedWorkflow<TContext, TOutput, TNextOutput>,\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── step: transform overload (replaces map + tap) ─────────────\n\n step<TNextOutput>(\n id: string,\n fn: (params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── step: implementation ──────────────────────────────────────\n\n step<TNextOutput>(\n target: Agent<TContext, TOutput, TNextOutput> | SealedWorkflow<TContext, TOutput, TNextOutput> | string,\n optionsOrFn?: StepOptions<TContext, TOutput, TNextOutput> | ((params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>)\n ): Workflow<TContext, TInput, TNextOutput> {\n // Nested workflow overload: step(workflow)\n if (target instanceof SealedWorkflow) {\n const workflow = target;\n const node: StepNode = {\n type: \"step\",\n id: workflow.id ?? \"nested-workflow\",\n execute: async (state) => {\n await this.executeNestedWorkflow(state, workflow as SealedWorkflow<TContext, unknown, unknown>);\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n // Transform overload: step(id, fn)\n if (typeof target === \"string\") {\n if (typeof optionsOrFn !== \"function\") {\n throw new Error(`Workflow step(\"${target}\"): second argument must be a function`);\n }\n const fn = optionsOrFn as (params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>;\n const node: StepNode = {\n type: \"step\",\n id: target,\n execute: async (state) => {\n state.output = await fn({\n ctx: state.ctx as Readonly<TContext>,\n input: state.output as TOutput,\n });\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n // Agent overload: step(agent, options?)\n const agent = target;\n const options = optionsOrFn as StepOptions<TContext, TOutput, TNextOutput> | undefined;\n const node: StepNode = {\n type: \"step\",\n id: agent.id,\n execute: async (state) => {\n const ctx = state.ctx as TContext;\n await this.executeAgent(state, agent, ctx, options);\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n // ── branch: predicate routing (array) ─────────────────────────\n\n branch<TNextOutput>(\n cases: BranchCase<TContext, TOutput, TNextOutput>[]\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── branch: key routing (select) ──────────────────────────────\n\n branch<TKeys extends string, TNextOutput>(\n config: BranchSelect<TContext, TOutput, TKeys, TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── branch: implementation ────────────────────────────────────\n\n branch<TKeys extends string, TNextOutput>(\n casesOrConfig: BranchCase<TContext, TOutput, TNextOutput>[] | BranchSelect<TContext, TOutput, TKeys, TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput> {\n if (Array.isArray(casesOrConfig)) {\n return this.branchPredicate(casesOrConfig);\n }\n return this.branchSelect(casesOrConfig);\n }\n\n private branchPredicate<TNextOutput>(\n cases: BranchCase<TContext, TOutput, TNextOutput>[]\n ): Workflow<TContext, TInput, TNextOutput> {\n const node: StepNode = {\n type: \"step\",\n id: \"branch:predicate\",\n execute: async (state) => {\n const ctx = state.ctx as TContext;\n const input = state.output as TOutput;\n\n for (const branchCase of cases) {\n if (branchCase.when) {\n const match = await branchCase.when({ ctx, input });\n if (!match) continue;\n }\n\n // Matched (or no `when` = default)\n await this.executeAgent(state, branchCase.agent, ctx, branchCase);\n return;\n }\n\n throw new WorkflowBranchError(\"predicate\", `No branch matched and no default branch (a case without \\`when\\`) was provided. Input: ${JSON.stringify(input)}`);\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n private branchSelect<TKeys extends string, TNextOutput>(\n config: BranchSelect<TContext, TOutput, TKeys, TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput> {\n const node: StepNode = {\n type: \"step\",\n id: \"branch:select\",\n execute: async (state) => {\n const ctx = state.ctx as TContext;\n const input = state.output as TOutput;\n const key = await config.select({ ctx, input });\n\n let agent = config.agents[key];\n if (!agent) {\n if (config.fallback) {\n agent = config.fallback;\n } else {\n throw new WorkflowBranchError(\"select\", `No agent found for key \"${key}\" and no fallback provided. Available keys: ${Object.keys(config.agents).join(\", \")}`);\n }\n }\n\n await this.executeAgent(state, agent, ctx, config);\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n // ── foreach: array iteration ─────────────────────────────────\n\n foreach<TNextOutput>(\n target: Agent<TContext, ElementOf<TOutput>, TNextOutput> | SealedWorkflow<TContext, ElementOf<TOutput>, TNextOutput>,\n options?: { concurrency?: number },\n ): Workflow<TContext, TInput, TNextOutput[]> {\n const concurrency = options?.concurrency ?? 1;\n const isWorkflow = target instanceof SealedWorkflow;\n const id = isWorkflow ? (target.id ?? \"foreach\") : `foreach:${(target as Agent<TContext, ElementOf<TOutput>, TNextOutput>).id}`;\n\n const node: StepNode = {\n type: \"step\",\n id,\n execute: async (state) => {\n const items = state.output;\n if (!Array.isArray(items)) {\n throw new Error(`foreach \"${id}\": expected array input, got ${typeof items}`);\n }\n\n const ctx = state.ctx as TContext;\n const results: unknown[] = new Array(items.length);\n\n // Streaming is intentionally not propagated to foreach items —\n // each item runs in generate mode because merging interleaved\n // streams from parallel items into a single writer is not supported.\n const executeItem = async (item: unknown, index: number) => {\n const itemState: RuntimeState = { ctx: state.ctx, output: item, mode: \"generate\" };\n if (isWorkflow) {\n await this.executeNestedWorkflow(itemState, target as SealedWorkflow<TContext, unknown, unknown>);\n } else {\n await this.executeAgent(itemState, target as Agent<TContext, unknown, TNextOutput>, ctx);\n }\n results[index] = itemState.output;\n };\n\n if (concurrency <= 1) {\n for (let i = 0; i < items.length; i++) {\n await executeItem(items[i], i);\n }\n } else {\n for (let i = 0; i < items.length; i += concurrency) {\n const batch = items.slice(i, i + concurrency);\n await Promise.all(batch.map((item, j) => executeItem(item, i + j)));\n }\n }\n\n state.output = results;\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput[]>([...this.steps, node] as any, this.id);\n }\n\n // ── repeat: conditional loop ─────────────────────────────────\n\n repeat(\n target: Agent<TContext, TOutput, TOutput> | SealedWorkflow<TContext, TOutput, TOutput>,\n options: RepeatOptions<TContext, TOutput>,\n ): Workflow<TContext, TInput, TOutput> {\n const maxIterations = options.maxIterations ?? 10;\n const isWorkflow = target instanceof SealedWorkflow;\n const id = isWorkflow ? (target.id ?? \"repeat\") : `repeat:${(target as Agent<TContext, TOutput, TOutput>).id}`;\n const predicate: LoopPredicate<TContext, TOutput> = options.until\n ?? (async (p) => !(await options.while!(p)));\n\n const node: StepNode = {\n type: \"step\",\n id,\n execute: async (state) => {\n const ctx = state.ctx as TContext;\n\n for (let i = 1; i <= maxIterations; i++) {\n if (isWorkflow) {\n await this.executeNestedWorkflow(state, target as SealedWorkflow<TContext, unknown, unknown>);\n } else {\n await this.executeAgent(state, target as Agent<TContext, TOutput, TOutput>, ctx);\n }\n\n const done = await predicate({\n output: state.output as TOutput,\n ctx: ctx as Readonly<TContext>,\n iterations: i,\n });\n if (done) return;\n }\n\n throw new WorkflowLoopError(maxIterations, maxIterations);\n },\n };\n return new Workflow<TContext, TInput, TOutput>([...this.steps, node], this.id);\n }\n\n // ── catch ─────────────────────────────────────────────────────\n\n catch(\n id: string,\n fn: (params: { error: unknown; ctx: Readonly<TContext>; lastOutput: TOutput; stepId: string }) => MaybePromise<TOutput>\n ): Workflow<TContext, TInput, TOutput> {\n if (!this.steps.some(s => s.type === \"step\")) {\n throw new Error(`Workflow: catch(\"${id}\") requires at least one preceding step.`);\n }\n const node: StepNode = {\n type: \"catch\",\n id,\n catchFn: fn as (params: { error: unknown; ctx: unknown; lastOutput: unknown; stepId: string }) => MaybePromise<unknown>,\n };\n return new Workflow<TContext, TInput, TOutput>([...this.steps, node], this.id);\n }\n\n // ── finally (terminal — returns sealed workflow) ──────────────\n\n finally(\n id: string,\n fn: (params: { ctx: Readonly<TContext> }) => MaybePromise<void>\n ): SealedWorkflow<TContext, TInput, TOutput> {\n const node: StepNode = {\n type: \"finally\",\n id,\n execute: async (state) => {\n await fn({ ctx: state.ctx as Readonly<TContext> });\n },\n };\n return new SealedWorkflow<TContext, TInput, TOutput>([...this.steps, node], this.id);\n }\n}\n\n"],"mappings":"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","names":["import_ai","import_ai","node"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/agent.ts","../src/tool-provider.ts","../src/utils.ts","../src/workflow.ts"],"sourcesContent":["export { Agent } from \"./agent\";\nexport type {\n AgentConfig,\n GenerateTextResult,\n StreamTextResult,\n} from \"./agent\";\n\nexport { Workflow, WorkflowBranchError, WorkflowLoopError } from \"./workflow\";\nexport type { SealedWorkflow } from \"./workflow\";\nexport type {\n AgentStepHooks,\n StepOptions,\n BranchCase,\n BranchSelect,\n RepeatOptions,\n WorkflowResult,\n WorkflowStreamResult,\n WorkflowStreamOptions,\n} from \"./workflow\";\n\nexport { defineTool } from \"./tool-provider\";\nexport type { ToolProviderConfig, ToolExecuteOptions, IToolProvider } from \"./tool-provider\";\n\nexport type { MaybePromise, Resolvable } from \"./utils\";\n","import {\n generateText,\n streamText,\n tool,\n Output,\n type GenerateTextResult as AIGenerateTextResult,\n type StreamTextResult as AIStreamTextResult,\n type UIMessageStreamWriter,\n type ModelMessage,\n type LanguageModel,\n type Tool,\n type ToolSet,\n type StopCondition,\n type ToolChoice,\n type OnStepFinishEvent,\n type OnFinishEvent,\n} from \"ai\";\n\n// Extract the Output interface type from the Output.object return type\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype OutputType<T = any> = ReturnType<typeof Output.object<T>>;\nimport type { ZodType } from \"zod\";\nimport { isToolProvider, TOOL_PROVIDER_BRAND, type IToolProvider } from \"./tool-provider\";\nimport { extractOutput, getActiveWriter, resolveValue, type MaybePromise, type Resolvable } from \"./utils\";\n\n// Tools config accepts both AI SDK tools and context-aware ToolProviders\ntype AgentToolSet<TContext> = Record<string, Tool | IToolProvider<TContext>>;\n\n// ── Result type aliases ─────────────────────────────────────────────\n\nexport type GenerateTextResult<TOOLS extends ToolSet = ToolSet, OUTPUT extends OutputType = OutputType> = AIGenerateTextResult<TOOLS, OUTPUT>;\nexport type StreamTextResult<TOOLS extends ToolSet = ToolSet, OUTPUT extends OutputType = OutputType> = AIStreamTextResult<TOOLS, OUTPUT>;\n\n// ── AI SDK passthrough types ────────────────────────────────────────\n\n// Extract options types from both AI SDK entry points\ntype StreamTextOptions = Parameters<typeof streamText>[0];\ntype GenerateTextOptions = Parameters<typeof generateText>[0];\n\n// Keys we replace with resolvable or context-enriched versions\ntype ManagedKeys =\n | 'model' | 'system' | 'prompt' | 'messages'\n | 'tools' | 'activeTools' | 'toolChoice' | 'stopWhen'\n | 'output' | 'onFinish' | 'onStepFinish' | 'onError';\n\n// Combine options from both streamText and generateText.\n// Each side contributes its unique props; shared props merge naturally.\n// Stream-only props (onChunk, onAbort) are ignored by generateText.\n// Generate-only props (experimental_include.responseBody) are ignored by streamText.\ntype AIPassthroughOptions =\n Omit<StreamTextOptions, ManagedKeys> &\n Omit<GenerateTextOptions, ManagedKeys>;\n\n// ── Resolved config (output of resolveConfig / resolveConfigAsync) ──\n\ninterface ResolvedAgentConfig {\n model: LanguageModel;\n prompt: string | undefined;\n system: string | undefined;\n messages: ModelMessage[] | undefined;\n tools: Record<string, Tool>;\n activeTools: string[] | undefined;\n toolChoice: ToolChoice<ToolSet> | undefined;\n stopWhen: StopCondition<ToolSet> | Array<StopCondition<ToolSet>> | undefined;\n}\n\n// ── Agent Configuration ─────────────────────────────────────────────\n\nexport interface AgentConfig<\n TContext,\n TInput = void,\n TOutput = void,\n> extends AIPassthroughOptions {\n // ── Custom (not in AI SDK) ──\n id: string;\n description?: string;\n input?: ZodType<TInput>;\n output?: OutputType<TOutput>;\n\n // ── Resolvable (our versions of AI SDK properties) ──\n model: Resolvable<TContext, TInput, LanguageModel>;\n system?: Resolvable<TContext, TInput, string>;\n prompt?: Resolvable<TContext, TInput, string>;\n messages?: Resolvable<TContext, TInput, ModelMessage[]>;\n tools?: Resolvable<TContext, TInput, AgentToolSet<TContext>>;\n activeTools?: Resolvable<TContext, TInput, string[]>;\n toolChoice?: Resolvable<TContext, TInput, ToolChoice<ToolSet>>;\n stopWhen?: Resolvable<TContext, TInput, StopCondition<ToolSet> | Array<StopCondition<ToolSet>>>;\n\n // ── Context-enriched callbacks (replace AI SDK versions) ──\n // `writer` is available when the agent runs inside a streaming workflow.\n onStepFinish?: (params: { result: OnStepFinishEvent; ctx: Readonly<TContext>; input: TInput; writer?: UIMessageStreamWriter }) => MaybePromise<void>;\n onFinish?: (params: { result: OnFinishEvent; ctx: Readonly<TContext>; input: TInput; writer?: UIMessageStreamWriter }) => MaybePromise<void>;\n onError?: (params: { error: unknown; ctx: Readonly<TContext>; input: TInput; writer?: UIMessageStreamWriter }) => MaybePromise<void>;\n}\n\n// ── Agent ───────────────────────────────────────────────────────────\n\nexport class Agent<\n TContext,\n TInput = void,\n TOutput = void,\n> {\n readonly id: string;\n readonly description: string;\n readonly hasOutput: boolean;\n private readonly config: AgentConfig<TContext, TInput, TOutput>;\n private readonly _hasDynamicConfig: boolean;\n private readonly _resolvedStaticTools: Record<string, Tool> | null = null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private readonly _passthrough: Record<string, any>;\n private readonly _onStepFinish: AgentConfig<TContext, TInput, TOutput>['onStepFinish'];\n private readonly _onFinish: AgentConfig<TContext, TInput, TOutput>['onFinish'];\n\n constructor(config: AgentConfig<TContext, TInput, TOutput>) {\n this.id = config.id;\n this.description = config.description ?? \"\";\n this.hasOutput = config.output !== undefined;\n this.config = config;\n this._hasDynamicConfig = [\n config.model, config.system, config.prompt,\n config.messages, config.tools, config.activeTools,\n config.toolChoice, config.stopWhen,\n ].some(v => typeof v === \"function\");\n\n // Cache tools when config is static and contains no ToolProviders.\n // Avoids re-iterating the tools map on every generate()/stream() call.\n if (!this._hasDynamicConfig) {\n const rawTools = (config.tools as AgentToolSet<TContext> | undefined) ?? {};\n const hasProvider = Object.values(rawTools).some(v => isToolProvider(v));\n if (!hasProvider) {\n this._resolvedStaticTools = rawTools as Record<string, Tool>;\n }\n }\n\n // Pre-compute the passthrough (AI SDK options we don't manage) once,\n // rather than destructuring on every generate()/stream() call.\n const {\n id: _id, description: _desc, input: _inputSchema, output: _output,\n model: _m, system: _s, prompt: _p, messages: _msg,\n tools: _t, activeTools: _at, toolChoice: _tc, stopWhen: _sw,\n onStepFinish, onFinish, onError: _onError,\n ...passthrough\n } = config;\n this._passthrough = passthrough;\n this._onStepFinish = onStepFinish;\n this._onFinish = onFinish;\n }\n\n async generate(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<GenerateTextResult> {\n const input = args[0] as TInput;\n const resolved = await this.resolveConfig(ctx, input);\n const options = this.buildCallOptions(resolved, ctx, input);\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return await generateText(options as any);\n } catch (error: unknown) {\n if (this.config.onError) {\n await this.config.onError({ error, ctx, input, writer: getActiveWriter() });\n }\n throw error;\n }\n }\n\n async stream(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<StreamTextResult> {\n const input = args[0] as TInput;\n const resolved = await this.resolveConfig(ctx, input);\n const options = this.buildCallOptions(resolved, ctx, input);\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return streamText({\n ...options,\n onError: this.config.onError\n ? ({ error }: { error: unknown }) => this.config.onError!({ error, ctx, input, writer: getActiveWriter() })\n : undefined,\n } as any);\n }\n\n asTool(ctx: TContext, options?: {\n mapOutput?: (result: GenerateTextResult) => MaybePromise<TOutput>;\n }): Tool {\n return this.createToolInstance(ctx, options);\n }\n\n asToolProvider(options?: {\n mapOutput?: (result: GenerateTextResult) => MaybePromise<TOutput>;\n }): IToolProvider<TContext> {\n if (!this.config.input) {\n throw new Error(`Agent \"${this.id}\": asToolProvider() requires an input schema`);\n }\n\n return {\n [TOOL_PROVIDER_BRAND]: true as const,\n createTool: (ctx: Readonly<TContext>) => this.createToolInstance(ctx as TContext, options),\n };\n }\n\n private createToolInstance(ctx: TContext, options?: {\n mapOutput?: (result: GenerateTextResult) => MaybePromise<TOutput>;\n }): Tool {\n if (!this.config.input) {\n throw new Error(`Agent \"${this.id}\": asTool() requires an input schema`);\n }\n\n return tool({\n description: this.description,\n parameters: this.config.input,\n execute: async (toolInput: TInput) => {\n // When inside a streaming workflow, automatically use stream() and merge to the active writer.\n // Otherwise fall back to generate().\n const writer = getActiveWriter();\n if (writer) {\n const result = await (this.stream as (ctx: TContext, input: TInput) => Promise<StreamTextResult>)(ctx, toolInput);\n writer.merge(result.toUIMessageStream());\n if (options?.mapOutput) return options.mapOutput(result as unknown as GenerateTextResult);\n return extractOutput(result, this.hasOutput);\n }\n const result = await (this.generate as (ctx: TContext, input: TInput) => Promise<GenerateTextResult>)(ctx, toolInput);\n if (options?.mapOutput) return options.mapOutput(result);\n return extractOutput(result, this.hasOutput);\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private buildCallOptions(resolved: ResolvedAgentConfig, ctx: TContext, input: TInput): Record<string, any> {\n return {\n ...this._passthrough,\n model: resolved.model,\n tools: resolved.tools,\n activeTools: resolved.activeTools,\n toolChoice: resolved.toolChoice,\n stopWhen: resolved.stopWhen,\n ...(resolved.messages\n ? { messages: resolved.messages }\n : { prompt: resolved.prompt ?? \"\" }),\n ...(resolved.system ? { system: resolved.system } : {}),\n ...(this.config.output ? { output: this.config.output } : {}),\n onStepFinish: this._onStepFinish\n ? (event: OnStepFinishEvent) => this._onStepFinish!({ result: event, ctx, input, writer: getActiveWriter() })\n : undefined,\n onFinish: this._onFinish\n ? (event: OnFinishEvent) => this._onFinish!({ result: event, ctx, input, writer: getActiveWriter() })\n : undefined,\n };\n }\n\n private resolveConfig(ctx: TContext, input: TInput): ResolvedAgentConfig | Promise<ResolvedAgentConfig> {\n if (!this._hasDynamicConfig) {\n return {\n model: this.config.model as LanguageModel,\n prompt: this.config.prompt as string | undefined,\n system: this.config.system as string | undefined,\n messages: this.config.messages as ModelMessage[] | undefined,\n tools: this._resolvedStaticTools ?? this.resolveTools(\n (this.config.tools as AgentToolSet<TContext> | undefined) ?? {}, ctx\n ),\n activeTools: this.config.activeTools as string[] | undefined,\n toolChoice: this.config.toolChoice as ToolChoice<ToolSet> | undefined,\n stopWhen: this.config.stopWhen as StopCondition<ToolSet> | Array<StopCondition<ToolSet>> | undefined,\n };\n }\n return this.resolveConfigAsync(ctx, input);\n }\n\n private async resolveConfigAsync(ctx: TContext, input: TInput): Promise<ResolvedAgentConfig> {\n const [model, prompt, system, messages, rawTools, activeTools, toolChoice, stopWhen] = await Promise.all([\n resolveValue(this.config.model, ctx, input),\n resolveValue(this.config.prompt, ctx, input),\n resolveValue(this.config.system, ctx, input),\n resolveValue(this.config.messages, ctx, input),\n resolveValue(this.config.tools, ctx, input),\n resolveValue(this.config.activeTools, ctx, input),\n resolveValue(this.config.toolChoice, ctx, input),\n resolveValue(this.config.stopWhen, ctx, input),\n ]);\n const tools = this.resolveTools(rawTools ?? {}, ctx);\n return { model, prompt, system, messages, tools, activeTools, toolChoice, stopWhen };\n }\n\n private resolveTools(\n tools: AgentToolSet<TContext>,\n ctx: TContext\n ): Record<string, Tool> {\n const entries = Object.entries(tools);\n if (entries.length === 0) return tools as Record<string, Tool>;\n let hasProvider = false;\n const resolved: Record<string, Tool> = {};\n for (const [key, toolOrProvider] of entries) {\n if (isToolProvider<TContext>(toolOrProvider)) {\n hasProvider = true;\n resolved[key] = toolOrProvider.createTool(ctx as Readonly<TContext>);\n } else {\n resolved[key] = toolOrProvider as Tool;\n }\n }\n return hasProvider ? resolved : (tools as Record<string, Tool>);\n }\n}\n","import { tool, type Tool, type ToolExecutionOptions, type FlexibleSchema, type UIMessageStreamWriter } from \"ai\";\nimport { getActiveWriter } from \"./utils\";\n\nexport const TOOL_PROVIDER_BRAND = Symbol.for(\"agent-workflow.ToolProvider\");\n\nexport type ToolExecuteOptions = ToolExecutionOptions & {\n writer?: UIMessageStreamWriter;\n};\n\nexport type ToolProviderConfig<TContext, TInput, TOutput> = {\n description?: string;\n input: FlexibleSchema<TInput>;\n output?: FlexibleSchema<unknown>;\n providerOptions?: unknown;\n execute: (input: TInput, ctx: Readonly<TContext>, options: ToolExecuteOptions) => Promise<TOutput>;\n};\n\nexport interface IToolProvider<TContext> {\n readonly [TOOL_PROVIDER_BRAND]: true;\n createTool(context: Readonly<TContext>): Tool;\n}\n\nexport class ToolProvider<\n TContext,\n TInput = unknown,\n TOutput = unknown,\n> implements IToolProvider<TContext> {\n readonly [TOOL_PROVIDER_BRAND] = true as const;\n private readonly config: ToolProviderConfig<TContext, TInput, TOutput>;\n\n constructor(config: ToolProviderConfig<TContext, TInput, TOutput>) {\n this.config = config;\n }\n\n createTool(context: Readonly<TContext>): Tool {\n const { execute, input: inputSchema, ...toolDef } = this.config;\n return tool({\n ...toolDef,\n parameters: inputSchema,\n execute: (input: TInput, options?: ToolExecutionOptions) => execute(input, context, { ...options, writer: getActiveWriter() } as ToolExecuteOptions),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any);\n }\n}\n\nexport function defineTool<TContext>() {\n return <TInput, TOutput>(\n config: ToolProviderConfig<TContext, TInput, TOutput>\n ): ToolProvider<TContext, TInput, TOutput> => new ToolProvider(config);\n}\n\nexport function isToolProvider<TContext>(obj: unknown): obj is IToolProvider<TContext> {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n TOOL_PROVIDER_BRAND in obj\n );\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { UIMessageStreamWriter } from \"ai\";\n\n// ── Stream writer context ────────────────────────────────────────────\n// Invisible to the user. The workflow sets the writer before agent execution;\n// tools and sub-agents read it automatically via getActiveWriter().\n\nconst writerStorage = new AsyncLocalStorage<UIMessageStreamWriter>();\n\nexport function runWithWriter<T>(writer: UIMessageStreamWriter, fn: () => T): T {\n return writerStorage.run(writer, fn);\n}\n\nexport function getActiveWriter(): UIMessageStreamWriter | undefined {\n return writerStorage.getStore();\n}\n\n// ── Common types ─────────────────────────────────────────────────────\n\nexport type MaybePromise<T> = T | Promise<T>;\n\n/**\n * A value that can be static or derived from context and input.\n * Used for agent config fields that may need runtime resolution.\n *\n * Functions may return a Promise for async resolution; static values are always sync.\n */\nexport type Resolvable<TCtx, TInput, TValue> =\n | TValue\n | ((ctx: Readonly<TCtx>, input: TInput) => TValue | Promise<TValue>);\n\nexport function resolveValue<TCtx, TInput, TValue>(\n value: Resolvable<TCtx, TInput, TValue>,\n ctx: TCtx,\n input: TInput\n): TValue | Promise<TValue>;\nexport function resolveValue<TCtx, TInput, TValue>(\n value: Resolvable<TCtx, TInput, TValue> | undefined,\n ctx: TCtx,\n input: TInput\n): TValue | Promise<TValue> | undefined {\n if (typeof value === \"function\") {\n return (value as (ctx: TCtx, input: TInput) => TValue | Promise<TValue>)(ctx, input);\n }\n return value;\n}\n\n/**\n * Extract structured output from an AI SDK result, falling back to text.\n * Works for both generate (sync .output/.text) and stream (async .output/.text) results.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function extractOutput(result: any, hasStructuredOutput: boolean): Promise<unknown> {\n if (hasStructuredOutput) {\n const output = await result.output;\n if (output !== undefined) return output;\n }\n return await result.text;\n}\n","import {\n createUIMessageStream,\n type UIMessageStreamWriter,\n} from \"ai\";\nimport { type Agent, type GenerateTextResult, type StreamTextResult } from \"./agent\";\nimport { extractOutput, runWithWriter, type MaybePromise } from \"./utils\";\n\n// ── Error Types ─────────────────────────────────────────────────────\n\nexport class WorkflowBranchError extends Error {\n constructor(\n public readonly branchType: \"predicate\" | \"select\",\n message: string,\n ) {\n super(message);\n this.name = \"WorkflowBranchError\";\n }\n}\n\nexport class WorkflowLoopError extends Error {\n constructor(\n public readonly iterations: number,\n public readonly maxIterations: number,\n ) {\n super(`Loop exceeded maximum iterations (${maxIterations})`);\n this.name = \"WorkflowLoopError\";\n }\n}\n\n// ── Shared Agent Step Hooks ─────────────────────────────────────────\n\nexport interface AgentStepHooks<TContext, TOutput, TNextOutput> {\n mapGenerateResult?: (params: { result: GenerateTextResult; ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>;\n mapStreamResult?: (params: { result: StreamTextResult; ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>;\n onGenerateResult?: (params: { result: GenerateTextResult; ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<void>;\n onStreamResult?: (params: { result: StreamTextResult; ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<void>;\n handleStream?: (params: {\n result: StreamTextResult;\n writer: UIMessageStreamWriter;\n ctx: Readonly<TContext>;\n }) => MaybePromise<void>;\n}\n\n// ── Step Options ────────────────────────────────────────────────────\n\nexport type StepOptions<TContext, TOutput, TNextOutput> = AgentStepHooks<TContext, TOutput, TNextOutput>;\n\n// ── Branch Types ────────────────────────────────────────────────────\n\nexport interface BranchCase<TContext, TOutput, TNextOutput> extends AgentStepHooks<TContext, TOutput, TNextOutput> {\n when?: (params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<boolean>;\n agent: Agent<TContext, TOutput, TNextOutput>;\n}\n\nexport interface BranchSelect<TContext, TOutput, TKeys extends string, TNextOutput> extends AgentStepHooks<TContext, TOutput, TNextOutput> {\n select: (params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TKeys>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n agents: Record<TKeys, Agent<TContext, any, TNextOutput>>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n fallback?: Agent<TContext, any, TNextOutput>;\n}\n\n// ── Result Types ────────────────────────────────────────────────────\n\nexport interface WorkflowResult<TOutput> {\n output: TOutput;\n}\n\nexport interface WorkflowStreamResult<TOutput> {\n stream: ReadableStream;\n output: Promise<TOutput>;\n}\n\nexport interface WorkflowStreamOptions {\n onError?: (error: unknown) => string;\n onFinish?: () => MaybePromise<void>;\n}\n\n// ── Loop Types ──────────────────────────────────────────────────────\n\ntype LoopPredicate<TContext, TOutput> = (params: {\n output: TOutput;\n ctx: Readonly<TContext>;\n iterations: number;\n}) => MaybePromise<boolean>;\n\n// Exactly one of `until` or `while` — never both.\nexport type RepeatOptions<TContext, TOutput> =\n | { until: LoopPredicate<TContext, TOutput>; while?: never; maxIterations?: number }\n | { while: LoopPredicate<TContext, TOutput>; until?: never; maxIterations?: number };\n\n// Extracts the element type from an array type. Resolves to `never` for non-arrays,\n// making foreach uncallable at compile time when the previous step doesn't produce an array.\ntype ElementOf<T> = T extends readonly (infer E)[] ? E : never;\n\n// ── Step Node ───────────────────────────────────────────────────────\n\ntype StepNode =\n | { readonly type: \"step\"; readonly id: string; readonly execute: (state: RuntimeState) => MaybePromise<void> }\n | { readonly type: \"catch\"; readonly id: string; readonly catchFn: (params: { error: unknown; ctx: unknown; lastOutput: unknown; stepId: string }) => MaybePromise<unknown> }\n | { readonly type: \"finally\"; readonly id: string; readonly execute: (state: RuntimeState) => MaybePromise<void> };\n\ninterface RuntimeState {\n ctx: unknown;\n output: unknown;\n mode: \"generate\" | \"stream\";\n writer?: UIMessageStreamWriter;\n}\n\n// ── Sealed Workflow (returned by finally — execution only) ───────────\n\nexport class SealedWorkflow<\n TContext,\n TInput = void,\n TOutput = void,\n> {\n readonly id?: string;\n protected readonly steps: ReadonlyArray<StepNode>;\n\n protected constructor(steps: ReadonlyArray<StepNode>, id?: string) {\n this.steps = steps;\n this.id = id;\n }\n\n // ── Execution ─────────────────────────────────────────────────\n\n async generate(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<WorkflowResult<TOutput>> {\n const input = args[0];\n const state: RuntimeState = {\n ctx,\n output: input,\n mode: \"generate\",\n };\n\n await this.execute(state);\n\n return {\n output: state.output as TOutput,\n };\n }\n\n stream(\n ctx: TContext,\n ...args: TInput extends void\n ? [input?: TInput, options?: WorkflowStreamOptions]\n : [input: TInput, options?: WorkflowStreamOptions]\n ): WorkflowStreamResult<TOutput> {\n const input = args[0];\n const options = args[1] as WorkflowStreamOptions | undefined;\n\n let resolveOutput: (value: TOutput) => void;\n let rejectOutput: (error: unknown) => void;\n const outputPromise = new Promise<TOutput>((res, rej) => {\n resolveOutput = res;\n rejectOutput = rej;\n });\n\n // Prevent unhandled rejection warning if the consumer never awaits `output`.\n // The original promise still rejects normally when awaited.\n outputPromise.catch(() => {});\n\n const stream = createUIMessageStream({\n execute: async ({ writer }) => {\n const state: RuntimeState = {\n ctx,\n output: input,\n mode: \"stream\",\n writer,\n };\n\n try {\n await this.execute(state);\n resolveOutput(state.output as TOutput);\n } catch (error) {\n rejectOutput!(error);\n throw error;\n }\n },\n ...(options?.onError ? { onError: options.onError } : {}),\n ...(options?.onFinish ? { onFinish: options.onFinish } : {}),\n });\n\n return {\n stream,\n output: outputPromise,\n };\n }\n\n // ── Internal: execute pipeline ────────────────────────────────\n\n protected async execute(state: RuntimeState): Promise<void> {\n if (this.steps.length === 0) {\n throw new Error(\"Workflow has no steps. Add at least one step before calling generate() or stream().\");\n }\n\n let pendingError: { error: unknown; stepId: string } | null = null;\n\n for (const node of this.steps) {\n if (node.type === \"finally\") {\n await node.execute(state);\n continue;\n }\n\n if (node.type === \"catch\") {\n if (!pendingError) continue;\n try {\n state.output = await node.catchFn({\n error: pendingError.error,\n ctx: state.ctx,\n lastOutput: state.output,\n stepId: pendingError.stepId,\n });\n pendingError = null;\n } catch (catchError) {\n pendingError = { error: catchError, stepId: node.id };\n }\n continue;\n }\n\n // type === \"step\" — skip while in error state\n if (pendingError) continue;\n\n try {\n await node.execute(state);\n } catch (error) {\n pendingError = { error, stepId: node.id };\n }\n }\n\n if (pendingError) throw pendingError.error;\n }\n\n // ── Internal: execute a nested workflow within a step/loop ─────\n // Defined on SealedWorkflow (not Workflow) because TypeScript's protected\n // access rules only allow calling workflow.execute() from the same class.\n\n protected async executeNestedWorkflow(\n state: RuntimeState,\n workflow: SealedWorkflow<TContext, unknown, unknown>,\n ): Promise<void> {\n await workflow.execute(state);\n }\n\n // ── Internal: execute an agent within a step/branch ───────────\n // In stream mode, output extraction awaits the full stream before returning.\n // Streaming benefits the client (incremental output), not pipeline throughput —\n // each step still runs sequentially.\n\n protected async executeAgent<TAgentInput, TNextOutput>(\n state: RuntimeState,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n agent: Agent<TContext, any, TNextOutput>,\n ctx: TContext,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options?: AgentStepHooks<TContext, any, TNextOutput>,\n ): Promise<void> {\n const input = state.output as TAgentInput;\n const hasStructuredOutput = agent.hasOutput;\n\n if (state.mode === \"stream\" && state.writer) {\n const writer = state.writer;\n // Run inside writer context so tools (asTool, defineTool) can access the writer automatically\n await runWithWriter(writer, async () => {\n const result = await (agent.stream as (ctx: TContext, input: unknown) => Promise<StreamTextResult>)(ctx, state.output);\n\n if (options?.handleStream) {\n await options.handleStream({ result, writer, ctx });\n } else {\n writer.merge(result.toUIMessageStream());\n }\n\n if (options?.onStreamResult) {\n await options.onStreamResult({ result, ctx, input });\n }\n\n if (options?.mapStreamResult) {\n state.output = await options.mapStreamResult({ result, ctx, input });\n } else {\n state.output = await extractOutput(result, hasStructuredOutput);\n }\n });\n } else {\n const result = await (agent.generate as (ctx: TContext, input: unknown) => Promise<GenerateTextResult>)(ctx, state.output);\n\n if (options?.onGenerateResult) {\n await options.onGenerateResult({ result, ctx, input });\n }\n\n if (options?.mapGenerateResult) {\n state.output = await options.mapGenerateResult({ result, ctx, input });\n } else {\n state.output = await extractOutput(result, hasStructuredOutput);\n }\n }\n }\n}\n\n// ── Workflow ────────────────────────────────────────────────────────\n\nexport class Workflow<\n TContext,\n TInput = void,\n TOutput = void,\n> extends SealedWorkflow<TContext, TInput, TOutput> {\n\n private constructor(steps: ReadonlyArray<StepNode> = [], id?: string) {\n super(steps, id);\n }\n\n static create<TContext, TInput = void>(options?: { id?: string }): Workflow<TContext, TInput, TInput> {\n return new Workflow<TContext, TInput, TInput>([], options?.id);\n }\n\n static from<TContext, TInput, TOutput>(\n agent: Agent<TContext, TInput, TOutput>,\n options?: StepOptions<TContext, TInput, TOutput>\n ): Workflow<TContext, TInput, TOutput> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, any>([]).step(agent, options);\n }\n\n // ── step: agent overload ──────────────────────────────────────\n\n step<TNextOutput>(\n agent: Agent<TContext, TOutput, TNextOutput>,\n options?: StepOptions<TContext, TOutput, TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── step: nested workflow overload ─────────────────────────────\n\n step<TNextOutput>(\n workflow: SealedWorkflow<TContext, TOutput, TNextOutput>,\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── step: transform overload (replaces map + tap) ─────────────\n\n step<TNextOutput>(\n id: string,\n fn: (params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── step: implementation ──────────────────────────────────────\n\n step<TNextOutput>(\n target: Agent<TContext, TOutput, TNextOutput> | SealedWorkflow<TContext, TOutput, TNextOutput> | string,\n optionsOrFn?: StepOptions<TContext, TOutput, TNextOutput> | ((params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>)\n ): Workflow<TContext, TInput, TNextOutput> {\n // Nested workflow overload: step(workflow)\n if (target instanceof SealedWorkflow) {\n const workflow = target;\n const node: StepNode = {\n type: \"step\",\n id: workflow.id ?? \"nested-workflow\",\n execute: async (state) => {\n await this.executeNestedWorkflow(state, workflow as SealedWorkflow<TContext, unknown, unknown>);\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n // Transform overload: step(id, fn)\n if (typeof target === \"string\") {\n if (typeof optionsOrFn !== \"function\") {\n throw new Error(`Workflow step(\"${target}\"): second argument must be a function`);\n }\n const fn = optionsOrFn as (params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>;\n const node: StepNode = {\n type: \"step\",\n id: target,\n execute: async (state) => {\n state.output = await fn({\n ctx: state.ctx as Readonly<TContext>,\n input: state.output as TOutput,\n });\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n // Agent overload: step(agent, options?)\n const agent = target;\n const options = optionsOrFn as StepOptions<TContext, TOutput, TNextOutput> | undefined;\n const node: StepNode = {\n type: \"step\",\n id: agent.id,\n execute: async (state) => {\n const ctx = state.ctx as TContext;\n await this.executeAgent(state, agent, ctx, options);\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n // ── branch: predicate routing (array) ─────────────────────────\n\n branch<TNextOutput>(\n cases: BranchCase<TContext, TOutput, TNextOutput>[]\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── branch: key routing (select) ──────────────────────────────\n\n branch<TKeys extends string, TNextOutput>(\n config: BranchSelect<TContext, TOutput, TKeys, TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── branch: implementation ────────────────────────────────────\n\n branch<TKeys extends string, TNextOutput>(\n casesOrConfig: BranchCase<TContext, TOutput, TNextOutput>[] | BranchSelect<TContext, TOutput, TKeys, TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput> {\n if (Array.isArray(casesOrConfig)) {\n return this.branchPredicate(casesOrConfig);\n }\n return this.branchSelect(casesOrConfig);\n }\n\n private branchPredicate<TNextOutput>(\n cases: BranchCase<TContext, TOutput, TNextOutput>[]\n ): Workflow<TContext, TInput, TNextOutput> {\n const node: StepNode = {\n type: \"step\",\n id: \"branch:predicate\",\n execute: async (state) => {\n const ctx = state.ctx as TContext;\n const input = state.output as TOutput;\n\n for (const branchCase of cases) {\n if (branchCase.when) {\n const match = await branchCase.when({ ctx, input });\n if (!match) continue;\n }\n\n // Matched (or no `when` = default)\n await this.executeAgent(state, branchCase.agent, ctx, branchCase);\n return;\n }\n\n throw new WorkflowBranchError(\"predicate\", `No branch matched and no default branch (a case without \\`when\\`) was provided. Input: ${JSON.stringify(input)}`);\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n private branchSelect<TKeys extends string, TNextOutput>(\n config: BranchSelect<TContext, TOutput, TKeys, TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput> {\n const node: StepNode = {\n type: \"step\",\n id: \"branch:select\",\n execute: async (state) => {\n const ctx = state.ctx as TContext;\n const input = state.output as TOutput;\n const key = await config.select({ ctx, input });\n\n let agent = config.agents[key];\n if (!agent) {\n if (config.fallback) {\n agent = config.fallback;\n } else {\n throw new WorkflowBranchError(\"select\", `No agent found for key \"${key}\" and no fallback provided. Available keys: ${Object.keys(config.agents).join(\", \")}`);\n }\n }\n\n await this.executeAgent(state, agent, ctx, config);\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n // ── foreach: array iteration ─────────────────────────────────\n\n foreach<TNextOutput>(\n target: Agent<TContext, ElementOf<TOutput>, TNextOutput> | SealedWorkflow<TContext, ElementOf<TOutput>, TNextOutput>,\n options?: { concurrency?: number },\n ): Workflow<TContext, TInput, TNextOutput[]> {\n const concurrency = options?.concurrency ?? 1;\n const isWorkflow = target instanceof SealedWorkflow;\n const id = isWorkflow ? (target.id ?? \"foreach\") : `foreach:${(target as Agent<TContext, ElementOf<TOutput>, TNextOutput>).id}`;\n\n const node: StepNode = {\n type: \"step\",\n id,\n execute: async (state) => {\n const items = state.output;\n if (!Array.isArray(items)) {\n throw new Error(`foreach \"${id}\": expected array input, got ${typeof items}`);\n }\n\n const ctx = state.ctx as TContext;\n const results: unknown[] = new Array(items.length);\n\n // Streaming is intentionally not propagated to foreach items —\n // each item runs in generate mode because merging interleaved\n // streams from parallel items into a single writer is not supported.\n const executeItem = async (item: unknown, index: number) => {\n const itemState: RuntimeState = { ctx: state.ctx, output: item, mode: \"generate\" };\n if (isWorkflow) {\n await this.executeNestedWorkflow(itemState, target as SealedWorkflow<TContext, unknown, unknown>);\n } else {\n await this.executeAgent(itemState, target as Agent<TContext, unknown, TNextOutput>, ctx);\n }\n results[index] = itemState.output;\n };\n\n if (concurrency <= 1) {\n for (let i = 0; i < items.length; i++) {\n await executeItem(items[i], i);\n }\n } else {\n for (let i = 0; i < items.length; i += concurrency) {\n const batch = items.slice(i, i + concurrency);\n await Promise.all(batch.map((item, j) => executeItem(item, i + j)));\n }\n }\n\n state.output = results;\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput[]>([...this.steps, node] as any, this.id);\n }\n\n // ── repeat: conditional loop ─────────────────────────────────\n\n repeat(\n target: Agent<TContext, TOutput, TOutput> | SealedWorkflow<TContext, TOutput, TOutput>,\n options: RepeatOptions<TContext, TOutput>,\n ): Workflow<TContext, TInput, TOutput> {\n const maxIterations = options.maxIterations ?? 10;\n const isWorkflow = target instanceof SealedWorkflow;\n const id = isWorkflow ? (target.id ?? \"repeat\") : `repeat:${(target as Agent<TContext, TOutput, TOutput>).id}`;\n const predicate: LoopPredicate<TContext, TOutput> = options.until\n ?? (async (p) => !(await options.while!(p)));\n\n const node: StepNode = {\n type: \"step\",\n id,\n execute: async (state) => {\n const ctx = state.ctx as TContext;\n\n for (let i = 1; i <= maxIterations; i++) {\n if (isWorkflow) {\n await this.executeNestedWorkflow(state, target as SealedWorkflow<TContext, unknown, unknown>);\n } else {\n await this.executeAgent(state, target as Agent<TContext, TOutput, TOutput>, ctx);\n }\n\n const done = await predicate({\n output: state.output as TOutput,\n ctx: ctx as Readonly<TContext>,\n iterations: i,\n });\n if (done) return;\n }\n\n throw new WorkflowLoopError(maxIterations, maxIterations);\n },\n };\n return new Workflow<TContext, TInput, TOutput>([...this.steps, node], this.id);\n }\n\n // ── catch ─────────────────────────────────────────────────────\n\n catch(\n id: string,\n fn: (params: { error: unknown; ctx: Readonly<TContext>; lastOutput: TOutput; stepId: string }) => MaybePromise<TOutput>\n ): Workflow<TContext, TInput, TOutput> {\n if (!this.steps.some(s => s.type === \"step\")) {\n throw new Error(`Workflow: catch(\"${id}\") requires at least one preceding step.`);\n }\n const node: StepNode = {\n type: \"catch\",\n id,\n catchFn: fn as (params: { error: unknown; ctx: unknown; lastOutput: unknown; stepId: string }) => MaybePromise<unknown>,\n };\n return new Workflow<TContext, TInput, TOutput>([...this.steps, node], this.id);\n }\n\n // ── finally (terminal — returns sealed workflow) ──────────────\n\n finally(\n id: string,\n fn: (params: { ctx: Readonly<TContext> }) => MaybePromise<void>\n ): SealedWorkflow<TContext, TInput, TOutput> {\n const node: StepNode = {\n type: \"finally\",\n id,\n execute: async (state) => {\n await fn({ ctx: state.ctx as Readonly<TContext> });\n },\n };\n return new SealedWorkflow<TContext, TInput, TOutput>([...this.steps, node], this.id);\n }\n}\n\n"],"mappings":"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","names":["import_ai","result","import_ai","node"]}
package/dist/index.d.cts CHANGED
@@ -1,13 +1,16 @@
1
- import { Tool, FlexibleSchema, ToolExecutionOptions, streamText, generateText, Output, LanguageModel, ModelMessage, ToolChoice, ToolSet, StopCondition, OnStepFinishEvent, OnFinishEvent, GenerateTextResult as GenerateTextResult$1, StreamTextResult as StreamTextResult$1, UIMessageStreamWriter } from 'ai';
1
+ import { Tool, ToolExecutionOptions, UIMessageStreamWriter, FlexibleSchema, streamText, generateText, Output, LanguageModel, ModelMessage, ToolChoice, ToolSet, StopCondition, OnStepFinishEvent, OnFinishEvent, GenerateTextResult as GenerateTextResult$1, StreamTextResult as StreamTextResult$1 } from 'ai';
2
2
  import { ZodType } from 'zod';
3
3
 
4
4
  declare const TOOL_PROVIDER_BRAND: unique symbol;
5
+ type ToolExecuteOptions = ToolExecutionOptions & {
6
+ writer?: UIMessageStreamWriter;
7
+ };
5
8
  type ToolProviderConfig<TContext, TInput, TOutput> = {
6
9
  description?: string;
7
10
  input: FlexibleSchema<TInput>;
8
11
  output?: FlexibleSchema<unknown>;
9
12
  providerOptions?: unknown;
10
- execute: (input: TInput, ctx: Readonly<TContext>, options?: ToolExecutionOptions) => Promise<TOutput>;
13
+ execute: (input: TInput, ctx: Readonly<TContext>, options: ToolExecuteOptions) => Promise<TOutput>;
11
14
  };
12
15
  interface IToolProvider<TContext> {
13
16
  readonly [TOOL_PROVIDER_BRAND]: true;
@@ -56,16 +59,19 @@ interface AgentConfig<TContext, TInput = void, TOutput = void> extends AIPassthr
56
59
  result: OnStepFinishEvent;
57
60
  ctx: Readonly<TContext>;
58
61
  input: TInput;
62
+ writer?: UIMessageStreamWriter;
59
63
  }) => MaybePromise<void>;
60
64
  onFinish?: (params: {
61
65
  result: OnFinishEvent;
62
66
  ctx: Readonly<TContext>;
63
67
  input: TInput;
68
+ writer?: UIMessageStreamWriter;
64
69
  }) => MaybePromise<void>;
65
70
  onError?: (params: {
66
71
  error: unknown;
67
72
  ctx: Readonly<TContext>;
68
73
  input: TInput;
74
+ writer?: UIMessageStreamWriter;
69
75
  }) => MaybePromise<void>;
70
76
  }
71
77
  declare class Agent<TContext, TInput = void, TOutput = void> {
@@ -237,4 +243,4 @@ declare class Workflow<TContext, TInput = void, TOutput = void> extends SealedWo
237
243
  }) => MaybePromise<void>): SealedWorkflow<TContext, TInput, TOutput>;
238
244
  }
239
245
 
240
- export { Agent, type AgentConfig, type AgentStepHooks, type BranchCase, type BranchSelect, type GenerateTextResult, type IToolProvider, type MaybePromise, type RepeatOptions, type Resolvable, SealedWorkflow, type StepOptions, type StreamTextResult, type ToolProviderConfig, Workflow, WorkflowBranchError, WorkflowLoopError, type WorkflowResult, type WorkflowStreamOptions, type WorkflowStreamResult, defineTool };
246
+ export { Agent, type AgentConfig, type AgentStepHooks, type BranchCase, type BranchSelect, type GenerateTextResult, type IToolProvider, type MaybePromise, type RepeatOptions, type Resolvable, SealedWorkflow, type StepOptions, type StreamTextResult, type ToolExecuteOptions, type ToolProviderConfig, Workflow, WorkflowBranchError, WorkflowLoopError, type WorkflowResult, type WorkflowStreamOptions, type WorkflowStreamResult, defineTool };
package/dist/index.d.ts CHANGED
@@ -1,13 +1,16 @@
1
- import { Tool, FlexibleSchema, ToolExecutionOptions, streamText, generateText, Output, LanguageModel, ModelMessage, ToolChoice, ToolSet, StopCondition, OnStepFinishEvent, OnFinishEvent, GenerateTextResult as GenerateTextResult$1, StreamTextResult as StreamTextResult$1, UIMessageStreamWriter } from 'ai';
1
+ import { Tool, ToolExecutionOptions, UIMessageStreamWriter, FlexibleSchema, streamText, generateText, Output, LanguageModel, ModelMessage, ToolChoice, ToolSet, StopCondition, OnStepFinishEvent, OnFinishEvent, GenerateTextResult as GenerateTextResult$1, StreamTextResult as StreamTextResult$1 } from 'ai';
2
2
  import { ZodType } from 'zod';
3
3
 
4
4
  declare const TOOL_PROVIDER_BRAND: unique symbol;
5
+ type ToolExecuteOptions = ToolExecutionOptions & {
6
+ writer?: UIMessageStreamWriter;
7
+ };
5
8
  type ToolProviderConfig<TContext, TInput, TOutput> = {
6
9
  description?: string;
7
10
  input: FlexibleSchema<TInput>;
8
11
  output?: FlexibleSchema<unknown>;
9
12
  providerOptions?: unknown;
10
- execute: (input: TInput, ctx: Readonly<TContext>, options?: ToolExecutionOptions) => Promise<TOutput>;
13
+ execute: (input: TInput, ctx: Readonly<TContext>, options: ToolExecuteOptions) => Promise<TOutput>;
11
14
  };
12
15
  interface IToolProvider<TContext> {
13
16
  readonly [TOOL_PROVIDER_BRAND]: true;
@@ -56,16 +59,19 @@ interface AgentConfig<TContext, TInput = void, TOutput = void> extends AIPassthr
56
59
  result: OnStepFinishEvent;
57
60
  ctx: Readonly<TContext>;
58
61
  input: TInput;
62
+ writer?: UIMessageStreamWriter;
59
63
  }) => MaybePromise<void>;
60
64
  onFinish?: (params: {
61
65
  result: OnFinishEvent;
62
66
  ctx: Readonly<TContext>;
63
67
  input: TInput;
68
+ writer?: UIMessageStreamWriter;
64
69
  }) => MaybePromise<void>;
65
70
  onError?: (params: {
66
71
  error: unknown;
67
72
  ctx: Readonly<TContext>;
68
73
  input: TInput;
74
+ writer?: UIMessageStreamWriter;
69
75
  }) => MaybePromise<void>;
70
76
  }
71
77
  declare class Agent<TContext, TInput = void, TOutput = void> {
@@ -237,4 +243,4 @@ declare class Workflow<TContext, TInput = void, TOutput = void> extends SealedWo
237
243
  }) => MaybePromise<void>): SealedWorkflow<TContext, TInput, TOutput>;
238
244
  }
239
245
 
240
- export { Agent, type AgentConfig, type AgentStepHooks, type BranchCase, type BranchSelect, type GenerateTextResult, type IToolProvider, type MaybePromise, type RepeatOptions, type Resolvable, SealedWorkflow, type StepOptions, type StreamTextResult, type ToolProviderConfig, Workflow, WorkflowBranchError, WorkflowLoopError, type WorkflowResult, type WorkflowStreamOptions, type WorkflowStreamResult, defineTool };
246
+ export { Agent, type AgentConfig, type AgentStepHooks, type BranchCase, type BranchSelect, type GenerateTextResult, type IToolProvider, type MaybePromise, type RepeatOptions, type Resolvable, SealedWorkflow, type StepOptions, type StreamTextResult, type ToolExecuteOptions, type ToolProviderConfig, Workflow, WorkflowBranchError, WorkflowLoopError, type WorkflowResult, type WorkflowStreamOptions, type WorkflowStreamResult, defineTool };
package/dist/index.js CHANGED
@@ -7,6 +7,31 @@ import {
7
7
 
8
8
  // src/tool-provider.ts
9
9
  import { tool } from "ai";
10
+
11
+ // src/utils.ts
12
+ import { AsyncLocalStorage } from "async_hooks";
13
+ var writerStorage = new AsyncLocalStorage();
14
+ function runWithWriter(writer, fn) {
15
+ return writerStorage.run(writer, fn);
16
+ }
17
+ function getActiveWriter() {
18
+ return writerStorage.getStore();
19
+ }
20
+ function resolveValue(value, ctx, input) {
21
+ if (typeof value === "function") {
22
+ return value(ctx, input);
23
+ }
24
+ return value;
25
+ }
26
+ async function extractOutput(result, hasStructuredOutput) {
27
+ if (hasStructuredOutput) {
28
+ const output = await result.output;
29
+ if (output !== void 0) return output;
30
+ }
31
+ return await result.text;
32
+ }
33
+
34
+ // src/tool-provider.ts
10
35
  var TOOL_PROVIDER_BRAND = /* @__PURE__ */ Symbol.for("agent-workflow.ToolProvider");
11
36
  var ToolProvider = class {
12
37
  [TOOL_PROVIDER_BRAND] = true;
@@ -19,7 +44,7 @@ var ToolProvider = class {
19
44
  return tool({
20
45
  ...toolDef,
21
46
  parameters: inputSchema,
22
- execute: (input, options) => execute(input, context, options)
47
+ execute: (input, options) => execute(input, context, { ...options, writer: getActiveWriter() })
23
48
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
24
49
  });
25
50
  }
@@ -31,21 +56,6 @@ function isToolProvider(obj) {
31
56
  return typeof obj === "object" && obj !== null && TOOL_PROVIDER_BRAND in obj;
32
57
  }
33
58
 
34
- // src/utils.ts
35
- function resolveValue(value, ctx, input) {
36
- if (typeof value === "function") {
37
- return value(ctx, input);
38
- }
39
- return value;
40
- }
41
- async function extractOutput(result, hasStructuredOutput) {
42
- if (hasStructuredOutput) {
43
- const output = await result.output;
44
- if (output !== void 0) return output;
45
- }
46
- return await result.text;
47
- }
48
-
49
59
  // src/agent.ts
50
60
  var Agent = class {
51
61
  id;
@@ -110,7 +120,7 @@ var Agent = class {
110
120
  return await generateText(options);
111
121
  } catch (error) {
112
122
  if (this.config.onError) {
113
- await this.config.onError({ error, ctx, input });
123
+ await this.config.onError({ error, ctx, input, writer: getActiveWriter() });
114
124
  }
115
125
  throw error;
116
126
  }
@@ -121,7 +131,7 @@ var Agent = class {
121
131
  const options = this.buildCallOptions(resolved, ctx, input);
122
132
  return streamText({
123
133
  ...options,
124
- onError: this.config.onError ? ({ error }) => this.config.onError({ error, ctx, input }) : void 0
134
+ onError: this.config.onError ? ({ error }) => this.config.onError({ error, ctx, input, writer: getActiveWriter() }) : void 0
125
135
  });
126
136
  }
127
137
  asTool(ctx, options) {
@@ -144,6 +154,13 @@ var Agent = class {
144
154
  description: this.description,
145
155
  parameters: this.config.input,
146
156
  execute: async (toolInput) => {
157
+ const writer = getActiveWriter();
158
+ if (writer) {
159
+ const result2 = await this.stream(ctx, toolInput);
160
+ writer.merge(result2.toUIMessageStream());
161
+ if (options?.mapOutput) return options.mapOutput(result2);
162
+ return extractOutput(result2, this.hasOutput);
163
+ }
147
164
  const result = await this.generate(ctx, toolInput);
148
165
  if (options?.mapOutput) return options.mapOutput(result);
149
166
  return extractOutput(result, this.hasOutput);
@@ -163,8 +180,8 @@ var Agent = class {
163
180
  ...resolved.messages ? { messages: resolved.messages } : { prompt: resolved.prompt ?? "" },
164
181
  ...resolved.system ? { system: resolved.system } : {},
165
182
  ...this.config.output ? { output: this.config.output } : {},
166
- onStepFinish: this._onStepFinish ? (event) => this._onStepFinish({ result: event, ctx, input }) : void 0,
167
- onFinish: this._onFinish ? (event) => this._onFinish({ result: event, ctx, input }) : void 0
183
+ onStepFinish: this._onStepFinish ? (event) => this._onStepFinish({ result: event, ctx, input, writer: getActiveWriter() }) : void 0,
184
+ onFinish: this._onFinish ? (event) => this._onFinish({ result: event, ctx, input, writer: getActiveWriter() }) : void 0
168
185
  };
169
186
  }
170
187
  resolveConfig(ctx, input) {
@@ -339,20 +356,23 @@ var SealedWorkflow = class {
339
356
  const input = state.output;
340
357
  const hasStructuredOutput = agent.hasOutput;
341
358
  if (state.mode === "stream" && state.writer) {
342
- const result = await agent.stream(ctx, state.output);
343
- if (options?.handleStream) {
344
- await options.handleStream({ result, writer: state.writer, ctx });
345
- } else {
346
- state.writer.merge(result.toUIMessageStream());
347
- }
348
- if (options?.onStreamResult) {
349
- await options.onStreamResult({ result, ctx, input });
350
- }
351
- if (options?.mapStreamResult) {
352
- state.output = await options.mapStreamResult({ result, ctx, input });
353
- } else {
354
- state.output = await extractOutput(result, hasStructuredOutput);
355
- }
359
+ const writer = state.writer;
360
+ await runWithWriter(writer, async () => {
361
+ const result = await agent.stream(ctx, state.output);
362
+ if (options?.handleStream) {
363
+ await options.handleStream({ result, writer, ctx });
364
+ } else {
365
+ writer.merge(result.toUIMessageStream());
366
+ }
367
+ if (options?.onStreamResult) {
368
+ await options.onStreamResult({ result, ctx, input });
369
+ }
370
+ if (options?.mapStreamResult) {
371
+ state.output = await options.mapStreamResult({ result, ctx, input });
372
+ } else {
373
+ state.output = await extractOutput(result, hasStructuredOutput);
374
+ }
375
+ });
356
376
  } else {
357
377
  const result = await agent.generate(ctx, state.output);
358
378
  if (options?.onGenerateResult) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/agent.ts","../src/tool-provider.ts","../src/utils.ts","../src/workflow.ts"],"sourcesContent":["import {\n generateText,\n streamText,\n tool,\n Output,\n type GenerateTextResult as AIGenerateTextResult,\n type StreamTextResult as AIStreamTextResult,\n type ModelMessage,\n type LanguageModel,\n type Tool,\n type ToolSet,\n type StopCondition,\n type ToolChoice,\n type OnStepFinishEvent,\n type OnFinishEvent,\n} from \"ai\";\n\n// Extract the Output interface type from the Output.object return type\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype OutputType<T = any> = ReturnType<typeof Output.object<T>>;\nimport type { ZodType } from \"zod\";\nimport { isToolProvider, TOOL_PROVIDER_BRAND, type IToolProvider } from \"./tool-provider\";\nimport { extractOutput, resolveValue, type MaybePromise, type Resolvable } from \"./utils\";\n\n// Tools config accepts both AI SDK tools and context-aware ToolProviders\ntype AgentToolSet<TContext> = Record<string, Tool | IToolProvider<TContext>>;\n\n// ── Result type aliases ─────────────────────────────────────────────\n\nexport type GenerateTextResult<TOOLS extends ToolSet = ToolSet, OUTPUT extends OutputType = OutputType> = AIGenerateTextResult<TOOLS, OUTPUT>;\nexport type StreamTextResult<TOOLS extends ToolSet = ToolSet, OUTPUT extends OutputType = OutputType> = AIStreamTextResult<TOOLS, OUTPUT>;\n\n// ── AI SDK passthrough types ────────────────────────────────────────\n\n// Extract options types from both AI SDK entry points\ntype StreamTextOptions = Parameters<typeof streamText>[0];\ntype GenerateTextOptions = Parameters<typeof generateText>[0];\n\n// Keys we replace with resolvable or context-enriched versions\ntype ManagedKeys =\n | 'model' | 'system' | 'prompt' | 'messages'\n | 'tools' | 'activeTools' | 'toolChoice' | 'stopWhen'\n | 'output' | 'onFinish' | 'onStepFinish' | 'onError';\n\n// Combine options from both streamText and generateText.\n// Each side contributes its unique props; shared props merge naturally.\n// Stream-only props (onChunk, onAbort) are ignored by generateText.\n// Generate-only props (experimental_include.responseBody) are ignored by streamText.\ntype AIPassthroughOptions =\n Omit<StreamTextOptions, ManagedKeys> &\n Omit<GenerateTextOptions, ManagedKeys>;\n\n// ── Resolved config (output of resolveConfig / resolveConfigAsync) ──\n\ninterface ResolvedAgentConfig {\n model: LanguageModel;\n prompt: string | undefined;\n system: string | undefined;\n messages: ModelMessage[] | undefined;\n tools: Record<string, Tool>;\n activeTools: string[] | undefined;\n toolChoice: ToolChoice<ToolSet> | undefined;\n stopWhen: StopCondition<ToolSet> | Array<StopCondition<ToolSet>> | undefined;\n}\n\n// ── Agent Configuration ─────────────────────────────────────────────\n\nexport interface AgentConfig<\n TContext,\n TInput = void,\n TOutput = void,\n> extends AIPassthroughOptions {\n // ── Custom (not in AI SDK) ──\n id: string;\n description?: string;\n input?: ZodType<TInput>;\n output?: OutputType<TOutput>;\n\n // ── Resolvable (our versions of AI SDK properties) ──\n model: Resolvable<TContext, TInput, LanguageModel>;\n system?: Resolvable<TContext, TInput, string>;\n prompt?: Resolvable<TContext, TInput, string>;\n messages?: Resolvable<TContext, TInput, ModelMessage[]>;\n tools?: Resolvable<TContext, TInput, AgentToolSet<TContext>>;\n activeTools?: Resolvable<TContext, TInput, string[]>;\n toolChoice?: Resolvable<TContext, TInput, ToolChoice<ToolSet>>;\n stopWhen?: Resolvable<TContext, TInput, StopCondition<ToolSet> | Array<StopCondition<ToolSet>>>;\n\n // ── Context-enriched callbacks (replace AI SDK versions) ──\n onStepFinish?: (params: { result: OnStepFinishEvent; ctx: Readonly<TContext>; input: TInput }) => MaybePromise<void>;\n onFinish?: (params: { result: OnFinishEvent; ctx: Readonly<TContext>; input: TInput }) => MaybePromise<void>;\n onError?: (params: { error: unknown; ctx: Readonly<TContext>; input: TInput }) => MaybePromise<void>;\n}\n\n// ── Agent ───────────────────────────────────────────────────────────\n\nexport class Agent<\n TContext,\n TInput = void,\n TOutput = void,\n> {\n readonly id: string;\n readonly description: string;\n readonly hasOutput: boolean;\n private readonly config: AgentConfig<TContext, TInput, TOutput>;\n private readonly _hasDynamicConfig: boolean;\n private readonly _resolvedStaticTools: Record<string, Tool> | null = null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private readonly _passthrough: Record<string, any>;\n private readonly _onStepFinish: AgentConfig<TContext, TInput, TOutput>['onStepFinish'];\n private readonly _onFinish: AgentConfig<TContext, TInput, TOutput>['onFinish'];\n\n constructor(config: AgentConfig<TContext, TInput, TOutput>) {\n this.id = config.id;\n this.description = config.description ?? \"\";\n this.hasOutput = config.output !== undefined;\n this.config = config;\n this._hasDynamicConfig = [\n config.model, config.system, config.prompt,\n config.messages, config.tools, config.activeTools,\n config.toolChoice, config.stopWhen,\n ].some(v => typeof v === \"function\");\n\n // Cache tools when config is static and contains no ToolProviders.\n // Avoids re-iterating the tools map on every generate()/stream() call.\n if (!this._hasDynamicConfig) {\n const rawTools = (config.tools as AgentToolSet<TContext> | undefined) ?? {};\n const hasProvider = Object.values(rawTools).some(v => isToolProvider(v));\n if (!hasProvider) {\n this._resolvedStaticTools = rawTools as Record<string, Tool>;\n }\n }\n\n // Pre-compute the passthrough (AI SDK options we don't manage) once,\n // rather than destructuring on every generate()/stream() call.\n const {\n id: _id, description: _desc, input: _inputSchema, output: _output,\n model: _m, system: _s, prompt: _p, messages: _msg,\n tools: _t, activeTools: _at, toolChoice: _tc, stopWhen: _sw,\n onStepFinish, onFinish, onError: _onError,\n ...passthrough\n } = config;\n this._passthrough = passthrough;\n this._onStepFinish = onStepFinish;\n this._onFinish = onFinish;\n }\n\n async generate(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<GenerateTextResult> {\n const input = args[0] as TInput;\n const resolved = await this.resolveConfig(ctx, input);\n const options = this.buildCallOptions(resolved, ctx, input);\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return await generateText(options as any);\n } catch (error: unknown) {\n if (this.config.onError) {\n await this.config.onError({ error, ctx, input });\n }\n throw error;\n }\n }\n\n async stream(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<StreamTextResult> {\n const input = args[0] as TInput;\n const resolved = await this.resolveConfig(ctx, input);\n const options = this.buildCallOptions(resolved, ctx, input);\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return streamText({\n ...options,\n onError: this.config.onError\n ? ({ error }: { error: unknown }) => this.config.onError!({ error, ctx, input })\n : undefined,\n } as any);\n }\n\n asTool(ctx: TContext, options?: {\n mapOutput?: (result: GenerateTextResult) => MaybePromise<TOutput>;\n }): Tool {\n return this.createToolInstance(ctx, options);\n }\n\n asToolProvider(options?: {\n mapOutput?: (result: GenerateTextResult) => MaybePromise<TOutput>;\n }): IToolProvider<TContext> {\n if (!this.config.input) {\n throw new Error(`Agent \"${this.id}\": asToolProvider() requires an input schema`);\n }\n\n return {\n [TOOL_PROVIDER_BRAND]: true as const,\n createTool: (ctx: Readonly<TContext>) => this.createToolInstance(ctx as TContext, options),\n };\n }\n\n private createToolInstance(ctx: TContext, options?: {\n mapOutput?: (result: GenerateTextResult) => MaybePromise<TOutput>;\n }): Tool {\n if (!this.config.input) {\n throw new Error(`Agent \"${this.id}\": asTool() requires an input schema`);\n }\n\n return tool({\n description: this.description,\n parameters: this.config.input,\n execute: async (toolInput: TInput) => {\n const result = await (this.generate as (ctx: TContext, input: TInput) => Promise<GenerateTextResult>)(ctx, toolInput);\n if (options?.mapOutput) return options.mapOutput(result);\n return extractOutput(result, this.hasOutput);\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private buildCallOptions(resolved: ResolvedAgentConfig, ctx: TContext, input: TInput): Record<string, any> {\n return {\n ...this._passthrough,\n model: resolved.model,\n tools: resolved.tools,\n activeTools: resolved.activeTools,\n toolChoice: resolved.toolChoice,\n stopWhen: resolved.stopWhen,\n ...(resolved.messages\n ? { messages: resolved.messages }\n : { prompt: resolved.prompt ?? \"\" }),\n ...(resolved.system ? { system: resolved.system } : {}),\n ...(this.config.output ? { output: this.config.output } : {}),\n onStepFinish: this._onStepFinish\n ? (event: OnStepFinishEvent) => this._onStepFinish!({ result: event, ctx, input })\n : undefined,\n onFinish: this._onFinish\n ? (event: OnFinishEvent) => this._onFinish!({ result: event, ctx, input })\n : undefined,\n };\n }\n\n private resolveConfig(ctx: TContext, input: TInput): ResolvedAgentConfig | Promise<ResolvedAgentConfig> {\n if (!this._hasDynamicConfig) {\n return {\n model: this.config.model as LanguageModel,\n prompt: this.config.prompt as string | undefined,\n system: this.config.system as string | undefined,\n messages: this.config.messages as ModelMessage[] | undefined,\n tools: this._resolvedStaticTools ?? this.resolveTools(\n (this.config.tools as AgentToolSet<TContext> | undefined) ?? {}, ctx\n ),\n activeTools: this.config.activeTools as string[] | undefined,\n toolChoice: this.config.toolChoice as ToolChoice<ToolSet> | undefined,\n stopWhen: this.config.stopWhen as StopCondition<ToolSet> | Array<StopCondition<ToolSet>> | undefined,\n };\n }\n return this.resolveConfigAsync(ctx, input);\n }\n\n private async resolveConfigAsync(ctx: TContext, input: TInput): Promise<ResolvedAgentConfig> {\n const [model, prompt, system, messages, rawTools, activeTools, toolChoice, stopWhen] = await Promise.all([\n resolveValue(this.config.model, ctx, input),\n resolveValue(this.config.prompt, ctx, input),\n resolveValue(this.config.system, ctx, input),\n resolveValue(this.config.messages, ctx, input),\n resolveValue(this.config.tools, ctx, input),\n resolveValue(this.config.activeTools, ctx, input),\n resolveValue(this.config.toolChoice, ctx, input),\n resolveValue(this.config.stopWhen, ctx, input),\n ]);\n const tools = this.resolveTools(rawTools ?? {}, ctx);\n return { model, prompt, system, messages, tools, activeTools, toolChoice, stopWhen };\n }\n\n private resolveTools(\n tools: AgentToolSet<TContext>,\n ctx: TContext\n ): Record<string, Tool> {\n const entries = Object.entries(tools);\n if (entries.length === 0) return tools as Record<string, Tool>;\n let hasProvider = false;\n const resolved: Record<string, Tool> = {};\n for (const [key, toolOrProvider] of entries) {\n if (isToolProvider<TContext>(toolOrProvider)) {\n hasProvider = true;\n resolved[key] = toolOrProvider.createTool(ctx as Readonly<TContext>);\n } else {\n resolved[key] = toolOrProvider as Tool;\n }\n }\n return hasProvider ? resolved : (tools as Record<string, Tool>);\n }\n}\n","import { tool, type Tool, type ToolExecutionOptions, type FlexibleSchema } from \"ai\";\n\nexport const TOOL_PROVIDER_BRAND = Symbol.for(\"agent-workflow.ToolProvider\");\n\nexport type ToolProviderConfig<TContext, TInput, TOutput> = {\n description?: string;\n input: FlexibleSchema<TInput>;\n output?: FlexibleSchema<unknown>;\n providerOptions?: unknown;\n execute: (input: TInput, ctx: Readonly<TContext>, options?: ToolExecutionOptions) => Promise<TOutput>;\n};\n\nexport interface IToolProvider<TContext> {\n readonly [TOOL_PROVIDER_BRAND]: true;\n createTool(context: Readonly<TContext>): Tool;\n}\n\nexport class ToolProvider<\n TContext,\n TInput = unknown,\n TOutput = unknown,\n> implements IToolProvider<TContext> {\n readonly [TOOL_PROVIDER_BRAND] = true as const;\n private readonly config: ToolProviderConfig<TContext, TInput, TOutput>;\n\n constructor(config: ToolProviderConfig<TContext, TInput, TOutput>) {\n this.config = config;\n }\n\n createTool(context: Readonly<TContext>): Tool {\n const { execute, input: inputSchema, ...toolDef } = this.config;\n return tool({\n ...toolDef,\n parameters: inputSchema,\n execute: (input: TInput, options?: ToolExecutionOptions) => execute(input, context, options),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any);\n }\n}\n\nexport function defineTool<TContext>() {\n return <TInput, TOutput>(\n config: ToolProviderConfig<TContext, TInput, TOutput>\n ): ToolProvider<TContext, TInput, TOutput> => new ToolProvider(config);\n}\n\nexport function isToolProvider<TContext>(obj: unknown): obj is IToolProvider<TContext> {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n TOOL_PROVIDER_BRAND in obj\n );\n}\n","export type MaybePromise<T> = T | Promise<T>;\n\n/**\n * A value that can be static or derived from context and input.\n * Used for agent config fields that may need runtime resolution.\n *\n * Functions may return a Promise for async resolution; static values are always sync.\n */\nexport type Resolvable<TCtx, TInput, TValue> =\n | TValue\n | ((ctx: Readonly<TCtx>, input: TInput) => TValue | Promise<TValue>);\n\nexport function resolveValue<TCtx, TInput, TValue>(\n value: Resolvable<TCtx, TInput, TValue>,\n ctx: TCtx,\n input: TInput\n): TValue | Promise<TValue>;\nexport function resolveValue<TCtx, TInput, TValue>(\n value: Resolvable<TCtx, TInput, TValue> | undefined,\n ctx: TCtx,\n input: TInput\n): TValue | Promise<TValue> | undefined {\n if (typeof value === \"function\") {\n return (value as (ctx: TCtx, input: TInput) => TValue | Promise<TValue>)(ctx, input);\n }\n return value;\n}\n\n/**\n * Extract structured output from an AI SDK result, falling back to text.\n * Works for both generate (sync .output/.text) and stream (async .output/.text) results.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function extractOutput(result: any, hasStructuredOutput: boolean): Promise<unknown> {\n if (hasStructuredOutput) {\n const output = await result.output;\n if (output !== undefined) return output;\n }\n return await result.text;\n}\n","import {\n createUIMessageStream,\n type UIMessageStreamWriter,\n} from \"ai\";\nimport { type Agent, type GenerateTextResult, type StreamTextResult } from \"./agent\";\nimport { extractOutput, type MaybePromise } from \"./utils\";\n\n// ── Error Types ─────────────────────────────────────────────────────\n\nexport class WorkflowBranchError extends Error {\n constructor(\n public readonly branchType: \"predicate\" | \"select\",\n message: string,\n ) {\n super(message);\n this.name = \"WorkflowBranchError\";\n }\n}\n\nexport class WorkflowLoopError extends Error {\n constructor(\n public readonly iterations: number,\n public readonly maxIterations: number,\n ) {\n super(`Loop exceeded maximum iterations (${maxIterations})`);\n this.name = \"WorkflowLoopError\";\n }\n}\n\n// ── Shared Agent Step Hooks ─────────────────────────────────────────\n\nexport interface AgentStepHooks<TContext, TOutput, TNextOutput> {\n mapGenerateResult?: (params: { result: GenerateTextResult; ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>;\n mapStreamResult?: (params: { result: StreamTextResult; ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>;\n onGenerateResult?: (params: { result: GenerateTextResult; ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<void>;\n onStreamResult?: (params: { result: StreamTextResult; ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<void>;\n handleStream?: (params: {\n result: StreamTextResult;\n writer: UIMessageStreamWriter;\n ctx: Readonly<TContext>;\n }) => MaybePromise<void>;\n}\n\n// ── Step Options ────────────────────────────────────────────────────\n\nexport type StepOptions<TContext, TOutput, TNextOutput> = AgentStepHooks<TContext, TOutput, TNextOutput>;\n\n// ── Branch Types ────────────────────────────────────────────────────\n\nexport interface BranchCase<TContext, TOutput, TNextOutput> extends AgentStepHooks<TContext, TOutput, TNextOutput> {\n when?: (params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<boolean>;\n agent: Agent<TContext, TOutput, TNextOutput>;\n}\n\nexport interface BranchSelect<TContext, TOutput, TKeys extends string, TNextOutput> extends AgentStepHooks<TContext, TOutput, TNextOutput> {\n select: (params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TKeys>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n agents: Record<TKeys, Agent<TContext, any, TNextOutput>>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n fallback?: Agent<TContext, any, TNextOutput>;\n}\n\n// ── Result Types ────────────────────────────────────────────────────\n\nexport interface WorkflowResult<TOutput> {\n output: TOutput;\n}\n\nexport interface WorkflowStreamResult<TOutput> {\n stream: ReadableStream;\n output: Promise<TOutput>;\n}\n\nexport interface WorkflowStreamOptions {\n onError?: (error: unknown) => string;\n onFinish?: () => MaybePromise<void>;\n}\n\n// ── Loop Types ──────────────────────────────────────────────────────\n\ntype LoopPredicate<TContext, TOutput> = (params: {\n output: TOutput;\n ctx: Readonly<TContext>;\n iterations: number;\n}) => MaybePromise<boolean>;\n\n// Exactly one of `until` or `while` — never both.\nexport type RepeatOptions<TContext, TOutput> =\n | { until: LoopPredicate<TContext, TOutput>; while?: never; maxIterations?: number }\n | { while: LoopPredicate<TContext, TOutput>; until?: never; maxIterations?: number };\n\n// Extracts the element type from an array type. Resolves to `never` for non-arrays,\n// making foreach uncallable at compile time when the previous step doesn't produce an array.\ntype ElementOf<T> = T extends readonly (infer E)[] ? E : never;\n\n// ── Step Node ───────────────────────────────────────────────────────\n\ntype StepNode =\n | { readonly type: \"step\"; readonly id: string; readonly execute: (state: RuntimeState) => MaybePromise<void> }\n | { readonly type: \"catch\"; readonly id: string; readonly catchFn: (params: { error: unknown; ctx: unknown; lastOutput: unknown; stepId: string }) => MaybePromise<unknown> }\n | { readonly type: \"finally\"; readonly id: string; readonly execute: (state: RuntimeState) => MaybePromise<void> };\n\ninterface RuntimeState {\n ctx: unknown;\n output: unknown;\n mode: \"generate\" | \"stream\";\n writer?: UIMessageStreamWriter;\n}\n\n// ── Sealed Workflow (returned by finally — execution only) ───────────\n\nexport class SealedWorkflow<\n TContext,\n TInput = void,\n TOutput = void,\n> {\n readonly id?: string;\n protected readonly steps: ReadonlyArray<StepNode>;\n\n protected constructor(steps: ReadonlyArray<StepNode>, id?: string) {\n this.steps = steps;\n this.id = id;\n }\n\n // ── Execution ─────────────────────────────────────────────────\n\n async generate(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<WorkflowResult<TOutput>> {\n const input = args[0];\n const state: RuntimeState = {\n ctx,\n output: input,\n mode: \"generate\",\n };\n\n await this.execute(state);\n\n return {\n output: state.output as TOutput,\n };\n }\n\n stream(\n ctx: TContext,\n ...args: TInput extends void\n ? [input?: TInput, options?: WorkflowStreamOptions]\n : [input: TInput, options?: WorkflowStreamOptions]\n ): WorkflowStreamResult<TOutput> {\n const input = args[0];\n const options = args[1] as WorkflowStreamOptions | undefined;\n\n let resolveOutput: (value: TOutput) => void;\n let rejectOutput: (error: unknown) => void;\n const outputPromise = new Promise<TOutput>((res, rej) => {\n resolveOutput = res;\n rejectOutput = rej;\n });\n\n // Prevent unhandled rejection warning if the consumer never awaits `output`.\n // The original promise still rejects normally when awaited.\n outputPromise.catch(() => {});\n\n const stream = createUIMessageStream({\n execute: async ({ writer }) => {\n const state: RuntimeState = {\n ctx,\n output: input,\n mode: \"stream\",\n writer,\n };\n\n try {\n await this.execute(state);\n resolveOutput(state.output as TOutput);\n } catch (error) {\n rejectOutput!(error);\n throw error;\n }\n },\n ...(options?.onError ? { onError: options.onError } : {}),\n ...(options?.onFinish ? { onFinish: options.onFinish } : {}),\n });\n\n return {\n stream,\n output: outputPromise,\n };\n }\n\n // ── Internal: execute pipeline ────────────────────────────────\n\n protected async execute(state: RuntimeState): Promise<void> {\n if (this.steps.length === 0) {\n throw new Error(\"Workflow has no steps. Add at least one step before calling generate() or stream().\");\n }\n\n let pendingError: { error: unknown; stepId: string } | null = null;\n\n for (const node of this.steps) {\n if (node.type === \"finally\") {\n await node.execute(state);\n continue;\n }\n\n if (node.type === \"catch\") {\n if (!pendingError) continue;\n try {\n state.output = await node.catchFn({\n error: pendingError.error,\n ctx: state.ctx,\n lastOutput: state.output,\n stepId: pendingError.stepId,\n });\n pendingError = null;\n } catch (catchError) {\n pendingError = { error: catchError, stepId: node.id };\n }\n continue;\n }\n\n // type === \"step\" — skip while in error state\n if (pendingError) continue;\n\n try {\n await node.execute(state);\n } catch (error) {\n pendingError = { error, stepId: node.id };\n }\n }\n\n if (pendingError) throw pendingError.error;\n }\n\n // ── Internal: execute a nested workflow within a step/loop ─────\n // Defined on SealedWorkflow (not Workflow) because TypeScript's protected\n // access rules only allow calling workflow.execute() from the same class.\n\n protected async executeNestedWorkflow(\n state: RuntimeState,\n workflow: SealedWorkflow<TContext, unknown, unknown>,\n ): Promise<void> {\n await workflow.execute(state);\n }\n\n // ── Internal: execute an agent within a step/branch ───────────\n // In stream mode, output extraction awaits the full stream before returning.\n // Streaming benefits the client (incremental output), not pipeline throughput —\n // each step still runs sequentially.\n\n protected async executeAgent<TAgentInput, TNextOutput>(\n state: RuntimeState,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n agent: Agent<TContext, any, TNextOutput>,\n ctx: TContext,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options?: AgentStepHooks<TContext, any, TNextOutput>,\n ): Promise<void> {\n const input = state.output as TAgentInput;\n const hasStructuredOutput = agent.hasOutput;\n\n if (state.mode === \"stream\" && state.writer) {\n const result = await (agent.stream as (ctx: TContext, input: unknown) => Promise<StreamTextResult>)(ctx, state.output);\n\n if (options?.handleStream) {\n await options.handleStream({ result, writer: state.writer, ctx });\n } else {\n state.writer.merge(result.toUIMessageStream());\n }\n\n if (options?.onStreamResult) {\n await options.onStreamResult({ result, ctx, input });\n }\n\n if (options?.mapStreamResult) {\n state.output = await options.mapStreamResult({ result, ctx, input });\n } else {\n state.output = await extractOutput(result, hasStructuredOutput);\n }\n } else {\n const result = await (agent.generate as (ctx: TContext, input: unknown) => Promise<GenerateTextResult>)(ctx, state.output);\n\n if (options?.onGenerateResult) {\n await options.onGenerateResult({ result, ctx, input });\n }\n\n if (options?.mapGenerateResult) {\n state.output = await options.mapGenerateResult({ result, ctx, input });\n } else {\n state.output = await extractOutput(result, hasStructuredOutput);\n }\n }\n }\n}\n\n// ── Workflow ────────────────────────────────────────────────────────\n\nexport class Workflow<\n TContext,\n TInput = void,\n TOutput = void,\n> extends SealedWorkflow<TContext, TInput, TOutput> {\n\n private constructor(steps: ReadonlyArray<StepNode> = [], id?: string) {\n super(steps, id);\n }\n\n static create<TContext, TInput = void>(options?: { id?: string }): Workflow<TContext, TInput, TInput> {\n return new Workflow<TContext, TInput, TInput>([], options?.id);\n }\n\n static from<TContext, TInput, TOutput>(\n agent: Agent<TContext, TInput, TOutput>,\n options?: StepOptions<TContext, TInput, TOutput>\n ): Workflow<TContext, TInput, TOutput> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, any>([]).step(agent, options);\n }\n\n // ── step: agent overload ──────────────────────────────────────\n\n step<TNextOutput>(\n agent: Agent<TContext, TOutput, TNextOutput>,\n options?: StepOptions<TContext, TOutput, TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── step: nested workflow overload ─────────────────────────────\n\n step<TNextOutput>(\n workflow: SealedWorkflow<TContext, TOutput, TNextOutput>,\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── step: transform overload (replaces map + tap) ─────────────\n\n step<TNextOutput>(\n id: string,\n fn: (params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── step: implementation ──────────────────────────────────────\n\n step<TNextOutput>(\n target: Agent<TContext, TOutput, TNextOutput> | SealedWorkflow<TContext, TOutput, TNextOutput> | string,\n optionsOrFn?: StepOptions<TContext, TOutput, TNextOutput> | ((params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>)\n ): Workflow<TContext, TInput, TNextOutput> {\n // Nested workflow overload: step(workflow)\n if (target instanceof SealedWorkflow) {\n const workflow = target;\n const node: StepNode = {\n type: \"step\",\n id: workflow.id ?? \"nested-workflow\",\n execute: async (state) => {\n await this.executeNestedWorkflow(state, workflow as SealedWorkflow<TContext, unknown, unknown>);\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n // Transform overload: step(id, fn)\n if (typeof target === \"string\") {\n if (typeof optionsOrFn !== \"function\") {\n throw new Error(`Workflow step(\"${target}\"): second argument must be a function`);\n }\n const fn = optionsOrFn as (params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>;\n const node: StepNode = {\n type: \"step\",\n id: target,\n execute: async (state) => {\n state.output = await fn({\n ctx: state.ctx as Readonly<TContext>,\n input: state.output as TOutput,\n });\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n // Agent overload: step(agent, options?)\n const agent = target;\n const options = optionsOrFn as StepOptions<TContext, TOutput, TNextOutput> | undefined;\n const node: StepNode = {\n type: \"step\",\n id: agent.id,\n execute: async (state) => {\n const ctx = state.ctx as TContext;\n await this.executeAgent(state, agent, ctx, options);\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n // ── branch: predicate routing (array) ─────────────────────────\n\n branch<TNextOutput>(\n cases: BranchCase<TContext, TOutput, TNextOutput>[]\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── branch: key routing (select) ──────────────────────────────\n\n branch<TKeys extends string, TNextOutput>(\n config: BranchSelect<TContext, TOutput, TKeys, TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── branch: implementation ────────────────────────────────────\n\n branch<TKeys extends string, TNextOutput>(\n casesOrConfig: BranchCase<TContext, TOutput, TNextOutput>[] | BranchSelect<TContext, TOutput, TKeys, TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput> {\n if (Array.isArray(casesOrConfig)) {\n return this.branchPredicate(casesOrConfig);\n }\n return this.branchSelect(casesOrConfig);\n }\n\n private branchPredicate<TNextOutput>(\n cases: BranchCase<TContext, TOutput, TNextOutput>[]\n ): Workflow<TContext, TInput, TNextOutput> {\n const node: StepNode = {\n type: \"step\",\n id: \"branch:predicate\",\n execute: async (state) => {\n const ctx = state.ctx as TContext;\n const input = state.output as TOutput;\n\n for (const branchCase of cases) {\n if (branchCase.when) {\n const match = await branchCase.when({ ctx, input });\n if (!match) continue;\n }\n\n // Matched (or no `when` = default)\n await this.executeAgent(state, branchCase.agent, ctx, branchCase);\n return;\n }\n\n throw new WorkflowBranchError(\"predicate\", `No branch matched and no default branch (a case without \\`when\\`) was provided. Input: ${JSON.stringify(input)}`);\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n private branchSelect<TKeys extends string, TNextOutput>(\n config: BranchSelect<TContext, TOutput, TKeys, TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput> {\n const node: StepNode = {\n type: \"step\",\n id: \"branch:select\",\n execute: async (state) => {\n const ctx = state.ctx as TContext;\n const input = state.output as TOutput;\n const key = await config.select({ ctx, input });\n\n let agent = config.agents[key];\n if (!agent) {\n if (config.fallback) {\n agent = config.fallback;\n } else {\n throw new WorkflowBranchError(\"select\", `No agent found for key \"${key}\" and no fallback provided. Available keys: ${Object.keys(config.agents).join(\", \")}`);\n }\n }\n\n await this.executeAgent(state, agent, ctx, config);\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n // ── foreach: array iteration ─────────────────────────────────\n\n foreach<TNextOutput>(\n target: Agent<TContext, ElementOf<TOutput>, TNextOutput> | SealedWorkflow<TContext, ElementOf<TOutput>, TNextOutput>,\n options?: { concurrency?: number },\n ): Workflow<TContext, TInput, TNextOutput[]> {\n const concurrency = options?.concurrency ?? 1;\n const isWorkflow = target instanceof SealedWorkflow;\n const id = isWorkflow ? (target.id ?? \"foreach\") : `foreach:${(target as Agent<TContext, ElementOf<TOutput>, TNextOutput>).id}`;\n\n const node: StepNode = {\n type: \"step\",\n id,\n execute: async (state) => {\n const items = state.output;\n if (!Array.isArray(items)) {\n throw new Error(`foreach \"${id}\": expected array input, got ${typeof items}`);\n }\n\n const ctx = state.ctx as TContext;\n const results: unknown[] = new Array(items.length);\n\n // Streaming is intentionally not propagated to foreach items —\n // each item runs in generate mode because merging interleaved\n // streams from parallel items into a single writer is not supported.\n const executeItem = async (item: unknown, index: number) => {\n const itemState: RuntimeState = { ctx: state.ctx, output: item, mode: \"generate\" };\n if (isWorkflow) {\n await this.executeNestedWorkflow(itemState, target as SealedWorkflow<TContext, unknown, unknown>);\n } else {\n await this.executeAgent(itemState, target as Agent<TContext, unknown, TNextOutput>, ctx);\n }\n results[index] = itemState.output;\n };\n\n if (concurrency <= 1) {\n for (let i = 0; i < items.length; i++) {\n await executeItem(items[i], i);\n }\n } else {\n for (let i = 0; i < items.length; i += concurrency) {\n const batch = items.slice(i, i + concurrency);\n await Promise.all(batch.map((item, j) => executeItem(item, i + j)));\n }\n }\n\n state.output = results;\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput[]>([...this.steps, node] as any, this.id);\n }\n\n // ── repeat: conditional loop ─────────────────────────────────\n\n repeat(\n target: Agent<TContext, TOutput, TOutput> | SealedWorkflow<TContext, TOutput, TOutput>,\n options: RepeatOptions<TContext, TOutput>,\n ): Workflow<TContext, TInput, TOutput> {\n const maxIterations = options.maxIterations ?? 10;\n const isWorkflow = target instanceof SealedWorkflow;\n const id = isWorkflow ? (target.id ?? \"repeat\") : `repeat:${(target as Agent<TContext, TOutput, TOutput>).id}`;\n const predicate: LoopPredicate<TContext, TOutput> = options.until\n ?? (async (p) => !(await options.while!(p)));\n\n const node: StepNode = {\n type: \"step\",\n id,\n execute: async (state) => {\n const ctx = state.ctx as TContext;\n\n for (let i = 1; i <= maxIterations; i++) {\n if (isWorkflow) {\n await this.executeNestedWorkflow(state, target as SealedWorkflow<TContext, unknown, unknown>);\n } else {\n await this.executeAgent(state, target as Agent<TContext, TOutput, TOutput>, ctx);\n }\n\n const done = await predicate({\n output: state.output as TOutput,\n ctx: ctx as Readonly<TContext>,\n iterations: i,\n });\n if (done) return;\n }\n\n throw new WorkflowLoopError(maxIterations, maxIterations);\n },\n };\n return new Workflow<TContext, TInput, TOutput>([...this.steps, node], this.id);\n }\n\n // ── catch ─────────────────────────────────────────────────────\n\n catch(\n id: string,\n fn: (params: { error: unknown; ctx: Readonly<TContext>; lastOutput: TOutput; stepId: string }) => MaybePromise<TOutput>\n ): Workflow<TContext, TInput, TOutput> {\n if (!this.steps.some(s => s.type === \"step\")) {\n throw new Error(`Workflow: catch(\"${id}\") requires at least one preceding step.`);\n }\n const node: StepNode = {\n type: \"catch\",\n id,\n catchFn: fn as (params: { error: unknown; ctx: unknown; lastOutput: unknown; stepId: string }) => MaybePromise<unknown>,\n };\n return new Workflow<TContext, TInput, TOutput>([...this.steps, node], this.id);\n }\n\n // ── finally (terminal — returns sealed workflow) ──────────────\n\n finally(\n id: string,\n fn: (params: { ctx: Readonly<TContext> }) => MaybePromise<void>\n ): SealedWorkflow<TContext, TInput, TOutput> {\n const node: StepNode = {\n type: \"finally\",\n id,\n execute: async (state) => {\n await fn({ ctx: state.ctx as Readonly<TContext> });\n },\n };\n return new SealedWorkflow<TContext, TInput, TOutput>([...this.steps, node], this.id);\n }\n}\n\n"],"mappings":"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","names":["tool","tool","node"]}
1
+ {"version":3,"sources":["../src/agent.ts","../src/tool-provider.ts","../src/utils.ts","../src/workflow.ts"],"sourcesContent":["import {\n generateText,\n streamText,\n tool,\n Output,\n type GenerateTextResult as AIGenerateTextResult,\n type StreamTextResult as AIStreamTextResult,\n type UIMessageStreamWriter,\n type ModelMessage,\n type LanguageModel,\n type Tool,\n type ToolSet,\n type StopCondition,\n type ToolChoice,\n type OnStepFinishEvent,\n type OnFinishEvent,\n} from \"ai\";\n\n// Extract the Output interface type from the Output.object return type\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype OutputType<T = any> = ReturnType<typeof Output.object<T>>;\nimport type { ZodType } from \"zod\";\nimport { isToolProvider, TOOL_PROVIDER_BRAND, type IToolProvider } from \"./tool-provider\";\nimport { extractOutput, getActiveWriter, resolveValue, type MaybePromise, type Resolvable } from \"./utils\";\n\n// Tools config accepts both AI SDK tools and context-aware ToolProviders\ntype AgentToolSet<TContext> = Record<string, Tool | IToolProvider<TContext>>;\n\n// ── Result type aliases ─────────────────────────────────────────────\n\nexport type GenerateTextResult<TOOLS extends ToolSet = ToolSet, OUTPUT extends OutputType = OutputType> = AIGenerateTextResult<TOOLS, OUTPUT>;\nexport type StreamTextResult<TOOLS extends ToolSet = ToolSet, OUTPUT extends OutputType = OutputType> = AIStreamTextResult<TOOLS, OUTPUT>;\n\n// ── AI SDK passthrough types ────────────────────────────────────────\n\n// Extract options types from both AI SDK entry points\ntype StreamTextOptions = Parameters<typeof streamText>[0];\ntype GenerateTextOptions = Parameters<typeof generateText>[0];\n\n// Keys we replace with resolvable or context-enriched versions\ntype ManagedKeys =\n | 'model' | 'system' | 'prompt' | 'messages'\n | 'tools' | 'activeTools' | 'toolChoice' | 'stopWhen'\n | 'output' | 'onFinish' | 'onStepFinish' | 'onError';\n\n// Combine options from both streamText and generateText.\n// Each side contributes its unique props; shared props merge naturally.\n// Stream-only props (onChunk, onAbort) are ignored by generateText.\n// Generate-only props (experimental_include.responseBody) are ignored by streamText.\ntype AIPassthroughOptions =\n Omit<StreamTextOptions, ManagedKeys> &\n Omit<GenerateTextOptions, ManagedKeys>;\n\n// ── Resolved config (output of resolveConfig / resolveConfigAsync) ──\n\ninterface ResolvedAgentConfig {\n model: LanguageModel;\n prompt: string | undefined;\n system: string | undefined;\n messages: ModelMessage[] | undefined;\n tools: Record<string, Tool>;\n activeTools: string[] | undefined;\n toolChoice: ToolChoice<ToolSet> | undefined;\n stopWhen: StopCondition<ToolSet> | Array<StopCondition<ToolSet>> | undefined;\n}\n\n// ── Agent Configuration ─────────────────────────────────────────────\n\nexport interface AgentConfig<\n TContext,\n TInput = void,\n TOutput = void,\n> extends AIPassthroughOptions {\n // ── Custom (not in AI SDK) ──\n id: string;\n description?: string;\n input?: ZodType<TInput>;\n output?: OutputType<TOutput>;\n\n // ── Resolvable (our versions of AI SDK properties) ──\n model: Resolvable<TContext, TInput, LanguageModel>;\n system?: Resolvable<TContext, TInput, string>;\n prompt?: Resolvable<TContext, TInput, string>;\n messages?: Resolvable<TContext, TInput, ModelMessage[]>;\n tools?: Resolvable<TContext, TInput, AgentToolSet<TContext>>;\n activeTools?: Resolvable<TContext, TInput, string[]>;\n toolChoice?: Resolvable<TContext, TInput, ToolChoice<ToolSet>>;\n stopWhen?: Resolvable<TContext, TInput, StopCondition<ToolSet> | Array<StopCondition<ToolSet>>>;\n\n // ── Context-enriched callbacks (replace AI SDK versions) ──\n // `writer` is available when the agent runs inside a streaming workflow.\n onStepFinish?: (params: { result: OnStepFinishEvent; ctx: Readonly<TContext>; input: TInput; writer?: UIMessageStreamWriter }) => MaybePromise<void>;\n onFinish?: (params: { result: OnFinishEvent; ctx: Readonly<TContext>; input: TInput; writer?: UIMessageStreamWriter }) => MaybePromise<void>;\n onError?: (params: { error: unknown; ctx: Readonly<TContext>; input: TInput; writer?: UIMessageStreamWriter }) => MaybePromise<void>;\n}\n\n// ── Agent ───────────────────────────────────────────────────────────\n\nexport class Agent<\n TContext,\n TInput = void,\n TOutput = void,\n> {\n readonly id: string;\n readonly description: string;\n readonly hasOutput: boolean;\n private readonly config: AgentConfig<TContext, TInput, TOutput>;\n private readonly _hasDynamicConfig: boolean;\n private readonly _resolvedStaticTools: Record<string, Tool> | null = null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private readonly _passthrough: Record<string, any>;\n private readonly _onStepFinish: AgentConfig<TContext, TInput, TOutput>['onStepFinish'];\n private readonly _onFinish: AgentConfig<TContext, TInput, TOutput>['onFinish'];\n\n constructor(config: AgentConfig<TContext, TInput, TOutput>) {\n this.id = config.id;\n this.description = config.description ?? \"\";\n this.hasOutput = config.output !== undefined;\n this.config = config;\n this._hasDynamicConfig = [\n config.model, config.system, config.prompt,\n config.messages, config.tools, config.activeTools,\n config.toolChoice, config.stopWhen,\n ].some(v => typeof v === \"function\");\n\n // Cache tools when config is static and contains no ToolProviders.\n // Avoids re-iterating the tools map on every generate()/stream() call.\n if (!this._hasDynamicConfig) {\n const rawTools = (config.tools as AgentToolSet<TContext> | undefined) ?? {};\n const hasProvider = Object.values(rawTools).some(v => isToolProvider(v));\n if (!hasProvider) {\n this._resolvedStaticTools = rawTools as Record<string, Tool>;\n }\n }\n\n // Pre-compute the passthrough (AI SDK options we don't manage) once,\n // rather than destructuring on every generate()/stream() call.\n const {\n id: _id, description: _desc, input: _inputSchema, output: _output,\n model: _m, system: _s, prompt: _p, messages: _msg,\n tools: _t, activeTools: _at, toolChoice: _tc, stopWhen: _sw,\n onStepFinish, onFinish, onError: _onError,\n ...passthrough\n } = config;\n this._passthrough = passthrough;\n this._onStepFinish = onStepFinish;\n this._onFinish = onFinish;\n }\n\n async generate(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<GenerateTextResult> {\n const input = args[0] as TInput;\n const resolved = await this.resolveConfig(ctx, input);\n const options = this.buildCallOptions(resolved, ctx, input);\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return await generateText(options as any);\n } catch (error: unknown) {\n if (this.config.onError) {\n await this.config.onError({ error, ctx, input, writer: getActiveWriter() });\n }\n throw error;\n }\n }\n\n async stream(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<StreamTextResult> {\n const input = args[0] as TInput;\n const resolved = await this.resolveConfig(ctx, input);\n const options = this.buildCallOptions(resolved, ctx, input);\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return streamText({\n ...options,\n onError: this.config.onError\n ? ({ error }: { error: unknown }) => this.config.onError!({ error, ctx, input, writer: getActiveWriter() })\n : undefined,\n } as any);\n }\n\n asTool(ctx: TContext, options?: {\n mapOutput?: (result: GenerateTextResult) => MaybePromise<TOutput>;\n }): Tool {\n return this.createToolInstance(ctx, options);\n }\n\n asToolProvider(options?: {\n mapOutput?: (result: GenerateTextResult) => MaybePromise<TOutput>;\n }): IToolProvider<TContext> {\n if (!this.config.input) {\n throw new Error(`Agent \"${this.id}\": asToolProvider() requires an input schema`);\n }\n\n return {\n [TOOL_PROVIDER_BRAND]: true as const,\n createTool: (ctx: Readonly<TContext>) => this.createToolInstance(ctx as TContext, options),\n };\n }\n\n private createToolInstance(ctx: TContext, options?: {\n mapOutput?: (result: GenerateTextResult) => MaybePromise<TOutput>;\n }): Tool {\n if (!this.config.input) {\n throw new Error(`Agent \"${this.id}\": asTool() requires an input schema`);\n }\n\n return tool({\n description: this.description,\n parameters: this.config.input,\n execute: async (toolInput: TInput) => {\n // When inside a streaming workflow, automatically use stream() and merge to the active writer.\n // Otherwise fall back to generate().\n const writer = getActiveWriter();\n if (writer) {\n const result = await (this.stream as (ctx: TContext, input: TInput) => Promise<StreamTextResult>)(ctx, toolInput);\n writer.merge(result.toUIMessageStream());\n if (options?.mapOutput) return options.mapOutput(result as unknown as GenerateTextResult);\n return extractOutput(result, this.hasOutput);\n }\n const result = await (this.generate as (ctx: TContext, input: TInput) => Promise<GenerateTextResult>)(ctx, toolInput);\n if (options?.mapOutput) return options.mapOutput(result);\n return extractOutput(result, this.hasOutput);\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private buildCallOptions(resolved: ResolvedAgentConfig, ctx: TContext, input: TInput): Record<string, any> {\n return {\n ...this._passthrough,\n model: resolved.model,\n tools: resolved.tools,\n activeTools: resolved.activeTools,\n toolChoice: resolved.toolChoice,\n stopWhen: resolved.stopWhen,\n ...(resolved.messages\n ? { messages: resolved.messages }\n : { prompt: resolved.prompt ?? \"\" }),\n ...(resolved.system ? { system: resolved.system } : {}),\n ...(this.config.output ? { output: this.config.output } : {}),\n onStepFinish: this._onStepFinish\n ? (event: OnStepFinishEvent) => this._onStepFinish!({ result: event, ctx, input, writer: getActiveWriter() })\n : undefined,\n onFinish: this._onFinish\n ? (event: OnFinishEvent) => this._onFinish!({ result: event, ctx, input, writer: getActiveWriter() })\n : undefined,\n };\n }\n\n private resolveConfig(ctx: TContext, input: TInput): ResolvedAgentConfig | Promise<ResolvedAgentConfig> {\n if (!this._hasDynamicConfig) {\n return {\n model: this.config.model as LanguageModel,\n prompt: this.config.prompt as string | undefined,\n system: this.config.system as string | undefined,\n messages: this.config.messages as ModelMessage[] | undefined,\n tools: this._resolvedStaticTools ?? this.resolveTools(\n (this.config.tools as AgentToolSet<TContext> | undefined) ?? {}, ctx\n ),\n activeTools: this.config.activeTools as string[] | undefined,\n toolChoice: this.config.toolChoice as ToolChoice<ToolSet> | undefined,\n stopWhen: this.config.stopWhen as StopCondition<ToolSet> | Array<StopCondition<ToolSet>> | undefined,\n };\n }\n return this.resolveConfigAsync(ctx, input);\n }\n\n private async resolveConfigAsync(ctx: TContext, input: TInput): Promise<ResolvedAgentConfig> {\n const [model, prompt, system, messages, rawTools, activeTools, toolChoice, stopWhen] = await Promise.all([\n resolveValue(this.config.model, ctx, input),\n resolveValue(this.config.prompt, ctx, input),\n resolveValue(this.config.system, ctx, input),\n resolveValue(this.config.messages, ctx, input),\n resolveValue(this.config.tools, ctx, input),\n resolveValue(this.config.activeTools, ctx, input),\n resolveValue(this.config.toolChoice, ctx, input),\n resolveValue(this.config.stopWhen, ctx, input),\n ]);\n const tools = this.resolveTools(rawTools ?? {}, ctx);\n return { model, prompt, system, messages, tools, activeTools, toolChoice, stopWhen };\n }\n\n private resolveTools(\n tools: AgentToolSet<TContext>,\n ctx: TContext\n ): Record<string, Tool> {\n const entries = Object.entries(tools);\n if (entries.length === 0) return tools as Record<string, Tool>;\n let hasProvider = false;\n const resolved: Record<string, Tool> = {};\n for (const [key, toolOrProvider] of entries) {\n if (isToolProvider<TContext>(toolOrProvider)) {\n hasProvider = true;\n resolved[key] = toolOrProvider.createTool(ctx as Readonly<TContext>);\n } else {\n resolved[key] = toolOrProvider as Tool;\n }\n }\n return hasProvider ? resolved : (tools as Record<string, Tool>);\n }\n}\n","import { tool, type Tool, type ToolExecutionOptions, type FlexibleSchema, type UIMessageStreamWriter } from \"ai\";\nimport { getActiveWriter } from \"./utils\";\n\nexport const TOOL_PROVIDER_BRAND = Symbol.for(\"agent-workflow.ToolProvider\");\n\nexport type ToolExecuteOptions = ToolExecutionOptions & {\n writer?: UIMessageStreamWriter;\n};\n\nexport type ToolProviderConfig<TContext, TInput, TOutput> = {\n description?: string;\n input: FlexibleSchema<TInput>;\n output?: FlexibleSchema<unknown>;\n providerOptions?: unknown;\n execute: (input: TInput, ctx: Readonly<TContext>, options: ToolExecuteOptions) => Promise<TOutput>;\n};\n\nexport interface IToolProvider<TContext> {\n readonly [TOOL_PROVIDER_BRAND]: true;\n createTool(context: Readonly<TContext>): Tool;\n}\n\nexport class ToolProvider<\n TContext,\n TInput = unknown,\n TOutput = unknown,\n> implements IToolProvider<TContext> {\n readonly [TOOL_PROVIDER_BRAND] = true as const;\n private readonly config: ToolProviderConfig<TContext, TInput, TOutput>;\n\n constructor(config: ToolProviderConfig<TContext, TInput, TOutput>) {\n this.config = config;\n }\n\n createTool(context: Readonly<TContext>): Tool {\n const { execute, input: inputSchema, ...toolDef } = this.config;\n return tool({\n ...toolDef,\n parameters: inputSchema,\n execute: (input: TInput, options?: ToolExecutionOptions) => execute(input, context, { ...options, writer: getActiveWriter() } as ToolExecuteOptions),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any);\n }\n}\n\nexport function defineTool<TContext>() {\n return <TInput, TOutput>(\n config: ToolProviderConfig<TContext, TInput, TOutput>\n ): ToolProvider<TContext, TInput, TOutput> => new ToolProvider(config);\n}\n\nexport function isToolProvider<TContext>(obj: unknown): obj is IToolProvider<TContext> {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n TOOL_PROVIDER_BRAND in obj\n );\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { UIMessageStreamWriter } from \"ai\";\n\n// ── Stream writer context ────────────────────────────────────────────\n// Invisible to the user. The workflow sets the writer before agent execution;\n// tools and sub-agents read it automatically via getActiveWriter().\n\nconst writerStorage = new AsyncLocalStorage<UIMessageStreamWriter>();\n\nexport function runWithWriter<T>(writer: UIMessageStreamWriter, fn: () => T): T {\n return writerStorage.run(writer, fn);\n}\n\nexport function getActiveWriter(): UIMessageStreamWriter | undefined {\n return writerStorage.getStore();\n}\n\n// ── Common types ─────────────────────────────────────────────────────\n\nexport type MaybePromise<T> = T | Promise<T>;\n\n/**\n * A value that can be static or derived from context and input.\n * Used for agent config fields that may need runtime resolution.\n *\n * Functions may return a Promise for async resolution; static values are always sync.\n */\nexport type Resolvable<TCtx, TInput, TValue> =\n | TValue\n | ((ctx: Readonly<TCtx>, input: TInput) => TValue | Promise<TValue>);\n\nexport function resolveValue<TCtx, TInput, TValue>(\n value: Resolvable<TCtx, TInput, TValue>,\n ctx: TCtx,\n input: TInput\n): TValue | Promise<TValue>;\nexport function resolveValue<TCtx, TInput, TValue>(\n value: Resolvable<TCtx, TInput, TValue> | undefined,\n ctx: TCtx,\n input: TInput\n): TValue | Promise<TValue> | undefined {\n if (typeof value === \"function\") {\n return (value as (ctx: TCtx, input: TInput) => TValue | Promise<TValue>)(ctx, input);\n }\n return value;\n}\n\n/**\n * Extract structured output from an AI SDK result, falling back to text.\n * Works for both generate (sync .output/.text) and stream (async .output/.text) results.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function extractOutput(result: any, hasStructuredOutput: boolean): Promise<unknown> {\n if (hasStructuredOutput) {\n const output = await result.output;\n if (output !== undefined) return output;\n }\n return await result.text;\n}\n","import {\n createUIMessageStream,\n type UIMessageStreamWriter,\n} from \"ai\";\nimport { type Agent, type GenerateTextResult, type StreamTextResult } from \"./agent\";\nimport { extractOutput, runWithWriter, type MaybePromise } from \"./utils\";\n\n// ── Error Types ─────────────────────────────────────────────────────\n\nexport class WorkflowBranchError extends Error {\n constructor(\n public readonly branchType: \"predicate\" | \"select\",\n message: string,\n ) {\n super(message);\n this.name = \"WorkflowBranchError\";\n }\n}\n\nexport class WorkflowLoopError extends Error {\n constructor(\n public readonly iterations: number,\n public readonly maxIterations: number,\n ) {\n super(`Loop exceeded maximum iterations (${maxIterations})`);\n this.name = \"WorkflowLoopError\";\n }\n}\n\n// ── Shared Agent Step Hooks ─────────────────────────────────────────\n\nexport interface AgentStepHooks<TContext, TOutput, TNextOutput> {\n mapGenerateResult?: (params: { result: GenerateTextResult; ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>;\n mapStreamResult?: (params: { result: StreamTextResult; ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>;\n onGenerateResult?: (params: { result: GenerateTextResult; ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<void>;\n onStreamResult?: (params: { result: StreamTextResult; ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<void>;\n handleStream?: (params: {\n result: StreamTextResult;\n writer: UIMessageStreamWriter;\n ctx: Readonly<TContext>;\n }) => MaybePromise<void>;\n}\n\n// ── Step Options ────────────────────────────────────────────────────\n\nexport type StepOptions<TContext, TOutput, TNextOutput> = AgentStepHooks<TContext, TOutput, TNextOutput>;\n\n// ── Branch Types ────────────────────────────────────────────────────\n\nexport interface BranchCase<TContext, TOutput, TNextOutput> extends AgentStepHooks<TContext, TOutput, TNextOutput> {\n when?: (params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<boolean>;\n agent: Agent<TContext, TOutput, TNextOutput>;\n}\n\nexport interface BranchSelect<TContext, TOutput, TKeys extends string, TNextOutput> extends AgentStepHooks<TContext, TOutput, TNextOutput> {\n select: (params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TKeys>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n agents: Record<TKeys, Agent<TContext, any, TNextOutput>>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n fallback?: Agent<TContext, any, TNextOutput>;\n}\n\n// ── Result Types ────────────────────────────────────────────────────\n\nexport interface WorkflowResult<TOutput> {\n output: TOutput;\n}\n\nexport interface WorkflowStreamResult<TOutput> {\n stream: ReadableStream;\n output: Promise<TOutput>;\n}\n\nexport interface WorkflowStreamOptions {\n onError?: (error: unknown) => string;\n onFinish?: () => MaybePromise<void>;\n}\n\n// ── Loop Types ──────────────────────────────────────────────────────\n\ntype LoopPredicate<TContext, TOutput> = (params: {\n output: TOutput;\n ctx: Readonly<TContext>;\n iterations: number;\n}) => MaybePromise<boolean>;\n\n// Exactly one of `until` or `while` — never both.\nexport type RepeatOptions<TContext, TOutput> =\n | { until: LoopPredicate<TContext, TOutput>; while?: never; maxIterations?: number }\n | { while: LoopPredicate<TContext, TOutput>; until?: never; maxIterations?: number };\n\n// Extracts the element type from an array type. Resolves to `never` for non-arrays,\n// making foreach uncallable at compile time when the previous step doesn't produce an array.\ntype ElementOf<T> = T extends readonly (infer E)[] ? E : never;\n\n// ── Step Node ───────────────────────────────────────────────────────\n\ntype StepNode =\n | { readonly type: \"step\"; readonly id: string; readonly execute: (state: RuntimeState) => MaybePromise<void> }\n | { readonly type: \"catch\"; readonly id: string; readonly catchFn: (params: { error: unknown; ctx: unknown; lastOutput: unknown; stepId: string }) => MaybePromise<unknown> }\n | { readonly type: \"finally\"; readonly id: string; readonly execute: (state: RuntimeState) => MaybePromise<void> };\n\ninterface RuntimeState {\n ctx: unknown;\n output: unknown;\n mode: \"generate\" | \"stream\";\n writer?: UIMessageStreamWriter;\n}\n\n// ── Sealed Workflow (returned by finally — execution only) ───────────\n\nexport class SealedWorkflow<\n TContext,\n TInput = void,\n TOutput = void,\n> {\n readonly id?: string;\n protected readonly steps: ReadonlyArray<StepNode>;\n\n protected constructor(steps: ReadonlyArray<StepNode>, id?: string) {\n this.steps = steps;\n this.id = id;\n }\n\n // ── Execution ─────────────────────────────────────────────────\n\n async generate(ctx: TContext, ...args: TInput extends void ? [input?: TInput] : [input: TInput]): Promise<WorkflowResult<TOutput>> {\n const input = args[0];\n const state: RuntimeState = {\n ctx,\n output: input,\n mode: \"generate\",\n };\n\n await this.execute(state);\n\n return {\n output: state.output as TOutput,\n };\n }\n\n stream(\n ctx: TContext,\n ...args: TInput extends void\n ? [input?: TInput, options?: WorkflowStreamOptions]\n : [input: TInput, options?: WorkflowStreamOptions]\n ): WorkflowStreamResult<TOutput> {\n const input = args[0];\n const options = args[1] as WorkflowStreamOptions | undefined;\n\n let resolveOutput: (value: TOutput) => void;\n let rejectOutput: (error: unknown) => void;\n const outputPromise = new Promise<TOutput>((res, rej) => {\n resolveOutput = res;\n rejectOutput = rej;\n });\n\n // Prevent unhandled rejection warning if the consumer never awaits `output`.\n // The original promise still rejects normally when awaited.\n outputPromise.catch(() => {});\n\n const stream = createUIMessageStream({\n execute: async ({ writer }) => {\n const state: RuntimeState = {\n ctx,\n output: input,\n mode: \"stream\",\n writer,\n };\n\n try {\n await this.execute(state);\n resolveOutput(state.output as TOutput);\n } catch (error) {\n rejectOutput!(error);\n throw error;\n }\n },\n ...(options?.onError ? { onError: options.onError } : {}),\n ...(options?.onFinish ? { onFinish: options.onFinish } : {}),\n });\n\n return {\n stream,\n output: outputPromise,\n };\n }\n\n // ── Internal: execute pipeline ────────────────────────────────\n\n protected async execute(state: RuntimeState): Promise<void> {\n if (this.steps.length === 0) {\n throw new Error(\"Workflow has no steps. Add at least one step before calling generate() or stream().\");\n }\n\n let pendingError: { error: unknown; stepId: string } | null = null;\n\n for (const node of this.steps) {\n if (node.type === \"finally\") {\n await node.execute(state);\n continue;\n }\n\n if (node.type === \"catch\") {\n if (!pendingError) continue;\n try {\n state.output = await node.catchFn({\n error: pendingError.error,\n ctx: state.ctx,\n lastOutput: state.output,\n stepId: pendingError.stepId,\n });\n pendingError = null;\n } catch (catchError) {\n pendingError = { error: catchError, stepId: node.id };\n }\n continue;\n }\n\n // type === \"step\" — skip while in error state\n if (pendingError) continue;\n\n try {\n await node.execute(state);\n } catch (error) {\n pendingError = { error, stepId: node.id };\n }\n }\n\n if (pendingError) throw pendingError.error;\n }\n\n // ── Internal: execute a nested workflow within a step/loop ─────\n // Defined on SealedWorkflow (not Workflow) because TypeScript's protected\n // access rules only allow calling workflow.execute() from the same class.\n\n protected async executeNestedWorkflow(\n state: RuntimeState,\n workflow: SealedWorkflow<TContext, unknown, unknown>,\n ): Promise<void> {\n await workflow.execute(state);\n }\n\n // ── Internal: execute an agent within a step/branch ───────────\n // In stream mode, output extraction awaits the full stream before returning.\n // Streaming benefits the client (incremental output), not pipeline throughput —\n // each step still runs sequentially.\n\n protected async executeAgent<TAgentInput, TNextOutput>(\n state: RuntimeState,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n agent: Agent<TContext, any, TNextOutput>,\n ctx: TContext,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options?: AgentStepHooks<TContext, any, TNextOutput>,\n ): Promise<void> {\n const input = state.output as TAgentInput;\n const hasStructuredOutput = agent.hasOutput;\n\n if (state.mode === \"stream\" && state.writer) {\n const writer = state.writer;\n // Run inside writer context so tools (asTool, defineTool) can access the writer automatically\n await runWithWriter(writer, async () => {\n const result = await (agent.stream as (ctx: TContext, input: unknown) => Promise<StreamTextResult>)(ctx, state.output);\n\n if (options?.handleStream) {\n await options.handleStream({ result, writer, ctx });\n } else {\n writer.merge(result.toUIMessageStream());\n }\n\n if (options?.onStreamResult) {\n await options.onStreamResult({ result, ctx, input });\n }\n\n if (options?.mapStreamResult) {\n state.output = await options.mapStreamResult({ result, ctx, input });\n } else {\n state.output = await extractOutput(result, hasStructuredOutput);\n }\n });\n } else {\n const result = await (agent.generate as (ctx: TContext, input: unknown) => Promise<GenerateTextResult>)(ctx, state.output);\n\n if (options?.onGenerateResult) {\n await options.onGenerateResult({ result, ctx, input });\n }\n\n if (options?.mapGenerateResult) {\n state.output = await options.mapGenerateResult({ result, ctx, input });\n } else {\n state.output = await extractOutput(result, hasStructuredOutput);\n }\n }\n }\n}\n\n// ── Workflow ────────────────────────────────────────────────────────\n\nexport class Workflow<\n TContext,\n TInput = void,\n TOutput = void,\n> extends SealedWorkflow<TContext, TInput, TOutput> {\n\n private constructor(steps: ReadonlyArray<StepNode> = [], id?: string) {\n super(steps, id);\n }\n\n static create<TContext, TInput = void>(options?: { id?: string }): Workflow<TContext, TInput, TInput> {\n return new Workflow<TContext, TInput, TInput>([], options?.id);\n }\n\n static from<TContext, TInput, TOutput>(\n agent: Agent<TContext, TInput, TOutput>,\n options?: StepOptions<TContext, TInput, TOutput>\n ): Workflow<TContext, TInput, TOutput> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, any>([]).step(agent, options);\n }\n\n // ── step: agent overload ──────────────────────────────────────\n\n step<TNextOutput>(\n agent: Agent<TContext, TOutput, TNextOutput>,\n options?: StepOptions<TContext, TOutput, TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── step: nested workflow overload ─────────────────────────────\n\n step<TNextOutput>(\n workflow: SealedWorkflow<TContext, TOutput, TNextOutput>,\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── step: transform overload (replaces map + tap) ─────────────\n\n step<TNextOutput>(\n id: string,\n fn: (params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── step: implementation ──────────────────────────────────────\n\n step<TNextOutput>(\n target: Agent<TContext, TOutput, TNextOutput> | SealedWorkflow<TContext, TOutput, TNextOutput> | string,\n optionsOrFn?: StepOptions<TContext, TOutput, TNextOutput> | ((params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>)\n ): Workflow<TContext, TInput, TNextOutput> {\n // Nested workflow overload: step(workflow)\n if (target instanceof SealedWorkflow) {\n const workflow = target;\n const node: StepNode = {\n type: \"step\",\n id: workflow.id ?? \"nested-workflow\",\n execute: async (state) => {\n await this.executeNestedWorkflow(state, workflow as SealedWorkflow<TContext, unknown, unknown>);\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n // Transform overload: step(id, fn)\n if (typeof target === \"string\") {\n if (typeof optionsOrFn !== \"function\") {\n throw new Error(`Workflow step(\"${target}\"): second argument must be a function`);\n }\n const fn = optionsOrFn as (params: { ctx: Readonly<TContext>; input: TOutput }) => MaybePromise<TNextOutput>;\n const node: StepNode = {\n type: \"step\",\n id: target,\n execute: async (state) => {\n state.output = await fn({\n ctx: state.ctx as Readonly<TContext>,\n input: state.output as TOutput,\n });\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n // Agent overload: step(agent, options?)\n const agent = target;\n const options = optionsOrFn as StepOptions<TContext, TOutput, TNextOutput> | undefined;\n const node: StepNode = {\n type: \"step\",\n id: agent.id,\n execute: async (state) => {\n const ctx = state.ctx as TContext;\n await this.executeAgent(state, agent, ctx, options);\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n // ── branch: predicate routing (array) ─────────────────────────\n\n branch<TNextOutput>(\n cases: BranchCase<TContext, TOutput, TNextOutput>[]\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── branch: key routing (select) ──────────────────────────────\n\n branch<TKeys extends string, TNextOutput>(\n config: BranchSelect<TContext, TOutput, TKeys, TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput>;\n\n // ── branch: implementation ────────────────────────────────────\n\n branch<TKeys extends string, TNextOutput>(\n casesOrConfig: BranchCase<TContext, TOutput, TNextOutput>[] | BranchSelect<TContext, TOutput, TKeys, TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput> {\n if (Array.isArray(casesOrConfig)) {\n return this.branchPredicate(casesOrConfig);\n }\n return this.branchSelect(casesOrConfig);\n }\n\n private branchPredicate<TNextOutput>(\n cases: BranchCase<TContext, TOutput, TNextOutput>[]\n ): Workflow<TContext, TInput, TNextOutput> {\n const node: StepNode = {\n type: \"step\",\n id: \"branch:predicate\",\n execute: async (state) => {\n const ctx = state.ctx as TContext;\n const input = state.output as TOutput;\n\n for (const branchCase of cases) {\n if (branchCase.when) {\n const match = await branchCase.when({ ctx, input });\n if (!match) continue;\n }\n\n // Matched (or no `when` = default)\n await this.executeAgent(state, branchCase.agent, ctx, branchCase);\n return;\n }\n\n throw new WorkflowBranchError(\"predicate\", `No branch matched and no default branch (a case without \\`when\\`) was provided. Input: ${JSON.stringify(input)}`);\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n private branchSelect<TKeys extends string, TNextOutput>(\n config: BranchSelect<TContext, TOutput, TKeys, TNextOutput>\n ): Workflow<TContext, TInput, TNextOutput> {\n const node: StepNode = {\n type: \"step\",\n id: \"branch:select\",\n execute: async (state) => {\n const ctx = state.ctx as TContext;\n const input = state.output as TOutput;\n const key = await config.select({ ctx, input });\n\n let agent = config.agents[key];\n if (!agent) {\n if (config.fallback) {\n agent = config.fallback;\n } else {\n throw new WorkflowBranchError(\"select\", `No agent found for key \"${key}\" and no fallback provided. Available keys: ${Object.keys(config.agents).join(\", \")}`);\n }\n }\n\n await this.executeAgent(state, agent, ctx, config);\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput>([...this.steps, node] as any, this.id);\n }\n\n // ── foreach: array iteration ─────────────────────────────────\n\n foreach<TNextOutput>(\n target: Agent<TContext, ElementOf<TOutput>, TNextOutput> | SealedWorkflow<TContext, ElementOf<TOutput>, TNextOutput>,\n options?: { concurrency?: number },\n ): Workflow<TContext, TInput, TNextOutput[]> {\n const concurrency = options?.concurrency ?? 1;\n const isWorkflow = target instanceof SealedWorkflow;\n const id = isWorkflow ? (target.id ?? \"foreach\") : `foreach:${(target as Agent<TContext, ElementOf<TOutput>, TNextOutput>).id}`;\n\n const node: StepNode = {\n type: \"step\",\n id,\n execute: async (state) => {\n const items = state.output;\n if (!Array.isArray(items)) {\n throw new Error(`foreach \"${id}\": expected array input, got ${typeof items}`);\n }\n\n const ctx = state.ctx as TContext;\n const results: unknown[] = new Array(items.length);\n\n // Streaming is intentionally not propagated to foreach items —\n // each item runs in generate mode because merging interleaved\n // streams from parallel items into a single writer is not supported.\n const executeItem = async (item: unknown, index: number) => {\n const itemState: RuntimeState = { ctx: state.ctx, output: item, mode: \"generate\" };\n if (isWorkflow) {\n await this.executeNestedWorkflow(itemState, target as SealedWorkflow<TContext, unknown, unknown>);\n } else {\n await this.executeAgent(itemState, target as Agent<TContext, unknown, TNextOutput>, ctx);\n }\n results[index] = itemState.output;\n };\n\n if (concurrency <= 1) {\n for (let i = 0; i < items.length; i++) {\n await executeItem(items[i], i);\n }\n } else {\n for (let i = 0; i < items.length; i += concurrency) {\n const batch = items.slice(i, i + concurrency);\n await Promise.all(batch.map((item, j) => executeItem(item, i + j)));\n }\n }\n\n state.output = results;\n },\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new Workflow<TContext, TInput, TNextOutput[]>([...this.steps, node] as any, this.id);\n }\n\n // ── repeat: conditional loop ─────────────────────────────────\n\n repeat(\n target: Agent<TContext, TOutput, TOutput> | SealedWorkflow<TContext, TOutput, TOutput>,\n options: RepeatOptions<TContext, TOutput>,\n ): Workflow<TContext, TInput, TOutput> {\n const maxIterations = options.maxIterations ?? 10;\n const isWorkflow = target instanceof SealedWorkflow;\n const id = isWorkflow ? (target.id ?? \"repeat\") : `repeat:${(target as Agent<TContext, TOutput, TOutput>).id}`;\n const predicate: LoopPredicate<TContext, TOutput> = options.until\n ?? (async (p) => !(await options.while!(p)));\n\n const node: StepNode = {\n type: \"step\",\n id,\n execute: async (state) => {\n const ctx = state.ctx as TContext;\n\n for (let i = 1; i <= maxIterations; i++) {\n if (isWorkflow) {\n await this.executeNestedWorkflow(state, target as SealedWorkflow<TContext, unknown, unknown>);\n } else {\n await this.executeAgent(state, target as Agent<TContext, TOutput, TOutput>, ctx);\n }\n\n const done = await predicate({\n output: state.output as TOutput,\n ctx: ctx as Readonly<TContext>,\n iterations: i,\n });\n if (done) return;\n }\n\n throw new WorkflowLoopError(maxIterations, maxIterations);\n },\n };\n return new Workflow<TContext, TInput, TOutput>([...this.steps, node], this.id);\n }\n\n // ── catch ─────────────────────────────────────────────────────\n\n catch(\n id: string,\n fn: (params: { error: unknown; ctx: Readonly<TContext>; lastOutput: TOutput; stepId: string }) => MaybePromise<TOutput>\n ): Workflow<TContext, TInput, TOutput> {\n if (!this.steps.some(s => s.type === \"step\")) {\n throw new Error(`Workflow: catch(\"${id}\") requires at least one preceding step.`);\n }\n const node: StepNode = {\n type: \"catch\",\n id,\n catchFn: fn as (params: { error: unknown; ctx: unknown; lastOutput: unknown; stepId: string }) => MaybePromise<unknown>,\n };\n return new Workflow<TContext, TInput, TOutput>([...this.steps, node], this.id);\n }\n\n // ── finally (terminal — returns sealed workflow) ──────────────\n\n finally(\n id: string,\n fn: (params: { ctx: Readonly<TContext> }) => MaybePromise<void>\n ): SealedWorkflow<TContext, TInput, TOutput> {\n const node: StepNode = {\n type: \"finally\",\n id,\n execute: async (state) => {\n await fn({ ctx: state.ctx as Readonly<TContext> });\n },\n };\n return new SealedWorkflow<TContext, TInput, TOutput>([...this.steps, node], this.id);\n }\n}\n\n"],"mappings":"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","names":["tool","tool","result","node"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pipeai",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "A typed multi-agent workflow pipeline built on top of the Vercel AI SDK",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -27,15 +27,16 @@
27
27
  "test:watch": "vitest"
28
28
  },
29
29
  "peerDependencies": {
30
- "ai": "^6.0.0",
30
+ "ai": "^6.0.116",
31
31
  "zod": ">=3.0.0 || >=4.0.0"
32
32
  },
33
33
  "devDependencies": {
34
- "ai": "^6.0.0",
34
+ "@types/node": "^25.5.0",
35
+ "ai": "^6.0.116",
35
36
  "tsup": "^8.5.1",
36
37
  "typescript": "^5.7.3",
37
38
  "vitest": "^4.0.18",
38
- "zod": "^3.24.0"
39
+ "zod": "^4.3.6"
39
40
  },
40
41
  "keywords": [
41
42
  "ai",