ai 7.0.78 → 7.0.82

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/dist/index.d.ts +103 -37
  3. package/dist/index.js +608 -422
  4. package/dist/index.js.map +1 -1
  5. package/dist/internal/index.d.ts +9 -1
  6. package/dist/internal/index.js +4 -2
  7. package/dist/internal/index.js.map +1 -1
  8. package/dist/test/index.d.ts +4 -1
  9. package/dist/test/index.js +4 -0
  10. package/dist/test/index.js.map +1 -1
  11. package/docs/02-foundations/02-providers-and-models.mdx +2 -2
  12. package/docs/03-agents/06-policy-tool-approvals.mdx +1 -1
  13. package/docs/03-agents/06-tool-approvals.mdx +6 -0
  14. package/docs/03-ai-sdk-core/15-tools-and-tool-calling.mdx +6 -4
  15. package/docs/03-ai-sdk-core/50-error-handling.mdx +17 -2
  16. package/docs/03-ai-sdk-harnesses/05-harness-adapters.mdx +4 -4
  17. package/docs/04-ai-sdk-ui/03-chatbot-tool-usage.mdx +6 -0
  18. package/docs/04-ai-sdk-ui/50-stream-protocol.mdx +2 -2
  19. package/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx +1 -1
  20. package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +5 -4
  21. package/docs/07-reference/01-ai-sdk-core/06-embed-many.mdx +6 -2
  22. package/docs/07-reference/01-ai-sdk-core/16-tool-loop-agent.mdx +1 -1
  23. package/docs/07-reference/02-ai-sdk-ui/31-convert-to-model-messages.mdx +2 -2
  24. package/docs/07-reference/04-ai-sdk-workflow/03-generate-video.mdx +157 -0
  25. package/docs/07-reference/04-ai-sdk-workflow/index.mdx +6 -0
  26. package/docs/07-reference/05-ai-sdk-errors/ai-stream-provider-error.mdx +52 -0
  27. package/docs/07-reference/05-ai-sdk-errors/index.mdx +1 -0
  28. package/package.json +18 -7
  29. package/src/batch/batch-types.ts +7 -0
  30. package/src/batch/batch.ts +2 -0
  31. package/src/embed/embed-many.ts +78 -8
  32. package/src/error/index.ts +1 -0
  33. package/src/error/stream-provider-error.ts +78 -0
  34. package/src/generate-text/execute-tools-from-stream.ts +3 -0
  35. package/src/generate-text/generate-text-result.ts +2 -1
  36. package/src/generate-text/generate-text.ts +9 -2
  37. package/src/generate-text/stream-language-model-call.ts +8 -0
  38. package/src/generate-text/to-response-messages.ts +1 -0
  39. package/src/generate-text/tool-approval-configuration.ts +5 -1
  40. package/src/generate-text/tool-approval-request-output.ts +5 -0
  41. package/src/index.ts +7 -1
  42. package/src/middleware/wrap-embedding-model.ts +11 -2
  43. package/src/model/get-embedding-model-max-input-bytes-per-call.ts +15 -0
  44. package/src/prompt/content-part.ts +1 -0
  45. package/src/prompt/normalize-stream-provider-error.ts +131 -0
  46. package/src/test/mock-embedding-model-v4.ts +9 -0
  47. package/src/ui/convert-to-model-messages.ts +3 -0
  48. package/src/ui/process-ui-message-stream.ts +8 -3
  49. package/src/ui/ui-messages.ts +10 -0
  50. package/src/ui/validate-ui-messages.ts +10 -0
  51. package/src/ui-message-stream/to-ui-message-chunk.ts +1 -0
  52. package/src/ui-message-stream/ui-message-chunks.ts +2 -0
@@ -4,8 +4,15 @@ import type {
4
4
  EmbeddingModelV4CallOptions,
5
5
  EmbeddingModelV4Result,
6
6
  } from '@ai-sdk/provider';
7
- import { asArray } from '@ai-sdk/provider-utils';
7
+ import {
8
+ asArray,
9
+ EXPERIMENTAL_EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL,
10
+ } from '@ai-sdk/provider-utils';
8
11
  import { asEmbeddingModelV4 } from '../model/as-embedding-model-v4';
