ai 7.0.54 → 7.0.56

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.
@@ -1399,6 +1399,8 @@ type LanguageModelCallEndEvent<TOOLS extends ToolSet = ToolSet> = ModelInfo & {
1399
1399
  readonly content: ReadonlyArray<ContentPart<TOOLS>>;
1400
1400
  /** The provider-returned response id for this model call. */
1401
1401
  readonly responseId: string;
1402
+ /** Optional provider-specific metadata for this model call. */
1403
+ readonly providerMetadata?: ProviderMetadata;
1402
1404
  /** Performance metrics for the model call. */
1403
1405
  readonly performance: {
1404
1406
  /** Time spent waiting for the language model response in milliseconds. */
@@ -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.54" : "0.0.0-test";
95
+ var VERSION = true ? "7.0.56" : "0.0.0-test";
96
96
 
97
97
  // src/util/download/download.ts
98
98
  var download = async ({
@@ -187,7 +187,7 @@ The available lifecycle callbacks are:
187
187
  - **`onStart`**: Called once when the `generateText` operation begins, before any LLM calls. Receives model info, messages, settings, and `runtimeContext`.
188
188
  - **`onStepStart`**: Called before each step (LLM call). Receives the step number, model, messages being sent, tools, and prior steps.
189
189
  - **`onLanguageModelCallStart`**: Called immediately before the provider model call begins. Useful when you want to observe the model invocation separately from later tool execution.
190
- - **`onLanguageModelCallEnd`**: Called after the model response has been normalized and parsed, but before any client-side tool execution begins. Receives the model-call content parts, usage, and finish reason.
190
+ - **`onLanguageModelCallEnd`**: Called after the model response has been normalized and parsed, but before any client-side tool execution begins. Receives the model-call content parts, usage, finish reason, and provider metadata.
191
191
  - **`onToolExecutionStart`**: Called right before a tool's `execute` function runs. Receives the tool call object, messages, and `toolContext`.
192
192
  - **`onToolExecutionEnd`**: Called right after a tool's `execute` function completes or errors. Receives the tool call object, `toolExecutionMs`, and a `toolOutput` discriminated union (`type: 'tool-result'` with `output`, or `type: 'tool-error'` with `error`).
193
193
  - **`onStepEnd`**: Called after each step finishes. Includes `stepNumber` (zero-based index of the completed step).
@@ -417,7 +417,7 @@ The available lifecycle callbacks are:
417
417
  - **`onStart`**: Called once when the `streamText` operation begins, before any LLM calls. Receives model info, messages, settings, and `runtimeContext`.
418
418
  - **`onStepStart`**: Called before each step (LLM call). Receives the step number, model, messages being sent, tools, and prior steps.
419
419
  - **`onLanguageModelCallStart`**: Called immediately before the provider model call begins. Useful when you want to observe the model invocation separately from later tool execution.
420
- - **`onLanguageModelCallEnd`**: Called after the model response has been normalized and parsed, but before any client-side tool execution begins. Receives the model-call content parts, usage, and finish reason.
420
+ - **`onLanguageModelCallEnd`**: Called after the model response has been normalized and parsed, but before any client-side tool execution begins. Receives the model-call content parts, usage, finish reason, and provider metadata.
421
421
  - **`onToolExecutionStart`**: Called right before a tool's `execute` function runs. Receives the tool call object, messages, and `toolContext`.
422
422
  - **`onToolExecutionEnd`**: Called right after a tool's `execute` function completes or errors. Receives the tool call object, `toolExecutionMs`, and a `toolOutput` discriminated union (`type: 'tool-result'` with `output`, or `type: 'tool-error'` with `error`).
423
423
  - **`onStepEnd`**: Called after each step finishes. Receives the finish reason, usage, and other step details.
@@ -356,7 +356,7 @@ export function myIntegration(): Telemetry {
356
356
  name: 'onLanguageModelCallEnd',
357
357
  type: '(event: LanguageModelCallEndEvent) => void | PromiseLike<void>',
358
358
  description:
359
- 'Called after the model response has been normalized and parsed, but before any client-side tool execution begins.',
359
+ 'Called after the model response has been normalized and parsed, but before any client-side tool execution begins. Includes provider-specific metadata when available.',
360
360
  },
361
361
  {
362
362
  name: 'onToolExecutionStart',
@@ -628,7 +628,7 @@ registerTelemetry(
628
628
  The available options are:
629
629
 
630
630
  - `usage`: detailed usage attributes that are not covered by GenAI usage attributes, such as uncached input tokens and output text/reasoning token details.
631
- - `providerMetadata`: `ai.response.providerMetadata`.
631
+ - `providerMetadata`: `ai.response.providerMetadata` on operation, step, and model-call spans.
632
632
  - `embedding`: embedding inputs and outputs.
633
633
  - `reranking`: rerank input documents and ranking output.
634
634
  - `runtimeContext`: `ai.settings.context.*`.
@@ -97,7 +97,13 @@ const result = streamText({
97
97
  model: __MODEL__,
98
98
  prompt: 'Explain partial prerendering in two paragraphs.',
99
99
 
100
- onLanguageModelCallEnd({ callId, modelId, usage, performance }) {
100
+ onLanguageModelCallEnd({
101
+ callId,
102
+ modelId,
103
+ usage,
104
+ performance,
105
+ providerMetadata,
106
+ }) {
101
107
  metrics.histogram('ai.model.response_time_ms', performance.responseTimeMs, {
102
108
  callId,
103
109
  modelId,
@@ -108,6 +114,11 @@ const result = streamText({
108
114
  total: performance.effectiveTotalTokensPerSecond,
109
115
  tokens: usage.totalTokens,
110
116
  });
117
+
118
+ logger.info('ai.model.provider_metadata', {
119
+ callId,
120
+ providerMetadata,
121
+ });
111
122
  },
112
123
  });
113
124
 
@@ -675,6 +686,12 @@ Called after the provider response has been normalized and parsed, before local
675
686
  type: 'string',
676
687
  description: 'Provider-returned response ID for this model call.',
677
688
  },
689
+ {
690
+ name: 'providerMetadata',
691
+ type: 'ProviderMetadata | undefined',
692
+ description:
693
+ 'Provider-specific metadata for this model call, when returned by the provider.',
694
+ },
678
695
  {
679
696
  name: 'performance',
680
697
  type: 'LanguageModelCallPerformance',
@@ -1438,6 +1438,12 @@ To see `generateText` in action, check out [these examples](#examples).
1438
1438
  description:
1439
1439
  'The provider-returned response ID for this model call.',
1440
1440
  },
1441
+ {
1442
+ name: 'providerMetadata',
1443
+ type: 'ProviderMetadata | undefined',
1444
+ description:
1445
+ 'Provider-specific metadata for this model call, when returned by the provider.',
1446
+ },
1441
1447
  {
1442
1448
  name: 'performance',
1443
1449
  type: '{ responseTimeMs: number; effectiveOutputTokensPerSecond: number; outputTokensPerSecond: number | undefined; inputTokensPerSecond: number | undefined; effectiveTotalTokensPerSecond: number; timeToFirstOutputMs: number | undefined; timeBetweenOutputChunksMs?: OutputChunkTimingStats }',
@@ -2422,6 +2422,12 @@ To see `streamText` in action, check out [these examples](#examples).
2422
2422
  description:
2423
2423
  'The provider-returned response ID for this model call.',
2424
2424
  },
2425
+ {
2426
+ name: 'providerMetadata',
2427
+ type: 'ProviderMetadata | undefined',
2428
+ description:
2429
+ 'Provider-specific metadata for this model call, when returned by the provider.',
2430
+ },
2425
2431
  {
2426
2432
  name: 'performance',
2427
2433
  type: '{ responseTimeMs: number; effectiveOutputTokensPerSecond: number; outputTokensPerSecond: number | undefined; inputTokensPerSecond: number | undefined; effectiveTotalTokensPerSecond: number; timeToFirstOutputMs: number | undefined; timeBetweenOutputChunksMs?: OutputChunkTimingStats }',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "7.0.54",
3
+ "version": "7.0.56",
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,9 +42,9 @@
42
42
  }
43
43
  },
44
44
  "dependencies": {
45
- "@ai-sdk/gateway": "4.0.42",
46
- "@ai-sdk/provider": "4.0.5",
47
- "@ai-sdk/provider-utils": "5.0.22"
45
+ "@ai-sdk/gateway": "4.0.44",
46
+ "@ai-sdk/provider": "4.0.6",
47
+ "@ai-sdk/provider-utils": "5.0.23"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@edge-runtime/vm": "^5.0.0",
@@ -0,0 +1,134 @@
1
+ import type {
2
+ Experimental_BatchV4Error as BatchV4Error,
3
+ Experimental_BatchV4StartResult as BatchV4StartResult,
4
+ Experimental_BatchV4Status as BatchV4Status,
5
+ Experimental_BatchLanguageModelV4 as BatchLanguageModelV4,
6
+ } from '@ai-sdk/provider';
7
+ import type { ProviderOptions } from '@ai-sdk/provider-utils';
8
+ import type { LanguageModelCallOptions } from '../prompt/language-model-call-options';
9
+ import type { Prompt } from '../prompt/prompt';
10
+ import type {
11
+ FinishReason,
12
+ GlobalProviderModelId,
13
+ } from '../types/language-model';
14
+ import type { ProviderMetadata } from '../types/provider-metadata';
15
+ import type { LanguageModelUsage } from '../types/usage';
16
+
17
+ /**
18
+ * Language model input that can be used for durable batch processing.
19
+ *
20
+ * String model IDs are resolved through the global provider and checked for
21
+ * batch support at runtime.
22
+ */
23
+ export type BatchLanguageModel = GlobalProviderModelId | BatchLanguageModelV4;
24
+
25
+ /**
26
+ * The persisted reference for a text batch.
27
+ */
28
+ export type TextBatchReference = {
29
+ readonly version: 1;
30
+ readonly type: 'text';
31
+ readonly id: string;
32
+ readonly provider: string;
33
+ readonly modelId: string;
34
+ };
35
+
36
+ /**
37
+ * Persisted reference for any supported batch type.
38
+ *
39
+ * Additional modality-specific references can be added to this union.
40
+ */
41
+ export type BatchReference = TextBatchReference;
42
+
43
+ /**
44
+ * Serializable error information for a batch or batch item.
45
+ */
46
+ export type BatchError = BatchV4Error;
47
+
48
+ /**
49
+ * The latest normalized lifecycle status for a batch.
50
+ */
51
+ export type BatchStatus = BatchV4Status;
52
+
53
+ /**
54
+ * A text batch and its latest normalized lifecycle status.
55
+ */
56
+ export type TextBatch = TextBatchReference & BatchStatus;
57
+
58
+ /**
59
+ * One text generation request within a batch.
60
+ */
61
+ export type TextBatchRequest = Prompt &
62
+ LanguageModelCallOptions & {
63
+ id: string;
64
+ providerOptions?: ProviderOptions;
65
+ };
66
+
67
+ type BatchRequestOptions = {
68
+ abortSignal?: AbortSignal;
69
+ headers?: Record<string, string | undefined>;
70
+ timeout?: number | { totalMs?: number };
71
+ };
72
+
73
+ /**
74
+ * Options for starting a text batch.
75
+ */
76
+ export type StartTextBatchOptions = {
77
+ model: BatchLanguageModel;
78
+ requests: ReadonlyArray<TextBatchRequest>;
79
+ providerOptions?: ProviderOptions;
80
+ } & BatchRequestOptions;
81
+
82
+ /**
83
+ * The acknowledged text batch and warnings produced while starting it.
84
+ */
85
+ export type StartTextBatchResult = TextBatch & {
86
+ readonly warnings: BatchV4StartResult['warnings'];
87
+ };
88
+
89
+ /**
90
+ * Options shared by batch status and result retrieval operations.
91
+ */
92
+ export type BatchOperationOptions = {
93
+ model: BatchLanguageModel;
94
+ batch: BatchReference;
95
+ providerOptions?: ProviderOptions;
96
+ maxRetries?: number;
97
+ } & BatchRequestOptions;
98
+
99
+ /**
100
+ * A normalized result for a successful text batch item.
101
+ */
102
+ export type TextBatchGenerationResult = {
103
+ readonly text: string;
104
+ readonly finishReason: FinishReason;
105
+ readonly rawFinishReason?: string;
106
+ readonly usage: LanguageModelUsage;
107
+ readonly response?: {
108
+ readonly id?: string;
109
+ readonly timestamp?: string;
110
+ readonly modelId?: string;
111
+ };
112
+ readonly providerMetadata?: ProviderMetadata;
113
+ };
114
+
115
+ /**
116
+ * A complete terminal result for one request in a text batch.
117
+ */
118
+ export type TextBatchItemResult =
119
+ | (TextBatchGenerationResult & {
120
+ readonly id: string;
121
+ readonly status: 'succeeded';
122
+ })
123
+ | {
124
+ readonly id: string;
125
+ readonly status: 'failed';
126
+ readonly error: BatchError;
127
+ readonly providerMetadata?: ProviderMetadata;
128
+ }
129
+ | {
130
+ readonly id: string;
131
+ readonly status: 'cancelled' | 'expired';
132
+ readonly error?: BatchError;
133
+ readonly providerMetadata?: ProviderMetadata;
134
+ };
@@ -0,0 +1,336 @@
1
+ import {
2
+ UnsupportedFunctionalityError,
3
+ type Experimental_BatchLanguageModelV4 as BatchLanguageModelV4,
4
+ type Experimental_BatchV4ItemResult as BatchV4ItemResult,
5
+ type LanguageModelV4,
6
+ type LanguageModelV4GenerateResult,
7
+ } from '@ai-sdk/provider';
8
+ import { withUserAgentSuffix } from '@ai-sdk/provider-utils';
9
+ import { InvalidArgumentError } from '../error/invalid-argument-error';
10
+ import { logWarnings } from '../logger/log-warnings';
11
+ import { resolveLanguageModel } from '../model/resolve-model';
12
+ import { convertToLanguageModelPrompt } from '../prompt/convert-to-language-model-prompt';
13
+ import { prepareLanguageModelCallOptions } from '../prompt/prepare-language-model-call-options';
14
+ import { getTotalTimeoutMs } from '../prompt/request-options';
15
+ import { standardizePrompt } from '../prompt/standardize-prompt';
16
+ import { wrapGatewayError } from '../prompt/wrap-gateway-error';
17
+ import { asLanguageModelUsage } from '../types/usage';
18
+ import { asAsyncIterableStream } from '../util/async-iterable-stream';
19
+ import { mergeAbortSignals } from '../util/merge-abort-signals';
20
+ import { prepareRetries } from '../util/prepare-retries';
21
+ import { VERSION } from '../version';
22
+ import type {
23
+ BatchOperationOptions,
24
+ BatchReference,
25
+ BatchStatus,
26
+ StartTextBatchOptions,
27
+ StartTextBatchResult,
28
+ TextBatchGenerationResult,
29
+ TextBatchItemResult,
30
+ TextBatchRequest,
31
+ } from './batch-types';
32
+
33
+ /**
34
+ * Starts a durable text-generation batch.
35
+ */
36
+ export async function startTextBatch({
37
+ model: modelArg,
38
+ requests,
39
+ providerOptions,
40
+ abortSignal,
41
+ headers,
42
+ timeout,
43
+ }: StartTextBatchOptions): Promise<StartTextBatchResult> {
44
+ validateRequests(requests);
45
+
46
+ const model = resolveBatchLanguageModel(modelArg);
47
+ const operationAbortSignal = mergeAbortSignals(
48
+ abortSignal,
49
+ getTotalTimeoutMs(timeout),
50
+ );
51
+ const supportedUrls = await model.supportedUrls;
52
+ operationAbortSignal?.throwIfAborted();
53
+ const normalizedRequests = [];
54
+
55
+ for (const request of requests) {
56
+ const standardizedPrompt = await standardizePrompt(request);
57
+
58
+ normalizedRequests.push({
59
+ id: request.id,
60
+ options: {
61
+ ...prepareLanguageModelCallOptions(request),
62
+ prompt: await convertToLanguageModelPrompt({
63
+ prompt: standardizedPrompt,
64
+ supportedUrls,
65
+ download: undefined,
66
+ provider: model.provider.split('.')[0],
67
+ }),
68
+ providerOptions: request.providerOptions,
69
+ },
70
+ });
71
+ operationAbortSignal?.throwIfAborted();
72
+ }
73
+
74
+ const headersWithUserAgent = withUserAgentSuffix(
75
+ headers ?? {},
76
+ `ai/${VERSION}`,
77
+ );
78
+ try {
79
+ const result = await model.experimental_doStartBatch({
80
+ requests: normalizedRequests,
81
+ providerOptions,
82
+ abortSignal: operationAbortSignal,
83
+ headers: headersWithUserAgent,
84
+ });
85
+ const { batchId, warnings, ...status } = result;
86
+
87
+ logWarnings({
88
+ warnings: warnings.map(({ warning }) => warning),
89
+ provider: model.provider,
90
+ model: model.modelId,
91
+ });
92
+
93
+ return {
94
+ version: 1,
95
+ type: 'text',
96
+ id: batchId,
97
+ provider: model.provider,
98
+ modelId: model.modelId,
99
+ ...status,
100
+ warnings,
101
+ };
102
+ } catch (error) {
103
+ throw wrapGatewayError(error);
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Retrieves the latest normalized status for a durable batch.
109
+ */
110
+ export async function getBatchStatus({
111
+ model: modelArg,
112
+ batch,
113
+ providerOptions,
114
+ maxRetries,
115
+ abortSignal,
116
+ headers,
117
+ timeout,
118
+ }: BatchOperationOptions): Promise<BatchStatus> {
119
+ const model = resolveBatchLanguageModel(modelArg);
120
+ validateBatchReference({ model, batch });
121
+
122
+ const operationAbortSignal = mergeAbortSignals(
123
+ abortSignal,
124
+ getTotalTimeoutMs(timeout),
125
+ );
126
+ const { retry } = prepareRetries({
127
+ maxRetries,
128
+ abortSignal: operationAbortSignal,
129
+ });
130
+
131
+ try {
132
+ const status = await retry(() =>
133
+ model.experimental_doGetBatchStatus({
134
+ batchId: batch.id,
135
+ providerOptions,
136
+ abortSignal: operationAbortSignal,
137
+ headers: withUserAgentSuffix(headers ?? {}, `ai/${VERSION}`),
138
+ }),
139
+ );
140
+
141
+ return status;
142
+ } catch (error) {
143
+ throw wrapGatewayError(error);
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Streams complete terminal results for the requests in a durable batch.
149
+ */
150
+ export function getBatchResults({
151
+ model: modelArg,
152
+ batch,
153
+ providerOptions,
154
+ maxRetries,
155
+ abortSignal,
156
+ headers,
157
+ timeout,
158
+ }: BatchOperationOptions) {
159
+ const model = resolveBatchLanguageModel(modelArg);
160
+ validateBatchReference({ model, batch });
161
+
162
+ const streamAbortController = new AbortController();
163
+ const operationAbortSignal = mergeAbortSignals(
164
+ abortSignal,
165
+ getTotalTimeoutMs(timeout),
166
+ streamAbortController.signal,
167
+ );
168
+ const { retry } = prepareRetries({
169
+ maxRetries,
170
+ abortSignal: operationAbortSignal,
171
+ });
172
+ const transformer: Transformer<
173
+ BatchV4ItemResult<LanguageModelV4GenerateResult>,
174
+ TextBatchItemResult
175
+ > & { cancel?: (reason?: unknown) => void } = {
176
+ transform(item, controller) {
177
+ controller.enqueue(convertBatchItemResult(item));
178
+ },
179
+
180
+ cancel(reason) {
181
+ streamAbortController.abort(
182
+ reason ?? new Error('Batch results stream was cancelled.'),
183
+ );
184
+ },
185
+ };
186
+ const transform = new TransformStream<
187
+ BatchV4ItemResult<LanguageModelV4GenerateResult>,
188
+ TextBatchItemResult
189
+ >(transformer);
190
+
191
+ void (async () => {
192
+ try {
193
+ const stream = await retry(() =>
194
+ model.experimental_doGetBatchResults({
195
+ batchId: batch.id,
196
+ providerOptions,
197
+ abortSignal: operationAbortSignal,
198
+ headers: withUserAgentSuffix(headers ?? {}, `ai/${VERSION}`),
199
+ }),
200
+ );
201
+
202
+ await stream.pipeTo(transform.writable, {
203
+ signal: operationAbortSignal,
204
+ });
205
+ } catch (error) {
206
+ await transform.writable.abort(wrapGatewayError(error)).catch(() => {});
207
+ }
208
+ })();
209
+
210
+ return asAsyncIterableStream(transform.readable);
211
+ }
212
+
213
+ function resolveBatchLanguageModel(
214
+ modelArg: StartTextBatchOptions['model'],
215
+ ): BatchLanguageModelV4 {
216
+ const model = resolveLanguageModel(modelArg);
217
+
218
+ if (!isBatchLanguageModel(model)) {
219
+ throw new UnsupportedFunctionalityError({
220
+ functionality: 'batch processing',
221
+ message: `The ${model.provider} model "${model.modelId}" does not support batch processing.`,
222
+ });
223
+ }
224
+
225
+ return model;
226
+ }
227
+
228
+ function isBatchLanguageModel(
229
+ model: LanguageModelV4,
230
+ ): model is BatchLanguageModelV4 {
231
+ const candidate = model as Partial<BatchLanguageModelV4>;
232
+ return (
233
+ typeof candidate.experimental_doStartBatch === 'function' &&
234
+ typeof candidate.experimental_doGetBatchStatus === 'function' &&
235
+ typeof candidate.experimental_doGetBatchResults === 'function'
236
+ );
237
+ }
238
+
239
+ function validateRequests(requests: ReadonlyArray<TextBatchRequest>) {
240
+ if (requests.length === 0) {
241
+ throw new InvalidArgumentError({
242
+ parameter: 'requests',
243
+ value: requests,
244
+ message: 'requests must not be empty',
245
+ });
246
+ }
247
+
248
+ const ids = new Set<string>();
249
+
250
+ for (const request of requests) {
251
+ if (request.id.trim().length === 0) {
252
+ throw new InvalidArgumentError({
253
+ parameter: 'requests',
254
+ value: requests,
255
+ message: 'request IDs must not be empty',
256
+ });
257
+ }
258
+
259
+ if (ids.has(request.id)) {
260
+ throw new InvalidArgumentError({
261
+ parameter: 'requests',
262
+ value: requests,
263
+ message: `request IDs must be unique; duplicate ID "${request.id}"`,
264
+ });
265
+ }
266
+
267
+ ids.add(request.id);
268
+ }
269
+ }
270
+
271
+ function validateBatchReference({
272
+ model,
273
+ batch,
274
+ }: {
275
+ model: BatchLanguageModelV4;
276
+ batch: BatchReference;
277
+ }) {
278
+ if (batch.version !== 1 || batch.type !== 'text') {
279
+ throw new InvalidArgumentError({
280
+ parameter: 'batch',
281
+ value: batch,
282
+ message: 'batch must be a supported text batch reference',
283
+ });
284
+ }
285
+
286
+ if (batch.provider !== model.provider || batch.modelId !== model.modelId) {
287
+ throw new InvalidArgumentError({
288
+ parameter: 'model',
289
+ value: model,
290
+ message:
291
+ `model ${model.provider}:${model.modelId} is not compatible with ` +
292
+ `batch ${batch.provider}:${batch.modelId}`,
293
+ });
294
+ }
295
+ }
296
+
297
+ function convertBatchItemResult(
298
+ item: BatchV4ItemResult<LanguageModelV4GenerateResult>,
299
+ ): TextBatchItemResult {
300
+ if (item.status !== 'succeeded') {
301
+ return item;
302
+ }
303
+
304
+ return {
305
+ id: item.id,
306
+ status: 'succeeded',
307
+ ...convertGenerateResult(item.result),
308
+ };
309
+ }
310
+
311
+ function convertGenerateResult(
312
+ result: LanguageModelV4GenerateResult,
313
+ ): TextBatchGenerationResult {
314
+ return {
315
+ text: result.content
316
+ .filter(
317
+ (part): part is Extract<typeof part, { type: 'text' }> =>
318
+ part.type === 'text',
319
+ )
320
+ .map(part => part.text)
321
+ .join(''),
322
+ finishReason: result.finishReason.unified,
323
+ rawFinishReason: result.finishReason.raw,
324
+ usage: asLanguageModelUsage(result.usage),
325
+ ...(result.response != null
326
+ ? {
327
+ response: {
328
+ id: result.response.id,
329
+ timestamp: result.response.timestamp?.toISOString(),
330
+ modelId: result.response.modelId,
331
+ },
332
+ }
333
+ : {}),
334
+ providerMetadata: result.providerMetadata,
335
+ };
336
+ }
@@ -0,0 +1,19 @@
1
+ export {
2
+ startTextBatch as experimental_startTextBatch,
3
+ getBatchResults as experimental_getBatchResults,
4
+ getBatchStatus as experimental_getBatchStatus,
5
+ } from './batch';
6
+ export type {
7
+ BatchError as Experimental_BatchError,
8
+ BatchLanguageModel as Experimental_BatchLanguageModel,
9
+ BatchOperationOptions as Experimental_BatchOperationOptions,
10
+ BatchReference as Experimental_BatchReference,
11
+ BatchStatus as Experimental_BatchStatus,
12
+ StartTextBatchOptions as Experimental_StartTextBatchOptions,
13
+ StartTextBatchResult as Experimental_StartTextBatchResult,
14
+ TextBatch as Experimental_TextBatch,
15
+ TextBatchGenerationResult as Experimental_TextBatchGenerationResult,
16
+ TextBatchItemResult as Experimental_TextBatchItemResult,
17
+ TextBatchReference as Experimental_TextBatchReference,
18
+ TextBatchRequest as Experimental_TextBatchRequest,
19
+ } from './batch-types';
@@ -1085,6 +1085,11 @@ export async function generateText<
1085
1085
  usage: stepUsage,
1086
1086
  content: modelCallContent,
1087
1087
  responseId: currentModelResponse.response.id,
1088
+ ...(currentModelResponse.providerMetadata != null
1089
+ ? {
1090
+ providerMetadata: currentModelResponse.providerMetadata,
1091
+ }
1092
+ : {}),
1088
1093
  performance: {
1089
1094
  responseTimeMs,
1090
1095
  effectiveOutputTokensPerSecond: calculateTokensPerSecond({
@@ -1,6 +1,7 @@
1
1
  import type { ToolSet } from '@ai-sdk/provider-utils';
2
2
  import type { Callback } from '../util/callback';
3
3
  import type { FinishReason } from '../types/language-model';
4
+ import type { ProviderMetadata } from '../types/provider-metadata';
4
5
  import type { LanguageModelUsage } from '../types/usage';
5
6
  import type { ContentPart } from './content-part';
6
7
  import type { StandardizedPrompt } from '../prompt/standardize-prompt';
@@ -55,6 +56,9 @@ export type LanguageModelCallEndEvent<TOOLS extends ToolSet = ToolSet> =
55
56
  /** The provider-returned response id for this model call. */
56
57
  readonly responseId: string;
57
58
 
59
+ /** Optional provider-specific metadata for this model call. */
60
+ readonly providerMetadata?: ProviderMetadata;
61
+
58
62
  /** Performance metrics for the model call. */
59
63
  readonly performance: {
60
64
  /** Time spent waiting for the language model response in milliseconds. */
@@ -596,6 +596,9 @@ function createLanguageModelV4StreamPartToLanguageModelStreamPartTransform<
596
596
  usage,
597
597
  content: modelCallContent,
598
598
  responseId,
599
+ ...(chunk.providerMetadata != null
600
+ ? { providerMetadata: chunk.providerMetadata }
601
+ : {}),
599
602
  performance,
600
603
  },
601
604
  callbacks: onLanguageModelCallEnd,