@ai-sdk/provider-utils 5.0.0-beta.28 → 5.0.0-beta.29
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 +11 -0
- package/dist/index.d.ts +967 -843
- package/dist/index.js +340 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/add-additional-properties-to-json-schema.ts +1 -1
- package/src/convert-image-model-file-to-data-uri.ts +1 -1
- package/src/convert-inline-file-data-to-uint8-array.ts +30 -0
- package/src/create-tool-name-mapping.ts +1 -1
- package/src/detect-media-type.ts +312 -0
- package/src/get-from-api.ts +2 -2
- package/src/index.ts +8 -0
- package/src/inject-json-instruction.ts +1 -1
- package/src/is-buffer.ts +9 -0
- package/src/is-json-serializable.ts +1 -1
- package/src/is-provider-reference.ts +11 -8
- package/src/is-url-supported.ts +17 -2
- package/src/map-reasoning-to-provider.ts +4 -1
- package/src/parse-json-event-stream.ts +3 -3
- package/src/parse-json.ts +2 -2
- package/src/parse-provider-options.ts +1 -1
- package/src/post-to-api.ts +2 -2
- package/src/provider-defined-tool-factory.ts +10 -9
- package/src/provider-executed-tool-factory.ts +6 -7
- package/src/resolve-full-media-type.ts +49 -0
- package/src/resolve-provider-reference.ts +1 -2
- package/src/resolve.ts +1 -1
- package/src/response-handler.ts +2 -2
- package/src/schema.ts +6 -3
- package/src/serialize-model-options.ts +2 -2
- package/src/streaming-tool-call-tracker.ts +2 -2
- package/src/to-json-schema/zod3-to-json-schema/options.ts +3 -3
- package/src/to-json-schema/zod3-to-json-schema/parse-def.ts +3 -3
- package/src/to-json-schema/zod3-to-json-schema/parse-types.ts +22 -22
- package/src/to-json-schema/zod3-to-json-schema/parsers/array.ts +3 -3
- package/src/to-json-schema/zod3-to-json-schema/parsers/bigint.ts +1 -1
- package/src/to-json-schema/zod3-to-json-schema/parsers/branded.ts +2 -2
- package/src/to-json-schema/zod3-to-json-schema/parsers/catch.ts +2 -2
- package/src/to-json-schema/zod3-to-json-schema/parsers/date.ts +3 -3
- package/src/to-json-schema/zod3-to-json-schema/parsers/default.ts +3 -3
- package/src/to-json-schema/zod3-to-json-schema/parsers/effects.ts +3 -3
- package/src/to-json-schema/zod3-to-json-schema/parsers/enum.ts +1 -1
- package/src/to-json-schema/zod3-to-json-schema/parsers/intersection.ts +4 -4
- package/src/to-json-schema/zod3-to-json-schema/parsers/literal.ts +1 -1
- package/src/to-json-schema/zod3-to-json-schema/parsers/map.ts +4 -5
- package/src/to-json-schema/zod3-to-json-schema/parsers/native-enum.ts +1 -1
- package/src/to-json-schema/zod3-to-json-schema/parsers/never.ts +1 -2
- package/src/to-json-schema/zod3-to-json-schema/parsers/nullable.ts +4 -4
- package/src/to-json-schema/zod3-to-json-schema/parsers/number.ts +1 -1
- package/src/to-json-schema/zod3-to-json-schema/parsers/object.ts +3 -3
- package/src/to-json-schema/zod3-to-json-schema/parsers/optional.ts +3 -3
- package/src/to-json-schema/zod3-to-json-schema/parsers/pipeline.ts +4 -4
- package/src/to-json-schema/zod3-to-json-schema/parsers/promise.ts +3 -3
- package/src/to-json-schema/zod3-to-json-schema/parsers/readonly.ts +2 -2
- package/src/to-json-schema/zod3-to-json-schema/parsers/record.ts +7 -8
- package/src/to-json-schema/zod3-to-json-schema/parsers/set.ts +3 -3
- package/src/to-json-schema/zod3-to-json-schema/parsers/string.ts +2 -2
- package/src/to-json-schema/zod3-to-json-schema/parsers/tuple.ts +3 -3
- package/src/to-json-schema/zod3-to-json-schema/parsers/undefined.ts +1 -2
- package/src/to-json-schema/zod3-to-json-schema/parsers/union.ts +3 -3
- package/src/to-json-schema/zod3-to-json-schema/parsers/unknown.ts +1 -2
- package/src/to-json-schema/zod3-to-json-schema/refs.ts +3 -3
- package/src/to-json-schema/zod3-to-json-schema/select-parser.ts +2 -2
- package/src/to-json-schema/zod3-to-json-schema/zod3-to-json-schema.ts +3 -3
- package/src/types/assistant-model-message.ts +3 -3
- package/src/types/content-part.ts +37 -14
- package/src/types/executable-tool.ts +1 -1
- package/src/types/execute-tool.ts +6 -5
- package/src/types/file-data.ts +48 -0
- package/src/types/index.ts +16 -3
- package/src/types/infer-tool-context.ts +1 -1
- package/src/types/model-message.ts +4 -4
- package/src/types/never-optional.ts +7 -0
- package/src/types/provider-options.ts +1 -1
- package/src/types/provider-reference.ts +1 -1
- package/src/types/system-model-message.ts +1 -1
- package/src/types/tool-execute-function.ts +50 -0
- package/src/types/tool-model-message.ts +3 -3
- package/src/types/tool-needs-approval-function.ts +39 -0
- package/src/types/tool.ts +200 -271
- package/src/types/user-model-message.ts +2 -2
- package/src/validate-types.ts +5 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/provider-utils",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.29",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"@standard-schema/spec": "^1.1.0",
|
|
36
36
|
"@workflow/serde": "4.1.0",
|
|
37
37
|
"eventsource-parser": "^3.0.8",
|
|
38
|
-
"@ai-sdk/provider": "4.0.0-beta.
|
|
38
|
+
"@ai-sdk/provider": "4.0.0-beta.14"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/node": "20.17.24",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { JSONSchema7, JSONSchema7Definition } from '@ai-sdk/provider';
|
|
1
|
+
import type { JSONSchema7, JSONSchema7Definition } from '@ai-sdk/provider';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Recursively adds additionalProperties: false to the JSON schema. This is necessary because some providers (e.g. OpenAI) do not support additionalProperties: true.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { FilePart } from './types/content-part';
|
|
2
|
+
import { convertBase64ToUint8Array } from './uint8-utils';
|
|
3
|
+
|
|
4
|
+
type InlineFileData = Extract<
|
|
5
|
+
FilePart['data'],
|
|
6
|
+
{ type: 'data' } | { type: 'text' }
|
|
7
|
+
>;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Converts inline file data (a tagged `data` or `text` shape) into raw bytes.
|
|
11
|
+
*
|
|
12
|
+
* - `{ type: 'text', text }` → UTF-8 encoded bytes
|
|
13
|
+
* - `{ type: 'data', data: Uint8Array | Buffer }` → returned as-is
|
|
14
|
+
* - `{ type: 'data', data: ArrayBuffer }` → wrapped in a `Uint8Array`
|
|
15
|
+
* - `{ type: 'data', data: string }` → decoded as base64
|
|
16
|
+
*/
|
|
17
|
+
export function convertInlineFileDataToUint8Array(
|
|
18
|
+
data: InlineFileData,
|
|
19
|
+
): Uint8Array {
|
|
20
|
+
if (data.type === 'text') {
|
|
21
|
+
return new TextEncoder().encode(data.text);
|
|
22
|
+
}
|
|
23
|
+
if (data.data instanceof Uint8Array) {
|
|
24
|
+
return data.data;
|
|
25
|
+
}
|
|
26
|
+
if (data.data instanceof ArrayBuffer) {
|
|
27
|
+
return new Uint8Array(data.data);
|
|
28
|
+
}
|
|
29
|
+
return convertBase64ToUint8Array(data.data);
|
|
30
|
+
}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { convertBase64ToUint8Array } from './uint8-utils';
|
|
2
|
+
|
|
3
|
+
const imageMediaTypeSignatures = [
|
|
4
|
+
{
|
|
5
|
+
mediaType: 'image/gif' as const,
|
|
6
|
+
bytesPrefix: [0x47, 0x49, 0x46], // GIF
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
mediaType: 'image/png' as const,
|
|
10
|
+
bytesPrefix: [0x89, 0x50, 0x4e, 0x47], // PNG
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
mediaType: 'image/jpeg' as const,
|
|
14
|
+
bytesPrefix: [0xff, 0xd8], // JPEG
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
mediaType: 'image/webp' as const,
|
|
18
|
+
bytesPrefix: [
|
|
19
|
+
0x52,
|
|
20
|
+
0x49,
|
|
21
|
+
0x46,
|
|
22
|
+
0x46, // "RIFF"
|
|
23
|
+
null,
|
|
24
|
+
null,
|
|
25
|
+
null,
|
|
26
|
+
null, // file size (variable)
|
|
27
|
+
0x57,
|
|
28
|
+
0x45,
|
|
29
|
+
0x42,
|
|
30
|
+
0x50, // "WEBP"
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
mediaType: 'image/bmp' as const,
|
|
35
|
+
bytesPrefix: [0x42, 0x4d],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
mediaType: 'image/tiff' as const,
|
|
39
|
+
bytesPrefix: [0x49, 0x49, 0x2a, 0x00],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
mediaType: 'image/tiff' as const,
|
|
43
|
+
bytesPrefix: [0x4d, 0x4d, 0x00, 0x2a],
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
mediaType: 'image/avif' as const,
|
|
47
|
+
bytesPrefix: [
|
|
48
|
+
0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70, 0x61, 0x76, 0x69, 0x66,
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
mediaType: 'image/heic' as const,
|
|
53
|
+
bytesPrefix: [
|
|
54
|
+
0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70, 0x68, 0x65, 0x69, 0x63,
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
] as const;
|
|
58
|
+
|
|
59
|
+
const documentMediaTypeSignatures = [
|
|
60
|
+
{
|
|
61
|
+
mediaType: 'application/pdf' as const,
|
|
62
|
+
bytesPrefix: [0x25, 0x50, 0x44, 0x46], // %PDF
|
|
63
|
+
},
|
|
64
|
+
] as const;
|
|
65
|
+
|
|
66
|
+
const audioMediaTypeSignatures = [
|
|
67
|
+
{
|
|
68
|
+
mediaType: 'audio/mpeg' as const,
|
|
69
|
+
bytesPrefix: [0xff, 0xfb],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
mediaType: 'audio/mpeg' as const,
|
|
73
|
+
bytesPrefix: [0xff, 0xfa],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
mediaType: 'audio/mpeg' as const,
|
|
77
|
+
bytesPrefix: [0xff, 0xf3],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
mediaType: 'audio/mpeg' as const,
|
|
81
|
+
bytesPrefix: [0xff, 0xf2],
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
mediaType: 'audio/mpeg' as const,
|
|
85
|
+
bytesPrefix: [0xff, 0xe3],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
mediaType: 'audio/mpeg' as const,
|
|
89
|
+
bytesPrefix: [0xff, 0xe2],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
mediaType: 'audio/wav' as const,
|
|
93
|
+
bytesPrefix: [
|
|
94
|
+
0x52, // R
|
|
95
|
+
0x49, // I
|
|
96
|
+
0x46, // F
|
|
97
|
+
0x46, // F
|
|
98
|
+
null,
|
|
99
|
+
null,
|
|
100
|
+
null,
|
|
101
|
+
null,
|
|
102
|
+
0x57, // W
|
|
103
|
+
0x41, // A
|
|
104
|
+
0x56, // V
|
|
105
|
+
0x45, // E
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
mediaType: 'audio/ogg' as const,
|
|
110
|
+
bytesPrefix: [0x4f, 0x67, 0x67, 0x53],
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
mediaType: 'audio/flac' as const,
|
|
114
|
+
bytesPrefix: [0x66, 0x4c, 0x61, 0x43],
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
mediaType: 'audio/aac' as const,
|
|
118
|
+
bytesPrefix: [0x40, 0x15, 0x00, 0x00],
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
mediaType: 'audio/mp4' as const,
|
|
122
|
+
bytesPrefix: [0x66, 0x74, 0x79, 0x70],
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
mediaType: 'audio/webm',
|
|
126
|
+
bytesPrefix: [0x1a, 0x45, 0xdf, 0xa3],
|
|
127
|
+
},
|
|
128
|
+
] as const;
|
|
129
|
+
|
|
130
|
+
const videoMediaTypeSignatures = [
|
|
131
|
+
{
|
|
132
|
+
mediaType: 'video/mp4' as const,
|
|
133
|
+
bytesPrefix: [
|
|
134
|
+
0x00,
|
|
135
|
+
0x00,
|
|
136
|
+
0x00,
|
|
137
|
+
null,
|
|
138
|
+
0x66,
|
|
139
|
+
0x74,
|
|
140
|
+
0x79,
|
|
141
|
+
0x70, // ftyp
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
mediaType: 'video/webm' as const,
|
|
146
|
+
bytesPrefix: [0x1a, 0x45, 0xdf, 0xa3], // EBML
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
mediaType: 'video/quicktime' as const,
|
|
150
|
+
bytesPrefix: [
|
|
151
|
+
0x00,
|
|
152
|
+
0x00,
|
|
153
|
+
0x00,
|
|
154
|
+
0x14,
|
|
155
|
+
0x66,
|
|
156
|
+
0x74,
|
|
157
|
+
0x79,
|
|
158
|
+
0x70,
|
|
159
|
+
0x71,
|
|
160
|
+
0x74, // ftypqt
|
|
161
|
+
],
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
mediaType: 'video/x-msvideo' as const,
|
|
165
|
+
bytesPrefix: [0x52, 0x49, 0x46, 0x46], // RIFF (AVI)
|
|
166
|
+
},
|
|
167
|
+
] as const;
|
|
168
|
+
|
|
169
|
+
const stripID3 = (data: Uint8Array | string) => {
|
|
170
|
+
const bytes =
|
|
171
|
+
typeof data === 'string' ? convertBase64ToUint8Array(data) : data;
|
|
172
|
+
const id3Size =
|
|
173
|
+
((bytes[6] & 0x7f) << 21) |
|
|
174
|
+
((bytes[7] & 0x7f) << 14) |
|
|
175
|
+
((bytes[8] & 0x7f) << 7) |
|
|
176
|
+
(bytes[9] & 0x7f);
|
|
177
|
+
|
|
178
|
+
// The raw MP3 starts here
|
|
179
|
+
return bytes.slice(id3Size + 10);
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
function stripID3TagsIfPresent(data: Uint8Array | string): Uint8Array | string {
|
|
183
|
+
const hasId3 =
|
|
184
|
+
(typeof data === 'string' && data.startsWith('SUQz')) ||
|
|
185
|
+
(typeof data !== 'string' &&
|
|
186
|
+
data.length > 10 &&
|
|
187
|
+
data[0] === 0x49 && // 'I'
|
|
188
|
+
data[1] === 0x44 && // 'D'
|
|
189
|
+
data[2] === 0x33); // '3'
|
|
190
|
+
|
|
191
|
+
return hasId3 ? stripID3(data) : data;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
type MediaTypeSignatures = ReadonlyArray<{
|
|
195
|
+
readonly mediaType: string;
|
|
196
|
+
readonly bytesPrefix: ReadonlyArray<number | null>;
|
|
197
|
+
}>;
|
|
198
|
+
|
|
199
|
+
function detectMediaTypeBySignatures<T extends MediaTypeSignatures>({
|
|
200
|
+
data,
|
|
201
|
+
signatures,
|
|
202
|
+
}: {
|
|
203
|
+
data: Uint8Array | string;
|
|
204
|
+
signatures: T;
|
|
205
|
+
}): T[number]['mediaType'] | undefined {
|
|
206
|
+
const processedData = stripID3TagsIfPresent(data);
|
|
207
|
+
|
|
208
|
+
// Convert the first ~18 bytes (24 base64 chars) for consistent detection logic:
|
|
209
|
+
const bytes =
|
|
210
|
+
typeof processedData === 'string'
|
|
211
|
+
? convertBase64ToUint8Array(
|
|
212
|
+
processedData.substring(0, Math.min(processedData.length, 24)),
|
|
213
|
+
)
|
|
214
|
+
: processedData;
|
|
215
|
+
|
|
216
|
+
for (const signature of signatures) {
|
|
217
|
+
if (
|
|
218
|
+
bytes.length >= signature.bytesPrefix.length &&
|
|
219
|
+
signature.bytesPrefix.every(
|
|
220
|
+
(byte, index) => byte === null || bytes[index] === byte,
|
|
221
|
+
)
|
|
222
|
+
) {
|
|
223
|
+
return signature.mediaType;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return undefined;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const topLevelSignatureTables = {
|
|
231
|
+
image: imageMediaTypeSignatures,
|
|
232
|
+
audio: audioMediaTypeSignatures,
|
|
233
|
+
video: videoMediaTypeSignatures,
|
|
234
|
+
application: documentMediaTypeSignatures,
|
|
235
|
+
} as const;
|
|
236
|
+
|
|
237
|
+
type TopLevelMediaType = keyof typeof topLevelSignatureTables;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Detect the IANA media type of a file from its raw bytes or base64 string.
|
|
241
|
+
*
|
|
242
|
+
* - When `topLevelType` is omitted, every known signature is considered
|
|
243
|
+
* (image, audio, video, and application). Returns `undefined` when the
|
|
244
|
+
* bytes do not match any known signature.
|
|
245
|
+
* - When `topLevelType` is provided, only signatures for that top-level
|
|
246
|
+
* segment are considered. Returns `undefined` for unsupported segments
|
|
247
|
+
* (e.g. `"text"`) or when no signature matches.
|
|
248
|
+
*/
|
|
249
|
+
export function detectMediaType({
|
|
250
|
+
data,
|
|
251
|
+
topLevelType,
|
|
252
|
+
}: {
|
|
253
|
+
data: Uint8Array | string;
|
|
254
|
+
topLevelType?: string;
|
|
255
|
+
}): string | undefined {
|
|
256
|
+
if (topLevelType === undefined) {
|
|
257
|
+
return detectMediaTypeBySignatures({
|
|
258
|
+
data,
|
|
259
|
+
signatures: [
|
|
260
|
+
...imageMediaTypeSignatures,
|
|
261
|
+
...documentMediaTypeSignatures,
|
|
262
|
+
...audioMediaTypeSignatures,
|
|
263
|
+
...videoMediaTypeSignatures,
|
|
264
|
+
],
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const signatures = topLevelSignatureTables[topLevelType as TopLevelMediaType];
|
|
269
|
+
|
|
270
|
+
if (signatures === undefined) {
|
|
271
|
+
return undefined;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return detectMediaTypeBySignatures({ data, signatures });
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Returns the top-level segment of a media type (the portion before `/`).
|
|
279
|
+
*
|
|
280
|
+
* Examples:
|
|
281
|
+
* - `"image/png"` -> `"image"`
|
|
282
|
+
* - `"image/*"` -> `"image"`
|
|
283
|
+
* - `"image"` -> `"image"`
|
|
284
|
+
* - `"image/"` -> `"image"`
|
|
285
|
+
* - `""` -> `""`
|
|
286
|
+
* - `"/"` -> `""`
|
|
287
|
+
*/
|
|
288
|
+
export function getTopLevelMediaType(mediaType: string): string {
|
|
289
|
+
const slashIndex = mediaType.indexOf('/');
|
|
290
|
+
return slashIndex === -1 ? mediaType : mediaType.substring(0, slashIndex);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Returns `true` only when the given media type has a non-empty, non-wildcard
|
|
295
|
+
* subtype (i.e. matches the form `type/subtype`, and `subtype` is not `*`).
|
|
296
|
+
*
|
|
297
|
+
* Examples:
|
|
298
|
+
* - `"image/png"` -> `true`
|
|
299
|
+
* - `"image/*"` -> `false`
|
|
300
|
+
* - `"image"` -> `false`
|
|
301
|
+
* - `"image/"` -> `false`
|
|
302
|
+
* - `""` -> `false`
|
|
303
|
+
* - `"/"` -> `false`
|
|
304
|
+
*/
|
|
305
|
+
export function isFullMediaType(mediaType: string): boolean {
|
|
306
|
+
const slashIndex = mediaType.indexOf('/');
|
|
307
|
+
if (slashIndex === -1) {
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
const subtype = mediaType.substring(slashIndex + 1);
|
|
311
|
+
return subtype.length > 0 && subtype !== '*';
|
|
312
|
+
}
|
package/src/get-from-api.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { APICallError } from '@ai-sdk/provider';
|
|
2
2
|
import { extractResponseHeaders } from './extract-response-headers';
|
|
3
|
-
import { FetchFunction } from './fetch-function';
|
|
3
|
+
import type { FetchFunction } from './fetch-function';
|
|
4
4
|
import { handleFetchError } from './handle-fetch-error';
|
|
5
5
|
import { isAbortError } from './is-abort-error';
|
|
6
|
-
import { ResponseHandler } from './response-handler';
|
|
6
|
+
import type { ResponseHandler } from './response-handler';
|
|
7
7
|
import { getRuntimeEnvironmentUserAgent } from './get-runtime-environment-user-agent';
|
|
8
8
|
import { withUserAgentSuffix } from './with-user-agent-suffix';
|
|
9
9
|
import { VERSION } from './version';
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { asArray } from './as-array';
|
|
|
2
2
|
export type { Arrayable } from './as-array';
|
|
3
3
|
export * from './combine-headers';
|
|
4
4
|
export { convertAsyncIteratorToReadableStream } from './convert-async-iterator-to-readable-stream';
|
|
5
|
+
export { convertInlineFileDataToUint8Array } from './convert-inline-file-data-to-uint8-array';
|
|
5
6
|
export { convertImageModelFileToDataUri } from './convert-image-model-file-to-data-uri';
|
|
6
7
|
export { convertToFormData } from './convert-to-form-data';
|
|
7
8
|
export {
|
|
@@ -10,6 +11,11 @@ export {
|
|
|
10
11
|
} from './create-tool-name-mapping';
|
|
11
12
|
export * from './delay';
|
|
12
13
|
export { DelayedPromise } from './delayed-promise';
|
|
14
|
+
export {
|
|
15
|
+
detectMediaType,
|
|
16
|
+
getTopLevelMediaType,
|
|
17
|
+
isFullMediaType,
|
|
18
|
+
} from './detect-media-type';
|
|
13
19
|
export { downloadBlob } from './download-blob';
|
|
14
20
|
export { DownloadError } from './download-error';
|
|
15
21
|
export * from './extract-response-headers';
|
|
@@ -22,6 +28,7 @@ export { getRuntimeEnvironmentUserAgent } from './get-runtime-environment-user-a
|
|
|
22
28
|
export type { HasRequiredKey } from './has-required-key';
|
|
23
29
|
export { injectJsonInstructionIntoMessages } from './inject-json-instruction';
|
|
24
30
|
export * from './is-abort-error';
|
|
31
|
+
export { isBuffer } from './is-buffer';
|
|
25
32
|
export { isNonNullable } from './is-non-nullable';
|
|
26
33
|
export { isProviderReference } from './is-provider-reference';
|
|
27
34
|
export { isUrlSupported } from './is-url-supported';
|
|
@@ -56,6 +63,7 @@ export {
|
|
|
56
63
|
} from './read-response-with-size-limit';
|
|
57
64
|
export * from './remove-undefined-entries';
|
|
58
65
|
export * from './resolve';
|
|
66
|
+
export { resolveFullMediaType } from './resolve-full-media-type';
|
|
59
67
|
export { resolveProviderReference } from './resolve-provider-reference';
|
|
60
68
|
export * from './response-handler';
|
|
61
69
|
export {
|
package/src/is-buffer.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-guard for Node.js `Buffer` instances.
|
|
3
|
+
*
|
|
4
|
+
* Uses optional chaining on `globalThis.Buffer` so it returns `false` in
|
|
5
|
+
* runtimes where `Buffer` is not available (e.g. CloudFlare Workers).
|
|
6
|
+
*/
|
|
7
|
+
export function isBuffer(value: unknown): value is Buffer {
|
|
8
|
+
return globalThis.Buffer?.isBuffer(value) ?? false;
|
|
9
|
+
}
|
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
SharedV4ProviderReference,
|
|
4
|
-
} from '@ai-sdk/provider';
|
|
1
|
+
import type { SharedV4ProviderReference } from '@ai-sdk/provider';
|
|
2
|
+
import { isBuffer } from './is-buffer';
|
|
5
3
|
|
|
6
4
|
/**
|
|
7
|
-
* Checks whether
|
|
8
|
-
*
|
|
5
|
+
* Checks whether a value is a provider reference (a mapping of provider names
|
|
6
|
+
* to provider-specific identifiers) as opposed to raw bytes, a URL, or a
|
|
7
|
+
* tagged `{ type: ... }` object.
|
|
9
8
|
*/
|
|
10
9
|
export function isProviderReference(
|
|
11
|
-
data:
|
|
10
|
+
data: unknown,
|
|
12
11
|
): data is SharedV4ProviderReference {
|
|
13
12
|
return (
|
|
14
13
|
typeof data === 'object' &&
|
|
14
|
+
data !== null &&
|
|
15
15
|
!(data instanceof Uint8Array) &&
|
|
16
|
-
!(data instanceof URL)
|
|
16
|
+
!(data instanceof URL) &&
|
|
17
|
+
!(data instanceof ArrayBuffer) &&
|
|
18
|
+
!isBuffer(data) &&
|
|
19
|
+
!('type' in data)
|
|
17
20
|
);
|
|
18
21
|
}
|
package/src/is-url-supported.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Checks if the given URL is supported natively by the model.
|
|
3
3
|
*
|
|
4
|
-
* @param mediaType - The media type of the URL. Case-sensitive.
|
|
4
|
+
* @param mediaType - The media type of the URL. Case-sensitive. May be a full
|
|
5
|
+
* `type/subtype`, a wildcard `type/*`, or just the
|
|
6
|
+
* top-level segment (e.g. `image`).
|
|
5
7
|
* @param url - The URL to check.
|
|
6
8
|
* @param supportedUrls - A record where keys are case-sensitive media types (or '*')
|
|
7
9
|
* and values are arrays of RegExp patterns for URLs.
|
|
@@ -22,6 +24,8 @@ export function isUrlSupported({
|
|
|
22
24
|
url = url.toLowerCase();
|
|
23
25
|
mediaType = mediaType.toLowerCase();
|
|
24
26
|
|
|
27
|
+
const isTopLevelOnly = !mediaType.includes('/');
|
|
28
|
+
|
|
25
29
|
return (
|
|
26
30
|
Object.entries(supportedUrls)
|
|
27
31
|
// standardize supported url map into lowercase prefixes:
|
|
@@ -32,7 +36,18 @@ export function isUrlSupported({
|
|
|
32
36
|
: { mediaTypePrefix: mediaType.replace(/\*/, ''), regexes: value };
|
|
33
37
|
})
|
|
34
38
|
// gather all regexp pattern from matched media type prefixes:
|
|
35
|
-
.filter(({ mediaTypePrefix }) =>
|
|
39
|
+
.filter(({ mediaTypePrefix }) => {
|
|
40
|
+
if (mediaTypePrefix === '') {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
// For a top-level-only media type (e.g. `image`), we cannot determine
|
|
44
|
+
// whether a specific subtype (e.g. `image/png`) would apply, so we
|
|
45
|
+
// only match the corresponding `type/*` prefix exactly.
|
|
46
|
+
if (isTopLevelOnly) {
|
|
47
|
+
return `${mediaType}/` === mediaTypePrefix;
|
|
48
|
+
}
|
|
49
|
+
return mediaType.startsWith(mediaTypePrefix);
|
|
50
|
+
})
|
|
36
51
|
.flatMap(({ regexes }) => regexes)
|
|
37
52
|
// check if any pattern matches the url:
|
|
38
53
|
.some(pattern => pattern.test(url))
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
-
EventSourceMessage,
|
|
3
2
|
EventSourceParserStream,
|
|
3
|
+
type EventSourceMessage,
|
|
4
4
|
} from 'eventsource-parser/stream';
|
|
5
|
-
import {
|
|
6
|
-
import { FlexibleSchema } from './schema';
|
|
5
|
+
import { safeParseJSON, type ParseResult } from './parse-json';
|
|
6
|
+
import type { FlexibleSchema } from './schema';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Parses a JSON event stream into a stream of parsed JSON objects.
|
package/src/parse-json.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
JSONParseError,
|
|
3
|
-
JSONValue,
|
|
4
3
|
TypeValidationError,
|
|
4
|
+
type JSONValue,
|
|
5
5
|
} from '@ai-sdk/provider';
|
|
6
6
|
import { secureJsonParse } from './secure-json-parse';
|
|
7
7
|
import { safeValidateTypes, validateTypes } from './validate-types';
|
|
8
|
-
import { FlexibleSchema } from './schema';
|
|
8
|
+
import type { FlexibleSchema } from './schema';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Parses a JSON string into an unknown object.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { InvalidArgumentError } from '@ai-sdk/provider';
|
|
2
2
|
import { safeValidateTypes } from './validate-types';
|
|
3
|
-
import { FlexibleSchema } from './schema';
|
|
3
|
+
import type { FlexibleSchema } from './schema';
|
|
4
4
|
|
|
5
5
|
export async function parseProviderOptions<OPTIONS>({
|
|
6
6
|
provider,
|
package/src/post-to-api.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { APICallError } from '@ai-sdk/provider';
|
|
2
2
|
import { extractResponseHeaders } from './extract-response-headers';
|
|
3
|
-
import { FetchFunction } from './fetch-function';
|
|
3
|
+
import type { FetchFunction } from './fetch-function';
|
|
4
4
|
import { handleFetchError } from './handle-fetch-error';
|
|
5
5
|
import { isAbortError } from './is-abort-error';
|
|
6
|
-
import { ResponseHandler } from './response-handler';
|
|
6
|
+
import type { ResponseHandler } from './response-handler';
|
|
7
7
|
import { getRuntimeEnvironmentUserAgent } from './get-runtime-environment-user-agent';
|
|
8
8
|
import { withUserAgentSuffix } from './with-user-agent-suffix';
|
|
9
9
|
import { VERSION } from './version';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { tool,
|
|
2
|
-
import { FlexibleSchema } from './schema';
|
|
3
|
-
import { Context } from './types/context';
|
|
1
|
+
import { tool, type ProviderDefinedTool, type Tool } from './types/tool';
|
|
2
|
+
import type { FlexibleSchema } from './schema';
|
|
3
|
+
import type { Context } from './types/context';
|
|
4
|
+
import type { ToolExecuteFunction } from './types/tool-execute-function';
|
|
4
5
|
/**
|
|
5
6
|
* A provider-defined tool is a tool for which the provider defines the input
|
|
6
7
|
* and output schemas, but does not execute the tool.
|
|
@@ -18,7 +19,7 @@ export type ProviderDefinedToolFactory<
|
|
|
18
19
|
onInputDelta?: Tool<INPUT, OUTPUT, CONTEXT>['onInputDelta'];
|
|
19
20
|
onInputAvailable?: Tool<INPUT, OUTPUT, CONTEXT>['onInputAvailable'];
|
|
20
21
|
},
|
|
21
|
-
) =>
|
|
22
|
+
) => ProviderDefinedTool<INPUT, OUTPUT, CONTEXT>;
|
|
22
23
|
|
|
23
24
|
export function createProviderDefinedToolFactory<
|
|
24
25
|
INPUT,
|
|
@@ -48,7 +49,7 @@ export function createProviderDefinedToolFactory<
|
|
|
48
49
|
onInputStart?: Tool<INPUT, OUTPUT, CONTEXT>['onInputStart'];
|
|
49
50
|
onInputDelta?: Tool<INPUT, OUTPUT, CONTEXT>['onInputDelta'];
|
|
50
51
|
onInputAvailable?: Tool<INPUT, OUTPUT, CONTEXT>['onInputAvailable'];
|
|
51
|
-
}):
|
|
52
|
+
}): ProviderDefinedTool<INPUT, OUTPUT, CONTEXT> =>
|
|
52
53
|
tool({
|
|
53
54
|
type: 'provider',
|
|
54
55
|
isProviderExecuted: false,
|
|
@@ -62,7 +63,7 @@ export function createProviderDefinedToolFactory<
|
|
|
62
63
|
onInputStart,
|
|
63
64
|
onInputDelta,
|
|
64
65
|
onInputAvailable,
|
|
65
|
-
})
|
|
66
|
+
}) as ProviderDefinedTool<INPUT, OUTPUT, CONTEXT>;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
export type ProviderDefinedToolFactoryWithOutputSchema<
|
|
@@ -79,7 +80,7 @@ export type ProviderDefinedToolFactoryWithOutputSchema<
|
|
|
79
80
|
onInputDelta?: Tool<INPUT, OUTPUT, CONTEXT>['onInputDelta'];
|
|
80
81
|
onInputAvailable?: Tool<INPUT, OUTPUT, CONTEXT>['onInputAvailable'];
|
|
81
82
|
},
|
|
82
|
-
) =>
|
|
83
|
+
) => ProviderDefinedTool<INPUT, OUTPUT, CONTEXT>;
|
|
83
84
|
|
|
84
85
|
export function createProviderDefinedToolFactoryWithOutputSchema<
|
|
85
86
|
INPUT,
|
|
@@ -110,7 +111,7 @@ export function createProviderDefinedToolFactoryWithOutputSchema<
|
|
|
110
111
|
onInputStart?: Tool<INPUT, OUTPUT, CONTEXT>['onInputStart'];
|
|
111
112
|
onInputDelta?: Tool<INPUT, OUTPUT, CONTEXT>['onInputDelta'];
|
|
112
113
|
onInputAvailable?: Tool<INPUT, OUTPUT, CONTEXT>['onInputAvailable'];
|
|
113
|
-
}):
|
|
114
|
+
}): ProviderDefinedTool<INPUT, OUTPUT, CONTEXT> =>
|
|
114
115
|
tool({
|
|
115
116
|
type: 'provider',
|
|
116
117
|
isProviderExecuted: false,
|
|
@@ -124,5 +125,5 @@ export function createProviderDefinedToolFactoryWithOutputSchema<
|
|
|
124
125
|
onInputStart,
|
|
125
126
|
onInputDelta,
|
|
126
127
|
onInputAvailable,
|
|
127
|
-
})
|
|
128
|
+
}) as ProviderDefinedTool<INPUT, OUTPUT, CONTEXT>;
|
|
128
129
|
}
|