ai 6.0.233 → 6.0.235
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 +19 -0
- package/dist/index.d.mts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +33 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +33 -21
- package/dist/index.mjs.map +1 -1
- package/dist/internal/index.js +26 -14
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/index.mjs +26 -14
- package/dist/internal/index.mjs.map +1 -1
- package/docs/02-foundations/02-providers-and-models.mdx +1 -0
- package/docs/04-ai-sdk-ui/03-chatbot-tool-usage.mdx +29 -0
- package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +2 -2
- package/docs/07-reference/02-ai-sdk-ui/42-pipe-ui-message-stream-to-response.mdx +6 -1
- package/docs/08-migration-guides/24-migration-guide-6-0.mdx +28 -0
- package/package.json +2 -2
- package/src/agent/pipe-agent-ui-stream-to-response.ts +1 -1
- package/src/generate-object/stream-object-result.ts +4 -1
- package/src/generate-object/stream-object.ts +1 -1
- package/src/generate-text/stream-text-result.ts +5 -2
- package/src/generate-text/stream-text.ts +2 -2
- package/src/text-stream/pipe-text-stream-to-response.ts +3 -2
- package/src/ui-message-stream/pipe-ui-message-stream-to-response.ts +3 -2
- package/src/util/detect-media-type.ts +47 -26
- package/src/util/write-to-server-response.ts +2 -2
|
@@ -525,6 +525,34 @@ The `unknown` finish reason has been removed. It is now returned as `other`.
|
|
|
525
525
|
|
|
526
526
|
## AI SDK UI
|
|
527
527
|
|
|
528
|
+
### Tool UI Part Approval States
|
|
529
|
+
|
|
530
|
+
AI SDK 6 adds `approval-requested`, `approval-responded`, and `output-denied`
|
|
531
|
+
to the tool UI part `state` union. Update exhaustive `switch` statements and
|
|
532
|
+
other state handling to cover the three approval states.
|
|
533
|
+
|
|
534
|
+
```tsx filename="AI SDK 6"
|
|
535
|
+
switch (part.state) {
|
|
536
|
+
case 'input-streaming':
|
|
537
|
+
return 'Loading input';
|
|
538
|
+
case 'input-available':
|
|
539
|
+
return 'Input ready';
|
|
540
|
+
case 'approval-requested':
|
|
541
|
+
return 'Approval requested';
|
|
542
|
+
case 'approval-responded':
|
|
543
|
+
return 'Approval response received';
|
|
544
|
+
case 'output-available':
|
|
545
|
+
return 'Output ready';
|
|
546
|
+
case 'output-error':
|
|
547
|
+
return part.errorText;
|
|
548
|
+
case 'output-denied':
|
|
549
|
+
return 'Tool call denied';
|
|
550
|
+
}
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
See [Tool execution approval](/docs/ai-sdk-ui/chatbot-tool-usage#tool-execution-approval)
|
|
554
|
+
for handling approval requests and responses in a chat UI.
|
|
555
|
+
|
|
528
556
|
### Tool UI Part Helper Functions Rename
|
|
529
557
|
|
|
530
558
|
The tool UI part helper functions have been renamed to better reflect their purpose and to accommodate both static and dynamic tool parts ([PR #XXXX](https://github.com/vercel/ai/pull/XXXX)).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.235",
|
|
4
4
|
"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.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@opentelemetry/api": "^1.9.0",
|
|
48
|
-
"@ai-sdk/gateway": "3.0.
|
|
48
|
+
"@ai-sdk/gateway": "3.0.157",
|
|
49
49
|
"@ai-sdk/provider": "3.0.14",
|
|
50
50
|
"@ai-sdk/provider-utils": "4.0.40"
|
|
51
51
|
},
|
|
@@ -56,7 +56,7 @@ export async function pipeAgentUIStreamToResponse<
|
|
|
56
56
|
UIMessageStreamOptions<
|
|
57
57
|
UIMessage<MESSAGE_METADATA, never, InferUITools<TOOLS>>
|
|
58
58
|
>): Promise<void> {
|
|
59
|
-
pipeUIMessageStreamToResponse({
|
|
59
|
+
return pipeUIMessageStreamToResponse({
|
|
60
60
|
response,
|
|
61
61
|
headers,
|
|
62
62
|
status,
|
|
@@ -85,7 +85,10 @@ export interface StreamObjectResult<PARTIAL, RESULT, ELEMENT_STREAM> {
|
|
|
85
85
|
* @param response A Node.js response-like object (ServerResponse).
|
|
86
86
|
* @param init Optional headers, status code, and status text.
|
|
87
87
|
*/
|
|
88
|
-
pipeTextStreamToResponse(
|
|
88
|
+
pipeTextStreamToResponse(
|
|
89
|
+
response: ServerResponse,
|
|
90
|
+
init?: ResponseInit,
|
|
91
|
+
): Promise<void>;
|
|
89
92
|
|
|
90
93
|
/**
|
|
91
94
|
* Creates a simple text stream response.
|
|
@@ -342,7 +342,7 @@ export interface StreamTextResult<
|
|
|
342
342
|
pipeUIMessageStreamToResponse<UI_MESSAGE extends UIMessage>(
|
|
343
343
|
response: ServerResponse,
|
|
344
344
|
options?: UIMessageStreamResponseInit & UIMessageStreamOptions<UI_MESSAGE>,
|
|
345
|
-
): void
|
|
345
|
+
): Promise<void>;
|
|
346
346
|
|
|
347
347
|
/**
|
|
348
348
|
* Writes text delta output to a Node.js response-like object.
|
|
@@ -352,7 +352,10 @@ export interface StreamTextResult<
|
|
|
352
352
|
* @param response A Node.js response-like object (ServerResponse).
|
|
353
353
|
* @param init Optional headers, status code, and status text.
|
|
354
354
|
*/
|
|
355
|
-
pipeTextStreamToResponse(
|
|
355
|
+
pipeTextStreamToResponse(
|
|
356
|
+
response: ServerResponse,
|
|
357
|
+
init?: ResponseInit,
|
|
358
|
+
): Promise<void>;
|
|
356
359
|
|
|
357
360
|
/**
|
|
358
361
|
* Converts the result to a streamed response object with a stream data part stream.
|
|
@@ -2914,7 +2914,7 @@ class DefaultStreamTextResult<
|
|
|
2914
2914
|
...init
|
|
2915
2915
|
}: UIMessageStreamResponseInit & UIMessageStreamOptions<UI_MESSAGE> = {},
|
|
2916
2916
|
) {
|
|
2917
|
-
pipeUIMessageStreamToResponse({
|
|
2917
|
+
return pipeUIMessageStreamToResponse({
|
|
2918
2918
|
response,
|
|
2919
2919
|
stream: this.toUIMessageStream({
|
|
2920
2920
|
originalMessages,
|
|
@@ -2932,7 +2932,7 @@ class DefaultStreamTextResult<
|
|
|
2932
2932
|
}
|
|
2933
2933
|
|
|
2934
2934
|
pipeTextStreamToResponse(response: ServerResponse, init?: ResponseInit) {
|
|
2935
|
-
pipeTextStreamToResponse({
|
|
2935
|
+
return pipeTextStreamToResponse({
|
|
2936
2936
|
response,
|
|
2937
2937
|
textStream: this.textStream,
|
|
2938
2938
|
...init,
|
|
@@ -13,6 +13,7 @@ import { writeToServerResponse } from '../util/write-to-server-response';
|
|
|
13
13
|
* @param options.statusText - Optional HTTP status text.
|
|
14
14
|
* @param options.headers - Optional response headers.
|
|
15
15
|
* @param options.textStream - The text stream to pipe.
|
|
16
|
+
* @returns A promise that resolves when the stream has been written.
|
|
16
17
|
*/
|
|
17
18
|
export function pipeTextStreamToResponse({
|
|
18
19
|
response,
|
|
@@ -23,8 +24,8 @@ export function pipeTextStreamToResponse({
|
|
|
23
24
|
}: {
|
|
24
25
|
response: ServerResponse;
|
|
25
26
|
textStream: ReadableStream<string>;
|
|
26
|
-
} & ResponseInit): void {
|
|
27
|
-
writeToServerResponse({
|
|
27
|
+
} & ResponseInit): Promise<void> {
|
|
28
|
+
return writeToServerResponse({
|
|
28
29
|
response,
|
|
29
30
|
status,
|
|
30
31
|
statusText,
|
|
@@ -16,6 +16,7 @@ import type { UIMessageStreamResponseInit } from './ui-message-stream-response-i
|
|
|
16
16
|
* @param options.headers - Additional HTTP headers to include in the response.
|
|
17
17
|
* @param options.stream - The UI message chunk stream to send.
|
|
18
18
|
* @param options.consumeSseStream - Optional callback to consume a copy of the SSE stream independently.
|
|
19
|
+
* @returns A promise that resolves when the stream has been written.
|
|
19
20
|
*/
|
|
20
21
|
export function pipeUIMessageStreamToResponse({
|
|
21
22
|
response,
|
|
@@ -27,7 +28,7 @@ export function pipeUIMessageStreamToResponse({
|
|
|
27
28
|
}: {
|
|
28
29
|
response: ServerResponse;
|
|
29
30
|
stream: ReadableStream<UIMessageChunk>;
|
|
30
|
-
} & UIMessageStreamResponseInit): void {
|
|
31
|
+
} & UIMessageStreamResponseInit): Promise<void> {
|
|
31
32
|
let sseStream = stream.pipeThrough(new JsonToSseTransformStream());
|
|
32
33
|
|
|
33
34
|
// when the consumeSseStream is provided, we need to tee the stream
|
|
@@ -39,7 +40,7 @@ export function pipeUIMessageStreamToResponse({
|
|
|
39
40
|
consumeSseStream({ stream: stream2 }); // no await (do not block the response)
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
writeToServerResponse({
|
|
43
|
+
return writeToServerResponse({
|
|
43
44
|
response,
|
|
44
45
|
status,
|
|
45
46
|
statusText,
|
|
@@ -168,31 +168,54 @@ export const videoMediaTypeSignatures = [
|
|
|
168
168
|
},
|
|
169
169
|
] as const;
|
|
170
170
|
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
const DEFAULT_SNIFF_BYTES = 18;
|
|
172
|
+
|
|
173
|
+
// Longest signature prefix in the tables above (e.g. image/avif = 12 bytes).
|
|
174
|
+
const MAX_SIGNATURE_BYTES = 12;
|
|
175
|
+
|
|
176
|
+
// Largest ID3v2 tag (10-byte header + body) skipped to reach the audio frame.
|
|
177
|
+
// Covers typical tags including embedded cover art while keeping the decode
|
|
178
|
+
// bounded and O(1) in the attachment size. Exported for boundary tests.
|
|
179
|
+
export const MAX_ID3_TAG_BYTES = 128 * 1024;
|
|
180
|
+
|
|
181
|
+
// Total prefix decoded when an ID3 tag is present: the tag plus room for the
|
|
182
|
+
// trailing signature, so a tag right at the size limit stays detectable.
|
|
183
|
+
const ID3_SCAN_BYTES = MAX_ID3_TAG_BYTES + MAX_SIGNATURE_BYTES;
|
|
184
|
+
|
|
185
|
+
// Decode/view exactly the first `maxBytes` bytes from the front of the input.
|
|
186
|
+
// The base64 and raw-byte paths yield the same length, so detection does not
|
|
187
|
+
// depend on the input's representation.
|
|
188
|
+
function decodePrefix(data: Uint8Array | string, maxBytes: number): Uint8Array {
|
|
189
|
+
if (typeof data !== 'string') {
|
|
190
|
+
return data.length > maxBytes ? data.subarray(0, maxBytes) : data;
|
|
191
|
+
}
|
|
192
|
+
// base64: 4 chars -> 3 bytes. Decode whole 4-char groups, then trim the 0-2
|
|
193
|
+
// extra bytes so the result matches the raw-byte path exactly.
|
|
194
|
+
const maxChars = Math.ceil(maxBytes / 3) * 4;
|
|
195
|
+
const bytes = convertBase64ToUint8Array(
|
|
196
|
+
data.substring(0, Math.min(data.length, maxChars)),
|
|
197
|
+
);
|
|
198
|
+
return bytes.length > maxBytes ? bytes.subarray(0, maxBytes) : bytes;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function hasID3(bytes: Uint8Array): boolean {
|
|
202
|
+
return (
|
|
203
|
+
bytes.length > 10 &&
|
|
204
|
+
bytes[0] === 0x49 && // 'I'
|
|
205
|
+
bytes[1] === 0x44 && // 'D'
|
|
206
|
+
bytes[2] === 0x33 // '3'
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const stripID3 = (bytes: Uint8Array): Uint8Array => {
|
|
174
211
|
const id3Size =
|
|
175
212
|
((bytes[6] & 0x7f) << 21) |
|
|
176
213
|
((bytes[7] & 0x7f) << 14) |
|
|
177
214
|
((bytes[8] & 0x7f) << 7) |
|
|
178
215
|
(bytes[9] & 0x7f);
|
|
179
|
-
|
|
180
|
-
// The raw MP3 starts here
|
|
181
|
-
return bytes.slice(id3Size + 10);
|
|
216
|
+
return bytes.subarray(id3Size + 10);
|
|
182
217
|
};
|
|
183
218
|
|
|
184
|
-
function stripID3TagsIfPresent(data: Uint8Array | string): Uint8Array | string {
|
|
185
|
-
const hasId3 =
|
|
186
|
-
(typeof data === 'string' && data.startsWith('SUQz')) ||
|
|
187
|
-
(typeof data !== 'string' &&
|
|
188
|
-
data.length > 10 &&
|
|
189
|
-
data[0] === 0x49 && // 'I'
|
|
190
|
-
data[1] === 0x44 && // 'D'
|
|
191
|
-
data[2] === 0x33); // '3'
|
|
192
|
-
|
|
193
|
-
return hasId3 ? stripID3(data) : data;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
219
|
/**
|
|
197
220
|
* Detect the media IANA media type of a file using a list of signatures.
|
|
198
221
|
*
|
|
@@ -210,15 +233,13 @@ export function detectMediaType({
|
|
|
210
233
|
| typeof imageMediaTypeSignatures
|
|
211
234
|
| typeof videoMediaTypeSignatures;
|
|
212
235
|
}): (typeof signatures)[number]['mediaType'] | undefined {
|
|
213
|
-
|
|
236
|
+
let bytes = decodePrefix(data, DEFAULT_SNIFF_BYTES);
|
|
214
237
|
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
)
|
|
221
|
-
: processedData;
|
|
238
|
+
// ID3v2-tagged MP3s carry the audio frame after the tag; scan a bounded
|
|
239
|
+
// prefix past it rather than decoding the whole input.
|
|
240
|
+
if (hasID3(bytes)) {
|
|
241
|
+
bytes = stripID3(decodePrefix(data, ID3_SCAN_BYTES));
|
|
242
|
+
}
|
|
222
243
|
|
|
223
244
|
for (const signature of signatures) {
|
|
224
245
|
if (
|
|
@@ -15,7 +15,7 @@ export function writeToServerResponse({
|
|
|
15
15
|
statusText?: string;
|
|
16
16
|
headers?: Record<string, string | number | string[]>;
|
|
17
17
|
stream: ReadableStream<Uint8Array>;
|
|
18
|
-
}): void {
|
|
18
|
+
}): Promise<void> {
|
|
19
19
|
const statusCode = status ?? 200;
|
|
20
20
|
if (statusText !== undefined) {
|
|
21
21
|
response.writeHead(statusCode, statusText, headers);
|
|
@@ -45,5 +45,5 @@ export function writeToServerResponse({
|
|
|
45
45
|
}
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
-
read();
|
|
48
|
+
return read();
|
|
49
49
|
}
|