@standardagents/google 0.0.1-dev.ffffff
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/README.md +7 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.js +1140 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1140 @@
|
|
|
1
|
+
// src/GoogleProvider.ts
|
|
2
|
+
import {
|
|
3
|
+
GoogleGenAI,
|
|
4
|
+
FunctionCallingConfigMode,
|
|
5
|
+
createPartFromBase64,
|
|
6
|
+
createPartFromFunctionResponse,
|
|
7
|
+
RawReferenceImage
|
|
8
|
+
} from "@google/genai/web";
|
|
9
|
+
import { ProviderError } from "@standardagents/spec";
|
|
10
|
+
|
|
11
|
+
// src/icons.ts
|
|
12
|
+
var GOOGLE_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none"><rect width="64" height="64" rx="16" fill="#fff"/><path d="M54 32.73c0-1.58-.14-3.1-.4-4.55H32v8.61h12.33c-.53 2.85-2.14 5.27-4.56 6.9v5.73h7.38C51.47 45.44 54 39.61 54 32.73Z" fill="#4285F4"/><path d="M32 55c6.2 0 11.4-2.05 15.2-5.58l-7.38-5.73c-2.05 1.37-4.67 2.18-7.82 2.18-6 0-11.08-4.05-12.9-9.49h-7.62v5.96A22.98 22.98 0 0 0 32 55Z" fill="#34A853"/><path d="M19.1 36.38A13.8 13.8 0 0 1 18.38 32c0-1.52.26-3 .72-4.38v-5.96h-7.62A22.98 22.98 0 0 0 9 32c0 3.67.88 7.13 2.48 10.34l7.62-5.96Z" fill="#FBBC05"/><path d="M32 18.9c3.37 0 6.4 1.16 8.79 3.45l6.59-6.59C43.39 12.05 38.19 9 32 9A22.98 22.98 0 0 0 11.48 21.66l7.62 5.96C20.92 22.95 26 18.9 32 18.9Z" fill="#EA4335"/></svg>`;
|
|
13
|
+
function svgToDataUri(svg) {
|
|
14
|
+
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
|
15
|
+
}
|
|
16
|
+
function getGoogleIconDataUri() {
|
|
17
|
+
return svgToDataUri(GOOGLE_ICON);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// src/pricing.ts
|
|
21
|
+
var MODEL_PRICING = {
|
|
22
|
+
"gemini-3-pro-preview": {
|
|
23
|
+
inputPerMillion: 2,
|
|
24
|
+
outputPerMillion: 12,
|
|
25
|
+
cachedInputPerMillion: 0.2
|
|
26
|
+
},
|
|
27
|
+
"gemini-3.1-pro-preview": {
|
|
28
|
+
inputPerMillion: 2,
|
|
29
|
+
longInputPerMillion: 4,
|
|
30
|
+
outputPerMillion: 12,
|
|
31
|
+
longOutputPerMillion: 18,
|
|
32
|
+
cachedInputPerMillion: 0.2,
|
|
33
|
+
longCachedInputPerMillion: 0.4,
|
|
34
|
+
longContextThreshold: 2e5
|
|
35
|
+
},
|
|
36
|
+
"gemini-2.5-pro": {
|
|
37
|
+
inputPerMillion: 1.25,
|
|
38
|
+
longInputPerMillion: 2.5,
|
|
39
|
+
outputPerMillion: 10,
|
|
40
|
+
longOutputPerMillion: 15,
|
|
41
|
+
cachedInputPerMillion: 0.125,
|
|
42
|
+
longCachedInputPerMillion: 0.25,
|
|
43
|
+
longContextThreshold: 2e5
|
|
44
|
+
},
|
|
45
|
+
"gemini-2.5-flash": {
|
|
46
|
+
inputPerMillion: 0.3,
|
|
47
|
+
outputPerMillion: 2.5,
|
|
48
|
+
cachedInputPerMillion: 0.03
|
|
49
|
+
},
|
|
50
|
+
"gemini-2.5-flash-lite": {
|
|
51
|
+
inputPerMillion: 0.1,
|
|
52
|
+
outputPerMillion: 0.4,
|
|
53
|
+
cachedInputPerMillion: 0.01
|
|
54
|
+
},
|
|
55
|
+
"gemini-3-flash-preview": {
|
|
56
|
+
inputPerMillion: 0.5,
|
|
57
|
+
outputPerMillion: 3,
|
|
58
|
+
cachedInputPerMillion: 0.05,
|
|
59
|
+
inputByModalityPerMillion: {
|
|
60
|
+
text: 0.5,
|
|
61
|
+
image: 0.5,
|
|
62
|
+
video: 0.5,
|
|
63
|
+
audio: 1
|
|
64
|
+
},
|
|
65
|
+
cachedByModalityPerMillion: {
|
|
66
|
+
text: 0.05,
|
|
67
|
+
image: 0.05,
|
|
68
|
+
video: 0.05,
|
|
69
|
+
audio: 0.1
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"gemini-3.1-flash-lite-preview": {
|
|
73
|
+
inputPerMillion: 0.25,
|
|
74
|
+
outputPerMillion: 1.5,
|
|
75
|
+
cachedInputPerMillion: 0.025,
|
|
76
|
+
inputByModalityPerMillion: {
|
|
77
|
+
text: 0.25,
|
|
78
|
+
image: 0.25,
|
|
79
|
+
video: 0.25,
|
|
80
|
+
audio: 0.5
|
|
81
|
+
},
|
|
82
|
+
cachedByModalityPerMillion: {
|
|
83
|
+
text: 0.025,
|
|
84
|
+
image: 0.025,
|
|
85
|
+
video: 0.025,
|
|
86
|
+
audio: 0.05
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"deep-research-pro-preview-12-2025": {
|
|
90
|
+
inputPerMillion: 2,
|
|
91
|
+
outputPerMillion: 12,
|
|
92
|
+
cachedInputPerMillion: 0.2
|
|
93
|
+
},
|
|
94
|
+
"gemini-2.0-flash": {
|
|
95
|
+
inputPerMillion: 0.1,
|
|
96
|
+
outputPerMillion: 0.4,
|
|
97
|
+
cachedInputPerMillion: 0.025,
|
|
98
|
+
inputByModalityPerMillion: {
|
|
99
|
+
text: 0.1,
|
|
100
|
+
image: 0.1,
|
|
101
|
+
video: 0.1,
|
|
102
|
+
audio: 0.7
|
|
103
|
+
},
|
|
104
|
+
cachedByModalityPerMillion: {
|
|
105
|
+
text: 0.025,
|
|
106
|
+
image: 0.025,
|
|
107
|
+
video: 0.025,
|
|
108
|
+
audio: 0.175
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"gemini-2.0-flash-001": {
|
|
112
|
+
inputPerMillion: 0.1,
|
|
113
|
+
outputPerMillion: 0.4,
|
|
114
|
+
cachedInputPerMillion: 0.025,
|
|
115
|
+
inputByModalityPerMillion: {
|
|
116
|
+
text: 0.1,
|
|
117
|
+
image: 0.1,
|
|
118
|
+
video: 0.1,
|
|
119
|
+
audio: 0.7
|
|
120
|
+
},
|
|
121
|
+
cachedByModalityPerMillion: {
|
|
122
|
+
text: 0.025,
|
|
123
|
+
image: 0.025,
|
|
124
|
+
video: 0.025,
|
|
125
|
+
audio: 0.175
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"gemini-2.0-flash-lite": {
|
|
129
|
+
inputPerMillion: 0.075,
|
|
130
|
+
outputPerMillion: 0.3
|
|
131
|
+
},
|
|
132
|
+
"gemini-2.0-flash-lite-001": {
|
|
133
|
+
inputPerMillion: 0.075,
|
|
134
|
+
outputPerMillion: 0.3
|
|
135
|
+
},
|
|
136
|
+
"gemini-2.5-computer-use-preview-10-2025": {
|
|
137
|
+
inputPerMillion: 1.25,
|
|
138
|
+
longInputPerMillion: 2.5,
|
|
139
|
+
outputPerMillion: 10,
|
|
140
|
+
longOutputPerMillion: 15,
|
|
141
|
+
longContextThreshold: 2e5
|
|
142
|
+
},
|
|
143
|
+
"gemini-2.5-flash-preview-tts": {
|
|
144
|
+
inputPerMillion: 0.5,
|
|
145
|
+
outputPerMillion: 10,
|
|
146
|
+
outputByModalityPerMillion: {
|
|
147
|
+
audio: 10
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
"gemini-2.5-pro-preview-tts": {
|
|
151
|
+
inputPerMillion: 1,
|
|
152
|
+
outputPerMillion: 20,
|
|
153
|
+
outputByModalityPerMillion: {
|
|
154
|
+
audio: 20
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
"gemini-robotics-er-1.5-preview": {
|
|
158
|
+
inputPerMillion: 0.3,
|
|
159
|
+
outputPerMillion: 2.5,
|
|
160
|
+
inputByModalityPerMillion: {
|
|
161
|
+
text: 0.3,
|
|
162
|
+
image: 0.3,
|
|
163
|
+
video: 0.3,
|
|
164
|
+
audio: 1
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
"gemini-2.5-flash-image": {
|
|
168
|
+
inputPerMillion: 0.3,
|
|
169
|
+
outputImagePerImage: 0.039
|
|
170
|
+
},
|
|
171
|
+
"gemini-3.1-flash-image-preview": {
|
|
172
|
+
inputPerMillion: 0.5,
|
|
173
|
+
outputPerMillion: 3,
|
|
174
|
+
outputImagePerImage: 0.045
|
|
175
|
+
},
|
|
176
|
+
"gemini-3-pro-image-preview": {
|
|
177
|
+
inputPerMillion: 2,
|
|
178
|
+
outputPerMillion: 12,
|
|
179
|
+
outputImagePerImage: 0.134
|
|
180
|
+
},
|
|
181
|
+
"nano-banana-pro-preview": {
|
|
182
|
+
inputPerMillion: 2,
|
|
183
|
+
outputPerMillion: 12,
|
|
184
|
+
outputImagePerImage: 0.134
|
|
185
|
+
},
|
|
186
|
+
"imagen-4.0-generate-001": {
|
|
187
|
+
inputPerMillion: 0,
|
|
188
|
+
outputImagePerImage: 0.04
|
|
189
|
+
},
|
|
190
|
+
"imagen-4.0-fast-generate-001": {
|
|
191
|
+
inputPerMillion: 0,
|
|
192
|
+
outputImagePerImage: 0.02
|
|
193
|
+
},
|
|
194
|
+
"imagen-4.0-ultra-generate-001": {
|
|
195
|
+
inputPerMillion: 0,
|
|
196
|
+
outputImagePerImage: 0.06
|
|
197
|
+
},
|
|
198
|
+
"imagen-3.0-capability-001": {
|
|
199
|
+
inputPerMillion: 0,
|
|
200
|
+
outputImagePerImage: 0.04
|
|
201
|
+
},
|
|
202
|
+
"gemma-4-31b-it": {
|
|
203
|
+
inputPerMillion: 0,
|
|
204
|
+
outputPerMillion: 0,
|
|
205
|
+
cachedInputPerMillion: 0
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
var MODEL_PRICING_PREFIXES = [
|
|
209
|
+
{
|
|
210
|
+
prefix: "gemini-3.1-pro-preview",
|
|
211
|
+
pricing: MODEL_PRICING["gemini-3.1-pro-preview"]
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
prefix: "gemini-3-pro-preview",
|
|
215
|
+
pricing: MODEL_PRICING["gemini-3-pro-preview"]
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
prefix: "gemini-3-flash-preview",
|
|
219
|
+
pricing: MODEL_PRICING["gemini-3-flash-preview"]
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
prefix: "gemini-3.1-flash-lite-preview",
|
|
223
|
+
pricing: MODEL_PRICING["gemini-3.1-flash-lite-preview"]
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
prefix: "gemini-2.5-flash-lite-preview-",
|
|
227
|
+
pricing: MODEL_PRICING["gemini-2.5-flash-lite"]
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
prefix: "gemini-flash-latest",
|
|
231
|
+
pricing: MODEL_PRICING["gemini-2.5-flash"]
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
prefix: "gemini-flash-lite-latest",
|
|
235
|
+
pricing: MODEL_PRICING["gemini-2.5-flash-lite"]
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
prefix: "gemini-pro-latest",
|
|
239
|
+
pricing: MODEL_PRICING["gemini-2.5-pro"]
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
prefix: "gemma-4-",
|
|
243
|
+
pricing: {
|
|
244
|
+
inputPerMillion: 0,
|
|
245
|
+
outputPerMillion: 0,
|
|
246
|
+
cachedInputPerMillion: 0
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
prefix: "gemma-3-",
|
|
251
|
+
pricing: {
|
|
252
|
+
inputPerMillion: 0,
|
|
253
|
+
outputPerMillion: 0,
|
|
254
|
+
cachedInputPerMillion: 0
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
prefix: "gemma-3n-",
|
|
259
|
+
pricing: {
|
|
260
|
+
inputPerMillion: 0,
|
|
261
|
+
outputPerMillion: 0,
|
|
262
|
+
cachedInputPerMillion: 0
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
];
|
|
266
|
+
function normalizeGoogleModelId(modelId) {
|
|
267
|
+
return modelId.trim().toLowerCase().replace(/^google\//, "").replace(/^models\//, "").replace(/^publishers\/google\/models\//, "");
|
|
268
|
+
}
|
|
269
|
+
function normalizeModality(modality) {
|
|
270
|
+
const normalized = (modality || "").trim().toLowerCase();
|
|
271
|
+
if (normalized === "text") return "text";
|
|
272
|
+
if (normalized === "image") return "image";
|
|
273
|
+
if (normalized === "video") return "video";
|
|
274
|
+
if (normalized === "audio") return "audio";
|
|
275
|
+
if (normalized === "document") return "document";
|
|
276
|
+
return "unspecified";
|
|
277
|
+
}
|
|
278
|
+
function toModalityCounts(details) {
|
|
279
|
+
const counts = {};
|
|
280
|
+
for (const detail of details || []) {
|
|
281
|
+
const modality = normalizeModality(detail.modality);
|
|
282
|
+
const tokenCount = Math.max(detail.tokenCount ?? 0, 0);
|
|
283
|
+
counts[modality] = (counts[modality] ?? 0) + tokenCount;
|
|
284
|
+
}
|
|
285
|
+
return counts;
|
|
286
|
+
}
|
|
287
|
+
function sumModalityCosts(counts, modalityRates, defaultRate) {
|
|
288
|
+
let total = 0;
|
|
289
|
+
for (const [modality, tokenCount] of Object.entries(counts)) {
|
|
290
|
+
if (!tokenCount) continue;
|
|
291
|
+
const rate = modalityRates?.[modality] ?? defaultRate;
|
|
292
|
+
total += tokenCount / 1e6 * rate;
|
|
293
|
+
}
|
|
294
|
+
return total;
|
|
295
|
+
}
|
|
296
|
+
function getGoogleModelPricing(modelId) {
|
|
297
|
+
const normalizedModelId = normalizeGoogleModelId(modelId);
|
|
298
|
+
const exact = MODEL_PRICING[normalizedModelId];
|
|
299
|
+
if (exact) return exact;
|
|
300
|
+
return MODEL_PRICING_PREFIXES.find((entry) => normalizedModelId.startsWith(entry.prefix))?.pricing;
|
|
301
|
+
}
|
|
302
|
+
function calculateGoogleUsageCost(modelId, usage, imageCount = 0) {
|
|
303
|
+
const pricing = getGoogleModelPricing(modelId);
|
|
304
|
+
if (!pricing) return void 0;
|
|
305
|
+
const cachedTokens = usage.cachedTokens ?? 0;
|
|
306
|
+
const uncachedPromptTokens = Math.max(0, usage.promptTokens - cachedTokens);
|
|
307
|
+
const useLongContext = pricing.longContextThreshold != null && usage.promptTokens > pricing.longContextThreshold;
|
|
308
|
+
const inputRate = useLongContext ? pricing.longInputPerMillion ?? pricing.inputPerMillion : pricing.inputPerMillion;
|
|
309
|
+
const outputRate = useLongContext ? pricing.longOutputPerMillion ?? pricing.outputPerMillion ?? 0 : pricing.outputPerMillion ?? 0;
|
|
310
|
+
const cachedRate = useLongContext ? pricing.longCachedInputPerMillion ?? pricing.cachedInputPerMillion ?? 0 : pricing.cachedInputPerMillion ?? 0;
|
|
311
|
+
const billableOutputTokens = usage.completionTokens + (usage.reasoningTokens ?? 0);
|
|
312
|
+
const promptModalityCounts = toModalityCounts(usage.promptTokenDetails);
|
|
313
|
+
const cachedModalityCounts = toModalityCounts(usage.cachedTokenDetails);
|
|
314
|
+
const uncachedPromptModalityCounts = {};
|
|
315
|
+
for (const modality of /* @__PURE__ */ new Set([
|
|
316
|
+
...Object.keys(promptModalityCounts),
|
|
317
|
+
...Object.keys(cachedModalityCounts)
|
|
318
|
+
])) {
|
|
319
|
+
uncachedPromptModalityCounts[modality] = Math.max(
|
|
320
|
+
(promptModalityCounts[modality] ?? 0) - (cachedModalityCounts[modality] ?? 0),
|
|
321
|
+
0
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
const completionModalityCounts = toModalityCounts(usage.completionTokenDetails);
|
|
325
|
+
if (usage.reasoningTokens) {
|
|
326
|
+
completionModalityCounts.text = (completionModalityCounts.text ?? 0) + usage.reasoningTokens;
|
|
327
|
+
}
|
|
328
|
+
const hasPromptModalityPricing = Object.keys(uncachedPromptModalityCounts).length > 0 && pricing.inputByModalityPerMillion;
|
|
329
|
+
const hasCachedModalityPricing = Object.keys(cachedModalityCounts).length > 0 && pricing.cachedByModalityPerMillion;
|
|
330
|
+
const hasOutputModalityPricing = Object.keys(completionModalityCounts).length > 0 && pricing.outputByModalityPerMillion;
|
|
331
|
+
const inputCost = hasPromptModalityPricing ? sumModalityCosts(uncachedPromptModalityCounts, pricing.inputByModalityPerMillion, inputRate) : uncachedPromptTokens / 1e6 * inputRate;
|
|
332
|
+
const cachedCost = hasCachedModalityPricing ? sumModalityCosts(cachedModalityCounts, pricing.cachedByModalityPerMillion, cachedRate) : cachedTokens / 1e6 * cachedRate;
|
|
333
|
+
const outputCost = hasOutputModalityPricing ? sumModalityCosts(completionModalityCounts, pricing.outputByModalityPerMillion, outputRate) : billableOutputTokens / 1e6 * outputRate;
|
|
334
|
+
const imageCost = imageCount * (pricing.outputImagePerImage ?? 0);
|
|
335
|
+
return Number((inputCost + cachedCost + outputCost + imageCost).toFixed(12));
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// src/GoogleProvider.ts
|
|
339
|
+
var STATIC_MODELS = [
|
|
340
|
+
{
|
|
341
|
+
id: "gemma-4-31b-it",
|
|
342
|
+
name: "Gemma 4 31B IT",
|
|
343
|
+
description: "Hosted Gemma 4 instruction-tuned model with image input and optional thinking.",
|
|
344
|
+
capabilities: {
|
|
345
|
+
supportsImages: true,
|
|
346
|
+
supportsToolCalls: false,
|
|
347
|
+
supportsStreaming: true,
|
|
348
|
+
supportsJsonMode: false,
|
|
349
|
+
maxContextTokens: 262144,
|
|
350
|
+
reasoningLevels: { 0: null, 100: "high" }
|
|
351
|
+
}
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
id: "gemini-2.5-pro",
|
|
355
|
+
name: "Gemini 2.5 Pro",
|
|
356
|
+
description: "State-of-the-art Gemini model for coding and reasoning.",
|
|
357
|
+
capabilities: {
|
|
358
|
+
supportsImages: true,
|
|
359
|
+
supportsToolCalls: true,
|
|
360
|
+
supportsStreaming: true,
|
|
361
|
+
supportsJsonMode: true,
|
|
362
|
+
maxContextTokens: 1048576,
|
|
363
|
+
reasoningLevels: { 0: null, 50: "medium", 100: "high" }
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
id: "gemini-2.5-flash",
|
|
368
|
+
name: "Gemini 2.5 Flash",
|
|
369
|
+
description: "Fast multimodal Gemini model for general-purpose tasks.",
|
|
370
|
+
capabilities: {
|
|
371
|
+
supportsImages: true,
|
|
372
|
+
supportsToolCalls: true,
|
|
373
|
+
supportsStreaming: true,
|
|
374
|
+
supportsJsonMode: true,
|
|
375
|
+
maxContextTokens: 1048576
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
id: "gemini-2.5-flash-lite",
|
|
380
|
+
name: "Gemini 2.5 Flash-Lite",
|
|
381
|
+
description: "Low-cost Gemini model for high-volume workloads.",
|
|
382
|
+
capabilities: {
|
|
383
|
+
supportsImages: true,
|
|
384
|
+
supportsToolCalls: true,
|
|
385
|
+
supportsStreaming: true,
|
|
386
|
+
supportsJsonMode: true,
|
|
387
|
+
maxContextTokens: 1048576
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
id: "gemini-2.5-flash-image",
|
|
392
|
+
name: "Gemini 2.5 Flash Image",
|
|
393
|
+
description: "Gemini image generation model with native image output.",
|
|
394
|
+
capabilities: {
|
|
395
|
+
supportsImages: true,
|
|
396
|
+
supportsToolCalls: true,
|
|
397
|
+
supportsStreaming: true,
|
|
398
|
+
supportsJsonMode: false,
|
|
399
|
+
maxContextTokens: 1048576
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
id: "gemini-3-pro-image-preview",
|
|
404
|
+
name: "Gemini 3 Pro Image Preview",
|
|
405
|
+
description: "High-end Gemini image-preview model with image generation output.",
|
|
406
|
+
capabilities: {
|
|
407
|
+
supportsImages: true,
|
|
408
|
+
supportsToolCalls: true,
|
|
409
|
+
supportsStreaming: true,
|
|
410
|
+
supportsJsonMode: false,
|
|
411
|
+
maxContextTokens: 1048576
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
id: "gemini-3.1-flash-image-preview",
|
|
416
|
+
name: "Gemini 3.1 Flash Image Preview",
|
|
417
|
+
description: "Fast Gemini image-preview model with image output.",
|
|
418
|
+
capabilities: {
|
|
419
|
+
supportsImages: true,
|
|
420
|
+
supportsToolCalls: true,
|
|
421
|
+
supportsStreaming: true,
|
|
422
|
+
supportsJsonMode: false,
|
|
423
|
+
maxContextTokens: 1048576
|
|
424
|
+
}
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
id: "imagen-4.0-generate-001",
|
|
428
|
+
name: "Imagen 4 Generate",
|
|
429
|
+
description: "Google Imagen model for image generation.",
|
|
430
|
+
capabilities: {
|
|
431
|
+
supportsImages: true,
|
|
432
|
+
supportsToolCalls: false,
|
|
433
|
+
supportsStreaming: false,
|
|
434
|
+
supportsJsonMode: false,
|
|
435
|
+
maxContextTokens: 0
|
|
436
|
+
}
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
id: "imagen-3.0-capability-001",
|
|
440
|
+
name: "Imagen 3 Capability",
|
|
441
|
+
description: "Google Imagen model for image editing.",
|
|
442
|
+
capabilities: {
|
|
443
|
+
supportsImages: true,
|
|
444
|
+
supportsToolCalls: false,
|
|
445
|
+
supportsStreaming: false,
|
|
446
|
+
supportsJsonMode: false,
|
|
447
|
+
maxContextTokens: 0
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
];
|
|
451
|
+
function normalizeModelId(modelId) {
|
|
452
|
+
return modelId.trim().replace(/^google\//, "").replace(/^models\//, "").replace(/^publishers\/google\/models\//, "");
|
|
453
|
+
}
|
|
454
|
+
function isImagenModel(modelId) {
|
|
455
|
+
return normalizeModelId(modelId).startsWith("imagen-");
|
|
456
|
+
}
|
|
457
|
+
function supportsGoogleVision(model, normalizedId) {
|
|
458
|
+
const description = (model.description || "").toLowerCase();
|
|
459
|
+
if (isImagenModel(normalizedId)) {
|
|
460
|
+
return true;
|
|
461
|
+
}
|
|
462
|
+
if (normalizedId.startsWith("gemini-")) {
|
|
463
|
+
return true;
|
|
464
|
+
}
|
|
465
|
+
if (normalizedId.startsWith("gemma-3") || normalizedId.startsWith("gemma-4")) {
|
|
466
|
+
return true;
|
|
467
|
+
}
|
|
468
|
+
return ["multimodal", "image", "vision", "video", "audio"].some((term) => description.includes(term));
|
|
469
|
+
}
|
|
470
|
+
function supportsGoogleToolCalls(normalizedId) {
|
|
471
|
+
return normalizedId.startsWith("gemini-") || normalizedId.startsWith("functiongemma");
|
|
472
|
+
}
|
|
473
|
+
function inferGoogleReasoningLevels(model, normalizedId) {
|
|
474
|
+
if (!model.thinking) return void 0;
|
|
475
|
+
if (normalizedId.startsWith("gemma-")) {
|
|
476
|
+
return { 0: null, 100: "high" };
|
|
477
|
+
}
|
|
478
|
+
return { 0: null, 50: "medium", 100: "high" };
|
|
479
|
+
}
|
|
480
|
+
function mapDynamicCapabilities(model) {
|
|
481
|
+
const normalizedId = normalizeModelId(model.name || model.displayName || "");
|
|
482
|
+
const supportedActions = new Set(model.supportedActions || []);
|
|
483
|
+
const supportsContentGeneration = supportedActions.has("generateContent") || normalizedId.startsWith("gemini-") || normalizedId.startsWith("gemma-");
|
|
484
|
+
const supportsTools = supportsGoogleToolCalls(normalizedId);
|
|
485
|
+
return {
|
|
486
|
+
supportsImages: supportsGoogleVision(model, normalizedId),
|
|
487
|
+
supportsToolCalls: supportsTools,
|
|
488
|
+
supportsStreaming: supportsContentGeneration && !isImagenModel(normalizedId),
|
|
489
|
+
supportsJsonMode: supportsTools,
|
|
490
|
+
maxContextTokens: model.inputTokenLimit,
|
|
491
|
+
maxOutputTokens: model.outputTokenLimit,
|
|
492
|
+
reasoningLevels: inferGoogleReasoningLevels(model, normalizedId)
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
function toProviderModelInfo(model) {
|
|
496
|
+
const id = normalizeModelId(model.name || model.displayName || "");
|
|
497
|
+
return {
|
|
498
|
+
id,
|
|
499
|
+
name: model.displayName || id,
|
|
500
|
+
description: model.description,
|
|
501
|
+
contextLength: model.inputTokenLimit,
|
|
502
|
+
iconId: getGoogleIconDataUri(),
|
|
503
|
+
slug: id
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
function mapFinishReason(value) {
|
|
507
|
+
switch (value) {
|
|
508
|
+
case "MAX_TOKENS":
|
|
509
|
+
return "length";
|
|
510
|
+
case "SAFETY":
|
|
511
|
+
case "IMAGE_SAFETY":
|
|
512
|
+
case "PROHIBITED_CONTENT":
|
|
513
|
+
case "IMAGE_PROHIBITED_CONTENT":
|
|
514
|
+
return "content_filter";
|
|
515
|
+
case "MALFORMED_FUNCTION_CALL":
|
|
516
|
+
case "UNEXPECTED_TOOL_CALL":
|
|
517
|
+
return "error";
|
|
518
|
+
case "STOP":
|
|
519
|
+
default:
|
|
520
|
+
return "stop";
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
function toolChoiceToGoogle(choice) {
|
|
524
|
+
if (choice === "auto") {
|
|
525
|
+
return { mode: FunctionCallingConfigMode.AUTO };
|
|
526
|
+
}
|
|
527
|
+
if (choice === "none") {
|
|
528
|
+
return { mode: FunctionCallingConfigMode.NONE };
|
|
529
|
+
}
|
|
530
|
+
if (choice === "required") {
|
|
531
|
+
return { mode: FunctionCallingConfigMode.ANY };
|
|
532
|
+
}
|
|
533
|
+
if (choice && typeof choice === "object" && "name" in choice) {
|
|
534
|
+
return {
|
|
535
|
+
mode: FunctionCallingConfigMode.ANY,
|
|
536
|
+
allowedFunctionNames: [choice.name]
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
return void 0;
|
|
540
|
+
}
|
|
541
|
+
function transformTools(tools) {
|
|
542
|
+
if (!tools?.length) return void 0;
|
|
543
|
+
return [{
|
|
544
|
+
functionDeclarations: tools.map((tool) => ({
|
|
545
|
+
name: tool.function.name,
|
|
546
|
+
description: tool.function.description,
|
|
547
|
+
parameters: tool.function.parameters || {
|
|
548
|
+
type: "object",
|
|
549
|
+
properties: {},
|
|
550
|
+
required: []
|
|
551
|
+
}
|
|
552
|
+
}))
|
|
553
|
+
}];
|
|
554
|
+
}
|
|
555
|
+
function normalizeInlineBytes(data, mediaType) {
|
|
556
|
+
const value = data || "";
|
|
557
|
+
const match = value.match(/^data:([^;]+);base64,(.*)$/);
|
|
558
|
+
if (!match) {
|
|
559
|
+
return { data: value, mediaType };
|
|
560
|
+
}
|
|
561
|
+
return {
|
|
562
|
+
data: match[2],
|
|
563
|
+
mediaType: match[1] || mediaType
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
function buildUserParts(message) {
|
|
567
|
+
if (typeof message.content === "string") {
|
|
568
|
+
return [{ text: message.content }];
|
|
569
|
+
}
|
|
570
|
+
return message.content.map((part) => {
|
|
571
|
+
if (part.type === "text") {
|
|
572
|
+
return { text: part.text };
|
|
573
|
+
}
|
|
574
|
+
if (part.type === "image") {
|
|
575
|
+
const normalized = normalizeInlineBytes(part.data, part.mediaType || "image/png");
|
|
576
|
+
return createPartFromBase64(normalized.data, normalized.mediaType || "image/png");
|
|
577
|
+
}
|
|
578
|
+
if (part.type === "image_url") {
|
|
579
|
+
const url = part.image_url?.url || "";
|
|
580
|
+
if (url.startsWith("data:")) {
|
|
581
|
+
const match = url.match(/^data:([^;]+);base64,(.*)$/);
|
|
582
|
+
if (match) {
|
|
583
|
+
return createPartFromBase64(match[2], match[1]);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return {
|
|
587
|
+
fileData: {
|
|
588
|
+
mimeType: "image/*",
|
|
589
|
+
fileUri: url
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
return {
|
|
594
|
+
inlineData: {
|
|
595
|
+
mimeType: part.mediaType,
|
|
596
|
+
data: part.data
|
|
597
|
+
}
|
|
598
|
+
};
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
function buildAssistantParts(message) {
|
|
602
|
+
const parts = [];
|
|
603
|
+
if (message.content) {
|
|
604
|
+
parts.push({ text: message.content });
|
|
605
|
+
}
|
|
606
|
+
if (message.reasoning) {
|
|
607
|
+
parts.push({ text: message.reasoning, thought: true });
|
|
608
|
+
}
|
|
609
|
+
if (message.toolCalls?.length) {
|
|
610
|
+
for (const toolCall of message.toolCalls) {
|
|
611
|
+
parts.push({
|
|
612
|
+
functionCall: {
|
|
613
|
+
id: toolCall.id,
|
|
614
|
+
name: toolCall.name,
|
|
615
|
+
args: toolCall.arguments
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return parts;
|
|
621
|
+
}
|
|
622
|
+
function buildToolParts(message) {
|
|
623
|
+
const response = {};
|
|
624
|
+
if (typeof message.content === "string") {
|
|
625
|
+
response.output = message.content;
|
|
626
|
+
} else if ("type" in message.content) {
|
|
627
|
+
if (message.content.type === "text") response.output = message.content.text;
|
|
628
|
+
else if (message.content.type === "error") response.error = message.content.error;
|
|
629
|
+
else response.output = message.content;
|
|
630
|
+
} else {
|
|
631
|
+
response.output = message.content;
|
|
632
|
+
}
|
|
633
|
+
const imageParts = message.attachments?.filter((attachment) => attachment.type === "image" && attachment.data).map((attachment, index) => {
|
|
634
|
+
const normalized = normalizeInlineBytes(attachment.data, attachment.mediaType);
|
|
635
|
+
return {
|
|
636
|
+
inlineData: {
|
|
637
|
+
mimeType: normalized.mediaType,
|
|
638
|
+
data: normalized.data
|
|
639
|
+
},
|
|
640
|
+
partMetadata: { attachmentIndex: index }
|
|
641
|
+
};
|
|
642
|
+
}) || [];
|
|
643
|
+
return [
|
|
644
|
+
createPartFromFunctionResponse(
|
|
645
|
+
message.toolCallId,
|
|
646
|
+
message.toolName,
|
|
647
|
+
response,
|
|
648
|
+
imageParts.length ? imageParts.map((part) => ({ inlineData: part.inlineData })) : void 0
|
|
649
|
+
)
|
|
650
|
+
];
|
|
651
|
+
}
|
|
652
|
+
function buildContents(messages) {
|
|
653
|
+
const contents = [];
|
|
654
|
+
const systemMessages = messages.filter((message) => message.role === "system").map((message) => message.content);
|
|
655
|
+
const systemInstruction = systemMessages.length ? { role: "user", parts: [{ text: systemMessages.join("\n\n") }] } : void 0;
|
|
656
|
+
for (const message of messages) {
|
|
657
|
+
if (message.role === "system") continue;
|
|
658
|
+
if (message.role === "user") {
|
|
659
|
+
contents.push({ role: "user", parts: buildUserParts(message) });
|
|
660
|
+
continue;
|
|
661
|
+
}
|
|
662
|
+
if (message.role === "assistant") {
|
|
663
|
+
contents.push({ role: "model", parts: buildAssistantParts(message) });
|
|
664
|
+
continue;
|
|
665
|
+
}
|
|
666
|
+
contents.push({ role: "user", parts: buildToolParts(message) });
|
|
667
|
+
}
|
|
668
|
+
return { systemInstruction, contents };
|
|
669
|
+
}
|
|
670
|
+
function extractReasoningFromParts(parts) {
|
|
671
|
+
if (!parts?.length) return null;
|
|
672
|
+
const text = parts.filter((part) => part.thought && typeof part.text === "string").map((part) => part.text).join("");
|
|
673
|
+
return text || null;
|
|
674
|
+
}
|
|
675
|
+
function extractImagesFromParts(parts) {
|
|
676
|
+
if (!parts?.length) return void 0;
|
|
677
|
+
const images = parts.filter((part) => part.inlineData?.mimeType?.startsWith("image/")).map((part, index) => ({
|
|
678
|
+
id: `image_${index}`,
|
|
679
|
+
data: part.inlineData?.data || "",
|
|
680
|
+
mediaType: part.inlineData?.mimeType || "image/png"
|
|
681
|
+
}));
|
|
682
|
+
return images.length ? images : void 0;
|
|
683
|
+
}
|
|
684
|
+
function extractToolCalls(parts) {
|
|
685
|
+
if (!parts?.length) return void 0;
|
|
686
|
+
const toolCalls = parts.filter((part) => part.functionCall?.name).map((part) => ({
|
|
687
|
+
id: part.functionCall?.id || crypto.randomUUID(),
|
|
688
|
+
name: part.functionCall?.name || "tool",
|
|
689
|
+
arguments: part.functionCall?.args || {}
|
|
690
|
+
}));
|
|
691
|
+
return toolCalls.length ? toolCalls : void 0;
|
|
692
|
+
}
|
|
693
|
+
function transformUsage(modelId, usage, imageCount = 0) {
|
|
694
|
+
const mapped = {
|
|
695
|
+
promptTokens: usage?.promptTokenCount || 0,
|
|
696
|
+
completionTokens: usage?.candidatesTokenCount || 0,
|
|
697
|
+
totalTokens: usage?.totalTokenCount || 0,
|
|
698
|
+
reasoningTokens: usage?.thoughtsTokenCount,
|
|
699
|
+
cachedTokens: usage?.cachedContentTokenCount,
|
|
700
|
+
provider: "google"
|
|
701
|
+
};
|
|
702
|
+
mapped.cost = calculateGoogleUsageCost(
|
|
703
|
+
modelId,
|
|
704
|
+
{
|
|
705
|
+
...mapped,
|
|
706
|
+
promptTokenDetails: usage?.promptTokensDetails,
|
|
707
|
+
completionTokenDetails: usage?.candidatesTokensDetails || usage?.responseTokensDetails,
|
|
708
|
+
cachedTokenDetails: usage?.cacheTokensDetails
|
|
709
|
+
},
|
|
710
|
+
imageCount
|
|
711
|
+
);
|
|
712
|
+
return mapped;
|
|
713
|
+
}
|
|
714
|
+
var GoogleProvider = class _GoogleProvider {
|
|
715
|
+
name = "google";
|
|
716
|
+
specificationVersion = "1";
|
|
717
|
+
config;
|
|
718
|
+
client = null;
|
|
719
|
+
static cacheTtl = 5 * 60 * 1e3;
|
|
720
|
+
static modelsCache = null;
|
|
721
|
+
static modelsCacheTime = 0;
|
|
722
|
+
static modelMetadataCache = /* @__PURE__ */ new Map();
|
|
723
|
+
constructor(config) {
|
|
724
|
+
this.config = config;
|
|
725
|
+
}
|
|
726
|
+
getClient() {
|
|
727
|
+
if (!this.client) {
|
|
728
|
+
this.client = new GoogleGenAI({
|
|
729
|
+
apiKey: this.config.apiKey
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
return this.client;
|
|
733
|
+
}
|
|
734
|
+
supportsModel(modelId) {
|
|
735
|
+
return modelId.startsWith("gemini-") || modelId.startsWith("gemma-") || modelId.startsWith("imagen-") || modelId.startsWith("models/");
|
|
736
|
+
}
|
|
737
|
+
getIcon(_modelId) {
|
|
738
|
+
return getGoogleIconDataUri();
|
|
739
|
+
}
|
|
740
|
+
getHttpOptions() {
|
|
741
|
+
if (!this.config.baseUrl && !this.config.timeout) return void 0;
|
|
742
|
+
return {
|
|
743
|
+
...this.config.baseUrl ? { baseUrl: this.config.baseUrl } : {},
|
|
744
|
+
...this.config.timeout ? { timeout: this.config.timeout } : {}
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
async getModels(filter) {
|
|
748
|
+
const now = Date.now();
|
|
749
|
+
if (_GoogleProvider.modelsCache && now - _GoogleProvider.modelsCacheTime < _GoogleProvider.cacheTtl) {
|
|
750
|
+
return this.filterModels(_GoogleProvider.modelsCache, filter);
|
|
751
|
+
}
|
|
752
|
+
try {
|
|
753
|
+
const models = [];
|
|
754
|
+
const client = this.getClient();
|
|
755
|
+
const pager = await client.models.list({
|
|
756
|
+
config: {
|
|
757
|
+
httpOptions: this.getHttpOptions()
|
|
758
|
+
}
|
|
759
|
+
});
|
|
760
|
+
for await (const model of pager) {
|
|
761
|
+
const id = normalizeModelId(model.name || "");
|
|
762
|
+
if (!id) continue;
|
|
763
|
+
const supportsGeneration = model.supportedActions?.some(
|
|
764
|
+
(action) => ["generateContent", "generateImages", "editImage", "predict"].includes(action)
|
|
765
|
+
);
|
|
766
|
+
if (!supportsGeneration) continue;
|
|
767
|
+
_GoogleProvider.modelMetadataCache.set(id, model);
|
|
768
|
+
models.push(toProviderModelInfo(model));
|
|
769
|
+
}
|
|
770
|
+
for (const staticModel of STATIC_MODELS) {
|
|
771
|
+
if (!models.some((model) => model.id === staticModel.id)) {
|
|
772
|
+
models.push({
|
|
773
|
+
id: staticModel.id,
|
|
774
|
+
name: staticModel.name,
|
|
775
|
+
description: staticModel.description,
|
|
776
|
+
iconId: this.getIcon(staticModel.id),
|
|
777
|
+
slug: staticModel.id
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
_GoogleProvider.modelsCache = models.sort((a, b) => a.name.localeCompare(b.name));
|
|
782
|
+
_GoogleProvider.modelsCacheTime = now;
|
|
783
|
+
return this.filterModels(_GoogleProvider.modelsCache, filter);
|
|
784
|
+
} catch (error) {
|
|
785
|
+
console.error("Failed to list Google models:", error);
|
|
786
|
+
return this.filterModels(
|
|
787
|
+
STATIC_MODELS.map((model) => ({
|
|
788
|
+
id: model.id,
|
|
789
|
+
name: model.name,
|
|
790
|
+
description: model.description,
|
|
791
|
+
iconId: this.getIcon(model.id),
|
|
792
|
+
slug: model.id
|
|
793
|
+
})),
|
|
794
|
+
filter
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
filterModels(models, filter) {
|
|
799
|
+
if (!filter) return models;
|
|
800
|
+
const query = filter.toLowerCase();
|
|
801
|
+
return models.filter(
|
|
802
|
+
(model) => model.id.toLowerCase().includes(query) || model.name.toLowerCase().includes(query) || (model.description?.toLowerCase().includes(query) ?? false)
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
async getModelMetadata(modelId) {
|
|
806
|
+
const normalized = normalizeModelId(modelId);
|
|
807
|
+
const cached = _GoogleProvider.modelMetadataCache.get(normalized);
|
|
808
|
+
if (cached) {
|
|
809
|
+
return cached;
|
|
810
|
+
}
|
|
811
|
+
try {
|
|
812
|
+
const model = await this.getClient().models.get({
|
|
813
|
+
model: normalized,
|
|
814
|
+
config: {
|
|
815
|
+
httpOptions: this.getHttpOptions()
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
_GoogleProvider.modelMetadataCache.set(normalized, model);
|
|
819
|
+
return model;
|
|
820
|
+
} catch {
|
|
821
|
+
return null;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
async getModelCapabilities(modelId) {
|
|
825
|
+
const normalized = normalizeModelId(modelId);
|
|
826
|
+
const staticModel = STATIC_MODELS.find((model) => model.id === normalized);
|
|
827
|
+
if (staticModel) {
|
|
828
|
+
return { ...staticModel.capabilities };
|
|
829
|
+
}
|
|
830
|
+
try {
|
|
831
|
+
const metadata = await this.getModelMetadata(normalized);
|
|
832
|
+
if (metadata) {
|
|
833
|
+
return mapDynamicCapabilities(metadata);
|
|
834
|
+
}
|
|
835
|
+
const models = await this.getModels();
|
|
836
|
+
const found = models.find((model) => model.id === normalized);
|
|
837
|
+
if (!found) return null;
|
|
838
|
+
return {
|
|
839
|
+
supportsImages: normalized.startsWith("gemini-") || normalized.startsWith("gemma-") || normalized.includes("image"),
|
|
840
|
+
supportsToolCalls: supportsGoogleToolCalls(normalized),
|
|
841
|
+
supportsStreaming: !isImagenModel(normalized),
|
|
842
|
+
supportsJsonMode: supportsGoogleToolCalls(normalized),
|
|
843
|
+
maxContextTokens: found.contextLength
|
|
844
|
+
};
|
|
845
|
+
} catch {
|
|
846
|
+
return null;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
buildGenerateContentParams(request) {
|
|
850
|
+
const providerOptions = request.providerOptions || {};
|
|
851
|
+
const { systemInstruction, contents } = buildContents(request.messages);
|
|
852
|
+
const config = {
|
|
853
|
+
...this.getHttpOptions() ? { httpOptions: this.getHttpOptions() } : {},
|
|
854
|
+
...systemInstruction ? { systemInstruction } : {},
|
|
855
|
+
...typeof request.temperature === "number" ? { temperature: request.temperature } : {},
|
|
856
|
+
...typeof request.topP === "number" ? { topP: request.topP } : {},
|
|
857
|
+
...typeof request.topK === "number" ? { topK: request.topK } : {},
|
|
858
|
+
...typeof request.maxOutputTokens === "number" ? { maxOutputTokens: request.maxOutputTokens } : {},
|
|
859
|
+
...request.stopSequences?.length ? { stopSequences: request.stopSequences } : {},
|
|
860
|
+
...request.responseFormat?.type === "json" ? {
|
|
861
|
+
responseMimeType: "application/json",
|
|
862
|
+
...request.responseFormat.schema ? { responseJsonSchema: request.responseFormat.schema } : {}
|
|
863
|
+
} : {},
|
|
864
|
+
...request.tools?.length ? { tools: transformTools(request.tools) } : {},
|
|
865
|
+
...request.tools?.length && toolChoiceToGoogle(request.toolChoice) ? { toolConfig: { functionCallingConfig: toolChoiceToGoogle(request.toolChoice) } } : {},
|
|
866
|
+
...typeof providerOptions.candidateCount === "number" ? { candidateCount: providerOptions.candidateCount } : {},
|
|
867
|
+
...Array.isArray(providerOptions.responseModalities) ? { responseModalities: providerOptions.responseModalities } : {},
|
|
868
|
+
...typeof providerOptions.mediaResolution === "string" ? { mediaResolution: providerOptions.mediaResolution } : {},
|
|
869
|
+
...typeof providerOptions.cachedContent === "string" ? { cachedContent: providerOptions.cachedContent } : {},
|
|
870
|
+
...typeof providerOptions.enableEnhancedCivicAnswers === "boolean" ? { enableEnhancedCivicAnswers: providerOptions.enableEnhancedCivicAnswers } : {},
|
|
871
|
+
...providerOptions.labels ? { labels: providerOptions.labels } : {},
|
|
872
|
+
...providerOptions.safetySettings ? { safetySettings: providerOptions.safetySettings } : {},
|
|
873
|
+
...providerOptions.thinkingConfig ? { thinkingConfig: providerOptions.thinkingConfig } : {},
|
|
874
|
+
...providerOptions.imageConfig ? { imageConfig: providerOptions.imageConfig } : {},
|
|
875
|
+
...typeof request.reasoning?.maxTokens === "number" ? { thinkingConfig: { ...providerOptions.thinkingConfig || {}, thinkingBudget: request.reasoning.maxTokens } } : {}
|
|
876
|
+
};
|
|
877
|
+
return {
|
|
878
|
+
model: normalizeModelId(request.model),
|
|
879
|
+
contents,
|
|
880
|
+
config
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
extractImagenRequest(request) {
|
|
884
|
+
const providerOptions = request.providerOptions || {};
|
|
885
|
+
const latestUser = [...request.messages].reverse().find((message) => message.role === "user");
|
|
886
|
+
const prompt = latestUser ? typeof latestUser.content === "string" ? latestUser.content : latestUser.content.filter((part) => part.type === "text").map((part) => part.text).join("\n") : "";
|
|
887
|
+
const referenceImages = latestUser && typeof latestUser.content !== "string" ? latestUser.content.filter((part) => part.type === "image").map((part, index) => {
|
|
888
|
+
const normalized = normalizeInlineBytes(part.data, part.mediaType);
|
|
889
|
+
const image = new RawReferenceImage();
|
|
890
|
+
image.referenceId = index + 1;
|
|
891
|
+
image.referenceImage = {
|
|
892
|
+
imageBytes: normalized.data,
|
|
893
|
+
mimeType: normalized.mediaType
|
|
894
|
+
};
|
|
895
|
+
return image;
|
|
896
|
+
}) : [];
|
|
897
|
+
const body = {
|
|
898
|
+
model: normalizeModelId(request.model),
|
|
899
|
+
prompt,
|
|
900
|
+
...referenceImages.length ? { referenceImages: "[binary images omitted]" } : {},
|
|
901
|
+
config: {
|
|
902
|
+
...this.getHttpOptions() ? { httpOptions: this.getHttpOptions() } : {},
|
|
903
|
+
...typeof providerOptions.numberOfImages === "number" ? { numberOfImages: providerOptions.numberOfImages } : {},
|
|
904
|
+
...typeof providerOptions.negativePrompt === "string" ? { negativePrompt: providerOptions.negativePrompt } : {},
|
|
905
|
+
...typeof providerOptions.aspectRatio === "string" ? { aspectRatio: providerOptions.aspectRatio } : {},
|
|
906
|
+
...typeof providerOptions.guidanceScale === "number" ? { guidanceScale: providerOptions.guidanceScale } : {},
|
|
907
|
+
...typeof providerOptions.seed === "number" ? { seed: providerOptions.seed } : {},
|
|
908
|
+
...typeof providerOptions.safetyFilterLevel === "string" ? { safetyFilterLevel: providerOptions.safetyFilterLevel } : {},
|
|
909
|
+
...typeof providerOptions.personGeneration === "string" ? { personGeneration: providerOptions.personGeneration } : {},
|
|
910
|
+
...typeof providerOptions.includeSafetyAttributes === "boolean" ? { includeSafetyAttributes: providerOptions.includeSafetyAttributes } : {},
|
|
911
|
+
...typeof providerOptions.includeRaiReason === "boolean" ? { includeRaiReason: providerOptions.includeRaiReason } : {},
|
|
912
|
+
...typeof providerOptions.language === "string" ? { language: providerOptions.language } : {},
|
|
913
|
+
...typeof providerOptions.outputMimeType === "string" ? { outputMimeType: providerOptions.outputMimeType } : {},
|
|
914
|
+
...typeof providerOptions.outputCompressionQuality === "number" ? { outputCompressionQuality: providerOptions.outputCompressionQuality } : {},
|
|
915
|
+
...typeof providerOptions.addWatermark === "boolean" ? { addWatermark: providerOptions.addWatermark } : {},
|
|
916
|
+
...providerOptions.labels ? { labels: providerOptions.labels } : {},
|
|
917
|
+
...typeof providerOptions.imageSize === "string" ? { imageSize: providerOptions.imageSize } : {},
|
|
918
|
+
...typeof providerOptions.enhancePrompt === "boolean" ? { enhancePrompt: providerOptions.enhancePrompt } : {},
|
|
919
|
+
...typeof providerOptions.editMode === "string" ? { editMode: providerOptions.editMode } : {},
|
|
920
|
+
...typeof providerOptions.baseSteps === "number" ? { baseSteps: providerOptions.baseSteps } : {}
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
return {
|
|
924
|
+
prompt,
|
|
925
|
+
referenceImages: referenceImages.length ? referenceImages : void 0,
|
|
926
|
+
body
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
async inspectRequest(request) {
|
|
930
|
+
if (isImagenModel(request.model)) {
|
|
931
|
+
const imagen = this.extractImagenRequest(request);
|
|
932
|
+
return {
|
|
933
|
+
body: imagen.body,
|
|
934
|
+
messagesPath: "prompt",
|
|
935
|
+
metadata: {
|
|
936
|
+
endpoint: imagen.referenceImages?.length ? `${this.config.baseUrl || "https://generativelanguage.googleapis.com"}/editImage` : `${this.config.baseUrl || "https://generativelanguage.googleapis.com"}/generateImages`,
|
|
937
|
+
headers: { "Content-Type": "application/json" }
|
|
938
|
+
}
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
return {
|
|
942
|
+
body: this.buildGenerateContentParams(request),
|
|
943
|
+
messagesPath: "contents",
|
|
944
|
+
metadata: {
|
|
945
|
+
endpoint: `${this.config.baseUrl || "https://generativelanguage.googleapis.com"}/generateContent`,
|
|
946
|
+
headers: { "Content-Type": "application/json" }
|
|
947
|
+
}
|
|
948
|
+
};
|
|
949
|
+
}
|
|
950
|
+
async generate(request) {
|
|
951
|
+
if (isImagenModel(request.model)) {
|
|
952
|
+
return this.generateImagen(request);
|
|
953
|
+
}
|
|
954
|
+
try {
|
|
955
|
+
const client = this.getClient();
|
|
956
|
+
const response = await client.models.generateContent(this.buildGenerateContentParams(request));
|
|
957
|
+
const candidate = response.candidates?.[0];
|
|
958
|
+
const parts = candidate?.content?.parts;
|
|
959
|
+
const images = extractImagesFromParts(parts);
|
|
960
|
+
const usage = transformUsage(normalizeModelId(request.model), response.usageMetadata, images?.length || 0);
|
|
961
|
+
return {
|
|
962
|
+
content: response.text || null,
|
|
963
|
+
reasoning: extractReasoningFromParts(parts),
|
|
964
|
+
reasoningDetails: extractReasoningFromParts(parts) ? [{ type: "text", text: extractReasoningFromParts(parts) || void 0, format: "google-gemini-v1" }] : void 0,
|
|
965
|
+
toolCalls: extractToolCalls(parts),
|
|
966
|
+
images,
|
|
967
|
+
finishReason: mapFinishReason(candidate?.finishReason),
|
|
968
|
+
usage,
|
|
969
|
+
metadata: {
|
|
970
|
+
provider: "google",
|
|
971
|
+
responseId: response.responseId,
|
|
972
|
+
modelVersion: response.modelVersion,
|
|
973
|
+
promptFeedback: response.promptFeedback
|
|
974
|
+
}
|
|
975
|
+
};
|
|
976
|
+
} catch (error) {
|
|
977
|
+
throw this.toProviderError(error);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
async generateImagen(request) {
|
|
981
|
+
try {
|
|
982
|
+
const client = this.getClient();
|
|
983
|
+
const imagen = this.extractImagenRequest(request);
|
|
984
|
+
const model = normalizeModelId(request.model);
|
|
985
|
+
const response = imagen.referenceImages?.length ? await client.models.editImage({
|
|
986
|
+
model,
|
|
987
|
+
prompt: imagen.prompt,
|
|
988
|
+
referenceImages: imagen.referenceImages,
|
|
989
|
+
config: imagen.body.config
|
|
990
|
+
}) : await client.models.generateImages({
|
|
991
|
+
model,
|
|
992
|
+
prompt: imagen.prompt,
|
|
993
|
+
config: imagen.body.config
|
|
994
|
+
});
|
|
995
|
+
const images = (response.generatedImages || []).filter((image) => image.image?.imageBytes).map((image, index) => ({
|
|
996
|
+
id: `image_${index}`,
|
|
997
|
+
data: image.image?.imageBytes || "",
|
|
998
|
+
mediaType: image.image?.mimeType || "image/png",
|
|
999
|
+
revisedPrompt: image.enhancedPrompt
|
|
1000
|
+
}));
|
|
1001
|
+
return {
|
|
1002
|
+
content: null,
|
|
1003
|
+
images,
|
|
1004
|
+
finishReason: "stop",
|
|
1005
|
+
usage: {
|
|
1006
|
+
promptTokens: 0,
|
|
1007
|
+
completionTokens: 0,
|
|
1008
|
+
totalTokens: 0,
|
|
1009
|
+
cost: calculateGoogleUsageCost(model, { promptTokens: 0, completionTokens: 0, cachedTokens: 0 }, images.length),
|
|
1010
|
+
provider: "google"
|
|
1011
|
+
},
|
|
1012
|
+
metadata: {
|
|
1013
|
+
provider: "google"
|
|
1014
|
+
}
|
|
1015
|
+
};
|
|
1016
|
+
} catch (error) {
|
|
1017
|
+
throw this.toProviderError(error);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
async stream(request) {
|
|
1021
|
+
if (isImagenModel(request.model)) {
|
|
1022
|
+
throw new ProviderError("Imagen models do not support streaming in Standard Agents.", "invalid_request");
|
|
1023
|
+
}
|
|
1024
|
+
const self = this;
|
|
1025
|
+
try {
|
|
1026
|
+
const client = this.getClient();
|
|
1027
|
+
const stream = await client.models.generateContentStream(this.buildGenerateContentParams(request));
|
|
1028
|
+
return {
|
|
1029
|
+
async *[Symbol.asyncIterator]() {
|
|
1030
|
+
let sawContent = false;
|
|
1031
|
+
let sawReasoning = false;
|
|
1032
|
+
let finishReason = "stop";
|
|
1033
|
+
let finalUsage = {
|
|
1034
|
+
promptTokens: 0,
|
|
1035
|
+
completionTokens: 0,
|
|
1036
|
+
totalTokens: 0,
|
|
1037
|
+
provider: "google"
|
|
1038
|
+
};
|
|
1039
|
+
let imageIndex = 0;
|
|
1040
|
+
try {
|
|
1041
|
+
for await (const chunk of stream) {
|
|
1042
|
+
const candidate = chunk.candidates?.[0];
|
|
1043
|
+
const parts = candidate?.content?.parts || [];
|
|
1044
|
+
for (const part of parts) {
|
|
1045
|
+
if (part.text && !part.thought) {
|
|
1046
|
+
sawContent = true;
|
|
1047
|
+
yield { type: "content-delta", delta: part.text };
|
|
1048
|
+
} else if (part.text && part.thought) {
|
|
1049
|
+
sawReasoning = true;
|
|
1050
|
+
yield { type: "reasoning-delta", delta: part.text };
|
|
1051
|
+
} else if (part.functionCall?.name) {
|
|
1052
|
+
const id = part.functionCall.id || crypto.randomUUID();
|
|
1053
|
+
yield { type: "tool-call-start", id, name: part.functionCall.name };
|
|
1054
|
+
yield { type: "tool-call-done", id, arguments: part.functionCall.args || {} };
|
|
1055
|
+
} else if (part.inlineData?.mimeType?.startsWith("image/")) {
|
|
1056
|
+
const image = {
|
|
1057
|
+
id: `image_${imageIndex}`,
|
|
1058
|
+
data: part.inlineData.data || "",
|
|
1059
|
+
mediaType: part.inlineData.mimeType || "image/png"
|
|
1060
|
+
};
|
|
1061
|
+
yield { type: "image-done", index: imageIndex, image };
|
|
1062
|
+
imageIndex += 1;
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
if (chunk.usageMetadata) {
|
|
1066
|
+
finalUsage = transformUsage(normalizeModelId(request.model), chunk.usageMetadata, imageIndex);
|
|
1067
|
+
}
|
|
1068
|
+
if (candidate?.finishReason) {
|
|
1069
|
+
finishReason = mapFinishReason(candidate.finishReason);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
if (sawContent) yield { type: "content-done" };
|
|
1073
|
+
if (sawReasoning) yield { type: "reasoning-done" };
|
|
1074
|
+
yield { type: "finish", finishReason, usage: finalUsage };
|
|
1075
|
+
} catch (error) {
|
|
1076
|
+
yield { type: "error", error: self.toProviderError(error).message };
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
};
|
|
1080
|
+
} catch (error) {
|
|
1081
|
+
throw this.toProviderError(error);
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
toProviderError(error) {
|
|
1085
|
+
if (error instanceof ProviderError) return error;
|
|
1086
|
+
if (error instanceof Error) {
|
|
1087
|
+
const candidate = error;
|
|
1088
|
+
const status = candidate.status || candidate.statusCode;
|
|
1089
|
+
if (status === 429) return new ProviderError(error.message, "rate_limit", status);
|
|
1090
|
+
if (status === 401 || status === 403) return new ProviderError(error.message, "auth_error", status);
|
|
1091
|
+
if (status === 400) return new ProviderError(error.message, "invalid_request", status);
|
|
1092
|
+
if (status && status >= 500) return new ProviderError(error.message, "server_error", status);
|
|
1093
|
+
if (error.name === "AbortError") return new ProviderError(error.message, "timeout");
|
|
1094
|
+
return new ProviderError(error.message, "unknown", status);
|
|
1095
|
+
}
|
|
1096
|
+
return new ProviderError(String(error), "unknown");
|
|
1097
|
+
}
|
|
1098
|
+
};
|
|
1099
|
+
|
|
1100
|
+
// src/providerOptions.ts
|
|
1101
|
+
import { z } from "zod";
|
|
1102
|
+
var googleProviderOptions = z.object({
|
|
1103
|
+
candidateCount: z.number().int().min(1).max(8).optional(),
|
|
1104
|
+
responseModalities: z.array(z.enum(["TEXT", "IMAGE", "AUDIO"])).optional(),
|
|
1105
|
+
mediaResolution: z.string().optional(),
|
|
1106
|
+
cachedContent: z.string().optional(),
|
|
1107
|
+
enableEnhancedCivicAnswers: z.boolean().optional(),
|
|
1108
|
+
labels: z.record(z.string(), z.string()).optional(),
|
|
1109
|
+
safetySettings: z.array(z.record(z.string(), z.unknown())).optional(),
|
|
1110
|
+
thinkingConfig: z.record(z.string(), z.unknown()).optional(),
|
|
1111
|
+
imageConfig: z.record(z.string(), z.unknown()).optional(),
|
|
1112
|
+
numberOfImages: z.number().int().min(1).max(4).optional(),
|
|
1113
|
+
negativePrompt: z.string().optional(),
|
|
1114
|
+
aspectRatio: z.string().optional(),
|
|
1115
|
+
guidanceScale: z.number().optional(),
|
|
1116
|
+
safetyFilterLevel: z.string().optional(),
|
|
1117
|
+
personGeneration: z.string().optional(),
|
|
1118
|
+
includeSafetyAttributes: z.boolean().optional(),
|
|
1119
|
+
includeRaiReason: z.boolean().optional(),
|
|
1120
|
+
language: z.string().optional(),
|
|
1121
|
+
outputMimeType: z.string().optional(),
|
|
1122
|
+
outputCompressionQuality: z.number().int().optional(),
|
|
1123
|
+
addWatermark: z.boolean().optional(),
|
|
1124
|
+
imageSize: z.string().optional(),
|
|
1125
|
+
enhancePrompt: z.boolean().optional(),
|
|
1126
|
+
editMode: z.string().optional(),
|
|
1127
|
+
baseSteps: z.number().int().optional()
|
|
1128
|
+
}).passthrough();
|
|
1129
|
+
|
|
1130
|
+
// src/index.ts
|
|
1131
|
+
var google = Object.assign(
|
|
1132
|
+
(config) => new GoogleProvider(config),
|
|
1133
|
+
{ providerOptions: googleProviderOptions }
|
|
1134
|
+
);
|
|
1135
|
+
export {
|
|
1136
|
+
GoogleProvider,
|
|
1137
|
+
google,
|
|
1138
|
+
googleProviderOptions
|
|
1139
|
+
};
|
|
1140
|
+
//# sourceMappingURL=index.js.map
|