ai 7.0.38 → 7.0.40

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.
@@ -85,7 +85,7 @@ import {
85
85
  } from "@ai-sdk/provider-utils";
86
86
 
87
87
  // src/version.ts
88
- var VERSION = true ? "7.0.38" : "0.0.0-test";
88
+ var VERSION = true ? "7.0.40" : "0.0.0-test";
89
89
 
90
90
  // src/util/download/download.ts
91
91
  var download = async ({
@@ -447,8 +447,9 @@ This differs from `ToolLoopAgent`, which runs in memory and can carry richer Jav
447
447
  ### experimental_sandbox
448
448
 
449
449
  Pass a sandbox session when tools need an execution environment. The sandbox is
450
- available to tool `execute` functions as `experimental_sandbox` and to
451
- `prepareStep`, where you can override it for the current step:
450
+ available to tool descriptions and `execute` functions as
451
+ `experimental_sandbox`, and to `prepareStep`, where you can override it for the
452
+ current step:
452
453
 
453
454
  ```ts
454
455
  const agent = new WorkflowAgent({
@@ -24,12 +24,11 @@ specification (`Experimental_SpeechTranslationModelV4`).
24
24
  </Note>
25
25
 
26
26
  ```ts
27
+ import { openai } from '@ai-sdk/openai';
27
28
  import { experimental_streamTranslate as streamTranslate } from 'ai';
28
29
 
29
30
  const result = streamTranslate({
30
- // any provider model instance that implements the experimental
31
- // speech translation model specification (Experimental_SpeechTranslationModelV4):
32
- model: translationModel,
31
+ model: openai.translation('gpt-realtime-translate'),
33
32
  audio: audioStream, // ReadableStream<Uint8Array | string>
34
33
  inputAudioFormat: { type: 'audio/pcm', rate: 24000 },
35
34
  targetLanguage: 'es',
@@ -108,11 +107,12 @@ part for output text by design for now.
108
107
  Use `outputAudioFormat` to request a specific audio format for translated
109
108
  audio chunks. When absent, the provider default output format is used.
110
109
 
111
- ```ts highlight="6"
110
+ ```ts highlight="8"
111
+ import { openai } from '@ai-sdk/openai';
112
112
  import { experimental_streamTranslate as streamTranslate } from 'ai';
113
113
 
114
114
  const result = streamTranslate({
115
- model: translationModel,
115
+ model: openai.translation('gpt-realtime-translate'),
116
116
  audio: audioStream,
117
117
  inputAudioFormat: { type: 'audio/pcm', rate: 24000 },
118
118
  outputAudioFormat: { type: 'audio/pcm', rate: 24000 },
@@ -125,16 +125,17 @@ const result = streamTranslate({
125
125
  Translation models often have provider or model-specific settings which you can
126
126
  set using the `providerOptions` parameter.
127
127
 
128
- ```ts highlight="8-12"
128
+ ```ts highlight="9-13"
129
+ import { openai } from '@ai-sdk/openai';
129
130
  import { experimental_streamTranslate as streamTranslate } from 'ai';
130
131
 
131
132
  const result = streamTranslate({
132
- model: translationModel,
133
+ model: openai.translation('gpt-realtime-translate'),
133
134
  audio: audioStream,
134
135
  inputAudioFormat: { type: 'audio/pcm', rate: 24000 },
135
136
  targetLanguage: 'es',
136
137
  providerOptions: {
137
- 'provider-name': {
138
+ openai: {
138
139
  // provider-specific options
139
140
  },
140
141
  },
@@ -145,11 +146,12 @@ const result = streamTranslate({
145
146
 
146
147
  Pass an `abortSignal` to cancel the translation:
147
148
 
148
- ```ts highlight="8"
149
+ ```ts highlight="9"
150
+ import { openai } from '@ai-sdk/openai';
149
151
  import { experimental_streamTranslate as streamTranslate } from 'ai';
150
152
 
151
153
  const result = streamTranslate({
152
- model: translationModel,
154
+ model: openai.translation('gpt-realtime-translate'),
153
155
  audio: audioStream,
154
156
  inputAudioFormat: { type: 'audio/pcm', rate: 24000 },
155
157
  targetLanguage: 'es',
@@ -172,6 +174,7 @@ The error preserves the following information to help you log the issue:
172
174
  handling.
173
175
 
174
176
  ```ts
177
+ import { openai } from '@ai-sdk/openai';
175
178
  import {
176
179
  experimental_streamTranslate as streamTranslate,
177
180
  NoTranslationGeneratedError,
@@ -179,7 +182,7 @@ import {
179
182
 
180
183
  try {
181
184
  const result = streamTranslate({
182
- model: translationModel,
185
+ model: openai.translation('gpt-realtime-translate'),
183
186
  audio: audioStream,
184
187
  inputAudioFormat: { type: 'audio/pcm', rate: 24000 },
185
188
  targetLanguage: 'es',
@@ -194,3 +197,13 @@ try {
194
197
  }
195
198
  }
196
199
  ```
200
+
201
+ ## Translation Models
202
+
203
+ | Provider | Model |
204
+ | --------------------------------------------------------------- | ----------------------------------- |
205
+ | [OpenAI](/providers/ai-sdk-providers/openai#translation-models) | `gpt-realtime-translate` |
206
+ | [Google](/providers/ai-sdk-providers/google#translation-models) | `gemini-3.5-live-translate-preview` |
207
+
208
+ Above are a small subset of the translation models supported by the AI SDK
209
+ providers. For more, see the respective provider documentation.
@@ -8,29 +8,35 @@ description: Run HarnessAgent turns as durable Workflow DevKit workflows.
8
8
  `@ai-sdk/workflow-harness` provides helpers for running `HarnessAgent` turns
9
9
  inside a [workflow](https://vercel.com/docs/workflow).
10
10
 
11
- The package provides a serializable state machine and a slice runner that you
12
- call from your own `'use workflow'` and `'use step'` functions.
11
+ The package provides a serializable state machine and runners for time-sliced
12
+ and semantic agent step turns. You call the appropriate runner from your own
13
+ `'use workflow'` and `'use step'` functions.
13
14
 
14
- The core harness and workflow files are framework-independent. The HTTP handler
15
- and Next.js configuration shown below are examples of how to expose the workflow
16
- from one app framework; adapt those parts to your runtime and Workflow SDK
17
- integration.
15
+ The core harness and workflow files are framework-independent. The HTTP handlers
16
+ shown below use Next.js as one example; adapt them to your runtime and Workflow
17
+ SDK integration. If you use Next.js, ensure you have
18
+ [configured your project for Workflow](https://workflow-sdk.dev/docs/getting-started/next)
19
+ before following the examples.
18
20
 
19
21
  ## Installation
20
22
 
21
23
  <InstallPackages packages="@ai-sdk/workflow-harness workflow" />
22
24
 
23
- Install the core harness package, a harness adapter, and a sandbox provider as
24
- shown in [HarnessAgent](/docs/ai-sdk-harnesses/harness-agent).
25
+ In addition to the workflow specific packages, install the core harness package,
26
+ a harness adapter, and a sandbox provider as shown in
27
+ [HarnessAgent](/docs/ai-sdk-harnesses/harness-agent).
25
28
 
26
- ## Using a Durable Harness Agent
29
+ ## Configuring the Harness Agent
27
30
 
28
- The agent can be configured in the usual way.
31
+ The agent can be configured in the usual way, for the most part. When using
32
+ semantic agent steps, set `stopWhen` to `isStepCount(1)` so one call to
33
+ `stream()` completes one agent step. Omit it when using time slices.
29
34
 
30
- ```ts filename='harness-workflow/agent.ts'
35
+ ```ts filename='harness-workflow/agent.ts' highlight="13-17"
31
36
  import { HarnessAgent } from '@ai-sdk/harness/agent';
32
37
  import { claudeCode } from '@ai-sdk/harness-claude-code';
33
38
  import { createVercelSandbox } from '@ai-sdk/sandbox-vercel';
39
+ import { isStepCount } from 'ai';
34
40
 
35
41
  export const agent = new HarnessAgent({
36
42
  harness: claudeCode,
@@ -39,92 +45,210 @@ export const agent = new HarnessAgent({
39
45
  ports: [4000],
40
46
  }),
41
47
  instructions: 'You are a helpful coding assistant.',
48
+ /*
49
+ * Only needed for semantic agent-step workflows.
50
+ * Omit this for time-sliced workflows.
51
+ */
52
+ stopWhen: isStepCount(1),
42
53
  });
43
54
  ```
44
55
 
45
- With the agent definition file in place, start with the two workflow-specific
46
- pieces: a slice step that runs one time-boxed part of the harness turn, and a
47
- workflow that calls that step until the turn finishes.
56
+ ## Using Semantic Agent Steps
48
57
 
49
- ```ts filename='harness-workflow/run-slice-step.ts'
58
+ Semantic agent steps persist the harness turn after each agent step. Configure
59
+ the shared agent with the highlighted `stopWhen` option shown above, then call
60
+ `runHarnessAgentStep()` from a Workflow step.
61
+
62
+ ### Defining the Agent Step
63
+
64
+ Keep the Workflow step in its own module and import the agent dynamically inside
65
+ the step body. This keeps the agent, sandbox provider, and other Node.js
66
+ dependencies out of the workflow bundle.
67
+
68
+ ```ts filename='harness-workflow/agent-step.ts'
50
69
  import {
51
- runHarnessAgentSlice,
70
+ runHarnessAgentStep,
52
71
  type HarnessWorkflowState,
53
72
  } from '@ai-sdk/workflow-harness';
54
73
 
55
- export async function runSlice(
74
+ export async function agentStep(
56
75
  state: HarnessWorkflowState,
57
76
  ): Promise<HarnessWorkflowState> {
58
77
  'use step';
59
78
 
60
79
  const { agent } = await import('./agent');
61
80
 
62
- return runHarnessAgentSlice({
81
+ return runHarnessAgentStep({
63
82
  agent,
64
83
  state,
65
84
  });
66
85
  }
67
86
  ```
68
87
 
88
+ ### Defining the Semantic Agent Step Workflow
89
+
90
+ Create the workflow state and keep scheduling `agentStep()` while the agent has
91
+ more work.
92
+
69
93
  ```ts filename='harness-workflow/workflow.ts'
70
- import { runSlice } from './run-slice-step';
94
+ import { agentStep } from './agent-step';
71
95
  import {
72
96
  createHarnessWorkflowState,
73
97
  finalizeHarnessWorkflow,
74
98
  type HarnessWorkflowInput,
75
99
  } from '@ai-sdk/workflow-harness';
76
100
 
77
- export async function codingWorkflow(
78
- input: Pick<HarnessWorkflowInput, 'prompt' | 'sessionId'>,
79
- ) {
101
+ export async function agentWorkflow(input: {
102
+ messages: NonNullable<HarnessWorkflowInput['messages']>;
103
+ sessionId: string;
104
+ }) {
80
105
  'use workflow';
81
106
 
82
107
  let state = createHarnessWorkflowState(input);
83
108
 
84
- while (state.status === 'running' || state.status === 'timed_out') {
85
- state = await runSlice(state);
86
- }
109
+ do {
110
+ state = await agentStep(state);
111
+ } while (state.status === 'ready_for_next_step');
87
112
 
88
113
  return finalizeHarnessWorkflow(state);
89
114
  }
90
115
  ```
91
116
 
92
- ### Starting the Workflow
117
+ <Note>
118
+ This example covers the workflow execution foundation only. For multi-turn
119
+ conversations, you must persist the harness session's `resumeFrom` state
120
+ between workflow runs. See [Resume Persistence](#resume-persistence).
121
+ </Note>
122
+
123
+ Each `ready_for_next_step` result carries `continueFrom`, which lets the next
124
+ Workflow step continue the same unfinished turn. When the turn finishes,
125
+ `finalizeHarnessWorkflow()` returns its result or throws if the workflow failed.
93
126
 
94
- Start the workflow from server-side code. You can return `run.readable` from an
95
- HTTP endpoint, consume it directly, or expose it through your framework's
96
- streaming response primitive.
127
+ ### Starting the Semantic Agent Step Workflow
97
128
 
98
- ```ts filename='server/start-coding-workflow.ts'
99
- import { codingWorkflow } from '../harness-workflow/workflow';
129
+ Start the workflow from server-side code. This Next.js route converts the AI SDK
130
+ UI messages, starts `agentWorkflow()`, and returns the workflow's AI SDK UI
131
+ message stream. Passing the converted messages lets `HarnessAgent` distinguish a
132
+ new user turn from tool approval and tool result continuations.
133
+
134
+ ```ts filename='app/api/harness-workflow/route.ts'
135
+ import { agentWorkflow } from '../../../harness-workflow/workflow';
136
+ import {
137
+ convertToModelMessages,
138
+ createUIMessageStreamResponse,
139
+ type UIMessage,
140
+ type UIMessageChunk,
141
+ } from 'ai';
100
142
  import { start } from 'workflow/api';
101
143
 
102
- export async function startCodingWorkflow({
103
- prompt,
104
- sessionId,
105
- }: {
106
- prompt: string;
144
+ export async function POST(request: Request) {
145
+ const body: {
146
+ id?: string;
147
+ messages: UIMessage[];
148
+ } = await request.json();
149
+
150
+ if (!body.id) {
151
+ return new Response('Missing chat ID', { status: 400 });
152
+ }
153
+
154
+ const messages = await convertToModelMessages(body.messages);
155
+ const run = await start(agentWorkflow, [
156
+ {
157
+ messages,
158
+ sessionId: body.id,
159
+ },
160
+ ]);
161
+
162
+ return createUIMessageStreamResponse({
163
+ stream: run.readable as ReadableStream<UIMessageChunk>,
164
+ });
165
+ }
166
+ ```
167
+
168
+ The `sessionId` gives the sandbox a stable identity across workflow runs. Keep
169
+ `agent.ts`, `agent-step.ts`, `workflow.ts`, and the route in separate modules so
170
+ the workflow bundle does not include Node-heavy agent, sandbox, or framework
171
+ dependencies.
172
+
173
+ ## Using Time Slices
174
+
175
+ Time slices persist a long-running harness turn at wall-clock boundaries. Omit
176
+ the highlighted `stopWhen` option from the shared agent, then call
177
+ `runHarnessAgentTimeSlice()` from a Workflow step. It uses a 750-second budget
178
+ by default; pass `timeSliceSeconds` to choose a different budget.
179
+
180
+ ### Defining the Time Slice Step
181
+
182
+ As with semantic agent steps, keep the Workflow step in its own module and
183
+ import the agent dynamically inside the step body.
184
+
185
+ ```ts filename='harness-workflow/time-slice-step.ts'
186
+ import {
187
+ runHarnessAgentTimeSlice,
188
+ type HarnessWorkflowState,
189
+ } from '@ai-sdk/workflow-harness';
190
+
191
+ export async function timeSliceStep(
192
+ state: HarnessWorkflowState,
193
+ ): Promise<HarnessWorkflowState> {
194
+ 'use step';
195
+
196
+ const { agent } = await import('./agent');
197
+
198
+ return runHarnessAgentTimeSlice({
199
+ agent,
200
+ state,
201
+ });
202
+ }
203
+ ```
204
+
205
+ ### Defining the Time-Sliced Workflow
206
+
207
+ Create the workflow state and keep scheduling `timeSliceStep()` while the agent
208
+ has more work.
209
+
210
+ ```ts filename='harness-workflow/workflow.ts'
211
+ import { timeSliceStep } from './time-slice-step';
212
+ import {
213
+ createHarnessWorkflowState,
214
+ finalizeHarnessWorkflow,
215
+ type HarnessWorkflowInput,
216
+ } from '@ai-sdk/workflow-harness';
217
+
218
+ export async function timeSliceWorkflow(input: {
219
+ messages: NonNullable<HarnessWorkflowInput['messages']>;
107
220
  sessionId: string;
108
221
  }) {
109
- const run = await start(codingWorkflow, [{ prompt, sessionId }]);
222
+ 'use workflow';
223
+
224
+ let state = createHarnessWorkflowState(input);
225
+
226
+ do {
227
+ state = await timeSliceStep(state);
228
+ } while (state.status === 'ready_for_next_step');
110
229
 
111
- return run.readable;
230
+ return finalizeHarnessWorkflow(state);
112
231
  }
113
232
  ```
114
233
 
115
- This is the core workflow/harness integration. Add resume persistence when you
116
- need a multi-turn chat to reattach to the same native harness session across
117
- workflow runs.
234
+ <Note>
235
+ This example covers the workflow execution foundation only. For multi-turn
236
+ conversations, you must persist the harness session's `resumeFrom` state
237
+ between workflow runs. See [Resume Persistence](#resume-persistence).
238
+ </Note>
239
+
240
+ Each `ready_for_next_step` result carries `continueFrom`, which lets the next
241
+ Workflow step continue the same unfinished turn. When the turn finishes,
242
+ `finalizeHarnessWorkflow()` returns its result or throws if the workflow failed.
118
243
 
119
- ### HTTP Route Example
244
+ ### Starting the Time-Sliced Workflow
120
245
 
121
- This example uses a Next.js `Request`/`Response` handler and AI SDK UI message
122
- streams. For other frameworks, the workflow related code is similar: derive the
123
- newest user message, call `start(codingWorkflow, [...])`, and return the run's
124
- readable stream.
246
+ Start the workflow from server-side code. As with semantic agent steps, pass the
247
+ converted messages so `HarnessAgent` can distinguish a new user turn from tool
248
+ approval and tool result continuations.
125
249
 
126
250
  ```ts filename='app/api/harness-workflow/route.ts'
127
- import { codingWorkflow } from '../../../harness-workflow/workflow';
251
+ import { timeSliceWorkflow } from '../../../harness-workflow/workflow';
128
252
  import {
129
253
  convertToModelMessages,
130
254
  createUIMessageStreamResponse,
@@ -133,15 +257,6 @@ import {
133
257
  } from 'ai';
134
258
  import { start } from 'workflow/api';
135
259
 
136
- function latestUserMessage(
137
- messages: Awaited<ReturnType<typeof convertToModelMessages>>,
138
- ) {
139
- for (let index = messages.length - 1; index >= 0; index--) {
140
- const message = messages[index];
141
- if (message.role === 'user') return message;
142
- }
143
- }
144
-
145
260
  export async function POST(request: Request) {
146
261
  const body: {
147
262
  id?: string;
@@ -152,14 +267,10 @@ export async function POST(request: Request) {
152
267
  return new Response('Missing chat ID', { status: 400 });
153
268
  }
154
269
 
155
- const prompt = latestUserMessage(await convertToModelMessages(body.messages));
156
- if (!prompt) {
157
- return new Response('No user message to run', { status: 400 });
158
- }
159
-
160
- const run = await start(codingWorkflow, [
270
+ const messages = await convertToModelMessages(body.messages);
271
+ const run = await start(timeSliceWorkflow, [
161
272
  {
162
- prompt,
273
+ messages,
163
274
  sessionId: body.id,
164
275
  },
165
276
  ]);
@@ -170,23 +281,21 @@ export async function POST(request: Request) {
170
281
  }
171
282
  ```
172
283
 
173
- If you use Next.js, wrap your config with `withWorkflow()` so Workflow SDK
174
- transforms `'use workflow'` and `'use step'` modules. Other frameworks have
175
- their own Workflow SDK setup.
176
-
177
- ```js filename='next.config.js'
178
- const { withWorkflow } = require('workflow/next');
179
-
180
- const nextConfig = {};
181
-
182
- module.exports = withWorkflow(nextConfig, {});
183
- ```
284
+ The `sessionId` gives the sandbox a stable identity across workflow runs. Keep
285
+ `agent.ts`, `time-slice-step.ts`, `workflow.ts`, and the route in separate
286
+ modules so the workflow bundle does not include Node-heavy agent, sandbox, or
287
+ framework dependencies.
184
288
 
185
289
  ## Resume Persistence
186
290
 
187
- Persist only the opaque `resumeFrom` state returned after a finished turn. The
188
- example below uses Workflow steps because filesystem access must stay out of the
189
- workflow function itself. Use durable storage instead of local files in
291
+ Workflow automatically persists the `HarnessWorkflowState` returned by each
292
+ step, including `continueFrom`, for the duration of the current workflow run.
293
+ To continue the native harness session across separate user-turn workflow runs,
294
+ persist the opaque `resumeFrom` state by `sessionId`.
295
+
296
+ The storage implementation is the same for semantic agent steps and time
297
+ slices. This example uses Workflow steps because filesystem access must stay out
298
+ of the workflow function itself. Use durable storage instead of local files in
190
299
  production.
191
300
 
192
301
  ```ts filename='harness-workflow/resume-store.ts'
@@ -244,29 +353,33 @@ export async function persistResumeStep({
244
353
  }
245
354
  ```
246
355
 
247
- Load the resume state before the first slice and persist the new one after the
248
- turn finishes:
356
+ Load the previous `resumeFrom` state before creating the workflow state, then
357
+ persist the updated value after the execution loop. The integration points are
358
+ the same for both workflow approaches.
359
+
360
+ ### Semantic Agent Step Workflow
249
361
 
250
362
  ```ts filename='harness-workflow/workflow.ts'
363
+ import { agentStep } from './agent-step';
251
364
  import { loadResumeStep, persistResumeStep } from './resume-store';
252
- import { runSlice } from './run-slice-step';
253
365
  import {
254
366
  createHarnessWorkflowState,
255
367
  finalizeHarnessWorkflow,
256
368
  type HarnessWorkflowInput,
257
369
  } from '@ai-sdk/workflow-harness';
258
370
 
259
- export async function codingWorkflow(
260
- input: Pick<HarnessWorkflowInput, 'prompt' | 'sessionId'>,
261
- ) {
371
+ export async function agentWorkflow(input: {
372
+ messages: NonNullable<HarnessWorkflowInput['messages']>;
373
+ sessionId: string;
374
+ }) {
262
375
  'use workflow';
263
376
 
264
377
  const resumeFrom = await loadResumeStep(input.sessionId);
265
378
  let state = createHarnessWorkflowState({ ...input, resumeFrom });
266
379
 
267
- while (state.status === 'running' || state.status === 'timed_out') {
268
- state = await runSlice(state);
269
- }
380
+ do {
381
+ state = await agentStep(state);
382
+ } while (state.status === 'ready_for_next_step');
270
383
 
271
384
  await persistResumeStep({
272
385
  sessionId: state.sessionId,
@@ -277,48 +390,38 @@ export async function codingWorkflow(
277
390
  }
278
391
  ```
279
392
 
280
- The harness `sessionId` gives the sandbox a stable identity across workflow runs
281
- and lets the workflow load the previous turn's resume state before sending the
282
- next user message.
283
-
284
- A harness session owns its native conversation history, so the route sends only
285
- the newest user message. Do not replay the full UI message history into the
286
- harness.
393
+ ### Time-Sliced Workflow
287
394
 
288
- ## How It Works
289
-
290
- Each user turn is represented by a `HarnessWorkflowState`:
291
-
292
- - `createHarnessWorkflowState()` creates the initial state for the turn.
293
- - `runHarnessAgentSlice()` streams one time-boxed slice of the turn.
294
- - If the slice times out, the harness turn is suspended non-destructively and
295
- the returned state contains `continueFrom` for the next slice.
296
- - If the turn finishes, the helper closes the workflow output stream and returns
297
- `resumeFrom` for the next user turn.
298
- - `finalizeHarnessWorkflow()` returns the final result or throws when the
299
- workflow failed.
395
+ ```ts filename='harness-workflow/workflow.ts'
396
+ import { loadResumeStep, persistResumeStep } from './resume-store';
397
+ import { timeSliceStep } from './time-slice-step';
398
+ import {
399
+ createHarnessWorkflowState,
400
+ finalizeHarnessWorkflow,
401
+ type HarnessWorkflowInput,
402
+ } from '@ai-sdk/workflow-harness';
300
403
 
301
- The workflow output stream receives AI SDK UI message chunks, so a route can
302
- return `run.readable` through `createUIMessageStreamResponse()`.
404
+ export async function timeSliceWorkflow(input: {
405
+ messages: NonNullable<HarnessWorkflowInput['messages']>;
406
+ sessionId: string;
407
+ }) {
408
+ 'use workflow';
303
409
 
304
- ## File Boundaries
410
+ const resumeFrom = await loadResumeStep(input.sessionId);
411
+ let state = createHarnessWorkflowState({ ...input, resumeFrom });
305
412
 
306
- Keep the `workflow` entrypoints separate from the agent definition:
413
+ do {
414
+ state = await timeSliceStep(state);
415
+ } while (state.status === 'ready_for_next_step');
307
416
 
308
- - `agent.ts` defines the `HarnessAgent`.
309
- - `run-slice-step.ts` is a `'use step'` module and imports the agent
310
- dynamically inside the step body.
311
- - `workflow.ts` contains the `'use workflow'` function and imports only
312
- workflow-safe helpers and step modules.
313
- - your route or server entrypoint starts the workflow. It can import `ai`
314
- helpers such as `convertToModelMessages()` and
315
- `createUIMessageStreamResponse()`.
417
+ await persistResumeStep({
418
+ sessionId: state.sessionId,
419
+ resumeState: state.resumeFrom,
420
+ });
316
421
 
317
- Do not define the workflow function in the same module as the route handler,
318
- server entrypoint, or agent. The Workflow DevKit compiles the module graph
319
- reachable from a `'use workflow'` directive. Keeping the graph small prevents
320
- Node-heavy agent, sandbox, and framework dependencies from being pulled into the
321
- workflow bundle.
422
+ return finalizeHarnessWorkflow(state);
423
+ }
424
+ ```
322
425
 
323
426
  ## Related
324
427
 
@@ -134,7 +134,7 @@ To see `WorkflowAgent` in action, check out [these examples](#examples).
134
134
  type: 'Experimental_SandboxSession',
135
135
  isOptional: true,
136
136
  description:
137
- 'Default sandbox session passed to tool execution as `experimental_sandbox` and exposed to `prepareStep`. Per-stream values override this default.',
137
+ 'Default sandbox session passed to tool descriptions and execution as `experimental_sandbox`, and exposed to `prepareStep`. Per-stream values override this default.',
138
138
  },
139
139
  {
140
140
  name: 'prepareStep',
@@ -471,11 +471,17 @@ const result = await agent.stream({
471
471
  description:
472
472
  'A writable stream that receives raw model stream parts in real-time. Convert to UI message chunks at the response boundary using `createModelCallToUIChunkTransform()`.',
473
473
  },
474
+ {
475
+ name: 'instructions',
476
+ type: 'Instructions',
477
+ isOptional: true,
478
+ description: 'Override the agent instructions for this call.',
479
+ },
474
480
  {
475
481
  name: 'system',
476
482
  type: 'string',
477
483
  isOptional: true,
478
- description: 'Override the system prompt for this call.',
484
+ description: 'Deprecated. Use `instructions` instead.',
479
485
  },
480
486
  {
481
487
  name: 'stopWhen',
@@ -550,7 +556,7 @@ const result = await agent.stream({
550
556
  type: 'Experimental_SandboxSession',
551
557
  isOptional: true,
552
558
  description:
553
- 'Sandbox session passed to tool execution as `experimental_sandbox` and exposed to `prepareStep`. Overrides the constructor default.',
559
+ 'Sandbox session passed to tool descriptions and execution as `experimental_sandbox`, and exposed to `prepareStep`. Overrides the constructor default.',
554
560
  },
555
561
  {
556
562
  name: 'telemetry',
@@ -576,7 +582,8 @@ const result = await agent.stream({
576
582
  name: 'prepareStep',
577
583
  type: 'PrepareStepCallback',
578
584
  isOptional: true,
579
- description: 'Per-call prepareStep override.',
585
+ description:
586
+ 'Per-call prepareStep override. Receives the initial instructions and messages alongside the current step state.',
580
587
  },
581
588
  {
582
589
  name: 'experimental_onStart',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "7.0.38",
3
+ "version": "7.0.40",
4
4
  "type": "module",
5
5
  "description": "AI SDK by Vercel - build apps like ChatGPT, Claude, Gemini, and more with a single interface for any model using the Vercel AI Gateway or go direct to OpenAI, Anthropic, Google, or any other model provider.",
6
6
  "license": "Apache-2.0",
@@ -42,9 +42,9 @@
42
42
  }
43
43
  },
44
44
  "dependencies": {
45
- "@ai-sdk/gateway": "4.0.29",
45
+ "@ai-sdk/gateway": "4.0.30",
46
46
  "@ai-sdk/provider": "4.0.4",
47
- "@ai-sdk/provider-utils": "5.0.13"
47
+ "@ai-sdk/provider-utils": "5.0.14"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@edge-runtime/vm": "^5.0.0",