workflow 5.0.0-beta.24 → 5.0.0-beta.25

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.
@@ -14,6 +14,10 @@ related:
14
14
  - /docs/api-reference/workflow/define-hook
15
15
  ---
16
16
 
17
+ <Callout type="warn">
18
+ The examples below use the deprecated `DurableAgent` API. For new agents, use AI SDK's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) and follow the [migration guide](https://ai-sdk.dev/v7/docs/agents/workflow-agent#migrating-from-durableagent). The session-modeling patterns here (single- vs multi-turn, hooks, stream reconnection) apply to either API.
19
+ </Callout>
20
+
17
21
  Chat sessions in AI agents can be modeled at different layers of your architecture. The choice affects state ownership and how you handle interruptions and reconnections.
18
22
 
19
23
  While there are many ways to model chat sessions, the two most common categories are single-turn and multi-turn.
@@ -83,7 +87,7 @@ Chat messages need to be stored somewhere—typically a database. In this exampl
83
87
  "use client";
84
88
 
85
89
  import { useChat } from "@ai-sdk/react";
86
- import { WorkflowChatTransport } from "@workflow/ai"; // [!code highlight]
90
+ import { WorkflowChatTransport } from "@ai-sdk/workflow"; // [!code highlight]
87
91
  import { useParams } from "next/navigation";
88
92
  import { useMemo } from "react";
89
93
 
@@ -338,7 +342,7 @@ A custom hook wraps `useChat` to manage the multi-turn session. It handles:
338
342
 
339
343
  import type { UIMessage, UIDataTypes, ChatStatus } from "ai";
340
344
  import { useChat } from "@ai-sdk/react";
341
- import { WorkflowChatTransport } from "@workflow/ai";
345
+ import { WorkflowChatTransport } from "@ai-sdk/workflow";
342
346
  import { useState, useCallback, useMemo, useEffect, useRef } from "react";
343
347
 
344
348
  const STORAGE_KEY = "workflow-run-id";
