@gullabs/google 0.13.0 → 0.16.0
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/NOTICE +6 -0
- package/README.md +446 -31
- package/dist/index.cjs +2248 -632
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +680 -278
- package/dist/index.d.ts +680 -278
- package/dist/index.js +2246 -634
- package/dist/index.js.map +1 -1
- package/package.json +18 -10
package/dist/index.cjs
CHANGED
|
@@ -17,9 +17,18 @@ function requireApiKey(auth) {
|
|
|
17
17
|
var FLEX_DEFAULT_TIMEOUT_MS = 15e5;
|
|
18
18
|
var STANDARD_DEFAULT_TIMEOUT_MS = 3e5;
|
|
19
19
|
var TRANSPORT_TIMEOUT_BUFFER_MS = 5e3;
|
|
20
|
+
var MAX_TIMER_MS = 2147483647;
|
|
21
|
+
var GOOGLE_MAX_TIMEOUT_MS = MAX_TIMER_MS - TRANSPORT_TIMEOUT_BUFFER_MS;
|
|
22
|
+
var GEMINI_API_ROOT = "https://generativelanguage.googleapis.com";
|
|
23
|
+
async function newGoogleGenAI(auth) {
|
|
24
|
+
const { GoogleGenAI: Sdk } = await import('@google/genai');
|
|
25
|
+
return new Sdk({
|
|
26
|
+
apiKey: requireApiKey(auth),
|
|
27
|
+
httpOptions: { baseUrl: `${GEMINI_API_ROOT}/` }
|
|
28
|
+
});
|
|
29
|
+
}
|
|
20
30
|
async function buildGoogleClient(auth) {
|
|
21
|
-
const
|
|
22
|
-
const ai = new GoogleGenAI({ apiKey: requireApiKey(auth) });
|
|
31
|
+
const ai = await newGoogleGenAI(auth);
|
|
23
32
|
return {
|
|
24
33
|
models: {
|
|
25
34
|
async generateContent(params) {
|
|
@@ -27,12 +36,59 @@ async function buildGoogleClient(auth) {
|
|
|
27
36
|
return result;
|
|
28
37
|
},
|
|
29
38
|
async countTokens(params) {
|
|
39
|
+
if (params.systemInstruction !== void 0 || params.tools !== void 0) {
|
|
40
|
+
return countTokensWithRequest(requireApiKey(auth), params);
|
|
41
|
+
}
|
|
30
42
|
const result = await ai.models.countTokens(params);
|
|
31
43
|
return result;
|
|
32
44
|
}
|
|
33
45
|
}
|
|
34
46
|
};
|
|
35
47
|
}
|
|
48
|
+
var GEMINI_API_BASE = `${GEMINI_API_ROOT}/v1beta`;
|
|
49
|
+
var MAX_ERROR_BODY_CHARS = 500;
|
|
50
|
+
async function countTokensWithRequest(apiKey, params) {
|
|
51
|
+
const { ApiError } = await import('@google/genai');
|
|
52
|
+
const model = params.model.startsWith("models/") ? params.model : `models/${params.model}`;
|
|
53
|
+
const response = await fetch(`${GEMINI_API_BASE}/${model}:countTokens`, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers: { "content-type": "application/json", "x-goog-api-key": apiKey },
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
generateContentRequest: {
|
|
58
|
+
model,
|
|
59
|
+
contents: params.contents,
|
|
60
|
+
...params.systemInstruction !== void 0 ? { systemInstruction: params.systemInstruction } : {},
|
|
61
|
+
...params.tools !== void 0 ? { tools: params.tools } : {}
|
|
62
|
+
}
|
|
63
|
+
}),
|
|
64
|
+
...params.config?.abortSignal !== void 0 ? { signal: params.config.abortSignal } : {}
|
|
65
|
+
});
|
|
66
|
+
const raw = await response.text();
|
|
67
|
+
let parsed;
|
|
68
|
+
try {
|
|
69
|
+
parsed = JSON.parse(raw);
|
|
70
|
+
} catch {
|
|
71
|
+
parsed = void 0;
|
|
72
|
+
}
|
|
73
|
+
if (!response.ok) {
|
|
74
|
+
const body = typeof parsed === "object" && parsed !== null && typeof parsed.error === "object" ? parsed : {
|
|
75
|
+
error: {
|
|
76
|
+
message: raw.length > MAX_ERROR_BODY_CHARS ? `${raw.slice(0, MAX_ERROR_BODY_CHARS)}\u2026` : raw,
|
|
77
|
+
code: response.status,
|
|
78
|
+
status: response.statusText
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
throw new ApiError({ message: JSON.stringify(body), status: response.status });
|
|
82
|
+
}
|
|
83
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
84
|
+
throw new core.LlmError("Gemini countTokens response is not a JSON object", {
|
|
85
|
+
kind: "server",
|
|
86
|
+
retryable: true,
|
|
87
|
+
provider: "google"
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return parsed;
|
|
91
|
+
}
|
|
36
92
|
|
|
37
93
|
// src/reasoning-budget.ts
|
|
38
94
|
var GOOGLE_REASONING_EFFORT_BUDGET = {
|
|
@@ -41,6 +97,69 @@ var GOOGLE_REASONING_EFFORT_BUDGET = {
|
|
|
41
97
|
medium: 8192,
|
|
42
98
|
high: 24576
|
|
43
99
|
};
|
|
100
|
+
var GOOGLE_HIGH_EFFORT_MIN_OUTPUT_TOKENS = 4096;
|
|
101
|
+
|
|
102
|
+
// src/json-schema.ts
|
|
103
|
+
var GEMINI_KEYWORDS = [
|
|
104
|
+
"type",
|
|
105
|
+
"properties",
|
|
106
|
+
"required",
|
|
107
|
+
"additionalProperties",
|
|
108
|
+
"enum",
|
|
109
|
+
"anyOf",
|
|
110
|
+
"$ref",
|
|
111
|
+
"$defs",
|
|
112
|
+
"items",
|
|
113
|
+
"prefixItems",
|
|
114
|
+
"minItems",
|
|
115
|
+
"maxItems",
|
|
116
|
+
"minimum",
|
|
117
|
+
"maximum",
|
|
118
|
+
"format",
|
|
119
|
+
"pattern",
|
|
120
|
+
"minLength",
|
|
121
|
+
"maxLength"
|
|
122
|
+
];
|
|
123
|
+
var GEMMA_IGNORED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
124
|
+
"format",
|
|
125
|
+
"minLength",
|
|
126
|
+
"maxLength"
|
|
127
|
+
]);
|
|
128
|
+
var GOOGLE_FORMATS = ["date-time", "date", "email"];
|
|
129
|
+
var GEMINI_PROFILE = {
|
|
130
|
+
provider: "google",
|
|
131
|
+
keywords: GEMINI_KEYWORDS,
|
|
132
|
+
formats: GOOGLE_FORMATS,
|
|
133
|
+
limits: {},
|
|
134
|
+
circularRefs: true,
|
|
135
|
+
booleanItems: true,
|
|
136
|
+
patternSubset: true
|
|
137
|
+
};
|
|
138
|
+
var GEMMA_PROFILE = {
|
|
139
|
+
...GEMINI_PROFILE,
|
|
140
|
+
keywords: GEMINI_KEYWORDS.filter((keyword) => !GEMMA_IGNORED_KEYWORDS.has(keyword))
|
|
141
|
+
};
|
|
142
|
+
function googleJsonSchemaProfile(canonicalModel) {
|
|
143
|
+
return canonicalModel.startsWith("gemma-") ? GEMMA_PROFILE : GEMINI_PROFILE;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// src/safety-settings.ts
|
|
147
|
+
var GOOGLE_SAFETY_CATEGORIES = [
|
|
148
|
+
"HARM_CATEGORY_HARASSMENT",
|
|
149
|
+
"HARM_CATEGORY_HATE_SPEECH",
|
|
150
|
+
"HARM_CATEGORY_SEXUALLY_EXPLICIT",
|
|
151
|
+
"HARM_CATEGORY_DANGEROUS_CONTENT",
|
|
152
|
+
"HARM_CATEGORY_CIVIC_INTEGRITY",
|
|
153
|
+
"HARM_CATEGORY_JAILBREAK"
|
|
154
|
+
];
|
|
155
|
+
var GOOGLE_SAFETY_THRESHOLDS = [
|
|
156
|
+
"HARM_BLOCK_THRESHOLD_UNSPECIFIED",
|
|
157
|
+
"BLOCK_LOW_AND_ABOVE",
|
|
158
|
+
"BLOCK_MEDIUM_AND_ABOVE",
|
|
159
|
+
"BLOCK_ONLY_HIGH",
|
|
160
|
+
"BLOCK_NONE",
|
|
161
|
+
"OFF"
|
|
162
|
+
];
|
|
44
163
|
|
|
45
164
|
// src/grounding.ts
|
|
46
165
|
function hostnameFrom(url) {
|
|
@@ -69,23 +188,116 @@ function toCitation(chunk) {
|
|
|
69
188
|
sourceName
|
|
70
189
|
};
|
|
71
190
|
}
|
|
72
|
-
function
|
|
191
|
+
function utf16IndexAtByte(text, byte) {
|
|
192
|
+
if (!Number.isInteger(byte) || byte < 0) return void 0;
|
|
193
|
+
let bytes = 0;
|
|
194
|
+
let units = 0;
|
|
195
|
+
if (byte === 0) return 0;
|
|
196
|
+
for (const char of text) {
|
|
197
|
+
const code = char.codePointAt(0);
|
|
198
|
+
bytes += code < 128 ? 1 : code < 2048 ? 2 : code < 65536 ? 3 : 4;
|
|
199
|
+
units += char.length;
|
|
200
|
+
if (bytes === byte) return units;
|
|
201
|
+
if (bytes > byte) return void 0;
|
|
202
|
+
}
|
|
203
|
+
return void 0;
|
|
204
|
+
}
|
|
205
|
+
function segmentRange(segment, answerParts, joined, onDropped) {
|
|
206
|
+
if (segment === null || typeof segment !== "object") return void 0;
|
|
207
|
+
const raw = segment;
|
|
208
|
+
const partIndex = raw["partIndex"] ?? 0;
|
|
209
|
+
const startByte = raw["startIndex"] ?? 0;
|
|
210
|
+
const endByte = raw["endIndex"];
|
|
211
|
+
if (typeof partIndex !== "number" || typeof startByte !== "number" || typeof endByte !== "number") {
|
|
212
|
+
return void 0;
|
|
213
|
+
}
|
|
214
|
+
const part = answerParts[partIndex];
|
|
215
|
+
if (part === void 0) return void 0;
|
|
216
|
+
const start = utf16IndexAtByte(part.text, startByte);
|
|
217
|
+
const end = utf16IndexAtByte(part.text, endByte);
|
|
218
|
+
if (start === void 0 || end === void 0 || end <= start) return void 0;
|
|
219
|
+
const range = { start: part.offset + start, end: part.offset + end };
|
|
220
|
+
const expected = raw["text"];
|
|
221
|
+
if (typeof expected === "string" && joined.slice(range.start, range.end) !== expected) {
|
|
222
|
+
onDropped(
|
|
223
|
+
`google: dropped a textRange for a grounding segment (partIndex ${partIndex}, bytes ${startByte}-${endByte}): the answer at that range does not equal segment.text. The source stays cited without a range.`
|
|
224
|
+
);
|
|
225
|
+
return void 0;
|
|
226
|
+
}
|
|
227
|
+
return range;
|
|
228
|
+
}
|
|
229
|
+
function readSupports(groundingMetadata, answerParts, onDropped) {
|
|
230
|
+
const supports = groundingMetadata["groundingSupports"];
|
|
231
|
+
if (!Array.isArray(supports)) return void 0;
|
|
232
|
+
const joined = answerParts.map((part) => part?.text ?? "").join("");
|
|
233
|
+
const byChunk = /* @__PURE__ */ new Map();
|
|
234
|
+
for (const support of supports) {
|
|
235
|
+
if (support === null || typeof support !== "object") continue;
|
|
236
|
+
const record = support;
|
|
237
|
+
const indices = record["groundingChunkIndices"];
|
|
238
|
+
if (!Array.isArray(indices)) continue;
|
|
239
|
+
const range = segmentRange(record["segment"], answerParts, joined, onDropped);
|
|
240
|
+
for (const index of indices) {
|
|
241
|
+
if (typeof index !== "number") continue;
|
|
242
|
+
if (!byChunk.has(index) || byChunk.get(index) === void 0 && range) {
|
|
243
|
+
byChunk.set(index, range);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return byChunk;
|
|
248
|
+
}
|
|
249
|
+
function normalizeGroundingCitations(groundingMetadata, answerParts = [], onDropped = () => {
|
|
250
|
+
}) {
|
|
73
251
|
if (groundingMetadata === null || typeof groundingMetadata !== "object") return [];
|
|
74
|
-
const
|
|
252
|
+
const metadata = groundingMetadata;
|
|
253
|
+
const chunks = metadata["groundingChunks"];
|
|
75
254
|
if (!Array.isArray(chunks)) return [];
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
|
|
255
|
+
const supports = readSupports(metadata, answerParts, onDropped);
|
|
256
|
+
const byUrl = /* @__PURE__ */ new Map();
|
|
257
|
+
chunks.forEach((chunk, chunkIndex) => {
|
|
79
258
|
const citation = toCitation(chunk);
|
|
80
|
-
if (citation === void 0)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
259
|
+
if (citation === void 0) return;
|
|
260
|
+
const existing = byUrl.get(citation.url);
|
|
261
|
+
const target = existing ?? citation;
|
|
262
|
+
if (existing === void 0) byUrl.set(citation.url, citation);
|
|
263
|
+
if (supports === void 0) return;
|
|
264
|
+
if (supports.has(chunkIndex)) {
|
|
265
|
+
target.cited = true;
|
|
266
|
+
const range = supports.get(chunkIndex);
|
|
267
|
+
if (range !== void 0 && target.textRange === void 0) {
|
|
268
|
+
target.textRange = { ...range };
|
|
269
|
+
}
|
|
270
|
+
} else if (target.cited === void 0) {
|
|
271
|
+
target.cited = false;
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
return [...byUrl.values()];
|
|
275
|
+
}
|
|
276
|
+
function countWebSearchQueries(groundingMetadata) {
|
|
277
|
+
if (groundingMetadata === null || typeof groundingMetadata !== "object") {
|
|
278
|
+
return void 0;
|
|
84
279
|
}
|
|
85
|
-
|
|
280
|
+
const queries = groundingMetadata["webSearchQueries"];
|
|
281
|
+
if (!Array.isArray(queries)) return void 0;
|
|
282
|
+
const named = queries.filter((q) => typeof q === "string" && q.length > 0).length;
|
|
283
|
+
return named === 0 && queries.length > 0 ? void 0 : named;
|
|
284
|
+
}
|
|
285
|
+
function readSearchEntryPoint(groundingMetadata) {
|
|
286
|
+
if (groundingMetadata === null || typeof groundingMetadata !== "object") {
|
|
287
|
+
return void 0;
|
|
288
|
+
}
|
|
289
|
+
const entry = groundingMetadata["searchEntryPoint"];
|
|
290
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) {
|
|
291
|
+
return void 0;
|
|
292
|
+
}
|
|
293
|
+
return Object.keys(entry).length > 0 ? entry : void 0;
|
|
86
294
|
}
|
|
87
295
|
|
|
88
296
|
// src/tool-call-id.ts
|
|
297
|
+
var SYNTHESIZED_PREFIX = "anyllm_call_";
|
|
298
|
+
function isSynthesizedToolCallId(id) {
|
|
299
|
+
return id.startsWith(SYNTHESIZED_PREFIX);
|
|
300
|
+
}
|
|
89
301
|
function reserveProviderToolCallIds(ids) {
|
|
90
302
|
const reserved = /* @__PURE__ */ new Set();
|
|
91
303
|
for (const id of ids) {
|
|
@@ -98,7 +310,7 @@ function nextFallbackToolCallId(toolName, counters, reserved, counterKey = toolN
|
|
|
98
310
|
let id;
|
|
99
311
|
do {
|
|
100
312
|
n += 1;
|
|
101
|
-
id =
|
|
313
|
+
id = `${SYNTHESIZED_PREFIX}${toolName}_${n}`;
|
|
102
314
|
} while (reserved.has(id));
|
|
103
315
|
counters.set(counterKey, n);
|
|
104
316
|
return id;
|
|
@@ -111,78 +323,645 @@ function resolveToolCallId(providerId, toolName, counters, reserved, counterKey)
|
|
|
111
323
|
}
|
|
112
324
|
|
|
113
325
|
// src/flex-fallback.ts
|
|
114
|
-
var CAPACITY_PATTERNS = [
|
|
115
|
-
/capacity/i,
|
|
116
|
-
/overload/i,
|
|
117
|
-
/overloaded/i,
|
|
118
|
-
/unavailable/i,
|
|
119
|
-
/no\s+capacity/i,
|
|
120
|
-
/temporar(?:y|ily)/i,
|
|
121
|
-
/try\s+again/i
|
|
122
|
-
];
|
|
123
|
-
var QUOTA_PATTERNS = [
|
|
124
|
-
/quota/i,
|
|
125
|
-
/billing/i,
|
|
126
|
-
/billable/i,
|
|
127
|
-
/payment/i,
|
|
128
|
-
/rate\s+limit/i,
|
|
129
|
-
/exceeded/i,
|
|
130
|
-
/insufficient/i
|
|
131
|
-
];
|
|
132
326
|
function isGeminiCapacityError(err) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
function matchesGoogleTransportSignature(err) {
|
|
143
|
-
if (!(err instanceof Error)) return false;
|
|
144
|
-
if (GOOGLE_TRANSPORT_ERROR_PATTERN.test(err.message)) return true;
|
|
145
|
-
const code = err.code;
|
|
146
|
-
return typeof code === "string" && GOOGLE_TRANSPORT_ERROR_PATTERN.test(code);
|
|
147
|
-
}
|
|
148
|
-
function isGoogleTransportError(rawErr) {
|
|
149
|
-
if (matchesGoogleTransportSignature(rawErr)) return true;
|
|
150
|
-
if (rawErr instanceof Error) {
|
|
151
|
-
const cause = rawErr.cause;
|
|
152
|
-
if (matchesGoogleTransportSignature(cause)) return true;
|
|
153
|
-
}
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
function isGoogleModelNotFound(rawErr) {
|
|
157
|
-
if (!(rawErr instanceof Error)) return false;
|
|
158
|
-
if (rawErr.status !== 404) return false;
|
|
327
|
+
return err.httpStatus === 503;
|
|
328
|
+
}
|
|
329
|
+
function isRecord(value) {
|
|
330
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
331
|
+
}
|
|
332
|
+
function parseGoogleErrorBody(rawErr) {
|
|
333
|
+
const source = rawErr instanceof core.LlmError ? rawErr.cause : rawErr;
|
|
334
|
+
if (!(source instanceof Error)) return void 0;
|
|
335
|
+
let parsed;
|
|
159
336
|
try {
|
|
160
|
-
|
|
161
|
-
return parsed.error?.code === 404 && parsed.error.status === "NOT_FOUND";
|
|
337
|
+
parsed = JSON.parse(source.message);
|
|
162
338
|
} catch {
|
|
163
|
-
return
|
|
339
|
+
return void 0;
|
|
340
|
+
}
|
|
341
|
+
if (!isRecord(parsed) || !isRecord(parsed["error"])) return void 0;
|
|
342
|
+
const error = parsed["error"];
|
|
343
|
+
const details = Array.isArray(error["details"]) ? error["details"].filter(isRecord) : [];
|
|
344
|
+
return {
|
|
345
|
+
...typeof error["status"] === "string" ? { status: error["status"] } : {},
|
|
346
|
+
...typeof error["message"] === "string" ? { message: error["message"] } : {},
|
|
347
|
+
details
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function detailOfType(body, type) {
|
|
351
|
+
return body.details.filter((d) => d["@type"] === `type.googleapis.com/${type}`);
|
|
352
|
+
}
|
|
353
|
+
function errorInfoReasons(body) {
|
|
354
|
+
return detailOfType(body, "google.rpc.ErrorInfo").flatMap(
|
|
355
|
+
(d) => typeof d["reason"] === "string" ? [d["reason"]] : []
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
function isDailyQuota(body) {
|
|
359
|
+
return detailOfType(body, "google.rpc.QuotaFailure").some(
|
|
360
|
+
(failure) => Array.isArray(failure["violations"]) && failure["violations"].some(
|
|
361
|
+
(v) => isRecord(v) && typeof v["quotaId"] === "string" && v["quotaId"].includes("PerDay")
|
|
362
|
+
)
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
var PROTO_DURATION = /^\d+(?:\.\d{1,9})?s$/;
|
|
366
|
+
function durationText(delay) {
|
|
367
|
+
if (typeof delay === "string") return PROTO_DURATION.test(delay) ? delay : void 0;
|
|
368
|
+
if (!isRecord(delay)) return void 0;
|
|
369
|
+
const { seconds, nanos } = delay;
|
|
370
|
+
const whole = typeof seconds === "number" && Number.isSafeInteger(seconds) && seconds >= 0 ? String(seconds) : typeof seconds === "string" && /^\d+$/.test(seconds) ? seconds : seconds === void 0 ? "0" : void 0;
|
|
371
|
+
const fraction = typeof nanos === "number" && Number.isInteger(nanos) && nanos >= 0 && nanos < 1e9 ? String(nanos).padStart(9, "0") : nanos === void 0 ? "0" : void 0;
|
|
372
|
+
return whole !== void 0 && fraction !== void 0 ? `${whole}.${fraction}s` : void 0;
|
|
373
|
+
}
|
|
374
|
+
function retryDelayMs(body) {
|
|
375
|
+
for (const info of detailOfType(body, "google.rpc.RetryInfo")) {
|
|
376
|
+
const text = durationText(info["retryDelay"]);
|
|
377
|
+
if (text === void 0) continue;
|
|
378
|
+
const ms = core.parseRetryAfter({ "retry-after": text }, Date.now());
|
|
379
|
+
if (ms !== void 0) return ms;
|
|
164
380
|
}
|
|
381
|
+
return void 0;
|
|
382
|
+
}
|
|
383
|
+
var API_KEY_REASONS = /* @__PURE__ */ new Set(["API_KEY_INVALID", "API_KEY_EXPIRED"]);
|
|
384
|
+
var STALE_CACHE_MESSAGE = "CachedContent not found";
|
|
385
|
+
function isGoogleNotFoundError(err) {
|
|
386
|
+
if (typeof err !== "object" || err === null) return false;
|
|
387
|
+
const obj = err;
|
|
388
|
+
const httpStatus = core.classifyError(err).httpStatus ?? numericStatus(obj["httpStatus"]);
|
|
389
|
+
if (httpStatus === 404 || obj["status"] === "NOT_FOUND" || obj["code"] === "NOT_FOUND") {
|
|
390
|
+
return true;
|
|
391
|
+
}
|
|
392
|
+
const body = parseGoogleErrorBody(err);
|
|
393
|
+
const message = body?.message ?? (typeof obj["message"] === "string" ? obj["message"] : "");
|
|
394
|
+
if (httpStatus === 403) return /may not exist|not found/i.test(message);
|
|
395
|
+
const statusKnown = httpStatus !== void 0 || body?.status !== void 0 || typeof obj["status"] === "string" || [obj["status"], obj["code"]].some((value) => typeof value === "number");
|
|
396
|
+
if (statusKnown) return false;
|
|
397
|
+
return /not\s*found|404/i.test(message) && /file|cachedcontent/i.test(message);
|
|
398
|
+
}
|
|
399
|
+
function numericStatus(value) {
|
|
400
|
+
const n = typeof value === "number" ? value : typeof value === "string" && /^\d{3}$/.test(value.trim()) ? Number(value) : void 0;
|
|
401
|
+
return n !== void 0 && Number.isInteger(n) && n >= 100 && n <= 599 ? n : void 0;
|
|
165
402
|
}
|
|
166
403
|
function classifyGoogleError(rawErr, extra) {
|
|
167
404
|
const base = core.classifyError(rawErr);
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
405
|
+
const body = parseGoogleErrorBody(rawErr);
|
|
406
|
+
let kind = base.kind;
|
|
407
|
+
let retryable = base.retryable;
|
|
408
|
+
let reason = base.reason;
|
|
409
|
+
let retryAfterMs = base.retryAfterMs;
|
|
410
|
+
let message = base.message;
|
|
411
|
+
if (extra?.transportTimeout !== void 0) {
|
|
412
|
+
kind = "timeout";
|
|
413
|
+
retryable = false;
|
|
414
|
+
reason = "transport_timeout";
|
|
415
|
+
retryAfterMs = void 0;
|
|
416
|
+
message = extra.transportTimeout;
|
|
417
|
+
} else if (!(rawErr instanceof core.LlmError) && base.kind === "timeout" && base.httpStatus === void 0) {
|
|
418
|
+
retryable = false;
|
|
419
|
+
reason = "transport_timeout";
|
|
420
|
+
retryAfterMs = void 0;
|
|
421
|
+
}
|
|
422
|
+
if (body !== void 0 && base.httpStatus !== void 0) {
|
|
423
|
+
if (errorInfoReasons(body).some((r) => API_KEY_REASONS.has(r))) {
|
|
424
|
+
kind = "invalid_auth";
|
|
425
|
+
retryable = false;
|
|
426
|
+
} else if (base.httpStatus === 403 && body.message?.startsWith(STALE_CACHE_MESSAGE) === true) {
|
|
427
|
+
kind = "bad_request";
|
|
428
|
+
retryable = false;
|
|
429
|
+
reason = "cache_not_found";
|
|
430
|
+
} else if (base.httpStatus === 429) {
|
|
431
|
+
if (isDailyQuota(body)) {
|
|
432
|
+
kind = "rate_limited";
|
|
433
|
+
retryable = false;
|
|
434
|
+
reason = "daily_quota";
|
|
435
|
+
retryAfterMs = void 0;
|
|
436
|
+
} else {
|
|
437
|
+
retryAfterMs = retryDelayMs(body) ?? retryAfterMs;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return new core.LlmError(message, {
|
|
442
|
+
kind,
|
|
443
|
+
retryable,
|
|
444
|
+
...reason !== void 0 ? { reason } : {},
|
|
173
445
|
...base.httpStatus !== void 0 ? { httpStatus: base.httpStatus } : {},
|
|
174
|
-
...
|
|
446
|
+
...retryAfterMs !== void 0 ? { retryAfterMs } : {},
|
|
175
447
|
provider: "google",
|
|
176
448
|
cause: base.cause ?? rawErr,
|
|
177
449
|
...extra?.servedServiceTier !== void 0 ? { servedServiceTier: extra.servedServiceTier } : {}
|
|
178
450
|
});
|
|
179
451
|
}
|
|
180
452
|
|
|
453
|
+
// src/platform-scheduler.ts
|
|
454
|
+
var PLATFORM_SCHEDULER = {
|
|
455
|
+
setTimeout: (callback, ms) => globalThis.setTimeout(callback, ms),
|
|
456
|
+
clearTimeout: (handle) => {
|
|
457
|
+
globalThis.clearTimeout(handle);
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
// src/pricing.ts
|
|
462
|
+
var pricingVersion = "gemini-2026-10-03";
|
|
463
|
+
var GEMINI_PRICED_TIERS = ["standard", "flex"];
|
|
464
|
+
function freezeRates(rates) {
|
|
465
|
+
if (rates.gt200k !== void 0) Object.freeze(rates.gt200k);
|
|
466
|
+
if (rates.audio !== void 0) Object.freeze(rates.audio);
|
|
467
|
+
return Object.freeze(rates);
|
|
468
|
+
}
|
|
469
|
+
function tiers(standard, flex) {
|
|
470
|
+
return Object.freeze({ standard: freezeRates(standard), flex: freezeRates(flex) });
|
|
471
|
+
}
|
|
472
|
+
var GEMINI_PRICING = Object.freeze({
|
|
473
|
+
// Gemini 2.5 Pro. Flex cached equals standard on both context bands. No separate audio price.
|
|
474
|
+
"gemini-2.5-pro": tiers(
|
|
475
|
+
{
|
|
476
|
+
inputPerM: 125e4,
|
|
477
|
+
cachedPerM: 125e3,
|
|
478
|
+
outputPerM: 1e7,
|
|
479
|
+
gt200k: { inputPerM: 25e5, cachedPerM: 25e4, outputPerM: 15e6 }
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
inputPerM: 625e3,
|
|
483
|
+
cachedPerM: 125e3,
|
|
484
|
+
outputPerM: 5e6,
|
|
485
|
+
gt200k: { inputPerM: 125e4, cachedPerM: 25e4, outputPerM: 75e5 }
|
|
486
|
+
}
|
|
487
|
+
),
|
|
488
|
+
// Gemini 2.5 Flash. Flex cached stays $0.03. Audio: $1.00 / cached $0.10 standard,
|
|
489
|
+
// $0.50 / cached $0.10 flex.
|
|
490
|
+
"gemini-2.5-flash": tiers(
|
|
491
|
+
{
|
|
492
|
+
inputPerM: 3e5,
|
|
493
|
+
cachedPerM: 3e4,
|
|
494
|
+
outputPerM: 25e5,
|
|
495
|
+
audio: { inputPerM: 1e6, cachedPerM: 1e5 }
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
inputPerM: 15e4,
|
|
499
|
+
cachedPerM: 3e4,
|
|
500
|
+
outputPerM: 125e4,
|
|
501
|
+
audio: { inputPerM: 5e5, cachedPerM: 1e5 }
|
|
502
|
+
}
|
|
503
|
+
),
|
|
504
|
+
// Gemini 2.5 Flash-Lite. Flex cached stays $0.01. Audio: $0.30 / cached $0.03
|
|
505
|
+
// standard, $0.15 / cached $0.03 flex.
|
|
506
|
+
"gemini-2.5-flash-lite": tiers(
|
|
507
|
+
{
|
|
508
|
+
inputPerM: 1e5,
|
|
509
|
+
cachedPerM: 1e4,
|
|
510
|
+
outputPerM: 4e5,
|
|
511
|
+
audio: { inputPerM: 3e5, cachedPerM: 3e4 }
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
inputPerM: 5e4,
|
|
515
|
+
cachedPerM: 1e4,
|
|
516
|
+
outputPerM: 2e5,
|
|
517
|
+
audio: { inputPerM: 15e4, cachedPerM: 3e4 }
|
|
518
|
+
}
|
|
519
|
+
),
|
|
520
|
+
// Gemini 3.1 Flash-Lite. Flex cached is the published $0.0125. Audio: $0.50 /
|
|
521
|
+
// cached $0.05 standard, $0.25 / cached $0.025 flex.
|
|
522
|
+
"gemini-3.1-flash-lite": tiers(
|
|
523
|
+
{
|
|
524
|
+
inputPerM: 25e4,
|
|
525
|
+
cachedPerM: 25e3,
|
|
526
|
+
outputPerM: 15e5,
|
|
527
|
+
audio: { inputPerM: 5e5, cachedPerM: 5e4 }
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
inputPerM: 125e3,
|
|
531
|
+
cachedPerM: 12500,
|
|
532
|
+
outputPerM: 75e4,
|
|
533
|
+
audio: { inputPerM: 25e4, cachedPerM: 25e3 }
|
|
534
|
+
}
|
|
535
|
+
),
|
|
536
|
+
// Gemini 3.8 / 3.7 / 3.6 Flash intro rates (2026-09-25), one rate for all
|
|
537
|
+
// modalities. Flex cached is half of the intro cached rate. Re-snapshot on 2027-01-01.
|
|
538
|
+
"gemini-3.8-flash": tiers(
|
|
539
|
+
{ inputPerM: 75e4, cachedPerM: 75e3, outputPerM: 375e4 },
|
|
540
|
+
{ inputPerM: 375e3, cachedPerM: 37500, outputPerM: 1875e3 }
|
|
541
|
+
),
|
|
542
|
+
"gemini-3.7-flash": tiers(
|
|
543
|
+
{ inputPerM: 75e4, cachedPerM: 75e3, outputPerM: 375e4 },
|
|
544
|
+
{ inputPerM: 375e3, cachedPerM: 37500, outputPerM: 1875e3 }
|
|
545
|
+
),
|
|
546
|
+
"gemini-3.6-flash": tiers(
|
|
547
|
+
{ inputPerM: 75e4, cachedPerM: 75e3, outputPerM: 375e4 },
|
|
548
|
+
{ inputPerM: 375e3, cachedPerM: 37500, outputPerM: 1875e3 }
|
|
549
|
+
),
|
|
550
|
+
// Gemini 3.5 Flash-Lite, one rate for all modalities (audio included). Flex
|
|
551
|
+
// cached is the published $0.02, not half of $0.03.
|
|
552
|
+
"gemini-3.5-flash-lite": tiers(
|
|
553
|
+
{ inputPerM: 3e5, cachedPerM: 3e4, outputPerM: 25e5 },
|
|
554
|
+
{ inputPerM: 15e4, cachedPerM: 2e4, outputPerM: 125e4 }
|
|
555
|
+
),
|
|
556
|
+
// Gemini 3.1 Pro Preview. Flex cached equals standard on both bands. No separate audio price.
|
|
557
|
+
"gemini-3.1-pro-preview": tiers(
|
|
558
|
+
{
|
|
559
|
+
inputPerM: 2e6,
|
|
560
|
+
cachedPerM: 2e5,
|
|
561
|
+
outputPerM: 12e6,
|
|
562
|
+
gt200k: { inputPerM: 4e6, cachedPerM: 4e5, outputPerM: 18e6 }
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
inputPerM: 1e6,
|
|
566
|
+
cachedPerM: 2e5,
|
|
567
|
+
outputPerM: 6e6,
|
|
568
|
+
gt200k: { inputPerM: 2e6, cachedPerM: 4e5, outputPerM: 9e6 }
|
|
569
|
+
}
|
|
570
|
+
)
|
|
571
|
+
});
|
|
572
|
+
var PER_QUERY = Object.freeze({
|
|
573
|
+
unit: "query",
|
|
574
|
+
microUsdPerUnit: 14e3
|
|
575
|
+
});
|
|
576
|
+
var PER_GROUNDED_PROMPT = Object.freeze({
|
|
577
|
+
unit: "prompt",
|
|
578
|
+
microUsdPerUnit: 35e3
|
|
579
|
+
});
|
|
580
|
+
var GEMINI_GROUNDING_PRICING = Object.freeze({
|
|
581
|
+
"gemini-2.5-pro": PER_GROUNDED_PROMPT,
|
|
582
|
+
"gemini-2.5-flash": PER_GROUNDED_PROMPT,
|
|
583
|
+
"gemini-2.5-flash-lite": PER_GROUNDED_PROMPT,
|
|
584
|
+
"gemini-3.1-flash-lite": PER_QUERY,
|
|
585
|
+
"gemini-3.8-flash": PER_QUERY,
|
|
586
|
+
"gemini-3.7-flash": PER_QUERY,
|
|
587
|
+
"gemini-3.6-flash": PER_QUERY,
|
|
588
|
+
"gemini-3.5-flash-lite": PER_QUERY,
|
|
589
|
+
"gemini-3.1-pro-preview": PER_QUERY
|
|
590
|
+
});
|
|
591
|
+
function resolveGeminiGroundingRate(model) {
|
|
592
|
+
return Object.hasOwn(GEMINI_GROUNDING_PRICING, model) ? GEMINI_GROUNDING_PRICING[model] : void 0;
|
|
593
|
+
}
|
|
594
|
+
function isPricedGeminiTier(tier) {
|
|
595
|
+
return GEMINI_PRICED_TIERS.includes(tier);
|
|
596
|
+
}
|
|
597
|
+
function lookupGeminiTierRates(model, tier) {
|
|
598
|
+
const entry = Object.hasOwn(GEMINI_PRICING, model) ? GEMINI_PRICING[model] : void 0;
|
|
599
|
+
if (entry === void 0) return void 0;
|
|
600
|
+
if (tier !== void 0 && !isPricedGeminiTier(tier)) return void 0;
|
|
601
|
+
return entry;
|
|
602
|
+
}
|
|
603
|
+
function resolveGeminiRates(model, tier) {
|
|
604
|
+
const entry = lookupGeminiTierRates(model, tier);
|
|
605
|
+
if (entry === void 0) return void 0;
|
|
606
|
+
const key = tier ?? "standard";
|
|
607
|
+
return entry[key];
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// src/cost.ts
|
|
611
|
+
function tokenDetail(usage, key) {
|
|
612
|
+
const value = usage.details[key];
|
|
613
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : void 0;
|
|
614
|
+
}
|
|
615
|
+
function modalitySplitTotal(usage, prefix) {
|
|
616
|
+
let total;
|
|
617
|
+
for (const [key, value] of Object.entries(usage.details)) {
|
|
618
|
+
if (key.startsWith(prefix) && Number.isFinite(value) && value >= 0) {
|
|
619
|
+
total = (total ?? 0) + value;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
return total;
|
|
623
|
+
}
|
|
624
|
+
function promptLanes(usage) {
|
|
625
|
+
const total = usage.inputTokens;
|
|
626
|
+
const cachedReported = usage.cachedInputTokens ?? 0;
|
|
627
|
+
const promptAudio = tokenDetail(usage, "input_audio");
|
|
628
|
+
const cachedAudio = tokenDetail(usage, "cached_audio");
|
|
629
|
+
const gaps = [];
|
|
630
|
+
const gap = (reason) => {
|
|
631
|
+
if (!gaps.includes(reason)) gaps.push(reason);
|
|
632
|
+
};
|
|
633
|
+
const cached = Math.min(cachedReported, total);
|
|
634
|
+
if (cachedReported > total) gap("inconsistent");
|
|
635
|
+
const audioCached = Math.min(cachedAudio ?? 0, cached);
|
|
636
|
+
if ((cachedAudio ?? 0) > cached) gap("inconsistent");
|
|
637
|
+
if (promptAudio !== void 0 && promptAudio < audioCached) gap("inconsistent");
|
|
638
|
+
const audioTotal = Math.min(Math.max(promptAudio ?? 0, audioCached), total);
|
|
639
|
+
if ((promptAudio ?? 0) > total) gap("inconsistent");
|
|
640
|
+
const audioUncached = Math.min(audioTotal - audioCached, total - cached);
|
|
641
|
+
if (audioTotal - audioCached > total - cached) gap("inconsistent");
|
|
642
|
+
if (usage.details["audio_input_requested"] === 1 && !((promptAudio ?? 0) > 0)) {
|
|
643
|
+
gap("audio-unreported");
|
|
644
|
+
}
|
|
645
|
+
const promptSplit = modalitySplitTotal(usage, "input_");
|
|
646
|
+
const promptHoldsNoAudio = promptAudio === 0 || promptAudio === void 0 && promptSplit !== void 0 && promptSplit >= total;
|
|
647
|
+
if (cached > 0 && cachedAudio === void 0 && !promptHoldsNoAudio) {
|
|
648
|
+
gap("cached-audio-unknown");
|
|
649
|
+
}
|
|
650
|
+
return {
|
|
651
|
+
audioUncached,
|
|
652
|
+
audioCached,
|
|
653
|
+
otherUncached: total - cached - audioUncached,
|
|
654
|
+
otherCached: cached - audioCached,
|
|
655
|
+
gaps
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
function priceCall(model, usage, tier) {
|
|
659
|
+
if (usage.details["usage_missing"] === 1) {
|
|
660
|
+
return {
|
|
661
|
+
microUsd: null,
|
|
662
|
+
usd: null,
|
|
663
|
+
pricingVersion,
|
|
664
|
+
confidence: "estimated",
|
|
665
|
+
details: { input: 0, cached: 0, output: 0, tools: 0 },
|
|
666
|
+
unpricedReason: "The response carried no usageMetadata, so the tokens billed are unknown."
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
const modelRates = resolveGeminiRates(model, tier);
|
|
670
|
+
const audioRates = modelRates?.audio;
|
|
671
|
+
let cost;
|
|
672
|
+
if (audioRates === void 0) {
|
|
673
|
+
cost = core.computeCost(model, usage, tier, resolveGeminiRates, pricingVersion);
|
|
674
|
+
} else {
|
|
675
|
+
const lanes = promptLanes(usage);
|
|
676
|
+
const textUsage = {
|
|
677
|
+
...usage,
|
|
678
|
+
inputTokens: lanes.otherUncached + lanes.otherCached,
|
|
679
|
+
cachedInputTokens: lanes.otherCached
|
|
680
|
+
};
|
|
681
|
+
const text = core.computeCost(model, textUsage, tier, resolveGeminiRates, pricingVersion);
|
|
682
|
+
const audioUncachedCost = Math.round(
|
|
683
|
+
lanes.audioUncached * audioRates.inputPerM / 1e6
|
|
684
|
+
);
|
|
685
|
+
const audioCachedCost = Math.round(
|
|
686
|
+
lanes.audioCached * audioRates.cachedPerM / 1e6
|
|
687
|
+
);
|
|
688
|
+
const microUsd2 = (text.microUsd ?? 0) + audioUncachedCost + audioCachedCost;
|
|
689
|
+
cost = {
|
|
690
|
+
...text,
|
|
691
|
+
microUsd: microUsd2,
|
|
692
|
+
usd: microUsd2 / 1e6,
|
|
693
|
+
// An audio share the response does not pin down can understate the amount.
|
|
694
|
+
...lanes.gaps.length > 0 ? { confidence: "estimated" } : {},
|
|
695
|
+
details: {
|
|
696
|
+
...text.details,
|
|
697
|
+
input: text.details.input + audioUncachedCost,
|
|
698
|
+
cached: text.details.cached + audioCachedCost
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
if (cost.microUsd === null) return cost;
|
|
703
|
+
if (usage.details["web_search_requested"] !== 1) return cost;
|
|
704
|
+
const calls = usage.details["web_search_calls"];
|
|
705
|
+
if (calls === 0) return cost;
|
|
706
|
+
const rate = resolveGeminiGroundingRate(model);
|
|
707
|
+
const tools = rate === void 0 || calls === void 0 ? 0 : rate.unit === "query" ? Math.round(calls * rate.microUsdPerUnit) : rate.microUsdPerUnit;
|
|
708
|
+
const microUsd = cost.microUsd + tools;
|
|
709
|
+
return {
|
|
710
|
+
...cost,
|
|
711
|
+
microUsd,
|
|
712
|
+
usd: microUsd / 1e6,
|
|
713
|
+
confidence: "estimated",
|
|
714
|
+
details: { ...cost.details, tools }
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
function geminiPricingSource() {
|
|
718
|
+
return {
|
|
719
|
+
version: pricingVersion,
|
|
720
|
+
price(model, usage, tier) {
|
|
721
|
+
return priceCall(model, usage, tier);
|
|
722
|
+
},
|
|
723
|
+
hasModel(model) {
|
|
724
|
+
return resolveGeminiRates(model, void 0) !== void 0;
|
|
725
|
+
},
|
|
726
|
+
listModels() {
|
|
727
|
+
return Object.keys(GEMINI_PRICING);
|
|
728
|
+
}
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// src/utf8.ts
|
|
733
|
+
function utf8ByteLength(text) {
|
|
734
|
+
let bytes = 0;
|
|
735
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
736
|
+
const unit = text.charCodeAt(i);
|
|
737
|
+
if (unit < 128) bytes += 1;
|
|
738
|
+
else if (unit < 2048) bytes += 2;
|
|
739
|
+
else if (unit >= 55296 && unit <= 56319) {
|
|
740
|
+
const next = text.charCodeAt(i + 1);
|
|
741
|
+
if (next >= 56320 && next <= 57343) {
|
|
742
|
+
bytes += 4;
|
|
743
|
+
i += 1;
|
|
744
|
+
} else bytes += 3;
|
|
745
|
+
} else bytes += 3;
|
|
746
|
+
}
|
|
747
|
+
return bytes;
|
|
748
|
+
}
|
|
749
|
+
var STATE_PATH = "transientProviderState";
|
|
750
|
+
var SHA256_HEX = /^[0-9a-f]{64}$/;
|
|
751
|
+
var ENTRY_KEYS = /* @__PURE__ */ new Set([
|
|
752
|
+
"messageIndex",
|
|
753
|
+
"partIndex",
|
|
754
|
+
"kind",
|
|
755
|
+
"model",
|
|
756
|
+
"partSha256",
|
|
757
|
+
"signature"
|
|
758
|
+
]);
|
|
759
|
+
function badState(path, why) {
|
|
760
|
+
return new core.LlmError(`${path}: ${why}`, {
|
|
761
|
+
kind: "bad_request",
|
|
762
|
+
retryable: false,
|
|
763
|
+
provider: "google",
|
|
764
|
+
issues: [{ path, message: why }]
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
function isRecord2(value) {
|
|
768
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
769
|
+
}
|
|
770
|
+
function hashedForm(part, path) {
|
|
771
|
+
switch (part.kind) {
|
|
772
|
+
case "text":
|
|
773
|
+
return { kind: "text", text: part.text };
|
|
774
|
+
case "tool-call":
|
|
775
|
+
return {
|
|
776
|
+
kind: "tool-call",
|
|
777
|
+
toolCallId: part.toolCallId,
|
|
778
|
+
toolName: part.toolName,
|
|
779
|
+
args: part.args
|
|
780
|
+
};
|
|
781
|
+
default:
|
|
782
|
+
throw badState(
|
|
783
|
+
path,
|
|
784
|
+
`a thought signature cannot be attached to a "${part.kind}" part`
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
function partSha256(part, path = "part") {
|
|
789
|
+
return core.sha256Hex(core.canonicalJson(hashedForm(part, path)));
|
|
790
|
+
}
|
|
791
|
+
function parseSignatureState(value) {
|
|
792
|
+
if (value === void 0) return [];
|
|
793
|
+
if (!isRecord2(value)) {
|
|
794
|
+
throw badState(STATE_PATH, "must be { google: { signatures: [...] } }");
|
|
795
|
+
}
|
|
796
|
+
for (const key of Object.keys(value)) {
|
|
797
|
+
if (key !== "google") {
|
|
798
|
+
throw badState(
|
|
799
|
+
`${STATE_PATH}.${key}`,
|
|
800
|
+
`holds another provider's state; Google state is { google: { signatures: [...] } }`
|
|
801
|
+
);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
const google = value["google"];
|
|
805
|
+
if (!isRecord2(google)) {
|
|
806
|
+
throw badState(`${STATE_PATH}.google`, "must be { signatures: [...] }");
|
|
807
|
+
}
|
|
808
|
+
for (const key of Object.keys(google)) {
|
|
809
|
+
if (key !== "signatures") {
|
|
810
|
+
throw badState(`${STATE_PATH}.google.${key}`, "is not a known key");
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
const list = google["signatures"];
|
|
814
|
+
if (!Array.isArray(list)) {
|
|
815
|
+
throw badState(`${STATE_PATH}.google.signatures`, "must be an array");
|
|
816
|
+
}
|
|
817
|
+
return list.map((raw, index) => {
|
|
818
|
+
const path = `${STATE_PATH}.google.signatures.${index}`;
|
|
819
|
+
if (!isRecord2(raw)) throw badState(path, "must be an object");
|
|
820
|
+
for (const key of Object.keys(raw)) {
|
|
821
|
+
if (!ENTRY_KEYS.has(key)) throw badState(`${path}.${key}`, "is not a known key");
|
|
822
|
+
}
|
|
823
|
+
const { messageIndex, partIndex, kind, model, partSha256: digest, signature } = raw;
|
|
824
|
+
if (typeof messageIndex !== "number" || !Number.isInteger(messageIndex) || messageIndex < 0) {
|
|
825
|
+
throw badState(`${path}.messageIndex`, "must be a non-negative integer");
|
|
826
|
+
}
|
|
827
|
+
if (typeof partIndex !== "number" || !Number.isInteger(partIndex) || partIndex < 0) {
|
|
828
|
+
throw badState(`${path}.partIndex`, "must be a non-negative integer");
|
|
829
|
+
}
|
|
830
|
+
if (kind !== "text" && kind !== "tool-call") {
|
|
831
|
+
throw badState(`${path}.kind`, 'must be "text" or "tool-call"');
|
|
832
|
+
}
|
|
833
|
+
if (typeof model !== "string" || model.length === 0) {
|
|
834
|
+
throw badState(`${path}.model`, "must be a non-empty string");
|
|
835
|
+
}
|
|
836
|
+
if (typeof digest !== "string" || !SHA256_HEX.test(digest)) {
|
|
837
|
+
throw badState(`${path}.partSha256`, "must be 64 lowercase hex characters");
|
|
838
|
+
}
|
|
839
|
+
if (typeof signature !== "string" || signature.length === 0) {
|
|
840
|
+
throw badState(`${path}.signature`, "must be a non-empty string");
|
|
841
|
+
}
|
|
842
|
+
return { messageIndex, partIndex, kind, model, partSha256: digest, signature };
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
var STALE = "history was edited, reordered or produced by another model after the signature was issued";
|
|
846
|
+
function resolveSignatures(entries, messages, model) {
|
|
847
|
+
const bySlot = /* @__PURE__ */ new Map();
|
|
848
|
+
const kept = [];
|
|
849
|
+
const dropped = [];
|
|
850
|
+
const seen = /* @__PURE__ */ new Set();
|
|
851
|
+
for (const [index, entry] of entries.entries()) {
|
|
852
|
+
const path = `${STATE_PATH}.google.signatures.${index}`;
|
|
853
|
+
const slot = `${entry.messageIndex}:${entry.partIndex}`;
|
|
854
|
+
const where = `messages.${entry.messageIndex}.parts.${entry.partIndex}`;
|
|
855
|
+
const stale = (field, why) => {
|
|
856
|
+
if (entry.kind === "tool-call") throw badState(`${path}.${field}`, why);
|
|
857
|
+
dropped.push(`${where}: ${why}`);
|
|
858
|
+
};
|
|
859
|
+
if (seen.has(slot)) throw badState(path, `duplicates the entry for ${where}`);
|
|
860
|
+
seen.add(slot);
|
|
861
|
+
if (entry.model !== model) {
|
|
862
|
+
stale(
|
|
863
|
+
"model",
|
|
864
|
+
`was issued for model "${entry.model}" but this request names "${model}"; signatures are not replayed across models (${STALE})`
|
|
865
|
+
);
|
|
866
|
+
continue;
|
|
867
|
+
}
|
|
868
|
+
const message = messages[entry.messageIndex];
|
|
869
|
+
if (message === void 0 || message.role !== "assistant") {
|
|
870
|
+
stale(
|
|
871
|
+
"messageIndex",
|
|
872
|
+
`does not point at an assistant message in messages (${STALE})`
|
|
873
|
+
);
|
|
874
|
+
continue;
|
|
875
|
+
}
|
|
876
|
+
const part = message.parts[entry.partIndex];
|
|
877
|
+
if (part === void 0) {
|
|
878
|
+
stale("partIndex", `is out of range for the message (${STALE})`);
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
881
|
+
if (part.kind !== entry.kind) {
|
|
882
|
+
stale(
|
|
883
|
+
"kind",
|
|
884
|
+
`is for a "${entry.kind}" part but ${where} is a "${part.kind}" part (${STALE})`
|
|
885
|
+
);
|
|
886
|
+
continue;
|
|
887
|
+
}
|
|
888
|
+
if (partSha256(part, where) !== entry.partSha256) {
|
|
889
|
+
stale("partSha256", `does not match ${where} (${STALE})`);
|
|
890
|
+
continue;
|
|
891
|
+
}
|
|
892
|
+
bySlot.set(slot, entry.signature);
|
|
893
|
+
kept.push(entry);
|
|
894
|
+
}
|
|
895
|
+
for (const [mi, message] of messages.entries()) {
|
|
896
|
+
if (message.role !== "assistant") continue;
|
|
897
|
+
const first = message.parts.findIndex((part) => part.kind === "tool-call");
|
|
898
|
+
if (first === -1 || bySlot.has(`${mi}:${first}`)) continue;
|
|
899
|
+
const call = message.parts[first];
|
|
900
|
+
throw badState(
|
|
901
|
+
`messages.${mi}.parts.${first}`,
|
|
902
|
+
`replays tool call "${call?.kind === "tool-call" ? call.toolCallId : ""}" without its thought signature in transientProviderState; Gemini 3 rejects a function call that lost it. Send the transientProviderState from the result that produced this message, and the history unedited, with the same model string. If you removed messages from the history, remove their entries with dropMessagesFromSignatureState`
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
return { bySlot, kept, dropped };
|
|
906
|
+
}
|
|
907
|
+
function signatureEntry(messageIndex, partIndex, model, part, signature) {
|
|
908
|
+
if (part.kind !== "text" && part.kind !== "tool-call") {
|
|
909
|
+
throw badState(
|
|
910
|
+
`messages.${messageIndex}.parts.${partIndex}`,
|
|
911
|
+
`a thought signature cannot be attached to a "${part.kind}" part`
|
|
912
|
+
);
|
|
913
|
+
}
|
|
914
|
+
return {
|
|
915
|
+
messageIndex,
|
|
916
|
+
partIndex,
|
|
917
|
+
kind: part.kind,
|
|
918
|
+
model,
|
|
919
|
+
partSha256: partSha256(part),
|
|
920
|
+
signature
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
function dropMessagesFromSignatureState(state, indices) {
|
|
924
|
+
const removed = /* @__PURE__ */ new Set();
|
|
925
|
+
for (const [i, value] of indices.entries()) {
|
|
926
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
927
|
+
throw new core.LlmError(
|
|
928
|
+
`dropMessagesFromSignatureState: indices.${i} must be a non-negative integer.`,
|
|
929
|
+
{
|
|
930
|
+
kind: "bad_request",
|
|
931
|
+
retryable: false,
|
|
932
|
+
issues: [{ path: `indices.${i}`, message: "must be a non-negative integer" }]
|
|
933
|
+
}
|
|
934
|
+
);
|
|
935
|
+
}
|
|
936
|
+
if (removed.has(value)) {
|
|
937
|
+
throw new core.LlmError(
|
|
938
|
+
`dropMessagesFromSignatureState: indices.${i} repeats message ${value}.`,
|
|
939
|
+
{
|
|
940
|
+
kind: "bad_request",
|
|
941
|
+
retryable: false,
|
|
942
|
+
issues: [{ path: `indices.${i}`, message: "is a duplicate" }]
|
|
943
|
+
}
|
|
944
|
+
);
|
|
945
|
+
}
|
|
946
|
+
removed.add(value);
|
|
947
|
+
}
|
|
948
|
+
const sorted = [...removed].sort((a, b) => a - b);
|
|
949
|
+
const signatures = [];
|
|
950
|
+
for (const entry of parseSignatureState(state)) {
|
|
951
|
+
if (removed.has(entry.messageIndex)) continue;
|
|
952
|
+
const shift = sorted.filter((index) => index < entry.messageIndex).length;
|
|
953
|
+
signatures.push({ ...entry, messageIndex: entry.messageIndex - shift });
|
|
954
|
+
}
|
|
955
|
+
return signatures.length > 0 ? { google: { signatures } } : void 0;
|
|
956
|
+
}
|
|
957
|
+
|
|
181
958
|
// src/adapter.ts
|
|
182
959
|
var ALLOWED_GOOGLE_PROVIDER_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
960
|
+
"allowSchemaWithSearch",
|
|
183
961
|
"cachedContent",
|
|
184
962
|
"flexFallback",
|
|
185
963
|
"httpOptions",
|
|
964
|
+
"requireGrounding",
|
|
186
965
|
"safetySettings",
|
|
187
966
|
"tools"
|
|
188
967
|
]);
|
|
@@ -243,6 +1022,8 @@ function parseGoogleTool(tool, model) {
|
|
|
243
1022
|
);
|
|
244
1023
|
}
|
|
245
1024
|
}
|
|
1025
|
+
var SAFETY_CATEGORY_SET = new Set(GOOGLE_SAFETY_CATEGORIES);
|
|
1026
|
+
var SAFETY_THRESHOLD_SET = new Set(GOOGLE_SAFETY_THRESHOLDS);
|
|
246
1027
|
function parseGoogleSafetySetting(setting, index, model) {
|
|
247
1028
|
if (!isPlainRecord(setting)) {
|
|
248
1029
|
throw badGoogleProviderOptions(
|
|
@@ -258,14 +1039,14 @@ function parseGoogleSafetySetting(setting, index, model) {
|
|
|
258
1039
|
)}] for model "${model}". Allowed keys: category, threshold.`
|
|
259
1040
|
);
|
|
260
1041
|
}
|
|
261
|
-
if (typeof setting["category"] !== "string" || setting["category"]
|
|
1042
|
+
if (typeof setting["category"] !== "string" || !SAFETY_CATEGORY_SET.has(setting["category"])) {
|
|
262
1043
|
throw badGoogleProviderOptions(
|
|
263
|
-
`providerOptions.google.safetySettings[${index}].category must be
|
|
1044
|
+
`providerOptions.google.safetySettings[${index}].category must be one of ${GOOGLE_SAFETY_CATEGORIES.join(", ")} for model "${model}".`
|
|
264
1045
|
);
|
|
265
1046
|
}
|
|
266
|
-
if (typeof setting["threshold"] !== "string" || setting["threshold"]
|
|
1047
|
+
if (typeof setting["threshold"] !== "string" || !SAFETY_THRESHOLD_SET.has(setting["threshold"])) {
|
|
267
1048
|
throw badGoogleProviderOptions(
|
|
268
|
-
`providerOptions.google.safetySettings[${index}].threshold must be
|
|
1049
|
+
`providerOptions.google.safetySettings[${index}].threshold must be one of ${GOOGLE_SAFETY_THRESHOLDS.join(", ")} for model "${model}".`
|
|
269
1050
|
);
|
|
270
1051
|
}
|
|
271
1052
|
return {
|
|
@@ -273,11 +1054,28 @@ function parseGoogleSafetySetting(setting, index, model) {
|
|
|
273
1054
|
threshold: setting["threshold"]
|
|
274
1055
|
};
|
|
275
1056
|
}
|
|
1057
|
+
function describeType(value) {
|
|
1058
|
+
return value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
1059
|
+
}
|
|
1060
|
+
function noSchemaWithSearchEvidence(model) {
|
|
1061
|
+
return `Structured output with googleSearch is not supported for model "${model}": no live capture shows Search running when a response schema is attached to this model (the captures cover Gemini 3.x only), so there is no measured behaviour to opt into and providerOptions.google.allowSchemaWithSearch does not apply. Make two calls instead: grounded research without a schema, then structured synthesis (the two-call recipe in docs/grounded-structured.md).`;
|
|
1062
|
+
}
|
|
1063
|
+
function assertSchemaWithSearchAllowed(model, structuredOutputWithTools, allowSchemaWithSearch, declaredBy) {
|
|
1064
|
+
if (structuredOutputWithTools === void 0) {
|
|
1065
|
+
throw badGoogleProviderOptions(noSchemaWithSearchEvidence(model));
|
|
1066
|
+
}
|
|
1067
|
+
if (allowSchemaWithSearch !== true) {
|
|
1068
|
+
throw badGoogleProviderOptions(
|
|
1069
|
+
`Structured output with googleSearch is not enabled for model "${model}" (Search is declared by ${declaredBy}): the provider accepts the request but Search does not reliably run when a response schema is attached. Make two calls instead: grounded research without a schema, then structured synthesis (the two-call recipe in docs/grounded-structured.md). To send both in one call anyway, set providerOptions.google.allowSchemaWithSearch: true; the call then fails unless the response proves Search ran (requireGrounding), and that failure is not retryable because the same call keeps missing.`
|
|
1070
|
+
);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
276
1073
|
function mapGoogleProviderOptions({
|
|
277
1074
|
googleOpts,
|
|
278
1075
|
model,
|
|
279
1076
|
structuredOutputRequested,
|
|
280
1077
|
descriptorGrounding,
|
|
1078
|
+
descriptorCaching,
|
|
281
1079
|
structuredOutputWithTools
|
|
282
1080
|
}) {
|
|
283
1081
|
if (googleOpts === void 0) {
|
|
@@ -299,23 +1097,43 @@ function mapGoogleProviderOptions({
|
|
|
299
1097
|
);
|
|
300
1098
|
}
|
|
301
1099
|
const unknownKeys = Object.keys(googleOpts).filter(
|
|
302
|
-
(key) => !ALLOWED_GOOGLE_PROVIDER_OPTION_KEYS.has(key)
|
|
1100
|
+
(key) => !ALLOWED_GOOGLE_PROVIDER_OPTION_KEYS.has(key)
|
|
303
1101
|
);
|
|
304
1102
|
if (unknownKeys.length > 0) {
|
|
305
1103
|
throw badGoogleProviderOptions(
|
|
306
1104
|
`providerOptions.google contains unsupported keys [${unknownKeys.join(
|
|
307
1105
|
", "
|
|
308
|
-
)}] for model "${model}". Allowed keys: cachedContent, flexFallback, httpOptions, safetySettings, tools.`
|
|
1106
|
+
)}] for model "${model}". Allowed keys: allowSchemaWithSearch, cachedContent, flexFallback, httpOptions, requireGrounding, safetySettings, tools.`
|
|
309
1107
|
);
|
|
310
1108
|
}
|
|
311
1109
|
const mapped = {};
|
|
312
1110
|
if (googleOpts["cachedContent"] !== void 0) {
|
|
313
|
-
if (
|
|
1111
|
+
if (!descriptorCaching) {
|
|
1112
|
+
throw badGoogleProviderOptions(
|
|
1113
|
+
`providerOptions.google.cachedContent is not supported for model "${model}": the model has no explicit-caching capability.`
|
|
1114
|
+
);
|
|
1115
|
+
}
|
|
1116
|
+
const cached = googleOpts["cachedContent"];
|
|
1117
|
+
if (typeof cached === "string" && cached.length > 0) {
|
|
1118
|
+
mapped.cachedContent = cached;
|
|
1119
|
+
} else if (isPlainRecord(cached)) {
|
|
1120
|
+
const extraKeys = Object.keys(cached).filter(
|
|
1121
|
+
(key) => key !== "cacheName" && key !== "toolKinds"
|
|
1122
|
+
);
|
|
1123
|
+
const cacheName = cached["cacheName"];
|
|
1124
|
+
const toolKinds = cached["toolKinds"];
|
|
1125
|
+
if (extraKeys.length > 0 || typeof cacheName !== "string" || cacheName.length === 0 || toolKinds !== void 0 && (!Array.isArray(toolKinds) || !toolKinds.every((kind) => typeof kind === "string"))) {
|
|
1126
|
+
throw badGoogleProviderOptions(
|
|
1127
|
+
`providerOptions.google.cachedContent must be a non-empty cache name, or { cacheName: non-empty string, toolKinds?: string[] } and nothing else (pass handle.cacheName and handle.toolKinds, not the whole handle), for model "${model}".`
|
|
1128
|
+
);
|
|
1129
|
+
}
|
|
1130
|
+
mapped.cachedContent = cacheName;
|
|
1131
|
+
if (toolKinds !== void 0) mapped.cachedToolKinds = toolKinds;
|
|
1132
|
+
} else {
|
|
314
1133
|
throw badGoogleProviderOptions(
|
|
315
|
-
`providerOptions.google.cachedContent must be a non-empty string for model "${model}".`
|
|
1134
|
+
`providerOptions.google.cachedContent must be a non-empty cache name, or { cacheName: non-empty string, toolKinds?: string[] }, for model "${model}".`
|
|
316
1135
|
);
|
|
317
1136
|
}
|
|
318
|
-
mapped.cachedContent = googleOpts["cachedContent"];
|
|
319
1137
|
}
|
|
320
1138
|
if (googleOpts["flexFallback"] !== void 0) {
|
|
321
1139
|
if (typeof googleOpts["flexFallback"] !== "boolean") {
|
|
@@ -343,9 +1161,9 @@ function mapGoogleProviderOptions({
|
|
|
343
1161
|
}
|
|
344
1162
|
const timeout = googleOpts["httpOptions"]["timeout"];
|
|
345
1163
|
if (timeout !== void 0) {
|
|
346
|
-
if (typeof timeout !== "number" || !Number.isInteger(timeout) || timeout <= 0) {
|
|
1164
|
+
if (typeof timeout !== "number" || !Number.isInteger(timeout) || timeout <= 0 || timeout > MAX_TIMER_MS) {
|
|
347
1165
|
throw badGoogleProviderOptions(
|
|
348
|
-
`providerOptions.google.httpOptions.timeout must be a positive integer for model "${model}".`
|
|
1166
|
+
`providerOptions.google.httpOptions.timeout must be a positive integer of at most ${MAX_TIMER_MS} ms (the longest delay a Node timer holds; a larger one aborts the call after 1 ms) for model "${model}".`
|
|
349
1167
|
);
|
|
350
1168
|
}
|
|
351
1169
|
mapped.httpOptions = { timeout };
|
|
@@ -363,6 +1181,18 @@ function mapGoogleProviderOptions({
|
|
|
363
1181
|
(setting, index) => parseGoogleSafetySetting(setting, index, model)
|
|
364
1182
|
);
|
|
365
1183
|
}
|
|
1184
|
+
const allowSchemaWithSearch = googleOpts["allowSchemaWithSearch"];
|
|
1185
|
+
if (allowSchemaWithSearch !== void 0 && typeof allowSchemaWithSearch !== "boolean") {
|
|
1186
|
+
throw badGoogleProviderOptions(
|
|
1187
|
+
`providerOptions.google.allowSchemaWithSearch must be a boolean for model "${model}", received ${describeType(allowSchemaWithSearch)}.`
|
|
1188
|
+
);
|
|
1189
|
+
}
|
|
1190
|
+
const requireGrounding = googleOpts["requireGrounding"];
|
|
1191
|
+
if (requireGrounding !== void 0 && typeof requireGrounding !== "boolean") {
|
|
1192
|
+
throw badGoogleProviderOptions(
|
|
1193
|
+
`providerOptions.google.requireGrounding must be a boolean for model "${model}", received ${describeType(requireGrounding)}.`
|
|
1194
|
+
);
|
|
1195
|
+
}
|
|
366
1196
|
if (googleOpts["tools"] !== void 0) {
|
|
367
1197
|
if (!Array.isArray(googleOpts["tools"])) {
|
|
368
1198
|
throw badGoogleProviderOptions(
|
|
@@ -376,12 +1206,54 @@ function mapGoogleProviderOptions({
|
|
|
376
1206
|
);
|
|
377
1207
|
}
|
|
378
1208
|
if (structuredOutputRequested && structuredOutputWithTools !== true) {
|
|
379
|
-
|
|
380
|
-
|
|
1209
|
+
assertSchemaWithSearchAllowed(
|
|
1210
|
+
model,
|
|
1211
|
+
structuredOutputWithTools,
|
|
1212
|
+
allowSchemaWithSearch,
|
|
1213
|
+
"providerOptions.google.tools"
|
|
381
1214
|
);
|
|
382
1215
|
}
|
|
383
1216
|
mapped.tools = tools;
|
|
384
1217
|
}
|
|
1218
|
+
const searchInCache = mapped.cachedToolKinds?.includes("googleSearch") === true;
|
|
1219
|
+
if (searchInCache) {
|
|
1220
|
+
if (descriptorGrounding !== true) {
|
|
1221
|
+
throw badGoogleProviderOptions(
|
|
1222
|
+
`providerOptions.google.cachedContent.toolKinds lists googleSearch, which is not supported for model "${model}": the model does not support grounding.`
|
|
1223
|
+
);
|
|
1224
|
+
}
|
|
1225
|
+
if (structuredOutputRequested && structuredOutputWithTools !== true) {
|
|
1226
|
+
assertSchemaWithSearchAllowed(
|
|
1227
|
+
model,
|
|
1228
|
+
structuredOutputWithTools,
|
|
1229
|
+
allowSchemaWithSearch,
|
|
1230
|
+
"the cache handle (cachedContent.toolKinds)"
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
const searchSent = searchInCache || mapped.tools?.some((tool) => "googleSearch" in tool) === true;
|
|
1235
|
+
if (allowSchemaWithSearch === true) {
|
|
1236
|
+
if (descriptorGrounding !== true) {
|
|
1237
|
+
throw badGoogleProviderOptions(
|
|
1238
|
+
`providerOptions.google.allowSchemaWithSearch is not supported for model "${model}": the model does not support grounding.`
|
|
1239
|
+
);
|
|
1240
|
+
}
|
|
1241
|
+
if (!searchSent || !structuredOutputRequested) {
|
|
1242
|
+
throw badGoogleProviderOptions(
|
|
1243
|
+
`providerOptions.google.allowSchemaWithSearch requires both Search (providerOptions.google.tools: [{ googleSearch: {} }], or a cachedContent handle whose toolKinds lists googleSearch) and output.jsonSchema for model "${model}".`
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
if (structuredOutputWithTools === void 0) {
|
|
1247
|
+
throw badGoogleProviderOptions(noSchemaWithSearchEvidence(model));
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
if (requireGrounding === true && !searchSent) {
|
|
1251
|
+
throw badGoogleProviderOptions(
|
|
1252
|
+
`providerOptions.google.requireGrounding requires Search: providerOptions.google.tools: [{ googleSearch: {} }], or a cachedContent handle whose toolKinds lists googleSearch, for model "${model}".`
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
const effectiveRequireGrounding = requireGrounding ?? allowSchemaWithSearch === true;
|
|
1256
|
+
if (effectiveRequireGrounding) mapped.requireGrounding = true;
|
|
385
1257
|
return mapped;
|
|
386
1258
|
}
|
|
387
1259
|
function assertSamplingAllowed(config, model, sampling) {
|
|
@@ -405,6 +1277,99 @@ function assertSamplingAllowed(config, model, sampling) {
|
|
|
405
1277
|
);
|
|
406
1278
|
}
|
|
407
1279
|
}
|
|
1280
|
+
var MAX_INLINE_REQUEST_BYTES = 100 * 1024 * 1024;
|
|
1281
|
+
var MAX_INLINE_PDF_BYTES = 50 * 1024 * 1024;
|
|
1282
|
+
var PDF_MEDIA_TYPES = ["application/pdf"];
|
|
1283
|
+
function assertInlinePayloadWithinLimits(contents, system) {
|
|
1284
|
+
let total = system === void 0 ? 0 : utf8ByteLength(system);
|
|
1285
|
+
contents.forEach((content, mi) => {
|
|
1286
|
+
content.parts.forEach((part, pi) => {
|
|
1287
|
+
if ("text" in part) total += utf8ByteLength(part.text);
|
|
1288
|
+
if (!("inlineData" in part)) return;
|
|
1289
|
+
const { mimeType, data } = part.inlineData;
|
|
1290
|
+
total += data.length;
|
|
1291
|
+
if (core.isMediaTypeAdmitted(mimeType, PDF_MEDIA_TYPES)) {
|
|
1292
|
+
const decoded = Math.floor(data.length * 3 / 4);
|
|
1293
|
+
if (decoded > MAX_INLINE_PDF_BYTES) {
|
|
1294
|
+
throw new core.LlmError(
|
|
1295
|
+
`messages[${mi}].parts[${pi}] is an inline PDF of about ${decoded} bytes, over Google's 50 MB inline PDF limit. Upload it with GoogleFileStore and send a file-uri part.`,
|
|
1296
|
+
{
|
|
1297
|
+
kind: "bad_request",
|
|
1298
|
+
retryable: false,
|
|
1299
|
+
provider: "google",
|
|
1300
|
+
issues: [
|
|
1301
|
+
{
|
|
1302
|
+
path: `messages[${mi}].parts[${pi}]`,
|
|
1303
|
+
message: "inline PDF over 50 MB"
|
|
1304
|
+
}
|
|
1305
|
+
]
|
|
1306
|
+
}
|
|
1307
|
+
);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
});
|
|
1311
|
+
});
|
|
1312
|
+
if (total > MAX_INLINE_REQUEST_BYTES) {
|
|
1313
|
+
throw new core.LlmError(
|
|
1314
|
+
`The request carries at least ${total} bytes of inline data and text, over Google's 100 MB request limit. Upload large media with GoogleFileStore and send file-uri parts.`,
|
|
1315
|
+
{
|
|
1316
|
+
kind: "bad_request",
|
|
1317
|
+
retryable: false,
|
|
1318
|
+
provider: "google",
|
|
1319
|
+
issues: [{ path: "messages", message: "request over 100 MB" }]
|
|
1320
|
+
}
|
|
1321
|
+
);
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
var CANDIDATE_METADATA_KEYS = [
|
|
1325
|
+
"finishReason",
|
|
1326
|
+
"finishMessage",
|
|
1327
|
+
"safetyRatings",
|
|
1328
|
+
"citationMetadata",
|
|
1329
|
+
"urlContextMetadata"
|
|
1330
|
+
];
|
|
1331
|
+
var MAX_FINISH_MESSAGE_CHARS = 512;
|
|
1332
|
+
var MAX_METADATA_ARRAY = 50;
|
|
1333
|
+
var MAX_METADATA_STRING = 2048;
|
|
1334
|
+
var MAX_METADATA_DEPTH = 8;
|
|
1335
|
+
var MAX_RATINGS_IN_MESSAGE = 12;
|
|
1336
|
+
function truncateText(text, max) {
|
|
1337
|
+
return text.length > max ? `${text.slice(0, max)}\u2026` : text;
|
|
1338
|
+
}
|
|
1339
|
+
function boundMetadata(value, state, depth = 0) {
|
|
1340
|
+
if (typeof value === "string") {
|
|
1341
|
+
if (value.length > MAX_METADATA_STRING) state.truncated = true;
|
|
1342
|
+
return truncateText(value, MAX_METADATA_STRING);
|
|
1343
|
+
}
|
|
1344
|
+
if (value === null || typeof value !== "object") return value;
|
|
1345
|
+
if (depth >= MAX_METADATA_DEPTH) {
|
|
1346
|
+
state.truncated = true;
|
|
1347
|
+
return null;
|
|
1348
|
+
}
|
|
1349
|
+
if (Array.isArray(value)) {
|
|
1350
|
+
if (value.length > MAX_METADATA_ARRAY) state.truncated = true;
|
|
1351
|
+
return value.slice(0, MAX_METADATA_ARRAY).map((item) => boundMetadata(item, state, depth + 1));
|
|
1352
|
+
}
|
|
1353
|
+
const out = {};
|
|
1354
|
+
for (const [key, item] of Object.entries(value)) {
|
|
1355
|
+
if (item !== void 0) out[key] = boundMetadata(item, state, depth + 1);
|
|
1356
|
+
}
|
|
1357
|
+
return out;
|
|
1358
|
+
}
|
|
1359
|
+
function describeSafetyRatings(ratings) {
|
|
1360
|
+
if (!Array.isArray(ratings) || ratings.length === 0) return "";
|
|
1361
|
+
const parts = ratings.slice(0, MAX_RATINGS_IN_MESSAGE).flatMap((rating) => {
|
|
1362
|
+
if (typeof rating !== "object" || rating === null) return [];
|
|
1363
|
+
const { category, probability, blocked } = rating;
|
|
1364
|
+
if (typeof category !== "string") return [];
|
|
1365
|
+
return [
|
|
1366
|
+
`${truncateText(category, 80)}=${typeof probability === "string" ? truncateText(probability, 40) : "unknown"}${blocked === true ? " (blocked)" : ""}`
|
|
1367
|
+
];
|
|
1368
|
+
});
|
|
1369
|
+
if (parts.length === 0) return "";
|
|
1370
|
+
const more = ratings.length > MAX_RATINGS_IN_MESSAGE ? ` and ${ratings.length - MAX_RATINGS_IN_MESSAGE} more` : "";
|
|
1371
|
+
return `${parts.join(", ")}${more}`;
|
|
1372
|
+
}
|
|
408
1373
|
function mapFinishReason(raw) {
|
|
409
1374
|
if (raw === void 0) return void 0;
|
|
410
1375
|
switch (raw) {
|
|
@@ -416,7 +1381,10 @@ function mapFinishReason(raw) {
|
|
|
416
1381
|
case "RECITATION":
|
|
417
1382
|
case "BLOCKLIST":
|
|
418
1383
|
case "PROHIBITED_CONTENT":
|
|
1384
|
+
case "SPII":
|
|
419
1385
|
case "IMAGE_SAFETY":
|
|
1386
|
+
case "IMAGE_PROHIBITED_CONTENT":
|
|
1387
|
+
case "IMAGE_RECITATION":
|
|
420
1388
|
return "content_filter";
|
|
421
1389
|
default:
|
|
422
1390
|
return "other";
|
|
@@ -439,6 +1407,7 @@ function mapUsage(meta) {
|
|
|
439
1407
|
const candidatesTokenCount = meta?.candidatesTokenCount ?? 0;
|
|
440
1408
|
const cachedContentTokenCount = meta?.cachedContentTokenCount;
|
|
441
1409
|
const thoughtsTokenCount = meta?.thoughtsTokenCount;
|
|
1410
|
+
const toolUsePromptTokenCount = meta?.toolUsePromptTokenCount;
|
|
442
1411
|
const outputTokens = candidatesTokenCount + (thoughtsTokenCount ?? 0);
|
|
443
1412
|
const inputTokens = promptTokenCount;
|
|
444
1413
|
const totalTokens = meta?.totalTokenCount;
|
|
@@ -446,8 +1415,36 @@ function mapUsage(meta) {
|
|
|
446
1415
|
input: inputTokens,
|
|
447
1416
|
output: outputTokens,
|
|
448
1417
|
...cachedContentTokenCount !== void 0 ? { cached: cachedContentTokenCount } : {},
|
|
449
|
-
...thoughtsTokenCount !== void 0 ? { thinking: thoughtsTokenCount } : {}
|
|
1418
|
+
...thoughtsTokenCount !== void 0 ? { thinking: thoughtsTokenCount } : {},
|
|
1419
|
+
// Tokens of Search results fed back to the model. They sit in
|
|
1420
|
+
// `totalTokenCount` but outside `promptTokenCount`. Google's pricing page
|
|
1421
|
+
// (read 2026-10) says retrieved search results are not charged
|
|
1422
|
+
// as input tokens, so they are recorded and not priced; no live billing
|
|
1423
|
+
// reconciliation has confirmed it, so the total mismatch still marks the
|
|
1424
|
+
// cost `estimated`.
|
|
1425
|
+
...toolUsePromptTokenCount !== void 0 ? { tool_use_prompt: toolUsePromptTokenCount } : {}
|
|
450
1426
|
};
|
|
1427
|
+
let cachedSplitTokens;
|
|
1428
|
+
for (const [prefix, entries] of [
|
|
1429
|
+
["input", meta?.promptTokensDetails],
|
|
1430
|
+
["cached", meta?.cacheTokensDetails]
|
|
1431
|
+
]) {
|
|
1432
|
+
if (!Array.isArray(entries)) continue;
|
|
1433
|
+
if (prefix === "cached") cachedSplitTokens = 0;
|
|
1434
|
+
for (const entry of entries) {
|
|
1435
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
1436
|
+
const { modality, tokenCount: count } = entry;
|
|
1437
|
+
if (typeof modality !== "string" || modality === "" || typeof count !== "number" || !Number.isFinite(count) || count < 0) {
|
|
1438
|
+
continue;
|
|
1439
|
+
}
|
|
1440
|
+
const key = `${prefix}_${modality.toLowerCase()}`;
|
|
1441
|
+
details[key] = (details[key] ?? 0) + count;
|
|
1442
|
+
if (prefix === "cached") cachedSplitTokens = (cachedSplitTokens ?? 0) + count;
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
if (cachedSplitTokens !== void 0 && cachedContentTokenCount !== void 0 && cachedContentTokenCount > 0 && cachedSplitTokens >= cachedContentTokenCount && details["cached_audio"] === void 0) {
|
|
1446
|
+
details["cached_audio"] = 0;
|
|
1447
|
+
}
|
|
451
1448
|
const raw = meta !== void 0 ? meta : null;
|
|
452
1449
|
const usage = {
|
|
453
1450
|
inputTokens,
|
|
@@ -466,10 +1463,20 @@ function mapGoogleToolChoice(choice) {
|
|
|
466
1463
|
if (choice === "none") return { mode: "NONE" };
|
|
467
1464
|
return { mode: "ANY", allowedFunctionNames: [choice.name] };
|
|
468
1465
|
}
|
|
469
|
-
function
|
|
1466
|
+
function toFunctionResponseObject(p) {
|
|
1467
|
+
if (p.isError === true) return { error: p.result };
|
|
1468
|
+
if (typeof p.result === "object" && p.result !== null && !Array.isArray(p.result)) {
|
|
1469
|
+
return p.result;
|
|
1470
|
+
}
|
|
1471
|
+
return { output: p.result };
|
|
1472
|
+
}
|
|
1473
|
+
function mapPart(p, signature) {
|
|
470
1474
|
switch (p.kind) {
|
|
471
1475
|
case "text":
|
|
472
|
-
return {
|
|
1476
|
+
return {
|
|
1477
|
+
text: p.text,
|
|
1478
|
+
...signature !== void 0 ? { thoughtSignature: signature } : {}
|
|
1479
|
+
};
|
|
473
1480
|
case "inline-media": {
|
|
474
1481
|
return {
|
|
475
1482
|
inlineData: {
|
|
@@ -496,30 +1503,35 @@ function mapPart(p) {
|
|
|
496
1503
|
case "tool-call":
|
|
497
1504
|
return {
|
|
498
1505
|
functionCall: {
|
|
499
|
-
id
|
|
1506
|
+
// A synthesized id never reached Gemini; sending it would only be noise.
|
|
1507
|
+
...isSynthesizedToolCallId(p.toolCallId) ? {} : { id: p.toolCallId },
|
|
500
1508
|
name: p.toolName,
|
|
501
1509
|
args: p.args
|
|
502
|
-
}
|
|
1510
|
+
},
|
|
1511
|
+
...signature !== void 0 ? { thoughtSignature: signature } : {}
|
|
503
1512
|
};
|
|
504
1513
|
case "tool-result":
|
|
505
1514
|
return {
|
|
506
1515
|
functionResponse: {
|
|
507
|
-
id: p.toolCallId,
|
|
1516
|
+
...isSynthesizedToolCallId(p.toolCallId) ? {} : { id: p.toolCallId },
|
|
508
1517
|
name: p.toolName,
|
|
509
|
-
response: p
|
|
1518
|
+
response: toFunctionResponseObject(p)
|
|
510
1519
|
}
|
|
511
1520
|
};
|
|
512
1521
|
default:
|
|
513
1522
|
return core.assertNever(p);
|
|
514
1523
|
}
|
|
515
1524
|
}
|
|
516
|
-
function mapMessagesToGeminiContents(messages) {
|
|
517
|
-
return messages.map((msg) => ({
|
|
1525
|
+
function mapMessagesToGeminiContents(messages, signatures) {
|
|
1526
|
+
return messages.map((msg, mi) => ({
|
|
518
1527
|
role: msg.role === "assistant" ? "model" : "user",
|
|
519
|
-
parts: msg.parts.map(mapPart)
|
|
1528
|
+
parts: msg.parts.map((part, pi) => mapPart(part, signatures?.get(`${mi}:${pi}`)))
|
|
520
1529
|
}));
|
|
521
1530
|
}
|
|
522
1531
|
function geminiAdapter(opts) {
|
|
1532
|
+
return geminiAdapterWithClientFactory(opts?.client, buildGoogleClient);
|
|
1533
|
+
}
|
|
1534
|
+
function geminiAdapterWithClientFactory(injectedClient, buildClient) {
|
|
523
1535
|
return {
|
|
524
1536
|
id: "google",
|
|
525
1537
|
async run(req, ctx) {
|
|
@@ -532,23 +1544,37 @@ function geminiAdapter(opts) {
|
|
|
532
1544
|
const warnings = [];
|
|
533
1545
|
const model = req.model;
|
|
534
1546
|
const descriptor = req.modelDescriptor;
|
|
535
|
-
|
|
536
|
-
|
|
1547
|
+
core.assertModelMatchesDescriptor(req, descriptor, "google");
|
|
1548
|
+
core.assertInputMimeTypesAdmitted(req.messages, descriptor, "google");
|
|
1549
|
+
const signsHistory = descriptor.capabilities?.providerState === true;
|
|
1550
|
+
if (req.transientProviderState !== void 0 && !signsHistory) {
|
|
1551
|
+
throw new core.LlmError(`Model "${model}" does not admit transientProviderState.`, {
|
|
537
1552
|
kind: "bad_request",
|
|
538
1553
|
retryable: false
|
|
539
1554
|
});
|
|
540
1555
|
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
1556
|
+
const resolved = signsHistory ? resolveSignatures(
|
|
1557
|
+
parseSignatureState(req.transientProviderState),
|
|
1558
|
+
req.messages,
|
|
1559
|
+
model
|
|
1560
|
+
) : void 0;
|
|
1561
|
+
const incomingSignatures = resolved?.kept ?? [];
|
|
1562
|
+
if (resolved !== void 0 && resolved.dropped.length > 0) {
|
|
1563
|
+
warnings.push({
|
|
1564
|
+
type: "other",
|
|
1565
|
+
message: `google: dropped ${resolved.dropped.length} stale text signature(s) from transientProviderState (${resolved.dropped.join("; ")}); Google treats text signatures as optional, so nothing required was lost.`
|
|
545
1566
|
});
|
|
546
1567
|
}
|
|
547
|
-
const contents = mapMessagesToGeminiContents(
|
|
1568
|
+
const contents = mapMessagesToGeminiContents(
|
|
1569
|
+
req.messages,
|
|
1570
|
+
resolved?.bySlot
|
|
1571
|
+
);
|
|
1572
|
+
const system = req.system !== void 0 && req.system !== "" ? req.system : void 0;
|
|
1573
|
+
assertInlinePayloadWithinLimits(contents, system);
|
|
548
1574
|
const genConfig = req.config;
|
|
549
1575
|
const config = {};
|
|
550
|
-
if (
|
|
551
|
-
config.systemInstruction = { parts: [{ text:
|
|
1576
|
+
if (system !== void 0) {
|
|
1577
|
+
config.systemInstruction = { parts: [{ text: system }] };
|
|
552
1578
|
}
|
|
553
1579
|
if (genConfig.temperature !== void 0) {
|
|
554
1580
|
config.temperature = genConfig.temperature;
|
|
@@ -605,6 +1631,12 @@ function geminiAdapter(opts) {
|
|
|
605
1631
|
);
|
|
606
1632
|
}
|
|
607
1633
|
const budget = reasoning.budgetTokens !== void 0 ? reasoning.budgetTokens : reasoning.effort !== void 0 ? GOOGLE_REASONING_EFFORT_BUDGET[reasoning.effort] : void 0;
|
|
1634
|
+
if (budget !== void 0 && budget > 0 && genConfig.maxOutputTokens !== void 0 && budget >= genConfig.maxOutputTokens) {
|
|
1635
|
+
warnings.push({
|
|
1636
|
+
type: "other",
|
|
1637
|
+
message: `google: thinkingBudget (${budget}) is not below maxOutputTokens (${genConfig.maxOutputTokens}); thinking may consume the whole cap and leave no answer. Raise maxOutputTokens or lower the reasoning budget.`
|
|
1638
|
+
});
|
|
1639
|
+
}
|
|
608
1640
|
config.thinkingConfig = {
|
|
609
1641
|
...budget !== void 0 ? { thinkingBudget: budget } : {},
|
|
610
1642
|
...reasoning.includeThoughts === true ? { includeThoughts: true } : {}
|
|
@@ -648,6 +1680,12 @@ function geminiAdapter(opts) {
|
|
|
648
1680
|
core.assertNever(reasoning.effort);
|
|
649
1681
|
}
|
|
650
1682
|
}
|
|
1683
|
+
if (thinkingLevel === "HIGH" && genConfig.maxOutputTokens !== void 0 && genConfig.maxOutputTokens < GOOGLE_HIGH_EFFORT_MIN_OUTPUT_TOKENS) {
|
|
1684
|
+
warnings.push({
|
|
1685
|
+
type: "other",
|
|
1686
|
+
message: `google: reasoning.effort "high" can spend several thousand thinking tokens (measured up to 8,859) and maxOutputTokens is ${genConfig.maxOutputTokens}, below ${GOOGLE_HIGH_EFFORT_MIN_OUTPUT_TOKENS}; thinking may consume the whole cap and leave no answer. Raise maxOutputTokens or lower the effort.`
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
651
1689
|
config.thinkingConfig = {
|
|
652
1690
|
...thinkingLevel !== void 0 ? { thinkingLevel } : {},
|
|
653
1691
|
...reasoning.includeThoughts === true ? { includeThoughts: true } : {}
|
|
@@ -661,24 +1699,148 @@ function geminiAdapter(opts) {
|
|
|
661
1699
|
}
|
|
662
1700
|
const structuredOutputRequested = req.outputJsonSchema !== void 0;
|
|
663
1701
|
if (structuredOutputRequested) {
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
1702
|
+
if (descriptor.capabilities?.nativeStructuredOutput === false) {
|
|
1703
|
+
throw new core.LlmError(
|
|
1704
|
+
`output.jsonSchema is not supported for model "${model}": the model has no native structured output and the Google adapter has no other path.`,
|
|
1705
|
+
{
|
|
1706
|
+
kind: "bad_request",
|
|
1707
|
+
retryable: false,
|
|
1708
|
+
provider: "google",
|
|
1709
|
+
issues: [
|
|
1710
|
+
{
|
|
1711
|
+
path: "output.jsonSchema",
|
|
1712
|
+
message: "model has no native structured output"
|
|
1713
|
+
}
|
|
1714
|
+
]
|
|
1715
|
+
}
|
|
1716
|
+
);
|
|
668
1717
|
}
|
|
1718
|
+
core.assertJsonSchemaProfile(
|
|
1719
|
+
req.outputJsonSchema,
|
|
1720
|
+
"output.jsonSchema",
|
|
1721
|
+
googleJsonSchemaProfile(descriptor.model)
|
|
1722
|
+
);
|
|
1723
|
+
config.responseMimeType = "application/json";
|
|
1724
|
+
config.responseJsonSchema = req.outputJsonSchema;
|
|
669
1725
|
}
|
|
670
1726
|
const googleProviderConfig = mapGoogleProviderOptions({
|
|
671
1727
|
googleOpts: genConfig.providerOptions?.["google"],
|
|
672
1728
|
model,
|
|
673
1729
|
structuredOutputRequested,
|
|
674
1730
|
descriptorGrounding: descriptor.capabilities?.grounding,
|
|
1731
|
+
descriptorCaching: descriptor.capabilities?.caching !== void 0,
|
|
675
1732
|
structuredOutputWithTools: descriptor.capabilities?.structuredOutputWithTools
|
|
676
1733
|
});
|
|
1734
|
+
const googleSearchSent = googleProviderConfig.tools?.some((tool) => "googleSearch" in tool) === true;
|
|
1735
|
+
const searchDeclared = googleSearchSent || googleProviderConfig.cachedToolKinds?.includes("googleSearch") === true;
|
|
1736
|
+
const requireGrounding = googleProviderConfig.requireGrounding === true;
|
|
1737
|
+
const schemaSearchUndeclared = structuredOutputRequested && !searchDeclared && descriptor.capabilities?.structuredOutputWithTools !== true;
|
|
1738
|
+
const audioRequested = req.messages.some(
|
|
1739
|
+
(message) => message.parts.some(
|
|
1740
|
+
(part) => (part.kind === "inline-media" || part.kind === "file-uri") && part.mimeType.toLowerCase().startsWith("audio/")
|
|
1741
|
+
)
|
|
1742
|
+
);
|
|
1743
|
+
const mapUsageWithAudioMarker = (meta) => {
|
|
1744
|
+
const mapped = mapUsage(meta);
|
|
1745
|
+
if (audioRequested) mapped.details["audio_input_requested"] = 1;
|
|
1746
|
+
return mapped;
|
|
1747
|
+
};
|
|
1748
|
+
const usageFor = (meta, groundingMetadata2) => {
|
|
1749
|
+
const mapped = mapUsageWithAudioMarker(meta);
|
|
1750
|
+
const queries = countWebSearchQueries(groundingMetadata2);
|
|
1751
|
+
if (searchDeclared) {
|
|
1752
|
+
mapped.details["web_search_requested"] = 1;
|
|
1753
|
+
if (queries !== void 0) mapped.details["web_search_calls"] = queries;
|
|
1754
|
+
} else if (groundingMetadata2 !== void 0) {
|
|
1755
|
+
mapped.details["web_search_requested"] = 1;
|
|
1756
|
+
if (queries !== void 0 && queries > 0) {
|
|
1757
|
+
mapped.details["web_search_calls"] = queries;
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
return mapped;
|
|
1761
|
+
};
|
|
1762
|
+
const groundingWarnings = (groundingMetadata2) => {
|
|
1763
|
+
if (!searchDeclared) {
|
|
1764
|
+
if (groundingMetadata2 === void 0) return [];
|
|
1765
|
+
const queries = countWebSearchQueries(groundingMetadata2);
|
|
1766
|
+
const undeclaredSearchWarnings = schemaSearchUndeclared && queries !== void 0 && queries > 0 ? [
|
|
1767
|
+
{
|
|
1768
|
+
type: "other",
|
|
1769
|
+
message: `google: this call attached a response schema and the response reports search queries, so Search ran from the cache named in cachedContent. Schema plus Search is not admitted by default for model "${model}" (Search does not reliably run when a schema is attached) and no googleSearch was declared, so nothing checked that it would run or opted in; the result is returned, the Search fee is priced from the observed queries (cost.confidence is "estimated"), and this pattern is unreliable. Declare Search with cachedContent: { cacheName, toolKinds: ['googleSearch'] } together with allowSchemaWithSearch: true (the call then fails unless the response proves Search ran), or use the two-call recipe in docs/grounded-structured.md.`
|
|
1770
|
+
}
|
|
1771
|
+
] : [];
|
|
1772
|
+
return [
|
|
1773
|
+
...undeclaredSearchWarnings,
|
|
1774
|
+
{
|
|
1775
|
+
type: "other",
|
|
1776
|
+
message: queries !== void 0 && queries > 0 ? `google: the response reports ${queries} search quer${queries === 1 ? "y" : "ies"} but the request did not declare googleSearch (a cachedContent cache can hold the tool); the Search fee was priced from the observed queries, and cost.confidence is "estimated" because the free allowance is unknowable per call.` : 'google: the response carries groundingMetadata but the request did not declare googleSearch and the metadata names no query, so the number of searches is unknown; grounding fees are not included in cost, so cost.confidence is "estimated".'
|
|
1777
|
+
}
|
|
1778
|
+
];
|
|
1779
|
+
}
|
|
1780
|
+
if (groundingMetadata2 === void 0) {
|
|
1781
|
+
return [
|
|
1782
|
+
{
|
|
1783
|
+
type: "other",
|
|
1784
|
+
message: 'google: googleSearch was requested (sent, or held by the cache named in cachedContent) but the response carries no groundingMetadata, so Search may not have run, or may have run without being reported; grounding fees are not included in cost, so cost.confidence is "estimated".'
|
|
1785
|
+
}
|
|
1786
|
+
];
|
|
1787
|
+
}
|
|
1788
|
+
if (countWebSearchQueries(groundingMetadata2) === void 0) {
|
|
1789
|
+
return [
|
|
1790
|
+
{
|
|
1791
|
+
type: "other",
|
|
1792
|
+
message: 'google: groundingMetadata has no webSearchQueries, so the number of searches is unknown; grounding fees are not included in cost, so cost.confidence is "estimated".'
|
|
1793
|
+
}
|
|
1794
|
+
];
|
|
1795
|
+
}
|
|
1796
|
+
return [];
|
|
1797
|
+
};
|
|
1798
|
+
const modalityWarnings = (meta) => {
|
|
1799
|
+
if (meta === void 0) return [];
|
|
1800
|
+
const warnings2 = [];
|
|
1801
|
+
const { gaps } = promptLanes(mapUsageWithAudioMarker(meta));
|
|
1802
|
+
if (gaps.includes("audio-unreported")) {
|
|
1803
|
+
warnings2.push({
|
|
1804
|
+
type: "other",
|
|
1805
|
+
message: 'google: the request carries audio but usageMetadata.promptTokensDetails reports no AUDIO tokens, so the audio input rate could not be applied; on a model that prices audio apart from text, cost.confidence is "estimated" and the amount can understate.'
|
|
1806
|
+
});
|
|
1807
|
+
}
|
|
1808
|
+
if (gaps.includes("cached-audio-unknown")) {
|
|
1809
|
+
warnings2.push({
|
|
1810
|
+
type: "other",
|
|
1811
|
+
message: 'google: usageMetadata reports cached tokens without showing how many are audio (no AUDIO entry in cacheTokensDetails, and no per-modality prompt split that rules audio out), so audio in the cached content cannot be ruled out; on a model that prices audio apart from text, cost.confidence is "estimated" and the amount can understate.'
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
if (gaps.includes("inconsistent")) {
|
|
1815
|
+
warnings2.push({
|
|
1816
|
+
type: "other",
|
|
1817
|
+
message: 'google: the per-modality token counts in usageMetadata contradict each other (audio above the prompt or the cache, or lanes that exceed the prompt); the counts were clamped, and on a model that prices audio apart from text, cost.confidence is "estimated".'
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
return warnings2;
|
|
1821
|
+
};
|
|
1822
|
+
const billedFailure = (meta, groundingMetadata2) => {
|
|
1823
|
+
if (meta === void 0) return {};
|
|
1824
|
+
const failureWarnings = [
|
|
1825
|
+
...groundingWarnings(groundingMetadata2),
|
|
1826
|
+
...modalityWarnings(meta)
|
|
1827
|
+
];
|
|
1828
|
+
return {
|
|
1829
|
+
usage: usageFor(meta, groundingMetadata2),
|
|
1830
|
+
...failureWarnings.length > 0 ? { warnings: failureWarnings } : {}
|
|
1831
|
+
};
|
|
1832
|
+
};
|
|
677
1833
|
if (googleProviderConfig.cachedContent !== void 0) {
|
|
678
1834
|
config.cachedContent = googleProviderConfig.cachedContent;
|
|
679
1835
|
}
|
|
680
1836
|
if (googleProviderConfig.httpOptions !== void 0) {
|
|
681
1837
|
config.httpOptions = googleProviderConfig.httpOptions;
|
|
1838
|
+
const sdkTimeout = googleProviderConfig.httpOptions.timeout;
|
|
1839
|
+
if (sdkTimeout !== void 0 && genConfig.timeoutMs !== void 0 && sdkTimeout < genConfig.timeoutMs + TRANSPORT_TIMEOUT_BUFFER_MS) {
|
|
1840
|
+
throw badGoogleProviderOptions(
|
|
1841
|
+
`providerOptions.google.httpOptions.timeout (${sdkTimeout} ms) must be at least timeoutMs + ${TRANSPORT_TIMEOUT_BUFFER_MS} ms (${genConfig.timeoutMs + TRANSPORT_TIMEOUT_BUFFER_MS} ms) for model "${model}": a shorter SDK timer would abort the call before the engine's own timeout and surface a raw SDK abort.`
|
|
1842
|
+
);
|
|
1843
|
+
}
|
|
682
1844
|
}
|
|
683
1845
|
if (googleProviderConfig.safetySettings !== void 0) {
|
|
684
1846
|
config.safetySettings = googleProviderConfig.safetySettings;
|
|
@@ -687,7 +1849,7 @@ function geminiAdapter(opts) {
|
|
|
687
1849
|
config.tools = googleProviderConfig.tools;
|
|
688
1850
|
}
|
|
689
1851
|
if (req.tools !== void 0 && req.tools.length > 0) {
|
|
690
|
-
if (
|
|
1852
|
+
if (descriptor.capabilities?.functionCalling !== true) {
|
|
691
1853
|
throw new core.LlmError(
|
|
692
1854
|
`tools is not supported for google model "${model}" (capabilities.functionCalling is not true).`,
|
|
693
1855
|
{ kind: "bad_request", retryable: false, provider: "google" }
|
|
@@ -695,16 +1857,24 @@ function geminiAdapter(opts) {
|
|
|
695
1857
|
}
|
|
696
1858
|
if (googleProviderConfig.tools !== void 0) {
|
|
697
1859
|
throw new core.LlmError(
|
|
698
|
-
"tools cannot be combined with providerOptions.google.tools (googleSearch) in
|
|
1860
|
+
"tools cannot be combined with providerOptions.google.tools (googleSearch): this adapter does not send function declarations and Search in one request.",
|
|
699
1861
|
{ kind: "bad_request", retryable: false, provider: "google" }
|
|
700
1862
|
);
|
|
701
1863
|
}
|
|
1864
|
+
const toolProfile = googleJsonSchemaProfile(descriptor.model);
|
|
1865
|
+
req.tools.forEach((tool, index) => {
|
|
1866
|
+
core.assertJsonSchemaProfile(
|
|
1867
|
+
tool.inputJsonSchema,
|
|
1868
|
+
`tools[${index}].inputJsonSchema`,
|
|
1869
|
+
toolProfile
|
|
1870
|
+
);
|
|
1871
|
+
});
|
|
702
1872
|
config.tools = [
|
|
703
1873
|
{
|
|
704
1874
|
functionDeclarations: req.tools.map((tool) => ({
|
|
705
1875
|
name: tool.name,
|
|
706
1876
|
description: tool.description,
|
|
707
|
-
|
|
1877
|
+
parametersJsonSchema: tool.inputJsonSchema
|
|
708
1878
|
}))
|
|
709
1879
|
}
|
|
710
1880
|
];
|
|
@@ -714,11 +1884,37 @@ function geminiAdapter(opts) {
|
|
|
714
1884
|
};
|
|
715
1885
|
}
|
|
716
1886
|
}
|
|
717
|
-
|
|
1887
|
+
if (config.cachedContent !== void 0) {
|
|
1888
|
+
const conflicts = [
|
|
1889
|
+
...system !== void 0 ? ["system"] : [],
|
|
1890
|
+
...req.tools !== void 0 && req.tools.length > 0 ? ["tools"] : [],
|
|
1891
|
+
...googleProviderConfig.tools !== void 0 ? ["providerOptions.google.tools"] : []
|
|
1892
|
+
];
|
|
1893
|
+
if (conflicts.length > 0) {
|
|
1894
|
+
throw new core.LlmError(
|
|
1895
|
+
`providerOptions.google.cachedContent cannot be combined with ${conflicts.join(
|
|
1896
|
+
" or "
|
|
1897
|
+
)} for model "${model}": Gemini requires the system instruction and tools to be stored in the cache. Put them in GoogleCacheStore.create and omit them from the request.`,
|
|
1898
|
+
{
|
|
1899
|
+
kind: "bad_request",
|
|
1900
|
+
retryable: false,
|
|
1901
|
+
provider: "google",
|
|
1902
|
+
issues: conflicts.map((path) => ({
|
|
1903
|
+
path,
|
|
1904
|
+
message: "cannot be sent with cachedContent"
|
|
1905
|
+
}))
|
|
1906
|
+
}
|
|
1907
|
+
);
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
assertSamplingAllowed(config, model, descriptor.capabilities?.sampling);
|
|
1911
|
+
const timers = ctx.scheduler ?? PLATFORM_SCHEDULER;
|
|
718
1912
|
let tierTimeoutHandle;
|
|
1913
|
+
let ceilingFiredMs;
|
|
719
1914
|
const clearTierTimeout = () => {
|
|
1915
|
+
ceilingFiredMs = void 0;
|
|
720
1916
|
if (tierTimeoutHandle !== void 0) {
|
|
721
|
-
clearTimeout(tierTimeoutHandle);
|
|
1917
|
+
timers.clearTimeout(tierTimeoutHandle);
|
|
722
1918
|
tierTimeoutHandle = void 0;
|
|
723
1919
|
}
|
|
724
1920
|
};
|
|
@@ -733,7 +1929,8 @@ function geminiAdapter(opts) {
|
|
|
733
1929
|
`${tierLabel} timeout: call exceeded ${defaultTimeoutMs}ms client-side ceiling (@google/genai #1277 belt-and-suspenders)`,
|
|
734
1930
|
"TimeoutError"
|
|
735
1931
|
);
|
|
736
|
-
tierTimeoutHandle = setTimeout(() => {
|
|
1932
|
+
tierTimeoutHandle = timers.setTimeout(() => {
|
|
1933
|
+
ceilingFiredMs = defaultTimeoutMs;
|
|
737
1934
|
tierController.abort(timeoutReason);
|
|
738
1935
|
}, defaultTimeoutMs);
|
|
739
1936
|
config.abortSignal = ctx.signal !== void 0 ? AbortSignal.any([tierController.signal, ctx.signal]) : tierController.signal;
|
|
@@ -763,8 +1960,7 @@ function geminiAdapter(opts) {
|
|
|
763
1960
|
contents,
|
|
764
1961
|
config: dispatchConfig
|
|
765
1962
|
};
|
|
766
|
-
const
|
|
767
|
-
const client = opts?.client !== void 0 ? opts.client : await buildClient(ctx.auth);
|
|
1963
|
+
const client = injectedClient !== void 0 ? injectedClient : await buildClient(ctx.auth);
|
|
768
1964
|
ctx.logger.debug(
|
|
769
1965
|
{
|
|
770
1966
|
model,
|
|
@@ -775,16 +1971,32 @@ function geminiAdapter(opts) {
|
|
|
775
1971
|
);
|
|
776
1972
|
return client.models.generateContent(params);
|
|
777
1973
|
};
|
|
1974
|
+
const transportTimeoutOf = (rawErr) => {
|
|
1975
|
+
if (ctx.signal?.aborted === true) return void 0;
|
|
1976
|
+
if (ceilingFiredMs !== void 0) {
|
|
1977
|
+
return `Google call hit the ${ceilingFiredMs}ms client-side ceiling`;
|
|
1978
|
+
}
|
|
1979
|
+
const sdkTimeoutMs = config.httpOptions?.timeout;
|
|
1980
|
+
if (sdkTimeoutMs !== void 0 && rawErr instanceof Error && rawErr.name === "AbortError") {
|
|
1981
|
+
return `Google call hit the SDK transport timeout of ${sdkTimeoutMs}ms`;
|
|
1982
|
+
}
|
|
1983
|
+
return void 0;
|
|
1984
|
+
};
|
|
778
1985
|
try {
|
|
779
1986
|
response = await dispatch();
|
|
780
1987
|
} catch (rawErr) {
|
|
781
|
-
const
|
|
782
|
-
|
|
783
|
-
servedServiceTier !== void 0 ? { servedServiceTier } :
|
|
784
|
-
|
|
1988
|
+
const transportTimeout = transportTimeoutOf(rawErr);
|
|
1989
|
+
const typed = classifyGoogleError(rawErr, {
|
|
1990
|
+
...servedServiceTier !== void 0 ? { servedServiceTier } : {},
|
|
1991
|
+
...transportTimeout !== void 0 ? { transportTimeout } : {}
|
|
1992
|
+
});
|
|
785
1993
|
if (config.serviceTier === "flex" && googleProviderConfig.flexFallback !== false && isGeminiCapacityError(typed)) {
|
|
786
1994
|
config.serviceTier = "standard";
|
|
787
1995
|
servedServiceTier = "standard";
|
|
1996
|
+
warnings.push({
|
|
1997
|
+
type: "other",
|
|
1998
|
+
message: `google: the flex call hit a capacity error (${typed.httpStatus ?? "no status"}) and was sent again at the standard tier, billed at standard rates.${genConfig.timeoutMs === void 0 ? ` Without timeoutMs the standard attempt runs under the ${STANDARD_DEFAULT_TIMEOUT_MS} ms client-side ceiling, not the flex ${FLEX_DEFAULT_TIMEOUT_MS} ms one.` : ""}`
|
|
1999
|
+
});
|
|
788
2000
|
const fallbackTimeout = genConfig.timeoutMs !== void 0 ? genConfig.timeoutMs + TRANSPORT_TIMEOUT_BUFFER_MS : STANDARD_DEFAULT_TIMEOUT_MS;
|
|
789
2001
|
config.httpOptions = {
|
|
790
2002
|
timeout: fallbackTimeout,
|
|
@@ -794,7 +2006,11 @@ function geminiAdapter(opts) {
|
|
|
794
2006
|
try {
|
|
795
2007
|
response = await dispatch();
|
|
796
2008
|
} catch (fallbackRawErr) {
|
|
797
|
-
|
|
2009
|
+
const fallbackTransportTimeout = transportTimeoutOf(fallbackRawErr);
|
|
2010
|
+
throw classifyGoogleError(fallbackRawErr, {
|
|
2011
|
+
servedServiceTier: "standard",
|
|
2012
|
+
...fallbackTransportTimeout !== void 0 ? { transportTimeout: fallbackTransportTimeout } : {}
|
|
2013
|
+
});
|
|
798
2014
|
}
|
|
799
2015
|
} else {
|
|
800
2016
|
throw typed;
|
|
@@ -813,49 +2029,105 @@ function geminiAdapter(opts) {
|
|
|
813
2029
|
servedServiceTier = echoedTier;
|
|
814
2030
|
}
|
|
815
2031
|
const hasBlockReason = response.promptFeedback?.blockReason !== void 0;
|
|
816
|
-
const
|
|
817
|
-
if (hasBlockReason ||
|
|
2032
|
+
const candidate = response.candidates?.[0];
|
|
2033
|
+
if (hasBlockReason || candidate === void 0) {
|
|
818
2034
|
const reason = response.promptFeedback?.blockReason ?? "NO_CANDIDATES";
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
2035
|
+
const thoughtTokens = response.usageMetadata?.thoughtsTokenCount ?? 0;
|
|
2036
|
+
const reasoningHint = !hasBlockReason && thoughtTokens > 0 ? `. The call billed ${thoughtTokens} reasoning tokens, and maxOutputTokens (${config.maxOutputTokens ?? "the provider default"}) includes reasoning tokens, so a low cap can be used up by reasoning before any answer is produced` : "";
|
|
2037
|
+
const promptRatings = hasBlockReason ? describeSafetyRatings(response.promptFeedback?.safetyRatings) : "";
|
|
2038
|
+
throw new core.LlmError(
|
|
2039
|
+
`Gemini response has no usable candidate: ${reason}${promptRatings !== "" ? ` (safetyRatings: ${promptRatings})` : ""}${reasoningHint}`,
|
|
2040
|
+
{
|
|
2041
|
+
kind: hasBlockReason ? "content_filter" : "server",
|
|
2042
|
+
retryable: !hasBlockReason && thoughtTokens === 0,
|
|
2043
|
+
provider: "google",
|
|
2044
|
+
...billedFailure(response.usageMetadata),
|
|
2045
|
+
...servedServiceTier !== void 0 ? { servedServiceTier } : {}
|
|
2046
|
+
}
|
|
2047
|
+
);
|
|
826
2048
|
}
|
|
827
|
-
const
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
2049
|
+
const groundingMetadata = candidate.groundingMetadata;
|
|
2050
|
+
const parts = candidate.content?.parts ?? [];
|
|
2051
|
+
const callsComplete = candidate.finishReason === void 0 || candidate.finishReason === "STOP";
|
|
2052
|
+
const isFunctionCall = (part) => part.functionCall !== void 0 && typeof part.functionCall.name === "string";
|
|
2053
|
+
const hasAnswer = parts.some(
|
|
2054
|
+
(part) => part.thought !== true && typeof part.text === "string" && part.text.length > 0 || callsComplete && isFunctionCall(part)
|
|
2055
|
+
);
|
|
2056
|
+
const filteredCandidateError = (note) => {
|
|
2057
|
+
const finishMessage = candidate.finishMessage !== void 0 ? truncateText(candidate.finishMessage, MAX_FINISH_MESSAGE_CHARS) : void 0;
|
|
2058
|
+
const ratings = describeSafetyRatings(candidate.safetyRatings);
|
|
2059
|
+
const bounded = { truncated: false };
|
|
2060
|
+
return new core.LlmError(
|
|
2061
|
+
`Gemini candidate was filtered (finishReason ${candidate.finishReason}${finishMessage !== void 0 ? `: ${finishMessage}` : ""}${ratings !== "" ? `; safetyRatings: ${ratings}` : ""}); ${note}. The attempt was billed.`,
|
|
2062
|
+
{
|
|
2063
|
+
kind: "content_filter",
|
|
2064
|
+
retryable: false,
|
|
2065
|
+
provider: "google",
|
|
2066
|
+
// The raw evidence, bounded: which category blocked, and why.
|
|
2067
|
+
cause: {
|
|
2068
|
+
finishReason: candidate.finishReason ?? null,
|
|
2069
|
+
...finishMessage !== void 0 ? { finishMessage } : {},
|
|
2070
|
+
...candidate.safetyRatings !== void 0 ? { safetyRatings: boundMetadata(candidate.safetyRatings, bounded) } : {}
|
|
2071
|
+
},
|
|
2072
|
+
...billedFailure(response.usageMetadata, groundingMetadata),
|
|
2073
|
+
...servedServiceTier !== void 0 ? { servedServiceTier } : {}
|
|
2074
|
+
}
|
|
2075
|
+
);
|
|
2076
|
+
};
|
|
2077
|
+
if (mapFinishReason(candidate.finishReason) === "content_filter" && !hasAnswer) {
|
|
2078
|
+
throw filteredCandidateError(
|
|
2079
|
+
"it carries no answer text and no complete tool call"
|
|
2080
|
+
);
|
|
836
2081
|
}
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
2082
|
+
if (requireGrounding) {
|
|
2083
|
+
const queries = countWebSearchQueries(groundingMetadata);
|
|
2084
|
+
if (groundingMetadata === void 0 || queries === void 0 || queries < 1) {
|
|
2085
|
+
const finishReason2 = mapFinishReason(candidate.finishReason);
|
|
2086
|
+
if (finishReason2 === "content_filter") {
|
|
2087
|
+
throw filteredCandidateError("the grounding check was not applied");
|
|
2088
|
+
}
|
|
2089
|
+
if (candidate.finishReason === void 0 || candidate.finishReason === "STOP") {
|
|
2090
|
+
const why = groundingMetadata === void 0 ? "the response has no groundingMetadata" : queries === void 0 ? "groundingMetadata has no webSearchQueries" : "groundingMetadata reports zero webSearchQueries";
|
|
2091
|
+
const retryable = !structuredOutputRequested;
|
|
2092
|
+
throw new core.LlmError(
|
|
2093
|
+
`google: requireGrounding is set but there is no evidence that Search ran: ${why}. The attempt was billed for its tokens${retryable ? "; a retry may ground." : "; it is not retryable, because a call with a response schema attached keeps missing (use the two-call recipe in docs/grounded-structured.md)."}`,
|
|
2094
|
+
{
|
|
2095
|
+
kind: "server",
|
|
2096
|
+
retryable,
|
|
2097
|
+
reason: "grounding_missing",
|
|
2098
|
+
provider: "google",
|
|
2099
|
+
...billedFailure(response.usageMetadata, groundingMetadata),
|
|
2100
|
+
...servedServiceTier !== void 0 ? { servedServiceTier } : {}
|
|
2101
|
+
}
|
|
2102
|
+
);
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
846
2105
|
}
|
|
847
|
-
const parts = candidate.content?.parts ?? [];
|
|
848
2106
|
const textParts = [];
|
|
849
2107
|
const thoughtParts = [];
|
|
850
2108
|
const toolCalls = [];
|
|
2109
|
+
const messageParts = [];
|
|
2110
|
+
const issuedSignatures = [];
|
|
2111
|
+
let droppedSignatures = 0;
|
|
2112
|
+
const droppedCalls = [];
|
|
851
2113
|
const nameCounts = /* @__PURE__ */ new Map();
|
|
852
|
-
const reservedIds = reserveProviderToolCallIds(
|
|
853
|
-
parts.map((part) => part.functionCall?.id)
|
|
854
|
-
|
|
2114
|
+
const reservedIds = reserveProviderToolCallIds([
|
|
2115
|
+
...parts.map((part) => part.functionCall?.id),
|
|
2116
|
+
...req.messages.flatMap(
|
|
2117
|
+
(message) => message.parts.flatMap(
|
|
2118
|
+
(part) => part.kind === "tool-call" || part.kind === "tool-result" ? [part.toolCallId] : []
|
|
2119
|
+
)
|
|
2120
|
+
)
|
|
2121
|
+
]);
|
|
855
2122
|
for (const part of parts) {
|
|
856
|
-
|
|
2123
|
+
const signature = typeof part.thoughtSignature === "string" && part.thoughtSignature.length > 0 ? part.thoughtSignature : void 0;
|
|
2124
|
+
let represented = false;
|
|
2125
|
+
if (isFunctionCall(part) && !callsComplete) {
|
|
2126
|
+
droppedCalls.push(part.functionCall?.name ?? "");
|
|
2127
|
+
represented = true;
|
|
2128
|
+
} else if (part.functionCall !== void 0 && typeof part.functionCall.name === "string") {
|
|
857
2129
|
const toolName = part.functionCall.name;
|
|
858
|
-
|
|
2130
|
+
const call = {
|
|
859
2131
|
toolCallId: resolveToolCallId(
|
|
860
2132
|
part.functionCall.id,
|
|
861
2133
|
toolName,
|
|
@@ -864,31 +2136,115 @@ function geminiAdapter(opts) {
|
|
|
864
2136
|
),
|
|
865
2137
|
toolName,
|
|
866
2138
|
args: part.functionCall.args ?? {}
|
|
867
|
-
}
|
|
2139
|
+
};
|
|
2140
|
+
toolCalls.push(call);
|
|
2141
|
+
if (signature !== void 0) {
|
|
2142
|
+
issuedSignatures.push({ partIndex: messageParts.length, signature });
|
|
2143
|
+
}
|
|
2144
|
+
messageParts.push({ kind: "tool-call", ...call });
|
|
2145
|
+
represented = true;
|
|
868
2146
|
}
|
|
869
2147
|
if (part.text !== void 0) {
|
|
870
2148
|
if (part.thought === true) {
|
|
871
2149
|
thoughtParts.push(part.text);
|
|
872
2150
|
} else {
|
|
873
2151
|
textParts.push(part.text);
|
|
2152
|
+
if (part.text.length > 0) {
|
|
2153
|
+
if (signature !== void 0 && !represented) {
|
|
2154
|
+
issuedSignatures.push({ partIndex: messageParts.length, signature });
|
|
2155
|
+
}
|
|
2156
|
+
messageParts.push({ kind: "text", text: part.text });
|
|
2157
|
+
represented = true;
|
|
2158
|
+
}
|
|
874
2159
|
}
|
|
875
2160
|
}
|
|
2161
|
+
if (signature !== void 0 && !represented) droppedSignatures += 1;
|
|
2162
|
+
}
|
|
2163
|
+
if (droppedCalls.length > 0) {
|
|
2164
|
+
const named = droppedCalls.map((name) => `"${name}"`).join(", ");
|
|
2165
|
+
warnings.push({
|
|
2166
|
+
type: "other",
|
|
2167
|
+
message: `google: dropped ${droppedCalls.length} function call(s) (${named}) because the candidate ended with finishReason ${candidate.finishReason ?? "unspecified"}, not STOP: ${candidate.finishReason === "MAX_TOKENS" ? "the call was cut by the output cap and is incomplete" : "a call beside an abnormal stop is not a call to run"}. The result carries no tool call; finishReason is "${mapFinishReason(candidate.finishReason) ?? "other"}".`
|
|
2168
|
+
});
|
|
876
2169
|
}
|
|
877
2170
|
const text = textParts.join("");
|
|
878
2171
|
const reasoningText = thoughtParts.length > 0 ? thoughtParts.join("") : void 0;
|
|
2172
|
+
let transientProviderState;
|
|
2173
|
+
if (signsHistory) {
|
|
2174
|
+
const issued = [];
|
|
2175
|
+
for (const { partIndex, signature } of issuedSignatures) {
|
|
2176
|
+
const part = messageParts[partIndex];
|
|
2177
|
+
try {
|
|
2178
|
+
issued.push(
|
|
2179
|
+
signatureEntry(req.messages.length, partIndex, model, part, signature)
|
|
2180
|
+
);
|
|
2181
|
+
} catch (error) {
|
|
2182
|
+
if (!(error instanceof core.LlmError)) throw error;
|
|
2183
|
+
warnings.push({
|
|
2184
|
+
type: "other",
|
|
2185
|
+
message: `google: no signature entry for messages.${req.messages.length}.parts.${partIndex} (a "${part.kind}" part): ${error.message} The result is returned without it; ${part.kind === "tool-call" ? "replaying this function call on the next turn will be rejected" : "a text signature is optional, so nothing required is lost"}.`
|
|
2186
|
+
});
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
const signatures = [...incomingSignatures, ...issued];
|
|
2190
|
+
if (signatures.length > 0) {
|
|
2191
|
+
transientProviderState = { google: { signatures } };
|
|
2192
|
+
}
|
|
2193
|
+
if (droppedSignatures > 0) {
|
|
2194
|
+
warnings.push({
|
|
2195
|
+
type: "other",
|
|
2196
|
+
message: `google: dropped ${droppedSignatures} thoughtSignature(s) on parts that have no message representation (thought or empty parts); Gemini requires only the function-call ones.`
|
|
2197
|
+
});
|
|
2198
|
+
}
|
|
2199
|
+
const firstCall = messageParts.findIndex((part) => part.kind === "tool-call");
|
|
2200
|
+
if (firstCall !== -1 && !issuedSignatures.some((entry) => entry.partIndex === firstCall)) {
|
|
2201
|
+
warnings.push({
|
|
2202
|
+
type: "other",
|
|
2203
|
+
message: "google: the first function call in this response carries no thoughtSignature; replaying it on the next turn will be rejected."
|
|
2204
|
+
});
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
879
2207
|
let rawStructured;
|
|
880
2208
|
if (structuredOutputRequested && text.length > 0) {
|
|
881
2209
|
try {
|
|
882
2210
|
rawStructured = JSON.parse(text);
|
|
883
2211
|
} catch {
|
|
2212
|
+
if (descriptor.model.startsWith("gemma-") && /^\s*```/.test(text)) {
|
|
2213
|
+
warnings.push({
|
|
2214
|
+
type: "other",
|
|
2215
|
+
message: `google: gemma_fenced_json: the answer from "${model}" is wrapped in a markdown code fence, so it is not parseable JSON and outputParsed is false. Gemma 4 fenced 67 of 162 schema answers (41%) in a live probe (2026-10-03) although the schema is native. The text is returned as the model sent it; call again, or unwrap the fence on the host side.`
|
|
2216
|
+
});
|
|
2217
|
+
}
|
|
884
2218
|
}
|
|
885
2219
|
}
|
|
886
|
-
const usage =
|
|
2220
|
+
const usage = usageFor(response.usageMetadata, groundingMetadata);
|
|
2221
|
+
if (response.usageMetadata === void 0) {
|
|
2222
|
+
usage.details["usage_missing"] = 1;
|
|
2223
|
+
warnings.push({
|
|
2224
|
+
type: "other",
|
|
2225
|
+
message: 'google: the response carries no usageMetadata, so token usage is unknown; the call is recorded with zero tokens and is not priced (cost.microUsd is null, cost.confidence is "estimated").'
|
|
2226
|
+
});
|
|
2227
|
+
}
|
|
887
2228
|
const finishReason = mapFinishReason(candidate.finishReason);
|
|
2229
|
+
warnings.push(...groundingWarnings(groundingMetadata));
|
|
2230
|
+
warnings.push(...modalityWarnings(response.usageMetadata));
|
|
2231
|
+
const answerParts = [];
|
|
2232
|
+
let answerOffset = 0;
|
|
2233
|
+
for (const part of parts) {
|
|
2234
|
+
if (part.thought === true) continue;
|
|
2235
|
+
if (typeof part.text === "string") {
|
|
2236
|
+
answerParts.push({ text: part.text, offset: answerOffset });
|
|
2237
|
+
answerOffset += part.text.length;
|
|
2238
|
+
} else {
|
|
2239
|
+
answerParts.push(void 0);
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
888
2242
|
const result = {
|
|
889
2243
|
model,
|
|
2244
|
+
message: { role: "assistant", parts: messageParts },
|
|
890
2245
|
usage,
|
|
891
2246
|
warnings,
|
|
2247
|
+
...transientProviderState !== void 0 ? { transientProviderState } : {},
|
|
892
2248
|
...servedServiceTier !== void 0 ? { servedServiceTier } : {},
|
|
893
2249
|
...text.length > 0 ? { text } : {},
|
|
894
2250
|
...reasoningText !== void 0 ? { reasoningText } : {},
|
|
@@ -896,24 +2252,59 @@ function geminiAdapter(opts) {
|
|
|
896
2252
|
...toolCalls.length > 0 ? { toolCalls, finishReason: "tool_calls" } : finishReason !== void 0 ? { finishReason } : {},
|
|
897
2253
|
...response.modelVersion !== void 0 ? { modelVersion: response.modelVersion } : {},
|
|
898
2254
|
...response.responseId !== void 0 ? { responseId: response.responseId } : {},
|
|
899
|
-
// Build providerMetadata — merge promptFeedback + groundingMetadata when
|
|
2255
|
+
// Build providerMetadata — merge promptFeedback + groundingMetadata when
|
|
2256
|
+
// present. `google.searchEntryPoint` is the Search Suggestions widget
|
|
2257
|
+
// Google requires a grounded answer to display.
|
|
900
2258
|
...(() => {
|
|
901
2259
|
const pf = response.promptFeedback;
|
|
902
|
-
const gm =
|
|
903
|
-
|
|
2260
|
+
const gm = groundingMetadata;
|
|
2261
|
+
const candidateFields = {};
|
|
2262
|
+
const bounded = { truncated: false };
|
|
2263
|
+
for (const key of CANDIDATE_METADATA_KEYS) {
|
|
2264
|
+
const value = candidate[key];
|
|
2265
|
+
if (value === void 0) continue;
|
|
2266
|
+
candidateFields[key] = key === "finishMessage" && typeof value === "string" ? (() => {
|
|
2267
|
+
if (value.length > MAX_FINISH_MESSAGE_CHARS) bounded.truncated = true;
|
|
2268
|
+
return truncateText(value, MAX_FINISH_MESSAGE_CHARS);
|
|
2269
|
+
})() : boundMetadata(value, bounded);
|
|
2270
|
+
}
|
|
2271
|
+
const googleMeta = {};
|
|
2272
|
+
if (Object.keys(candidateFields).length > 0) {
|
|
2273
|
+
googleMeta["candidate"] = candidateFields;
|
|
2274
|
+
}
|
|
2275
|
+
if (pf === void 0 && gm === void 0 && Object.keys(googleMeta).length === 0) {
|
|
2276
|
+
return {};
|
|
2277
|
+
}
|
|
904
2278
|
const meta = {};
|
|
905
2279
|
if (pf !== void 0) {
|
|
906
|
-
meta["promptFeedback"] = pf;
|
|
2280
|
+
meta["promptFeedback"] = boundMetadata(pf, bounded);
|
|
907
2281
|
}
|
|
908
2282
|
if (gm !== void 0) {
|
|
909
|
-
|
|
2283
|
+
const searchEntryPoint = readSearchEntryPoint(gm);
|
|
2284
|
+
if (searchEntryPoint !== void 0) {
|
|
2285
|
+
const { searchEntryPoint: _widget, ...rest } = gm;
|
|
2286
|
+
meta["groundingMetadata"] = boundMetadata(rest, bounded);
|
|
2287
|
+
googleMeta["searchEntryPoint"] = searchEntryPoint;
|
|
2288
|
+
} else {
|
|
2289
|
+
meta["groundingMetadata"] = boundMetadata(gm, bounded);
|
|
2290
|
+
}
|
|
910
2291
|
}
|
|
2292
|
+
if (bounded.truncated) {
|
|
2293
|
+
warnings.push({
|
|
2294
|
+
type: "other",
|
|
2295
|
+
message: `google: providerMetadata was truncated (finishMessage over ${MAX_FINISH_MESSAGE_CHARS} characters, a string over ${MAX_METADATA_STRING}, a list over ${MAX_METADATA_ARRAY} entries or nesting over ${MAX_METADATA_DEPTH} levels, in the candidate fields, promptFeedback or groundingMetadata); the citations are built from the full response.`
|
|
2296
|
+
});
|
|
2297
|
+
}
|
|
2298
|
+
if (Object.keys(googleMeta).length > 0) meta["google"] = googleMeta;
|
|
911
2299
|
return { providerMetadata: meta };
|
|
912
2300
|
})(),
|
|
913
2301
|
...(() => {
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
2302
|
+
if (groundingMetadata === void 0) return {};
|
|
2303
|
+
const citations = normalizeGroundingCitations(
|
|
2304
|
+
groundingMetadata,
|
|
2305
|
+
answerParts,
|
|
2306
|
+
(message) => warnings.push({ type: "other", message })
|
|
2307
|
+
);
|
|
917
2308
|
return citations.length > 0 ? { citations } : {};
|
|
918
2309
|
})()
|
|
919
2310
|
};
|
|
@@ -926,30 +2317,49 @@ function geminiAdapter(opts) {
|
|
|
926
2317
|
{ kind: "bad_request", retryable: false }
|
|
927
2318
|
);
|
|
928
2319
|
}
|
|
929
|
-
const
|
|
930
|
-
const
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
2320
|
+
const system = req.system !== void 0 && req.system !== "" ? req.system : void 0;
|
|
2321
|
+
const tools = req.tools !== void 0 && req.tools.length > 0 ? req.tools : void 0;
|
|
2322
|
+
if (tools !== void 0) {
|
|
2323
|
+
const descriptor = ctx.modelDescriptor;
|
|
2324
|
+
if (descriptor !== void 0 && descriptor.capabilities?.functionCalling !== true) {
|
|
2325
|
+
throw new core.LlmError(
|
|
2326
|
+
`tools is not supported for google model "${req.model}" (capabilities.functionCalling is not true).`,
|
|
2327
|
+
{ kind: "bad_request", retryable: false, provider: "google" }
|
|
2328
|
+
);
|
|
937
2329
|
}
|
|
938
|
-
|
|
2330
|
+
const toolProfile = googleJsonSchemaProfile(descriptor?.model ?? req.model);
|
|
2331
|
+
tools.forEach((tool, index) => {
|
|
2332
|
+
core.assertJsonSchemaProfile(
|
|
2333
|
+
tool.inputJsonSchema,
|
|
2334
|
+
`tools[${index}].inputJsonSchema`,
|
|
2335
|
+
toolProfile
|
|
2336
|
+
);
|
|
2337
|
+
});
|
|
2338
|
+
}
|
|
2339
|
+
if (ctx.modelDescriptor !== void 0) {
|
|
2340
|
+
core.assertInputMimeTypesAdmitted(req.messages, ctx.modelDescriptor, "google");
|
|
2341
|
+
}
|
|
2342
|
+
const contents = mapMessagesToGeminiContents(req.messages);
|
|
2343
|
+
assertInlinePayloadWithinLimits(contents, system);
|
|
939
2344
|
const params = {
|
|
940
2345
|
model: req.model,
|
|
941
2346
|
contents,
|
|
942
|
-
...
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
2347
|
+
...system !== void 0 ? { systemInstruction: { parts: [{ text: system }] } } : {},
|
|
2348
|
+
...tools !== void 0 ? {
|
|
2349
|
+
tools: [
|
|
2350
|
+
{
|
|
2351
|
+
functionDeclarations: tools.map((tool) => ({
|
|
2352
|
+
name: tool.name,
|
|
2353
|
+
description: tool.description,
|
|
2354
|
+
parametersJsonSchema: tool.inputJsonSchema
|
|
2355
|
+
}))
|
|
2356
|
+
}
|
|
2357
|
+
]
|
|
2358
|
+
} : {},
|
|
2359
|
+
...ctx.signal !== void 0 ? { config: { abortSignal: ctx.signal } } : {}
|
|
949
2360
|
};
|
|
950
2361
|
try {
|
|
951
|
-
const
|
|
952
|
-
const client = opts?.client !== void 0 ? opts.client : await buildClient(ctx.auth);
|
|
2362
|
+
const client = injectedClient !== void 0 ? injectedClient : await buildClient(ctx.auth);
|
|
953
2363
|
const response = await client.models.countTokens(params);
|
|
954
2364
|
if (response.totalTokens === void 0) {
|
|
955
2365
|
throw new core.LlmError(
|
|
@@ -958,9 +2368,12 @@ function geminiAdapter(opts) {
|
|
|
958
2368
|
);
|
|
959
2369
|
}
|
|
960
2370
|
const details = response.cachedContentTokenCount !== void 0 ? { cached: response.cachedContentTokenCount } : void 0;
|
|
2371
|
+
const omitsSignatures = ctx.modelDescriptor?.capabilities?.providerState === true && req.messages.some(
|
|
2372
|
+
(message) => message.role === "assistant" && message.parts.some((part) => part.kind === "tool-call")
|
|
2373
|
+
);
|
|
961
2374
|
return {
|
|
962
2375
|
totalTokens: response.totalTokens,
|
|
963
|
-
accuracy: "exact",
|
|
2376
|
+
accuracy: omitsSignatures ? "estimated" : "exact",
|
|
964
2377
|
...details !== void 0 ? { details } : {},
|
|
965
2378
|
raw: response
|
|
966
2379
|
};
|
|
@@ -970,129 +2383,52 @@ function geminiAdapter(opts) {
|
|
|
970
2383
|
}
|
|
971
2384
|
};
|
|
972
2385
|
}
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
},
|
|
989
|
-
{
|
|
990
|
-
inputPerM: 625e3,
|
|
991
|
-
cachedPerM: 125e3,
|
|
992
|
-
outputPerM: 5e6,
|
|
993
|
-
gt200k: { inputPerM: 125e4, cachedPerM: 25e4, outputPerM: 75e5 }
|
|
994
|
-
},
|
|
995
|
-
{
|
|
996
|
-
inputPerM: 625e3,
|
|
997
|
-
cachedPerM: 125e3,
|
|
998
|
-
outputPerM: 5e6,
|
|
999
|
-
gt200k: { inputPerM: 125e4, cachedPerM: 25e4, outputPerM: 75e5 }
|
|
1000
|
-
}
|
|
1001
|
-
),
|
|
1002
|
-
// Gemini 2.5 Flash. Flex/batch cached stays $0.03.
|
|
1003
|
-
"gemini-2.5-flash": tiers(
|
|
1004
|
-
{ inputPerM: 3e5, cachedPerM: 3e4, outputPerM: 25e5 },
|
|
1005
|
-
{ inputPerM: 15e4, cachedPerM: 3e4, outputPerM: 125e4 },
|
|
1006
|
-
{ inputPerM: 15e4, cachedPerM: 3e4, outputPerM: 125e4 }
|
|
1007
|
-
),
|
|
1008
|
-
// Gemini 2.5 Flash-Lite. Flex/batch cached stays $0.01.
|
|
1009
|
-
"gemini-2.5-flash-lite": tiers(
|
|
1010
|
-
{ inputPerM: 1e5, cachedPerM: 1e4, outputPerM: 4e5 },
|
|
1011
|
-
{ inputPerM: 5e4, cachedPerM: 1e4, outputPerM: 2e5 },
|
|
1012
|
-
{ inputPerM: 5e4, cachedPerM: 1e4, outputPerM: 2e5 }
|
|
1013
|
-
),
|
|
1014
|
-
// Gemini 3.1 Flash-Lite. Flex/batch cached is the published $0.0125.
|
|
1015
|
-
"gemini-3.1-flash-lite": tiers(
|
|
1016
|
-
{ inputPerM: 25e4, cachedPerM: 25e3, outputPerM: 15e5 },
|
|
1017
|
-
{ inputPerM: 125e3, cachedPerM: 12500, outputPerM: 75e4 },
|
|
1018
|
-
{ inputPerM: 125e3, cachedPerM: 12500, outputPerM: 75e4 }
|
|
1019
|
-
),
|
|
1020
|
-
// Gemini 3.8 / 3.7 / 3.6 Flash intro rates (2026-09-25). Flex/batch cached
|
|
1021
|
-
// is half of the intro cached rate. Re-snapshot on 2027-01-01.
|
|
1022
|
-
"gemini-3.8-flash": tiers(
|
|
1023
|
-
{ inputPerM: 75e4, cachedPerM: 75e3, outputPerM: 375e4 },
|
|
1024
|
-
{ inputPerM: 375e3, cachedPerM: 37500, outputPerM: 1875e3 },
|
|
1025
|
-
{ inputPerM: 375e3, cachedPerM: 37500, outputPerM: 1875e3 }
|
|
1026
|
-
),
|
|
1027
|
-
"gemini-3.7-flash": tiers(
|
|
1028
|
-
{ inputPerM: 75e4, cachedPerM: 75e3, outputPerM: 375e4 },
|
|
1029
|
-
{ inputPerM: 375e3, cachedPerM: 37500, outputPerM: 1875e3 },
|
|
1030
|
-
{ inputPerM: 375e3, cachedPerM: 37500, outputPerM: 1875e3 }
|
|
1031
|
-
),
|
|
1032
|
-
"gemini-3.6-flash": tiers(
|
|
1033
|
-
{ inputPerM: 75e4, cachedPerM: 75e3, outputPerM: 375e4 },
|
|
1034
|
-
{ inputPerM: 375e3, cachedPerM: 37500, outputPerM: 1875e3 },
|
|
1035
|
-
{ inputPerM: 375e3, cachedPerM: 37500, outputPerM: 1875e3 }
|
|
1036
|
-
),
|
|
1037
|
-
// Gemini 3.5 Flash-Lite. Flex/batch cached is the published $0.02, not half of $0.03.
|
|
1038
|
-
"gemini-3.5-flash-lite": tiers(
|
|
1039
|
-
{ inputPerM: 3e5, cachedPerM: 3e4, outputPerM: 25e5 },
|
|
1040
|
-
{ inputPerM: 15e4, cachedPerM: 2e4, outputPerM: 125e4 },
|
|
1041
|
-
{ inputPerM: 15e4, cachedPerM: 2e4, outputPerM: 125e4 }
|
|
1042
|
-
),
|
|
1043
|
-
// Gemini 3.1 Pro Preview. Flex/batch cached equals standard on both bands.
|
|
1044
|
-
"gemini-3.1-pro-preview": tiers(
|
|
1045
|
-
{
|
|
1046
|
-
inputPerM: 2e6,
|
|
1047
|
-
cachedPerM: 2e5,
|
|
1048
|
-
outputPerM: 12e6,
|
|
1049
|
-
gt200k: { inputPerM: 4e6, cachedPerM: 4e5, outputPerM: 18e6 }
|
|
1050
|
-
},
|
|
1051
|
-
{
|
|
1052
|
-
inputPerM: 1e6,
|
|
1053
|
-
cachedPerM: 2e5,
|
|
1054
|
-
outputPerM: 6e6,
|
|
1055
|
-
gt200k: { inputPerM: 2e6, cachedPerM: 4e5, outputPerM: 9e6 }
|
|
1056
|
-
},
|
|
1057
|
-
{
|
|
1058
|
-
inputPerM: 1e6,
|
|
1059
|
-
cachedPerM: 2e5,
|
|
1060
|
-
outputPerM: 6e6,
|
|
1061
|
-
gt200k: { inputPerM: 2e6, cachedPerM: 4e5, outputPerM: 9e6 }
|
|
1062
|
-
}
|
|
1063
|
-
)
|
|
2386
|
+
var cachedContentSchema = zod.z.union([
|
|
2387
|
+
zod.z.string().min(1),
|
|
2388
|
+
zod.z.strictObject({
|
|
2389
|
+
cacheName: zod.z.string().min(1).meta({
|
|
2390
|
+
title: "Cache Name",
|
|
2391
|
+
description: "Google cached content resource name."
|
|
2392
|
+
}),
|
|
2393
|
+
toolKinds: zod.z.array(zod.z.string().min(1)).optional().meta({
|
|
2394
|
+
title: "Tool Kinds",
|
|
2395
|
+
description: "The tool kinds the cache holds (`GoogleCacheHandle.toolKinds`), e.g. googleSearch."
|
|
2396
|
+
})
|
|
2397
|
+
})
|
|
2398
|
+
]).optional().meta({
|
|
2399
|
+
title: "Cached Content",
|
|
2400
|
+
description: "Google cached content: the resource name, or { cacheName, toolKinds } from a cache handle."
|
|
1064
2401
|
});
|
|
1065
|
-
function isPricedGeminiTier(tier) {
|
|
1066
|
-
return GEMINI_PRICED_TIERS.includes(tier);
|
|
1067
|
-
}
|
|
1068
|
-
function lookupGeminiTierRates(model, tier) {
|
|
1069
|
-
const entry = Object.hasOwn(GEMINI_PRICING, model) ? GEMINI_PRICING[model] : void 0;
|
|
1070
|
-
if (entry === void 0) return void 0;
|
|
1071
|
-
if (tier !== void 0 && !isPricedGeminiTier(tier)) return void 0;
|
|
1072
|
-
return entry;
|
|
1073
|
-
}
|
|
1074
|
-
function resolveGeminiRates(model, tier) {
|
|
1075
|
-
const entry = lookupGeminiTierRates(model, tier);
|
|
1076
|
-
if (entry === void 0) return void 0;
|
|
1077
|
-
const key = tier ?? "standard";
|
|
1078
|
-
return entry[key];
|
|
1079
|
-
}
|
|
1080
2402
|
|
|
1081
|
-
// src/
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
2403
|
+
// src/model-limits.ts
|
|
2404
|
+
var geminiLimits = () => Object.freeze({ contextWindow: 1048576, maxOutputTokens: 65536 });
|
|
2405
|
+
var gemma4Limits = () => Object.freeze({ contextWindow: 262144, maxOutputTokens: null });
|
|
2406
|
+
var GOOGLE_MODEL_LIMITS = {
|
|
2407
|
+
"gemini-2.5-pro": geminiLimits(),
|
|
2408
|
+
"gemini-2.5-flash": geminiLimits(),
|
|
2409
|
+
"gemini-2.5-flash-lite": geminiLimits(),
|
|
2410
|
+
"gemini-3.1-flash-lite": geminiLimits(),
|
|
2411
|
+
"gemini-3.1-pro-preview": geminiLimits(),
|
|
2412
|
+
"gemini-3.8-flash": geminiLimits(),
|
|
2413
|
+
"gemini-3.7-flash": geminiLimits(),
|
|
2414
|
+
"gemini-3.6-flash": geminiLimits(),
|
|
2415
|
+
"gemini-3.5-flash-lite": geminiLimits(),
|
|
2416
|
+
"gemma-4-31b-it": gemma4Limits(),
|
|
2417
|
+
"gemma-4-26b-a4b-it": gemma4Limits()
|
|
2418
|
+
};
|
|
2419
|
+
var GEMINI_INPUT_MIME_TYPES = Object.freeze([
|
|
2420
|
+
"application/pdf",
|
|
2421
|
+
"text/*",
|
|
2422
|
+
"image/*",
|
|
2423
|
+
"audio/*",
|
|
2424
|
+
"video/*"
|
|
2425
|
+
]);
|
|
2426
|
+
var GEMMA_INPUT_MIME_TYPES = Object.freeze([
|
|
2427
|
+
"image/*",
|
|
2428
|
+
"video/*"
|
|
2429
|
+
]);
|
|
2430
|
+
|
|
2431
|
+
// src/model-config/gemini-2.5-pro.ts
|
|
1096
2432
|
var Gemini25ProConfigSchema = zod.z.union([
|
|
1097
2433
|
zod.z.strictObject({
|
|
1098
2434
|
temperature: zod.z.number().min(0).max(2).optional().meta({
|
|
@@ -1108,7 +2444,7 @@ var Gemini25ProConfigSchema = zod.z.union([
|
|
|
1108
2444
|
title: "Top K",
|
|
1109
2445
|
description: "Top-k sampling limit for gemini-2.5-pro."
|
|
1110
2446
|
}),
|
|
1111
|
-
maxOutputTokens:
|
|
2447
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemini-2.5-pro"]).optional().meta({
|
|
1112
2448
|
title: "Max Output Tokens",
|
|
1113
2449
|
description: "Maximum output token cap for gemini-2.5-pro."
|
|
1114
2450
|
}),
|
|
@@ -1151,25 +2487,26 @@ var Gemini25ProConfigSchema = zod.z.union([
|
|
|
1151
2487
|
title: "Reasoning",
|
|
1152
2488
|
description: "Gemini 2.5 Pro thinkingBudget configuration."
|
|
1153
2489
|
}),
|
|
1154
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
2490
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
1155
2491
|
title: "Timeout",
|
|
1156
2492
|
description: "Logical request timeout in milliseconds."
|
|
1157
2493
|
}),
|
|
1158
2494
|
providerOptions: zod.z.strictObject({
|
|
1159
2495
|
google: zod.z.strictObject({
|
|
1160
|
-
|
|
1161
|
-
title: "
|
|
1162
|
-
description: "Google
|
|
2496
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
2497
|
+
title: "Require Grounding",
|
|
2498
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
1163
2499
|
}),
|
|
2500
|
+
cachedContent: cachedContentSchema,
|
|
1164
2501
|
safetySettings: zod.z.array(
|
|
1165
2502
|
zod.z.strictObject({
|
|
1166
|
-
category: zod.z.
|
|
2503
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
1167
2504
|
title: "Safety Category",
|
|
1168
|
-
description: "Google safety category
|
|
2505
|
+
description: "Documented Google safety category."
|
|
1169
2506
|
}),
|
|
1170
|
-
threshold: zod.z.
|
|
2507
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
1171
2508
|
title: "Safety Threshold",
|
|
1172
|
-
description: "Google safety threshold
|
|
2509
|
+
description: "Documented Google safety threshold."
|
|
1173
2510
|
})
|
|
1174
2511
|
})
|
|
1175
2512
|
).optional().meta({
|
|
@@ -1188,9 +2525,9 @@ var Gemini25ProConfigSchema = zod.z.union([
|
|
|
1188
2525
|
description: "Allowlisted Google tools for gemini-2.5-pro."
|
|
1189
2526
|
}),
|
|
1190
2527
|
httpOptions: zod.z.strictObject({
|
|
1191
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
2528
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
1192
2529
|
title: "HTTP Timeout",
|
|
1193
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
2530
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
1194
2531
|
})
|
|
1195
2532
|
}).optional().meta({
|
|
1196
2533
|
title: "HTTP Options",
|
|
@@ -1223,7 +2560,7 @@ var Gemini25ProConfigSchema = zod.z.union([
|
|
|
1223
2560
|
title: "Top K",
|
|
1224
2561
|
description: "Top-k sampling limit for gemini-2.5-pro."
|
|
1225
2562
|
}),
|
|
1226
|
-
maxOutputTokens:
|
|
2563
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemini-2.5-pro"]).optional().meta({
|
|
1227
2564
|
title: "Max Output Tokens",
|
|
1228
2565
|
description: "Maximum output token cap for gemini-2.5-pro."
|
|
1229
2566
|
}),
|
|
@@ -1266,25 +2603,26 @@ var Gemini25ProConfigSchema = zod.z.union([
|
|
|
1266
2603
|
title: "Reasoning",
|
|
1267
2604
|
description: "Gemini 2.5 Pro thinkingBudget configuration."
|
|
1268
2605
|
}),
|
|
1269
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
2606
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
1270
2607
|
title: "Timeout",
|
|
1271
2608
|
description: "Logical request timeout in milliseconds."
|
|
1272
2609
|
}),
|
|
1273
2610
|
providerOptions: zod.z.strictObject({
|
|
1274
2611
|
google: zod.z.strictObject({
|
|
1275
|
-
|
|
1276
|
-
title: "
|
|
1277
|
-
description: "Google
|
|
2612
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
2613
|
+
title: "Require Grounding",
|
|
2614
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
1278
2615
|
}),
|
|
2616
|
+
cachedContent: cachedContentSchema,
|
|
1279
2617
|
safetySettings: zod.z.array(
|
|
1280
2618
|
zod.z.strictObject({
|
|
1281
|
-
category: zod.z.
|
|
2619
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
1282
2620
|
title: "Safety Category",
|
|
1283
|
-
description: "Google safety category
|
|
2621
|
+
description: "Documented Google safety category."
|
|
1284
2622
|
}),
|
|
1285
|
-
threshold: zod.z.
|
|
2623
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
1286
2624
|
title: "Safety Threshold",
|
|
1287
|
-
description: "Google safety threshold
|
|
2625
|
+
description: "Documented Google safety threshold."
|
|
1288
2626
|
})
|
|
1289
2627
|
})
|
|
1290
2628
|
).optional().meta({
|
|
@@ -1303,9 +2641,9 @@ var Gemini25ProConfigSchema = zod.z.union([
|
|
|
1303
2641
|
description: "Allowlisted Google tools for gemini-2.5-pro."
|
|
1304
2642
|
}),
|
|
1305
2643
|
httpOptions: zod.z.strictObject({
|
|
1306
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
2644
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
1307
2645
|
title: "HTTP Timeout",
|
|
1308
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
2646
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
1309
2647
|
})
|
|
1310
2648
|
}).optional().meta({
|
|
1311
2649
|
title: "HTTP Options",
|
|
@@ -1340,7 +2678,7 @@ var Gemini25FlashConfigSchema = zod.z.union([
|
|
|
1340
2678
|
title: "Top K",
|
|
1341
2679
|
description: "Top-k sampling limit for gemini-2.5-flash."
|
|
1342
2680
|
}),
|
|
1343
|
-
maxOutputTokens:
|
|
2681
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemini-2.5-flash"]).optional().meta({
|
|
1344
2682
|
title: "Max Output Tokens",
|
|
1345
2683
|
description: "Maximum output token cap for gemini-2.5-flash."
|
|
1346
2684
|
}),
|
|
@@ -1383,25 +2721,26 @@ var Gemini25FlashConfigSchema = zod.z.union([
|
|
|
1383
2721
|
title: "Reasoning",
|
|
1384
2722
|
description: "Gemini 2.5 Flash thinkingBudget configuration."
|
|
1385
2723
|
}),
|
|
1386
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
2724
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
1387
2725
|
title: "Timeout",
|
|
1388
2726
|
description: "Logical request timeout in milliseconds."
|
|
1389
2727
|
}),
|
|
1390
2728
|
providerOptions: zod.z.strictObject({
|
|
1391
2729
|
google: zod.z.strictObject({
|
|
1392
|
-
|
|
1393
|
-
title: "
|
|
1394
|
-
description: "Google
|
|
2730
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
2731
|
+
title: "Require Grounding",
|
|
2732
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
1395
2733
|
}),
|
|
2734
|
+
cachedContent: cachedContentSchema,
|
|
1396
2735
|
safetySettings: zod.z.array(
|
|
1397
2736
|
zod.z.strictObject({
|
|
1398
|
-
category: zod.z.
|
|
2737
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
1399
2738
|
title: "Safety Category",
|
|
1400
|
-
description: "Google safety category
|
|
2739
|
+
description: "Documented Google safety category."
|
|
1401
2740
|
}),
|
|
1402
|
-
threshold: zod.z.
|
|
2741
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
1403
2742
|
title: "Safety Threshold",
|
|
1404
|
-
description: "Google safety threshold
|
|
2743
|
+
description: "Documented Google safety threshold."
|
|
1405
2744
|
})
|
|
1406
2745
|
})
|
|
1407
2746
|
).optional().meta({
|
|
@@ -1420,9 +2759,9 @@ var Gemini25FlashConfigSchema = zod.z.union([
|
|
|
1420
2759
|
description: "Allowlisted Google tools for gemini-2.5-flash."
|
|
1421
2760
|
}),
|
|
1422
2761
|
httpOptions: zod.z.strictObject({
|
|
1423
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
2762
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
1424
2763
|
title: "HTTP Timeout",
|
|
1425
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
2764
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
1426
2765
|
})
|
|
1427
2766
|
}).optional().meta({
|
|
1428
2767
|
title: "HTTP Options",
|
|
@@ -1455,7 +2794,7 @@ var Gemini25FlashConfigSchema = zod.z.union([
|
|
|
1455
2794
|
title: "Top K",
|
|
1456
2795
|
description: "Top-k sampling limit for gemini-2.5-flash."
|
|
1457
2796
|
}),
|
|
1458
|
-
maxOutputTokens:
|
|
2797
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemini-2.5-flash"]).optional().meta({
|
|
1459
2798
|
title: "Max Output Tokens",
|
|
1460
2799
|
description: "Maximum output token cap for gemini-2.5-flash."
|
|
1461
2800
|
}),
|
|
@@ -1498,25 +2837,26 @@ var Gemini25FlashConfigSchema = zod.z.union([
|
|
|
1498
2837
|
title: "Reasoning",
|
|
1499
2838
|
description: "Gemini 2.5 Flash thinkingBudget configuration."
|
|
1500
2839
|
}),
|
|
1501
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
2840
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
1502
2841
|
title: "Timeout",
|
|
1503
2842
|
description: "Logical request timeout in milliseconds."
|
|
1504
2843
|
}),
|
|
1505
2844
|
providerOptions: zod.z.strictObject({
|
|
1506
2845
|
google: zod.z.strictObject({
|
|
1507
|
-
|
|
1508
|
-
title: "
|
|
1509
|
-
description: "Google
|
|
2846
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
2847
|
+
title: "Require Grounding",
|
|
2848
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
1510
2849
|
}),
|
|
2850
|
+
cachedContent: cachedContentSchema,
|
|
1511
2851
|
safetySettings: zod.z.array(
|
|
1512
2852
|
zod.z.strictObject({
|
|
1513
|
-
category: zod.z.
|
|
2853
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
1514
2854
|
title: "Safety Category",
|
|
1515
|
-
description: "Google safety category
|
|
2855
|
+
description: "Documented Google safety category."
|
|
1516
2856
|
}),
|
|
1517
|
-
threshold: zod.z.
|
|
2857
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
1518
2858
|
title: "Safety Threshold",
|
|
1519
|
-
description: "Google safety threshold
|
|
2859
|
+
description: "Documented Google safety threshold."
|
|
1520
2860
|
})
|
|
1521
2861
|
})
|
|
1522
2862
|
).optional().meta({
|
|
@@ -1535,9 +2875,9 @@ var Gemini25FlashConfigSchema = zod.z.union([
|
|
|
1535
2875
|
description: "Allowlisted Google tools for gemini-2.5-flash."
|
|
1536
2876
|
}),
|
|
1537
2877
|
httpOptions: zod.z.strictObject({
|
|
1538
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
2878
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
1539
2879
|
title: "HTTP Timeout",
|
|
1540
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
2880
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
1541
2881
|
})
|
|
1542
2882
|
}).optional().meta({
|
|
1543
2883
|
title: "HTTP Options",
|
|
@@ -1572,7 +2912,7 @@ var Gemini25FlashLiteConfigSchema = zod.z.union([
|
|
|
1572
2912
|
title: "Top K",
|
|
1573
2913
|
description: "Top-k sampling limit for gemini-2.5-flash-lite."
|
|
1574
2914
|
}),
|
|
1575
|
-
maxOutputTokens:
|
|
2915
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemini-2.5-flash-lite"]).optional().meta({
|
|
1576
2916
|
title: "Max Output Tokens",
|
|
1577
2917
|
description: "Maximum output token cap for gemini-2.5-flash-lite."
|
|
1578
2918
|
}),
|
|
@@ -1615,25 +2955,26 @@ var Gemini25FlashLiteConfigSchema = zod.z.union([
|
|
|
1615
2955
|
title: "Reasoning",
|
|
1616
2956
|
description: "Gemini 2.5 Flash-Lite thinkingBudget configuration."
|
|
1617
2957
|
}),
|
|
1618
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
2958
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
1619
2959
|
title: "Timeout",
|
|
1620
2960
|
description: "Logical request timeout in milliseconds."
|
|
1621
2961
|
}),
|
|
1622
2962
|
providerOptions: zod.z.strictObject({
|
|
1623
2963
|
google: zod.z.strictObject({
|
|
1624
|
-
|
|
1625
|
-
title: "
|
|
1626
|
-
description: "Google
|
|
2964
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
2965
|
+
title: "Require Grounding",
|
|
2966
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
1627
2967
|
}),
|
|
2968
|
+
cachedContent: cachedContentSchema,
|
|
1628
2969
|
safetySettings: zod.z.array(
|
|
1629
2970
|
zod.z.strictObject({
|
|
1630
|
-
category: zod.z.
|
|
2971
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
1631
2972
|
title: "Safety Category",
|
|
1632
|
-
description: "Google safety category
|
|
2973
|
+
description: "Documented Google safety category."
|
|
1633
2974
|
}),
|
|
1634
|
-
threshold: zod.z.
|
|
2975
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
1635
2976
|
title: "Safety Threshold",
|
|
1636
|
-
description: "Google safety threshold
|
|
2977
|
+
description: "Documented Google safety threshold."
|
|
1637
2978
|
})
|
|
1638
2979
|
})
|
|
1639
2980
|
).optional().meta({
|
|
@@ -1652,9 +2993,9 @@ var Gemini25FlashLiteConfigSchema = zod.z.union([
|
|
|
1652
2993
|
description: "Allowlisted Google tools for gemini-2.5-flash-lite."
|
|
1653
2994
|
}),
|
|
1654
2995
|
httpOptions: zod.z.strictObject({
|
|
1655
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
2996
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
1656
2997
|
title: "HTTP Timeout",
|
|
1657
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
2998
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
1658
2999
|
})
|
|
1659
3000
|
}).optional().meta({
|
|
1660
3001
|
title: "HTTP Options",
|
|
@@ -1687,7 +3028,7 @@ var Gemini25FlashLiteConfigSchema = zod.z.union([
|
|
|
1687
3028
|
title: "Top K",
|
|
1688
3029
|
description: "Top-k sampling limit for gemini-2.5-flash-lite."
|
|
1689
3030
|
}),
|
|
1690
|
-
maxOutputTokens:
|
|
3031
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemini-2.5-flash-lite"]).optional().meta({
|
|
1691
3032
|
title: "Max Output Tokens",
|
|
1692
3033
|
description: "Maximum output token cap for gemini-2.5-flash-lite."
|
|
1693
3034
|
}),
|
|
@@ -1730,25 +3071,26 @@ var Gemini25FlashLiteConfigSchema = zod.z.union([
|
|
|
1730
3071
|
title: "Reasoning",
|
|
1731
3072
|
description: "Gemini 2.5 Flash-Lite thinkingBudget configuration."
|
|
1732
3073
|
}),
|
|
1733
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
3074
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
1734
3075
|
title: "Timeout",
|
|
1735
3076
|
description: "Logical request timeout in milliseconds."
|
|
1736
3077
|
}),
|
|
1737
3078
|
providerOptions: zod.z.strictObject({
|
|
1738
3079
|
google: zod.z.strictObject({
|
|
1739
|
-
|
|
1740
|
-
title: "
|
|
1741
|
-
description: "Google
|
|
3080
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
3081
|
+
title: "Require Grounding",
|
|
3082
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
1742
3083
|
}),
|
|
3084
|
+
cachedContent: cachedContentSchema,
|
|
1743
3085
|
safetySettings: zod.z.array(
|
|
1744
3086
|
zod.z.strictObject({
|
|
1745
|
-
category: zod.z.
|
|
3087
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
1746
3088
|
title: "Safety Category",
|
|
1747
|
-
description: "Google safety category
|
|
3089
|
+
description: "Documented Google safety category."
|
|
1748
3090
|
}),
|
|
1749
|
-
threshold: zod.z.
|
|
3091
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
1750
3092
|
title: "Safety Threshold",
|
|
1751
|
-
description: "Google safety threshold
|
|
3093
|
+
description: "Documented Google safety threshold."
|
|
1752
3094
|
})
|
|
1753
3095
|
})
|
|
1754
3096
|
).optional().meta({
|
|
@@ -1767,9 +3109,9 @@ var Gemini25FlashLiteConfigSchema = zod.z.union([
|
|
|
1767
3109
|
description: "Allowlisted Google tools for gemini-2.5-flash-lite."
|
|
1768
3110
|
}),
|
|
1769
3111
|
httpOptions: zod.z.strictObject({
|
|
1770
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
3112
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
1771
3113
|
title: "HTTP Timeout",
|
|
1772
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
3114
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
1773
3115
|
})
|
|
1774
3116
|
}).optional().meta({
|
|
1775
3117
|
title: "HTTP Options",
|
|
@@ -1791,7 +3133,7 @@ var Gemini25FlashLiteConfigSchema = zod.z.union([
|
|
|
1791
3133
|
});
|
|
1792
3134
|
var Gemini31FlashLiteConfigSchema = zod.z.union([
|
|
1793
3135
|
zod.z.strictObject({
|
|
1794
|
-
maxOutputTokens:
|
|
3136
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemini-3.1-flash-lite"]).optional().meta({
|
|
1795
3137
|
title: "Max Output Tokens",
|
|
1796
3138
|
description: "Maximum output token cap for gemini-3.1-flash-lite."
|
|
1797
3139
|
}),
|
|
@@ -1824,25 +3166,30 @@ var Gemini31FlashLiteConfigSchema = zod.z.union([
|
|
|
1824
3166
|
title: "Reasoning",
|
|
1825
3167
|
description: "Gemini 3.1 Flash-Lite thinkingLevel configuration."
|
|
1826
3168
|
}),
|
|
1827
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
3169
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
1828
3170
|
title: "Timeout",
|
|
1829
3171
|
description: "Logical request timeout in milliseconds."
|
|
1830
3172
|
}),
|
|
1831
3173
|
providerOptions: zod.z.strictObject({
|
|
1832
3174
|
google: zod.z.strictObject({
|
|
1833
|
-
|
|
1834
|
-
title: "
|
|
1835
|
-
description: "
|
|
3175
|
+
allowSchemaWithSearch: zod.z.boolean().optional().meta({
|
|
3176
|
+
title: "Allow Schema With Search",
|
|
3177
|
+
description: "Admit googleSearch together with a response schema. Turns requireGrounding on unless it is false."
|
|
1836
3178
|
}),
|
|
3179
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
3180
|
+
title: "Require Grounding",
|
|
3181
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
3182
|
+
}),
|
|
3183
|
+
cachedContent: cachedContentSchema,
|
|
1837
3184
|
safetySettings: zod.z.array(
|
|
1838
3185
|
zod.z.strictObject({
|
|
1839
|
-
category: zod.z.
|
|
3186
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
1840
3187
|
title: "Safety Category",
|
|
1841
|
-
description: "Google safety category
|
|
3188
|
+
description: "Documented Google safety category."
|
|
1842
3189
|
}),
|
|
1843
|
-
threshold: zod.z.
|
|
3190
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
1844
3191
|
title: "Safety Threshold",
|
|
1845
|
-
description: "Google safety threshold
|
|
3192
|
+
description: "Documented Google safety threshold."
|
|
1846
3193
|
})
|
|
1847
3194
|
})
|
|
1848
3195
|
).optional().meta({
|
|
@@ -1861,9 +3208,9 @@ var Gemini31FlashLiteConfigSchema = zod.z.union([
|
|
|
1861
3208
|
description: "Allowlisted Google tools for gemini-3.1-flash-lite."
|
|
1862
3209
|
}),
|
|
1863
3210
|
httpOptions: zod.z.strictObject({
|
|
1864
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
3211
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
1865
3212
|
title: "HTTP Timeout",
|
|
1866
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
3213
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
1867
3214
|
})
|
|
1868
3215
|
}).optional().meta({
|
|
1869
3216
|
title: "HTTP Options",
|
|
@@ -1883,7 +3230,7 @@ var Gemini31FlashLiteConfigSchema = zod.z.union([
|
|
|
1883
3230
|
})
|
|
1884
3231
|
}),
|
|
1885
3232
|
zod.z.strictObject({
|
|
1886
|
-
maxOutputTokens:
|
|
3233
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemini-3.1-flash-lite"]).optional().meta({
|
|
1887
3234
|
title: "Max Output Tokens",
|
|
1888
3235
|
description: "Maximum output token cap for gemini-3.1-flash-lite."
|
|
1889
3236
|
}),
|
|
@@ -1916,25 +3263,30 @@ var Gemini31FlashLiteConfigSchema = zod.z.union([
|
|
|
1916
3263
|
title: "Reasoning",
|
|
1917
3264
|
description: "Gemini 3.1 Flash-Lite thinkingLevel configuration."
|
|
1918
3265
|
}),
|
|
1919
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
3266
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
1920
3267
|
title: "Timeout",
|
|
1921
3268
|
description: "Logical request timeout in milliseconds."
|
|
1922
3269
|
}),
|
|
1923
3270
|
providerOptions: zod.z.strictObject({
|
|
1924
3271
|
google: zod.z.strictObject({
|
|
1925
|
-
|
|
1926
|
-
title: "
|
|
1927
|
-
description: "
|
|
3272
|
+
allowSchemaWithSearch: zod.z.boolean().optional().meta({
|
|
3273
|
+
title: "Allow Schema With Search",
|
|
3274
|
+
description: "Admit googleSearch together with a response schema. Turns requireGrounding on unless it is false."
|
|
3275
|
+
}),
|
|
3276
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
3277
|
+
title: "Require Grounding",
|
|
3278
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
1928
3279
|
}),
|
|
3280
|
+
cachedContent: cachedContentSchema,
|
|
1929
3281
|
safetySettings: zod.z.array(
|
|
1930
3282
|
zod.z.strictObject({
|
|
1931
|
-
category: zod.z.
|
|
3283
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
1932
3284
|
title: "Safety Category",
|
|
1933
|
-
description: "Google safety category
|
|
3285
|
+
description: "Documented Google safety category."
|
|
1934
3286
|
}),
|
|
1935
|
-
threshold: zod.z.
|
|
3287
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
1936
3288
|
title: "Safety Threshold",
|
|
1937
|
-
description: "Google safety threshold
|
|
3289
|
+
description: "Documented Google safety threshold."
|
|
1938
3290
|
})
|
|
1939
3291
|
})
|
|
1940
3292
|
).optional().meta({
|
|
@@ -1953,9 +3305,9 @@ var Gemini31FlashLiteConfigSchema = zod.z.union([
|
|
|
1953
3305
|
description: "Allowlisted Google tools for gemini-3.1-flash-lite."
|
|
1954
3306
|
}),
|
|
1955
3307
|
httpOptions: zod.z.strictObject({
|
|
1956
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
3308
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
1957
3309
|
title: "HTTP Timeout",
|
|
1958
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
3310
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
1959
3311
|
})
|
|
1960
3312
|
}).optional().meta({
|
|
1961
3313
|
title: "HTTP Options",
|
|
@@ -1977,7 +3329,9 @@ var Gemini31FlashLiteConfigSchema = zod.z.union([
|
|
|
1977
3329
|
});
|
|
1978
3330
|
var Gemini31ProPreviewConfigSchema = zod.z.union([
|
|
1979
3331
|
zod.z.strictObject({
|
|
1980
|
-
maxOutputTokens:
|
|
3332
|
+
maxOutputTokens: core.maxOutputTokensSchema(
|
|
3333
|
+
GOOGLE_MODEL_LIMITS["gemini-3.1-pro-preview"]
|
|
3334
|
+
).optional().meta({
|
|
1981
3335
|
title: "Max Output Tokens",
|
|
1982
3336
|
description: "Maximum output token cap for gemini-3.1-pro-preview."
|
|
1983
3337
|
}),
|
|
@@ -2010,25 +3364,30 @@ var Gemini31ProPreviewConfigSchema = zod.z.union([
|
|
|
2010
3364
|
title: "Reasoning",
|
|
2011
3365
|
description: "Gemini 3.1 Pro Preview thinkingLevel configuration."
|
|
2012
3366
|
}),
|
|
2013
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
3367
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
2014
3368
|
title: "Timeout",
|
|
2015
3369
|
description: "Logical request timeout in milliseconds."
|
|
2016
3370
|
}),
|
|
2017
3371
|
providerOptions: zod.z.strictObject({
|
|
2018
3372
|
google: zod.z.strictObject({
|
|
2019
|
-
|
|
2020
|
-
title: "
|
|
2021
|
-
description: "
|
|
3373
|
+
allowSchemaWithSearch: zod.z.boolean().optional().meta({
|
|
3374
|
+
title: "Allow Schema With Search",
|
|
3375
|
+
description: "Admit googleSearch together with a response schema. Turns requireGrounding on unless it is false."
|
|
2022
3376
|
}),
|
|
3377
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
3378
|
+
title: "Require Grounding",
|
|
3379
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
3380
|
+
}),
|
|
3381
|
+
cachedContent: cachedContentSchema,
|
|
2023
3382
|
safetySettings: zod.z.array(
|
|
2024
3383
|
zod.z.strictObject({
|
|
2025
|
-
category: zod.z.
|
|
3384
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
2026
3385
|
title: "Safety Category",
|
|
2027
|
-
description: "Google safety category
|
|
3386
|
+
description: "Documented Google safety category."
|
|
2028
3387
|
}),
|
|
2029
|
-
threshold: zod.z.
|
|
3388
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
2030
3389
|
title: "Safety Threshold",
|
|
2031
|
-
description: "Google safety threshold
|
|
3390
|
+
description: "Documented Google safety threshold."
|
|
2032
3391
|
})
|
|
2033
3392
|
})
|
|
2034
3393
|
).optional().meta({
|
|
@@ -2047,9 +3406,9 @@ var Gemini31ProPreviewConfigSchema = zod.z.union([
|
|
|
2047
3406
|
description: "Allowlisted Google tools for gemini-3.1-pro-preview."
|
|
2048
3407
|
}),
|
|
2049
3408
|
httpOptions: zod.z.strictObject({
|
|
2050
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
3409
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
2051
3410
|
title: "HTTP Timeout",
|
|
2052
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
3411
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
2053
3412
|
})
|
|
2054
3413
|
}).optional().meta({
|
|
2055
3414
|
title: "HTTP Options",
|
|
@@ -2069,7 +3428,9 @@ var Gemini31ProPreviewConfigSchema = zod.z.union([
|
|
|
2069
3428
|
})
|
|
2070
3429
|
}),
|
|
2071
3430
|
zod.z.strictObject({
|
|
2072
|
-
maxOutputTokens:
|
|
3431
|
+
maxOutputTokens: core.maxOutputTokensSchema(
|
|
3432
|
+
GOOGLE_MODEL_LIMITS["gemini-3.1-pro-preview"]
|
|
3433
|
+
).optional().meta({
|
|
2073
3434
|
title: "Max Output Tokens",
|
|
2074
3435
|
description: "Maximum output token cap for gemini-3.1-pro-preview."
|
|
2075
3436
|
}),
|
|
@@ -2102,25 +3463,30 @@ var Gemini31ProPreviewConfigSchema = zod.z.union([
|
|
|
2102
3463
|
title: "Reasoning",
|
|
2103
3464
|
description: "Gemini 3.1 Pro Preview thinkingLevel configuration."
|
|
2104
3465
|
}),
|
|
2105
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
3466
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
2106
3467
|
title: "Timeout",
|
|
2107
3468
|
description: "Logical request timeout in milliseconds."
|
|
2108
3469
|
}),
|
|
2109
3470
|
providerOptions: zod.z.strictObject({
|
|
2110
3471
|
google: zod.z.strictObject({
|
|
2111
|
-
|
|
2112
|
-
title: "
|
|
2113
|
-
description: "
|
|
3472
|
+
allowSchemaWithSearch: zod.z.boolean().optional().meta({
|
|
3473
|
+
title: "Allow Schema With Search",
|
|
3474
|
+
description: "Admit googleSearch together with a response schema. Turns requireGrounding on unless it is false."
|
|
3475
|
+
}),
|
|
3476
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
3477
|
+
title: "Require Grounding",
|
|
3478
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
2114
3479
|
}),
|
|
3480
|
+
cachedContent: cachedContentSchema,
|
|
2115
3481
|
safetySettings: zod.z.array(
|
|
2116
3482
|
zod.z.strictObject({
|
|
2117
|
-
category: zod.z.
|
|
3483
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
2118
3484
|
title: "Safety Category",
|
|
2119
|
-
description: "Google safety category
|
|
3485
|
+
description: "Documented Google safety category."
|
|
2120
3486
|
}),
|
|
2121
|
-
threshold: zod.z.
|
|
3487
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
2122
3488
|
title: "Safety Threshold",
|
|
2123
|
-
description: "Google safety threshold
|
|
3489
|
+
description: "Documented Google safety threshold."
|
|
2124
3490
|
})
|
|
2125
3491
|
})
|
|
2126
3492
|
).optional().meta({
|
|
@@ -2139,9 +3505,9 @@ var Gemini31ProPreviewConfigSchema = zod.z.union([
|
|
|
2139
3505
|
description: "Allowlisted Google tools for gemini-3.1-pro-preview."
|
|
2140
3506
|
}),
|
|
2141
3507
|
httpOptions: zod.z.strictObject({
|
|
2142
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
3508
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
2143
3509
|
title: "HTTP Timeout",
|
|
2144
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
3510
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
2145
3511
|
})
|
|
2146
3512
|
}).optional().meta({
|
|
2147
3513
|
title: "HTTP Options",
|
|
@@ -2163,7 +3529,7 @@ var Gemini31ProPreviewConfigSchema = zod.z.union([
|
|
|
2163
3529
|
});
|
|
2164
3530
|
var Gemini35FlashLiteConfigSchema = zod.z.union([
|
|
2165
3531
|
zod.z.strictObject({
|
|
2166
|
-
maxOutputTokens:
|
|
3532
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemini-3.5-flash-lite"]).optional().meta({
|
|
2167
3533
|
title: "Max Output Tokens",
|
|
2168
3534
|
description: "Maximum output token cap for gemini-3.5-flash-lite."
|
|
2169
3535
|
}),
|
|
@@ -2196,25 +3562,30 @@ var Gemini35FlashLiteConfigSchema = zod.z.union([
|
|
|
2196
3562
|
title: "Reasoning",
|
|
2197
3563
|
description: "Gemini 3.5 Flash-Lite thinkingLevel configuration."
|
|
2198
3564
|
}),
|
|
2199
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
3565
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
2200
3566
|
title: "Timeout",
|
|
2201
3567
|
description: "Logical request timeout in milliseconds."
|
|
2202
3568
|
}),
|
|
2203
3569
|
providerOptions: zod.z.strictObject({
|
|
2204
3570
|
google: zod.z.strictObject({
|
|
2205
|
-
|
|
2206
|
-
title: "
|
|
2207
|
-
description: "
|
|
3571
|
+
allowSchemaWithSearch: zod.z.boolean().optional().meta({
|
|
3572
|
+
title: "Allow Schema With Search",
|
|
3573
|
+
description: "Admit googleSearch together with a response schema. Turns requireGrounding on unless it is false."
|
|
2208
3574
|
}),
|
|
3575
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
3576
|
+
title: "Require Grounding",
|
|
3577
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
3578
|
+
}),
|
|
3579
|
+
cachedContent: cachedContentSchema,
|
|
2209
3580
|
safetySettings: zod.z.array(
|
|
2210
3581
|
zod.z.strictObject({
|
|
2211
|
-
category: zod.z.
|
|
3582
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
2212
3583
|
title: "Safety Category",
|
|
2213
|
-
description: "Google safety category
|
|
3584
|
+
description: "Documented Google safety category."
|
|
2214
3585
|
}),
|
|
2215
|
-
threshold: zod.z.
|
|
3586
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
2216
3587
|
title: "Safety Threshold",
|
|
2217
|
-
description: "Google safety threshold
|
|
3588
|
+
description: "Documented Google safety threshold."
|
|
2218
3589
|
})
|
|
2219
3590
|
})
|
|
2220
3591
|
).optional().meta({
|
|
@@ -2233,9 +3604,9 @@ var Gemini35FlashLiteConfigSchema = zod.z.union([
|
|
|
2233
3604
|
description: "Allowlisted Google tools for gemini-3.5-flash-lite."
|
|
2234
3605
|
}),
|
|
2235
3606
|
httpOptions: zod.z.strictObject({
|
|
2236
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
3607
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
2237
3608
|
title: "HTTP Timeout",
|
|
2238
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
3609
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
2239
3610
|
})
|
|
2240
3611
|
}).optional().meta({
|
|
2241
3612
|
title: "HTTP Options",
|
|
@@ -2255,7 +3626,7 @@ var Gemini35FlashLiteConfigSchema = zod.z.union([
|
|
|
2255
3626
|
})
|
|
2256
3627
|
}),
|
|
2257
3628
|
zod.z.strictObject({
|
|
2258
|
-
maxOutputTokens:
|
|
3629
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemini-3.5-flash-lite"]).optional().meta({
|
|
2259
3630
|
title: "Max Output Tokens",
|
|
2260
3631
|
description: "Maximum output token cap for gemini-3.5-flash-lite."
|
|
2261
3632
|
}),
|
|
@@ -2288,25 +3659,30 @@ var Gemini35FlashLiteConfigSchema = zod.z.union([
|
|
|
2288
3659
|
title: "Reasoning",
|
|
2289
3660
|
description: "Gemini 3.5 Flash-Lite thinkingLevel configuration."
|
|
2290
3661
|
}),
|
|
2291
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
3662
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
2292
3663
|
title: "Timeout",
|
|
2293
3664
|
description: "Logical request timeout in milliseconds."
|
|
2294
3665
|
}),
|
|
2295
3666
|
providerOptions: zod.z.strictObject({
|
|
2296
3667
|
google: zod.z.strictObject({
|
|
2297
|
-
|
|
2298
|
-
title: "
|
|
2299
|
-
description: "
|
|
3668
|
+
allowSchemaWithSearch: zod.z.boolean().optional().meta({
|
|
3669
|
+
title: "Allow Schema With Search",
|
|
3670
|
+
description: "Admit googleSearch together with a response schema. Turns requireGrounding on unless it is false."
|
|
3671
|
+
}),
|
|
3672
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
3673
|
+
title: "Require Grounding",
|
|
3674
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
2300
3675
|
}),
|
|
3676
|
+
cachedContent: cachedContentSchema,
|
|
2301
3677
|
safetySettings: zod.z.array(
|
|
2302
3678
|
zod.z.strictObject({
|
|
2303
|
-
category: zod.z.
|
|
3679
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
2304
3680
|
title: "Safety Category",
|
|
2305
|
-
description: "Google safety category
|
|
3681
|
+
description: "Documented Google safety category."
|
|
2306
3682
|
}),
|
|
2307
|
-
threshold: zod.z.
|
|
3683
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
2308
3684
|
title: "Safety Threshold",
|
|
2309
|
-
description: "Google safety threshold
|
|
3685
|
+
description: "Documented Google safety threshold."
|
|
2310
3686
|
})
|
|
2311
3687
|
})
|
|
2312
3688
|
).optional().meta({
|
|
@@ -2325,9 +3701,9 @@ var Gemini35FlashLiteConfigSchema = zod.z.union([
|
|
|
2325
3701
|
description: "Allowlisted Google tools for gemini-3.5-flash-lite."
|
|
2326
3702
|
}),
|
|
2327
3703
|
httpOptions: zod.z.strictObject({
|
|
2328
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
3704
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
2329
3705
|
title: "HTTP Timeout",
|
|
2330
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
3706
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
2331
3707
|
})
|
|
2332
3708
|
}).optional().meta({
|
|
2333
3709
|
title: "HTTP Options",
|
|
@@ -2349,7 +3725,7 @@ var Gemini35FlashLiteConfigSchema = zod.z.union([
|
|
|
2349
3725
|
});
|
|
2350
3726
|
var Gemini36FlashConfigSchema = zod.z.union([
|
|
2351
3727
|
zod.z.strictObject({
|
|
2352
|
-
maxOutputTokens:
|
|
3728
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemini-3.6-flash"]).optional().meta({
|
|
2353
3729
|
title: "Max Output Tokens",
|
|
2354
3730
|
description: "Maximum output token cap for gemini-3.6-flash."
|
|
2355
3731
|
}),
|
|
@@ -2382,25 +3758,30 @@ var Gemini36FlashConfigSchema = zod.z.union([
|
|
|
2382
3758
|
title: "Reasoning",
|
|
2383
3759
|
description: "Gemini 3.6 Flash thinkingLevel configuration."
|
|
2384
3760
|
}),
|
|
2385
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
3761
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
2386
3762
|
title: "Timeout",
|
|
2387
3763
|
description: "Logical request timeout in milliseconds."
|
|
2388
3764
|
}),
|
|
2389
3765
|
providerOptions: zod.z.strictObject({
|
|
2390
3766
|
google: zod.z.strictObject({
|
|
2391
|
-
|
|
2392
|
-
title: "
|
|
2393
|
-
description: "
|
|
3767
|
+
allowSchemaWithSearch: zod.z.boolean().optional().meta({
|
|
3768
|
+
title: "Allow Schema With Search",
|
|
3769
|
+
description: "Admit googleSearch together with a response schema. Turns requireGrounding on unless it is false."
|
|
2394
3770
|
}),
|
|
3771
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
3772
|
+
title: "Require Grounding",
|
|
3773
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
3774
|
+
}),
|
|
3775
|
+
cachedContent: cachedContentSchema,
|
|
2395
3776
|
safetySettings: zod.z.array(
|
|
2396
3777
|
zod.z.strictObject({
|
|
2397
|
-
category: zod.z.
|
|
3778
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
2398
3779
|
title: "Safety Category",
|
|
2399
|
-
description: "Google safety category
|
|
3780
|
+
description: "Documented Google safety category."
|
|
2400
3781
|
}),
|
|
2401
|
-
threshold: zod.z.
|
|
3782
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
2402
3783
|
title: "Safety Threshold",
|
|
2403
|
-
description: "Google safety threshold
|
|
3784
|
+
description: "Documented Google safety threshold."
|
|
2404
3785
|
})
|
|
2405
3786
|
})
|
|
2406
3787
|
).optional().meta({
|
|
@@ -2419,9 +3800,9 @@ var Gemini36FlashConfigSchema = zod.z.union([
|
|
|
2419
3800
|
description: "Allowlisted Google tools for gemini-3.6-flash."
|
|
2420
3801
|
}),
|
|
2421
3802
|
httpOptions: zod.z.strictObject({
|
|
2422
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
3803
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
2423
3804
|
title: "HTTP Timeout",
|
|
2424
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
3805
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
2425
3806
|
})
|
|
2426
3807
|
}).optional().meta({
|
|
2427
3808
|
title: "HTTP Options",
|
|
@@ -2441,7 +3822,7 @@ var Gemini36FlashConfigSchema = zod.z.union([
|
|
|
2441
3822
|
})
|
|
2442
3823
|
}),
|
|
2443
3824
|
zod.z.strictObject({
|
|
2444
|
-
maxOutputTokens:
|
|
3825
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemini-3.6-flash"]).optional().meta({
|
|
2445
3826
|
title: "Max Output Tokens",
|
|
2446
3827
|
description: "Maximum output token cap for gemini-3.6-flash."
|
|
2447
3828
|
}),
|
|
@@ -2474,25 +3855,30 @@ var Gemini36FlashConfigSchema = zod.z.union([
|
|
|
2474
3855
|
title: "Reasoning",
|
|
2475
3856
|
description: "Gemini 3.6 Flash thinkingLevel configuration."
|
|
2476
3857
|
}),
|
|
2477
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
3858
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
2478
3859
|
title: "Timeout",
|
|
2479
3860
|
description: "Logical request timeout in milliseconds."
|
|
2480
3861
|
}),
|
|
2481
3862
|
providerOptions: zod.z.strictObject({
|
|
2482
3863
|
google: zod.z.strictObject({
|
|
2483
|
-
|
|
2484
|
-
title: "
|
|
2485
|
-
description: "
|
|
3864
|
+
allowSchemaWithSearch: zod.z.boolean().optional().meta({
|
|
3865
|
+
title: "Allow Schema With Search",
|
|
3866
|
+
description: "Admit googleSearch together with a response schema. Turns requireGrounding on unless it is false."
|
|
3867
|
+
}),
|
|
3868
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
3869
|
+
title: "Require Grounding",
|
|
3870
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
2486
3871
|
}),
|
|
3872
|
+
cachedContent: cachedContentSchema,
|
|
2487
3873
|
safetySettings: zod.z.array(
|
|
2488
3874
|
zod.z.strictObject({
|
|
2489
|
-
category: zod.z.
|
|
3875
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
2490
3876
|
title: "Safety Category",
|
|
2491
|
-
description: "Google safety category
|
|
3877
|
+
description: "Documented Google safety category."
|
|
2492
3878
|
}),
|
|
2493
|
-
threshold: zod.z.
|
|
3879
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
2494
3880
|
title: "Safety Threshold",
|
|
2495
|
-
description: "Google safety threshold
|
|
3881
|
+
description: "Documented Google safety threshold."
|
|
2496
3882
|
})
|
|
2497
3883
|
})
|
|
2498
3884
|
).optional().meta({
|
|
@@ -2511,9 +3897,9 @@ var Gemini36FlashConfigSchema = zod.z.union([
|
|
|
2511
3897
|
description: "Allowlisted Google tools for gemini-3.6-flash."
|
|
2512
3898
|
}),
|
|
2513
3899
|
httpOptions: zod.z.strictObject({
|
|
2514
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
3900
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
2515
3901
|
title: "HTTP Timeout",
|
|
2516
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
3902
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
2517
3903
|
})
|
|
2518
3904
|
}).optional().meta({
|
|
2519
3905
|
title: "HTTP Options",
|
|
@@ -2535,7 +3921,7 @@ var Gemini36FlashConfigSchema = zod.z.union([
|
|
|
2535
3921
|
});
|
|
2536
3922
|
var Gemini37FlashConfigSchema = zod.z.union([
|
|
2537
3923
|
zod.z.strictObject({
|
|
2538
|
-
maxOutputTokens:
|
|
3924
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemini-3.7-flash"]).optional().meta({
|
|
2539
3925
|
title: "Max Output Tokens",
|
|
2540
3926
|
description: "Maximum output token cap for gemini-3.7-flash."
|
|
2541
3927
|
}),
|
|
@@ -2568,25 +3954,30 @@ var Gemini37FlashConfigSchema = zod.z.union([
|
|
|
2568
3954
|
title: "Reasoning",
|
|
2569
3955
|
description: "Gemini 3.7 Flash thinkingLevel configuration."
|
|
2570
3956
|
}),
|
|
2571
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
3957
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
2572
3958
|
title: "Timeout",
|
|
2573
3959
|
description: "Logical request timeout in milliseconds."
|
|
2574
3960
|
}),
|
|
2575
3961
|
providerOptions: zod.z.strictObject({
|
|
2576
3962
|
google: zod.z.strictObject({
|
|
2577
|
-
|
|
2578
|
-
title: "
|
|
2579
|
-
description: "
|
|
3963
|
+
allowSchemaWithSearch: zod.z.boolean().optional().meta({
|
|
3964
|
+
title: "Allow Schema With Search",
|
|
3965
|
+
description: "Admit googleSearch together with a response schema. Turns requireGrounding on unless it is false."
|
|
2580
3966
|
}),
|
|
3967
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
3968
|
+
title: "Require Grounding",
|
|
3969
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
3970
|
+
}),
|
|
3971
|
+
cachedContent: cachedContentSchema,
|
|
2581
3972
|
safetySettings: zod.z.array(
|
|
2582
3973
|
zod.z.strictObject({
|
|
2583
|
-
category: zod.z.
|
|
3974
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
2584
3975
|
title: "Safety Category",
|
|
2585
|
-
description: "Google safety category
|
|
3976
|
+
description: "Documented Google safety category."
|
|
2586
3977
|
}),
|
|
2587
|
-
threshold: zod.z.
|
|
3978
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
2588
3979
|
title: "Safety Threshold",
|
|
2589
|
-
description: "Google safety threshold
|
|
3980
|
+
description: "Documented Google safety threshold."
|
|
2590
3981
|
})
|
|
2591
3982
|
})
|
|
2592
3983
|
).optional().meta({
|
|
@@ -2605,9 +3996,9 @@ var Gemini37FlashConfigSchema = zod.z.union([
|
|
|
2605
3996
|
description: "Allowlisted Google tools for gemini-3.7-flash."
|
|
2606
3997
|
}),
|
|
2607
3998
|
httpOptions: zod.z.strictObject({
|
|
2608
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
3999
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
2609
4000
|
title: "HTTP Timeout",
|
|
2610
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
4001
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
2611
4002
|
})
|
|
2612
4003
|
}).optional().meta({
|
|
2613
4004
|
title: "HTTP Options",
|
|
@@ -2627,7 +4018,7 @@ var Gemini37FlashConfigSchema = zod.z.union([
|
|
|
2627
4018
|
})
|
|
2628
4019
|
}),
|
|
2629
4020
|
zod.z.strictObject({
|
|
2630
|
-
maxOutputTokens:
|
|
4021
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemini-3.7-flash"]).optional().meta({
|
|
2631
4022
|
title: "Max Output Tokens",
|
|
2632
4023
|
description: "Maximum output token cap for gemini-3.7-flash."
|
|
2633
4024
|
}),
|
|
@@ -2660,25 +4051,30 @@ var Gemini37FlashConfigSchema = zod.z.union([
|
|
|
2660
4051
|
title: "Reasoning",
|
|
2661
4052
|
description: "Gemini 3.7 Flash thinkingLevel configuration."
|
|
2662
4053
|
}),
|
|
2663
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
4054
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
2664
4055
|
title: "Timeout",
|
|
2665
4056
|
description: "Logical request timeout in milliseconds."
|
|
2666
4057
|
}),
|
|
2667
4058
|
providerOptions: zod.z.strictObject({
|
|
2668
4059
|
google: zod.z.strictObject({
|
|
2669
|
-
|
|
2670
|
-
title: "
|
|
2671
|
-
description: "
|
|
4060
|
+
allowSchemaWithSearch: zod.z.boolean().optional().meta({
|
|
4061
|
+
title: "Allow Schema With Search",
|
|
4062
|
+
description: "Admit googleSearch together with a response schema. Turns requireGrounding on unless it is false."
|
|
4063
|
+
}),
|
|
4064
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
4065
|
+
title: "Require Grounding",
|
|
4066
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
2672
4067
|
}),
|
|
4068
|
+
cachedContent: cachedContentSchema,
|
|
2673
4069
|
safetySettings: zod.z.array(
|
|
2674
4070
|
zod.z.strictObject({
|
|
2675
|
-
category: zod.z.
|
|
4071
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
2676
4072
|
title: "Safety Category",
|
|
2677
|
-
description: "Google safety category
|
|
4073
|
+
description: "Documented Google safety category."
|
|
2678
4074
|
}),
|
|
2679
|
-
threshold: zod.z.
|
|
4075
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
2680
4076
|
title: "Safety Threshold",
|
|
2681
|
-
description: "Google safety threshold
|
|
4077
|
+
description: "Documented Google safety threshold."
|
|
2682
4078
|
})
|
|
2683
4079
|
})
|
|
2684
4080
|
).optional().meta({
|
|
@@ -2697,9 +4093,9 @@ var Gemini37FlashConfigSchema = zod.z.union([
|
|
|
2697
4093
|
description: "Allowlisted Google tools for gemini-3.7-flash."
|
|
2698
4094
|
}),
|
|
2699
4095
|
httpOptions: zod.z.strictObject({
|
|
2700
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
4096
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
2701
4097
|
title: "HTTP Timeout",
|
|
2702
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
4098
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
2703
4099
|
})
|
|
2704
4100
|
}).optional().meta({
|
|
2705
4101
|
title: "HTTP Options",
|
|
@@ -2721,7 +4117,7 @@ var Gemini37FlashConfigSchema = zod.z.union([
|
|
|
2721
4117
|
});
|
|
2722
4118
|
var Gemini38FlashConfigSchema = zod.z.union([
|
|
2723
4119
|
zod.z.strictObject({
|
|
2724
|
-
maxOutputTokens:
|
|
4120
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemini-3.8-flash"]).optional().meta({
|
|
2725
4121
|
title: "Max Output Tokens",
|
|
2726
4122
|
description: "Maximum output token cap for gemini-3.8-flash."
|
|
2727
4123
|
}),
|
|
@@ -2754,25 +4150,30 @@ var Gemini38FlashConfigSchema = zod.z.union([
|
|
|
2754
4150
|
title: "Reasoning",
|
|
2755
4151
|
description: "Gemini 3.8 Flash thinkingLevel configuration."
|
|
2756
4152
|
}),
|
|
2757
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
4153
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
2758
4154
|
title: "Timeout",
|
|
2759
4155
|
description: "Logical request timeout in milliseconds."
|
|
2760
4156
|
}),
|
|
2761
4157
|
providerOptions: zod.z.strictObject({
|
|
2762
4158
|
google: zod.z.strictObject({
|
|
2763
|
-
|
|
2764
|
-
title: "
|
|
2765
|
-
description: "
|
|
4159
|
+
allowSchemaWithSearch: zod.z.boolean().optional().meta({
|
|
4160
|
+
title: "Allow Schema With Search",
|
|
4161
|
+
description: "Admit googleSearch together with a response schema. Turns requireGrounding on unless it is false."
|
|
2766
4162
|
}),
|
|
4163
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
4164
|
+
title: "Require Grounding",
|
|
4165
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
4166
|
+
}),
|
|
4167
|
+
cachedContent: cachedContentSchema,
|
|
2767
4168
|
safetySettings: zod.z.array(
|
|
2768
4169
|
zod.z.strictObject({
|
|
2769
|
-
category: zod.z.
|
|
4170
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
2770
4171
|
title: "Safety Category",
|
|
2771
|
-
description: "Google safety category
|
|
4172
|
+
description: "Documented Google safety category."
|
|
2772
4173
|
}),
|
|
2773
|
-
threshold: zod.z.
|
|
4174
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
2774
4175
|
title: "Safety Threshold",
|
|
2775
|
-
description: "Google safety threshold
|
|
4176
|
+
description: "Documented Google safety threshold."
|
|
2776
4177
|
})
|
|
2777
4178
|
})
|
|
2778
4179
|
).optional().meta({
|
|
@@ -2791,9 +4192,9 @@ var Gemini38FlashConfigSchema = zod.z.union([
|
|
|
2791
4192
|
description: "Allowlisted Google tools for gemini-3.8-flash."
|
|
2792
4193
|
}),
|
|
2793
4194
|
httpOptions: zod.z.strictObject({
|
|
2794
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
4195
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
2795
4196
|
title: "HTTP Timeout",
|
|
2796
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
4197
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
2797
4198
|
})
|
|
2798
4199
|
}).optional().meta({
|
|
2799
4200
|
title: "HTTP Options",
|
|
@@ -2813,7 +4214,7 @@ var Gemini38FlashConfigSchema = zod.z.union([
|
|
|
2813
4214
|
})
|
|
2814
4215
|
}),
|
|
2815
4216
|
zod.z.strictObject({
|
|
2816
|
-
maxOutputTokens:
|
|
4217
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemini-3.8-flash"]).optional().meta({
|
|
2817
4218
|
title: "Max Output Tokens",
|
|
2818
4219
|
description: "Maximum output token cap for gemini-3.8-flash."
|
|
2819
4220
|
}),
|
|
@@ -2846,25 +4247,30 @@ var Gemini38FlashConfigSchema = zod.z.union([
|
|
|
2846
4247
|
title: "Reasoning",
|
|
2847
4248
|
description: "Gemini 3.8 Flash thinkingLevel configuration."
|
|
2848
4249
|
}),
|
|
2849
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
4250
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
2850
4251
|
title: "Timeout",
|
|
2851
4252
|
description: "Logical request timeout in milliseconds."
|
|
2852
4253
|
}),
|
|
2853
4254
|
providerOptions: zod.z.strictObject({
|
|
2854
4255
|
google: zod.z.strictObject({
|
|
2855
|
-
|
|
2856
|
-
title: "
|
|
2857
|
-
description: "
|
|
4256
|
+
allowSchemaWithSearch: zod.z.boolean().optional().meta({
|
|
4257
|
+
title: "Allow Schema With Search",
|
|
4258
|
+
description: "Admit googleSearch together with a response schema. Turns requireGrounding on unless it is false."
|
|
4259
|
+
}),
|
|
4260
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
4261
|
+
title: "Require Grounding",
|
|
4262
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
2858
4263
|
}),
|
|
4264
|
+
cachedContent: cachedContentSchema,
|
|
2859
4265
|
safetySettings: zod.z.array(
|
|
2860
4266
|
zod.z.strictObject({
|
|
2861
|
-
category: zod.z.
|
|
4267
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
2862
4268
|
title: "Safety Category",
|
|
2863
|
-
description: "Google safety category
|
|
4269
|
+
description: "Documented Google safety category."
|
|
2864
4270
|
}),
|
|
2865
|
-
threshold: zod.z.
|
|
4271
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
2866
4272
|
title: "Safety Threshold",
|
|
2867
|
-
description: "Google safety threshold
|
|
4273
|
+
description: "Documented Google safety threshold."
|
|
2868
4274
|
})
|
|
2869
4275
|
})
|
|
2870
4276
|
).optional().meta({
|
|
@@ -2883,9 +4289,9 @@ var Gemini38FlashConfigSchema = zod.z.union([
|
|
|
2883
4289
|
description: "Allowlisted Google tools for gemini-3.8-flash."
|
|
2884
4290
|
}),
|
|
2885
4291
|
httpOptions: zod.z.strictObject({
|
|
2886
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
4292
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
2887
4293
|
title: "HTTP Timeout",
|
|
2888
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
4294
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
2889
4295
|
})
|
|
2890
4296
|
}).optional().meta({
|
|
2891
4297
|
title: "HTTP Options",
|
|
@@ -2919,7 +4325,7 @@ var Gemma431bItConfigSchema = zod.z.strictObject({
|
|
|
2919
4325
|
title: "Top K",
|
|
2920
4326
|
description: "Top-k sampling limit for gemma-4-31b-it."
|
|
2921
4327
|
}),
|
|
2922
|
-
maxOutputTokens:
|
|
4328
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemma-4-31b-it"]).optional().meta({
|
|
2923
4329
|
title: "Max Output Tokens",
|
|
2924
4330
|
description: "Maximum output token cap for gemma-4-31b-it."
|
|
2925
4331
|
}),
|
|
@@ -2948,25 +4354,25 @@ var Gemma431bItConfigSchema = zod.z.strictObject({
|
|
|
2948
4354
|
title: "Reasoning",
|
|
2949
4355
|
description: "Gemma 4 31B IT thinkingLevel configuration."
|
|
2950
4356
|
}),
|
|
2951
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
4357
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
2952
4358
|
title: "Timeout",
|
|
2953
4359
|
description: "Logical request timeout in milliseconds."
|
|
2954
4360
|
}),
|
|
2955
4361
|
providerOptions: zod.z.strictObject({
|
|
2956
4362
|
google: zod.z.strictObject({
|
|
2957
|
-
|
|
2958
|
-
title: "
|
|
2959
|
-
description: "Google
|
|
4363
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
4364
|
+
title: "Require Grounding",
|
|
4365
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
2960
4366
|
}),
|
|
2961
4367
|
safetySettings: zod.z.array(
|
|
2962
4368
|
zod.z.strictObject({
|
|
2963
|
-
category: zod.z.
|
|
4369
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
2964
4370
|
title: "Safety Category",
|
|
2965
|
-
description: "Google safety category
|
|
4371
|
+
description: "Documented Google safety category."
|
|
2966
4372
|
}),
|
|
2967
|
-
threshold: zod.z.
|
|
4373
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
2968
4374
|
title: "Safety Threshold",
|
|
2969
|
-
description: "Google safety threshold
|
|
4375
|
+
description: "Documented Google safety threshold."
|
|
2970
4376
|
})
|
|
2971
4377
|
})
|
|
2972
4378
|
).optional().meta({
|
|
@@ -2985,9 +4391,9 @@ var Gemma431bItConfigSchema = zod.z.strictObject({
|
|
|
2985
4391
|
description: "Allowlisted Google tools for gemma-4-31b-it."
|
|
2986
4392
|
}),
|
|
2987
4393
|
httpOptions: zod.z.strictObject({
|
|
2988
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
4394
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
2989
4395
|
title: "HTTP Timeout",
|
|
2990
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
4396
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
2991
4397
|
})
|
|
2992
4398
|
}).optional().meta({
|
|
2993
4399
|
title: "HTTP Options",
|
|
@@ -3020,7 +4426,7 @@ var Gemma426bA4bItConfigSchema = zod.z.strictObject({
|
|
|
3020
4426
|
title: "Top K",
|
|
3021
4427
|
description: "Top-k sampling limit for gemma-4-26b-a4b-it."
|
|
3022
4428
|
}),
|
|
3023
|
-
maxOutputTokens:
|
|
4429
|
+
maxOutputTokens: core.maxOutputTokensSchema(GOOGLE_MODEL_LIMITS["gemma-4-26b-a4b-it"]).optional().meta({
|
|
3024
4430
|
title: "Max Output Tokens",
|
|
3025
4431
|
description: "Maximum output token cap for gemma-4-26b-a4b-it."
|
|
3026
4432
|
}),
|
|
@@ -3049,25 +4455,25 @@ var Gemma426bA4bItConfigSchema = zod.z.strictObject({
|
|
|
3049
4455
|
title: "Reasoning",
|
|
3050
4456
|
description: "Gemma 4 26B A4B IT thinkingLevel configuration."
|
|
3051
4457
|
}),
|
|
3052
|
-
timeoutMs: zod.z.number().int().positive().optional().meta({
|
|
4458
|
+
timeoutMs: zod.z.number().int().positive().max(GOOGLE_MAX_TIMEOUT_MS).optional().meta({
|
|
3053
4459
|
title: "Timeout",
|
|
3054
4460
|
description: "Logical request timeout in milliseconds."
|
|
3055
4461
|
}),
|
|
3056
4462
|
providerOptions: zod.z.strictObject({
|
|
3057
4463
|
google: zod.z.strictObject({
|
|
3058
|
-
|
|
3059
|
-
title: "
|
|
3060
|
-
description: "Google
|
|
4464
|
+
requireGrounding: zod.z.boolean().optional().meta({
|
|
4465
|
+
title: "Require Grounding",
|
|
4466
|
+
description: "Fail the call unless the response proves Google Search ran (grounding metadata with at least one query). Judged only on a candidate that finished with STOP: a MAX_TOKENS or other abnormal finish returns with its own finish reason, a filtered one throws content_filter. The error is retryable only when no response schema is attached."
|
|
3061
4467
|
}),
|
|
3062
4468
|
safetySettings: zod.z.array(
|
|
3063
4469
|
zod.z.strictObject({
|
|
3064
|
-
category: zod.z.
|
|
4470
|
+
category: zod.z.enum(GOOGLE_SAFETY_CATEGORIES).meta({
|
|
3065
4471
|
title: "Safety Category",
|
|
3066
|
-
description: "Google safety category
|
|
4472
|
+
description: "Documented Google safety category."
|
|
3067
4473
|
}),
|
|
3068
|
-
threshold: zod.z.
|
|
4474
|
+
threshold: zod.z.enum(GOOGLE_SAFETY_THRESHOLDS).meta({
|
|
3069
4475
|
title: "Safety Threshold",
|
|
3070
|
-
description: "Google safety threshold
|
|
4476
|
+
description: "Documented Google safety threshold."
|
|
3071
4477
|
})
|
|
3072
4478
|
})
|
|
3073
4479
|
).optional().meta({
|
|
@@ -3086,9 +4492,9 @@ var Gemma426bA4bItConfigSchema = zod.z.strictObject({
|
|
|
3086
4492
|
description: "Allowlisted Google tools for gemma-4-26b-a4b-it."
|
|
3087
4493
|
}),
|
|
3088
4494
|
httpOptions: zod.z.strictObject({
|
|
3089
|
-
timeout: zod.z.number().int().positive().optional().meta({
|
|
4495
|
+
timeout: zod.z.number().int().positive().max(MAX_TIMER_MS).optional().meta({
|
|
3090
4496
|
title: "HTTP Timeout",
|
|
3091
|
-
description: "Per-request Google transport timeout in milliseconds."
|
|
4497
|
+
description: "Per-request Google transport timeout in milliseconds, at most 2147483647; with timeoutMs set, at least timeoutMs + 5000."
|
|
3092
4498
|
})
|
|
3093
4499
|
}).optional().meta({
|
|
3094
4500
|
title: "HTTP Options",
|
|
@@ -3126,12 +4532,13 @@ var geminiModelDescriptors = [
|
|
|
3126
4532
|
{
|
|
3127
4533
|
model: "gemini-2.5-pro",
|
|
3128
4534
|
provider: "google",
|
|
4535
|
+
limits: GOOGLE_MODEL_LIMITS["gemini-2.5-pro"],
|
|
3129
4536
|
pricingFamily: "gemini-2.5-pro",
|
|
3130
4537
|
capabilities: {
|
|
4538
|
+
inputMimeTypes: GEMINI_INPUT_MIME_TYPES,
|
|
3131
4539
|
reasoning: true,
|
|
3132
4540
|
structuredOutput: true,
|
|
3133
4541
|
nativeStructuredOutput: true,
|
|
3134
|
-
vision: true,
|
|
3135
4542
|
reasoningApi: "budget",
|
|
3136
4543
|
admittedReasoningEfforts: GEMINI_STANDARD_REASONING_EFFORTS,
|
|
3137
4544
|
sampling: "tunable",
|
|
@@ -3141,18 +4548,20 @@ var geminiModelDescriptors = [
|
|
|
3141
4548
|
serviceTiers: ["flex", "standard"]
|
|
3142
4549
|
},
|
|
3143
4550
|
configSchema: Gemini25ProConfigSchema,
|
|
4551
|
+
configKeys: core.toConfigKeys(Gemini25ProConfigSchema),
|
|
3144
4552
|
configJsonSchema: core.toConfigJsonSchema(Gemini25ProConfigSchema),
|
|
3145
4553
|
validateConfig: core.zodToStandardSchema(Gemini25ProConfigSchema)
|
|
3146
4554
|
},
|
|
3147
4555
|
{
|
|
3148
4556
|
model: "gemini-2.5-flash",
|
|
3149
4557
|
provider: "google",
|
|
4558
|
+
limits: GOOGLE_MODEL_LIMITS["gemini-2.5-flash"],
|
|
3150
4559
|
pricingFamily: "gemini-2.5-flash",
|
|
3151
4560
|
capabilities: {
|
|
4561
|
+
inputMimeTypes: GEMINI_INPUT_MIME_TYPES,
|
|
3152
4562
|
reasoning: true,
|
|
3153
4563
|
structuredOutput: true,
|
|
3154
4564
|
nativeStructuredOutput: true,
|
|
3155
|
-
vision: true,
|
|
3156
4565
|
reasoningApi: "budget",
|
|
3157
4566
|
admittedReasoningEfforts: GEMINI_LEVEL_WITH_NONE_REASONING_EFFORTS,
|
|
3158
4567
|
sampling: "tunable",
|
|
@@ -3162,18 +4571,20 @@ var geminiModelDescriptors = [
|
|
|
3162
4571
|
serviceTiers: ["flex", "standard"]
|
|
3163
4572
|
},
|
|
3164
4573
|
configSchema: Gemini25FlashConfigSchema,
|
|
4574
|
+
configKeys: core.toConfigKeys(Gemini25FlashConfigSchema),
|
|
3165
4575
|
configJsonSchema: core.toConfigJsonSchema(Gemini25FlashConfigSchema),
|
|
3166
4576
|
validateConfig: core.zodToStandardSchema(Gemini25FlashConfigSchema)
|
|
3167
4577
|
},
|
|
3168
4578
|
{
|
|
3169
4579
|
model: "gemini-2.5-flash-lite",
|
|
3170
4580
|
provider: "google",
|
|
4581
|
+
limits: GOOGLE_MODEL_LIMITS["gemini-2.5-flash-lite"],
|
|
3171
4582
|
pricingFamily: "gemini-2.5-flash-lite",
|
|
3172
4583
|
capabilities: {
|
|
4584
|
+
inputMimeTypes: GEMINI_INPUT_MIME_TYPES,
|
|
3173
4585
|
reasoning: true,
|
|
3174
4586
|
structuredOutput: true,
|
|
3175
4587
|
nativeStructuredOutput: true,
|
|
3176
|
-
vision: true,
|
|
3177
4588
|
reasoningApi: "budget",
|
|
3178
4589
|
admittedReasoningEfforts: GEMINI_LEVEL_WITH_NONE_REASONING_EFFORTS,
|
|
3179
4590
|
sampling: "tunable",
|
|
@@ -3183,138 +4594,167 @@ var geminiModelDescriptors = [
|
|
|
3183
4594
|
serviceTiers: ["flex", "standard"]
|
|
3184
4595
|
},
|
|
3185
4596
|
configSchema: Gemini25FlashLiteConfigSchema,
|
|
4597
|
+
configKeys: core.toConfigKeys(Gemini25FlashLiteConfigSchema),
|
|
3186
4598
|
configJsonSchema: core.toConfigJsonSchema(Gemini25FlashLiteConfigSchema),
|
|
3187
4599
|
validateConfig: core.zodToStandardSchema(Gemini25FlashLiteConfigSchema)
|
|
3188
4600
|
},
|
|
3189
4601
|
{
|
|
3190
4602
|
model: "gemini-3.1-flash-lite",
|
|
3191
4603
|
provider: "google",
|
|
4604
|
+
// Google's deprecations page (https://ai.google.dev/gemini-api/docs/deprecations,
|
|
4605
|
+
// "Page last updated" 2026-10-01, read 2026-10-03) lists a May 7, 2027
|
|
4606
|
+
// shutdown, replacement gemini-3.5-flash-lite.
|
|
4607
|
+
shutdownDate: "2027-05-07",
|
|
4608
|
+
limits: GOOGLE_MODEL_LIMITS["gemini-3.1-flash-lite"],
|
|
3192
4609
|
pricingFamily: "gemini-3.1-flash-lite",
|
|
3193
4610
|
capabilities: {
|
|
4611
|
+
inputMimeTypes: GEMINI_INPUT_MIME_TYPES,
|
|
3194
4612
|
reasoning: true,
|
|
3195
4613
|
structuredOutput: true,
|
|
3196
4614
|
nativeStructuredOutput: true,
|
|
3197
|
-
vision: true,
|
|
3198
4615
|
reasoningApi: "level",
|
|
3199
4616
|
admittedReasoningEfforts: GEMINI_LEVEL_WITH_NONE_REASONING_EFFORTS,
|
|
3200
4617
|
sampling: "fixed",
|
|
3201
4618
|
caching: { explicit: true, minTokens: 1024 },
|
|
3202
4619
|
grounding: true,
|
|
3203
4620
|
functionCalling: true,
|
|
3204
|
-
structuredOutputWithTools:
|
|
4621
|
+
structuredOutputWithTools: false,
|
|
4622
|
+
continuation: "history",
|
|
4623
|
+
providerState: true,
|
|
3205
4624
|
serviceTiers: ["flex", "standard"]
|
|
3206
4625
|
},
|
|
3207
4626
|
configSchema: Gemini31FlashLiteConfigSchema,
|
|
4627
|
+
configKeys: core.toConfigKeys(Gemini31FlashLiteConfigSchema),
|
|
3208
4628
|
configJsonSchema: core.toConfigJsonSchema(Gemini31FlashLiteConfigSchema),
|
|
3209
4629
|
validateConfig: core.zodToStandardSchema(Gemini31FlashLiteConfigSchema)
|
|
3210
4630
|
},
|
|
3211
4631
|
{
|
|
3212
4632
|
model: "gemini-3.1-pro-preview",
|
|
3213
4633
|
provider: "google",
|
|
4634
|
+
limits: GOOGLE_MODEL_LIMITS["gemini-3.1-pro-preview"],
|
|
3214
4635
|
pricingFamily: "gemini-3.1-pro-preview",
|
|
3215
4636
|
capabilities: {
|
|
4637
|
+
inputMimeTypes: GEMINI_INPUT_MIME_TYPES,
|
|
3216
4638
|
reasoning: true,
|
|
3217
4639
|
structuredOutput: true,
|
|
3218
4640
|
nativeStructuredOutput: true,
|
|
3219
|
-
vision: true,
|
|
3220
4641
|
reasoningApi: "level",
|
|
3221
4642
|
admittedReasoningEfforts: GEMINI_STANDARD_REASONING_EFFORTS,
|
|
3222
4643
|
sampling: "fixed",
|
|
3223
4644
|
caching: { explicit: true, minTokens: 1024 },
|
|
3224
4645
|
grounding: true,
|
|
3225
4646
|
functionCalling: true,
|
|
3226
|
-
structuredOutputWithTools:
|
|
4647
|
+
structuredOutputWithTools: false,
|
|
4648
|
+
continuation: "history",
|
|
4649
|
+
providerState: true,
|
|
3227
4650
|
serviceTiers: ["flex", "standard"]
|
|
3228
4651
|
},
|
|
3229
4652
|
configSchema: Gemini31ProPreviewConfigSchema,
|
|
4653
|
+
configKeys: core.toConfigKeys(Gemini31ProPreviewConfigSchema),
|
|
3230
4654
|
configJsonSchema: core.toConfigJsonSchema(Gemini31ProPreviewConfigSchema),
|
|
3231
4655
|
validateConfig: core.zodToStandardSchema(Gemini31ProPreviewConfigSchema)
|
|
3232
4656
|
},
|
|
3233
4657
|
{
|
|
3234
4658
|
model: "gemini-3.8-flash",
|
|
3235
4659
|
provider: "google",
|
|
4660
|
+
limits: GOOGLE_MODEL_LIMITS["gemini-3.8-flash"],
|
|
3236
4661
|
pricingFamily: "gemini-3.8-flash",
|
|
3237
4662
|
capabilities: {
|
|
4663
|
+
inputMimeTypes: GEMINI_INPUT_MIME_TYPES,
|
|
3238
4664
|
reasoning: true,
|
|
3239
4665
|
structuredOutput: true,
|
|
3240
4666
|
nativeStructuredOutput: true,
|
|
3241
|
-
vision: true,
|
|
3242
4667
|
reasoningApi: "level",
|
|
3243
4668
|
admittedReasoningEfforts: GEMINI_STANDARD_REASONING_EFFORTS,
|
|
3244
4669
|
sampling: "fixed",
|
|
3245
4670
|
caching: { explicit: true, minTokens: 1024 },
|
|
3246
4671
|
grounding: true,
|
|
3247
4672
|
functionCalling: true,
|
|
3248
|
-
structuredOutputWithTools:
|
|
4673
|
+
structuredOutputWithTools: false,
|
|
4674
|
+
continuation: "history",
|
|
4675
|
+
providerState: true,
|
|
3249
4676
|
serviceTiers: ["flex", "standard"]
|
|
3250
4677
|
},
|
|
3251
4678
|
configSchema: Gemini38FlashConfigSchema,
|
|
4679
|
+
configKeys: core.toConfigKeys(Gemini38FlashConfigSchema),
|
|
3252
4680
|
configJsonSchema: core.toConfigJsonSchema(Gemini38FlashConfigSchema),
|
|
3253
4681
|
validateConfig: core.zodToStandardSchema(Gemini38FlashConfigSchema)
|
|
3254
4682
|
},
|
|
3255
4683
|
{
|
|
3256
4684
|
model: "gemini-3.7-flash",
|
|
3257
4685
|
provider: "google",
|
|
4686
|
+
limits: GOOGLE_MODEL_LIMITS["gemini-3.7-flash"],
|
|
3258
4687
|
pricingFamily: "gemini-3.7-flash",
|
|
3259
4688
|
capabilities: {
|
|
4689
|
+
inputMimeTypes: GEMINI_INPUT_MIME_TYPES,
|
|
3260
4690
|
reasoning: true,
|
|
3261
4691
|
structuredOutput: true,
|
|
3262
4692
|
nativeStructuredOutput: true,
|
|
3263
|
-
vision: true,
|
|
3264
4693
|
reasoningApi: "level",
|
|
3265
4694
|
admittedReasoningEfforts: GEMINI_STANDARD_REASONING_EFFORTS,
|
|
3266
4695
|
sampling: "fixed",
|
|
3267
4696
|
caching: { explicit: true, minTokens: 1024 },
|
|
3268
4697
|
grounding: true,
|
|
3269
4698
|
functionCalling: true,
|
|
3270
|
-
structuredOutputWithTools:
|
|
4699
|
+
structuredOutputWithTools: false,
|
|
4700
|
+
continuation: "history",
|
|
4701
|
+
providerState: true,
|
|
3271
4702
|
serviceTiers: ["flex", "standard"]
|
|
3272
4703
|
},
|
|
3273
4704
|
configSchema: Gemini37FlashConfigSchema,
|
|
4705
|
+
configKeys: core.toConfigKeys(Gemini37FlashConfigSchema),
|
|
3274
4706
|
configJsonSchema: core.toConfigJsonSchema(Gemini37FlashConfigSchema),
|
|
3275
4707
|
validateConfig: core.zodToStandardSchema(Gemini37FlashConfigSchema)
|
|
3276
4708
|
},
|
|
3277
4709
|
{
|
|
3278
4710
|
model: "gemini-3.6-flash",
|
|
3279
4711
|
provider: "google",
|
|
4712
|
+
limits: GOOGLE_MODEL_LIMITS["gemini-3.6-flash"],
|
|
3280
4713
|
pricingFamily: "gemini-3.6-flash",
|
|
3281
4714
|
capabilities: {
|
|
4715
|
+
inputMimeTypes: GEMINI_INPUT_MIME_TYPES,
|
|
3282
4716
|
reasoning: true,
|
|
3283
4717
|
structuredOutput: true,
|
|
3284
4718
|
nativeStructuredOutput: true,
|
|
3285
|
-
vision: true,
|
|
3286
4719
|
reasoningApi: "level",
|
|
3287
4720
|
admittedReasoningEfforts: GEMINI_LEVEL_WITH_NONE_REASONING_EFFORTS,
|
|
3288
4721
|
sampling: "fixed",
|
|
3289
4722
|
caching: { explicit: true, minTokens: 1024 },
|
|
3290
4723
|
grounding: true,
|
|
3291
4724
|
functionCalling: true,
|
|
3292
|
-
structuredOutputWithTools:
|
|
4725
|
+
structuredOutputWithTools: false,
|
|
4726
|
+
continuation: "history",
|
|
4727
|
+
providerState: true,
|
|
3293
4728
|
serviceTiers: ["flex", "standard"]
|
|
3294
4729
|
},
|
|
3295
4730
|
configSchema: Gemini36FlashConfigSchema,
|
|
4731
|
+
configKeys: core.toConfigKeys(Gemini36FlashConfigSchema),
|
|
3296
4732
|
configJsonSchema: core.toConfigJsonSchema(Gemini36FlashConfigSchema),
|
|
3297
4733
|
validateConfig: core.zodToStandardSchema(Gemini36FlashConfigSchema)
|
|
3298
4734
|
},
|
|
3299
4735
|
{
|
|
3300
4736
|
model: "gemini-3.5-flash-lite",
|
|
3301
4737
|
provider: "google",
|
|
4738
|
+
limits: GOOGLE_MODEL_LIMITS["gemini-3.5-flash-lite"],
|
|
3302
4739
|
pricingFamily: "gemini-3.5-flash-lite",
|
|
3303
4740
|
capabilities: {
|
|
4741
|
+
inputMimeTypes: GEMINI_INPUT_MIME_TYPES,
|
|
3304
4742
|
reasoning: true,
|
|
3305
4743
|
structuredOutput: true,
|
|
3306
4744
|
nativeStructuredOutput: true,
|
|
3307
|
-
vision: true,
|
|
3308
4745
|
reasoningApi: "level",
|
|
3309
4746
|
admittedReasoningEfforts: GEMINI_LEVEL_WITH_NONE_REASONING_EFFORTS,
|
|
3310
4747
|
sampling: "fixed",
|
|
3311
4748
|
caching: { explicit: true, minTokens: 1024 },
|
|
3312
4749
|
grounding: true,
|
|
3313
4750
|
functionCalling: true,
|
|
3314
|
-
structuredOutputWithTools:
|
|
4751
|
+
structuredOutputWithTools: false,
|
|
4752
|
+
continuation: "history",
|
|
4753
|
+
providerState: true,
|
|
3315
4754
|
serviceTiers: ["flex", "standard"]
|
|
3316
4755
|
},
|
|
3317
4756
|
configSchema: Gemini35FlashLiteConfigSchema,
|
|
4757
|
+
configKeys: core.toConfigKeys(Gemini35FlashLiteConfigSchema),
|
|
3318
4758
|
configJsonSchema: core.toConfigJsonSchema(Gemini35FlashLiteConfigSchema),
|
|
3319
4759
|
validateConfig: core.zodToStandardSchema(Gemini35FlashLiteConfigSchema)
|
|
3320
4760
|
}
|
|
@@ -3323,34 +4763,38 @@ var gemmaModelDescriptors = [
|
|
|
3323
4763
|
{
|
|
3324
4764
|
model: "gemma-4-31b-it",
|
|
3325
4765
|
provider: "google",
|
|
4766
|
+
limits: GOOGLE_MODEL_LIMITS["gemma-4-31b-it"],
|
|
3326
4767
|
capabilities: {
|
|
4768
|
+
inputMimeTypes: GEMMA_INPUT_MIME_TYPES,
|
|
3327
4769
|
reasoning: true,
|
|
3328
4770
|
reasoningApi: "level",
|
|
3329
4771
|
admittedReasoningEfforts: GEMMA_REASONING_EFFORTS,
|
|
3330
4772
|
structuredOutput: true,
|
|
3331
4773
|
nativeStructuredOutput: true,
|
|
3332
4774
|
grounding: true,
|
|
3333
|
-
vision: true,
|
|
3334
4775
|
sampling: "tunable"
|
|
3335
4776
|
},
|
|
3336
4777
|
configSchema: Gemma431bItConfigSchema,
|
|
4778
|
+
configKeys: core.toConfigKeys(Gemma431bItConfigSchema),
|
|
3337
4779
|
configJsonSchema: core.toConfigJsonSchema(Gemma431bItConfigSchema),
|
|
3338
4780
|
validateConfig: core.zodToStandardSchema(Gemma431bItConfigSchema)
|
|
3339
4781
|
},
|
|
3340
4782
|
{
|
|
3341
4783
|
model: "gemma-4-26b-a4b-it",
|
|
3342
4784
|
provider: "google",
|
|
4785
|
+
limits: GOOGLE_MODEL_LIMITS["gemma-4-26b-a4b-it"],
|
|
3343
4786
|
capabilities: {
|
|
4787
|
+
inputMimeTypes: GEMMA_INPUT_MIME_TYPES,
|
|
3344
4788
|
reasoning: true,
|
|
3345
4789
|
reasoningApi: "level",
|
|
3346
4790
|
admittedReasoningEfforts: GEMMA_REASONING_EFFORTS,
|
|
3347
4791
|
structuredOutput: true,
|
|
3348
4792
|
nativeStructuredOutput: true,
|
|
3349
4793
|
grounding: true,
|
|
3350
|
-
vision: true,
|
|
3351
4794
|
sampling: "tunable"
|
|
3352
4795
|
},
|
|
3353
4796
|
configSchema: Gemma426bA4bItConfigSchema,
|
|
4797
|
+
configKeys: core.toConfigKeys(Gemma426bA4bItConfigSchema),
|
|
3354
4798
|
configJsonSchema: core.toConfigJsonSchema(Gemma426bA4bItConfigSchema),
|
|
3355
4799
|
validateConfig: core.zodToStandardSchema(Gemma426bA4bItConfigSchema)
|
|
3356
4800
|
}
|
|
@@ -3370,16 +4814,32 @@ function googleProvider(opts) {
|
|
|
3370
4814
|
}
|
|
3371
4815
|
var DEFAULT_INTERVAL_MS = 3e3;
|
|
3372
4816
|
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
3373
|
-
var
|
|
4817
|
+
var waitOn = (scheduler) => (ms) => {
|
|
4818
|
+
let timer;
|
|
4819
|
+
const promise = new Promise((resolve) => {
|
|
4820
|
+
timer = scheduler.setTimeout(resolve, ms);
|
|
4821
|
+
});
|
|
4822
|
+
return {
|
|
4823
|
+
promise,
|
|
4824
|
+
cancel: () => {
|
|
4825
|
+
if (timer !== void 0) scheduler.clearTimeout(timer);
|
|
4826
|
+
}
|
|
4827
|
+
};
|
|
4828
|
+
};
|
|
4829
|
+
function pollTimeoutError(name) {
|
|
4830
|
+
return new core.LlmError(`Timed out waiting for uploaded file "${name}" to become ACTIVE`, {
|
|
4831
|
+
kind: "server",
|
|
4832
|
+
retryable: false,
|
|
4833
|
+
provider: "google"
|
|
4834
|
+
});
|
|
4835
|
+
}
|
|
3374
4836
|
async function buildFilesClient(auth) {
|
|
3375
|
-
const
|
|
3376
|
-
const ai = new GoogleGenAI({ apiKey: requireApiKey(auth) });
|
|
4837
|
+
const ai = await newGoogleGenAI(auth);
|
|
3377
4838
|
return {
|
|
3378
4839
|
async upload(params) {
|
|
3379
|
-
const fileArg = params.file instanceof Uint8Array ? new Blob(
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
) : params.file;
|
|
4840
|
+
const fileArg = params.file instanceof Uint8Array ? new Blob([Uint8Array.from(params.file)], {
|
|
4841
|
+
...params.config?.mimeType !== void 0 ? { type: params.config.mimeType } : {}
|
|
4842
|
+
}) : params.file;
|
|
3383
4843
|
const result = await ai.files.upload({
|
|
3384
4844
|
file: fileArg,
|
|
3385
4845
|
...params.config !== void 0 ? { config: params.config } : {}
|
|
@@ -3411,7 +4871,8 @@ var GoogleFileStore = class {
|
|
|
3411
4871
|
logger;
|
|
3412
4872
|
intervalMs;
|
|
3413
4873
|
timeoutMs;
|
|
3414
|
-
|
|
4874
|
+
startWait;
|
|
4875
|
+
scheduler;
|
|
3415
4876
|
now;
|
|
3416
4877
|
/** Memoised client promise — built at most once per store instance. */
|
|
3417
4878
|
clientPromise;
|
|
@@ -3422,19 +4883,22 @@ var GoogleFileStore = class {
|
|
|
3422
4883
|
this.onDeleteError = opts.onDeleteError ?? ((name, err) => {
|
|
3423
4884
|
if (this.logger !== void 0) {
|
|
3424
4885
|
this.logger.error(
|
|
3425
|
-
{ name, error: core.redactSecrets(
|
|
4886
|
+
{ name, error: core.redactSecrets(classifyGoogleError(err).message) },
|
|
3426
4887
|
"gemini.file.delete.failed"
|
|
3427
4888
|
);
|
|
3428
4889
|
} else {
|
|
3429
4890
|
console.error(
|
|
3430
4891
|
`[GoogleFileStore] delete failed for "${name}":`,
|
|
3431
|
-
core.redactSecrets(
|
|
4892
|
+
core.redactSecrets(classifyGoogleError(err).message)
|
|
3432
4893
|
);
|
|
3433
4894
|
}
|
|
3434
4895
|
});
|
|
3435
4896
|
this.intervalMs = opts.poll?.intervalMs ?? DEFAULT_INTERVAL_MS;
|
|
3436
4897
|
this.timeoutMs = opts.poll?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
3437
|
-
this.
|
|
4898
|
+
this.scheduler = opts.scheduler ?? PLATFORM_SCHEDULER;
|
|
4899
|
+
const customSleep = opts.sleep;
|
|
4900
|
+
this.startWait = customSleep !== void 0 ? (ms) => ({ promise: customSleep(ms), cancel: () => {
|
|
4901
|
+
} }) : waitOn(this.scheduler);
|
|
3438
4902
|
this.now = opts.now ?? (() => Date.now());
|
|
3439
4903
|
}
|
|
3440
4904
|
getClient() {
|
|
@@ -3448,23 +4912,41 @@ var GoogleFileStore = class {
|
|
|
3448
4912
|
* Upload bytes to the Gemini File API and wait until the file is ACTIVE.
|
|
3449
4913
|
*
|
|
3450
4914
|
* @param source - Raw bytes or Blob.
|
|
3451
|
-
* @param mimeType - IANA media type, e.g. `"image/png"`.
|
|
4915
|
+
* @param mimeType - IANA media type, e.g. `"image/png"`. It must pass the same
|
|
4916
|
+
* admission rule `generate` applies to a Gemini model's parts (one shared
|
|
4917
|
+
* function, so a file that uploads can be used): an empty or unadmitted type
|
|
4918
|
+
* is `bad_request` before any bytes are sent. The string is sent to Google
|
|
4919
|
+
* unchanged.
|
|
3452
4920
|
* @param opts - Optional display name.
|
|
3453
4921
|
*/
|
|
3454
4922
|
async upload(source, mimeType, opts) {
|
|
3455
4923
|
const signal = opts?.signal;
|
|
4924
|
+
core.assertMediaTypeAdmitted(
|
|
4925
|
+
mimeType,
|
|
4926
|
+
GEMINI_INPUT_MIME_TYPES,
|
|
4927
|
+
"mimeType",
|
|
4928
|
+
"google",
|
|
4929
|
+
"a Google file upload"
|
|
4930
|
+
);
|
|
3456
4931
|
const client = await this.getClient();
|
|
4932
|
+
if (signal?.aborted === true) {
|
|
4933
|
+
throw new core.LlmError("File upload aborted", { kind: "aborted", retryable: false });
|
|
4934
|
+
}
|
|
3457
4935
|
let uploadResp;
|
|
3458
4936
|
try {
|
|
3459
|
-
uploadResp = await
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
4937
|
+
uploadResp = await abortable(
|
|
4938
|
+
client.upload({
|
|
4939
|
+
file: source,
|
|
4940
|
+
config: {
|
|
4941
|
+
mimeType,
|
|
4942
|
+
...opts?.displayName !== void 0 ? { displayName: opts.displayName } : {},
|
|
4943
|
+
...signal !== void 0 ? { abortSignal: signal } : {}
|
|
4944
|
+
}
|
|
4945
|
+
}),
|
|
4946
|
+
signal
|
|
4947
|
+
);
|
|
3466
4948
|
} catch (e) {
|
|
3467
|
-
throw
|
|
4949
|
+
throw classifyGoogleError(e);
|
|
3468
4950
|
}
|
|
3469
4951
|
const { name, uri } = uploadResp;
|
|
3470
4952
|
if (name === void 0 || name.length === 0 || uri === void 0 || uri.length === 0) {
|
|
@@ -3479,10 +4961,7 @@ var GoogleFileStore = class {
|
|
|
3479
4961
|
return makeHandle(uploadResp, fallback);
|
|
3480
4962
|
}
|
|
3481
4963
|
if (uploadResp.state === "FAILED") {
|
|
3482
|
-
throw
|
|
3483
|
-
kind: "bad_request",
|
|
3484
|
-
retryable: false
|
|
3485
|
-
});
|
|
4964
|
+
throw failedFile("File processing failed immediately after upload", uploadResp);
|
|
3486
4965
|
}
|
|
3487
4966
|
const deadline = this.now() + this.timeoutMs;
|
|
3488
4967
|
if (signal?.aborted === true) {
|
|
@@ -3491,49 +4970,102 @@ var GoogleFileStore = class {
|
|
|
3491
4970
|
retryable: false
|
|
3492
4971
|
});
|
|
3493
4972
|
}
|
|
4973
|
+
let onAbort;
|
|
3494
4974
|
const abortRacePromise = signal !== void 0 ? new Promise((_, reject) => {
|
|
3495
|
-
|
|
3496
|
-
|
|
4975
|
+
onAbort = () => {
|
|
4976
|
+
reject(
|
|
4977
|
+
new core.LlmError("File upload polling aborted", {
|
|
4978
|
+
kind: "aborted",
|
|
4979
|
+
retryable: false
|
|
4980
|
+
})
|
|
4981
|
+
);
|
|
4982
|
+
};
|
|
4983
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
4984
|
+
}) : void 0;
|
|
4985
|
+
abortRacePromise?.catch(() => {
|
|
4986
|
+
});
|
|
4987
|
+
try {
|
|
4988
|
+
return await this.pollUntilActive(
|
|
4989
|
+
client,
|
|
4990
|
+
name,
|
|
4991
|
+
fallback,
|
|
4992
|
+
deadline,
|
|
4993
|
+
signal,
|
|
4994
|
+
abortRacePromise
|
|
4995
|
+
);
|
|
4996
|
+
} finally {
|
|
4997
|
+
if (signal !== void 0 && onAbort !== void 0) {
|
|
4998
|
+
signal.removeEventListener("abort", onAbort);
|
|
4999
|
+
}
|
|
5000
|
+
}
|
|
5001
|
+
}
|
|
5002
|
+
/**
|
|
5003
|
+
* `work` raced against the abort promise and the time left until `deadline`
|
|
5004
|
+
* (the deadline is a non-retryable `server` error). `work` is observed, so a
|
|
5005
|
+
* late rejection after the race is lost is not unhandled; the deadline timer
|
|
5006
|
+
* is always cleared.
|
|
5007
|
+
*/
|
|
5008
|
+
async raceDeadline(work, name, deadline, abortRacePromise) {
|
|
5009
|
+
work.catch(() => {
|
|
5010
|
+
});
|
|
5011
|
+
const remainingMs = deadline - this.now();
|
|
5012
|
+
let deadlineTimer;
|
|
5013
|
+
const deadlineRace = new Promise((_, reject) => {
|
|
5014
|
+
if (remainingMs > MAX_TIMER_MS) return;
|
|
5015
|
+
deadlineTimer = this.scheduler.setTimeout(
|
|
3497
5016
|
() => {
|
|
3498
|
-
reject(
|
|
3499
|
-
new core.LlmError("File upload polling aborted", {
|
|
3500
|
-
kind: "aborted",
|
|
3501
|
-
retryable: false
|
|
3502
|
-
})
|
|
3503
|
-
);
|
|
5017
|
+
reject(pollTimeoutError(name));
|
|
3504
5018
|
},
|
|
3505
|
-
|
|
5019
|
+
Math.max(remainingMs, 0)
|
|
3506
5020
|
);
|
|
3507
|
-
})
|
|
5021
|
+
});
|
|
5022
|
+
deadlineRace.catch(() => {
|
|
5023
|
+
});
|
|
5024
|
+
try {
|
|
5025
|
+
return await Promise.race(
|
|
5026
|
+
abortRacePromise !== void 0 ? [work, deadlineRace, abortRacePromise] : [work, deadlineRace]
|
|
5027
|
+
);
|
|
5028
|
+
} finally {
|
|
5029
|
+
if (deadlineTimer !== void 0) this.scheduler.clearTimeout(deadlineTimer);
|
|
5030
|
+
}
|
|
5031
|
+
}
|
|
5032
|
+
/** Polls `name` until ACTIVE; see {@link GoogleFileStore.upload}. */
|
|
5033
|
+
async pollUntilActive(client, name, fallback, deadline, signal, abortRacePromise) {
|
|
3508
5034
|
for (; ; ) {
|
|
3509
5035
|
if (this.now() >= deadline) {
|
|
3510
|
-
throw
|
|
3511
|
-
kind: "timeout",
|
|
3512
|
-
retryable: true
|
|
3513
|
-
});
|
|
5036
|
+
throw pollTimeoutError(name);
|
|
3514
5037
|
}
|
|
3515
|
-
const
|
|
3516
|
-
await (abortRacePromise !== void 0 ? Promise.race([sleepCall, abortRacePromise]) : sleepCall);
|
|
3517
|
-
let pollResp;
|
|
5038
|
+
const wait = this.startWait(this.intervalMs);
|
|
3518
5039
|
try {
|
|
3519
|
-
|
|
3520
|
-
}
|
|
3521
|
-
|
|
5040
|
+
await this.raceDeadline(wait.promise, name, deadline, abortRacePromise);
|
|
5041
|
+
} finally {
|
|
5042
|
+
wait.cancel();
|
|
5043
|
+
}
|
|
5044
|
+
if (this.now() >= deadline) {
|
|
5045
|
+
throw pollTimeoutError(name);
|
|
3522
5046
|
}
|
|
5047
|
+
const pollCall = (async () => {
|
|
5048
|
+
try {
|
|
5049
|
+
return await client.get({ name });
|
|
5050
|
+
} catch (e) {
|
|
5051
|
+
throw classifyGoogleError(e);
|
|
5052
|
+
}
|
|
5053
|
+
})();
|
|
5054
|
+
const pollResp = await this.raceDeadline(pollCall, name, deadline, abortRacePromise);
|
|
3523
5055
|
if (signal?.aborted === true) {
|
|
3524
5056
|
throw new core.LlmError("File upload polling aborted", {
|
|
3525
5057
|
kind: "aborted",
|
|
3526
5058
|
retryable: false
|
|
3527
5059
|
});
|
|
3528
5060
|
}
|
|
5061
|
+
if (this.now() >= deadline) {
|
|
5062
|
+
throw pollTimeoutError(name);
|
|
5063
|
+
}
|
|
3529
5064
|
if (pollResp.state === "ACTIVE") {
|
|
3530
5065
|
return makeHandle(pollResp, fallback);
|
|
3531
5066
|
}
|
|
3532
5067
|
if (pollResp.state === "FAILED") {
|
|
3533
|
-
throw
|
|
3534
|
-
kind: "bad_request",
|
|
3535
|
-
retryable: false
|
|
3536
|
-
});
|
|
5068
|
+
throw failedFile("File processing failed during polling", pollResp);
|
|
3537
5069
|
}
|
|
3538
5070
|
}
|
|
3539
5071
|
}
|
|
@@ -3570,15 +5102,7 @@ var GoogleFileStore = class {
|
|
|
3570
5102
|
if (isGoogleNotFoundError(err)) {
|
|
3571
5103
|
return;
|
|
3572
5104
|
}
|
|
3573
|
-
const
|
|
3574
|
-
const withProvider = classified.provider === void 0 ? new core.LlmError(classified.message, {
|
|
3575
|
-
kind: classified.kind,
|
|
3576
|
-
retryable: classified.retryable,
|
|
3577
|
-
...classified.httpStatus !== void 0 ? { httpStatus: classified.httpStatus } : {},
|
|
3578
|
-
...classified.retryAfterMs !== void 0 ? { retryAfterMs: classified.retryAfterMs } : {},
|
|
3579
|
-
provider: "google",
|
|
3580
|
-
cause: classified.cause ?? err
|
|
3581
|
-
}) : classified;
|
|
5105
|
+
const withProvider = classifyGoogleError(err);
|
|
3582
5106
|
if (failClosed) {
|
|
3583
5107
|
throw withProvider;
|
|
3584
5108
|
}
|
|
@@ -3600,31 +5124,58 @@ var GoogleFileStore = class {
|
|
|
3600
5124
|
await Promise.allSettled(handles.map((h) => this.delete(h, opts)));
|
|
3601
5125
|
}
|
|
3602
5126
|
};
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
if (
|
|
3619
|
-
|
|
5127
|
+
var TRANSIENT_FILE_STATUS_CODES = /* @__PURE__ */ new Set([4, 13, 14]);
|
|
5128
|
+
function failedFile(prefix, resp) {
|
|
5129
|
+
const providerMessage = resp.error?.message;
|
|
5130
|
+
const transient = typeof resp.error?.code === "number" && TRANSIENT_FILE_STATUS_CODES.has(resp.error.code);
|
|
5131
|
+
return new core.LlmError(
|
|
5132
|
+
providerMessage !== void 0 && providerMessage.length > 0 ? `${prefix}: ${providerMessage}` : prefix,
|
|
5133
|
+
{
|
|
5134
|
+
kind: transient ? "server" : "bad_request",
|
|
5135
|
+
retryable: transient,
|
|
5136
|
+
provider: "google",
|
|
5137
|
+
...resp.error !== void 0 ? { cause: resp.error } : {}
|
|
5138
|
+
}
|
|
5139
|
+
);
|
|
5140
|
+
}
|
|
5141
|
+
async function abortable(promise, signal) {
|
|
5142
|
+
if (signal === void 0) return promise;
|
|
5143
|
+
promise.catch(() => {
|
|
5144
|
+
});
|
|
5145
|
+
let onAbort;
|
|
5146
|
+
const aborted = new Promise((_, reject) => {
|
|
5147
|
+
onAbort = () => {
|
|
5148
|
+
reject(new core.LlmError("File upload aborted", { kind: "aborted", retryable: false }));
|
|
5149
|
+
};
|
|
5150
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
5151
|
+
if (signal.aborted) onAbort();
|
|
5152
|
+
});
|
|
5153
|
+
try {
|
|
5154
|
+
return await Promise.race([promise, aborted]);
|
|
5155
|
+
} finally {
|
|
5156
|
+
if (onAbort !== void 0) signal.removeEventListener("abort", onAbort);
|
|
3620
5157
|
}
|
|
3621
|
-
return false;
|
|
3622
5158
|
}
|
|
3623
5159
|
var DEFAULT_SKEW_SECONDS = 30;
|
|
3624
5160
|
var DEFAULT_EXTENSION_SECONDS = 3600;
|
|
5161
|
+
function toolKindsOf(tools) {
|
|
5162
|
+
const kinds = /* @__PURE__ */ new Set();
|
|
5163
|
+
for (const tool of tools ?? []) {
|
|
5164
|
+
for (const [kind, value] of Object.entries(tool)) {
|
|
5165
|
+
if (value !== void 0) kinds.add(kind);
|
|
5166
|
+
}
|
|
5167
|
+
}
|
|
5168
|
+
return [...kinds];
|
|
5169
|
+
}
|
|
5170
|
+
function expiryOf(expireTime, fallbackMs) {
|
|
5171
|
+
if (expireTime !== void 0 && expireTime.length > 0) {
|
|
5172
|
+
const parsed = new Date(expireTime);
|
|
5173
|
+
if (!Number.isNaN(parsed.getTime())) return parsed;
|
|
5174
|
+
}
|
|
5175
|
+
return new Date(fallbackMs);
|
|
5176
|
+
}
|
|
3625
5177
|
async function buildCachesClient(auth) {
|
|
3626
|
-
const
|
|
3627
|
-
const ai = new GoogleGenAI({ apiKey: requireApiKey(auth) });
|
|
5178
|
+
const ai = await newGoogleGenAI(auth);
|
|
3628
5179
|
return {
|
|
3629
5180
|
async create(params) {
|
|
3630
5181
|
const result = await ai.caches.create(params);
|
|
@@ -3663,13 +5214,13 @@ var GoogleCacheStore = class {
|
|
|
3663
5214
|
this.onDeleteError = opts.onDeleteError ?? ((cacheName, err) => {
|
|
3664
5215
|
if (this.logger !== void 0) {
|
|
3665
5216
|
this.logger.error(
|
|
3666
|
-
{ name: cacheName, error: core.redactSecrets(
|
|
5217
|
+
{ name: cacheName, error: core.redactSecrets(classifyGoogleError(err).message) },
|
|
3667
5218
|
"gemini.cache.delete.failed"
|
|
3668
5219
|
);
|
|
3669
5220
|
} else {
|
|
3670
5221
|
console.error(
|
|
3671
5222
|
`[GoogleCacheStore] delete failed for "${cacheName}":`,
|
|
3672
|
-
core.redactSecrets(
|
|
5223
|
+
core.redactSecrets(classifyGoogleError(err).message)
|
|
3673
5224
|
);
|
|
3674
5225
|
}
|
|
3675
5226
|
});
|
|
@@ -3694,11 +5245,18 @@ var GoogleCacheStore = class {
|
|
|
3694
5245
|
* `now + ttlSeconds * 1000`.
|
|
3695
5246
|
*/
|
|
3696
5247
|
async create(input) {
|
|
5248
|
+
if (!Number.isInteger(input.ttlSeconds) || input.ttlSeconds <= 0) {
|
|
5249
|
+
throw new core.LlmError(
|
|
5250
|
+
`GoogleCacheStore.create: ttlSeconds must be a positive integer, got ${String(input.ttlSeconds)}.`,
|
|
5251
|
+
{ kind: "bad_request", retryable: false, provider: "google" }
|
|
5252
|
+
);
|
|
5253
|
+
}
|
|
3697
5254
|
if (this.preflight !== void 0) {
|
|
3698
5255
|
const counted = await this.preflight.countTokens({
|
|
3699
5256
|
model: input.model,
|
|
3700
5257
|
...input.contents !== void 0 ? { contents: input.contents } : {},
|
|
3701
|
-
...input.systemInstruction !== void 0 ? { systemInstruction: input.systemInstruction } : {}
|
|
5258
|
+
...input.systemInstruction !== void 0 ? { systemInstruction: input.systemInstruction } : {},
|
|
5259
|
+
...input.tools !== void 0 ? { tools: input.tools } : {}
|
|
3702
5260
|
});
|
|
3703
5261
|
if (counted < this.preflight.minTokens) {
|
|
3704
5262
|
throw new core.LlmError(
|
|
@@ -3712,12 +5270,14 @@ var GoogleCacheStore = class {
|
|
|
3712
5270
|
if (input.contents !== void 0) config.contents = input.contents;
|
|
3713
5271
|
if (input.systemInstruction !== void 0)
|
|
3714
5272
|
config.systemInstruction = input.systemInstruction;
|
|
5273
|
+
if (input.tools !== void 0) config.tools = input.tools;
|
|
5274
|
+
if (input.toolConfig !== void 0) config.toolConfig = input.toolConfig;
|
|
3715
5275
|
if (input.displayName !== void 0) config.displayName = input.displayName;
|
|
3716
5276
|
let resp;
|
|
3717
5277
|
try {
|
|
3718
5278
|
resp = await client.create({ model: input.model, config });
|
|
3719
5279
|
} catch (e) {
|
|
3720
|
-
throw
|
|
5280
|
+
throw classifyGoogleError(e);
|
|
3721
5281
|
}
|
|
3722
5282
|
if (resp.name === void 0 || resp.name.length === 0) {
|
|
3723
5283
|
throw new core.LlmError("Cache create response missing required field: name", {
|
|
@@ -3726,12 +5286,14 @@ var GoogleCacheStore = class {
|
|
|
3726
5286
|
provider: "google"
|
|
3727
5287
|
});
|
|
3728
5288
|
}
|
|
3729
|
-
const
|
|
3730
|
-
const
|
|
5289
|
+
const expiresAt = expiryOf(resp.expireTime, this.now() + input.ttlSeconds * 1e3);
|
|
5290
|
+
const totalTokenCount = resp.usageMetadata?.totalTokenCount;
|
|
3731
5291
|
return {
|
|
3732
5292
|
cacheName: resp.name,
|
|
3733
5293
|
model: resp.model ?? input.model,
|
|
3734
|
-
expiresAt
|
|
5294
|
+
expiresAt,
|
|
5295
|
+
...typeof totalTokenCount === "number" && Number.isFinite(totalTokenCount) ? { totalTokenCount } : {},
|
|
5296
|
+
toolKinds: toolKindsOf(input.tools)
|
|
3735
5297
|
};
|
|
3736
5298
|
}
|
|
3737
5299
|
/**
|
|
@@ -3746,8 +5308,9 @@ var GoogleCacheStore = class {
|
|
|
3746
5308
|
async getOrCreate(key, factory) {
|
|
3747
5309
|
const mapKey = `${key.model}:${key.stableKey}`;
|
|
3748
5310
|
const existing = this.entries.get(mapKey);
|
|
3749
|
-
if (existing !== void 0
|
|
3750
|
-
return existing.handle;
|
|
5311
|
+
if (existing !== void 0) {
|
|
5312
|
+
if (this.isLive(existing.handle)) return existing.handle;
|
|
5313
|
+
this.entries.delete(mapKey);
|
|
3751
5314
|
}
|
|
3752
5315
|
if (this.coalesce) {
|
|
3753
5316
|
const inFlight = this.inflight.get(mapKey);
|
|
@@ -3761,7 +5324,9 @@ var GoogleCacheStore = class {
|
|
|
3761
5324
|
model: key.model,
|
|
3762
5325
|
ttlSeconds: factoryResult.ttlSeconds,
|
|
3763
5326
|
...factoryResult.contents !== void 0 ? { contents: factoryResult.contents } : {},
|
|
3764
|
-
...factoryResult.systemInstruction !== void 0 ? { systemInstruction: factoryResult.systemInstruction } : {}
|
|
5327
|
+
...factoryResult.systemInstruction !== void 0 ? { systemInstruction: factoryResult.systemInstruction } : {},
|
|
5328
|
+
...factoryResult.tools !== void 0 ? { tools: factoryResult.tools } : {},
|
|
5329
|
+
...factoryResult.toolConfig !== void 0 ? { toolConfig: factoryResult.toolConfig } : {}
|
|
3765
5330
|
});
|
|
3766
5331
|
this.entries.set(mapKey, { handle, ttlSeconds: factoryResult.ttlSeconds });
|
|
3767
5332
|
return handle;
|
|
@@ -3808,12 +5373,13 @@ var GoogleCacheStore = class {
|
|
|
3808
5373
|
name: handle.cacheName,
|
|
3809
5374
|
config: { ttl: `${extensionSeconds}s` }
|
|
3810
5375
|
});
|
|
3811
|
-
const
|
|
3812
|
-
const newExpiresAt = resp.expireTime !== void 0 && resp.expireTime.length > 0 ? new Date(resp.expireTime) : fallbackExpiry;
|
|
5376
|
+
const newExpiresAt = expiryOf(resp.expireTime, this.now() + extensionSeconds * 1e3);
|
|
3813
5377
|
const newHandle = {
|
|
3814
5378
|
cacheName: handle.cacheName,
|
|
3815
5379
|
model: handle.model,
|
|
3816
|
-
expiresAt: newExpiresAt
|
|
5380
|
+
expiresAt: newExpiresAt,
|
|
5381
|
+
...handle.totalTokenCount !== void 0 ? { totalTokenCount: handle.totalTokenCount } : {},
|
|
5382
|
+
...handle.toolKinds !== void 0 ? { toolKinds: handle.toolKinds } : {}
|
|
3817
5383
|
};
|
|
3818
5384
|
for (const [k, entry] of this.entries.entries()) {
|
|
3819
5385
|
if (entry.handle.cacheName === handle.cacheName) {
|
|
@@ -3827,9 +5393,11 @@ var GoogleCacheStore = class {
|
|
|
3827
5393
|
}
|
|
3828
5394
|
}
|
|
3829
5395
|
/**
|
|
3830
|
-
* Delete a cached content resource.
|
|
5396
|
+
* Delete a cached content resource. Idempotent: a cache that is already gone
|
|
5397
|
+
* (HTTP 404, or the 403 `CachedContent not found` Google sends for an expired
|
|
5398
|
+
* one) is success, not an error.
|
|
3831
5399
|
*
|
|
3832
|
-
*
|
|
5400
|
+
* Any other error is forwarded to `onDeleteError` and NOT rethrown.
|
|
3833
5401
|
* The handle is removed from the in-process entries map regardless.
|
|
3834
5402
|
*/
|
|
3835
5403
|
async delete(handle) {
|
|
@@ -3843,6 +5411,7 @@ var GoogleCacheStore = class {
|
|
|
3843
5411
|
const client = await this.getClient();
|
|
3844
5412
|
await client.delete({ name: handle.cacheName });
|
|
3845
5413
|
} catch (err) {
|
|
5414
|
+
if (isGoogleNotFoundError(err)) return;
|
|
3846
5415
|
this.onDeleteError(handle.cacheName, err);
|
|
3847
5416
|
}
|
|
3848
5417
|
}
|
|
@@ -3884,7 +5453,7 @@ function convertMediaResolution(mediaResolution, location) {
|
|
|
3884
5453
|
return mapMediaResolutionLevel(mediaResolution.level, location);
|
|
3885
5454
|
}
|
|
3886
5455
|
function convertPart(part, location, nameCounts, reservedIds) {
|
|
3887
|
-
const keys = definedKeys(part);
|
|
5456
|
+
const keys = definedKeys(part).filter((key) => key !== "thoughtSignature");
|
|
3888
5457
|
const baseKeys = keys.filter(
|
|
3889
5458
|
(key) => key === "text" || key === "inlineData" || key === "fileData"
|
|
3890
5459
|
);
|
|
@@ -3993,6 +5562,20 @@ function convertPart(part, location, nameCounts, reservedIds) {
|
|
|
3993
5562
|
}
|
|
3994
5563
|
throw badRequest(`${location}: Part has no recognized fields set.`);
|
|
3995
5564
|
}
|
|
5565
|
+
function convertPartWithSignature(part, location, role, nameCounts, reservedIds) {
|
|
5566
|
+
const converted = convertPart(part, location, nameCounts, reservedIds);
|
|
5567
|
+
const signature = part.thoughtSignature;
|
|
5568
|
+
if (signature === void 0) return { part: converted };
|
|
5569
|
+
if (typeof signature !== "string" || signature.length === 0) {
|
|
5570
|
+
throw badRequest(`${location}: Part.thoughtSignature must be a non-empty string.`);
|
|
5571
|
+
}
|
|
5572
|
+
if (role !== "assistant" || converted.kind !== "text" && converted.kind !== "tool-call") {
|
|
5573
|
+
throw badRequest(
|
|
5574
|
+
`${location}: Part.thoughtSignature can only be imported from a model text or functionCall part.`
|
|
5575
|
+
);
|
|
5576
|
+
}
|
|
5577
|
+
return { part: converted, signature };
|
|
5578
|
+
}
|
|
3996
5579
|
function convertRole(role, location) {
|
|
3997
5580
|
if (role === "user") return "user";
|
|
3998
5581
|
if (role === "model") return "assistant";
|
|
@@ -4038,6 +5621,7 @@ function geminiContentToMessages(input) {
|
|
|
4038
5621
|
})
|
|
4039
5622
|
)
|
|
4040
5623
|
);
|
|
5624
|
+
const signatures = [];
|
|
4041
5625
|
const messages = input.contents.map((content, contentIndex) => {
|
|
4042
5626
|
const location = `contents[${contentIndex}]`;
|
|
4043
5627
|
const envelopeExtraKeys = definedKeys(content).filter(
|
|
@@ -4049,15 +5633,45 @@ function geminiContentToMessages(input) {
|
|
|
4049
5633
|
);
|
|
4050
5634
|
}
|
|
4051
5635
|
const role = convertRole(content.role, location);
|
|
4052
|
-
const parts = (content.parts ?? []).map(
|
|
4053
|
-
|
|
4054
|
-
|
|
5636
|
+
const parts = (content.parts ?? []).map((part, partIndex) => {
|
|
5637
|
+
const partLocation = `${location}.parts[${partIndex}]`;
|
|
5638
|
+
const converted = convertPartWithSignature(
|
|
5639
|
+
part,
|
|
5640
|
+
partLocation,
|
|
5641
|
+
role,
|
|
5642
|
+
nameCounts,
|
|
5643
|
+
reservedIds
|
|
5644
|
+
);
|
|
5645
|
+
if (converted.signature !== void 0) {
|
|
5646
|
+
if (input.model === void 0) {
|
|
5647
|
+
throw badRequest(
|
|
5648
|
+
`${partLocation}: Part.thoughtSignature requires the \`model\` input; a signature is bound to the model that issued it.`
|
|
5649
|
+
);
|
|
5650
|
+
}
|
|
5651
|
+
signatures.push(
|
|
5652
|
+
signatureEntry(
|
|
5653
|
+
contentIndex,
|
|
5654
|
+
partIndex,
|
|
5655
|
+
input.model,
|
|
5656
|
+
converted.part,
|
|
5657
|
+
converted.signature
|
|
5658
|
+
)
|
|
5659
|
+
);
|
|
5660
|
+
}
|
|
5661
|
+
return converted.part;
|
|
5662
|
+
});
|
|
4055
5663
|
return { role, parts };
|
|
4056
5664
|
});
|
|
4057
|
-
return {
|
|
5665
|
+
return {
|
|
5666
|
+
...system !== void 0 ? { system } : {},
|
|
5667
|
+
messages,
|
|
5668
|
+
...signatures.length > 0 ? { transientProviderState: { google: { signatures } } } : {}
|
|
5669
|
+
};
|
|
4058
5670
|
}
|
|
4059
5671
|
|
|
4060
5672
|
exports.FLEX_DEFAULT_TIMEOUT_MS = FLEX_DEFAULT_TIMEOUT_MS;
|
|
5673
|
+
exports.GEMINI_GROUNDING_PRICING = GEMINI_GROUNDING_PRICING;
|
|
5674
|
+
exports.GEMINI_INPUT_MIME_TYPES = GEMINI_INPUT_MIME_TYPES;
|
|
4061
5675
|
exports.GEMINI_PRICED_TIERS = GEMINI_PRICED_TIERS;
|
|
4062
5676
|
exports.GEMINI_PRICING = GEMINI_PRICING;
|
|
4063
5677
|
exports.GoogleCacheStore = GoogleCacheStore;
|
|
@@ -4065,7 +5679,9 @@ exports.GoogleFileStore = GoogleFileStore;
|
|
|
4065
5679
|
exports.STANDARD_DEFAULT_TIMEOUT_MS = STANDARD_DEFAULT_TIMEOUT_MS;
|
|
4066
5680
|
exports.TRANSPORT_TIMEOUT_BUFFER_MS = TRANSPORT_TIMEOUT_BUFFER_MS;
|
|
4067
5681
|
exports.buildGoogleClient = buildGoogleClient;
|
|
5682
|
+
exports.classifyGoogleError = classifyGoogleError;
|
|
4068
5683
|
exports.defaultGeminiRegistry = defaultGeminiRegistry;
|
|
5684
|
+
exports.dropMessagesFromSignatureState = dropMessagesFromSignatureState;
|
|
4069
5685
|
exports.geminiAdapter = geminiAdapter;
|
|
4070
5686
|
exports.geminiContentToMessages = geminiContentToMessages;
|
|
4071
5687
|
exports.geminiModelDescriptors = geminiModelDescriptors;
|