@google/genai 1.39.0 → 1.41.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.
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var pRetry = require('p-retry');
3
4
  var googleAuthLibrary = require('google-auth-library');
4
5
  var fs = require('fs');
5
6
  var fs$1 = require('fs/promises');
@@ -11639,10 +11640,22 @@ const CONTENT_TYPE_HEADER = 'Content-Type';
11639
11640
  const SERVER_TIMEOUT_HEADER = 'X-Server-Timeout';
11640
11641
  const USER_AGENT_HEADER = 'User-Agent';
11641
11642
  const GOOGLE_API_CLIENT_HEADER = 'x-goog-api-client';
11642
- const SDK_VERSION = '1.39.0'; // x-release-please-version
11643
+ const SDK_VERSION = '1.41.0'; // x-release-please-version
11643
11644
  const LIBRARY_LABEL = `google-genai-sdk/${SDK_VERSION}`;
11644
11645
  const VERTEX_AI_API_DEFAULT_VERSION = 'v1beta1';
11645
11646
  const GOOGLE_AI_API_DEFAULT_VERSION = 'v1beta';
11647
+ // Default retry options.
11648
+ // The config is based on https://cloud.google.com/storage/docs/retry-strategy.
11649
+ const DEFAULT_RETRY_ATTEMPTS = 5; // Including the initial call
11650
+ // LINT.IfChange
11651
+ const DEFAULT_RETRY_HTTP_STATUS_CODES = [
11652
+ 408, // Request timeout
11653
+ 429, // Too many requests
11654
+ 500, // Internal server error
11655
+ 502, // Bad gateway
11656
+ 503, // Service unavailable
11657
+ 504, // Gateway timeout
11658
+ ];
11646
11659
  /**
11647
11660
  * The ApiClient class is used to send requests to the Gemini API or Vertex AI
11648
11661
  * endpoints.
@@ -12027,8 +12040,25 @@ class ApiClient {
12027
12040
  });
12028
12041
  }
12029
12042
  async apiCall(url, requestInit) {
12030
- return fetch(url, requestInit).catch((e) => {
12031
- throw new Error(`exception ${e} sending request`);
12043
+ var _a;
12044
+ if (!this.clientOptions.httpOptions ||
12045
+ !this.clientOptions.httpOptions.retryOptions) {
12046
+ return fetch(url, requestInit);
12047
+ }
12048
+ const retryOptions = this.clientOptions.httpOptions.retryOptions;
12049
+ const runFetch = async () => {
12050
+ const response = await fetch(url, requestInit);
12051
+ if (response.ok) {
12052
+ return response;
12053
+ }
12054
+ if (DEFAULT_RETRY_HTTP_STATUS_CODES.includes(response.status)) {
12055
+ throw new Error(`Retryable HTTP Error: ${response.statusText}`);
12056
+ }
12057
+ throw new pRetry.AbortError(`Non-retryable exception ${response.statusText} sending request`);
12058
+ };
12059
+ return pRetry(runFetch, {
12060
+ // Retry attempts is one less than the number of total attempts.
12061
+ retries: ((_a = retryOptions.attempts) !== null && _a !== void 0 ? _a : DEFAULT_RETRY_ATTEMPTS) - 1,
12032
12062
  });
12033
12063
  }
12034
12064
  getDefaultHeaders() {
@@ -17412,6 +17442,11 @@ async function defaultParseResponse(client, props) {
17412
17442
  const mediaType = (_a = contentType === null || contentType === void 0 ? void 0 : contentType.split(';')[0]) === null || _a === void 0 ? void 0 : _a.trim();
17413
17443
  const isJSON = (mediaType === null || mediaType === void 0 ? void 0 : mediaType.includes('application/json')) || (mediaType === null || mediaType === void 0 ? void 0 : mediaType.endsWith('+json'));
17414
17444
  if (isJSON) {
17445
+ const contentLength = response.headers.get('content-length');
17446
+ if (contentLength === '0') {
17447
+ // if there is no content we can't do anything
17448
+ return undefined;
17449
+ }
17415
17450
  const json = await response.json();
17416
17451
  return json;
17417
17452
  }
@@ -17871,9 +17906,10 @@ class BaseGeminiNextGenAPIClient {
17871
17906
  }
17872
17907
  async fetchWithTimeout(url, init, ms, controller) {
17873
17908
  const _b = init || {}, { signal, method } = _b, options = __rest(_b, ["signal", "method"]);
17909
+ const abort = this._makeAbort(controller);
17874
17910
  if (signal)
17875
- signal.addEventListener('abort', () => controller.abort());
17876
- const timeout = setTimeout(() => controller.abort(), ms);
17911
+ signal.addEventListener('abort', abort, { once: true });
17912
+ const timeout = setTimeout(abort, ms);
17877
17913
  const isReadableBody = (globalThis.ReadableStream && options.body instanceof globalThis.ReadableStream) ||
17878
17914
  (typeof options.body === 'object' && options.body !== null && Symbol.asyncIterator in options.body);
17879
17915
  const fetchOptions = Object.assign(Object.assign(Object.assign({ signal: controller.signal }, (isReadableBody ? { duplex: 'half' } : {})), { method: 'GET' }), options);
@@ -17986,6 +18022,11 @@ class BaseGeminiNextGenAPIClient {
17986
18022
  this.validateHeaders(headers);
17987
18023
  return headers.values;
17988
18024
  }
18025
+ _makeAbort(controller) {
18026
+ // note: we can't just inline this method inside `fetchWithTimeout()` because then the closure
18027
+ // would capture all request options, and cause a memory leak.
18028
+ return () => controller.abort();
18029
+ }
17989
18030
  buildBody({ options: { body, headers: rawHeaders } }) {
17990
18031
  if (!body) {
17991
18032
  return { bodyHeaders: undefined, body: undefined };
@@ -18335,6 +18376,9 @@ function createTuningJobConfigToMldev(fromObject, parentObject, _rootObject) {
18335
18376
  if (getValueByPath(fromObject, ['outputUri']) !== undefined) {
18336
18377
  throw new Error('outputUri parameter is not supported in Gemini API.');
18337
18378
  }
18379
+ if (getValueByPath(fromObject, ['encryptionSpec']) !== undefined) {
18380
+ throw new Error('encryptionSpec parameter is not supported in Gemini API.');
18381
+ }
18338
18382
  return toObject;
18339
18383
  }
18340
18384
  function createTuningJobConfigToVertex(fromObject, parentObject, rootObject) {
@@ -18570,6 +18614,12 @@ function createTuningJobConfigToVertex(fromObject, parentObject, rootObject) {
18570
18614
  if (parentObject !== undefined && fromOutputUri != null) {
18571
18615
  setValueByPath(parentObject, ['outputUri'], fromOutputUri);
18572
18616
  }
18617
+ const fromEncryptionSpec = getValueByPath(fromObject, [
18618
+ 'encryptionSpec',
18619
+ ]);
18620
+ if (parentObject !== undefined && fromEncryptionSpec != null) {
18621
+ setValueByPath(parentObject, ['encryptionSpec'], fromEncryptionSpec);
18622
+ }
18573
18623
  return toObject;
18574
18624
  }
18575
18625
  function createTuningJobParametersPrivateToMldev(fromObject, rootObject) {
@@ -19822,6 +19872,7 @@ const LANGUAGE_LABEL_PREFIX = 'gl-node/';
19822
19872
  */