12
+ import {
13
+ getEmbeddingModelMaxInputBytesPerCall,
14
+ type EmbeddingModelWithMaxInputBytesPerCall,
15
+ } from '../model/get-embedding-model-max-input-bytes-per-call';
9
16
  import type { EmbeddingModelMiddleware } from '../types';
10
17
 
11
18
  /**
@@ -56,7 +63,7 @@ const doWrap = ({
56
63
  middleware: EmbeddingModelMiddleware;
57
64
  modelId?: string;
58
65
  providerId?: string;
59
- }): EmbeddingModelV4 => {
66
+ }): EmbeddingModelWithMaxInputBytesPerCall => {
60
67
  async function doTransform({
61
68
  params,
62
69
  }: {
@@ -71,6 +78,8 @@ const doWrap = ({
71
78
  modelId: modelId ?? overrideModelId?.({ model }) ?? model.modelId,
72
79
  maxEmbeddingsPerCall:
73
80
  overrideMaxEmbeddingsPerCall?.({ model }) ?? model.maxEmbeddingsPerCall,
81
+ [EXPERIMENTAL_EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL]:
82
+ getEmbeddingModelMaxInputBytesPerCall(model),
74
83
  supportsParallelCalls:
75
84
  overrideSupportsParallelCalls?.({ model }) ?? model.supportsParallelCalls,
76
85
  async doEmbed(
@@ -0,0 +1,15 @@
1
+ import type { EmbeddingModelV4 } from '@ai-sdk/provider';
2
+ import { EXPERIMENTAL_EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL } from '@ai-sdk/provider-utils';
3
+
4
+ export type EmbeddingModelWithMaxInputBytesPerCall = EmbeddingModelV4 & {
5
+ readonly [EXPERIMENTAL_EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL]?:
6
+ | PromiseLike<number | undefined>
7
+ | number
8
+ | undefined;
9
+ };
10
+
11
+ export function getEmbeddingModelMaxInputBytesPerCall(model: EmbeddingModelV4) {
12
+ return (model as EmbeddingModelWithMaxInputBytesPerCall)[
13
+ EXPERIMENTAL_EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL
14
+ ];
15
+ }
@@ -283,6 +283,7 @@ export const toolApprovalRequestSchema: ZodType<ToolApprovalRequest> = z.object(
283
283
  type: z.literal('tool-approval-request'),
284
284
  approvalId: z.string(),
285
285
  toolCallId: z.string(),
286
+ reason: z.string().optional(),
286
287
  },
287
288
  );
288
289
 
@@ -0,0 +1,131 @@
1
+ import { AISDKError } from '@ai-sdk/provider';
2
+ import { isProviderStreamError } from '@ai-sdk/provider-utils';
3
+ import { StreamProviderError } from '../error/stream-provider-error';
4
+
5
+ /**
6
+ * Normalizes well-formed provider error payloads without changing existing
7
+ * Error instances or malformed/unknown values.
8
+ */
9
+ export function normalizeStreamProviderError(error: unknown): unknown {
10
+ if (
11
+ isError(error) ||
12
+ AISDKError.isInstance(error) ||
13
+ StreamProviderError.isInstance(error)
14
+ ) {
15
+ return error;
16
+ }
17
+
18
+ const outer = asRecord(error);
19
+ if (outer == null) {
20
+ return error;
21
+ }
22
+
23
+ const providerStreamError = isProviderStreamError(error);
24
+ const details = providerStreamError
25
+ ? outer
26
+ : (asRecord(asRecord(outer.response)?.error) ??
27
+ asRecord(outer.error) ??
28
+ outer);
29
+
30
+ if (typeof details.message !== 'string') {
31
+ return error;
32
+ }
33
+
34
+ const type = getString(details.type) ?? getString(outer.type);
35
+ const code = getStringOrNumber(details.code) ?? getStringOrNumber(outer.code);
36
+ const explicitStatusCode =
37
+ getHttpStatusCode(details.statusCode) ??
38
+ getHttpStatusCode(outer.statusCode) ??
39
+ getHttpStatusCode(details.status_code) ??
40
+ getHttpStatusCode(outer.status_code) ??
41
+ getHttpStatusCode(details.status) ??
42
+ getHttpStatusCode(outer.status) ??
43
+ getHttpStatusCode(details.code) ??
44
+ getHttpStatusCode(outer.code);
45
+ const messageMetadata = inferExactMessageMetadata(details.message);
46
+ const statusCode = explicitStatusCode ?? messageMetadata?.statusCode;
47
+ const explicitRetryability =
48
+ getBoolean(details.isRetryable) ??
49
+ getBoolean(outer.isRetryable) ??
50
+ getBoolean(details.is_retryable) ??
51
+ getBoolean(outer.is_retryable);
52
+
53
+ return new StreamProviderError({
54
+ message: details.message,
55
+ type,
56
+ code,
57
+ statusCode,
58
+ isRetryable:
59
+ explicitRetryability ??
60
+ messageMetadata?.isRetryable ??
61
+ isRetryableStatusCode(statusCode),
62
+ data: providerStreamError ? error.data : error,
63
+ });
64
+ }
65
+
66
+ function inferExactMessageMetadata(
67
+ message: string,
68
+ ): { statusCode: number; isRetryable: true } | undefined {
69
+ switch (message.trim().toLowerCase()) {
70
+ case 'overloaded':
71
+ case 'overloaded error':
72
+ case 'model overloaded':
73
+ return { statusCode: 503, isRetryable: true };
74
+ case 'internal server error':
75
+ return { statusCode: 500, isRetryable: true };
76
+ case 'service unavailable':
77
+ return { statusCode: 503, isRetryable: true };
78
+ default:
79
+ return undefined;
80
+ }
81
+ }
82
+
83
+ function isRetryableStatusCode(statusCode: number | undefined): boolean {
84
+ return (
85
+ statusCode != null &&
86
+ (statusCode === 408 ||
87
+ statusCode === 409 ||
88
+ statusCode === 429 ||
89
+ statusCode >= 500)
90
+ );
91
+ }
92
+
93
+ function asRecord(value: unknown): Record<string, unknown> | undefined {
94
+ return typeof value === 'object' && value != null
95
+ ? (value as Record<string, unknown>)
96
+ : undefined;
97
+ }
98
+
99
+ // `instanceof` misses Error instances created in another JavaScript realm.
100
+ function isError(value: unknown): value is Error {
101
+ return (
102
+ value instanceof Error ||
103
+ Object.prototype.toString.call(value) === '[object Error]'
104
+ );
105
+ }
106
+
107
+ function getString(value: unknown): string | undefined {
108
+ return typeof value === 'string' ? value : undefined;
109
+ }
110
+
111
+ function getStringOrNumber(value: unknown): string | number | undefined {
112
+ return typeof value === 'string' || typeof value === 'number'
113
+ ? value
114
+ : undefined;
115
+ }
116
+
117
+ function getBoolean(value: unknown): boolean | undefined {
118
+ return typeof value === 'boolean' ? value : undefined;
119
+ }
120
+
121
+ function getHttpStatusCode(value: unknown): number | undefined {
122
+ const statusCode =
123
+ typeof value === 'string' && /^\d{3}$/.test(value) ? Number(value) : value;
124
+
125
+ return typeof statusCode === 'number' &&
126
+ Number.isInteger(statusCode) &&
127
+ statusCode >= 400 &&
128
+ statusCode <= 599
129
+ ? statusCode
130
+ : undefined;
131
+ }
@@ -1,4 +1,5 @@
1
1
  import type { EmbeddingModelV4 } from '@ai-sdk/provider';
