@firebase/ai 2.2.1 → 2.3.0-canary.0ffcb26af

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.
@@ -8,7 +8,7 @@ var util = require('@firebase/util');
8
8
  var logger$1 = require('@firebase/logger');
9
9
 
10
10
  var name = "@firebase/ai";
11
- var version = "2.2.1";
11
+ var version = "2.3.0-canary.0ffcb26af";
12
12
 
13
13
  /**
14
14
  * @license
@@ -301,14 +301,51 @@ const ResponseModality = {
301
301
  AUDIO: 'AUDIO'
302
302
  };
303
303
  /**
304
- * <b>(EXPERIMENTAL)</b>
305
304
  * Determines whether inference happens on-device or in-cloud.
306
- * @public
305
+ *
306
+ * @remarks
307
+ * <b>PREFER_ON_DEVICE:</b> Attempt to make inference calls using an
308
+ * on-device model. If on-device inference is not available, the SDK
309
+ * will fall back to using a cloud-hosted model.
310
+ * <br/>
311
+ * <b>ONLY_ON_DEVICE:</b> Only attempt to make inference calls using an
312
+ * on-device model. The SDK will not fall back to a cloud-hosted model.
313
+ * If on-device inference is not available, inference methods will throw.
314
+ * <br/>
315
+ * <b>ONLY_IN_CLOUD:</b> Only attempt to make inference calls using a
316
+ * cloud-hosted model. The SDK will not fall back to an on-device model.
317
+ * <br/>
318
+ * <b>PREFER_IN_CLOUD:</b> Attempt to make inference calls to a
319
+ * cloud-hosted model. If not available, the SDK will fall back to an
320
+ * on-device model.
321
+ *
322
+ * @beta
307
323
  */
308
324
  const InferenceMode = {
309
325
  'PREFER_ON_DEVICE': 'prefer_on_device',
310
326
  'ONLY_ON_DEVICE': 'only_on_device',
311
- 'ONLY_IN_CLOUD': 'only_in_cloud'
327
+ 'ONLY_IN_CLOUD': 'only_in_cloud',
328
+ 'PREFER_IN_CLOUD': 'prefer_in_cloud'
329
+ };
330
+ /**
331
+ * Represents the result of the code execution.
332
+ *
333
+ * @public
334
+ */
335
+ const Outcome = {
336
+ UNSPECIFIED: 'OUTCOME_UNSPECIFIED',
337
+ OK: 'OUTCOME_OK',
338
+ FAILED: 'OUTCOME_FAILED',
339
+ DEADLINE_EXCEEDED: 'OUTCOME_DEADLINE_EXCEEDED'
340
+ };
341
+ /**
342
+ * The programming language of the code.
343
+ *
344
+ * @public
345
+ */
346
+ const Language = {
347
+ UNSPECIFIED: 'LANGUAGE_UNSPECIFIED',
348
+ PYTHON: 'PYTHON'
312
349
  };
313
350
 
314
351
  /**
@@ -327,6 +364,45 @@ const InferenceMode = {
327
364
  * See the License for the specific language governing permissions and
328
365
  * limitations under the License.
329
366
  */
