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
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AISDKError,
|
|
3
|
+
type LanguageModelV4Content,
|
|
4
|
+
type LanguageModelV4ToolChoice,
|
|
5
|
+
} from '@ai-sdk/provider';
|
|
6
|
+
import type { FinishReason } from '../types/language-model';
|
|
7
|
+
|
|
8
|
+
const name = 'AI_ToolChoiceViolationError';
|
|
9
|
+
const marker = `vercel.ai.error.${name}`;
|
|
10
|
+
const symbol = Symbol.for(marker);
|
|
11
|
+
|
|
12
|
+
type EnforcedToolChoice = Extract<
|
|
13
|
+
LanguageModelV4ToolChoice,
|
|
14
|
+
{ type: 'required' } | { type: 'tool' }
|
|
15
|
+
>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Thrown when a model response does not satisfy an enforced tool choice.
|
|
19
|
+
*/
|
|
20
|
+
export class ToolChoiceViolationError extends AISDKError {
|
|
21
|
+
private readonly [symbol] = true; // used in isInstance
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The tool choice that the model response did not satisfy.
|
|
25
|
+
*/
|
|
26
|
+
readonly toolChoice: EnforcedToolChoice;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Reason why the model finished generating the response.
|
|
30
|
+
*/
|
|
31
|
+
readonly finishReason: FinishReason;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The provider that returned the response.
|
|
35
|
+
*/
|
|
36
|
+
readonly provider: string;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The model that returned the response.
|
|
40
|
+
*/
|
|
41
|
+
readonly modelId: string;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The normalized content returned by the model.
|
|
45
|
+
*
|
|
46
|
+
* This can be inspected to recover a tool call that the provider returned as
|
|
47
|
+
* text or reasoning instead of a structured tool call.
|
|
48
|
+
*/
|
|
49
|
+
readonly content: Array<LanguageModelV4Content>;
|
|
50
|
+
|
|
51
|
+
constructor({
|
|
52
|
+
toolChoice,
|
|
53
|
+
finishReason,
|
|
54
|
+
provider,
|
|
55
|
+
modelId,
|
|
56
|
+
content,
|
|
57
|
+
message = toolChoice.type === 'required'
|
|
58
|
+
? 'Model response did not contain a tool call even though tool choice was required.'
|
|
59
|
+
: `Model response did not contain a call to the required tool '${toolChoice.toolName}'.`,
|
|
60
|
+
}: {
|
|
61
|
+
toolChoice: EnforcedToolChoice;
|
|
62
|
+
finishReason: FinishReason;
|
|
63
|
+
provider: string;
|
|
64
|
+
modelId: string;
|
|
65
|
+
content: Array<LanguageModelV4Content>;
|
|
66
|
+
message?: string;
|
|
67
|
+
}) {
|
|
68
|
+
super({ name, message });
|
|
69
|
+
|
|
70
|
+
this.toolChoice = toolChoice;
|
|
71
|
+
this.finishReason = finishReason;
|
|
72
|
+
this.provider = provider;
|
|
73
|
+
this.modelId = modelId;
|
|
74
|
+
this.content = content;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static isInstance(error: unknown): error is ToolChoiceViolationError {
|
|
78
|
+
return AISDKError.hasMarker(error, marker);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
type ProviderOptions,
|
|
16
16
|
type ToolSet,
|
|
17
17
|
} from '@ai-sdk/provider-utils';
|
|
18
|
-
import { NoOutputGeneratedError } from '../error';
|
|
18
|
+
import { NoOutputGeneratedError, ToolChoiceViolationError } from '../error';
|
|
19
19
|
import { logWarnings } from '../logger/log-warnings';
|
|
20
20
|
import { resolveLanguageModel } from '../model/resolve-model';
|
|
21
21
|
import type { ModelMessage } from '../prompt';
|
|
@@ -1073,6 +1073,7 @@ export async function generateText<
|
|
|
1073
1073
|
}),
|
|
1074
1074
|
),
|
|
1075
1075
|
);
|
|
1076
|
+
|
|
1076
1077
|
const toolApprovalRequests: Record<
|
|
1077
1078
|
string,
|
|
1078
1079
|
ToolApprovalRequestOutput<TOOLS>
|
|
@@ -1132,6 +1133,29 @@ export async function generateText<
|
|
|
1132
1133
|
],
|
|
1133
1134
|
});
|
|
1134
1135
|
|
|
1136
|
+
const enforcedToolChoice =
|
|
1137
|
+
stepToolChoice.type === 'required' ||
|
|
1138
|
+
stepToolChoice.type === 'tool'
|
|
1139
|
+
? stepToolChoice
|
|
1140
|
+
: undefined;
|
|
1141
|
+
|
|
1142
|
+
if (
|
|
1143
|
+
enforcedToolChoice != null &&
|
|
1144
|
+
!stepToolCalls.some(
|
|
1145
|
+
toolCall =>
|
|
1146
|
+
enforcedToolChoice.type === 'required' ||
|
|
1147
|
+
toolCall.toolName === enforcedToolChoice.toolName,
|
|
1148
|
+
)
|
|
1149
|
+
) {
|
|
1150
|
+
throw new ToolChoiceViolationError({
|
|
1151
|
+
toolChoice: enforcedToolChoice,
|
|
1152
|
+
finishReason: currentModelResponse.finishReason.unified,
|
|
1153
|
+
provider: stepModel.provider,
|
|
1154
|
+
modelId: stepModel.modelId,
|
|
1155
|
+
content: currentModelResponse.content,
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1135
1159
|
// notify the tools that the tool calls are available:
|
|
1136
1160
|
for (const toolCall of stepToolCalls) {
|
|
1137
1161
|
if (toolCall.invalid) {
|
|
@@ -6,6 +6,18 @@ export interface UploadFileResult {
|
|
|
6
6
|
readonly providerReference: ProviderReference;
|
|
7
7
|
readonly mediaType?: string;
|
|
8
8
|
readonly filename?: string;
|
|
9
|
+
/**
|
|
10
|
+
* The size of the uploaded file in bytes, if reported by the provider.
|
|
11
|
+
*/
|
|
12
|
+
readonly byteSize?: number;
|
|
13
|
+
/**
|
|
14
|
+
* When the file was created, if reported by the provider.
|
|
15
|
+
*/
|
|
16
|
+
readonly createdAt?: Date;
|
|
17
|
+
/**
|
|
18
|
+
* When the provider will delete the file (retention expiry), if reported.
|
|
19
|
+
*/
|
|
20
|
+
readonly expiresAt?: Date;
|
|
9
21
|
readonly providerMetadata?: ProviderMetadata;
|
|
10
22
|
readonly warnings: Array<Warning>;
|
|
11
23
|
}
|
|
@@ -16,19 +16,31 @@ import type { UploadFileResult } from './upload-file-result';
|
|
|
16
16
|
* Uploads a file using a files API interface.
|
|
17
17
|
*
|
|
18
18
|
* @param api - The Files API interface to use for uploading.
|
|
19
|
-
* @param data - The file data to upload (tagged `{ type: 'data' | 'text' }`).
|
|
19
|
+
* @param data - The file data to upload (tagged `{ type: 'data' | 'text' | 'stream' }`).
|
|
20
|
+
* Stream data is sent without buffering by providers that support streaming
|
|
21
|
+
* uploads (others reject with `UnsupportedFunctionalityError`); the provider
|
|
22
|
+
* consumes the stream — any failed upload, including validation failures
|
|
23
|
+
* before a request is made, cancels it. Do not reuse it.
|
|
20
24
|
* @param mediaType - Optional IANA media type. Auto-detected from file bytes
|
|
21
|
-
* when omitted (falls back to `text/plain` for the `text` variant
|
|
22
|
-
*
|
|
25
|
+
* when omitted (falls back to `text/plain` for the `text` variant and
|
|
26
|
+
* `application/octet-stream` for the `stream` variant, which cannot be sniffed).
|
|
27
|
+
* @param filename - Optional filename for the uploaded file. Multipart-based
|
|
28
|
+
* providers default it to `"blob"` when omitted.
|
|
29
|
+
* @param abortSignal - Optional signal to cancel the upload.
|
|
30
|
+
* @param headers - Optional additional HTTP headers for the request.
|
|
23
31
|
* @param providerOptions - Additional provider-specific options.
|
|
24
32
|
*
|
|
25
|
-
* @returns A result object containing the provider reference
|
|
33
|
+
* @returns A result object containing the provider reference, optional
|
|
34
|
+
* metadata, and — when reported by the provider — `byteSize`, `createdAt`,
|
|
35
|
+
* and `expiresAt` (the provider-applied retention expiry).
|
|
26
36
|
*/
|
|
27
37
|
export async function uploadFile({
|
|
28
38
|
api,
|
|
29
39
|
data: dataArg,
|
|
30
40
|
mediaType: mediaTypeArg,
|
|
31
41
|
filename,
|
|
42
|
+
abortSignal,
|
|
43
|
+
headers,
|
|
32
44
|
providerOptions,
|
|
33
45
|
}: {
|
|
34
46
|
/**
|
|
@@ -54,35 +66,55 @@ export async function uploadFile({
|
|
|
54
66
|
? { type: 'data', data: dataArg }
|
|
55
67
|
: dataArg;
|
|
56
68
|
|
|
69
|
+
// stream data cannot be sniffed without consuming it
|
|
57
70
|
const mediaType =
|
|
58
71
|
mediaTypeArg ??
|
|
59
72
|
(data.type === 'text'
|
|
60
73
|
? 'text/plain'
|
|
61
|
-
:
|
|
62
|
-
|
|
74
|
+
: data.type === 'stream'
|
|
75
|
+
? 'application/octet-stream'
|
|
76
|
+
: (detectMediaType({ data: data.data }) ??
|
|
77
|
+
(isLikelyText(data.data)
|
|
78
|
+
? 'text/plain'
|
|
79
|
+
: 'application/octet-stream')));
|
|
63
80
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
? api
|
|
69
|
-
:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
81
|
+
let result;
|
|
82
|
+
try {
|
|
83
|
+
const filesApi: FilesV4 =
|
|
84
|
+
'uploadFile' in api
|
|
85
|
+
? api
|
|
86
|
+
: typeof api.files === 'function'
|
|
87
|
+
? api.files()
|
|
88
|
+
: (() => {
|
|
89
|
+
throw new Error(
|
|
90
|
+
'The provider does not support file uploads. Make sure it exposes a files() method.',
|
|
91
|
+
);
|
|
92
|
+
})();
|
|
74
93
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
94
|
+
result = await filesApi.uploadFile({
|
|
95
|
+
data,
|
|
96
|
+
mediaType,
|
|
97
|
+
filename,
|
|
98
|
+
abortSignal,
|
|
99
|
+
headers,
|
|
100
|
+
providerOptions,
|
|
101
|
+
});
|
|
102
|
+
} catch (error) {
|
|
103
|
+
// ownership guarantee: a failed upload releases the stream, even when
|
|
104
|
+
// the provider rejected before (or without) consuming it
|
|
105
|
+
if (data.type === 'stream') {
|
|
106
|
+
await data.stream.cancel(error).catch(() => {});
|
|
107
|
+
}
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
81
110
|
|
|
82
111
|
return new DefaultUploadFileResult({
|
|
83
112
|
providerReference: result.providerReference,
|
|
84
113
|
mediaType: result.mediaType,
|
|
85
114
|
filename: result.filename,
|
|
115
|
+
byteSize: result.byteSize,
|
|
116
|
+
createdAt: result.createdAt,
|
|
117
|
+
expiresAt: result.expiresAt,
|
|
86
118
|
providerMetadata: result.providerMetadata,
|
|
87
119
|
warnings: result.warnings,
|
|
88
120
|
});
|
|
@@ -92,6 +124,9 @@ class DefaultUploadFileResult implements UploadFileResult {
|
|
|
92
124
|
readonly providerReference: ProviderReference;
|
|
93
125
|
readonly mediaType?: string;
|
|
94
126
|
readonly filename?: string;
|
|
127
|
+
readonly byteSize?: number;
|
|
128
|
+
readonly createdAt?: Date;
|
|
129
|
+
readonly expiresAt?: Date;
|
|
95
130
|
readonly providerMetadata?: ProviderMetadata;
|
|
96
131
|
readonly warnings: Array<Warning>;
|
|
97
132
|
|
|
@@ -99,12 +134,18 @@ class DefaultUploadFileResult implements UploadFileResult {
|
|
|
99
134
|
providerReference: ProviderReference;
|
|
100
135
|
mediaType?: string;
|
|
101
136
|
filename?: string;
|
|
137
|
+
byteSize?: number;
|
|
138
|
+
createdAt?: Date;
|
|
139
|
+
expiresAt?: Date;
|
|
102
140
|
providerMetadata?: ProviderMetadata;
|
|
103
141
|
warnings: Array<Warning>;
|
|
104
142
|
}) {
|
|
105
143
|
this.providerReference = options.providerReference;
|
|
106
144
|
this.mediaType = options.mediaType;
|
|
107
145
|
this.filename = options.filename;
|
|
146
|
+
this.byteSize = options.byteSize;
|
|
147
|
+
this.createdAt = options.createdAt;
|
|
148
|
+
this.expiresAt = options.expiresAt;
|
|
108
149
|
this.providerMetadata = options.providerMetadata;
|
|
109
150
|
this.warnings = options.warnings;
|
|
110
151
|
}
|