ai 7.0.73 → 7.0.76

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.
@@ -92,7 +92,7 @@ import {
92
92
  } from "@ai-sdk/provider-utils";
93
93
 
94
94
  // src/version.ts
95
- var VERSION = true ? "7.0.73" : "0.0.0-test";
95
+ var VERSION = true ? "7.0.76" : "0.0.0-test";
96
96
 
97
97
  // src/util/download/download.ts
98
98
  var download = async ({
@@ -491,10 +491,9 @@ For `embed` and `embedMany`, the integration records spans with `CLIENT` kind:
491
491
  - `gen_ai.provider.name`: the provider
492
492
  - `gen_ai.request.model`: the requested model ID
493
493
 
494
- Attributes set on finish:
495
- - `gen_ai.usage.input_tokens`: the number of tokens used
496
-
497
- - **`embeddings {modelId}`** (inner span, `embedMany` only): one span per provider batch call, nested under the root span.
494
+ - **`embeddings {modelId}`** (inner span): one span per provider request,
495
+ nested under the root span. `embed` creates one inner span. `embedMany`
496
+ creates one inner span per provider batch call.
498
497
 
499
498
  Initial attributes:
500
499
  - `gen_ai.operation.name`: `"embeddings"`
@@ -504,6 +503,9 @@ For `embed` and `embedMany`, the integration records spans with `CLIENT` kind:
504
503
  Attributes set on finish:
505
504
  - `gen_ai.usage.input_tokens`: the number of tokens used
506
505
 
506
+ Usage is recorded only on inner provider-request spans. For `embedMany`, sum
507
+ the usage from the inner spans to get the total usage for the operation.
508
+
507
509
  #### rerank
508
510
 
509
511
  For `rerank`, the integration records spans with `CLIENT` kind:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "7.0.73",
3
+ "version": "7.0.76",
4
4
  "type": "module",
5
5
  "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.",
6
6
  "license": "Apache-2.0",
@@ -42,7 +42,7 @@
42
42
  }
43
43
  },
44
44
  "dependencies": {
45
- "@ai-sdk/gateway": "4.0.59",
45
+ "@ai-sdk/gateway": "4.0.61",
46
46
  "@ai-sdk/provider": "4.0.7",
47
47
  "@ai-sdk/provider-utils": "5.0.28"
48
48
  },
@@ -1160,6 +1160,35 @@ class DefaultStreamTextResult<
1160
1160
  let stepMessagesForNextStep: Array<ModelMessage> | undefined;
1161
1161
  let currentStepMessages: Array<ModelMessage> = [];
1162
1162
 
1163
+ // provider-assigned text/reasoning part IDs are only unique within a
1164
+ // single model call (e.g. Anthropic uses the content block index, which
1165
+ // restarts at 0 for every call), so colliding IDs are remapped to keep
1166
+ // them unique across the whole multi-step stream:
1167
+ const createPartIdReserver = () => {
1168
+ const usedIds = new Set<string>();
1169
+
1170
+ return (id: string) => {
1171
+ if (!usedIds.has(id)) {
1172
+ usedIds.add(id);
1173
+ return id;
1174
+ }
1175
+
1176
+ const generatedId = generateId();
1177
+ let uniqueId = generatedId;
1178
+ let suffix = 0;
1179
+
1180
+ while (usedIds.has(uniqueId)) {
1181
+ uniqueId = `${generatedId}-${++suffix}`;
1182
+ }
1183
+
1184
+ usedIds.add(uniqueId);
1185
+ return uniqueId;
1186
+ };
1187
+ };
1188
+
1189
+ const reserveTextPartId = createPartIdReserver();
1190
+ const reserveReasoningPartId = createPartIdReserver();
1191
+
1163
1192
  // Track provider-executed tool calls that support deferred results
1164
1193
  // (e.g., code_execution in programmatic tool calling scenarios).
1165
1194
  // These tools may not return their results in the same turn as their call.
