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