367
+ /**
368
+ * The status of a URL retrieval.
369
+ *
370
+ * @remarks
371
+ * <b>URL_RETRIEVAL_STATUS_UNSPECIFIED:</b> Unspecified retrieval status.
372
+ * <br/>
373
+ * <b>URL_RETRIEVAL_STATUS_SUCCESS:</b> The URL retrieval was successful.
374
+ * <br/>
375
+ * <b>URL_RETRIEVAL_STATUS_ERROR:</b> The URL retrieval failed.
376
+ * <br/>
377
+ * <b>URL_RETRIEVAL_STATUS_PAYWALL:</b> The URL retrieval failed because the content is behind a paywall.
378
+ * <br/>
379
+ * <b>URL_RETRIEVAL_STATUS_UNSAFE:</b> The URL retrieval failed because the content is unsafe.
380
+ * <br/>
381
+ *
382
+ * @beta
383
+ */
384
+ const URLRetrievalStatus = {
385
+ /**
386
+ * Unspecified retrieval status.
387
+ */
388
+ URL_RETRIEVAL_STATUS_UNSPECIFIED: 'URL_RETRIEVAL_STATUS_UNSPECIFIED',
389
+ /**
390
+ * The URL retrieval was successful.
391
+ */
392
+ URL_RETRIEVAL_STATUS_SUCCESS: 'URL_RETRIEVAL_STATUS_SUCCESS',
393
+ /**
394
+ * The URL retrieval failed.
395
+ */
396
+ URL_RETRIEVAL_STATUS_ERROR: 'URL_RETRIEVAL_STATUS_ERROR',
397
+ /**
398
+ * The URL retrieval failed because the content is behind a paywall.
399
+ */
400
+ URL_RETRIEVAL_STATUS_PAYWALL: 'URL_RETRIEVAL_STATUS_PAYWALL',
401
+ /**
402
+ * The URL retrieval failed because the content is unsafe.
403
+ */
404
+ URL_RETRIEVAL_STATUS_UNSAFE: 'URL_RETRIEVAL_STATUS_UNSAFE'
405
+ };
330
406
  /**
331
407
  * The types of responses that can be returned by {@link LiveSession.receive}.
332
408
  *
@@ -1530,7 +1606,8 @@ function mapGenerateContentCandidates(candidates) {
1530
1606
  finishMessage: candidate.finishMessage,
1531
1607
  safetyRatings: mappedSafetyRatings,
1532
1608
  citationMetadata,
1533
- groundingMetadata: candidate.groundingMetadata
1609
+ groundingMetadata: candidate.groundingMetadata,
1610
+ urlContextMetadata: candidate.urlContextMetadata
1534
1611
  };
1535
1612
  mappedCandidates.push(mappedCandidate);
1536
1613
  });
@@ -1700,6 +1777,17 @@ function aggregateResponses(responses) {
1700
1777
  candidate.safetyRatings;
1701
1778
  aggregatedResponse.candidates[i].groundingMetadata =
1702
1779
  candidate.groundingMetadata;
1780
+ // The urlContextMetadata object is defined in the first chunk of the response stream.
1781
+ // In all subsequent chunks, the urlContextMetadata object will be undefined. We need to
1782
+ // make sure that we don't overwrite the first value urlContextMetadata object with undefined.
1783
+ // FIXME: What happens if we receive a second, valid urlContextMetadata object?
1784
+ const urlContextMetadata = candidate.urlContextMetadata;
1785
+ if (typeof urlContextMetadata === 'object' &&
1786
+ urlContextMetadata !== null &&
1787
+ Object.keys(urlContextMetadata).length > 0) {
1788
+ aggregatedResponse.candidates[i].urlContextMetadata =
1789
+ urlContextMetadata;
1790
+ }
1703
1791
  /**
1704
1792
  * Candidates should always have content and parts, but this handles
1705
1793
  * possible malformed responses.
@@ -1738,6 +1826,72 @@ function aggregateResponses(responses) {
1738
1826
  return aggregatedResponse;
1739
1827
  }
1740
1828
 
1829
+ /**
1830
+ * @license
1831
+ * Copyright 2025 Google LLC
1832
+ *
1833
+ * Licensed under the Apache License, Version 2.0 (the "License");
1834
+ * you may not use this file except in compliance with the License.
1835
+ * You may obtain a copy of the License at
1836
+ *
1837
+ * http://www.apache.org/licenses/LICENSE-2.0
1838
+ *
1839
+ * Unless required by applicable law or agreed to in writing, software
1840
+ * distributed under the License is distributed on an "AS IS" BASIS,
1841
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1842
+ * See the License for the specific language governing permissions and
1843
+ * limitations under the License.
1844
+ */
1845
+ const errorsCausingFallback = [
1846
+ // most network errors
1847
+ AIErrorCode.FETCH_ERROR,
1848
+ // fallback code for all other errors in makeRequest
1849
+ AIErrorCode.ERROR,
1850
+ // error due to API not being enabled in project
1851
+ AIErrorCode.API_NOT_ENABLED
1852
+ ];
1853
+ /**
1854
+ * Dispatches a request to the appropriate backend (on-device or in-cloud)
1855
+ * based on the inference mode.
1856
+ *
1857
+ * @param request - The request to be sent.
1858
+ * @param chromeAdapter - The on-device model adapter.
1859
+ * @param onDeviceCall - The function to call for on-device inference.
1860
+ * @param inCloudCall - The function to call for in-cloud inference.
1861
+ * @returns The response from the backend.
1862
+ */
1863
+ async function callCloudOrDevice(request, chromeAdapter, onDeviceCall, inCloudCall) {
1864
+ if (!chromeAdapter) {
1865
+ return inCloudCall();
1866
+ }
1867
+ switch (chromeAdapter.mode) {
1868
+ case InferenceMode.ONLY_ON_DEVICE:
1869
+ if (await chromeAdapter.isAvailable(request)) {
1870
+ return onDeviceCall();
1871
+ }
1872
+ throw new AIError(AIErrorCode.UNSUPPORTED, 'Inference mode is ONLY_ON_DEVICE, but an on-device model is not available.');
1873
+ case InferenceMode.ONLY_IN_CLOUD:
1874
+ return inCloudCall();
1875
+ case InferenceMode.PREFER_IN_CLOUD:
1876
+ try {
1877
+ return await inCloudCall();
1878
+ }
1879
+ catch (e) {
1880
+ if (e instanceof AIError && errorsCausingFallback.includes(e.code)) {
1881
+ return onDeviceCall();
1882
+ }
1883
+ throw e;
1884
+ }
1885
+ case InferenceMode.PREFER_ON_DEVICE:
1886
+ if (await chromeAdapter.isAvailable(request)) {
1887
+ return onDeviceCall();
1888
+ }
1889
+ return inCloudCall();
1890
+ default:
1891
+ throw new AIError(AIErrorCode.ERROR, `Unexpected infererence mode: ${chromeAdapter.mode}`);
1892
+ }
1893
+ }
1894
+
1741
1895
  /**
1742
1896
  * @license
1743
1897
  * Copyright 2024 Google LLC
@@ -1762,13 +1916,7 @@ async function generateContentStreamOnCloud(apiSettings, model, params, requestO
1762
1916
  /* stream */ true, JSON.stringify(params), requestOptions);