@@ -592,4 +596,4 @@ export async function POST(
592
596
  - [Building Durable AI Agents](/docs/ai) - Foundation guide for durable agents
593
597
  - [Message Queueing](/docs/ai/message-queueing) - Queueing messages during tool execution
594
598
  - [`defineHook()` API Reference](/docs/api-reference/workflow/define-hook) - Hook configuration options
595
- - [`DurableAgent` API Reference](/docs/api-reference/workflow-ai/durable-agent) - Full API documentation
599
+ - [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) - AI SDK API for durable, resumable agents
@@ -14,11 +14,11 @@ related:
14
14
 
15
15
  This page covers the details for some common patterns when defining tools for AI agents using Workflow SDK.
16
16
 
17
- Using DurableAgent, we model most tools as steps. These can be anything from a simple function call to a entire multi-day long workflow.
17
+ Using WorkflowAgent, we model most tools as steps. These can be anything from a simple function call to a entire multi-day long workflow.
18
18
 
19
19
  ## Accessing message context in tools
20
20
 
21
- Just like in regular AI SDK tool definitions, tool in DurableAgent are called with a first argument of the tool's input parameters, and a second argument of the tool call context.
21
+ Just like in regular AI SDK tool definitions, tool in WorkflowAgent are called with a first argument of the tool's input parameters, and a second argument of the tool call context.
22
22
 
23
23
  When you tool needs access to the full message history, you can access it via the `messages` property of the tool call context:
24
24
 
@@ -13,7 +13,7 @@ related:
13
13
 
14
14
  When using [multi-turn workflows](/docs/ai/chat-session-modeling#multi-turn-workflows), messages typically arrive between agent turns. The workflow waits at a hook, receives a message, then starts a new turn. But sometimes you need to inject messages *during* an agent's turn, before tool calls complete or while the model is reasoning.
15
15
 
16
- `DurableAgent`'s `prepareStep` callback enables this by running before each step in the agent loop, giving you a chance to inject queued messages into the conversation. `prepareStep` also allows you to modify the model choice and existing messages mid-turn, see AI SDK's [prepareStep callback](https://ai-sdk.dev/docs/agents/loop-control#prepare-step) for more details.
16
+ `WorkflowAgent`'s `prepareStep` callback enables this by running before each step in the agent loop, giving you a chance to inject queued messages into the conversation. `prepareStep` also allows you to modify the model choice and existing messages mid-turn, see AI SDK's [prepareStep callback](https://ai-sdk.dev/docs/agents/loop-control#prepare-step) for more details.
17
17
 
18
18
  ## When to Use This
19
19
 
@@ -52,20 +52,20 @@ interface PrepareStepResult {
52
52
  Once you have a [multi-turn workflow](/docs/ai/chat-session-modeling#multi-turn-workflows), you can combine a message queue with `prepareStep` to inject messages that arrive during processing:
53
53
 
54
54
  ```typescript title="workflows/chat/index.ts" lineNumbers
55
- import { DurableAgent } from "@workflow/ai/agent";
55
+ import { WorkflowAgent, type ModelCallStreamPart } from "@ai-sdk/workflow";
56
56
  import { getWritable, getWorkflowMetadata } from "workflow";
57
57
  import { chatMessageHook } from "./hooks/chat-message";
58
58
  import { flightBookingTools, FLIGHT_ASSISTANT_PROMPT } from "./steps/tools";
59
- import type { UIMessageChunk, ModelMessage } from "ai";
59
+ import type { ModelMessage } from "ai";
60
60
 
61
61
  export async function chat(initialMessages: ModelMessage[]) {
62
62
  "use workflow";
63
63
 
64
64
  const { workflowRunId: runId } = getWorkflowMetadata();
65
- const writable = getWritable<UIMessageChunk>();
65
+ const writable = getWritable<ModelCallStreamPart>();
66
66
  const messageQueue: Array<{ role: "user"; content: string }> = []; // [!code highlight]
67
67
 
68
- const agent = new DurableAgent({
68
+ const agent = new WorkflowAgent({
69
69
  model: "bedrock/claude-haiku-4-5-20251001-v1",
70
70
  instructions: FLIGHT_ASSISTANT_PROMPT,
71
71
  tools: flightBookingTools,
@@ -111,20 +111,20 @@ The `prepareStep` callback receives messages in `ModelMessage[]` format (with co
111
111
  You can also combine message queueing with the standard multi-turn pattern:
112
112
 
113
113
  ```typescript title="workflows/chat/index.ts" lineNumbers
114
- import { DurableAgent } from "@workflow/ai/agent";
114
+ import { WorkflowAgent, type ModelCallStreamPart } from "@ai-sdk/workflow";
115
115
  import { getWritable, getWorkflowMetadata } from "workflow";
116
116
  import { chatMessageHook } from "./hooks/chat-message";
117
- import type { UIMessageChunk, ModelMessage } from "ai";
117
+ import type { ModelMessage } from "ai";
118
118
 
119
119
  export async function chat(initialMessages: ModelMessage[]) {
120
120
  "use workflow";
121
121
 
122
122
  const { workflowRunId: runId } = getWorkflowMetadata();
123
- const writable = getWritable<UIMessageChunk>();
123
+ const writable = getWritable<ModelCallStreamPart>();
124
124
  const messages: ModelMessage[] = [...initialMessages];
125
125
  const messageQueue: Array<{ role: "user"; content: string }> = [];
126
126
 
127
- const agent = new DurableAgent({ /* ... */ });
127
+ const agent = new WorkflowAgent({ /* ... */ });
128
128
  const hook = chatMessageHook.create({ token: runId });
129
129
 
130
130
  while (true) {
@@ -173,5 +173,5 @@ export async function chat(initialMessages: ModelMessage[]) {
173
173
 
174
174
  - [Chat Session Modeling](/docs/ai/chat-session-modeling) - Single-turn vs multi-turn patterns
175
175
  - [Building Durable AI Agents](/docs/ai) - Complete guide to creating durable agents
176
- - [`DurableAgent` API Reference](/docs/api-reference/workflow-ai/durable-agent) - Full API documentation
176
+ - [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) - AI SDK API for durable, resumable agents
177
177
  - [`defineHook()` API Reference](/docs/api-reference/workflow/define-hook) - Hook configuration options
@@ -12,6 +12,10 @@ related:
12
12
  - /docs/api-reference/workflow-api/get-run
13
13
  ---
14
14
 
15
+ <Callout type="warn">
16
+ `WorkflowChatTransport` now ships in AI SDK as a 1:1 port — import it from `@ai-sdk/workflow` (the `@workflow/ai` export is deprecated). See [Resumable Streaming with `WorkflowChatTransport`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#resumable-streaming-with-workflowchattransport) for the full reference.
17
+ </Callout>
18
+
15
19
  When building chat interfaces, it's common to run into network interruptions, page refreshes, or serverless function timeouts, which can break the connection to an in-progress agent.
16
20
 
17
21
  Where a standard chat implementation would require the user to resend their message and wait for the entire response again, workflow runs are durable, and so are the streams attached to them. This means a stream can be resumed at any point, optionally only syncing the data that was missed since the last connection.
@@ -109,7 +113,7 @@ Replace the default transport in AI-SDK's `useChat` with [`WorkflowChatTransport
109
113
  "use client";
110
114
 
111
115
  import { useChat } from "@ai-sdk/react";
112
- import { WorkflowChatTransport } from "@workflow/ai"; // [!code highlight]
116
+ import { WorkflowChatTransport } from "@ai-sdk/workflow"; // [!code highlight]
113
117
  import { useMemo, useState } from "react";
114
118
 
115
119
  export default function ChatPage() {
@@ -194,6 +198,10 @@ This avoids replaying potentially thousands of chunks and lets the UI render fas
194
198
  When using a negative `initialStartIndex`, the reconnection endpoint **must** return the `x-workflow-stream-tail-index` header (as shown in [Step 2](#add-a-stream-reconnection-endpoint) above). The transport uses this header to compute absolute chunk positions so that retries after a disconnect resume from the correct position. If the header is missing, the transport falls back to `startIndex: 0` (replaying the entire stream) and logs a warning.
195
199
  </Callout>
196
200
 
201
+ ### Mid-part resumes
202
+
203
+ A workflow stream is a flat sequence of chunks, but the AI SDK's UI protocol groups chunks into logical parts (`text-*`, `reasoning-*`, `tool-input-*`) that must be opened with a `*-start` before any `*-delta` or `*-end`. A non-zero `startIndex` can land in the middle of an open part. See [`WorkflowChatTransport` → Mid-part resumes](/docs/api-reference/workflow-ai/workflow-chat-transport#mid-part-resumes) for how this is handled and an example of rewinding to a step boundary on the server.
204
+
197
205
  ## Related Documentation
198
206
 
199
207
  - [`WorkflowChatTransport` API Reference](/docs/api-reference/workflow-ai/workflow-chat-transport) - Full configuration options
@@ -10,7 +10,7 @@ related:
10
10
  ---
11
11
 
12
12
  <Callout type="warn">
13
- `DurableAgent` is deprecated. Use AI SDK's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) for new durable agents and migration guidance.
13
+ `DurableAgent` is deprecated. Use AI SDK's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) for new durable agents see the [migration guide](https://ai-sdk.dev/v7/docs/agents/workflow-agent#migrating-from-durableagent).
14
14
  </Callout>
15
15
 
16
16
  This reference is kept for existing applications that still import `DurableAgent` from `@workflow/ai/agent`. Do not use `DurableAgent` for new code.
@@ -13,9 +13,9 @@ Helpers for integrating AI SDK for building AI-powered workflows.
13
13
 
14
14
  <Cards>
15
15
  <Card title="DurableAgent" href="/docs/api-reference/workflow-ai/durable-agent">
16
- A class for building durable AI agents that maintain state across workflow steps and handle tool execution with automatic retries.
16
+ Deprecated use AI SDK's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent). Reference kept for existing `@workflow/ai/agent` imports.
17
17
  </Card>
18
18
  <Card title="WorkflowChatTransport" href="/docs/api-reference/workflow-ai/workflow-chat-transport">
19
- A drop-in transport for the AI SDK for automatic reconnection in interrupted streams.
19
+ Deprecated use AI SDK's [`WorkflowChatTransport`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#resumable-streaming-with-workflowchattransport) from `@ai-sdk/workflow`. Reference kept for existing `@workflow/ai` imports.
20
20
  </Card>
21
21
  </Cards>
@@ -9,6 +9,10 @@ related:
9
9
  - /docs/ai/resumable-streams
10
10
  ---
11
11
 
12
+ <Callout type="warn">
13
+ `WorkflowChatTransport` from `@workflow/ai` is deprecated. AI SDK ships a 1:1 port — use [`WorkflowChatTransport` from `@ai-sdk/workflow`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#resumable-streaming-with-workflowchattransport) instead. This reference is kept for existing applications that still import it from `@workflow/ai`.
14
+ </Callout>
15
+
12
16
  A chat transport implementation for the AI SDK that provides reliable message streaming with automatic reconnection to interrupted streams. This transport is a drop-in replacement for the default AI SDK transport, enabling seamless recovery from network issues, page refreshes, or Vercel Function timeouts.
13
17
 
14
18
  <Callout>
@@ -250,9 +254,48 @@ export default function ChatWithCustomConfig() {
250
254
  }
251
255
  ```
252
256
 
257
+ ## Mid-part resumes
258
+
259
+ A workflow stream is a flat sequence of chunks, but the AI SDK's UI protocol groups chunks into logical parts: a `text-start` opens a text part that subsequent `text-delta`s extend and a `text-end` closes, and the same shape applies to `reasoning-*` and `tool-input-*`. The AI SDK client enforces that grammar — a `reasoning-delta` whose `reasoning-start` was never seen throws and breaks the chat.
260
+
261
+ A non-zero `startIndex` (in particular a negative `initialStartIndex`) resolves to a chunk offset with no awareness of those part boundaries, so it can land in the middle of an open part. When that happens, `WorkflowChatTransport` will **drop chunks that reference a part it didn't see a start for** and log a one-time warning. The chat keeps working, but any partial part overlapping the resume cursor is discarded. Tool calls are an exception: `tool-input-available` / `tool-input-error` chunks are self-contained (they carry the full input), so a tool call is recovered as soon as one of those chunks appears in the resumed window — only its streamed input deltas are lost.
262
+
263
+ To preserve those partial parts, rewind to a step boundary on the server before returning the readable. `start-step` / `finish-step` chunks are the natural seams — no UI part is ever open across them. Sketch:
264
+
265
+ {/*@skip-typecheck: incomplete code sample*/}
266
+
267
+ ```typescript title="app/api/chat/[id]/stream/route.ts"
268
+ const run = getRun(id);
269
+ const tailIndex = await run.getReadable().getTailIndex();
270
+
271
+ let resolved = startIndex < 0
272
+ ? Math.max(0, tailIndex + 1 + startIndex)
273
+ : startIndex;
274
+
275
+ if (startIndex !== 0) {
276
+ // Walk back from `resolved` to the most recent start-step (or chunk 0),
277
+ // capping the lookback so a single huge step can't trigger an unbounded scan.
278
+ const LOOKBACK = 200;
279
+ const probe = run.getReadable({ startIndex: Math.max(0, resolved - LOOKBACK) });
280
+ let i = Math.max(0, resolved - LOOKBACK);
281
+ let lastBoundary = i;
282
+ for await (const chunk of probe as unknown as AsyncIterable<{ type: string }>) {
283
+ if (i >= resolved) break;
284
+ if (chunk.type === "start-step") lastBoundary = i;
285
+ i++;
286
+ }
287
+ resolved = lastBoundary;
288
+ }
289
+
290
+ return createUIMessageStreamResponse({
291
+ stream: run.getReadable({ startIndex: resolved }),
292
+ headers: { "x-workflow-stream-tail-index": String(tailIndex) },
293
+ });
294
+ ```
295
+
253
296
  ## See Also
254
297
 
255
- - [DurableAgent](/docs/api-reference/workflow-ai/durable-agent) - Building durable AI agents within workflows
298
+ - [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) - Building durable, resumable AI agents (replaces `DurableAgent`)
256
299
  - [AI SDK `useChat` Documentation](https://ai-sdk.dev/docs/reference/ai-sdk-ui/use-chat) - Using `useChat` with custom transports
257
300
  - [Workflows and Steps](/docs/foundations/workflows-and-steps) - Understanding workflow fundamentals
258
301
  - ["flight-booking-app" Example](https://github.com/vercel/workflow-examples/tree/main/flight-booking-app) - An example application which uses `WorkflowChatTransport`
@@ -63,6 +63,10 @@ The `DurableAgent` receives a function (`() => Promise<LanguageModel>`) instead
63
63
 
64
64
  ## How `@workflow/ai` Uses This
65
65
 
66
+ <Callout type="warn">
67
+ `@workflow/ai`'s pre-wrapped providers and `DurableAgent` are deprecated. AI SDK's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) resolves models from AI Gateway model strings (e.g. `"openai/gpt-4o"`), which usually removes the need for a model factory — see the [migration guide](https://ai-sdk.dev/v7/docs/agents/workflow-agent#migrating-from-durableagent). The serialization pattern on this page still applies to any non-serializable dependency you own (for example, cloud SDK clients).
68
+ </Callout>
69
+
66
70
  The `@workflow/ai` package ships pre-wrapped providers for all major AI SDK backends. Each one follows the same pattern:
67
71
 
68
72
  ```typescript lineNumbers
@@ -143,5 +147,5 @@ async function uploadFile(
143
147
 
144
148
  - [`"use step"`](/docs/foundations/workflows-and-steps#step-functions) — marks a function for extraction and serialization
145
149
  - [`"use workflow"`](/docs/foundations/workflows-and-steps#workflow-functions) — declares the orchestrator function
146
- - [`DurableAgent`](/docs/api-reference/workflow-ai/durable-agent) — accepts a model factory for durable AI agent streaming
150
+ - [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) — AI SDK's durable agent (resolves models via AI Gateway strings; replaces `DurableAgent`)
147
151
  - [Custom class serialization](/docs/foundations/serialization#custom-class-serialization) — the companion pattern for classes you own (`WORKFLOW_SERIALIZE` / `WORKFLOW_DESERIALIZE`)
@@ -7,6 +7,10 @@ summary: Cancel a running agent cooperatively with AbortController. A stop hook
7
7
 
8
8
  Cancel a running agent from the outside — for example, a "Stop" button in a chat UI, an admin cancellation endpoint, or a timeout fallback.
9
9
 
10
+ <Callout type="warn">
11
+ This recipe uses the deprecated `DurableAgent` API. For new agents, use AI SDK's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) and follow the [migration guide](https://ai-sdk.dev/v7/docs/agents/workflow-agent#migrating-from-durableagent). The cancellation patterns here (`run.cancel()`, stop-signal hook + `Promise.race`, `AbortController`) apply to either API.
12
+ </Callout>
13
+
10
14
  ## Pattern
11
15
 
12
16
  Create an `AbortController` in the workflow and race the agent (passing its signal) against a stop hook. When the hook fires, `controller.abort()` is called — the signal propagates into the agent step and cancels the underlying model stream. Before returning, a `data-stopped` part is written to the stream so any streaming clients can render a clean end state.
@@ -153,4 +157,4 @@ export function StopButton({ runId }: { runId: string }) {
153
157
  * [`defineHook()`](/docs/api-reference/workflow/define-hook) — type-safe hook for the stop signal
154
158
  * [`getWorkflowMetadata()`](/docs/api-reference/workflow/get-workflow-metadata) — access the run ID for deterministic hook tokens
155
159
  * [`getWritable()`](/docs/api-reference/workflow/get-writable) — stream output and the stop notification to the client
156
- * [`DurableAgent`](/docs/api-reference/workflow-ai/durable-agent) — the agent that respects the abort signal via its `signal` option
160
+ * [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) — AI SDK's durable agent that respects the abort signal (replaces `DurableAgent`)
@@ -7,12 +7,12 @@ summary: Build durable, resumable AI agents with AI SDK v7's WorkflowAgent.
7
7
 
8
8
  ## WorkflowAgent from AI SDK v7
9
9
 
10
- Use AI SDK v7's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) for new durable agent work. It replaces `DurableAgent` in v5 and keeps the current agent pattern in the AI SDK package.
10
+ Use AI SDK v7's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) for new durable agent work. It replaces `DurableAgent` and keeps the current agent pattern in the AI SDK package.
11
11
 
12
12
  - Import `WorkflowAgent` from `@ai-sdk/workflow` and run it inside a `"use workflow"` function.
13
13
  - Stream `ModelCallStreamPart` chunks with `getWritable()`, then convert the run stream to UI message chunks with `createModelCallToUIChunkTransform()` in your route.
14
14
  - Mark tool `execute` functions with `"use step"` when they should run as durable workflow steps with retry and observability behavior.
15
15
 
16
16
  <Callout type="warn">
17
- `DurableAgent` is deprecated in v5 and remains documented for existing code only. Existing `DurableAgent` users can refer to the [`DurableAgent` API reference](/docs/api-reference/workflow-ai/durable-agent) while migrating.
17
+ `DurableAgent` is deprecated and remains documented for existing code only. See the [migration guide](https://ai-sdk.dev/v7/docs/agents/workflow-agent#migrating-from-durableagent), or the [`DurableAgent` API reference](/docs/api-reference/workflow-ai/durable-agent) while migrating.
18
18
  </Callout>
@@ -5,6 +5,10 @@ type: guide
5
5
  summary: Use defineHook with the tool call ID to suspend an agent for human approval, with an optional timeout.
6
6
  ---
7
7
 
8
+ <Callout type="warn">
9
+ This recipe uses the deprecated `DurableAgent` API. For new agents, use AI SDK's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) and follow the [migration guide](https://ai-sdk.dev/v7/docs/agents/workflow-agent#migrating-from-durableagent). The human-in-the-loop pattern here (hooks, `Promise.race`, approval gating) applies to either API.
10
+ </Callout>
11
+
8
12
  Use this pattern when an AI agent needs human confirmation before performing a consequential action like booking, purchasing, or publishing. The workflow suspends without consuming resources until the human responds.
9
13
 
10
14
  ## When to use this
@@ -252,4 +256,4 @@ const approvalResult = messages
252
256
  - [`defineHook()`](/docs/api-reference/workflow/define-hook) — type-safe hook with schema validation
253
257
  - [`sleep()`](/docs/api-reference/workflow/sleep) — durable timeout for approval expiry
254
258
  - [`getWritable()`](/docs/api-reference/workflow/get-writable) — stream custom data parts from steps
255
- - [`DurableAgent`](/docs/api-reference/workflow-ai/durable-agent) — durable agent with tool definitions
259
+ - [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) — AI SDK's durable agent (replaces `DurableAgent`)
@@ -2,7 +2,7 @@
2
2
  title: AI SDK
3
3
  description: Use AI SDK's streamText directly inside durable workflows when you need the raw AI SDK API or a per-turn durability boundary.
4
4
  type: guide
5
- summary: Use streamText() inside a workflow when the durability boundary is an entire user turn, or when you need AI SDK APIs not exposed by DurableAgent. Individual tool calls and LLM calls inside a turn are not separately durable.
5
+ summary: Use streamText() inside a workflow when the durability boundary is an entire user turn, or when you need AI SDK APIs not exposed by WorkflowAgent. Individual tool calls and LLM calls inside a turn are not separately durable.
6
6
  related:
7
7
  - /docs/ai
8
8
  - /docs/ai/chat-session-modeling
@@ -16,18 +16,18 @@ related:
16
16
  For the full AI SDK reference (providers, `streamText`, `generateObject`, `useChat`, tool calling, etc.) see the [AI SDK docs](https://ai-sdk.dev/docs). This page covers the Workflow-specific integration points.
17
17
 
18
18
  <Callout type="info">
19
- For most agent use cases, prefer [`DurableAgent`](/cookbook/agent-patterns/durable-agent), which implements the same agent loop as [`streamText`](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text), manages tool calling automatically, and runs tools at workflow scope — each tool can be marked `"use step"` for per-call durability and retries, or stay at workflow level to use primitives like `sleep()` and hooks. Use this page's raw `streamText()` pattern when you want the exact AI SDK API (for example `toUIMessageStream()`, `onChunk`, or `generateText`), or when the durability boundary should be an entire user turn in one step — accepting that tool calls inside that turn are not individually durable.
19
+ For most agent use cases, prefer AI SDK's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent), which implements the same agent loop as [`streamText`](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text), manages tool calling automatically, and runs tools at workflow scope — each tool can be marked `"use step"` for per-call durability and retries, or stay at workflow level to use primitives like `sleep()` and hooks. Use this page's raw `streamText()` pattern when you want the exact AI SDK API (for example `toUIMessageStream()`, `onChunk`, or `generateText`), or when the durability boundary should be an entire user turn in one step — accepting that tool calls inside that turn are not individually durable.
20
20
  </Callout>
21
21
 
22
22
  ## When to use streamText directly
23
23
 
24
- Use [`streamText()`](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text) instead of `DurableAgent` when you need:
24
+ Use [`streamText()`](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text) instead of `WorkflowAgent` when you need:
25
25
 
26
- * **The raw AI SDK API** — `streamText().toUIMessageStream()`, `onChunk`, `smoothStream`, or other options that map directly to the [`streamText`](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text) return value rather than `DurableAgent.stream()`
26
+ * **The raw AI SDK API** — `streamText().toUIMessageStream()`, `onChunk`, `smoothStream`, or other options that map directly to the [`streamText`](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text) return value rather than `WorkflowAgent.stream()`
27
27
  * **Per-turn durability** — wrap the entire agent response (model + tools) in a single `"use step"` function so one user turn is the atomic retry unit; useful when you want all tool calls inside a turn to re-execute together
28
- * **Custom multi-turn orchestration** — manual hook loops, per-turn stream slicing (`sliceUntilFinish`), or other workflow patterns shown below that don't map cleanly to `DurableAgent`
28
+ * **Custom multi-turn orchestration** — manual hook loops, per-turn stream slicing (`sliceUntilFinish`), or other workflow patterns shown below that don't map cleanly to `WorkflowAgent`
29
29
 
30
- `DurableAgent` already supports `stopWhen`, `prepareStep`, `onStepFinish`, structured output (`experimental_output`), per-step model switching, and [provider options](https://ai-sdk.dev/docs/ai-sdk-core/provider-options). See the [DurableAgent reference](/docs/api-reference/workflow-ai/durable-agent).
30
+ `WorkflowAgent` already supports `stopWhen`, `prepareStep`, lifecycle callbacks, structured output (`output`), per-step model switching, and [provider options](https://ai-sdk.dev/docs/ai-sdk-core/provider-options). See the [`WorkflowAgent` docs](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent).
31
31
 
32
32
  ## Multi-turn pattern
33
33
 
@@ -250,7 +250,7 @@ Store the `runId` in a ref and pass it in the body of every follow-up. `Workflow
250
250
  "use client";
251
251
 
252
252
  import { useChat } from "@ai-sdk/react";
253
- import { WorkflowChatTransport } from "@workflow/ai";
253
+ import { WorkflowChatTransport } from "@ai-sdk/workflow";
254
254
  import { useMemo, useRef, useState } from "react";
255
255
 
256
256
  export function SupportChat() {
@@ -324,7 +324,7 @@ The consequences:
324
324
  **Mitigations:**
325
325
 
326
326
  - Make side-effectful tool implementations idempotent — dedupe server-side on a stable key (e.g. `orderId`, an `Idempotency-Key` header, etc.).
327
- - Or use [`DurableAgent`](/docs/api-reference/workflow-ai/durable-agent), which runs tools at workflow scope — each tool can be marked `"use step"` to become its own durable, retryable step, or stay at workflow level to use primitives like `sleep()` and hooks.
327
+ - Or use AI SDK's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent), which runs tools at workflow scope — each tool can be marked `"use step"` to become its own durable, retryable step, or stay at workflow level to use primitives like `sleep()` and hooks.
328
328
 
329
329
  ### Snapshot `tailIndex` *before* resuming the hook
330
330
 
@@ -358,19 +358,19 @@ Clients can send a `runId` from a long-gone workflow (localStorage, back button,
358
358
 
359
359
  This example stores the `runId` after the first response. For strict one-session-per-thread behavior, use a deterministic hook token derived from the thread ID or conversation ID and route retries through the active hook. See [Idempotency](/docs/foundations/idempotency).
360
360
 
361
- ## streamText vs DurableAgent
361
+ ## streamText vs WorkflowAgent
362
362
 
363
- | | `streamText()` (this pattern) | `DurableAgent` |
363
+ | | `streamText()` (this pattern) | `WorkflowAgent` |
364
364
  |---|---|---|
365
365
  | **Tool loop** | AI SDK handles via `stopWhen` | Handles internally (AI SDK–compatible options) |
366
366
  | **LLM call durability** | Re-executes with the parent turn | Each LLM call is a durable step |
367
367
  | **Tool call durability** | Not individually durable — re-executes with the parent turn | Per tool — mark `"use step"` for a durable, retryable step, or keep at workflow level for `sleep()` / hooks |
368
368
  | **Stop conditions** | `stopWhen`, `prepareStep` | `stopWhen`, `prepareStep` |
369
- | **Structured output** | `Output.object()`, `Output.array()` | `experimental_output` (`Output.object()`, `Output.text()`) |
369
+ | **Structured output** | `Output.object()`, `Output.array()` | `output` (`Output.object()`, `Output.text()`) |
370
370
  | **Step callbacks** | `onStepFinish`, `onChunk`, etc. | `onStepFinish`, `onFinish`, `onError`, `onAbort` (`onChunk` not available) |
371
371
  | **Setup** | Manual stream piping and turn slicing | Automatic |
372
372
 
373
- Use `DurableAgent` for most agent use cases. Use `streamText` when you need the raw AI SDK surface or a per-turn durability boundary.
373
+ Use `WorkflowAgent` for most agent use cases. Use `streamText` when you need the raw AI SDK surface or a per-turn durability boundary.
374
374
 
375
375
  ## Key APIs
376
376
 
@@ -31,10 +31,42 @@ WORKFLOW_POSTGRES_URL="postgres://user:password@host:5432/database"
31
31
 
32
32
  Run the migration script to create the necessary tables in your database. Ensure `WORKFLOW_POSTGRES_URL` is set when running this command:
33
33
 
34
+ <Tabs items={["npm", "pnpm", "Yarn", "Bun"]}>
35
+
36
+ <Tab value="npm">
37
+
38
+ ```bash
39
+ npx --package=@workflow/world-postgres bootstrap
40
+ ```
41
+
42
+ </Tab>
43
+
44
+ <Tab value="pnpm">
45
+
46
+ ```bash
47
+ pnpm dlx --package @workflow/world-postgres bootstrap
48
+ ```
49
+
50
+ </Tab>
51
+
52
+ <Tab value="Yarn">
53
+
54
+ ```bash
55
+ yarn dlx --package @workflow/world-postgres bootstrap
56
+ ```
57
+
58
+ </Tab>
59
+
60
+ <Tab value="Bun">
61
+
34
62
  ```bash
35
- npx workflow-postgres-setup
63
+ bunx --package @workflow/world-postgres bootstrap
36
64
  ```
37
65
 
66
+ </Tab>
67
+
68
+ </Tabs>
69
+
38
70
  <Callout type="info">
39
71
  The migration is idempotent and can safely be run as a post-deployment lifecycle script.
40
72
  </Callout>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workflow",
3
- "version": "5.0.0-beta.24",
3
+ "version": "5.0.0-beta.25",
4
4
  "description": "Workflow SDK - Build durable, resilient, and observable workflows",
5
5
  "main": "dist/typescript-plugin.cjs",
6
6
  "type": "module",
@@ -57,18 +57,18 @@
57
57
  },
58
58
  "dependencies": {
59
59
  "ms": "2.1.3",
60
- "@workflow/cli": "5.0.0-beta.24",
61
- "@workflow/core": "5.0.0-beta.24",
60
+ "@workflow/astro": "5.0.0-beta.25",
61
+ "@workflow/cli": "5.0.0-beta.25",
62
+ "@workflow/core": "5.0.0-beta.25",
62
63
  "@workflow/errors": "5.0.0-beta.8",
63
- "@workflow/astro": "5.0.0-beta.24",
64
64
  "@workflow/typescript-plugin": "5.0.0-beta.4",
65
- "@workflow/nitro": "5.0.0-beta.24",
66
- "@workflow/nuxt": "5.0.0-beta.24",
67
65
  "@workflow/utils": "5.0.0-beta.4",
68
- "@workflow/sveltekit": "5.0.0-beta.24",
69
- "@workflow/next": "5.0.0-beta.24",
70
- "@workflow/nest": "5.0.0-beta.24",
71
- "@workflow/rollup": "5.0.0-beta.24"
66
+ "@workflow/next": "5.0.0-beta.25",
67
+ "@workflow/nest": "5.0.0-beta.25",
68
+ "@workflow/nitro": "5.0.0-beta.25",
69
+ "@workflow/nuxt": "5.0.0-beta.25",
70
+ "@workflow/sveltekit": "5.0.0-beta.25",
71
+ "@workflow/rollup": "5.0.0-beta.25"
72
72
  },
73
73
  "devDependencies": {
74
74
  "@types/ms": "2.1.0",