@ai-sdk/google 4.0.66 → 4.0.68
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 +22 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +355 -168
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/google-batch.ts +271 -25
- package/src/google-provider.ts +4 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/google",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.68",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@ai-sdk/provider": "4.0.
|
|
39
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
38
|
+
"@ai-sdk/provider": "4.0.14",
|
|
39
|
+
"@ai-sdk/provider-utils": "5.0.40"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@ai-sdk/test-server": "2.0.1",
|
package/src/google-batch.ts
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
InvalidArgumentError,
|
|
3
3
|
InvalidResponseDataError,
|
|
4
|
+
UnsupportedFunctionalityError,
|
|
4
5
|
type Experimental_BatchV4 as BatchV4,
|
|
6
|
+
type Experimental_BatchV4CancelResult as BatchV4CancelResult,
|
|
5
7
|
type Experimental_BatchV4Error as BatchV4Error,
|
|
6
8
|
type Experimental_BatchV4ItemResult as BatchV4ItemResult,
|
|
9
|
+
type Experimental_BatchV4ListOptions as BatchV4ListOptions,
|
|
10
|
+
type Experimental_BatchV4ListResult as BatchV4ListResult,
|
|
7
11
|
type Experimental_BatchV4OperationOptions as BatchV4OperationOptions,
|
|
8
12
|
type Experimental_BatchV4StartResult as BatchV4StartResult,
|
|
9
13
|
type Experimental_BatchV4Status as BatchV4Status,
|
|
10
|
-
type
|
|
14
|
+
type Experimental_ImageBatchV4Request as ImageBatchV4Request,
|
|
11
15
|
type Experimental_BatchV4StartOptions as BatchV4StartOptions,
|
|
12
16
|
type LanguageModelV4GenerateResult,
|
|
17
|
+
type ImageModelV4Result,
|
|
18
|
+
type LanguageModelV4Prompt,
|
|
19
|
+
type SharedV4Warning,
|
|
13
20
|
} from '@ai-sdk/provider';
|
|
14
21
|
import {
|
|
15
22
|
combineHeaders,
|
|
@@ -20,11 +27,13 @@ import {
|
|
|
20
27
|
getFromApi,
|
|
21
28
|
lazySchema,
|
|
22
29
|
normalizeBatchRequestCounts,
|
|
30
|
+
parseProviderOptions,
|
|
23
31
|
postJsonToApi,
|
|
24
32
|
postToApi,
|
|
25
33
|
resolve,
|
|
26
34
|
safeValidateTypes,
|
|
27
35
|
zodSchema,
|
|
36
|
+
convertToBase64,
|
|
28
37
|
type InferSchema,
|
|
29
38
|
type ResponseHandler,
|
|
30
39
|
} from '@ai-sdk/provider-utils';
|
|
@@ -36,7 +45,12 @@ import {
|
|
|
36
45
|
responseSchema,
|
|
37
46
|
type GoogleLanguageModelConfig,
|
|
38
47
|
} from './google-language-model';
|
|
39
|
-
import
|
|
48
|
+
import {
|
|
49
|
+
googleLanguageModelOptions,
|
|
50
|
+
type GoogleModelId,
|
|
51
|
+
} from './google-language-model-options';
|
|
52
|
+
import type { GoogleImageModelId } from './google-image-settings';
|
|
53
|
+
import { googleImageModelOptionsSchema } from './google-image-model-options';
|
|
40
54
|
|
|
41
55
|
const googleBatchInputFileMaxBytes = 2 * 1024 * 1024 * 1024;
|
|
42
56
|
const googleBatchInlineCreationMaxBytes = 20_000_000;
|
|
@@ -44,7 +58,25 @@ const supportedGoogleBatchContentTypes = new Set<
|
|
|
44
58
|
LanguageModelV4GenerateResult['content'][number]['type']
|
|
45
59
|
>(['text', 'reasoning', 'source', 'tool-call', 'tool-result']);
|
|
46
60
|
|
|
47
|
-
type
|
|
61
|
+
type GoogleImageBatchRequest = ImageBatchV4Request<GoogleImageModelId>;
|
|
62
|
+
type GoogleBatchModelIds = {
|
|
63
|
+
readonly text: GoogleModelId;
|
|
64
|
+
readonly image: GoogleImageModelId;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
function assertSupportedBatchRequests(
|
|
68
|
+
requests: BatchV4StartOptions<GoogleBatchModelIds>['requests'],
|
|
69
|
+
) {
|
|
70
|
+
for (const request of requests) {
|
|
71
|
+
const requestType = request.type;
|
|
72
|
+
if (requestType !== 'text' && requestType !== 'image') {
|
|
73
|
+
throw new UnsupportedFunctionalityError({
|
|
74
|
+
functionality: `batch request type: ${requestType}`,
|
|
75
|
+
message: `The Google Batch API does not support batch requests with type "${requestType}".`,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
48
80
|
|
|
49
81
|
const googleRpcStatusSchema = z.object({
|
|
50
82
|
code: z.union([z.number(), z.string()]).nullish(),
|
|
@@ -76,26 +108,40 @@ const googleBatchOutputSchema = z.object({
|
|
|
76
108
|
.nullish(),
|
|
77
109
|
});
|
|
78
110
|
|
|
111
|
+
const googleBatchOperationZodSchema = () =>
|
|
112
|
+
z.object({
|
|
113
|
+
name: z.string(),
|
|
114
|
+
metadata: z
|
|
115
|
+
.object({
|
|
116
|
+
state: z.string().nullish(),
|
|
117
|
+
createTime: z.string().nullish(),
|
|
118
|
+
batchStats: googleBatchStatsSchema.nullish(),
|
|
119
|
+
output: googleBatchOutputSchema.nullish(),
|
|
120
|
+
})
|
|
121
|
+
.nullish(),
|
|
122
|
+
done: z.boolean().nullish(),
|
|
123
|
+
error: googleRpcStatusSchema.nullish(),
|
|
124
|
+
response: googleBatchOutputSchema.nullish(),
|
|
125
|
+
});
|
|
126
|
+
|
|
79
127
|
const googleBatchOperationSchema = lazySchema(() =>
|
|
128
|
+
zodSchema(googleBatchOperationZodSchema()),
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
type GoogleBatchOperation = InferSchema<typeof googleBatchOperationSchema>;
|
|
132
|
+
|
|
133
|
+
const googleBatchListResponseSchema = lazySchema(() =>
|
|
80
134
|
zodSchema(
|
|
81
135
|
z.object({
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
.object({
|
|
85
|
-
state: z.string().nullish(),
|
|
86
|
-
createTime: z.string().nullish(),
|
|
87
|
-
batchStats: googleBatchStatsSchema.nullish(),
|
|
88
|
-
output: googleBatchOutputSchema.nullish(),
|
|
89
|
-
})
|
|
90
|
-
.nullish(),
|
|
91
|
-
done: z.boolean().nullish(),
|
|
92
|
-
error: googleRpcStatusSchema.nullish(),
|
|
93
|
-
response: googleBatchOutputSchema.nullish(),
|
|
136
|
+
operations: z.array(googleBatchOperationZodSchema()).nullish(),
|
|
137
|
+
nextPageToken: z.string().nullish(),
|
|
94
138
|
}),
|
|
95
139
|
),
|
|
96
140
|
);
|
|
97
141
|
|
|
98
|
-
|
|
142
|
+
const googleBatchCancelResponseSchema = lazySchema(() =>
|
|
143
|
+
zodSchema(z.object({})),
|
|
144
|
+
);
|
|
99
145
|
|
|
100
146
|
const googleFileUploadResponseSchema = lazySchema(() =>
|
|
101
147
|
zodSchema(
|
|
@@ -133,7 +179,7 @@ const googleBatchResponsePreviewSchema = lazySchema(() =>
|
|
|
133
179
|
),
|
|
134
180
|
);
|
|
135
181
|
|
|
136
|
-
export class GoogleBatch implements BatchV4<
|
|
182
|
+
export class GoogleBatch implements BatchV4<GoogleBatchModelIds> {
|
|
137
183
|
readonly specificationVersion = 'v4' as const;
|
|
138
184
|
readonly provider: string;
|
|
139
185
|
readonly supportedUrls: Record<string, RegExp[]>;
|
|
@@ -152,8 +198,9 @@ export class GoogleBatch implements BatchV4<{ readonly text: GoogleModelId }> {
|
|
|
152
198
|
}
|
|
153
199
|
|
|
154
200
|
async doStartBatch(
|
|
155
|
-
options: BatchV4StartOptions<
|
|
201
|
+
options: BatchV4StartOptions<GoogleBatchModelIds>,
|
|
156
202
|
): Promise<BatchV4StartResult> {
|
|
203
|
+
assertSupportedBatchRequests(options.requests);
|
|
157
204
|
const modelId = getGoogleBatchModelId(options.requests);
|
|
158
205
|
const warnings: BatchV4StartResult['warnings'] = [];
|
|
159
206
|
const displayName = `ai-sdk-batch-${this.batchGenerateId()}`;
|
|
@@ -179,11 +226,14 @@ export class GoogleBatch implements BatchV4<{ readonly text: GoogleModelId }> {
|
|
|
179
226
|
let fileParts: string[] | undefined;
|
|
180
227
|
|
|
181
228
|
for (const request of options.requests) {
|
|
182
|
-
const preparedRequest =
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
229
|
+
const preparedRequest =
|
|
230
|
+
request.type === 'text'
|
|
231
|
+
? await GoogleLanguageModel.prepareRequest({
|
|
232
|
+
modelId: request.modelId,
|
|
233
|
+
config: this.batchConfig,
|
|
234
|
+
options: request.options,
|
|
235
|
+
})
|
|
236
|
+
: await this.prepareImageRequest(request);
|
|
187
237
|
const inlinedRequest = {
|
|
188
238
|
request: preparedRequest.args,
|
|
189
239
|
metadata: { key: request.id },
|
|
@@ -355,6 +405,54 @@ export class GoogleBatch implements BatchV4<{ readonly text: GoogleModelId }> {
|
|
|
355
405
|
return convertGoogleBatchStatus(await this.retrieveBatch(options));
|
|
356
406
|
}
|
|
357
407
|
|
|
408
|
+
async doCancelBatch(
|
|
409
|
+
options: BatchV4OperationOptions,
|
|
410
|
+
): Promise<BatchV4CancelResult> {
|
|
411
|
+
await postJsonToApi({
|
|
412
|
+
url: `${this.batchConfig.baseURL}/${options.batchId}:cancel`,
|
|
413
|
+
headers: await this.getHeaders(options.headers),
|
|
414
|
+
body: {},
|
|
415
|
+
failedResponseHandler: googleFailedResponseHandler,
|
|
416
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
417
|
+
googleBatchCancelResponseSchema,
|
|
418
|
+
),
|
|
419
|
+
abortSignal: options.abortSignal,
|
|
420
|
+
fetch: this.batchConfig.fetch,
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
return {};
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
async doListBatches(options: BatchV4ListOptions): Promise<BatchV4ListResult> {
|
|
427
|
+
const url = new URL(`${this.batchConfig.baseURL}/batches`);
|
|
428
|
+
if (options.limit != null) {
|
|
429
|
+
url.searchParams.set('pageSize', String(options.limit));
|
|
430
|
+
}
|
|
431
|
+
if (options.cursor != null) {
|
|
432
|
+
url.searchParams.set('pageToken', options.cursor);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const { value: page } = await getFromApi({
|
|
436
|
+
url: url.toString(),
|
|
437
|
+
headers: await this.getHeaders(options.headers),
|
|
438
|
+
failedResponseHandler: googleFailedResponseHandler,
|
|
439
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
440
|
+
googleBatchListResponseSchema,
|
|
441
|
+
),
|
|
442
|
+
abortSignal: options.abortSignal,
|
|
443
|
+
fetch: this.batchConfig.fetch,
|
|
444
|
+
validateUrl: false,
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
return {
|
|
448
|
+
batches: (page.operations ?? []).map(operation => ({
|
|
449
|
+
batchId: operation.name,
|
|
450
|
+
...convertGoogleBatchStatus(operation),
|
|
451
|
+
})),
|
|
452
|
+
...(page.nextPageToken != null ? { nextCursor: page.nextPageToken } : {}),
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
|
|
358
456
|
async doGetBatchResults(
|
|
359
457
|
options: BatchV4OperationOptions,
|
|
360
458
|
): Promise<ReadableStream<BatchV4ItemResult>> {
|
|
@@ -537,6 +635,16 @@ export class GoogleBatch implements BatchV4<{ readonly text: GoogleModelId }> {
|
|
|
537
635
|
warnings: [],
|
|
538
636
|
providerOptionsNames: ['google'],
|
|
539
637
|
});
|
|
638
|
+
const imageResult = convertGoogleImageBatchResult(result);
|
|
639
|
+
if (imageResult != null) {
|
|
640
|
+
yield {
|
|
641
|
+
type: 'image',
|
|
642
|
+
id: line.key,
|
|
643
|
+
status: 'succeeded',
|
|
644
|
+
result: imageResult,
|
|
645
|
+
};
|
|
646
|
+
continue;
|
|
647
|
+
}
|
|
540
648
|
const unsupportedPart = result.content.find(
|
|
541
649
|
part => !supportedGoogleBatchContentTypes.has(part.type),
|
|
542
650
|
);
|
|
@@ -560,6 +668,108 @@ export class GoogleBatch implements BatchV4<{ readonly text: GoogleModelId }> {
|
|
|
560
668
|
}
|
|
561
669
|
}
|
|
562
670
|
|
|
671
|
+
private async prepareImageRequest(request: GoogleImageBatchRequest) {
|
|
672
|
+
const { prompt, n, size, aspectRatio, seed, files, mask, providerOptions } =
|
|
673
|
+
request.options;
|
|
674
|
+
const warnings: SharedV4Warning[] = [];
|
|
675
|
+
|
|
676
|
+
if (mask != null) {
|
|
677
|
+
throw new UnsupportedFunctionalityError({
|
|
678
|
+
functionality: 'mask-based image editing in Google batches',
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
if (n > 1) {
|
|
682
|
+
throw new UnsupportedFunctionalityError({
|
|
683
|
+
functionality: 'multiple images per Google batch request',
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
if (size != null) {
|
|
687
|
+
warnings.push({
|
|
688
|
+
type: 'unsupported',
|
|
689
|
+
feature: 'size',
|
|
690
|
+
details:
|
|
691
|
+
'This model does not support the `size` option. Use `aspectRatio` instead.',
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
const userContent: Extract<
|
|
696
|
+
LanguageModelV4Prompt[number],
|
|
697
|
+
{ role: 'user' }
|
|
698
|
+
>['content'] = [];
|
|
699
|
+
if (prompt != null) userContent.push({ type: 'text', text: prompt });
|
|
700
|
+
for (const file of files ?? []) {
|
|
701
|
+
userContent.push(
|
|
702
|
+
file.type === 'url'
|
|
703
|
+
? {
|
|
704
|
+
type: 'file',
|
|
705
|
+
data: { type: 'url', url: new URL(file.url) },
|
|
706
|
+
mediaType: 'image/*',
|
|
707
|
+
}
|
|
708
|
+
: {
|
|
709
|
+
type: 'file',
|
|
710
|
+
data: { type: 'data', data: file.data },
|
|
711
|
+
mediaType: file.mediaType,
|
|
712
|
+
},
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
const googleImageOptions = await parseProviderOptions({
|
|
717
|
+
provider: 'google',
|
|
718
|
+
providerOptions,
|
|
719
|
+
schema: googleImageModelOptionsSchema,
|
|
720
|
+
});
|
|
721
|
+
const {
|
|
722
|
+
responseModalities: _responseModalities,
|
|
723
|
+
imageConfig: userImageConfig,
|
|
724
|
+
...passthroughGoogleOptions
|
|
725
|
+
} = (await parseProviderOptions({
|
|
726
|
+
provider: 'google',
|
|
727
|
+
providerOptions,
|
|
728
|
+
schema: googleLanguageModelOptions,
|
|
729
|
+
})) ?? {};
|
|
730
|
+
const preparedGoogleOptions = await parseProviderOptions({
|
|
731
|
+
provider: 'google',
|
|
732
|
+
providerOptions: {
|
|
733
|
+
google: {
|
|
734
|
+
...passthroughGoogleOptions,
|
|
735
|
+
responseModalities: ['IMAGE'],
|
|
736
|
+
imageConfig:
|
|
737
|
+
aspectRatio != null || userImageConfig != null
|
|
738
|
+
? {
|
|
739
|
+
...userImageConfig,
|
|
740
|
+
...(aspectRatio != null ? { aspectRatio } : {}),
|
|
741
|
+
}
|
|
742
|
+
: undefined,
|
|
743
|
+
},
|
|
744
|
+
},
|
|
745
|
+
schema: googleLanguageModelOptions,
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
const prepared = await GoogleLanguageModel.prepareRequest({
|
|
749
|
+
modelId: request.modelId,
|
|
750
|
+
config: this.batchConfig,
|
|
751
|
+
options: {
|
|
752
|
+
prompt: [{ role: 'user', content: userContent }],
|
|
753
|
+
seed,
|
|
754
|
+
providerOptions: {
|
|
755
|
+
google: preparedGoogleOptions ?? { responseModalities: ['IMAGE'] },
|
|
756
|
+
},
|
|
757
|
+
tools:
|
|
758
|
+
googleImageOptions?.googleSearch != null
|
|
759
|
+
? [
|
|
760
|
+
{
|
|
761
|
+
type: 'provider',
|
|
762
|
+
id: 'google.google_search',
|
|
763
|
+
name: 'google_search',
|
|
764
|
+
args: googleImageOptions.googleSearch,
|
|
765
|
+
},
|
|
766
|
+
]
|
|
767
|
+
: undefined,
|
|
768
|
+
},
|
|
769
|
+
});
|
|
770
|
+
return { ...prepared, warnings: [...warnings, ...prepared.warnings] };
|
|
771
|
+
}
|
|
772
|
+
|
|
563
773
|
private async getHeaders(headers?: Record<string, string | undefined>) {
|
|
564
774
|
return combineHeaders(
|
|
565
775
|
this.batchConfig.headers
|
|
@@ -683,8 +893,8 @@ const googleUploadUrlResponseHandler: ResponseHandler<string> = async ({
|
|
|
683
893
|
};
|
|
684
894
|
|
|
685
895
|
function getGoogleBatchModelId(
|
|
686
|
-
requests:
|
|
687
|
-
): GoogleModelId {
|
|
896
|
+
requests: BatchV4StartOptions<GoogleBatchModelIds>['requests'],
|
|
897
|
+
): GoogleModelId | GoogleImageModelId {
|
|
688
898
|
const modelId = requests[0]?.modelId;
|
|
689
899
|
|
|
690
900
|
if (modelId == null) {
|
|
@@ -706,3 +916,39 @@ function getGoogleBatchModelId(
|
|
|
706
916
|
|
|
707
917
|
return modelId;
|
|
708
918
|
}
|
|
919
|
+
|
|
920
|
+
function convertGoogleImageBatchResult(
|
|
921
|
+
result: LanguageModelV4GenerateResult,
|
|
922
|
+
): ImageModelV4Result | undefined {
|
|
923
|
+
const images = result.content.flatMap(part =>
|
|
924
|
+
part.type === 'file' &&
|
|
925
|
+
part.mediaType.startsWith('image/') &&
|
|
926
|
+
part.data.type === 'data'
|
|
927
|
+
? [convertToBase64(part.data.data)]
|
|
928
|
+
: [],
|
|
929
|
+
);
|
|
930
|
+
if (images.length === 0) return undefined;
|
|
931
|
+
|
|
932
|
+
const googleMetadata =
|
|
933
|
+
(result.providerMetadata?.google as Record<string, unknown> | undefined) ??
|
|
934
|
+
{};
|
|
935
|
+
return {
|
|
936
|
+
images,
|
|
937
|
+
warnings: result.warnings,
|
|
938
|
+
providerMetadata: {
|
|
939
|
+
google: { ...googleMetadata, images: images.map(() => ({})) },
|
|
940
|
+
},
|
|
941
|
+
response: {
|
|
942
|
+
timestamp: new Date(),
|
|
943
|
+
modelId: result.response?.modelId ?? '',
|
|
944
|
+
headers: result.response?.headers,
|
|
945
|
+
},
|
|
946
|
+
usage: {
|
|
947
|
+
inputTokens: result.usage.inputTokens.total,
|
|
948
|
+
outputTokens: result.usage.outputTokens.total,
|
|
949
|
+
totalTokens:
|
|
950
|
+
(result.usage.inputTokens.total ?? 0) +
|
|
951
|
+
(result.usage.outputTokens.total ?? 0),
|
|
952
|
+
},
|
|
953
|
+
};
|
|
954
|
+
}
|
package/src/google-provider.ts
CHANGED
|
@@ -61,7 +61,10 @@ export interface GoogleProvider extends ProviderV4 {
|
|
|
61
61
|
|
|
62
62
|
chat(modelId: GoogleModelId): LanguageModelV4;
|
|
63
63
|
|
|
64
|
-
experimental_batch(): BatchV4<{
|
|
64
|
+
experimental_batch(): BatchV4<{
|
|
65
|
+
text: GoogleModelId;
|
|
66
|
+
image: GoogleImageModelId;
|
|
67
|
+
}>;
|
|
65
68
|
|
|
66
69
|
/**
|
|
67
70
|
* Creates a model for image generation.
|