@ai-sdk/workflow 2.0.54 → 2.0.57

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/workflow",
3
- "version": "2.0.54",
3
+ "version": "2.0.57",
4
4
  "type": "module",
5
5
  "description": "WorkflowAgent for building AI agents with AI SDK",
6
6
  "license": "Apache-2.0",
@@ -36,9 +36,9 @@
36
36
  }
37
37
  },
38
38
  "dependencies": {
39
- "@ai-sdk/provider": "4.0.20",
40
- "@ai-sdk/provider-utils": "5.0.52",
41
- "ai": "7.0.123",
39
+ "@ai-sdk/provider": "4.0.21",
40
+ "@ai-sdk/provider-utils": "5.0.53",
41
+ "ai": "7.0.126",
42
42
  "ajv": "^8.20.0"
43
43
  },
44
44
  "devDependencies": {
@@ -3,12 +3,14 @@ import type {
3
3
  LanguageModelV4CallOptions,
4
4
  LanguageModelV4Prompt,
5
5
  LanguageModelV4Source,
6
+ LanguageModelV4StreamPart,
6
7
  SharedV4ProviderMetadata,
7
8
  } from '@ai-sdk/provider';
8
- import { isAbortError } from '@ai-sdk/provider-utils';
9
+ import { asArray, isAbortError } from '@ai-sdk/provider-utils';
9
10
  import {
10
11
  experimental_streamLanguageModelCall as streamModelCall,
11
12
  gateway,
13
+ wrapLanguageModel,
12
14
  type Experimental_LanguageModelStreamPart,
13
15
  type FinishReason,
14
16
  type LanguageModel,
@@ -20,7 +22,7 @@ import {
20
22
  type ToolSet,
21
23
  } from 'ai';
22
24
  import { prepareRetries } from 'ai/internal';
23
- import type { ProviderOptions } from './workflow-agent.js';
25
+ import type { ProviderOptions, StreamTextTransform } from './workflow-agent.js';
24
26
  import {
25
27
  resolveSerializableTools,
26
28
  type SerializableToolDef,
@@ -72,6 +74,9 @@ export interface DoStreamStepOptions {
72
74
  includeRawChunks?: boolean;
73
75
  repairToolCall?: ToolCallRepairFunction<ToolSet>;
74
76
  responseFormat?: LanguageModelV4CallOptions['responseFormat'];
77
+ experimental_transform?:
78
+ | StreamTextTransform<ToolSet>
79
+ | Array<StreamTextTransform<ToolSet>>;
75
80
  }
76
81
 
77
82
  /**
@@ -201,7 +206,7 @@ export async function doStreamStep(
201
206
  : AbortSignal.any([options.abortSignal, AbortSignal.timeout(timeout)]);
202
207
 
203
208
  // Resolve model inside step (must happen here for serialization boundary)
204
- const model: LanguageModel =
209
+ const model =
205
210
  typeof modelInit === 'string'
206
211
  ? gateway.languageModel(modelInit)
207
212
  : modelInit;
@@ -213,6 +218,27 @@ export async function doStreamStep(
213
218
  const tools = serializedTools
214
219
  ? resolveSerializableTools(serializedTools)
215
220
  : undefined;
221
+ const modelWithTransforms =
222
+ options?.experimental_transform == null
223
+ ? model
224
+ : wrapLanguageModel({
225
+ model,
226
+ middleware: {
227
+ specificationVersion: 'v4',
228
+ wrapStream: async ({ doStream }) => {
229
+ const { stream, ...result } = await doStream();
230
+
231
+ return {
232
+ ...result,
233
+ stream: applyStreamTransforms({
234
+ stream,
235
+ transforms: asArray(options.experimental_transform!),
236
+ tools: tools ?? {},
237
+ }),
238
+ };
239
+ },
240
+ },
241
+ });
216
242
 
217
243
  // streamModelCall derives the model responseFormat from its output spec.
218
244
  // WorkflowAgent parses output outside the model-call helper, so this minimal
@@ -247,7 +273,7 @@ export async function doStreamStep(
247
273
  try {
248
274
  const { stream } = await retry(() =>
249
275
  streamModelCall({
250
- model,
276
+ model: modelWithTransforms,
251
277
  // streamModelCall expects Prompt (ModelMessage[]) but we pass the
252
278
  // pre-converted LanguageModelV4Prompt. standardizePrompt inside
253
279
  // streamModelCall handles both formats.
@@ -556,6 +582,61 @@ export async function doStreamStep(
556
582
  // another retry layer around the durable step.
557
583
  doStreamStep.maxRetries = 0;
558
584
 
585
+ function applyStreamTransforms({
586
+ stream,
587
+ transforms,
588
+ tools,
589
+ }: {
590
+ stream: ReadableStream<LanguageModelV4StreamPart>;
591
+ transforms: Array<StreamTextTransform<ToolSet>>;
592
+ tools: ToolSet;
593
+ }): ReadableStream<LanguageModelV4StreamPart> {
594
+ const sourceReader = stream.getReader();
595
+ let stopped = false;
596
+
597
+ const stopStream = () => {
598
+ if (stopped) {
599
+ return;
600
+ }
601
+
602
+ stopped = true;
603
+ void sourceReader.cancel().catch(() => {});
604
+ };
605
+
606
+ let transformedStream = new ReadableStream<LanguageModelV4StreamPart>(
607
+ {
608
+ async pull(controller) {
609
+ if (stopped) {
610
+ controller.close();
611
+ return;
612
+ }
613
+
614
+ const { done, value } = await sourceReader.read();
615
+
616
+ if (done || stopped) {
617
+ controller.close();
618
+ return;
619
+ }
620
+
621
+ controller.enqueue(value);
622
+ },
623
+ cancel(reason) {
624
+ stopped = true;
625
+ return sourceReader.cancel(reason);
626
+ },
627
+ },
628
+ { highWaterMark: 0 },
629
+ );
630
+
631
+ for (const transform of transforms) {
632
+ transformedStream = transformedStream.pipeThrough(
633
+ transform({ tools, stopStream }),
634
+ );
635
+ }
636
+
637
+ return transformedStream;
638
+ }
639
+
559
640
  function upsertTextContentPart({
560
641
  content,
561
642
  textPartIndexes,
@@ -47,6 +47,7 @@ import type {
47
47
  WorkflowAgentOnStepFinishCallback,
48
48
  TelemetryOptions,
49
49
  WorkflowAgentOnStepStartCallback,
50
+ StreamTextTransform,
50
51
  } from './workflow-agent.js';
51
52
 
52
53
  // Re-export for consumers
@@ -140,6 +141,7 @@ export async function* streamTextIterator({
140
141
  timeoutAt,
141
142
  repairToolCall,
142
143
  responseFormat,
144
+ experimental_transform,
143
145
  experimental_sandbox: sandbox,
144
146
  }: {
145
147
  prompt: LanguageModelV4Prompt;
@@ -164,6 +166,9 @@ export async function* streamTextIterator({
164
166
  timeoutAt?: number;
165
167
  repairToolCall?: ToolCallRepairFunction<ToolSet>;
166
168
  responseFormat?: LanguageModelV4CallOptions['responseFormat'];
169
+ experimental_transform?:
170
+ | StreamTextTransform<ToolSet>
171
+ | Array<StreamTextTransform<ToolSet>>;
167
172
  experimental_sandbox?: SandboxSession;
168
173
  }): AsyncGenerator<
169
174
  StreamTextIteratorYieldValue,
@@ -370,6 +375,7 @@ export async function* streamTextIterator({
370
375
  timeoutAt,
371
376
  repairToolCall,
372
377
  responseFormat,
378
+ experimental_transform,
373
379
  },
374
380
  );
375
381
 
@@ -2325,6 +2325,10 @@ export class WorkflowAgent<
2325
2325
  options.experimental_repairToolCall ??
2326
2326
  this.repairToolCall) as ToolCallRepairFunction<ToolSet> | undefined,
2327
2327
  responseFormat: await (options.output ?? this.output)?.responseFormat,
2328
+ experimental_transform: options.experimental_transform as
2329
+ | StreamTextTransform<ToolSet>
2330
+ | Array<StreamTextTransform<ToolSet>>
2331
+ | undefined,
2328
2332
  experimental_sandbox: sandbox,
2329
2333
  });
2330
2334