2
+ import { EXPERIMENTAL_EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL } from '@ai-sdk/provider-utils';
2
3
  import { notImplemented } from './not-implemented';
3
4
 
4
5
  export class MockEmbeddingModelV4 implements EmbeddingModelV4 {
@@ -7,6 +8,10 @@ export class MockEmbeddingModelV4 implements EmbeddingModelV4 {
7
8
  readonly provider: EmbeddingModelV4['provider'];
8
9
  readonly modelId: EmbeddingModelV4['modelId'];
9
10
  readonly maxEmbeddingsPerCall: EmbeddingModelV4['maxEmbeddingsPerCall'];
11
+ readonly [EXPERIMENTAL_EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL]:
12
+ | PromiseLike<number | undefined>
13
+ | number
14
+ | undefined;
10
15
  readonly supportsParallelCalls: EmbeddingModelV4['supportsParallelCalls'];
11
16
 
12
17
  doEmbed: EmbeddingModelV4['doEmbed'];
@@ -17,12 +22,14 @@ export class MockEmbeddingModelV4 implements EmbeddingModelV4 {
17
22
  provider = 'mock-provider',
18
23
  modelId = 'mock-model-id',
19
24
  maxEmbeddingsPerCall = 1,
25
+ maxInputBytesPerCall,
20
26
  supportsParallelCalls = false,
21
27
  doEmbed = notImplemented,
22
28
  }: {
23
29
  provider?: EmbeddingModelV4['provider'];
24
30
  modelId?: EmbeddingModelV4['modelId'];
25
31
  maxEmbeddingsPerCall?: EmbeddingModelV4['maxEmbeddingsPerCall'] | null;
32
+ maxInputBytesPerCall?: PromiseLike<number | undefined> | number | undefined;
26
33
  supportsParallelCalls?: EmbeddingModelV4['supportsParallelCalls'];
27
34
  doEmbed?:
28
35
  | EmbeddingModelV4['doEmbed']
@@ -32,6 +39,8 @@ export class MockEmbeddingModelV4 implements EmbeddingModelV4 {
32
39
  this.provider = provider;
33
40
  this.modelId = modelId;
34
41
  this.maxEmbeddingsPerCall = maxEmbeddingsPerCall ?? undefined;
42
+ this[EXPERIMENTAL_EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL] =
43
+ maxInputBytesPerCall;
35
44
  this.supportsParallelCalls = supportsParallelCalls;
36
45
  this.doEmbed = async options => {
37
46
  this.doEmbedCalls.push(options);
@@ -233,6 +233,9 @@ export async function convertToModelMessages<UI_MESSAGE extends UIMessage>(
233
233
  approvalId: part.approval.id,
234
234
  toolCallId: part.toolCallId,
235
235
  isAutomatic: part.approval.isAutomatic,
236
+ ...(part.approval.requestReason != null
237
+ ? { reason: part.approval.requestReason }
238
+ : {}),
236
239
  ...(part.approval.signature != null
237
240
  ? { signature: part.approval.signature }
238
241
  : {}),
@@ -748,6 +748,9 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
748
748
  toolInvocation.state = 'approval-requested';
749
749
  toolInvocation.approval = {
750
750
  id: chunk.approvalId,
751
+ ...(chunk.reason != null
752
+ ? { requestReason: chunk.reason }
753
+ : {}),
751
754
  ...(chunk.isAutomatic === true ? { isAutomatic: true } : {}),
752
755
  ...(chunk.signature != null
753
756
  ? { signature: chunk.signature }
@@ -770,6 +773,9 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
770
773
  toolInvocation.approval = {
771
774
  id: chunk.approvalId,
772
775
  approved: chunk.approved,
776
+ ...(approval.requestReason != null
777
+ ? { requestReason: approval.requestReason }
778
+ : {}),
773
779
  ...(chunk.reason != null ? { reason: chunk.reason } : {}),
774
780
  ...(approval.isAutomatic === true ? { isAutomatic: true } : {}),
775
781
  ...(approval.signature != null
@@ -881,9 +887,8 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
881
887
  }
882
888
 
883
889
  case 'finish-step': {
884
- // reset the current text and reasoning parts
885
- state.activeTextParts = createIdMap();
886
- state.activeReasoningParts = createIdMap();
890
+ // Active parts are closed by their explicit end chunks. A merged
891
+ // stream's step can finish while another stream's part is active.
887
892
  break;
888
893
  }
889
894
 
@@ -319,6 +319,7 @@ export type UIToolInvocation<TOOL extends UITool | Tool> = {
319
319
  approval: {
320
320
  id: string;
321
321
  approved?: never;
322
+ requestReason?: string;
322
323
  reason?: never;
323
324
  isAutomatic?: boolean;
324
325
  signature?: string;
@@ -333,6 +334,7 @@ export type UIToolInvocation<TOOL extends UITool | Tool> = {
333
334
  approval: {
334
335
  id: string;
335
336
  approved: boolean;
337
+ requestReason?: string;
336
338
  reason?: string;
337
339
  isAutomatic?: boolean;
338
340
  signature?: string;
@@ -349,6 +351,7 @@ export type UIToolInvocation<TOOL extends UITool | Tool> = {
349
351
  approval?: {
350
352
  id: string;
351
353
  approved: true;
354
+ requestReason?: string;
352
355
  reason?: string;
353
356
  isAutomatic?: boolean;
354
357
  signature?: string;
@@ -365,6 +368,7 @@ export type UIToolInvocation<TOOL extends UITool | Tool> = {
365
368
  approval?: {
366
369
  id: string;
367
370
  approved: true;
371
+ requestReason?: string;
368
372
  reason?: string;
369
373
  isAutomatic?: boolean;
370
374
  signature?: string;
@@ -379,6 +383,7 @@ export type UIToolInvocation<TOOL extends UITool | Tool> = {
379
383
  approval: {
380
384
  id: string;
381
385
  approved: false;
386
+ requestReason?: string;
382
387
  reason?: string;
383
388
  isAutomatic?: boolean;
384
389
  signature?: string;
@@ -437,6 +442,7 @@ export type DynamicToolUIPart = {
437
442
  approval: {
438
443
  id: string;
439
444
  approved?: never;
445
+ requestReason?: string;
440
446
  reason?: never;
441
447
  isAutomatic?: boolean;
442
448
  signature?: string;
@@ -451,6 +457,7 @@ export type DynamicToolUIPart = {
451
457
  approval: {
452
458
  id: string;
453
459
  approved: boolean;
460
+ requestReason?: string;
454
461
  reason?: string;
455
462
  isAutomatic?: boolean;
456
463
  signature?: string;
@@ -467,6 +474,7 @@ export type DynamicToolUIPart = {
467
474
  approval?: {
468
475
  id: string;
469
476
  approved: true;
477
+ requestReason?: string;
470
478
  reason?: string;
471
479
  isAutomatic?: boolean;
472
480
  signature?: string;
@@ -482,6 +490,7 @@ export type DynamicToolUIPart = {
482
490
  approval?: {
483
491
  id: string;
484
492
  approved: true;
493
+ requestReason?: string;
485
494
  reason?: string;
486
495
  isAutomatic?: boolean;
487
496
  signature?: string;
@@ -496,6 +505,7 @@ export type DynamicToolUIPart = {
496
505
  approval: {
497
506
  id: string;
498
507
  approved: false;
508
+ requestReason?: string;
499
509
  reason?: string;
500
510
  isAutomatic?: boolean;
501
511
  signature?: string;
@@ -132,6 +132,7 @@ const uiMessagesSchema = lazySchema(() =>
132
132
  approval: z.object({
133
133
  id: z.string(),
134
134
  approved: z.never().optional(),
135
+ requestReason: z.string().optional(),
135
136
  reason: z.never().optional(),
136
137
  isAutomatic: z.boolean().optional(),
137
138
  signature: z.string().optional(),
@@ -151,6 +152,7 @@ const uiMessagesSchema = lazySchema(() =>
151
152
  approval: z.object({
152
153
  id: z.string(),
153
154
  approved: z.boolean(),
155
+ requestReason: z.string().optional(),
154
156
  reason: z.string().optional(),
155
157
  isAutomatic: z.boolean().optional(),
156
158
  signature: z.string().optional(),
@@ -173,6 +175,7 @@ const uiMessagesSchema = lazySchema(() =>
173
175
  .object({
174
176
  id: z.string(),
175
177
  approved: z.literal(true),
178
+ requestReason: z.string().optional(),
176
179
  reason: z.string().optional(),
177
180
  isAutomatic: z.boolean().optional(),
178
181
  signature: z.string().optional(),
@@ -196,6 +199,7 @@ const uiMessagesSchema = lazySchema(() =>
196
199
  .object({
197
200
  id: z.string(),
198
201
  approved: z.literal(true),
202
+ requestReason: z.string().optional(),
199
203
  reason: z.string().optional(),
200
204
  isAutomatic: z.boolean().optional(),
201
205
  signature: z.string().optional(),
@@ -216,6 +220,7 @@ const uiMessagesSchema = lazySchema(() =>
216
220
  approval: z.object({
217
221
  id: z.string(),
218
222
  approved: z.literal(false),
223
+ requestReason: z.string().optional(),
219
224
  reason: z.string().optional(),
220
225
  isAutomatic: z.boolean().optional(),
221
226
  signature: z.string().optional(),
@@ -258,6 +263,7 @@ const uiMessagesSchema = lazySchema(() =>
258
263
  approval: z.object({
259
264
  id: z.string(),
260
265
  approved: z.never().optional(),
266
+ requestReason: z.string().optional(),
261
267
  reason: z.never().optional(),
262
268
  isAutomatic: z.boolean().optional(),
263
269
  signature: z.string().optional(),
@@ -276,6 +282,7 @@ const uiMessagesSchema = lazySchema(() =>
276
282
  approval: z.object({
277
283
  id: z.string(),
278
284
  approved: z.boolean(),
285
+ requestReason: z.string().optional(),
279
286
  reason: z.string().optional(),
280
287
  isAutomatic: z.boolean().optional(),
281
288
  signature: z.string().optional(),
@@ -297,6 +304,7 @@ const uiMessagesSchema = lazySchema(() =>
297
304
  .object({
298
305
  id: z.string(),
299
306
  approved: z.literal(true),
307
+ requestReason: z.string().optional(),
300
308
  reason: z.string().optional(),
301
309
  isAutomatic: z.boolean().optional(),
302
310
  signature: z.string().optional(),
@@ -319,6 +327,7 @@ const uiMessagesSchema = lazySchema(() =>
319
327
  .object({
320
328
  id: z.string(),
321
329
  approved: z.literal(true),
330
+ requestReason: z.string().optional(),
322
331
  reason: z.string().optional(),
323
332
  isAutomatic: z.boolean().optional(),
324
333
  signature: z.string().optional(),
@@ -338,6 +347,7 @@ const uiMessagesSchema = lazySchema(() =>
338
347
  approval: z.object({
339
348
  id: z.string(),
340
349
  approved: z.literal(false),
350
+ requestReason: z.string().optional(),
341
351
  reason: z.string().optional(),
342
352
  isAutomatic: z.boolean().optional(),
343
353
  signature: z.string().optional(),
@@ -254,6 +254,7 @@ export function toUIMessageChunk<
254
254
  type: 'tool-approval-request',
255
255
  approvalId: part.approvalId,
256
256
  toolCallId: part.toolCall.toolCallId,
257
+ ...(part.reason != null ? { reason: part.reason } : {}),
257
258
  ...(part.isAutomatic != null ? { isAutomatic: part.isAutomatic } : {}),
258
259
  ...(part.signature != null ? { signature: part.signature } : {}),
259
260
  };
@@ -85,6 +85,7 @@ export const uiMessageChunkSchema = lazySchema(() =>
85
85
  type: z.literal('tool-approval-request'),
86
86
  approvalId: z.string(),
87
87
  toolCallId: z.string(),
88
+ reason: z.string().optional(),
88
89
  isAutomatic: z.boolean().optional(),
89
90
  signature: z.string().optional(),
90
91
  }),
@@ -298,6 +299,7 @@ export type UIMessageChunk<
298
299
  type: 'tool-approval-request';
299
300
  approvalId: string;
300
301
  toolCallId: string;
302
+ reason?: string;
301
303
  isAutomatic?: boolean;
302
304
  signature?: string;
303
305
  }