@@ -2189,6 +2218,11 @@ class DefaultStreamTextResult<
2189
2218
  modelId: model.modelId,
2190
2219
  };
2191
2220
 
2221
+ // maps provider-assigned IDs to stream-unique IDs for the text and
2222
+ // reasoning parts that are active in this step
2223
+ const textPartIds = new Map<string, string>();
2224
+ const reasoningPartIds = new Map<string, string>();
2225
+
2192
2226
  self.addStream(
2193
2227
  streamWithToolResults.pipeThrough(
2194
2228
  new TransformStream<
@@ -2228,11 +2262,6 @@ class DefaultStreamTextResult<
2228
2262
  case 'file':
2229
2263
  case 'custom':
2230
2264
  case 'source':
2231
- case 'text-start':
2232
- case 'text-end':
2233
- case 'reasoning-start':
2234
- case 'reasoning-end':
2235
- case 'reasoning-delta':
2236
2265
  case 'reasoning-file':
2237
2266
  case 'tool-input-start':
2238
2267
  case 'tool-input-end':
@@ -2242,16 +2271,59 @@ class DefaultStreamTextResult<
2242
2271
  break;
2243
2272
  }
2244
2273
 
2274
+ case 'text-start': {
2275
+ const id = reserveTextPartId(chunk.id);
2276
+ textPartIds.set(chunk.id, id);
2277
+ controller.enqueue({ ...chunk, id });
2278
+ break;
2279
+ }
2280
+
2245
2281
  case 'text-delta': {
2246
2282
  if (
2247
2283
  chunk.text.length > 0 ||
2248
2284
  chunk.providerMetadata != null
2249
2285
  ) {
2250
- controller.enqueue(chunk);
2286
+ controller.enqueue({
2287
+ ...chunk,
2288
+ id: textPartIds.get(chunk.id) ?? chunk.id,
2289
+ });
2251
2290
  }
2252
2291
  break;
2253
2292
  }
2254
2293
 
2294
+ case 'text-end': {
2295
+ controller.enqueue({
2296
+ ...chunk,
2297
+ id: textPartIds.get(chunk.id) ?? chunk.id,
2298
+ });
2299
+ textPartIds.delete(chunk.id);
2300
+ break;
2301
+ }
2302
+
2303
+ case 'reasoning-start': {
2304
+ const id = reserveReasoningPartId(chunk.id);
2305
+ reasoningPartIds.set(chunk.id, id);
2306
+ controller.enqueue({ ...chunk, id });
2307
+ break;
2308
+ }
2309
+
2310
+ case 'reasoning-delta': {
2311
+ controller.enqueue({
2312
+ ...chunk,
2313
+ id: reasoningPartIds.get(chunk.id) ?? chunk.id,
2314
+ });
2315
+ break;
2316
+ }
2317
+
2318
+ case 'reasoning-end': {
2319
+ controller.enqueue({
2320
+ ...chunk,
2321
+ id: reasoningPartIds.get(chunk.id) ?? chunk.id,
2322
+ });
2323
+ reasoningPartIds.delete(chunk.id);
2324
+ break;
2325
+ }
2326
+
2255
2327
  case 'tool-call': {
2256
2328
  controller.enqueue(chunk);
2257
2329
  // store tool calls for onEnd callback and toolCalls promise:
@@ -292,59 +292,13 @@ export async function experimental_generateVideo({
292
292
  abortSignal,
293
293
  });
294
294
 
295
- const { prompt, image } = normalizePrompt(promptArg);
296
-
297
- const normalizedFrameImages:
298
- | Array<Experimental_VideoModelV4FrameImage>
299
- | undefined = frameImages?.flatMap(frame => {
300
- const normalizedImage = normalizeImageData(frame.image);
301
- return normalizedImage != null
302
- ? [{ image: normalizedImage, frameType: frame.frameType }]
303
- : [];
304
- });
305
-
306
- const normalizedInputReferences:
307
- | Array<Experimental_VideoModelV4File>
308
- | undefined = inputReferences?.flatMap(reference => {
309
- const normalized = normalizeReferenceData(reference);
310
- return normalized != null ? [normalized] : [];
311
- });
312
-
313
- const effectiveInputReferences =
314
- normalizedFrameImages != null && normalizedFrameImages.length > 0
315
- ? undefined
316
- : normalizedInputReferences;
317
-
318
- const warnings: Array<Warning> = [];
319
-
320
- if (
321
- normalizedFrameImages != null &&
322
- normalizedFrameImages.length > 0 &&
323
- normalizedInputReferences != null &&
324
- normalizedInputReferences.length > 0
325
- ) {
326
- warnings.push({
327
- type: 'other',
328
- message:
329
- 'inputReferences were ignored because frameImages were provided; ' +
330
- 'frameImages and inputReferences cannot be combined.',
331
- });
332
- }
333
-
334
- const firstFrameImage = normalizedFrameImages?.find(
335
- frame => frame.frameType === 'first_frame',
336
- )?.image;
337
-
338
- if (image != null && firstFrameImage != null) {
339
- warnings.push({
340
- type: 'other',
341
- message:
342
- 'prompt.image was ignored because a first_frame frameImage was provided; ' +
343
- 'the first_frame frameImage takes precedence as the start image.',
344
- });
345
- }
346
-
347
- const resolvedImage = firstFrameImage ?? image;
295
+ const {
296
+ prompt,
297
+ resolvedImage,
298
+ normalizedFrameImages,
299
+ effectiveInputReferences,
300
+ warnings,
301
+ } = normalizeVideoCallInputs({ promptArg, frameImages, inputReferences });
348
302
 
349
303
  const maxVideosPerCallWithDefault =
350
304
  maxVideosPerCall ?? (await invokeModelMaxVideosPerCall(model)) ?? 1;
@@ -737,6 +691,94 @@ function normalizePrompt(promptArg: GenerateVideoPrompt): {
737
691
  };
738
692
  }
739
693
 
694
+ /**
695
+ * Shared input normalization for `experimental_generateVideo` and
696
+ * `experimental_startVideo`: prompt/image plus the frameImages /
697
+ * inputReferences precedence rules and their warnings.
698
+ */
699
+ export function normalizeVideoCallInputs({
700
+ promptArg,
701
+ frameImages,
702
+ inputReferences,
703
+ }: {
704
+ promptArg: GenerateVideoPrompt;
705
+ frameImages?: Array<{
706
+ image: DataContent;
707
+ frameType: Experimental_VideoModelV4FrameType;
708
+ }>;
709
+ inputReferences?: Array<
710
+ DataContent | { data: DataContent; mediaType?: string }
711
+ >;
712
+ }): {
713
+ prompt: string | undefined;
714
+ resolvedImage: Experimental_VideoModelV4File | undefined;
715
+ normalizedFrameImages: Array<Experimental_VideoModelV4FrameImage> | undefined;
716
+ effectiveInputReferences: Array<Experimental_VideoModelV4File> | undefined;
717
+ warnings: Array<Warning>;
718
+ } {
719
+ const { prompt, image } = normalizePrompt(promptArg);
720
+
721
+ const normalizedFrameImages:
722
+ | Array<Experimental_VideoModelV4FrameImage>
723
+ | undefined = frameImages?.flatMap(frame => {
724
+ const normalizedImage = normalizeImageData(frame.image);
725
+ return normalizedImage != null
726
+ ? [{ image: normalizedImage, frameType: frame.frameType }]
727
+ : [];
728
+ });
729
+
730
+ const normalizedInputReferences:
731
+ | Array<Experimental_VideoModelV4File>
732
+ | undefined = inputReferences?.flatMap(reference => {
733
+ const normalized = normalizeReferenceData(reference);
734
+ return normalized != null ? [normalized] : [];
735
+ });
736
+
737
+ const effectiveInputReferences =
738
+ normalizedFrameImages != null && normalizedFrameImages.length > 0
739
+ ? undefined
740
+ : normalizedInputReferences;
741
+
742
+ const warnings: Array<Warning> = [];
743
+
744
+ if (
745
+ normalizedFrameImages != null &&
746
+ normalizedFrameImages.length > 0 &&
747
+ normalizedInputReferences != null &&
748
+ normalizedInputReferences.length > 0
749
+ ) {
750
+ warnings.push({
751
+ type: 'other',
752
+ message:
753
+ 'inputReferences were ignored because frameImages were provided; ' +
754
+ 'frameImages and inputReferences cannot be combined.',
755
+ });
756
+ }
757
+
758
+ const firstFrameImage = normalizedFrameImages?.find(
759
+ frame => frame.frameType === 'first_frame',
760
+ )?.image;
761
+
762
+ if (image != null && firstFrameImage != null) {
763
+ warnings.push({
764
+ type: 'other',
765
+ message:
766
+ 'prompt.image was ignored because a first_frame frameImage was provided; ' +
767
+ 'the first_frame frameImage takes precedence as the start image.',
768
+ });
769
+ }
770
+
771
+ const resolvedImage = firstFrameImage ?? image;
772
+
773
+ return {
774
+ prompt,
775
+ resolvedImage,
776
+ normalizedFrameImages,
777
+ effectiveInputReferences,
778
+ warnings,
779
+ };
780
+ }
781
+
740
782
  function detectFileMediaType(
741
783
  data: Uint8Array,
742
784
  restrictToImages: boolean,
@@ -0,0 +1,66 @@
1
+ import type {
2
+ Experimental_VideoModelV4OperationStatusResult,
3
+ JSONValue,
4
+ } from '@ai-sdk/provider';
5
+ import { withUserAgentSuffix } from '@ai-sdk/provider-utils';
6
+ import { resolveVideoModel } from '../model/resolve-model';
7
+ import type { VideoModel } from '../types/video-model';
8
+ import { prepareRetries } from '../util/prepare-retries';
9
+ import { VERSION } from '../version';
10
+
11
+ /**
12
+ * The result of an `experimental_getVideoStatus` call: the spec-level status
13
+ * payload, discriminated by `status` (`pending` | `completed` | `error`).
14
+ */
15
+ export type GetVideoStatusResult =
16
+ Experimental_VideoModelV4OperationStatusResult;
17
+
18
+ /**
19
+ * Checks the status of an asynchronous video generation started with
20
+ * `experimental_startVideo`.
21
+ *
22
+ * A single check — no polling loop. Poll by calling this on your own
23
+ * schedule, or skip polling entirely when the start used `webhookUrl` and
24
+ * your receiver fetches the result after the terminal notification arrives.
25
+ *
26
+ * @param model - The video model the operation was started on.
27
+ * @param operation - The opaque reference returned by `experimental_startVideo`.
28
+ * @param headers - Additional HTTP headers to be sent with the request. Only applicable for HTTP-based providers.
29
+ * @param abortSignal - An optional abort signal that can be used to cancel the call.
30
+ * @param maxRetries - Maximum number of retries for the status call. Set to 0 to disable retries. Default: 2.
31
+ */
32
+ export async function experimental_getVideoStatus(
33
+ modelArg: VideoModel,
34
+ {
35
+ operation,
36
+ headers,
37
+ abortSignal,
38
+ maxRetries: maxRetriesArg,
39
+ }: {
40
+ operation: JSONValue;
41
+ headers?: Record<string, string>;
42
+ abortSignal?: AbortSignal;
43
+ maxRetries?: number;
44
+ },
45
+ ): Promise<GetVideoStatusResult> {
46
+ const model = resolveVideoModel(modelArg);
47
+
48
+ if (model.doStatus == null) {
49
+ throw new Error(
50
+ `Video model ${model.modelId} does not implement doStatus.`,
51
+ );
52
+ }
53
+
54
+ const { retry } = prepareRetries({
55
+ maxRetries: maxRetriesArg,
56
+ abortSignal,
57
+ });
58
+
59
+ return retry(() =>
60
+ model.doStatus!({
61
+ operation,
62
+ headers: withUserAgentSuffix(headers ?? {}, `ai/${VERSION}`),
63
+ abortSignal,
64
+ }),
65
+ );
66
+ }
@@ -1,3 +1,7 @@
1
1
  export type { GenerateVideoPrompt } from './generate-video';
2
2
  export { experimental_generateVideo } from './generate-video';
3
3
  export type { GenerateVideoResult } from './generate-video-result';
4
+ export { experimental_startVideo } from './start-video';
5
+ export type { StartVideoResult } from './start-video';
6
+ export { experimental_getVideoStatus } from './get-video-status';
7
+ export type { GetVideoStatusResult } from './get-video-status';
@@ -0,0 +1,214 @@
1
+ import type {
2
+ Experimental_VideoModelV4CallOptions,
3
+ Experimental_VideoModelV4FrameType,
4
+ JSONValue,
5
+ } from '@ai-sdk/provider';
6
+ import {
7
+ generateId,
8
+ withUserAgentSuffix,
9
+ type DataContent,
10
+ type ProviderOptions,
11
+ } from '@ai-sdk/provider-utils';
12
+ import { resolveVideoModel } from '../model/resolve-model';
13
+ import type {
14
+ VideoModel,
15
+ VideoModelProviderMetadata,
16
+ } from '../types/video-model';
17
+ import type { VideoModelResponseMetadata } from '../types/video-model-response-metadata';
18
+ import type { Warning } from '../types/warning';
19
+ import { prepareRetries } from '../util/prepare-retries';
20
+ import { VERSION } from '../version';
21
+ import {
22
+ normalizeVideoCallInputs,
23
+ type GenerateVideoPrompt,
24
+ } from './generate-video';
25
+
26
+ /**
27
+ * The result of an `experimental_startVideo` call.
28
+ */
29
+ export interface StartVideoResult {
30
+ /**
31
+ * JSON-serializable opaque reference to the started generation.
32
+ * Persist it and pass it to `experimental_getVideoStatus` to retrieve the
33
+ * status and result later — from any process.
34
+ */
35
+ readonly operation: JSONValue;
36
+
37
+ /**
38
+ * Warnings for the call, e.g. unsupported settings.
39
+ */
40
+ readonly warnings: Array<Warning>;
41
+
42
+ /**
43
+ * Provider-specific metadata passed through from the provider.
44
+ * Carries the provider's own job identifiers (e.g. the AI Gateway's
45
+ * `providerMetadata.gateway.asyncJob.jobId` and, when `webhookUrl` was
46
+ * given, its `webhookSigningSecret`).
47
+ */
48
+ readonly providerMetadata?: VideoModelProviderMetadata;
49
+
50
+ /**
51
+ * Response metadata from the provider.
52
+ */
53
+ readonly response: VideoModelResponseMetadata;
54
+ }
55
+
56
+ /**
57
+ * Starts an asynchronous video generation and returns immediately with an
58
+ * opaque `operation` reference — without waiting for the video to finish.
59
+ *
60
+ * This is the fire-and-forget counterpart to `experimental_generateVideo`:
61
+ * use it to fan out many jobs, to submit from a process that will not stay
62
+ * alive, or together with `webhookUrl` so the provider notifies your endpoint
63
+ * at the terminal state. Check the outcome with `experimental_getVideoStatus`,
64
+ * or let your webhook receiver fetch the result.
65
+ *
66
+ * @param model - The video model to use. Must implement `doStart`.
67
+ * @param prompt - The prompt that should be used to generate the video.
68
+ * @param n - Number of videos to generate. Default: 1. Must not exceed the
69
+ * model's `maxVideosPerCall` — fan out with multiple `startVideo` calls.
70
+ * @param aspectRatio - Aspect ratio of the videos to generate. Must have the format `{width}:{height}`, or `'adaptive'`.
71
+ * @param resolution - Resolution of the videos to generate. Must have the format `{width}x${height}`.
72
+ * @param duration - Duration of the video in seconds.
73
+ * @param fps - Frames per second for the video.
74
+ * @param seed - Seed for the video generation.
75
+ * @param frameImages - Role-tagged image inputs for image-to-video and first-last-frame generation.
76
+ * @param inputReferences - Reference image or video inputs for reference-to-video generation.
77
+ * @param generateAudio - Whether the model should generate audio alongside the video.
78
+ * @param providerOptions - Additional provider-specific options that are passed through to the provider
79
+ * as body parameters.
80
+ * @param maxRetries - Maximum number of retries for the start call. Set to 0 to disable retries. Default: 2.
81
+ * @param abortSignal - An optional abort signal that can be used to cancel the call.
82
+ * @param headers - Additional HTTP headers to be sent with the request. Only applicable for HTTP-based providers.
83
+ * @param webhookUrl - A URL the provider should notify when the generation
84
+ * reaches a terminal state.
85
+ *
86
+ * @returns A result object that contains the opaque `operation` reference,
87
+ * warnings, provider metadata (including the provider's job id), and response
88
+ * metadata.
89
+ */
90
+ export async function experimental_startVideo({
91
+ model: modelArg,
92
+ prompt: promptArg,
93
+ n = 1,
94
+ maxVideosPerCall,
95
+ aspectRatio,
96
+ resolution,
97
+ duration,
98
+ fps,
99
+ seed,
100
+ frameImages,
101
+ inputReferences,
102
+ generateAudio,
103
+ providerOptions,
104
+ maxRetries: maxRetriesArg,
105
+ abortSignal,
106
+ headers,
107
+ webhookUrl,
108
+ }: {
109
+ model: VideoModel;
110
+ prompt: GenerateVideoPrompt;
111
+ n?: number;
112
+ maxVideosPerCall?: number;
113
+ aspectRatio?: `${number}:${number}` | 'adaptive';
114
+ resolution?: `${number}x${number}`;
115
+ duration?: number;
116
+ fps?: number;
117
+ seed?: number;
118
+ frameImages?: Array<{
119
+ image: DataContent;
120
+ frameType: Experimental_VideoModelV4FrameType;
121
+ }>;
122
+ inputReferences?: Array<
123
+ DataContent | { data: DataContent; mediaType?: string }
124
+ >;
125
+ generateAudio?: boolean;
126
+ providerOptions?: ProviderOptions;
127
+ maxRetries?: number;
128
+ abortSignal?: AbortSignal;
129
+ headers?: Record<string, string>;
130
+ webhookUrl?: string;
131
+ }): Promise<StartVideoResult> {
132
+ const model = resolveVideoModel(modelArg);
133
+
134
+ if (model.doStart == null) {
135
+ throw new Error(
136
+ `Video model ${model.modelId} does not implement doStart. ` +
137
+ 'Use generateVideo for models without an asynchronous start/status flow.',
138
+ );
139
+ }
140
+
141
+ if (!Number.isInteger(n) || n < 1) {
142
+ throw new Error(
143
+ `Invalid n: expected a positive integer, received ${JSON.stringify(n)}.`,
144
+ );
145
+ }
146
+
147
+ // A start yields one operation covering all n videos: refuse to silently
148
+ // exceed a known per-call limit instead of splitting into several starts.
149
+ const knownMaxVideosPerCall =
150
+ maxVideosPerCall ??
151
+ (typeof model.maxVideosPerCall === 'function'
152
+ ? await model.maxVideosPerCall({ modelId: model.modelId })
153
+ : model.maxVideosPerCall);
154
+ if (knownMaxVideosPerCall != null && n > knownMaxVideosPerCall) {
155
+ throw new Error(
156
+ `Video model ${model.modelId} supports at most ${knownMaxVideosPerCall} video(s) per call, ` +
157
+ `but ${n} were requested. Split the batch across multiple startVideo calls.`,
158
+ );
159
+ }
160
+
161
+ const {
162
+ prompt,
163
+ resolvedImage,
164
+ normalizedFrameImages,
165
+ effectiveInputReferences,
166
+ warnings,
167
+ } = normalizeVideoCallInputs({ promptArg, frameImages, inputReferences });
168
+
169
+ const { retry } = prepareRetries({
170
+ maxRetries: maxRetriesArg,
171
+ abortSignal,
172
+ });
173
+
174
+ // `doStart` is billable: mint one idempotency token per logical start,
175
+ // outside the retry closure; a caller-supplied key wins.
176
+ const callerIdempotencyKey = Object.entries(headers ?? {}).find(
177
+ ([key, value]) =>
178
+ key.toLowerCase() === 'idempotency-key' && value !== undefined,
179
+ );
180
+
181
+ const callOptions: Experimental_VideoModelV4CallOptions & {
182
+ webhookUrl?: string;
183
+ } = {
184
+ prompt,
185
+ n,
186
+ aspectRatio,
187
+ resolution,
188
+ duration,
189
+ fps,
190
+ seed,
191
+ image: resolvedImage,
192
+ frameImages: normalizedFrameImages,
193
+ inputReferences: effectiveInputReferences,
194
+ generateAudio,
195
+ providerOptions: providerOptions ?? {},
196
+ headers: {
197
+ ...withUserAgentSuffix(headers ?? {}, `ai/${VERSION}`),
198
+ ...(callerIdempotencyKey
199
+ ? {}
200
+ : { 'idempotency-key': `aisdk_vid_${generateId()}` }),
201
+ },
202
+ abortSignal,
203
+ webhookUrl,
204
+ };
205
+
206
+ const startResult = await retry(() => model.doStart!(callOptions));
207
+
208
+ return {
209
+ operation: startResult.operation,
210
+ warnings: [...warnings, ...startResult.warnings],
211
+ providerMetadata: startResult.providerMetadata,
212
+ response: startResult.response,
213
+ };
214
+ }
package/src/ui/chat.ts CHANGED
@@ -191,7 +191,7 @@ export interface ChatInit<UI_MESSAGE extends UIMessage> {
191
191
  */
192
192
  id?: string;
193
193
 
194
- messageMetadataSchema?: FlexibleSchema<InferUIMessageMetadata<UI_MESSAGE>>;
194
+ messageMetadataSchema?: FlexibleSchema<UI_MESSAGE['metadata']>;
195
195
  dataPartSchemas?: UIDataTypesToSchemas<InferUIMessageData<UI_MESSAGE>>;
196
196
 
197
197
  messages?: UI_MESSAGE[];
@@ -246,7 +246,7 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
246
246
  protected state: ChatState<UI_MESSAGE>;
247
247
 
248
248
  private messageMetadataSchema:
249
- | FlexibleSchema<InferUIMessageMetadata<UI_MESSAGE>>
249
+ | FlexibleSchema<UI_MESSAGE['metadata']>
250
250
  | undefined;
251
251
  private dataPartSchemas:
252
252
  | UIDataTypesToSchemas<InferUIMessageData<UI_MESSAGE>>
@@ -90,7 +90,7 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
90
90
  }: {
91
91
  // input stream is not fully typed yet:
92
92
  stream: ReadableStream<UIMessageChunk>;
93
- messageMetadataSchema?: FlexibleSchema<InferUIMessageMetadata<UI_MESSAGE>>;
93
+ messageMetadataSchema?: FlexibleSchema<UI_MESSAGE['metadata']>;
94
94
  dataPartSchemas?: UIDataTypesToSchemas<InferUIMessageData<UI_MESSAGE>>;
95
95
  onToolCall?: (options: {
96
96
  toolCall: InferUIMessageToolCall<UI_MESSAGE>;