1763
1917
  }
1764
1918
  async function generateContentStream(apiSettings, model, params, chromeAdapter, requestOptions) {
1765
- let response;
1766
- if (chromeAdapter && (await chromeAdapter.isAvailable(params))) {
1767
- response = await chromeAdapter.generateContentStream(params);
1768
- }
1769
- else {
1770
- response = await generateContentStreamOnCloud(apiSettings, model, params, requestOptions);
1771
- }
1919
+ const response = await callCloudOrDevice(params, chromeAdapter, () => chromeAdapter.generateContentStream(params), () => generateContentStreamOnCloud(apiSettings, model, params, requestOptions));
1772
1920
  return processStream(response, apiSettings); // TODO: Map streaming responses
1773
1921
  }
1774
1922
  async function generateContentOnCloud(apiSettings, model, params, requestOptions) {
@@ -1779,13 +1927,7 @@ async function generateContentOnCloud(apiSettings, model, params, requestOptions
1779
1927
  /* stream */ false, JSON.stringify(params), requestOptions);
1780
1928
  }
1781
1929
  async function generateContent(apiSettings, model, params, chromeAdapter, requestOptions) {
1782
- let response;
1783
- if (chromeAdapter && (await chromeAdapter.isAvailable(params))) {
1784
- response = await chromeAdapter.generateContent(params);
1785
- }
1786
- else {
1787
- response = await generateContentOnCloud(apiSettings, model, params, requestOptions);
1788
- }
1930
+ const response = await callCloudOrDevice(params, chromeAdapter, () => chromeAdapter.generateContent(params), () => generateContentOnCloud(apiSettings, model, params, requestOptions));
1789
1931
  const generateContentResponse = await processGenerateContentResponse(response, apiSettings);
1790
1932
  const enhancedResponse = createEnhancedContentResponse(generateContentResponse);
1791
1933
  return {
@@ -1995,7 +2137,9 @@ function validateChatHistory(history) {
1995
2137
  functionCall: 0,
1996
2138
  functionResponse: 0,
1997
2139
  thought: 0,
1998
- thoughtSignature: 0
2140
+ thoughtSignature: 0,
2141
+ executableCode: 0,
2142
+ codeExecutionResult: 0
1999
2143
  };
2000
2144
  for (const part of parts) {
2001
2145
  for (const key of VALID_PART_FIELDS) {
@@ -2196,8 +2340,8 @@ async function countTokensOnCloud(apiSettings, model, params, requestOptions) {
2196
2340
  return response.json();
2197
2341
  }
2198
2342
  async function countTokens(apiSettings, model, params, chromeAdapter, requestOptions) {
2199
- if (chromeAdapter && (await chromeAdapter.isAvailable(params))) {
2200
- return (await chromeAdapter.countTokens(params)).json();
2343
+ if (chromeAdapter?.mode === InferenceMode.ONLY_ON_DEVICE) {
2344
+ throw new AIError(AIErrorCode.UNSUPPORTED, 'countTokens() is not supported for on-device models.');
2201
2345
  }
2202
2346
  return countTokensOnCloud(apiSettings, model, params, requestOptions);
2203
2347
  }
@@ -3659,17 +3803,20 @@ exports.ImagenPersonFilterLevel = ImagenPersonFilterLevel;
3659
3803
  exports.ImagenSafetyFilterLevel = ImagenSafetyFilterLevel;
3660
3804
  exports.InferenceMode = InferenceMode;
3661
3805
  exports.IntegerSchema = IntegerSchema;
3806
+ exports.Language = Language;
3662
3807
  exports.LiveGenerativeModel = LiveGenerativeModel;
3663
3808
  exports.LiveResponseType = LiveResponseType;
3664
3809
  exports.LiveSession = LiveSession;
3665
3810
  exports.Modality = Modality;
3666
3811
  exports.NumberSchema = NumberSchema;
3667
3812
  exports.ObjectSchema = ObjectSchema;
3813
+ exports.Outcome = Outcome;
3668
3814
  exports.POSSIBLE_ROLES = POSSIBLE_ROLES;
3669
3815
  exports.ResponseModality = ResponseModality;
3670
3816
  exports.Schema = Schema;
3671
3817
  exports.SchemaType = SchemaType;
3672
3818
  exports.StringSchema = StringSchema;
3819
+ exports.URLRetrievalStatus = URLRetrievalStatus;
3673
3820
  exports.VertexAIBackend = VertexAIBackend;
3674
3821
  exports.getAI = getAI;
3675
3822
  exports.getGenerativeModel = getGenerativeModel;