@gullabs/google 0.2.0 → 0.3.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/LICENSE CHANGED
@@ -176,7 +176,7 @@
176
176
  comment syntax for the file format in please. Also attach a copy of
177
177
  this License to your work.
178
178
 
179
- Copyright 2026 Atif Gul
179
+ Copyright 2026 Gul Labs
180
180
 
181
181
  Licensed under the Apache License, Version 2.0 (the "License");
182
182
  you may not use this file except in compliance with the License.
package/README.md CHANGED
@@ -6,13 +6,13 @@ Gemini provider adapter for any-llm. A thin mapping layer over `@google/genai` t
6
6
 
7
7
  ## Key exports
8
8
 
9
- | Export | What it is |
10
- | --------------------------- | ----------------------------------------------------------------------------- |
11
- | `geminiAdapter(opts?)` | Creates the `ProviderAdapter` for Gemini |
12
- | `GeminiAdapterOptions` | `{ client?: GeminiClientLike }` — inject a pre-built or fake client |
13
- | `GeminiClientLike` | Structural interface the adapter depends on (satisfied by real SDK and fakes) |
14
- | `buildGoogleClient(auth)` | Builds the real `@google/genai` client from `AuthMaterial` |
15
- | `zodToGeminiSchema(schema)` | Converts a Zod schema to a Gemini `responseSchema` object |
9
+ | Export | What it is |
10
+ | ---------------------------- | ----------------------------------------------------------------------------- |
11
+ | `geminiAdapter(opts?)` | Creates the `ProviderAdapter` for Gemini |
12
+ | `GeminiAdapterOptions` | `{ client?: GeminiClientLike }` — inject a pre-built or fake client |
13
+ | `GeminiClientLike` | Structural interface the adapter depends on (satisfied by real SDK and fakes) |
14
+ | `buildGoogleClient(auth)` | Builds the real `@google/genai` client from `AuthMaterial` |
15
+ | `isGeminiCapacityError(err)` | Detects Gemini Flex shared-capacity errors for built-in fallback |
16
16
 
17
17
  ## Quick example
18
18
 
@@ -37,10 +37,30 @@ const result = await client.generate(
37
37
 
38
38
  ## What it maps
39
39
 
40
- - `serviceTier: 'flex'` → Gemini Flex service tier (default)
40
+ - `serviceTier: 'flex'` → Gemini Flex service tier when the model descriptor supports it
41
41
  - `reasoning.includeThoughts` → `thinkingConfig.includeThoughts`; thought parts become `reasoningText`
42
42
  - `reasoning.effort` → `thinkingBudget` (gemini-2.5) or `thinkingLevel` (gemini-3.x) with a warning when lossy
43
- - `output.schema` → `responseMimeType: 'application/json'` + `responseSchema` (Zod-converted)
44
- - `providerOptions.google.*` → forwarded verbatim to the SDK config
43
+ - `output.jsonSchema` → `responseMimeType: 'application/json'` + verbatim `responseSchema` when native structured output is enabled; the engine returns parsed output and `outputParsed` without validating shape
44
+ - `providerOptions.google.*` → forwarded verbatim to the SDK config, including Gemini `safetySettings`
45
45
  - Usage: `promptTokenCount`→`inputTokens`, `candidatesTokenCount`+`thoughtsTokenCount`→`outputTokens` (GROSS)
46
46
  - Errors: `401/403`→`invalid_auth`, `429`→`rate_limited`, `5xx`→`server`, timeouts, safety blocks
47
+
48
+ ## Gemma 4
49
+
50
+ The default registry includes two API-verified Gemma 4 models: `gemma-4-31b-it`
51
+ and `gemma-4-26b-a4b-it`. Both route through this adapter and support:
52
+
53
+ - **Native structured output** — `responseMimeType` + verbatim `responseSchema` are sent
54
+ automatically when `output.jsonSchema` is set.
55
+ - **Grounding** — `tools:[{googleSearch:{}}]` via `providerOptions.google`.
56
+ - **Vision** — `inline-media` and `file-uri` multimodal message parts.
57
+ - **Thinking** — `reasoning.effort` maps to `thinkingLevel` (`reasoningApi: 'level'`).
58
+ Gemma 4 thinking is binary: only `effort: 'none'` (MINIMAL) and `effort: 'high'`
59
+ (HIGH) are accepted. Passing `effort: 'low'` or `effort: 'medium'` is rejected at
60
+ validation time with a `bad_request` error because the model only supports MINIMAL
61
+ and HIGH `thinkingLevel` values. Note: `thinkingBudget` is **not** supported
62
+ (rejected by the API with HTTP 400).
63
+ - **Tunable sampling** — `temperature`, `topP`, `topK` are accepted.
64
+
65
+ Gemma 4 models do **not** support Gemini Flex service tier (`serviceTiers` is absent from their
66
+ descriptors) and are unpriced (`cost.microUsd` will be `null`).
package/dist/index.cjs CHANGED
@@ -1,12 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  var core = require('@gullabs/core');
4
- var zod = require('zod');
5
4
 
6
5
  // src/adapter.ts
7
6
 
8
7
  // src/client.ts
9
8
  var FLEX_DEFAULT_TIMEOUT_MS = 15e5;
9
+ var STANDARD_DEFAULT_TIMEOUT_MS = 3e5;
10
10
  var TRANSPORT_TIMEOUT_BUFFER_MS = 5e3;
11
11
  async function buildGoogleClient(auth) {
12
12
  const { GoogleGenAI } = await import('@google/genai');
@@ -20,121 +20,34 @@ async function buildGoogleClient(auth) {
20
20
  }
21
21
  };
22
22
  }
