ai 7.0.37 → 7.0.39

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.
Files changed (37) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/index.d.ts +283 -41
  3. package/dist/index.js +688 -425
  4. package/dist/index.js.map +1 -1
  5. package/dist/internal/index.js +1 -1
  6. package/dist/internal/index.js.map +1 -1
  7. package/dist/test/index.d.ts +14 -2
  8. package/dist/test/index.js +15 -0
  9. package/dist/test/index.js.map +1 -1
  10. package/docs/03-agents/07-workflow-agent.mdx +3 -2
  11. package/docs/03-ai-sdk-core/36-transcription.mdx +40 -35
  12. package/docs/03-ai-sdk-core/36-translation.mdx +209 -0
  13. package/docs/03-ai-sdk-core/index.mdx +5 -0
  14. package/docs/03-ai-sdk-harnesses/06-workflow-utilities.mdx +225 -122
  15. package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +1 -1
  16. package/docs/07-reference/01-ai-sdk-core/11-stream-translate.mdx +176 -0
  17. package/docs/07-reference/01-ai-sdk-core/index.mdx +5 -0
  18. package/docs/07-reference/04-ai-sdk-workflow/01-workflow-agent.mdx +11 -4
  19. package/docs/07-reference/05-ai-sdk-errors/ai-no-translation-generated-error.mdx +26 -0
  20. package/docs/07-reference/05-ai-sdk-errors/index.mdx +1 -0
  21. package/package.json +4 -4
  22. package/src/error/index.ts +1 -0
  23. package/src/error/no-translation-generated-error.ts +28 -0
  24. package/src/generate-object/generate-object.ts +12 -2
  25. package/src/generate-object/stream-object.ts +14 -1
  26. package/src/generate-text/generate-text.ts +4 -1
  27. package/src/generate-text/stream-language-model-call.ts +14 -12
  28. package/src/generate-text/stream-text-result.ts +3 -2
  29. package/src/index.ts +1 -0
  30. package/src/model/resolve-model.ts +35 -0
  31. package/src/test/mock-speech-translation-model-v4.ts +24 -0
  32. package/src/transcribe/stream-transcribe.ts +2 -11
  33. package/src/translate/index.ts +5 -0
  34. package/src/translate/stream-translate-result.ts +146 -0
  35. package/src/translate/stream-translate.ts +374 -0
  36. package/src/types/speech-translation-model-response-metadata.ts +22 -0
  37. package/src/types/speech-translation-model.ts +11 -0
@@ -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
 
@@ -3210,7 +3210,7 @@ To see `streamText` in action, check out [these examples](#examples).
3210
3210
  name: 'textStream',
3211
3211
  type: 'AsyncIterableStream<string>',
3212
3212
  description:
3213
- 'A text stream that returns only the generated text deltas. You can use it as either an AsyncIterable or a ReadableStream. When an error occurs, the stream will throw the error.',
3213
+ 'A text stream that returns only the generated text deltas. You can use it as either an AsyncIterable or a ReadableStream. Error parts are not surfaced in this stream. Use the `onError` callback or `stream` to observe them.',
3214
3214
  },
