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.
- package/CHANGELOG.md +31 -0
- package/dist/index.d.ts +128 -3
- package/dist/index.js +407 -83
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +2 -0
- package/dist/internal/index.js +1 -1
- package/docs/03-ai-sdk-core/05-generating-text.mdx +2 -2
- package/docs/03-ai-sdk-core/60-telemetry.mdx +2 -2
- package/docs/03-ai-sdk-core/65-lifecycle-callbacks.mdx +18 -1
- package/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx +6 -0
- package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +6 -0
- package/package.json +4 -4
- package/src/batch/batch-types.ts +134 -0
- package/src/batch/batch.ts +336 -0
- package/src/batch/index.ts +19 -0
- package/src/generate-text/generate-text.ts +5 -0
- package/src/generate-text/language-model-events.ts +4 -0
- package/src/generate-text/stream-language-model-call.ts +3 -0
- package/src/generate-video/generate-video.ts +17 -6
- package/src/index.ts +1 -0
- package/src/ui/chat-transport.ts +3 -0
- package/src/ui/chat.ts +87 -12
- package/src/ui/http-chat-transport.ts +1 -0
- package/src/util/consume-stream.ts +13 -0
package/dist/internal/index.d.ts
CHANGED
|
@@ -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. */
|
package/dist/internal/index.js
CHANGED
|
@@ -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
|
|
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
|
|
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({
|
|
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.
|
|
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.
|
|
46
|
-
"@ai-sdk/provider": "4.0.
|
|
47
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
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,
|