ai 7.0.87 → 7.0.89

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.
@@ -587,11 +587,11 @@ Agents provide lifecycle callbacks for logging, observability, and custom teleme
587
587
  const agent = new WorkflowAgent({
588
588
  model: 'anthropic/claude-sonnet-4-6',
589
589
 
590
- experimental_onStart({ modelId, messages }) {
591
- console.log('Agent started');
590
+ onStart({ messages }) {
591
+ console.log(`Agent started with ${messages.length} messages`);
592
592
  },
593
593
 
594
- experimental_onStepStart({ stepNumber }) {
594
+ onStepStart({ stepNumber }) {
595
595
  console.log(`Step ${stepNumber} starting`);
596
596
  },
597
597
 
@@ -613,6 +613,11 @@ const agent = new WorkflowAgent({
613
613
  });
614
614
  ```
615
615
 
616
+ The deprecated `experimental_onStart` and `experimental_onStepStart` names
617
+ remain available for backwards compatibility. When both the stable and
618
+ experimental name are provided in the same constructor or `stream()` call, the
619
+ stable callback is used.
620
+
616
621
  ## Type Inference
617
622
 
618
623
  Infer the UI message type for type-safe client components:
@@ -764,7 +769,7 @@ For persistence, store `UIMessage[]` as your source of truth and call [`convertT
764
769
 
765
770
  ### Everything else
766
771
 
767
- Other options carry over with the same names: `prepareStep`, `onStepEnd`, `onEnd`, `onError`, `toolChoice`, `activeTools`, `timeout`, `repairToolCall`, `experimental_sandbox`, and the usual generation settings (`temperature`, `maxOutputTokens`, `topP`, …). `WorkflowAgent` additionally adds `prepareCall` (runs once before the loop) and the `experimental_onStart` / `experimental_onStepStart` / `onToolExecutionStart` / `onToolExecutionEnd` lifecycle callbacks documented above.
772
+ Other options carry over with the same names: `prepareStep`, `onStart`, `onStepStart`, `onStepEnd`, `onEnd`, `onError`, `toolChoice`, `activeTools`, `timeout`, `repairToolCall`, `experimental_sandbox`, and the usual generation settings (`temperature`, `maxOutputTokens`, `topP`, …). `WorkflowAgent` additionally adds `prepareCall` (runs once before the loop) and the `onToolExecutionStart` / `onToolExecutionEnd` lifecycle callbacks documented above. The deprecated `experimental_onStart` and `experimental_onStepStart` aliases remain available for backwards compatibility.
768
773
 
769
774
  ## Next Steps
770
775
 
@@ -1133,11 +1133,12 @@ async function generateSomething(prompt: string): Promise<{
1133
1133
 
1134
1134
  ## Handling Errors
1135
1135
 
1136
- The AI SDK has three tool-call related errors:
1136
+ The AI SDK has four tool-call related errors:
1137
1137
 
1138
1138
  - [`NoSuchToolError`](/docs/reference/ai-sdk-errors/ai-no-such-tool-error): the model tries to call a tool that is not defined in the tools object
1139
1139
  - [`InvalidToolInputError`](/docs/reference/ai-sdk-errors/ai-invalid-tool-input-error): the model calls a tool with inputs that do not match the tool's input schema
1140
1140
  - [`ToolCallRepairError`](/docs/reference/ai-sdk-errors/ai-tool-call-repair-error): an error that occurred during tool call repair
1141
+ - [`ToolChoiceViolationError`](/docs/reference/ai-sdk-errors/ai-tool-choice-violation-error): the `generateText` response does not satisfy a required or specifically selected tool choice
1141
1142
 
1142
1143
  When tool execution fails (errors thrown by your tool's `execute` function), the AI SDK adds them as `tool-error` content parts to enable automated LLM roundtrips in multi-step scenarios.
1143
1144
 
@@ -94,6 +94,31 @@ const { providerReference } = await uploadFile({
94
94
  });
95
95
  ```
96
96
 
97
+ ## Streaming Uploads
98
+
99
+ Providers that support streaming uploads (e.g. OpenAI, xAI) accept a tagged
100
+ `{ type: 'stream', stream }` shape, sending the bytes without buffering the
101
+ full file in memory. Providers without streaming support reject stream data
102
+ with an `UnsupportedFunctionalityError`.
103
+
104
+ ```ts
105
+ const { providerReference } = await uploadFile({
106
+ api: openai.files(),
107
+ data: { type: 'stream', stream: fileStream },
108
+ mediaType: 'application/jsonl',
109
+ filename: 'batch.jsonl',
110
+ });
111
+ ```
112
+
113
+ The provider consumes the stream: any failed upload — including validation
114
+ failures before a request is made — cancels it, and it must not be reused. Stream data cannot be sniffed, so `mediaType` defaults to
115
+ `application/octet-stream` when omitted, and multipart-based providers default
116
+ the filename to `"blob"`.
117
+
118
+ Uploads can be cancelled with `abortSignal` and carry request-specific
119
+ `headers`. Results include `byteSize`, `createdAt`, and `expiresAt` (the
120
+ provider-applied retention expiry) when the provider reports them.
121
+
97
122
  ## Provider References
98
123
 
99
124
  A `ProviderReference` is a `Record<string, string>` that maps provider names to
@@ -39,22 +39,35 @@ const { providerReference } = await uploadFile({
39
39
  },
40
40
  {
41
41
  name: 'data',
42
- type: 'DataContent',
42
+ type: 'DataContent | { type: "stream"; stream: ReadableStream<Uint8Array> }',
43
43
  description:
44
- 'The file data to upload. Can be a `Uint8Array`, a base64-encoded string, an `ArrayBuffer`, or a `Buffer`. URLs are not supported — fetch the content first and pass the bytes.',
44
+ 'The file data to upload. Can be a `Uint8Array`, a base64-encoded string, an `ArrayBuffer`, a `Buffer`, or a tagged `{ type: "stream", stream }` shape for providers that support streaming uploads (sent without buffering; other providers reject with an `UnsupportedFunctionalityError`). The provider consumes the stream — any failed upload (including validation failures before a request is made) cancels it, and it must not be reused. URLs are not supported — fetch the content first and pass the bytes.',
45
45
  },
46
46
  {
47
47
  name: 'mediaType',
48
48
  type: 'string',
49
49
  isOptional: true,
50
50
  description:
51
- 'IANA media type of the file (e.g. `image/png`, `application/pdf`). Auto-detected from the file bytes if not provided.',
51
+ 'IANA media type of the file (e.g. `image/png`, `application/pdf`). Auto-detected from the file bytes if not provided; stream data cannot be sniffed and defaults to `application/octet-stream`.',
52
52
  },
53
53
  {
54
54
  name: 'filename',
55
55
  type: 'string',
56
56
  isOptional: true,
57
- description: 'Filename for the uploaded file.',
57
+ description:
58
+ 'Filename for the uploaded file. Multipart-based providers default it to `"blob"` when omitted.',
59
+ },
60
+ {
61
+ name: 'abortSignal',
62
+ type: 'AbortSignal',
63
+ isOptional: true,
64
+ description: 'Signal to cancel the upload.',
65
+ },
66
+ {
67
+ name: 'headers',
68
+ type: 'Record<string, string>',
69
+ isOptional: true,
70
+ description: 'Additional HTTP headers to send with the request.',
58
71
  },
59
72
  {
60
73
  name: 'providerOptions',
@@ -76,6 +89,26 @@ const { providerReference } = await uploadFile({
76
89
  description:
77
90
  'A `Record<string, string>` mapping provider names to provider-specific file identifiers. Pass this as the `data` or `image` field in message content parts.',
78
91
  },
92
+ {
93
+ name: 'byteSize',
94
+ type: 'number',
95
+ isOptional: true,
96
+ description:
97
+ 'Size of the uploaded file in bytes, if reported by the provider.',
98
+ },
99
+ {
100
+ name: 'createdAt',
101
+ type: 'Date',
102
+ isOptional: true,
103
+ description: 'When the file was created, if reported by the provider.',
104
+ },
105
+ {
106
+ name: 'expiresAt',
107
+ type: 'Date',
108
+ isOptional: true,
109
+ description:
110
+ 'When the provider will delete the file (retention expiry, e.g. from a requested upload TTL), if reported by the provider.',
111
+ },
79
112
  {
80
113
  name: 'providerMetadata',
81
114
  type: 'ProviderMetadata',
@@ -179,11 +179,11 @@ To see `WorkflowAgent` in action, check out [these examples](#examples).
179
179
  'Telemetry configuration with options for enabling/disabling telemetry, setting a function ID, and recording inputs/outputs.',
180
180
  },
181
181
  {
182
- name: 'experimental_onStart',
182
+ name: 'onStart',
183
183
  type: 'WorkflowAgentOnStartCallback',
184
184
  isOptional: true,
185
185
  description:
186
- 'Callback called when the agent starts streaming, before any LLM calls. Receives the model, messages, runtime context, and tools context. If also specified in `stream()`, both callbacks fire (constructor first). Experimental (can break in patch releases).',
186
+ 'Callback called when the agent starts streaming, before any LLM calls. Receives the model, messages, runtime context, and tools context. If also specified in `stream()`, both callbacks fire (constructor first). Takes precedence over `experimental_onStart` when both are provided in the constructor.',
187
187
  properties: [
188
188
  {
189
189
  type: 'GenerateTextStartEvent',
@@ -213,11 +213,18 @@ To see `WorkflowAgent` in action, check out [these examples](#examples).
213
213
  ],
214
214
  },
215
215
  {
216
- name: 'experimental_onStepStart',
216
+ name: 'experimental_onStart',
217
+ type: 'WorkflowAgentOnStartCallback',
218
+ isOptional: true,
219
+ description:
220
+ 'Deprecated alias for `onStart`. Used only when `onStart` is not provided in the constructor.',
221
+ },
222
+ {
223
+ name: 'onStepStart',
217
224
  type: 'WorkflowAgentOnStepStartCallback',
218
225
  isOptional: true,
219
226
  description:
220
- 'Callback called before each step (LLM call) begins. Receives step number, model, messages, previous steps, runtime context, and tools context. If also specified in `stream()`, both callbacks fire (constructor first). Experimental (can break in patch releases).',
227
+ 'Callback called before each step (LLM call) begins. Receives step number, model, messages, previous steps, runtime context, and tools context. If also specified in `stream()`, both callbacks fire (constructor first). Takes precedence over `experimental_onStepStart` when both are provided in the constructor.',
221
228
  properties: [
222
229
  {
223
230
  type: 'GenerateTextStepStartEvent',
@@ -252,6 +259,13 @@ To see `WorkflowAgent` in action, check out [these examples](#examples).
252
259
  },
253
260
  ],
254
261
  },
262
+ {
263
+ name: 'experimental_onStepStart',
264
+ type: 'WorkflowAgentOnStepStartCallback',
265
+ isOptional: true,
266
+ description:
267
+ 'Deprecated alias for `onStepStart`. Used only when `onStepStart` is not provided in the constructor.',
268
+ },
255
269
  {
256
270
  name: 'onToolExecutionStart',
257
271
  type: 'WorkflowAgentonToolExecutionStartCallback',
@@ -600,19 +614,33 @@ const result = await agent.stream({
600
614
  description:
601
615
  'Per-call prepareStep override. Receives the initial instructions and messages alongside the current step state.',
602
616
  },
617
+ {
618
+ name: 'onStart',
619
+ type: 'WorkflowAgentOnStartCallback',
620
+ isOptional: true,
621
+ description:
622
+ 'Per-call onStart callback. If also specified in the constructor, both fire (constructor first). Takes precedence over `experimental_onStart` when both are provided in this call.',
623
+ },
603
624
  {
604
625
  name: 'experimental_onStart',
605
626
  type: 'WorkflowAgentOnStartCallback',
606
627
  isOptional: true,
607
628
  description:
608
- 'Per-call onStart callback. If also specified in the constructor, both fire (constructor first). Experimental.',
629
+ 'Deprecated alias for the per-call `onStart` callback. Used only when `onStart` is not provided in this call.',
630
+ },
631
+ {
632
+ name: 'onStepStart',
633
+ type: 'WorkflowAgentOnStepStartCallback',
634
+ isOptional: true,
635
+ description:
636
+ 'Per-call onStepStart callback. If also specified in the constructor, both fire (constructor first). Takes precedence over `experimental_onStepStart` when both are provided in this call.',
609
637
  },
610
638
  {
611
639
  name: 'experimental_onStepStart',
612
640
  type: 'WorkflowAgentOnStepStartCallback',
613
641
  isOptional: true,
614
642
  description:
615
- 'Per-call onStepStart callback. If also specified in the constructor, both fire (constructor first). Experimental.',
643
+ 'Deprecated alias for the per-call `onStepStart` callback. Used only when `onStepStart` is not provided in this call.',
616
644
  },
617
645
  {
618
646
  name: 'onToolExecutionStart',
@@ -0,0 +1,38 @@
1
+ ---
2
+ title: ToolChoiceViolationError
3
+ description: Learn how to fix AI SDK ToolChoiceViolationError
4
+ ---
5
+
6
+ # ToolChoiceViolationError
7
+
8
+ This error occurs when a `generateText` response does not satisfy an enforced
9
+ tool choice. It is thrown when `toolChoice` is set to `'required'` but the
10
+ response contains no structured tool call, or when a specifically selected tool
11
+ was not called.
12
+
13
+ The error does not automatically interpret text or reasoning as an executable
14
+ tool call. You can inspect `content` to implement opt-in recovery, including
15
+ schema validation before executing any recovered call.
16
+
17
+ ## Properties
18
+
19
+ - `toolChoice`: The effective tool choice that the response did not satisfy
20
+ - `finishReason`: The reason why the model finished generating the response
21
+ - `provider`: The provider that returned the response
22
+ - `modelId`: The model that returned the response
23
+ - `content`: The normalized content returned by the model
24
+ - `message`: The error message
25
+
26
+ ## Checking for this Error
27
+
28
+ You can check if an error is an instance of `ToolChoiceViolationError` using:
29
+
30
+ ```typescript
31
+ import { ToolChoiceViolationError } from 'ai';
32
+
33
+ if (ToolChoiceViolationError.isInstance(error)) {
34
+ const serializedCall = error.content.find(part => part.type === 'text')?.text;
35
+
36
+ // Parse and validate serializedCall before treating it as a tool call.
37
+ }
38
+ ```
@@ -36,6 +36,7 @@ collapsed: true
36
36
  - [AI_StreamProviderError](/docs/reference/ai-sdk-errors/ai-stream-provider-error)
37
37
  - [AI_ToolCallNotFoundForApprovalError](/docs/reference/ai-sdk-errors/ai-tool-call-not-found-for-approval-error)
38
38
  - [AI_ToolCallRepairError](/docs/reference/ai-sdk-errors/ai-tool-call-repair-error)
39
+ - [AI_ToolChoiceViolationError](/docs/reference/ai-sdk-errors/ai-tool-choice-violation-error)
39
40
  - [AI_TooManyEmbeddingValuesForCallError](/docs/reference/ai-sdk-errors/ai-too-many-embedding-values-for-call-error)
40
41
  - [AI_TypeValidationError](/docs/reference/ai-sdk-errors/ai-type-validation-error)
41
42
  - [AI_UIMessageStreamError](/docs/reference/ai-sdk-errors/ai-ui-message-stream-error)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "7.0.87",
3
+ "version": "7.0.89",
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,20 +42,20 @@
42
42
  }
43
43
  },
44
44
  "dependencies": {
45
- "@ai-sdk/gateway": "4.0.70",
46
- "@ai-sdk/provider": "4.0.9",
47
- "@ai-sdk/provider-utils": "5.0.34"
45
+ "@ai-sdk/gateway": "4.0.71",
46
+ "@ai-sdk/provider": "4.0.10",
47
+ "@ai-sdk/provider-utils": "5.0.35"
48
48
  },
49
49
  "devDependencies": {
50
- "@ai-sdk/amazon-bedrock": "5.0.69",
51
- "@ai-sdk/deepseek": "3.0.37",
52
- "@ai-sdk/google": "4.0.59",
53
- "@ai-sdk/groq": "4.0.35",
54
- "@ai-sdk/huggingface": "2.0.41",
55
- "@ai-sdk/moonshotai": "3.0.43",
56
- "@ai-sdk/openai": "4.0.53",
50
+ "@ai-sdk/amazon-bedrock": "5.0.71",
51
+ "@ai-sdk/deepseek": "3.0.38",
52
+ "@ai-sdk/google": "4.0.61",
53
+ "@ai-sdk/groq": "4.0.36",
54
+ "@ai-sdk/huggingface": "2.0.42",
55
+ "@ai-sdk/moonshotai": "3.0.44",
56
+ "@ai-sdk/openai": "4.0.55",
57
57
  "@ai-sdk/test-server": "2.0.1",
58
- "@ai-sdk/xai": "4.0.50",
58
+ "@ai-sdk/xai": "4.0.52",
59
59
  "@edge-runtime/vm": "^5.0.0",
60
60
  "@smithy/eventstream-codec": "^4.3.3",
61
61
  "@smithy/util-utf8": "^4.3.3",
@@ -4,13 +4,19 @@ import type {
4
4
  Experimental_BatchV4Status as BatchV4Status,
5
5
  Experimental_BatchLanguageModelV4 as BatchLanguageModelV4,
6
6
  } from '@ai-sdk/provider';
7
- import type { ProviderOptions, ToolSet } from '@ai-sdk/provider-utils';
7
+ import type {
8
+ InferToolSetContext,
9
+ ProviderOptions,
10
+ ToolSet,
11
+ } from '@ai-sdk/provider-utils';
8
12
  import type { ContentPart } from '../generate-text/content-part';
13
+ import type { ToolOrder } from '../generate-text/tool-order';
9
14
  import type { LanguageModelCallOptions } from '../prompt/language-model-call-options';
10
15
  import type { Prompt } from '../prompt/prompt';
11
16
  import type {
12
17
  FinishReason,
13
18
  GlobalProviderModelId,
19
+ ToolChoice,
14
20
  } from '../types/language-model';
15
21
  import type { ProviderMetadata } from '../types/provider-metadata';
16
22
  import type { LanguageModelUsage } from '../types/usage';
@@ -74,9 +80,34 @@ type BatchRequestOptions = {
74
80
  /**
75
81
  * Options for starting a text batch.
76
82
  */
77
- export type StartTextBatchOptions = {
83
+ export type StartTextBatchOptions<TOOLS extends ToolSet = ToolSet> = {
78
84
  model: BatchLanguageModel;
79
85
  requests: ReadonlyArray<TextBatchRequest>;
86
+
87
+ /**
88
+ * Tools that the model can call for every request in the batch.
89
+ *
90
+ * Tool definitions are sent to the provider, but their `execute` functions
91
+ * are never invoked by batch processing.
92
+ */
93
+ tools?: TOOLS;
94
+
95
+ /**
96
+ * The tool choice strategy. Default: 'auto'.
97
+ */
98
+ toolChoice?: ToolChoice<NoInfer<TOOLS>>;
99
+
100
+ /**
101
+ * Controls the order in which tools are sent to the provider. Tools not
102
+ * listed are appended alphabetically.
103
+ */
104
+ toolOrder?: ToolOrder<TOOLS>;
105
+
106
+ /**
107
+ * Context used when resolving dynamic tool descriptions.
108
+ */
109
+ toolsContext?: InferToolSetContext<TOOLS>;
110
+
80
111
  providerOptions?: ProviderOptions;
81
112
 
82
113
  /**
@@ -97,9 +128,18 @@ export type StartTextBatchResult = TextBatch & {
97
128
  /**
98
129
  * Options shared by batch status and result retrieval operations.
99
130
  */
100
- export type BatchOperationOptions = {
131
+ export type BatchOperationOptions<TOOLS extends ToolSet = ToolSet> = {
101
132
  model: BatchLanguageModel;
102
133
  batch: BatchReference;
134
+
135
+ /**
136
+ * Definitions for client tools that were provided to `startTextBatch`.
137
+ *
138
+ * The definitions are used only to validate and normalize returned tool
139
+ * calls. Their `execute` functions are never invoked.
140
+ */
141
+ tools?: TOOLS;
142
+
103
143
  providerOptions?: ProviderOptions;
104
144
  maxRetries?: number;
105
145
  } & BatchRequestOptions;
@@ -107,9 +147,9 @@ export type BatchOperationOptions = {
107
147
  /**
108
148
  * A normalized result for a successful text batch item.
109
149
  */
110
- export type TextBatchGenerationResult = {
150
+ export type TextBatchGenerationResult<TOOLS extends ToolSet = ToolSet> = {
111
151
  /** Ordered normalized content, including citations, sources, and tool data. */
112
- readonly content: Array<ContentPart<ToolSet>>;
152
+ readonly content: Array<ContentPart<TOOLS>>;
113
153
  readonly text: string;
114
154
  readonly finishReason: FinishReason;
115
155
  readonly rawFinishReason?: string;
@@ -125,8 +165,8 @@ export type TextBatchGenerationResult = {
125
165
  /**
126
166
  * A complete terminal result for one request in a text batch.
127
167
  */
128
- export type TextBatchItemResult =
129
- | (TextBatchGenerationResult & {
168
+ export type TextBatchItemResult<TOOLS extends ToolSet = ToolSet> =
169
+ | (TextBatchGenerationResult<TOOLS> & {
130
170
  readonly id: string;
131
171
  readonly status: 'succeeded';
132
172
  })
@@ -10,6 +10,8 @@ import { type ToolSet, withUserAgentSuffix } from '@ai-sdk/provider-utils';
10
10
  import { InvalidArgumentError } from '../error/invalid-argument-error';
11
11
  import { convertLanguageModelContent } from '../generate-text/convert-language-model-content';
12
12
  import { parseToolCall } from '../generate-text/parse-tool-call';
13
+ import { prepareToolChoice } from '../prompt/prepare-tool-choice';
14
+ import { prepareTools } from '../prompt/prepare-tools';
13
15
  import { logWarnings } from '../logger/log-warnings';
14
16
  import { resolveLanguageModel } from '../model/resolve-model';
15
17
  import { convertToLanguageModelPrompt } from '../prompt/convert-to-language-model-prompt';
@@ -36,15 +38,19 @@ import type {
36
38
  /**
37
39
  * Starts a durable text-generation batch.
38
40
  */
39
- export async function startTextBatch({
41
+ export async function startTextBatch<TOOLS extends ToolSet>({
40
42
  model: modelArg,
41
43
  requests,
44
+ tools,
45
+ toolChoice,
46
+ toolOrder,
47
+ toolsContext,
42
48
  providerOptions,
43
49
  webhookUrl,
44
50
  abortSignal,
45
51
  headers,
46
52
  timeout,
47
- }: StartTextBatchOptions): Promise<StartTextBatchResult> {
53
+ }: StartTextBatchOptions<TOOLS>): Promise<StartTextBatchResult> {
48
54
  validateRequests(requests);
49
55
 
50
56
  const model = resolveBatchLanguageModel(modelArg);
@@ -53,6 +59,12 @@ export async function startTextBatch({
53
59
  getTotalTimeoutMs(timeout),
54
60
  );
55
61
  const supportedUrls = await model.supportedUrls;
62
+ const preparedTools = await prepareTools({
63
+ tools,
64
+ toolOrder,
65
+ toolsContext,
66
+ });
67
+ const preparedToolChoice = prepareToolChoice({ toolChoice });
56
68
  operationAbortSignal?.throwIfAborted();
57
69
  const normalizedRequests = [];
58
70
 
@@ -69,6 +81,8 @@ export async function startTextBatch({
69
81
  download: undefined,
70
82
  provider: model.provider.split('.')[0],
71
83
  }),
84
+ tools: preparedTools,
85
+ toolChoice: preparedToolChoice,
72
86
  providerOptions: request.providerOptions,
73
87
  },
74
88
  });
@@ -120,7 +134,7 @@ export async function getBatchStatus({
120
134
  abortSignal,
121
135
  headers,
122
136
  timeout,
123
- }: BatchOperationOptions): Promise<BatchStatus> {
137
+ }: Omit<BatchOperationOptions, 'tools'>): Promise<BatchStatus> {
124
138
  const model = resolveBatchLanguageModel(modelArg);
125
139
  validateBatchReference({ model, batch });
126
140
 
@@ -152,15 +166,16 @@ export async function getBatchStatus({
152
166
  /**
153
167
  * Streams complete terminal results for the requests in a durable batch.
154
168
  */
155
- export function getBatchResults({
169
+ export function getBatchResults<TOOLS extends ToolSet>({
156
170
  model: modelArg,
157
171
  batch,
172
+ tools,
158
173
  providerOptions,
159
174
  maxRetries,
160
175
  abortSignal,
161
176
  headers,
162
177
  timeout,
163
- }: BatchOperationOptions) {
178
+ }: BatchOperationOptions<TOOLS>) {
164
179
  const model = resolveBatchLanguageModel(modelArg);
165
180
  validateBatchReference({ model, batch });
166
181
 
@@ -176,10 +191,10 @@ export function getBatchResults({
176
191
  });
177
192
  const transformer: Transformer<
178
193
  BatchV4ItemResult<LanguageModelV4GenerateResult>,
179
- TextBatchItemResult
194
+ TextBatchItemResult<TOOLS>
180
195
  > & { cancel?: (reason?: unknown) => void } = {
181
196
  async transform(item, controller) {
182
- controller.enqueue(await convertBatchItemResult(item));
197
+ controller.enqueue(await convertBatchItemResult({ item, tools }));
183
198
  },
184
199
 
185
200
  cancel(reason) {
@@ -190,7 +205,7 @@ export function getBatchResults({
190
205
  };
191
206
  const transform = new TransformStream<
192
207
  BatchV4ItemResult<LanguageModelV4GenerateResult>,
193
- TextBatchItemResult
208
+ TextBatchItemResult<TOOLS>
194
209
  >(transformer);
195
210
 
196
211
  void (async () => {
@@ -299,9 +314,13 @@ function validateBatchReference({
299
314
  }
300
315
  }
301
316
 
302
- async function convertBatchItemResult(
303
- item: BatchV4ItemResult<LanguageModelV4GenerateResult>,
304
- ): Promise<TextBatchItemResult> {
317
+ async function convertBatchItemResult<TOOLS extends ToolSet>({
318
+ item,
319
+ tools,
320
+ }: {
321
+ item: BatchV4ItemResult<LanguageModelV4GenerateResult>;
322
+ tools: TOOLS | undefined;
323
+ }): Promise<TextBatchItemResult<TOOLS>> {
305
324
  if (item.status !== 'succeeded') {
306
325
  return item;
307
326
  }
@@ -309,22 +328,26 @@ async function convertBatchItemResult(
309
328
  return {
310
329
  id: item.id,
311
330
  status: 'succeeded',
312
- ...(await convertGenerateResult(item.result)),
331
+ ...(await convertGenerateResult({ result: item.result, tools })),
313
332
  };
314
333
  }
315
334
 
316
- async function convertGenerateResult(
317
- result: LanguageModelV4GenerateResult,
318
- ): Promise<TextBatchGenerationResult> {
335
+ async function convertGenerateResult<TOOLS extends ToolSet>({
336
+ result,
337
+ tools,
338
+ }: {
339
+ result: LanguageModelV4GenerateResult;
340
+ tools: TOOLS | undefined;
341
+ }): Promise<TextBatchGenerationResult<TOOLS>> {
319
342
  const toolCalls = await Promise.all(
320
343
  result.content
321
344
  .filter(
322
345
  (part): part is LanguageModelV4ToolCall => part.type === 'tool-call',
323
346
  )
324
347
  .map(toolCall =>
325
- parseToolCall<ToolSet>({
348
+ parseToolCall<TOOLS>({
326
349
  toolCall,
327
- tools: undefined,
350
+ tools,
328
351
  repairToolCall: undefined,
329
352
  refineToolInput: undefined,
330
353
  instructions: undefined,
@@ -332,18 +355,18 @@ async function convertGenerateResult(
332
355
  }),
333
356
  ),
334
357
  );
335
- const content = convertLanguageModelContent<ToolSet>({
358
+ const content = convertLanguageModelContent<TOOLS>({
336
359
  content: result.content,
337
360
  toolCalls,
338
361
  toolOutputs: [],
339
362
  toolApprovalRequests: [],
340
363
  toolApprovalResponses: [],
341
- tools: undefined,
364
+ tools,
342
365
  });
343
366
 
344
367
  return {
345
368
  content,
346
- text: content
369
+ text: result.content
347
370
  .filter(
348
371
  (part): part is Extract<typeof part, { type: 'text' }> =>
349
372
  part.type === 'text',
@@ -32,6 +32,7 @@ export { NoVideoGeneratedError } from './no-video-generated-error';
32
32
  export { NoSuchToolError } from './no-such-tool-error';
33
33
  export { StreamProviderError } from './stream-provider-error';
34
34
  export { ToolCallRepairError } from './tool-call-repair-error';
35
+ export { ToolChoiceViolationError } from './tool-choice-violation-error';
35
36
  export { UnsupportedModelVersionError } from './unsupported-model-version-error';
36
37
  export { UIMessageStreamError } from './ui-message-stream-error';
37
38
  export { InvalidDataContentError } from '../prompt/invalid-data-content-error';