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.
- package/CHANGELOG.md +17 -0
- package/dist/index.d.ts +143 -49
- package/dist/index.js +543 -462
- package/dist/index.js.map +1 -1
- package/dist/internal/index.js +1 -1
- package/dist/internal/index.js.map +1 -1
- package/docs/03-agents/07-workflow-agent.mdx +9 -4
- package/docs/03-ai-sdk-core/15-tools-and-tool-calling.mdx +2 -1
- package/docs/03-ai-sdk-core/39-file-uploads.mdx +25 -0
- package/docs/07-reference/01-ai-sdk-core/14-upload-file.mdx +37 -4
- package/docs/07-reference/04-ai-sdk-workflow/01-workflow-agent.mdx +34 -6
- package/docs/07-reference/05-ai-sdk-errors/ai-tool-choice-violation-error.mdx +38 -0
- package/docs/07-reference/05-ai-sdk-errors/index.mdx +1 -0
- package/package.json +12 -12
- package/src/batch/batch-types.ts +47 -7
- package/src/batch/batch.ts +43 -20
- package/src/error/index.ts +1 -0
- package/src/error/tool-choice-violation-error.ts +80 -0
- package/src/generate-text/generate-text.ts +25 -1
- package/src/upload-file/upload-file-result.ts +12 -0
- package/src/upload-file/upload-file.ts +63 -22
|
@@ -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
|
-
|
|
591
|
-
console.log(
|
|
590
|
+
onStart({ messages }) {
|
|
591
|
+
console.log(`Agent started with ${messages.length} messages`);
|
|
592
592
|
},
|
|
593
593
|
|
|
594
|
-
|
|
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 `
|
|
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
|
|
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 `
|
|
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:
|
|
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: '
|
|
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).
|
|
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: '
|
|
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).
|
|
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
|
-
'
|
|
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
|
-
'
|
|
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.
|
|
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.
|
|
46
|
-
"@ai-sdk/provider": "4.0.
|
|
47
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
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.
|
|
51
|
-
"@ai-sdk/deepseek": "3.0.
|
|
52
|
-
"@ai-sdk/google": "4.0.
|
|
53
|
-
"@ai-sdk/groq": "4.0.
|
|
54
|
-
"@ai-sdk/huggingface": "2.0.
|
|
55
|
-
"@ai-sdk/moonshotai": "3.0.
|
|
56
|
-
"@ai-sdk/openai": "4.0.
|
|
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.
|
|
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",
|
package/src/batch/batch-types.ts
CHANGED
|
@@ -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 {
|
|
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<
|
|
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
|
})
|
package/src/batch/batch.ts
CHANGED
|
@@ -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
|
|
304
|
-
|
|
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
|
|
318
|
-
|
|
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<
|
|
348
|
+
parseToolCall<TOOLS>({
|
|
326
349
|
toolCall,
|
|
327
|
-
tools
|
|
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<
|
|
358
|
+
const content = convertLanguageModelContent<TOOLS>({
|
|
336
359
|
content: result.content,
|
|
337
360
|
toolCalls,
|
|
338
361
|
toolOutputs: [],
|
|
339
362
|
toolApprovalRequests: [],
|
|
340
363
|
toolApprovalResponses: [],
|
|
341
|
-
tools
|
|
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',
|
package/src/error/index.ts
CHANGED
|
@@ -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';
|