@firebase/ai 2.2.1-20250829000033 → 2.2.1-canary.120a30838

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-20250829000033";
11
+ var version = "2.2.1-canary.120a30838";
12
12
 
13
13
  /**
14
14
  * @license
@@ -303,12 +303,30 @@ const ResponseModality = {
303
303
  /**
304
304
  * <b>(EXPERIMENTAL)</b>
305
305
  * Determines whether inference happens on-device or in-cloud.
306
+ *
307
+ * @remarks
308
+ * <b>PREFER_ON_DEVICE:</b> Attempt to make inference calls using an
309
+ * on-device model. If on-device inference is not available, the SDK
310
+ * will fall back to using a cloud-hosted model.
311
+ * <br/>
312
+ * <b>ONLY_ON_DEVICE:</b> Only attempt to make inference calls using an
313
+ * on-device model. The SDK will not fall back to a cloud-hosted model.
314
+ * If on-device inference is not available, inference methods will throw.
315
+ * <br/>
316
+ * <b>ONLY_IN_CLOUD:</b> Only attempt to make inference calls using a
317
+ * cloud-hosted model. The SDK will not fall back to an on-device model.
318
+ * <br/>
319
+ * <b>PREFER_IN_CLOUD:</b> Attempt to make inference calls to a
320
+ * cloud-hosted model. If not available, the SDK will fall back to an
321
+ * on-device model.
322
+ *
306
323
  * @public
307
324
  */
308
325
  const InferenceMode = {
309
326
  'PREFER_ON_DEVICE': 'prefer_on_device',
310
327
  'ONLY_ON_DEVICE': 'only_on_device',
311
- 'ONLY_IN_CLOUD': 'only_in_cloud'
328
+ 'ONLY_IN_CLOUD': 'only_in_cloud',
329
+ 'PREFER_IN_CLOUD': 'prefer_in_cloud'
312
330
  };
313
331
 
314
332
  /**
@@ -1738,6 +1756,72 @@ function aggregateResponses(responses) {
1738
1756
  return aggregatedResponse;
1739
1757
  }
1740
1758
 
1759
+ /**
1760
+ * @license
1761
+ * Copyright 2025 Google LLC
1762
+ *
1763
+ * Licensed under the Apache License, Version 2.0 (the "License");
1764
+ * you may not use this file except in compliance with the License.
1765
+ * You may obtain a copy of the License at
1766
+ *
1767
+ * http://www.apache.org/licenses/LICENSE-2.0
1768
+ *
1769
+ * Unless required by applicable law or agreed to in writing, software
1770
+ * distributed under the License is distributed on an "AS IS" BASIS,
1771
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1772
+ * See the License for the specific language governing permissions and
1773
+ * limitations under the License.
1774
+ */
1775
+ const errorsCausingFallback = [
1776
+ // most network errors
1777
+ AIErrorCode.FETCH_ERROR,
1778
+ // fallback code for all other errors in makeRequest
1779
+ AIErrorCode.ERROR,
1780
+ // error due to API not being enabled in project
1781
+ AIErrorCode.API_NOT_ENABLED
1782
+ ];
1783
+ /**
1784
+ * Dispatches a request to the appropriate backend (on-device or in-cloud)
1785
+ * based on the inference mode.
1786
+ *
1787
+ * @param request - The request to be sent.
1788
+ * @param chromeAdapter - The on-device model adapter.
1789
+ * @param onDeviceCall - The function to call for on-device inference.
1790
+ * @param inCloudCall - The function to call for in-cloud inference.
1791
+ * @returns The response from the backend.
1792
+ */
1793
+ async function callCloudOrDevice(request, chromeAdapter, onDeviceCall, inCloudCall) {
1794
+ if (!chromeAdapter) {
1795
+ return inCloudCall();
1796
+ }
1797
+ switch (chromeAdapter.mode) {
1798
+ case InferenceMode.ONLY_ON_DEVICE:
1799
+ if (await chromeAdapter.isAvailable(request)) {
1800
+ return onDeviceCall();
1801
+ }
1802
+ throw new AIError(AIErrorCode.UNSUPPORTED, 'Inference mode is ONLY_ON_DEVICE, but an on-device model is not available.');
1803
+ case InferenceMode.ONLY_IN_CLOUD:
1804
+ return inCloudCall();
1805
+ case InferenceMode.PREFER_IN_CLOUD:
1806
+ try {
1807
+ return await inCloudCall();
1808
+ }
1809
+ catch (e) {
1810
+ if (e instanceof AIError && errorsCausingFallback.includes(e.code)) {
1811
+ return onDeviceCall();
1812
+ }
1813
+ throw e;
1814
+ }
1815
+ case InferenceMode.PREFER_ON_DEVICE:
1816
+ if (await chromeAdapter.isAvailable(request)) {
1817
+ return onDeviceCall();
1818
+ }
1819
+ return inCloudCall();
1820
+ default:
1821
+ throw new AIError(AIErrorCode.ERROR, `Unexpected infererence mode: ${chromeAdapter.mode}`);
1822
+ }
1823
+ }
1824
+
1741
1825
  /**
1742
1826
  * @license
1743
1827
  * Copyright 2024 Google LLC
@@ -1762,13 +1846,7 @@ async function generateContentStreamOnCloud(apiSettings, model, params, requestO
1762
1846
  /* stream */ true, JSON.stringify(params), requestOptions);
1763
1847
  }
1764
1848
  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
- }
1849
+ const response = await callCloudOrDevice(params, chromeAdapter, () => chromeAdapter.generateContentStream(params), () => generateContentStreamOnCloud(apiSettings, model, params, requestOptions));
1772
1850
  return processStream(response, apiSettings); // TODO: Map streaming responses
1773
1851
  }
1774
1852
  async function generateContentOnCloud(apiSettings, model, params, requestOptions) {
@@ -1779,13 +1857,7 @@ async function generateContentOnCloud(apiSettings, model, params, requestOptions
1779
1857
  /* stream */ false, JSON.stringify(params), requestOptions);
1780
1858
  }
1781
1859
  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
- }
1860
+ const response = await callCloudOrDevice(params, chromeAdapter, () => chromeAdapter.generateContent(params), () => generateContentOnCloud(apiSettings, model, params, requestOptions));
1789
1861
  const generateContentResponse = await processGenerateContentResponse(response, apiSettings);
1790
1862
  const enhancedResponse = createEnhancedContentResponse(generateContentResponse);
1791
1863
  return {
@@ -2196,8 +2268,8 @@ async function countTokensOnCloud(apiSettings, model, params, requestOptions) {
2196
2268
  return response.json();
2197
2269
  }
2198
2270
  async function countTokens(apiSettings, model, params, chromeAdapter, requestOptions) {
2199
- if (chromeAdapter && (await chromeAdapter.isAvailable(params))) {
2200
- return (await chromeAdapter.countTokens(params)).json();
2271
+ if (chromeAdapter?.mode === InferenceMode.ONLY_ON_DEVICE) {
2272
+ throw new AIError(AIErrorCode.UNSUPPORTED, 'countTokens() is not supported for on-device models.');
2201
2273
  }
2202
2274
  return countTokensOnCloud(apiSettings, model, params, requestOptions);
2203
2275
  }