23
- function isOptionalField(schema) {
24
- if (schema instanceof zod.ZodOptional || schema instanceof zod.ZodDefault) return true;
25
- if (schema instanceof zod.ZodNullable) {
26
- const unwrapped = schema.unwrap();
27
- return isOptionalField(unwrapped);
28
- }
29
- return false;
30
- }
31
- function zodToGeminiSchema(schema) {
32
- return convertSchema(schema, false);
33
- }
34
- function convertSchema(schema, nullable) {
35
- const desc = typeof schema.description === "string" ? schema.description : void 0;
36
- if (schema instanceof zod.ZodOptional) {
37
- const unwrapped = schema.unwrap();
38
- return convertSchema(unwrapped, nullable);
39
- }
40
- if (schema instanceof zod.ZodNullable) {
41
- const unwrapped = schema.unwrap();
42
- return convertSchema(unwrapped, true);
43
- }
44
- if (schema instanceof zod.ZodDefault) {
45
- const innerType = schema._def.innerType;
46
- return convertSchema(innerType, nullable);
47
- }
48
- if (schema instanceof zod.ZodObject) {
49
- const shape = schema.shape;
50
- const properties = {};
51
- const required = [];
52
- for (const [key, fieldType] of Object.entries(shape)) {
53
- const fieldSchema = convertSchema(fieldType, false);
54
- if (fieldSchema === void 0) return void 0;
55
- properties[key] = fieldSchema;
56
- if (!isOptionalField(fieldType)) {
57
- required.push(key);
58
- }
59
- }
60
- const result = {
61
- type: "object",
62
- properties,
63
- ...required.length > 0 ? { required } : {},
64
- ...desc !== void 0 ? { description: desc } : {},
65
- ...nullable ? { nullable: true } : {}
66
- };
67
- return result;
68
- }
69
- if (schema instanceof zod.ZodString) {
70
- return {
71
- type: "string",
72
- ...desc !== void 0 ? { description: desc } : {},
73
- ...nullable ? { nullable: true } : {}
74
- };
75
- }
76
- if (schema instanceof zod.ZodNumber) {
77
- const checks = schema._def.checks ?? [];
78
- const isInt = checks.some((c) => c.kind === "int");
79
- return {
80
- type: isInt ? "integer" : "number",
81
- ...desc !== void 0 ? { description: desc } : {},
82
- ...nullable ? { nullable: true } : {}
83
- };
84
- }
85
- if (schema instanceof zod.ZodBoolean) {
86
- return {
87
- type: "boolean",
88
- ...desc !== void 0 ? { description: desc } : {},
89
- ...nullable ? { nullable: true } : {}
90
- };
91
- }
92
- if (schema instanceof zod.ZodArray) {
93
- const element = schema.element;
94
- const items = convertSchema(element, false);
95
- if (items === void 0) return void 0;
96
- return {
97
- type: "array",
98
- items,
99
- ...desc !== void 0 ? { description: desc } : {},
100
- ...nullable ? { nullable: true } : {}
101
- };
102
- }
103
- if (schema instanceof zod.ZodEnum) {
104
- return {
105
- type: "string",
106
- enum: schema.options,
107
- ...desc !== void 0 ? { description: desc } : {},
108
- ...nullable ? { nullable: true } : {}
109
- };
110
- }
111
- if (schema instanceof zod.ZodLiteral) {
112
- const val = schema.value;
113
- if (typeof val === "string") {
114
- return {
115
- type: "string",
116
- enum: [val],
117
- ...desc !== void 0 ? { description: desc } : {},
118
- ...nullable ? { nullable: true } : {}
119
- };
120
- }
121
- if (typeof val === "number") {
122
- return {
123
- type: "number",
124
- ...desc !== void 0 ? { description: desc } : {},
125
- ...nullable ? { nullable: true } : {}
126
- };
127
- }
128
- if (typeof val === "boolean") {
129
- return {
130
- type: "boolean",
131
- ...desc !== void 0 ? { description: desc } : {},
132
- ...nullable ? { nullable: true } : {}
133
- };
134
- }
135
- return void 0;
23
+
24
+ // src/flex-fallback.ts
25
+ var CAPACITY_PATTERNS = [
26
+ /capacity/i,
27
+ /overload/i,
28
+ /overloaded/i,
29
+ /unavailable/i,
30
+ /no\s+capacity/i,
31
+ /temporar(?:y|ily)/i,
32
+ /try\s+again/i
33
+ ];
34
+ var QUOTA_PATTERNS = [
35
+ /quota/i,
36
+ /billing/i,
37
+ /billable/i,
38
+ /payment/i,
39
+ /rate\s+limit/i,
40
+ /exceeded/i,
41
+ /insufficient/i
42
+ ];
43
+ function isGeminiCapacityError(err) {
44
+ if (err.kind === "server") return err.httpStatus === 503;
45
+ if (err.kind !== "rate_limited") return false;
46
+ const message = err.message;
47
+ if (QUOTA_PATTERNS.some((pattern) => pattern.test(message))) {
48
+ return false;
136
49
  }
137
- return void 0;
50
+ return CAPACITY_PATTERNS.some((pattern) => pattern.test(message));
138
51
  }
139
52
 
140
53
  // src/adapter.ts
@@ -255,24 +168,45 @@ function geminiAdapter(opts) {
255
168
  if (genConfig.stopSequences !== void 0) {
256
169
  config.stopSequences = genConfig.stopSequences;
257
170
  }
258
- config.serviceTier = genConfig.serviceTier === "standard" ? "standard" : "flex";
171
+ const explicit = genConfig.serviceTier;
172
+ const supported = req.modelDescriptor?.capabilities?.serviceTiers;
173
+ if (explicit !== void 0) {
174
+ if (req.modelDescriptor !== void 0 && (supported === void 0 || !supported.includes(explicit))) {
175
+ throw new core.LlmError(
176
+ `serviceTier "${explicit}" is not supported for model "${model}".`,
177
+ { kind: "bad_request", retryable: false }
178
+ );
179
+ }
180
+ config.serviceTier = explicit;
181
+ } else {
182
+ if (req.modelDescriptor === void 0) {
183
+ config.serviceTier = "flex";
184
+ } else if (supported?.includes("flex") === true) {
185
+ config.serviceTier = "flex";
186
+ }
187
+ }
259
188
  const reasoning = genConfig.reasoning;
260
189
  if (reasoning !== void 0) {
261
190
  const reasoningApi = req.modelDescriptor?.capabilities?.reasoningApi;
191
+ if (reasoning.effort !== void 0 && reasoning.budgetTokens !== void 0) {
192
+ throw new core.LlmError(
193
+ `Provide either reasoning.effort or reasoning.budgetTokens, not both, for model "${model}".`,
194
+ { kind: "bad_request", retryable: false }
195
+ );
196
+ }
262
197
  if (reasoningApi === "budget") {
263
198
  const budget = reasoning.budgetTokens !== void 0 ? reasoning.budgetTokens : reasoning.effort !== void 0 ? EFFORT_BUDGET[reasoning.effort] ?? 0 : void 0;
264
199
  config.thinkingConfig = {
265
200
  ...budget !== void 0 ? { thinkingBudget: budget } : {},
266
201
  ...reasoning.includeThoughts === true ? { includeThoughts: true } : {}
267
202
  };
268
- if (reasoning.effort !== void 0 && reasoning.budgetTokens !== void 0) {
269
- warnings.push({
270
- type: "reasoning-mapping",
271
- quality: "approximate",
272
- details: "budgetTokens takes precedence over effort for thinkingBudget"
273
- });
274
- }
275
203
  } else if (reasoningApi === "level") {
204
+ if (reasoning.budgetTokens !== void 0) {
205
+ throw new core.LlmError(
206
+ `reasoning.budgetTokens is not supported for model "${model}" (it uses thinkingLevel, not thinkingBudget); use reasoning.effort instead.`,
207
+ { kind: "bad_request", retryable: false }
208
+ );
209
+ }
276
210
  let thinkingLevel;
277
211
  if (reasoning.effort !== void 0) {
278
212
  switch (reasoning.effort) {
@@ -292,45 +226,23 @@ function geminiAdapter(opts) {
292
226
  core.assertNever(reasoning.effort);
293
227
  }
294
228
  }
295
- if (reasoning.budgetTokens !== void 0) {
296
- warnings.push({
297
- type: "reasoning-mapping",
298
- quality: "approximate",
299
- details: "budgetTokens is not supported for gemini-3.x models; mapping effort to thinkingLevel instead"
300
- });
301
- }
302
229
  config.thinkingConfig = {
303
230
  ...thinkingLevel !== void 0 ? { thinkingLevel } : {},
304
231
  ...reasoning.includeThoughts === true ? { includeThoughts: true } : {}
305
232
  };
306
233
  } else {
307
- warnings.push({
308
- type: "reasoning-mapping",
309
- quality: "unsupported",
310
- details: `thinkingConfig not mapped for model "${model}"; unknown generation`
311
- });
234
+ throw new core.LlmError(
235
+ `Model "${model}" does not support reasoning/thinkingConfig.`,
236
+ { kind: "bad_request", retryable: false }
237
+ );
312
238
  }
313
239
  }
314
- let outputSchemaRequested = false;
315
- if (req.outputSchema !== void 0) {
316
- outputSchemaRequested = true;
317
- config.responseMimeType = "application/json";
318
- if (req.outputSchema["~standard"].vendor === "zod") {
319
- const geminiSchema = zodToGeminiSchema(req.outputSchema);
320
- if (geminiSchema !== void 0) {
321
- config.responseSchema = geminiSchema;
322
- } else {
323
- warnings.push({
324
- type: "unsupported-setting",
325
- setting: "output.schema",
326
- details: "Could not convert Zod schema to Gemini responseSchema; proceeding with responseMimeType only. Engine will still validate."
327
- });
328
- }
329
- } else {
330
- warnings.push({
331
- type: "other",
332
- message: `Native Gemini responseSchema conversion is not available for vendor "${req.outputSchema["~standard"].vendor}"; proceeding with responseMimeType only. Engine will validate output client-side via Standard Schema.`
333
- });
240
+ const structuredOutputRequested = req.outputJsonSchema !== void 0;
241
+ if (structuredOutputRequested) {
242
+ const nativeStructuredOutput = req.modelDescriptor?.capabilities?.nativeStructuredOutput !== false;
243
+ if (nativeStructuredOutput) {
244
+ config.responseMimeType = "application/json";
245
+ config.responseSchema = req.outputJsonSchema;
334
246
  }
335
247
  }
336
248
  const googleOpts = genConfig.providerOptions?.["google"];
@@ -338,27 +250,23 @@ function geminiAdapter(opts) {
338
250
  Object.assign(config, googleOpts);
339
251
  }
340
252
  if (req.modelDescriptor?.capabilities?.sampling === "fixed") {
341
- const droppedSampling = [];
253
+ const offendingSampling = [];
342
254
  if ("temperature" in config) {
343
- delete config.temperature;
344
- droppedSampling.push("temperature");
255
+ offendingSampling.push("temperature");
345
256
  }
346
257
  if ("topP" in config) {
347
- delete config.topP;
348
- droppedSampling.push("topP");
258
+ offendingSampling.push("topP");
349
259
  }
350
260
  if ("topK" in config) {
351
- delete config.topK;
352
- droppedSampling.push("topK");
261
+ offendingSampling.push("topK");
353
262
  }
354
- if (droppedSampling.length > 0) {
355
- warnings.push({
356
- type: "unsupported-setting",
357
- setting: droppedSampling.join(", "),
358
- details: `Sampling parameter(s) [${droppedSampling.join(
263
+ if (offendingSampling.length > 0) {
264
+ throw new core.LlmError(
265
+ `Sampling parameters [${offendingSampling.join(
359
266
  ", "
360
- )}] from providerOptions.google were stripped: this model has fixed sampling (Gemini 3.x) and the API rejects these fields.`
361
- });
267
+ )}] are not supported for model "${model}" (fixed sampling); they were supplied via providerOptions.google.`,
268
+ { kind: "bad_request", retryable: false }
269
+ );
362
270
  }
363
271
  }
364
272
  const configAsAny = config;
@@ -369,32 +277,41 @@ function geminiAdapter(opts) {
369
277
  }
370
278
  return false;
371
279
  });
372
- if (groundingRequested && req.outputSchema !== void 0) {
280
+ if (groundingRequested && structuredOutputRequested) {
373
281
  throw new core.LlmError(
374
- "Grounding (googleSearch) cannot be combined with structured output (output.schema) on Gemini; choose one.",
282
+ "Grounding (googleSearch) cannot be combined with structured output (output.jsonSchema) on Gemini; choose one.",
375
283
  { kind: "bad_request", retryable: false }
376
284
  );
377
285
  }
378
- let _flexTimeoutHandle;
379
- if (config.serviceTier === "flex" && genConfig.timeoutMs === void 0) {
380
- const flexController = new AbortController();
381
- const timeoutReason = new DOMException(
382
- `Flex timeout: call exceeded ${FLEX_DEFAULT_TIMEOUT_MS}ms client-side ceiling (@google/genai #1277 belt-and-suspenders)`,
383
- "TimeoutError"
384
- );
385
- _flexTimeoutHandle = setTimeout(() => {
386
- flexController.abort(timeoutReason);
387
- }, FLEX_DEFAULT_TIMEOUT_MS);
388
- if (ctx.signal !== void 0) {
389
- config.abortSignal = AbortSignal.any([flexController.signal, ctx.signal]);
390
- } else {
391
- config.abortSignal = flexController.signal;
286
+ let tierTimeoutHandle;
287
+ const clearTierTimeout = () => {
288
+ if (tierTimeoutHandle !== void 0) {
289
+ clearTimeout(tierTimeoutHandle);
290
+ tierTimeoutHandle = void 0;
392
291
  }
393
- } else if (ctx.signal !== void 0) {
394
- config.abortSignal = ctx.signal;
395
- }
292
+ };
293
+ const applyTierTimeout = (tier) => {
294
+ clearTierTimeout();
295
+ delete config.abortSignal;
296
+ const defaultTimeoutMs = genConfig.timeoutMs === void 0 ? tier === "flex" ? FLEX_DEFAULT_TIMEOUT_MS : tier === "standard" ? STANDARD_DEFAULT_TIMEOUT_MS : void 0 : void 0;
297
+ if (defaultTimeoutMs !== void 0) {
298
+ const tierController = new AbortController();
299
+ const tierLabel = tier === "standard" ? "Standard" : "Flex";
300
+ const timeoutReason = new DOMException(
301
+ `${tierLabel} timeout: call exceeded ${defaultTimeoutMs}ms client-side ceiling (@google/genai #1277 belt-and-suspenders)`,
302
+ "TimeoutError"
303
+ );
304
+ tierTimeoutHandle = setTimeout(() => {
305
+ tierController.abort(timeoutReason);
306
+ }, defaultTimeoutMs);
307
+ config.abortSignal = ctx.signal !== void 0 ? AbortSignal.any([tierController.signal, ctx.signal]) : tierController.signal;
308
+ } else if (ctx.signal !== void 0) {
309
+ config.abortSignal = ctx.signal;
310
+ }
311
+ };
312
+ applyTierTimeout(config.serviceTier);
396
313
  const callerHttpOptions = config.httpOptions;
397
- const computedTimeoutMs = genConfig.timeoutMs !== void 0 ? genConfig.timeoutMs + TRANSPORT_TIMEOUT_BUFFER_MS : genConfig.serviceTier === "flex" ? FLEX_DEFAULT_TIMEOUT_MS : void 0;
314
+ const computedTimeoutMs = genConfig.timeoutMs !== void 0 ? genConfig.timeoutMs + TRANSPORT_TIMEOUT_BUFFER_MS : config.serviceTier === "flex" ? FLEX_DEFAULT_TIMEOUT_MS : config.serviceTier === "standard" ? STANDARD_DEFAULT_TIMEOUT_MS : void 0;
398
315
  const mergedHttpOptions = {
399
316
  ...computedTimeoutMs !== void 0 ? { timeout: computedTimeoutMs } : {},
400
317
  ...callerHttpOptions
@@ -402,32 +319,71 @@ function geminiAdapter(opts) {
402
319
  if (Object.keys(mergedHttpOptions).length > 0) {
403
320
  config.httpOptions = mergedHttpOptions;
404
321
  }
405
- const params = {
406
- model,
407
- contents,
408
- config
409
- };
410
322
  let response;
411
- try {
323
+ let servedServiceTier = config.serviceTier;
324
+ const dispatch = async () => {
325
+ const dispatchConfig = {
326
+ ...config,
327
+ ...config.httpOptions !== void 0 ? { httpOptions: { ...config.httpOptions } } : {}
328
+ };
329
+ const params = {
330
+ model,
331
+ contents,
332
+ config: dispatchConfig
333
+ };
412
334
  const buildClient = opts?._clientFactory ?? buildGoogleClient;
413
335
  const client = opts?.client !== void 0 ? opts.client : await buildClient(ctx.auth);
414
336
  ctx.logger.debug(
415
- { model, configKeys: Object.keys(config) },
337
+ {
338
+ model,
339
+ configKeys: Object.keys(dispatchConfig),
340
+ serviceTier: dispatchConfig.serviceTier
341
+ },
416
342
  "llm.adapter.dispatch"
417
343
  );
418
- response = await client.models.generateContent(params);
344
+ return client.models.generateContent(params);
345
+ };
346
+ try {
347
+ response = await dispatch();
419
348
  } catch (rawErr) {
420
349
  const classified = core.classifyError(rawErr);
421
- throw new core.LlmError(classified.message, {
350
+ const typed = new core.LlmError(classified.message, {
422
351
  kind: classified.kind,
423
352
  retryable: classified.retryable,
424
353
  ...classified.httpStatus !== void 0 ? { httpStatus: classified.httpStatus } : {},
425
354
  ...classified.retryAfterMs !== void 0 ? { retryAfterMs: classified.retryAfterMs } : {},
426
355
  provider: "google",
427
- cause: classified.cause ?? rawErr
356
+ cause: classified.cause ?? rawErr,
357
+ ...servedServiceTier !== void 0 ? { servedServiceTier } : {}
428
358
  });
359
+ if (config.serviceTier === "flex" && genConfig.flexFallback !== false && isGeminiCapacityError(typed)) {
360
+ config.serviceTier = "standard";
361
+ servedServiceTier = "standard";
362
+ const fallbackTimeout = genConfig.timeoutMs !== void 0 ? genConfig.timeoutMs + TRANSPORT_TIMEOUT_BUFFER_MS : STANDARD_DEFAULT_TIMEOUT_MS;
363
+ config.httpOptions = {
364
+ timeout: fallbackTimeout,
365
+ ...callerHttpOptions
366
+ };
367
+ applyTierTimeout("standard");
368
+ try {
369
+ response = await dispatch();
370
+ } catch (fallbackRawErr) {
371
+ const fallbackClassified = core.classifyError(fallbackRawErr);
372
+ throw new core.LlmError(fallbackClassified.message, {
373
+ kind: fallbackClassified.kind,
374
+ retryable: fallbackClassified.retryable,
375
+ ...fallbackClassified.httpStatus !== void 0 ? { httpStatus: fallbackClassified.httpStatus } : {},
376
+ ...fallbackClassified.retryAfterMs !== void 0 ? { retryAfterMs: fallbackClassified.retryAfterMs } : {},
377
+ provider: "google",
378
+ cause: fallbackClassified.cause ?? fallbackRawErr,
379
+ servedServiceTier: "standard"
380
+ });
381
+ }
382
+ } else {
383
+ throw typed;
384
+ }
429
385
  } finally {
430
- if (_flexTimeoutHandle !== void 0) clearTimeout(_flexTimeoutHandle);
386
+ clearTierTimeout();
431
387
  }
432
388
  const hasBlockReason = response.promptFeedback?.blockReason !== void 0;
433
389
  const hasCandidates = response.candidates !== void 0 && response.candidates.length > 0;
@@ -470,7 +426,7 @@ function geminiAdapter(opts) {
470
426
  const text = textParts.join("");
471
427
  const reasoningText = thoughtParts.length > 0 ? thoughtParts.join("") : void 0;
472
428
  let rawStructured;
473
- if (outputSchemaRequested && text.length > 0) {
429
+ if (structuredOutputRequested && text.length > 0) {
474
430
  try {
475
431
  rawStructured = JSON.parse(text);
476
432
  } catch {
@@ -482,6 +438,7 @@ function geminiAdapter(opts) {
482
438
  model,
483
439
  usage,
484
440
  warnings,
441
+ ...servedServiceTier !== void 0 ? { servedServiceTier } : {},
485
442
  ...text.length > 0 ? { text } : {},
486
443
  ...reasoningText !== void 0 ? { reasoningText } : {},
487
444
  ...rawStructured !== void 0 ? { rawStructured } : {},
@@ -910,9 +867,10 @@ var GoogleCacheStore = class {
910
867
  exports.FLEX_DEFAULT_TIMEOUT_MS = FLEX_DEFAULT_TIMEOUT_MS;
911
868
  exports.GoogleCacheStore = GoogleCacheStore;
912
869
  exports.GoogleFileStore = GoogleFileStore;
870
+ exports.STANDARD_DEFAULT_TIMEOUT_MS = STANDARD_DEFAULT_TIMEOUT_MS;
913
871
  exports.TRANSPORT_TIMEOUT_BUFFER_MS = TRANSPORT_TIMEOUT_BUFFER_MS;
914
872
  exports.buildGoogleClient = buildGoogleClient;
915
873
  exports.geminiAdapter = geminiAdapter;
916
- exports.zodToGeminiSchema = zodToGeminiSchema;
874
+ exports.isGeminiCapacityError = isGeminiCapacityError;
917
875
  //# sourceMappingURL=index.cjs.map
918
876
  //# sourceMappingURL=index.cjs.map