@ai-sdk/workflow 1.0.69 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/workflow",
3
- "version": "1.0.69",
3
+ "version": "2.0.0",
4
4
  "type": "module",
5
5
  "description": "WorkflowAgent for building AI agents with AI SDK",
6
6
  "license": "Apache-2.0",
@@ -28,20 +28,21 @@
28
28
  "dependencies": {
29
29
  "ajv": "^8.20.0",
30
30
  "@ai-sdk/provider": "4.0.7",
31
- "@ai-sdk/provider-utils": "5.0.27",
32
- "ai": "7.0.68"
31
+ "@ai-sdk/provider-utils": "5.0.28",
32
+ "ai": "7.0.70"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/node": "22.19.19",
36
- "@workflow/vitest": "4.0.5",
36
+ "@workflow/vitest": "5.0.0-beta.42",
37
37
  "tsup": "^8.5.1",
38
38
  "typescript": "5.8.3",
39
39
  "vitest": "4.1.6",
40
- "workflow": "4.2.4",
41
- "zod": "3.25.76",
40
+ "workflow": "5.0.0-beta.42",
41
+ "zod": "4.4.3",
42
42
  "@vercel/ai-tsconfig": "0.0.0"
43
43
  },
44
44
  "peerDependencies": {
45
+ "workflow": "^5.0.0-beta.42",
45
46
  "zod": "^3.25.76 || ^4.1.8"
46
47
  },
47
48
  "engines": {
@@ -6,7 +6,7 @@ import { isAbortError } from '@ai-sdk/provider-utils';
6
6
  import {
7
7
  experimental_streamLanguageModelCall as streamModelCall,
8
8
  gateway,
9
- type Experimental_LanguageModelStreamPart as ModelCallStreamPart,
9
+ type Experimental_LanguageModelStreamPart,
10
10
  type FinishReason,
11
11
  type LanguageModel,
12
12
  type LanguageModelUsage,
@@ -22,7 +22,10 @@ import {
22
22
  resolveSerializableTools,
23
23
  type SerializableToolDef,
24
24
  } from './serializable-schema.js';
25
- export type { Experimental_LanguageModelStreamPart as ModelCallStreamPart } from 'ai';
25
+
26
+ export type ModelCallStreamPart<TTools extends ToolSet = ToolSet> =
27
+ | Experimental_LanguageModelStreamPart<TTools>
28
+ | { type: 'reset-step' };
26
29
 
27
30
  export type ModelStopCondition = StopCondition<NoInfer<ToolSet>, any>;
28
31
 
@@ -248,6 +251,11 @@ export async function doStreamStep(
248
251
  const writer = writable?.getWriter();
249
252
 
250
253
  try {
254
+ // A workflow step can be retried after already writing partial output.
255
+ // Reset the current UI step before every attempt so a retry invalidates
256
+ // chunks left behind by an earlier execution.
257
+ await writer?.write({ type: 'reset-step' });
258
+
251
259
  for await (const part of modelStream) {
252
260
  switch (part.type) {
253
261
  case 'text-delta':
@@ -115,6 +115,16 @@ export async function* normalizeUIMessageStreamParts(
115
115
 
116
116
  for await (const chunk of source) {
117
117
  switch (chunk.type) {
118
+ case 'reset-step':
119
+ // A retried model-call step starts a new frame. Forget parts from the
120
+ // invalidated attempt so reused ids are framed normally.
121
+ text.open.clear();
122
+ text.ended.clear();
123
+ reasoning.open.clear();
124
+ reasoning.ended.clear();
125
+ yield chunk;
126
+ break;
127
+
118
128
  case 'finish-step':
119
129
  // The consumer clears its active-part maps here, so part ids may be
120
130
  // legitimately reused in the next step. Reset to match.
@@ -7,7 +7,6 @@ import type {
7
7
  import type { Context } from '@ai-sdk/provider-utils';
8
8
  import {
9
9
  experimental_filterActiveTools as filterActiveTools,
10
- type Experimental_LanguageModelStreamPart as ModelCallStreamPart,
11
10
  type Experimental_SandboxSession as SandboxSession,
12
11
  type Instructions,
13
12
  type LanguageModel,
@@ -22,6 +21,7 @@ import { createRestrictedTelemetryDispatcher } from 'ai/internal';
22
21
  import {
23
22
  type DoStreamStepRawResult,
24
23
  doStreamStep,
24
+ type ModelCallStreamPart,
25
25
  type ModelStopCondition,
26
26
  type ParsedToolCall,
27
27
  type ProviderExecutedToolResult,
@@ -1,8 +1,5 @@
1
- import type {
2
- Experimental_LanguageModelStreamPart as ModelCallStreamPart,
3
- ToolSet,
4
- UIMessageChunk,
5
- } from 'ai';
1
+ import type { ToolSet, UIMessageChunk } from 'ai';
2
+ import type { ModelCallStreamPart } from './do-stream-step.js';
6
3
 
7
4
  /**
8
5
  * Convert a single ModelCallStreamPart to a UIMessageChunk.
@@ -12,6 +9,9 @@ export function toUIMessageChunk(
12
9
  part: ModelCallStreamPart<ToolSet>,
13
10
  ): UIMessageChunk | undefined {
14
11
  switch (part.type) {
12
+ case 'reset-step':
13
+ return { type: 'reset-step' };
14
+
15
15
  case 'text-start':
16
16
  return {
17
17
  type: 'text-start',
@@ -20,7 +20,6 @@ import {
20
20
  type FinishReason,
21
21
  type LanguageModelResponseMetadata,
22
22
  type LanguageModelUsage,
23
- type Experimental_LanguageModelStreamPart as ModelCallStreamPart,
24
23
  type ModelMessage,
25
24
  type StepResult,
26
25
  type StopCondition,
@@ -45,6 +44,7 @@ import {
45
44
  validateApprovedToolApprovals,
46
45
  } from 'ai/internal';
47
46
  import { createLanguageModelToolResultOutput } from './create-language-model-tool-result-output.js';
47
+ import type { ModelCallStreamPart } from './do-stream-step.js';
48
48
  import { streamTextIterator } from './stream-text-iterator.js';
49
49
 
50
50
  // Re-export for consumers
@@ -59,6 +59,10 @@ function createOrphanFilter(): OrphanFilter {
59
59
 
60
60
  function shouldDrop(chunk: UIMessageChunk): boolean {
61
61
  switch (chunk.type) {
62
+ case 'reset-step':
63
+ seenStartedIds.clear();
64
+ seenStartedToolCallIds.clear();
65
+ return false;
62
66
  case 'text-start':
63
67
  case 'reasoning-start':
64
68
  seenStartedIds.add(chunk.id);