ai 7.0.111 → 7.0.113
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 +41 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +345 -222
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +2 -1
- package/dist/internal/index.js +125 -31
- package/dist/internal/index.js.map +1 -1
- package/docs/03-agents/06-tool-approvals.mdx +16 -0
- package/docs/03-ai-sdk-core/37-speech.mdx +2 -0
- package/docs/03-ai-sdk-core/40-middleware.mdx +92 -7
- package/docs/06-advanced/02-stopping-streams.mdx +8 -0
- package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +3 -3
- package/docs/07-reference/01-ai-sdk-core/12-generate-speech.mdx +1 -1
- package/docs/07-reference/01-ai-sdk-core/32-validate-ui-messages.mdx +18 -0
- package/docs/07-reference/02-ai-sdk-ui/40-create-ui-message-stream.mdx +9 -3
- package/package.json +12 -12
- package/src/embed/embed-many.ts +18 -2
- package/src/generate-speech/generate-speech.ts +15 -4
- package/src/generate-speech/generated-audio-file.ts +0 -8
- package/src/generate-text/execute-tools-from-stream.ts +0 -2
- package/src/generate-text/generate-text.ts +1 -0
- package/src/generate-text/generated-file.ts +0 -8
- package/src/generate-text/invoke-tool-callbacks-from-stream.ts +9 -8
- package/src/generate-text/output.ts +0 -2
- package/src/generate-text/parse-tool-call.ts +38 -25
- package/src/generate-text/prune-messages.ts +3 -1
- package/src/generate-text/stream-text.ts +1 -0
- package/src/generate-text/to-response-messages.ts +7 -0
- package/src/generate-text/tool-call.ts +26 -0
- package/src/generate-text/validate-tool-approvals.ts +39 -3
- package/src/generate-video/generate-video.ts +0 -2
- package/src/middleware/extract-reasoning-middleware.ts +1 -1
- package/src/middleware/wrap-embedding-model.ts +9 -1
- package/src/model/get-embedding-model-provider-options-transformer.ts +17 -0
- package/src/prompt/content-part.ts +3 -0
- package/src/prompt/convert-to-language-model-prompt.ts +12 -2
- package/src/prompt/file-part-data.ts +11 -1
- package/src/registry/custom-provider.ts +12 -5
- package/src/ui/chat.ts +108 -17
- package/src/ui/convert-to-model-messages.ts +8 -0
- package/src/ui/direct-chat-transport.ts +2 -0
- package/src/ui/process-ui-message-stream.ts +6 -0
- package/src/ui/ui-messages.ts +10 -0
- package/src/ui/validate-ui-messages.ts +100 -134
- package/src/ui-message-stream/handle-ui-message-stream-finish.ts +5 -3
- package/src/ui-message-stream/to-ui-message-chunk.ts +7 -0
- package/src/ui-message-stream/ui-message-chunks.ts +2 -0
- package/src/ui-message-stream/ui-message-stream-on-end-callback.ts +8 -0
- package/src/ui-message-stream/ui-message-stream-outcome.ts +4 -0
- package/src/util/write-to-server-response.ts +0 -2
|
@@ -5,11 +5,13 @@ import {
|
|
|
5
5
|
validateTypes,
|
|
6
6
|
zodSchema,
|
|
7
7
|
type FlexibleSchema,
|
|
8
|
+
type MaybePromiseLike,
|
|
8
9
|
type Tool,
|
|
9
10
|
} from '@ai-sdk/provider-utils';
|
|
10
11
|
import { InvalidArgumentError } from '../error';
|
|
11
12
|
import { jsonValueSchema } from '../types/json-value';
|
|
12
13
|
import { getOwn } from '../util/get-own';
|
|
14
|
+
import { isDeepEqualData } from '../util/is-deep-equal-data';
|
|
13
15
|
import { providerMetadataSchema } from '../types/provider-metadata';
|
|
14
16
|
import { z, type ZodType } from '../util/zod';
|
|
15
17
|
import type {
|
|
@@ -48,8 +50,38 @@ function asDynamicToolPart(toolPart: ToolUIPart): DynamicToolUIPart {
|
|
|
48
50
|
} as DynamicToolUIPart;
|
|
49
51
|
}
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
function getToolPartInputSchemaInput(
|
|
54
|
+
toolPart: ToolUIPart,
|
|
55
|
+
): { value: unknown } | undefined {
|
|
56
|
+
return toolPart.approval != null &&
|
|
57
|
+
Object.prototype.hasOwnProperty.call(toolPart.approval, 'inputSchemaInput')
|
|
58
|
+
? { value: toolPart.approval.inputSchemaInput }
|
|
59
|
+
: undefined;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const uiMessagesSchema = lazySchema(() => {
|
|
63
|
+
const approvalRequestedSchema = z.object({
|
|
64
|
+
id: z.string(),
|
|
65
|
+
approved: z.never().optional(),
|
|
66
|
+
descriptor: z.unknown().optional(),
|
|
67
|
+
requestReason: z.string().optional(),
|
|
68
|
+
reason: z.never().optional(),
|
|
69
|
+
isAutomatic: z.boolean().optional(),
|
|
70
|
+
signature: z.string().optional(),
|
|
71
|
+
inputSchemaInput: z.unknown().optional(),
|
|
72
|
+
});
|
|
73
|
+
const approvalRespondedSchema = approvalRequestedSchema.extend({
|
|
74
|
+
approved: z.boolean(),
|
|
75
|
+
reason: z.string().optional(),
|
|
76
|
+
});
|
|
77
|
+
const approvalGrantedSchema = approvalRespondedSchema.extend({
|
|
78
|
+
approved: z.literal(true),
|
|
79
|
+
});
|
|
80
|
+
const approvalDeniedSchema = approvalRespondedSchema.extend({
|
|
81
|
+
approved: z.literal(false),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
return zodSchema(
|
|
53
85
|
z
|
|
54
86
|
.array(
|
|
55
87
|
z
|
|
@@ -154,15 +186,7 @@ const uiMessagesSchema = lazySchema(() =>
|
|
|
154
186
|
output: z.never().optional(),
|
|
155
187
|
errorText: z.never().optional(),
|
|
156
188
|
callProviderMetadata: providerMetadataSchema.optional(),
|
|
157
|
-
approval:
|
|
158
|
-
id: z.string(),
|
|
159
|
-
approved: z.never().optional(),
|
|
160
|
-
descriptor: z.unknown().optional(),
|
|
161
|
-
requestReason: z.string().optional(),
|
|
162
|
-
reason: z.never().optional(),
|
|
163
|
-
isAutomatic: z.boolean().optional(),
|
|
164
|
-
signature: z.string().optional(),
|
|
165
|
-
}),
|
|
189
|
+
approval: approvalRequestedSchema,
|
|
166
190
|
}),
|
|
167
191
|
z.object({
|
|
168
192
|
type: z.literal('dynamic-tool'),
|
|
@@ -176,15 +200,7 @@ const uiMessagesSchema = lazySchema(() =>
|
|
|
176
200
|
output: z.never().optional(),
|
|
177
201
|
errorText: z.never().optional(),
|
|
178
202
|
callProviderMetadata: providerMetadataSchema.optional(),
|
|
179
|
-
approval:
|
|
180
|
-
id: z.string(),
|
|
181
|
-
approved: z.boolean(),
|
|
182
|
-
descriptor: z.unknown().optional(),
|
|
183
|
-
requestReason: z.string().optional(),
|
|
184
|
-
reason: z.string().optional(),
|
|
185
|
-
isAutomatic: z.boolean().optional(),
|
|
186
|
-
signature: z.string().optional(),
|
|
187
|
-
}),
|
|
203
|
+
approval: approvalRespondedSchema,
|
|
188
204
|
}),
|
|
189
205
|
z.object({
|
|
190
206
|
type: z.literal('dynamic-tool'),
|
|
@@ -200,17 +216,7 @@ const uiMessagesSchema = lazySchema(() =>
|
|
|
200
216
|
callProviderMetadata: providerMetadataSchema.optional(),
|
|
201
217
|
resultProviderMetadata: providerMetadataSchema.optional(),
|
|
202
218
|
preliminary: z.boolean().optional(),
|
|
203
|
-
approval:
|
|
204
|
-
.object({
|
|
205
|
-
id: z.string(),
|
|
206
|
-
approved: z.literal(true),
|
|
207
|
-
descriptor: z.unknown().optional(),
|
|
208
|
-
requestReason: z.string().optional(),
|
|
209
|
-
reason: z.string().optional(),
|
|
210
|
-
isAutomatic: z.boolean().optional(),
|
|
211
|
-
signature: z.string().optional(),
|
|
212
|
-
})
|
|
213
|
-
.optional(),
|
|
219
|
+
approval: approvalGrantedSchema.optional(),
|
|
214
220
|
}),
|
|
215
221
|
z.object({
|
|
216
222
|
type: z.literal('dynamic-tool'),
|
|
@@ -226,17 +232,7 @@ const uiMessagesSchema = lazySchema(() =>
|
|
|
226
232
|
errorText: z.string(),
|
|
227
233
|
callProviderMetadata: providerMetadataSchema.optional(),
|
|
228
234
|
resultProviderMetadata: providerMetadataSchema.optional(),
|
|
229
|
-
approval:
|
|
230
|
-
.object({
|
|
231
|
-
id: z.string(),
|
|
232
|
-
approved: z.literal(true),
|
|
233
|
-
descriptor: z.unknown().optional(),
|
|
234
|
-
requestReason: z.string().optional(),
|
|
235
|
-
reason: z.string().optional(),
|
|
236
|
-
isAutomatic: z.boolean().optional(),
|
|
237
|
-
signature: z.string().optional(),
|
|
238
|
-
})
|
|
239
|
-
.optional(),
|
|
235
|
+
approval: approvalGrantedSchema.optional(),
|
|
240
236
|
}),
|
|
241
237
|
z.object({
|
|
242
238
|
type: z.literal('dynamic-tool'),
|
|
@@ -250,15 +246,7 @@ const uiMessagesSchema = lazySchema(() =>
|
|
|
250
246
|
output: z.never().optional(),
|
|
251
247
|
errorText: z.never().optional(),
|
|
252
248
|
callProviderMetadata: providerMetadataSchema.optional(),
|
|
253
|
-
approval:
|
|
254
|
-
id: z.string(),
|
|
255
|
-
approved: z.literal(false),
|
|
256
|
-
descriptor: z.unknown().optional(),
|
|
257
|
-
requestReason: z.string().optional(),
|
|
258
|
-
reason: z.string().optional(),
|
|
259
|
-
isAutomatic: z.boolean().optional(),
|
|
260
|
-
signature: z.string().optional(),
|
|
261
|
-
}),
|
|
249
|
+
approval: approvalDeniedSchema,
|
|
262
250
|
}),
|
|
263
251
|
z.object({
|
|
264
252
|
type: z.string().startsWith('tool-'),
|
|
@@ -297,15 +285,7 @@ const uiMessagesSchema = lazySchema(() =>
|
|
|
297
285
|
output: z.never().optional(),
|
|
298
286
|
errorText: z.never().optional(),
|
|
299
287
|
callProviderMetadata: providerMetadataSchema.optional(),
|
|
300
|
-
approval:
|
|
301
|
-
id: z.string(),
|
|
302
|
-
approved: z.never().optional(),
|
|
303
|
-
descriptor: z.unknown().optional(),
|
|
304
|
-
requestReason: z.string().optional(),
|
|
305
|
-
reason: z.never().optional(),
|
|
306
|
-
isAutomatic: z.boolean().optional(),
|
|
307
|
-
signature: z.string().optional(),
|
|
308
|
-
}),
|
|
288
|
+
approval: approvalRequestedSchema,
|
|
309
289
|
}),
|
|
310
290
|
z.object({
|
|
311
291
|
type: z.string().startsWith('tool-'),
|
|
@@ -318,15 +298,7 @@ const uiMessagesSchema = lazySchema(() =>
|
|
|
318
298
|
output: z.never().optional(),
|
|
319
299
|
errorText: z.never().optional(),
|
|
320
300
|
callProviderMetadata: providerMetadataSchema.optional(),
|
|
321
|
-
approval:
|
|
322
|
-
id: z.string(),
|
|
323
|
-
approved: z.boolean(),
|
|
324
|
-
descriptor: z.unknown().optional(),
|
|
325
|
-
requestReason: z.string().optional(),
|
|
326
|
-
reason: z.string().optional(),
|
|
327
|
-
isAutomatic: z.boolean().optional(),
|
|
328
|
-
signature: z.string().optional(),
|
|
329
|
-
}),
|
|
301
|
+
approval: approvalRespondedSchema,
|
|
330
302
|
}),
|
|
331
303
|
z.object({
|
|
332
304
|
type: z.string().startsWith('tool-'),
|
|
@@ -341,17 +313,7 @@ const uiMessagesSchema = lazySchema(() =>
|
|
|
341
313
|
callProviderMetadata: providerMetadataSchema.optional(),
|
|
342
314
|
resultProviderMetadata: providerMetadataSchema.optional(),
|
|
343
315
|
preliminary: z.boolean().optional(),
|
|
344
|
-
approval:
|
|
345
|
-
.object({
|
|
346
|
-
id: z.string(),
|
|
347
|
-
approved: z.literal(true),
|
|
348
|
-
descriptor: z.unknown().optional(),
|
|
349
|
-
requestReason: z.string().optional(),
|
|
350
|
-
reason: z.string().optional(),
|
|
351
|
-
isAutomatic: z.boolean().optional(),
|
|
352
|
-
signature: z.string().optional(),
|
|
353
|
-
})
|
|
354
|
-
.optional(),
|
|
316
|
+
approval: approvalGrantedSchema.optional(),
|
|
355
317
|
}),
|
|
356
318
|
z.object({
|
|
357
319
|
type: z.string().startsWith('tool-'),
|
|
@@ -366,17 +328,7 @@ const uiMessagesSchema = lazySchema(() =>
|
|
|
366
328
|
errorText: z.string(),
|
|
367
329
|
callProviderMetadata: providerMetadataSchema.optional(),
|
|
368
330
|
resultProviderMetadata: providerMetadataSchema.optional(),
|
|
369
|
-
approval:
|
|
370
|
-
.object({
|
|
371
|
-
id: z.string(),
|
|
372
|
-
approved: z.literal(true),
|
|
373
|
-
descriptor: z.unknown().optional(),
|
|
374
|
-
requestReason: z.string().optional(),
|
|
375
|
-
reason: z.string().optional(),
|
|
376
|
-
isAutomatic: z.boolean().optional(),
|
|
377
|
-
signature: z.string().optional(),
|
|
378
|
-
})
|
|
379
|
-
.optional(),
|
|
331
|
+
approval: approvalGrantedSchema.optional(),
|
|
380
332
|
}),
|
|
381
333
|
z.object({
|
|
382
334
|
type: z.string().startsWith('tool-'),
|
|
@@ -389,15 +341,7 @@ const uiMessagesSchema = lazySchema(() =>
|
|
|
389
341
|
output: z.never().optional(),
|
|
390
342
|
errorText: z.never().optional(),
|
|
391
343
|
callProviderMetadata: providerMetadataSchema.optional(),
|
|
392
|
-
approval:
|
|
393
|
-
id: z.string(),
|
|
394
|
-
approved: z.literal(false),
|
|
395
|
-
descriptor: z.unknown().optional(),
|
|
396
|
-
requestReason: z.string().optional(),
|
|
397
|
-
reason: z.string().optional(),
|
|
398
|
-
isAutomatic: z.boolean().optional(),
|
|
399
|
-
signature: z.string().optional(),
|
|
400
|
-
}),
|
|
344
|
+
approval: approvalDeniedSchema,
|
|
401
345
|
}),
|
|
402
346
|
]),
|
|
403
347
|
),
|
|
@@ -417,8 +361,8 @@ const uiMessagesSchema = lazySchema(() =>
|
|
|
417
361
|
}),
|
|
418
362
|
)
|
|
419
363
|
.nonempty('Messages array must not be empty'),
|
|
420
|
-
)
|
|
421
|
-
);
|
|
364
|
+
);
|
|
365
|
+
});
|
|
422
366
|
|
|
423
367
|
export type SafeValidateUIMessagesResult<UI_MESSAGE extends UIMessage> =
|
|
424
368
|
| {
|
|
@@ -453,6 +397,11 @@ type ValidateUIMessagesOptions<UI_MESSAGE extends UIMessage> = {
|
|
|
453
397
|
>;
|
|
454
398
|
};
|
|
455
399
|
};
|
|
400
|
+
experimental_refineToolInput?: {
|
|
401
|
+
[NAME in keyof InferUIMessageTools<UI_MESSAGE> & string]?: (
|
|
402
|
+
input: InferUIMessageTools<UI_MESSAGE>[NAME]['input'],
|
|
403
|
+
) => MaybePromiseLike<InferUIMessageTools<UI_MESSAGE>[NAME]['input']>;
|
|
404
|
+
};
|
|
456
405
|
};
|
|
457
406
|
|
|
458
407
|
async function safeValidateUIMessagesInternal<UI_MESSAGE extends UIMessage>(
|
|
@@ -461,6 +410,7 @@ async function safeValidateUIMessagesInternal<UI_MESSAGE extends UIMessage>(
|
|
|
461
410
|
metadataSchema,
|
|
462
411
|
dataSchemas,
|
|
463
412
|
tools,
|
|
413
|
+
experimental_refineToolInput,
|
|
464
414
|
}: ValidateUIMessagesOptions<UI_MESSAGE>,
|
|
465
415
|
{
|
|
466
416
|
convertMissingTerminalToolsToDynamic,
|
|
@@ -489,7 +439,7 @@ async function safeValidateUIMessagesInternal<UI_MESSAGE extends UIMessage>(
|
|
|
489
439
|
|
|
490
440
|
if (metadataSchema) {
|
|
491
441
|
for (const [msgIdx, message] of validatedMessages.entries()) {
|
|
492
|
-
await validateTypes({
|
|
442
|
+
message.metadata = await validateTypes({
|
|
493
443
|
value: message.metadata,
|
|
494
444
|
schema: metadataSchema,
|
|
495
445
|
context: {
|
|
@@ -527,7 +477,7 @@ async function safeValidateUIMessagesInternal<UI_MESSAGE extends UIMessage>(
|
|
|
527
477
|
};
|
|
528
478
|
}
|
|
529
479
|
|
|
530
|
-
await validateTypes({
|
|
480
|
+
dataPart.data = await validateTypes({
|
|
531
481
|
value: dataPart.data,
|
|
532
482
|
schema: dataSchema,
|
|
533
483
|
context: {
|
|
@@ -583,49 +533,65 @@ async function safeValidateUIMessagesInternal<UI_MESSAGE extends UIMessage>(
|
|
|
583
533
|
entityName: toolName,
|
|
584
534
|
entityId: toolPart.toolCallId,
|
|
585
535
|
};
|
|
536
|
+
const inputSchemaInput = getToolPartInputSchemaInput(toolPart);
|
|
537
|
+
const inputToValidate =
|
|
538
|
+
inputSchemaInput == null
|
|
539
|
+
? toolPart.input
|
|
540
|
+
: inputSchemaInput.value;
|
|
586
541
|
let convertToDynamic = false;
|
|
587
542
|
|
|
588
543
|
// Tool input validation
|
|
589
|
-
if (
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
value: toolPart.input,
|
|
596
|
-
schema: tool.inputSchema,
|
|
597
|
-
context: inputValidationContext,
|
|
598
|
-
});
|
|
599
|
-
convertToDynamic = !result.success;
|
|
600
|
-
}
|
|
601
|
-
} else if (toolPart.state === 'output-available') {
|
|
544
|
+
if (
|
|
545
|
+
toolPart.state !== 'input-streaming' &&
|
|
546
|
+
(toolPart.state !== 'output-error' ||
|
|
547
|
+
inputSchemaInput != null ||
|
|
548
|
+
toolPart.input !== undefined)
|
|
549
|
+
) {
|
|
602
550
|
const result = await safeValidateTypes({
|
|
603
|
-
value:
|
|
551
|
+
value: inputToValidate,
|
|
604
552
|
schema: tool.inputSchema,
|
|
605
553
|
context: inputValidationContext,
|
|
606
554
|
});
|
|
607
555
|
|
|
556
|
+
let inputError: TypeValidationError | undefined;
|
|
608
557
|
if (!result.success) {
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
558
|
+
inputError = result.error;
|
|
559
|
+
} else if (inputSchemaInput != null) {
|
|
560
|
+
try {
|
|
561
|
+
const refine = getOwn(experimental_refineToolInput, toolName);
|
|
562
|
+
const reconstructedInput =
|
|
563
|
+
refine == null ? result.value : await refine(result.value);
|
|
564
|
+
|
|
565
|
+
if (!isDeepEqualData(reconstructedInput, toolPart.input)) {
|
|
566
|
+
inputError = new TypeValidationError({
|
|
567
|
+
value: toolPart.input,
|
|
568
|
+
cause:
|
|
569
|
+
'Tool input does not match the output reconstructed from inputSchemaInput.',
|
|
570
|
+
context: inputValidationContext,
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
} catch (error) {
|
|
574
|
+
inputError = new TypeValidationError({
|
|
575
|
+
value: inputToValidate,
|
|
576
|
+
cause: error,
|
|
577
|
+
context: inputValidationContext,
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
if (inputError != null) {
|
|
583
|
+
// Failed calls and empty terminal inputs must remain loadable,
|
|
584
|
+
// but must not claim to match the current static input type.
|
|
585
|
+
if (
|
|
586
|
+
toolPart.state === 'output-error' ||
|
|
587
|
+
(toolPart.state === 'output-available' &&
|
|
588
|
+
isEmptyObject(toolPart.input))
|
|
589
|
+
) {
|
|
613
590
|
convertToDynamic = true;
|
|
614
591
|
} else {
|
|
615
|
-
throw
|
|
592
|
+
throw inputError;
|
|
616
593
|
}
|
|
617
594
|
}
|
|
618
|
-
} else if (
|
|
619
|
-
toolPart.state === 'input-available' ||
|
|
620
|
-
toolPart.state === 'approval-requested' ||
|
|
621
|
-
toolPart.state === 'approval-responded' ||
|
|
622
|
-
toolPart.state === 'output-denied'
|
|
623
|
-
) {
|
|
624
|
-
await validateTypes({
|
|
625
|
-
value: toolPart.input,
|
|
626
|
-
schema: tool.inputSchema,
|
|
627
|
-
context: inputValidationContext,
|
|
628
|
-
});
|
|
629
595
|
}
|
|
630
596
|
|
|
631
597
|
// Tool output validation
|
|
@@ -147,7 +147,7 @@ export function handleUIMessageStreamFinish<UI_MESSAGE extends UIMessage>({
|
|
|
147
147
|
|
|
148
148
|
let finishCalled = false;
|
|
149
149
|
|
|
150
|
-
const callOnEnd = async () => {
|
|
150
|
+
const callOnEnd = async ({ isCancelled }: { isCancelled: boolean }) => {
|
|
151
151
|
if (finishCalled || !resolvedOnEnd) {
|
|
152
152
|
return;
|
|
153
153
|
}
|
|
@@ -160,9 +160,11 @@ export function handleUIMessageStreamFinish<UI_MESSAGE extends UIMessage>({
|
|
|
160
160
|
: declaredOutcome.status === 'unknown' && isAborted
|
|
161
161
|
? { status: 'aborted' }
|
|
162
162
|
: declaredOutcome;
|
|
163
|
+
const isConsumerCancellation = isCancelled && outcome.status === 'unknown';
|
|
163
164
|
|
|
164
165
|
await resolvedOnEnd({
|
|
165
166
|
isAborted: isAborted || outcome.status === 'aborted',
|
|
167
|
+
...(isConsumerCancellation ? { isCancelled: true as const } : {}),
|
|
166
168
|
isContinuation,
|
|
167
169
|
outcome,
|
|
168
170
|
responseMessage: state.message as UI_MESSAGE,
|
|
@@ -215,11 +217,11 @@ export function handleUIMessageStreamFinish<UI_MESSAGE extends UIMessage>({
|
|
|
215
217
|
},
|
|
216
218
|
// @ts-expect-error cancel is still new and missing from types https://developer.mozilla.org/en-US/docs/Web/API/TransformStream#browser_compatibility
|
|
217
219
|
async cancel() {
|
|
218
|
-
await callOnEnd();
|
|
220
|
+
await callOnEnd({ isCancelled: true });
|
|
219
221
|
},
|
|
220
222
|
|
|
221
223
|
async flush() {
|
|
222
|
-
await callOnEnd();
|
|
224
|
+
await callOnEnd({ isCancelled: false });
|
|
223
225
|
},
|
|
224
226
|
}),
|
|
225
227
|
);
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { ToolSet } from '@ai-sdk/provider-utils';
|
|
2
2
|
import type { TextStreamPart } from '../generate-text/stream-text-result';
|
|
3
|
+
import { getToolCallInputSchemaInput } from '../generate-text/tool-call';
|
|
3
4
|
import type {
|
|
4
5
|
InferUIMessageData,
|
|
5
6
|
InferUIMessageMetadata,
|
|
6
7
|
UIMessage,
|
|
7
8
|
} from '../ui/ui-messages';
|
|
9
|
+
import { isDeepEqualData } from '../util/is-deep-equal-data';
|
|
8
10
|
import type { InferUIMessageChunk, UIMessageChunk } from './ui-message-chunks';
|
|
9
11
|
|
|
10
12
|
export type ToUIMessageChunkOptions<
|
|
@@ -250,10 +252,15 @@ export function toUIMessageChunk<
|
|
|
250
252
|
}
|
|
251
253
|
|
|
252
254
|
case 'tool-approval-request': {
|
|
255
|
+
const inputSchemaInput = getToolCallInputSchemaInput(part.toolCall);
|
|
253
256
|
return {
|
|
254
257
|
type: 'tool-approval-request',
|
|
255
258
|
approvalId: part.approvalId,
|
|
256
259
|
toolCallId: part.toolCall.toolCallId,
|
|
260
|
+
...(inputSchemaInput != null &&
|
|
261
|
+
!isDeepEqualData(inputSchemaInput.value, part.toolCall.input)
|
|
262
|
+
? { inputSchemaInput: inputSchemaInput.value }
|
|
263
|
+
: {}),
|
|
257
264
|
...(part.reason != null ? { reason: part.reason } : {}),
|
|
258
265
|
...(part.isAutomatic != null ? { isAutomatic: part.isAutomatic } : {}),
|
|
259
266
|
...(part.signature != null ? { signature: part.signature } : {}),
|
|
@@ -86,6 +86,7 @@ export const uiMessageChunkSchema = lazySchema(() =>
|
|
|
86
86
|
approvalId: z.string(),
|
|
87
87
|
toolCallId: z.string(),
|
|
88
88
|
approvalDescriptor: z.unknown().optional(),
|
|
89
|
+
inputSchemaInput: z.unknown().optional(),
|
|
89
90
|
reason: z.string().optional(),
|
|
90
91
|
isAutomatic: z.boolean().optional(),
|
|
91
92
|
signature: z.string().optional(),
|
|
@@ -301,6 +302,7 @@ export type UIMessageChunk<
|
|
|
301
302
|
approvalId: string;
|
|
302
303
|
toolCallId: string;
|
|
303
304
|
approvalDescriptor?: unknown;
|
|
305
|
+
inputSchemaInput?: unknown;
|
|
304
306
|
reason?: string;
|
|
305
307
|
isAutomatic?: boolean;
|
|
306
308
|
signature?: string;
|
|
@@ -20,6 +20,14 @@ export type UIMessageStreamOnEndCallback<UI_MESSAGE extends UIMessage> =
|
|
|
20
20
|
*/
|
|
21
21
|
isAborted: boolean;
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Indicates that the consumer cancelled the stream before an outcome was
|
|
25
|
+
* declared, for example because the client disconnected.
|
|
26
|
+
*
|
|
27
|
+
* This property is only present when it is `true`.
|
|
28
|
+
*/
|
|
29
|
+
isCancelled?: true;
|
|
30
|
+
|
|
23
31
|
/**
|
|
24
32
|
* The operation-level outcome of the stream. Fatal stream-processing
|
|
25
33
|
* failures override outcomes declared by the stream owner.
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* This is separate from model finish reasons and individual stream chunks.
|
|
5
5
|
* Fatal stream-processing failures override outcomes declared by the stream
|
|
6
6
|
* owner.
|
|
7
|
+
*
|
|
8
|
+
* Consumer cancellation before an outcome is declared keeps the `unknown`
|
|
9
|
+
* status and is reported separately through the end callback's `isCancelled`
|
|
10
|
+
* property.
|
|
7
11
|
*/
|
|
8
12
|
export type UIMessageStreamOutcome =
|
|
9
13
|
| { status: 'completed' }
|