@ai-sdk/google 3.0.127 → 3.0.129
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 +16 -0
- package/dist/index.js +230 -137
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +121 -20
- package/dist/index.mjs.map +1 -1
- package/dist/internal/index.js +198 -105
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/index.mjs +118 -17
- package/dist/internal/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/convert-to-google-generative-ai-messages.ts +34 -12
- package/src/download-tool-result-files.ts +103 -0
- package/src/google-generative-ai-language-model.ts +22 -1
- package/src/google-generative-ai-prompt.ts +7 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/google",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.129",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@ai-sdk/provider": "3.0.
|
|
40
|
-
"@ai-sdk/provider-utils": "4.0.
|
|
39
|
+
"@ai-sdk/provider": "3.0.18",
|
|
40
|
+
"@ai-sdk/provider-utils": "4.0.56"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "20.17.24",
|
|
@@ -3,7 +3,11 @@ import {
|
|
|
3
3
|
type LanguageModelV3Prompt,
|
|
4
4
|
type SharedV3Warning,
|
|
5
5
|
} from '@ai-sdk/provider';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
convertToBase64,
|
|
8
|
+
isUrlSupported,
|
|
9
|
+
secureJsonParse,
|
|
10
|
+
} from '@ai-sdk/provider-utils';
|
|
7
11
|
import type {
|
|
8
12
|
GoogleGenerativeAIContent,
|
|
9
13
|
GoogleGenerativeAIContentPart,
|
|
@@ -71,21 +75,32 @@ function parseBase64DataUrl(
|
|
|
71
75
|
|
|
72
76
|
function convertUrlToolResultPart(
|
|
73
77
|
url: string,
|
|
78
|
+
mediaType: string | undefined,
|
|
79
|
+
supportedFunctionResponseUrls: Record<string, RegExp[]>,
|
|
74
80
|
): GoogleGenerativeAIFunctionResponsePart | undefined {
|
|
75
|
-
// Per https://ai.google.dev/api/caching#FunctionResponsePart, only inline data is supported.
|
|
76
|
-
// https://docs.cloud.google.com/vertex-ai/generative-ai/docs/model-reference/function-calling#functionresponsepart suggests that this
|
|
77
|
-
// may be different for Vertex, but this needs to be confirmed and further tested for both APIs.
|
|
78
81
|
const parsedDataUrl = parseBase64DataUrl(url);
|
|
79
|
-
if (parsedDataUrl
|
|
80
|
-
return
|
|
82
|
+
if (parsedDataUrl != null) {
|
|
83
|
+
return {
|
|
84
|
+
inlineData: {
|
|
85
|
+
mimeType: parsedDataUrl.mediaType,
|
|
86
|
+
data: parsedDataUrl.data,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
81
89
|
}
|
|
82
90
|
|
|
83
|
-
return
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
return mediaType != null &&
|
|
92
|
+
isUrlSupported({
|
|
93
|
+
url,
|
|
94
|
+
mediaType,
|
|
95
|
+
supportedUrls: supportedFunctionResponseUrls,
|
|
96
|
+
})
|
|
97
|
+
? {
|
|
98
|
+
fileData: {
|
|
99
|
+
mimeType: mediaType,
|
|
100
|
+
fileUri: url,
|
|
101
|
+
},
|
|
102
|
+
}
|
|
103
|
+
: undefined;
|
|
89
104
|
}
|
|
90
105
|
|
|
91
106
|
/*
|
|
@@ -102,6 +117,7 @@ function appendToolResultParts(
|
|
|
102
117
|
}>,
|
|
103
118
|
toolCallId?: string,
|
|
104
119
|
includeFunctionCallIds = true,
|
|
120
|
+
supportedFunctionResponseUrls: Record<string, RegExp[]> = {},
|
|
105
121
|
): void {
|
|
106
122
|
const functionResponseParts: GoogleGenerativeAIFunctionResponsePart[] = [];
|
|
107
123
|
const responseTextParts: string[] = [];
|
|
@@ -126,6 +142,8 @@ function appendToolResultParts(
|
|
|
126
142
|
case 'file-url': {
|
|
127
143
|
const functionResponsePart = convertUrlToolResultPart(
|
|
128
144
|
contentPart.url as string,
|
|
145
|
+
contentPart.mediaType as string | undefined,
|
|
146
|
+
supportedFunctionResponseUrls,
|
|
129
147
|
);
|
|
130
148
|
|
|
131
149
|
if (functionResponsePart != null) {
|
|
@@ -241,6 +259,7 @@ export function convertToGoogleGenerativeAIMessages(
|
|
|
241
259
|
*/
|
|
242
260
|
onWarning?: (warning: SharedV3Warning) => void;
|
|
243
261
|
includeFunctionCallIds?: boolean;
|
|
262
|
+
supportedFunctionResponseUrls?: Record<string, RegExp[]>;
|
|
244
263
|
},
|
|
245
264
|
): GoogleGenerativeAIPrompt {
|
|
246
265
|
const systemInstructionParts: Array<{ text: string }> = [];
|
|
@@ -253,6 +272,8 @@ export function convertToGoogleGenerativeAIMessages(
|
|
|
253
272
|
options?.supportsFunctionResponseParts ?? true;
|
|
254
273
|
const onWarning = options?.onWarning;
|
|
255
274
|
const includeFunctionCallIds = options?.includeFunctionCallIds ?? true;
|
|
275
|
+
const supportedFunctionResponseUrls =
|
|
276
|
+
options?.supportedFunctionResponseUrls ?? {};
|
|
256
277
|
|
|
257
278
|
let sentinelInjected = false;
|
|
258
279
|
const missingSignatureToolNames: string[] = [];
|
|
@@ -523,6 +544,7 @@ export function convertToGoogleGenerativeAIMessages(
|
|
|
523
544
|
output.value,
|
|
524
545
|
part.toolCallId,
|
|
525
546
|
includeFunctionCallIds,
|
|
547
|
+
supportedFunctionResponseUrls,
|
|
526
548
|
);
|
|
527
549
|
} else {
|
|
528
550
|
appendLegacyToolResultParts(
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
LanguageModelV3Prompt,
|
|
3
|
+
LanguageModelV3ToolResultOutput,
|
|
4
|
+
} from '@ai-sdk/provider';
|
|
5
|
+
import {
|
|
6
|
+
convertUint8ArrayToBase64,
|
|
7
|
+
downloadBlob,
|
|
8
|
+
isUrlSupported,
|
|
9
|
+
} from '@ai-sdk/provider-utils';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Vertex accepts more URLs in user messages than in function responses.
|
|
13
|
+
* Download tool result files that cannot be referenced in function responses.
|
|
14
|
+
*/
|
|
15
|
+
export async function downloadToolResultFiles(
|
|
16
|
+
prompt: LanguageModelV3Prompt,
|
|
17
|
+
{
|
|
18
|
+
abortSignal,
|
|
19
|
+
supportedUrls = {},
|
|
20
|
+
}: {
|
|
21
|
+
abortSignal: AbortSignal | undefined;
|
|
22
|
+
supportedUrls?: Record<string, RegExp[]>;
|
|
23
|
+
},
|
|
24
|
+
): Promise<LanguageModelV3Prompt> {
|
|
25
|
+
async function downloadOutput(
|
|
26
|
+
output: LanguageModelV3ToolResultOutput,
|
|
27
|
+
): Promise<LanguageModelV3ToolResultOutput> {
|
|
28
|
+
if (output.type !== 'content') {
|
|
29
|
+
return output;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
...output,
|
|
34
|
+
value: await Promise.all(
|
|
35
|
+
output.value.map(async part => {
|
|
36
|
+
if (part.type !== 'file-url' && part.type !== 'image-url') {
|
|
37
|
+
return part;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (
|
|
41
|
+
part.type === 'file-url' &&
|
|
42
|
+
part.mediaType != null &&
|
|
43
|
+
isUrlSupported({
|
|
44
|
+
url: part.url,
|
|
45
|
+
mediaType: part.mediaType,
|
|
46
|
+
supportedUrls,
|
|
47
|
+
})
|
|
48
|
+
) {
|
|
49
|
+
return part;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const blob = await downloadBlob(part.url, { abortSignal });
|
|
53
|
+
return {
|
|
54
|
+
type:
|
|
55
|
+
part.type === 'file-url'
|
|
56
|
+
? ('file-data' as const)
|
|
57
|
+
: ('image-data' as const),
|
|
58
|
+
data: convertUint8ArrayToBase64(
|
|
59
|
+
new Uint8Array(await blob.arrayBuffer()),
|
|
60
|
+
),
|
|
61
|
+
mediaType:
|
|
62
|
+
blob.type ||
|
|
63
|
+
(part.type === 'file-url'
|
|
64
|
+
? (part.mediaType ?? 'application/octet-stream')
|
|
65
|
+
: 'image/*'),
|
|
66
|
+
providerOptions: part.providerOptions,
|
|
67
|
+
};
|
|
68
|
+
}),
|
|
69
|
+
),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return Promise.all(
|
|
74
|
+
prompt.map(async message => {
|
|
75
|
+
switch (message.role) {
|
|
76
|
+
case 'assistant':
|
|
77
|
+
return {
|
|
78
|
+
...message,
|
|
79
|
+
content: await Promise.all(
|
|
80
|
+
message.content.map(async part =>
|
|
81
|
+
part.type === 'tool-result'
|
|
82
|
+
? { ...part, output: await downloadOutput(part.output) }
|
|
83
|
+
: part,
|
|
84
|
+
),
|
|
85
|
+
),
|
|
86
|
+
};
|
|
87
|
+
case 'tool':
|
|
88
|
+
return {
|
|
89
|
+
...message,
|
|
90
|
+
content: await Promise.all(
|
|
91
|
+
message.content.map(async part =>
|
|
92
|
+
part.type === 'tool-result'
|
|
93
|
+
? { ...part, output: await downloadOutput(part.output) }
|
|
94
|
+
: part,
|
|
95
|
+
),
|
|
96
|
+
),
|
|
97
|
+
};
|
|
98
|
+
default:
|
|
99
|
+
return message;
|
|
100
|
+
}
|
|
101
|
+
}),
|
|
102
|
+
);
|
|
103
|
+
}
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
} from './convert-google-generative-ai-usage';
|
|
34
34
|
import { convertJSONSchemaToOpenAPISchema } from './convert-json-schema-to-openapi-schema';
|
|
35
35
|
import { convertToGoogleGenerativeAIMessages } from './convert-to-google-generative-ai-messages';
|
|
36
|
+
import { downloadToolResultFiles } from './download-tool-result-files';
|
|
36
37
|
import { getModelPath } from './get-model-path';
|
|
37
38
|
import { googleFailedResponseHandler } from './google-error';
|
|
38
39
|
import {
|
|
@@ -60,6 +61,14 @@ const configurableSafetySettingCategories = [
|
|
|
60
61
|
|
|
61
62
|
const gemini25ModelPattern = /(^|\/)gemini-2\.5(?:[.-]|$)/i;
|
|
62
63
|
|
|
64
|
+
const googleCloudStorageFunctionResponseUrls = {
|
|
65
|
+
'image/png': [/^gs:\/\/.*$/],
|
|
66
|
+
'image/jpeg': [/^gs:\/\/.*$/],
|
|
67
|
+
'image/webp': [/^gs:\/\/.*$/],
|
|
68
|
+
'application/pdf': [/^gs:\/\/.*$/],
|
|
69
|
+
'text/plain': [/^gs:\/\/.*$/],
|
|
70
|
+
} satisfies Record<string, RegExp[]>;
|
|
71
|
+
|
|
63
72
|
type GoogleGenerativeAIConfig = {
|
|
64
73
|
provider: string;
|
|
65
74
|
baseURL: string;
|
|
@@ -113,6 +122,7 @@ export class GoogleGenerativeAILanguageModel implements LanguageModelV3 {
|
|
|
113
122
|
tools,
|
|
114
123
|
toolChoice,
|
|
115
124
|
providerOptions,
|
|
125
|
+
abortSignal,
|
|
116
126
|
}: LanguageModelV3CallOptions,
|
|
117
127
|
{ isStreaming = false }: { isStreaming?: boolean } = {},
|
|
118
128
|
) {
|
|
@@ -249,9 +259,19 @@ export class GoogleGenerativeAILanguageModel implements LanguageModelV3 {
|
|
|
249
259
|
}
|
|
250
260
|
|
|
251
261
|
const { usesGemini3Features } = getGoogleModelCapabilities(this.modelId);
|
|
262
|
+
const supportedFunctionResponseUrls =
|
|
263
|
+
usesGemini3Features && isVertexProvider
|
|
264
|
+
? googleCloudStorageFunctionResponseUrls
|
|
265
|
+
: undefined;
|
|
266
|
+
const promptWithDownloadedToolResultFiles = isVertexProvider
|
|
267
|
+
? await downloadToolResultFiles(prompt, {
|
|
268
|
+
abortSignal,
|
|
269
|
+
supportedUrls: supportedFunctionResponseUrls,
|
|
270
|
+
})
|
|
271
|
+
: prompt;
|
|
252
272
|
|
|
253
273
|
const { contents, systemInstruction } = convertToGoogleGenerativeAIMessages(
|
|
254
|
-
|
|
274
|
+
promptWithDownloadedToolResultFiles,
|
|
255
275
|
{
|
|
256
276
|
isGemmaModel,
|
|
257
277
|
isGemini3Model: usesGemini3Features,
|
|
@@ -259,6 +279,7 @@ export class GoogleGenerativeAILanguageModel implements LanguageModelV3 {
|
|
|
259
279
|
supportsFunctionResponseParts: usesGemini3Features,
|
|
260
280
|
onWarning: warning => warnings.push(warning),
|
|
261
281
|
includeFunctionCallIds: !isVertexProvider,
|
|
282
|
+
supportedFunctionResponseUrls,
|
|
262
283
|
},
|
|
263
284
|
);
|
|
264
285
|
|
|
@@ -53,9 +53,13 @@ export type GoogleGenerativeAIContentPart =
|
|
|
53
53
|
thoughtSignature?: string;
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
-
export type GoogleGenerativeAIFunctionResponsePart =
|
|
57
|
-
|
|
58
|
-
};
|
|
56
|
+
export type GoogleGenerativeAIFunctionResponsePart =
|
|
57
|
+
| {
|
|
58
|
+
inlineData: { mimeType: string; data: string };
|
|
59
|
+
}
|
|
60
|
+
| {
|
|
61
|
+
fileData: { mimeType: string; fileUri: string };
|
|
62
|
+
};
|
|
59
63
|
|
|
60
64
|
export type GoogleGenerativeAIGroundingMetadata = GroundingMetadataSchema;
|
|
61
65
|
|