19823
19873
  class GoogleGenAI {
19824
19874
  get interactions() {
19875
+ var _a;
19825
19876
  if (this._interactions !== undefined) {
19826
19877
  return this._interactions;
19827
19878
  }
@@ -19838,6 +19889,7 @@ class GoogleGenAI {
19838
19889
  clientAdapter: this.apiClient,
19839
19890
  defaultHeaders: this.apiClient.getDefaultHeaders(),
19840
19891
  timeout: httpOpts === null || httpOpts === void 0 ? void 0 : httpOpts.timeout,
19892
+ maxRetries: (_a = httpOpts === null || httpOpts === void 0 ? void 0 : httpOpts.retryOptions) === null || _a === void 0 ? void 0 : _a.attempts,
19841
19893
  });
19842
19894
  this._interactions = nextGenClient.interactions;
19843
19895
  return this._interactions;
@@ -1,3 +1,4 @@
1
+ import pRetry, { AbortError } from 'p-retry';
1
2
  import { GoogleAuth } from 'google-auth-library';
2
3
  import { createWriteStream } from 'fs';
3
4
  import * as fs from 'fs/promises';
@@ -11617,10 +11618,22 @@ const CONTENT_TYPE_HEADER = 'Content-Type';
11617
11618
  const SERVER_TIMEOUT_HEADER = 'X-Server-Timeout';
11618
11619
  const USER_AGENT_HEADER = 'User-Agent';
11619
11620
  const GOOGLE_API_CLIENT_HEADER = 'x-goog-api-client';
11620
- const SDK_VERSION = '1.39.0'; // x-release-please-version
11621
+ const SDK_VERSION = '1.41.0'; // x-release-please-version
11621
11622
  const LIBRARY_LABEL = `google-genai-sdk/${SDK_VERSION}`;
11622
11623
  const VERTEX_AI_API_DEFAULT_VERSION = 'v1beta1';
11623
11624
  const GOOGLE_AI_API_DEFAULT_VERSION = 'v1beta';
11625
+ // Default retry options.
11626
+ // The config is based on https://cloud.google.com/storage/docs/retry-strategy.
11627
+ const DEFAULT_RETRY_ATTEMPTS = 5; // Including the initial call
11628
+ // LINT.IfChange
11629
+ const DEFAULT_RETRY_HTTP_STATUS_CODES = [
11630
+ 408, // Request timeout
11631
+ 429, // Too many requests
11632
+ 500, // Internal server error
11633
+ 502, // Bad gateway
11634
+ 503, // Service unavailable
11635
+ 504, // Gateway timeout
11636
+ ];
11624
11637
  /**
11625
11638
  * The ApiClient class is used to send requests to the Gemini API or Vertex AI
11626
11639
  * endpoints.
@@ -12005,8 +12018,25 @@ class ApiClient {
12005
12018
  });
12006
12019
  }
12007
12020
  async apiCall(url, requestInit) {
12008
- return fetch(url, requestInit).catch((e) => {
12009
- throw new Error(`exception ${e} sending request`);
12021
+ var _a;
12022
+ if (!this.clientOptions.httpOptions ||
12023
+ !this.clientOptions.httpOptions.retryOptions) {
12024
+ return fetch(url, requestInit);
12025
+ }
12026
+ const retryOptions = this.clientOptions.httpOptions.retryOptions;
12027
+ const runFetch = async () => {
12028
+ const response = await fetch(url, requestInit);
12029
+ if (response.ok) {
12030
+ return response;
12031
+ }
12032
+ if (DEFAULT_RETRY_HTTP_STATUS_CODES.includes(response.status)) {
12033
+ throw new Error(`Retryable HTTP Error: ${response.statusText}`);
12034
+ }
12035
+ throw new AbortError(`Non-retryable exception ${response.statusText} sending request`);
12036
+ };
12037
+ return pRetry(runFetch, {
12038
+ // Retry attempts is one less than the number of total attempts.
12039
+ retries: ((_a = retryOptions.attempts) !== null && _a !== void 0 ? _a : DEFAULT_RETRY_ATTEMPTS) - 1,
12010
12040
  });
12011
12041
  }
12012
12042
  getDefaultHeaders() {
@@ -17390,6 +17420,11 @@ async function defaultParseResponse(client, props) {
17390
17420
  const mediaType = (_a = contentType === null || contentType === void 0 ? void 0 : contentType.split(';')[0]) === null || _a === void 0 ? void 0 : _a.trim();
17391
17421
  const isJSON = (mediaType === null || mediaType === void 0 ? void 0 : mediaType.includes('application/json')) || (mediaType === null || mediaType === void 0 ? void 0 : mediaType.endsWith('+json'));
17392
17422
  if (isJSON) {
17423
+ const contentLength = response.headers.get('content-length');
17424
+ if (contentLength === '0') {
17425
+ // if there is no content we can't do anything
17426
+ return undefined;
17427
+ }
17393
17428
  const json = await response.json();
17394
17429
  return json;
17395
17430
  }
@@ -17849,9 +17884,10 @@ class BaseGeminiNextGenAPIClient {
17849
17884
  }
17850
17885
  async fetchWithTimeout(url, init, ms, controller) {
17851
17886
  const _b = init || {}, { signal, method } = _b, options = __rest(_b, ["signal", "method"]);
17887
+ const abort = this._makeAbort(controller);
17852
17888
  if (signal)
17853
- signal.addEventListener('abort', () => controller.abort());
17854
- const timeout = setTimeout(() => controller.abort(), ms);
17889
+ signal.addEventListener('abort', abort, { once: true });
17890
+ const timeout = setTimeout(abort, ms);
17855
17891
  const isReadableBody = (globalThis.ReadableStream && options.body instanceof globalThis.ReadableStream) ||
17856
17892
  (typeof options.body === 'object' && options.body !== null && Symbol.asyncIterator in options.body);
17857
17893
  const fetchOptions = Object.assign(Object.assign(Object.assign({ signal: controller.signal }, (isReadableBody ? { duplex: 'half' } : {})), { method: 'GET' }), options);
@@ -17964,6 +18000,11 @@ class BaseGeminiNextGenAPIClient {
17964
18000
  this.validateHeaders(headers);
17965
18001
  return headers.values;
17966
18002
  }
18003
+ _makeAbort(controller) {
18004
+ // note: we can't just inline this method inside `fetchWithTimeout()` because then the closure
18005
+ // would capture all request options, and cause a memory leak.
18006
+ return () => controller.abort();
18007
+ }
17967
18008
  buildBody({ options: { body, headers: rawHeaders } }) {
17968
18009
  if (!body) {
17969
18010
  return { bodyHeaders: undefined, body: undefined };
@@ -18313,6 +18354,9 @@ function createTuningJobConfigToMldev(fromObject, parentObject, _rootObject) {
18313
18354
  if (getValueByPath(fromObject, ['outputUri']) !== undefined) {
18314
18355
  throw new Error('outputUri parameter is not supported in Gemini API.');
18315
18356
  }
18357
+ if (getValueByPath(fromObject, ['encryptionSpec']) !== undefined) {
18358
+ throw new Error('encryptionSpec parameter is not supported in Gemini API.');
18359
+ }
18316
18360
  return toObject;
18317
18361
  }
18318
18362
  function createTuningJobConfigToVertex(fromObject, parentObject, rootObject) {
@@ -18548,6 +18592,12 @@ function createTuningJobConfigToVertex(fromObject, parentObject, rootObject) {
18548
18592
  if (parentObject !== undefined && fromOutputUri != null) {
18549
18593
  setValueByPath(parentObject, ['outputUri'], fromOutputUri);
18550
18594
  }
18595
+ const fromEncryptionSpec = getValueByPath(fromObject, [
18596
+ 'encryptionSpec',
18597
+ ]);
18598
+ if (parentObject !== undefined && fromEncryptionSpec != null) {
18599
+ setValueByPath(parentObject, ['encryptionSpec'], fromEncryptionSpec);
18600
+ }
18551
18601
  return toObject;
18552
18602
  }
18553
18603
  function createTuningJobParametersPrivateToMldev(fromObject, rootObject) {
@@ -19800,6 +19850,7 @@ const LANGUAGE_LABEL_PREFIX = 'gl-node/';
19800
19850
  */
19801
19851
  class GoogleGenAI {
19802
19852
  get interactions() {
19853
+ var _a;
19803
19854
  if (this._interactions !== undefined) {
19804
19855
  return this._interactions;
19805
19856
  }
@@ -19816,6 +19867,7 @@ class GoogleGenAI {
19816
19867
  clientAdapter: this.apiClient,
19817
19868
  defaultHeaders: this.apiClient.getDefaultHeaders(),
19818
19869
  timeout: httpOpts === null || httpOpts === void 0 ? void 0 : httpOpts.timeout,
19870
+ maxRetries: (_a = httpOpts === null || httpOpts === void 0 ? void 0 : httpOpts.retryOptions) === null || _a === void 0 ? void 0 : _a.attempts,
19819
19871
  });
19820
19872
  this._interactions = nextGenClient.interactions;
19821
19873
  return this._interactions;