3215
3215
  {
3216
3216
  name: 'finalStep',
@@ -0,0 +1,176 @@
1
+ ---
2
+ title: experimental_streamTranslate
3
+ description: API Reference for experimental_streamTranslate.
4
+ ---
5
+
6
+ # `experimental_streamTranslate()`
7
+
8
+ <Note type="warning">
9
+ `experimental_streamTranslate` is an experimental feature.
10
+ </Note>
11
+
12
+ Streams a speech-to-speech translation from live raw audio. Models translate
13
+ live source audio into target-language audio and text.
14
+
15
+ `experimental_streamTranslate` is built on the speech translation model
16
+ specification (`Experimental_SpeechTranslationModelV4`). Provider
17
+ implementations of the specification ship separately — see your provider's
18
+ documentation for available translation models.
19
+
20
+ ```ts
21
+ import { experimental_streamTranslate as streamTranslate } from 'ai';
22
+
23
+ const result = streamTranslate({
24
+ // any provider model instance that implements the experimental
25
+ // speech translation model specification (Experimental_SpeechTranslationModelV4):
26
+ model: translationModel,
27
+ audio: audioStream, // ReadableStream<Uint8Array | string>
28
+ inputAudioFormat: { type: 'audio/pcm', rate: 24000 },
29
+ targetLanguage: 'es',
30
+ });
31
+
32
+ for await (const part of result.fullStream) {
33
+ if (part.type === 'output-text-delta') {
34
+ process.stdout.write(part.delta);
35
+ }
36
+ }
37
+
38
+ console.log(await result.translationText);
39
+ ```
40
+
41
+ ## Import
42
+
43
+ <Snippet
44
+ text={`import { experimental_streamTranslate as streamTranslate } from "ai"`}
45
+ prompt={false}
46
+ />
47
+
48
+ ## API Signature
49
+
50
+ ### Parameters
51
+
52
+ <PropertiesTable
53
+ content={[
54
+ {
55
+ name: 'model',
56
+ type: 'Experimental_SpeechTranslationModelV4',
57
+ description:
58
+ 'The speech translation model to use. Translation is a streaming-only modality. Pass a provider model instance that implements the experimental speech translation model specification. String model IDs resolve through the global provider (AI Gateway by default) when it supports speech translation models.',
59
+ },
60
+ {
61
+ name: 'audio',
62
+ type: 'ReadableStream<Uint8Array | string>',
63
+ description:
64
+ 'Raw audio chunks to translate. `Uint8Array` chunks contain raw audio bytes; `string` chunks contain base64-encoded raw audio bytes.',
65
+ },
66
+ {
67
+ name: 'inputAudioFormat',
68
+ type: '{ type: string; rate?: number }',
69
+ description:
70
+ 'The input audio format for the raw audio chunks, e.g. `{ type: "audio/pcm", rate: 24000 }`. Supported types are provider-specific (e.g. `audio/pcm`, `audio/pcmu`, `audio/pcma`).',
71
+ },
72
+ {
73
+ name: 'targetLanguage',
74
+ type: 'string',
75
+ description:
76
+ 'The language to translate the audio into, as a BCP-47-style language tag (e.g. `en`, `es`, `fr-CA`). Supported values are provider-specific and validated by the provider.',
77
+ },
78
+ {
79
+ name: 'sourceLanguage',
80
+ type: 'string',
81
+ isOptional: true,
82
+ description:
83
+ 'The language of the source audio, as a BCP-47-style language tag. When absent, providers auto-detect the source language.',
84
+ },
85
+ {
86
+ name: 'outputAudioFormat',
87
+ type: '{ type: string; rate?: number }',
88
+ isOptional: true,
89
+ description:
90
+ 'The desired audio format for translated audio chunks. When absent, the provider default output format is used.',
91
+ },
92
+ {
93
+ name: 'providerOptions',
94
+ type: 'Record<string, JSONObject>',
95
+ isOptional: true,
96
+ description: 'Additional provider-specific options.',
97
+ },
98
+ {
99
+ name: 'abortSignal',
100
+ type: 'AbortSignal',
101
+ isOptional: true,
102
+ description: 'An optional abort signal to cancel the call.',
103
+ },
104
+ {
105
+ name: 'headers',
106
+ type: 'Record<string, string>',
107
+ isOptional: true,
108
+ description:
109
+ 'Additional HTTP/WebSocket headers, if supported by the provider.',
110
+ },
111
+ {
112
+ name: 'includeRawChunks',
113
+ type: 'boolean',
114
+ isOptional: true,
115
+ description:
116
+ 'When true, the provider includes raw provider chunks in the stream as `raw` parts.',
117
+ },
118
+ ]}
119
+ />
120
+
121
+ ### Returns
122
+
123
+ <PropertiesTable
124
+ content={[
125
+ {
126
+ name: 'fullStream',
127
+ type: 'AsyncIterableStream<TranslationStreamPart>',
128
+ description:
129
+ 'A single-consumer live stream of translation parts: `audio`, `output-text-delta`, `output-text-final`, `source-transcript-delta`, `source-transcript-partial`, `source-transcript-final`, `raw`, and `error`. Access it once, before any result promise, when both stream parts and final results are needed. Accessing a result promise first consumes the stream internally and makes `fullStream` unavailable.',
130
+ },
131
+ {
132
+ name: 'sourceText',
133
+ type: 'Promise<string>',
134
+ description: 'The final source-language transcript of the input audio.',
135
+ },
136
+ {
137
+ name: 'translationText',
138
+ type: 'Promise<string>',
139
+ description:
140
+ 'The final translated text in the target language. May resolve to an empty string for providers that produce only audio output.',
141
+ },
142
+ {
143
+ name: 'durationInSeconds',
144
+ type: 'Promise<number | undefined>',
145
+ description: 'The duration of the source audio in seconds, if available.',
146
+ },
147
+ {
148
+ name: 'usage',
149
+ type: 'Promise<Experimental_SpeechTranslationModelV4Usage | undefined>',
150
+ description:
151
+ 'Usage information for the translation call, if reported by the provider: `inputAudioSeconds`, `inputAudioTokens`, `outputAudioTokens`, `inputTextTokens`, `outputTextTokens` (all optional numbers).',
152
+ },
153
+ {
154
+ name: 'warnings',
155
+ type: 'Promise<Warning[]>',
156
+ description:
157
+ 'Warnings for the call, e.g. unsupported settings. Resolves at stream start, or with an empty array at finish if no stream-start was emitted.',
158
+ },
159
+ {
160
+ name: 'response',
161
+ type: 'Promise<SpeechTranslationModelResponseMetadata>',
162
+ description: 'Response metadata (timestamp, model ID, headers).',
163
+ },
164
+ {
165
+ name: 'providerMetadata',
166
+ type: 'Promise<Record<string, JSONObject>>',
167
+ description: 'Additional provider-specific metadata.',
168
+ },
169
+ ]}
170
+ />
171
+
172
+ <Note>
173
+ The result promises settle as the stream is consumed. If you stop consuming
174
+ `fullStream` early (e.g. `break` out of the loop), the underlying provider
175
+ connection is closed and pending result promises reject.
176
+ </Note>