@firebase/ai 2.3.0 → 2.4.0-canary.b7e18d0ff

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.
Files changed (37) hide show
  1. package/dist/ai-public.d.ts +156 -29
  2. package/dist/ai.d.ts +157 -29
  3. package/dist/esm/index.esm.js +108 -34
  4. package/dist/esm/index.esm.js.map +1 -1
  5. package/dist/esm/src/api.d.ts +1 -1
  6. package/dist/esm/src/methods/live-session-helpers.d.ts +2 -2
  7. package/dist/esm/src/methods/live-session.d.ts +10 -1
  8. package/dist/esm/src/models/imagen-model.d.ts +2 -2
  9. package/dist/esm/src/requests/imagen-image-format.d.ts +3 -3
  10. package/dist/esm/src/types/content.d.ts +4 -4
  11. package/dist/esm/src/types/enums.d.ts +4 -4
  12. package/dist/esm/src/types/googleai.d.ts +2 -1
  13. package/dist/esm/src/types/imagen/requests.d.ts +9 -9
  14. package/dist/esm/src/types/imagen/responses.d.ts +3 -3
  15. package/dist/esm/src/types/live-responses.d.ts +9 -1
  16. package/dist/esm/src/types/requests.d.ts +22 -2
  17. package/dist/esm/src/types/responses.d.ts +92 -0
  18. package/dist/index.cjs.js +108 -33
  19. package/dist/index.cjs.js.map +1 -1
  20. package/dist/index.node.cjs.js +108 -33
  21. package/dist/index.node.cjs.js.map +1 -1
  22. package/dist/index.node.mjs +108 -34
  23. package/dist/index.node.mjs.map +1 -1
  24. package/dist/src/api.d.ts +1 -1
  25. package/dist/src/methods/live-session-helpers.d.ts +2 -2
  26. package/dist/src/methods/live-session.d.ts +10 -1
  27. package/dist/src/models/imagen-model.d.ts +2 -2
  28. package/dist/src/requests/imagen-image-format.d.ts +3 -3
  29. package/dist/src/types/content.d.ts +4 -4
  30. package/dist/src/types/enums.d.ts +4 -4
  31. package/dist/src/types/googleai.d.ts +2 -1
  32. package/dist/src/types/imagen/requests.d.ts +9 -9
  33. package/dist/src/types/imagen/responses.d.ts +3 -3
  34. package/dist/src/types/live-responses.d.ts +9 -1
  35. package/dist/src/types/requests.d.ts +22 -2
  36. package/dist/src/types/responses.d.ts +92 -0
  37. package/package.json +8 -8
@@ -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.3.0";
11
+ var version = "2.4.0-canary.b7e18d0ff";
12
12
 
13
13
  /**
14
14
  * @license
@@ -330,7 +330,7 @@ const InferenceMode = {
330
330
  /**
331
331
  * Represents the result of the code execution.
332
332
  *
333
- * @public
333
+ * @beta
334
334
  */
335
335
  const Outcome = {
336
336
  UNSPECIFIED: 'OUTCOME_UNSPECIFIED',
@@ -341,7 +341,7 @@ const Outcome = {
341
341
  /**
342
342
  * The programming language of the code.
343
343
  *
344
- * @public
344
+ * @beta
345
345
  */
346
346
  const Language = {
347
347
  UNSPECIFIED: 'LANGUAGE_UNSPECIFIED',
@@ -364,6 +364,45 @@ const Language = {
364
364
  * See the License for the specific language governing permissions and
365
365
  * limitations under the License.
366
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
+ };
367
406
  /**
368
407
  * The types of responses that can be returned by {@link LiveSession.receive}.
369
408
  *
@@ -490,7 +529,7 @@ const SchemaType = {
490
529
  * and the {@link https://cloud.google.com/vertex-ai/generative-ai/docs/image/responsible-ai-imagen#safety-filters | Responsible AI and usage guidelines}
491
530
  * for more details.
492
531
  *
493
- * @beta
532
+ * @public
494
533
  */
495
534
  const ImagenSafetyFilterLevel = {
496
535
  /**
@@ -519,7 +558,7 @@ const ImagenSafetyFilterLevel = {
519
558
  * See the <a href="http://firebase.google.com/docs/vertex-ai/generate-images">personGeneration</a>
520
559
  * documentation for more details.
521
560
  *
522
- * @beta
561
+ * @public
523
562
  */
524
563
  const ImagenPersonFilterLevel = {
525
564
  /**
@@ -552,7 +591,7 @@ const ImagenPersonFilterLevel = {
552
591
  * See the {@link http://firebase.google.com/docs/vertex-ai/generate-images | documentation }
553
592
  * for more details and examples of the supported aspect ratios.
554
593
  *
555
- * @beta
594
+ * @public
556
595
  */
557
596
  const ImagenAspectRatio = {
558
597
  /**
@@ -1557,7 +1596,7 @@ function mapGenerateContentCandidates(candidates) {
1557
1596
  // videoMetadata is not supported.
1558
1597
  // Throw early since developers may send a long video as input and only expect to pay
1559
1598
  // for inference on a small portion of the video.
1560
- if (candidate.content?.parts.some(part => part?.videoMetadata)) {
1599
+ if (candidate.content?.parts?.some(part => part?.videoMetadata)) {
1561
1600
  throw new AIError(AIErrorCode.UNSUPPORTED, 'Part.videoMetadata is not supported in the Gemini Developer API. Please remove this property.');
1562
1601
  }
1563
1602
  const mappedCandidate = {
@@ -1567,7 +1606,8 @@ function mapGenerateContentCandidates(candidates) {
1567
1606
  finishMessage: candidate.finishMessage,
1568
1607
  safetyRatings: mappedSafetyRatings,
1569
1608
  citationMetadata,
1570
- groundingMetadata: candidate.groundingMetadata
1609
+ groundingMetadata: candidate.groundingMetadata,
1610
+ urlContextMetadata: candidate.urlContextMetadata
1571
1611
  };
1572
1612
  mappedCandidates.push(mappedCandidate);
1573
1613
  });
@@ -1658,6 +1698,14 @@ async function* generateResponseSequence(stream, apiSettings) {
1658
1698
  else {
1659
1699
  enhancedResponse = createEnhancedContentResponse(value);
1660
1700
  }
1701
+ const firstCandidate = enhancedResponse.candidates?.[0];
1702
+ // Don't yield a response with no useful data for the developer.
1703
+ if (!firstCandidate?.content?.parts &&
1704
+ !firstCandidate?.finishReason &&
1705
+ !firstCandidate?.citationMetadata &&
1706
+ !firstCandidate?.urlContextMetadata) {
1707
+ continue;
1708
+ }
1661
1709
  yield enhancedResponse;
1662
1710
  }
1663
1711
  }
@@ -1737,36 +1785,43 @@ function aggregateResponses(responses) {
1737
1785
  candidate.safetyRatings;
1738
1786
  aggregatedResponse.candidates[i].groundingMetadata =
1739
1787
  candidate.groundingMetadata;
1788
+ // The urlContextMetadata object is defined in the first chunk of the response stream.
1789
+ // In all subsequent chunks, the urlContextMetadata object will be undefined. We need to
1790
+ // make sure that we don't overwrite the first value urlContextMetadata object with undefined.
1791
+ // FIXME: What happens if we receive a second, valid urlContextMetadata object?
1792
+ const urlContextMetadata = candidate.urlContextMetadata;
1793
+ if (typeof urlContextMetadata === 'object' &&
1794
+ urlContextMetadata !== null &&
1795
+ Object.keys(urlContextMetadata).length > 0) {
1796
+ aggregatedResponse.candidates[i].urlContextMetadata =
1797
+ urlContextMetadata;
1798
+ }
1740
1799
  /**
1741
1800
  * Candidates should always have content and parts, but this handles
1742
1801
  * possible malformed responses.
1743
1802
  */
1744
- if (candidate.content && candidate.content.parts) {
1803
+ if (candidate.content) {
1804
+ // Skip a candidate without parts.
1805
+ if (!candidate.content.parts) {
1806
+ continue;
1807
+ }
1745
1808
  if (!aggregatedResponse.candidates[i].content) {
1746
1809
  aggregatedResponse.candidates[i].content = {
1747
1810
  role: candidate.content.role || 'user',
1748
1811
  parts: []
1749
1812
  };
1750
1813
  }
1751
- const newPart = {};
1752
1814
  for (const part of candidate.content.parts) {
1753
- if (part.text !== undefined) {
1754
- // The backend can send empty text parts. If these are sent back
1755
- // (e.g. in chat history), the backend will respond with an error.
1756
- // To prevent this, ignore empty text parts.
1757
- if (part.text === '') {
1758
- continue;
1759
- }
1760
- newPart.text = part.text;
1761
- }
1762
- if (part.functionCall) {
1763
- newPart.functionCall = part.functionCall;
1815
+ const newPart = { ...part };
1816
+ // The backend can send empty text parts. If these are sent back
1817
+ // (e.g. in chat history), the backend will respond with an error.
1818
+ // To prevent this, ignore empty text parts.
1819
+ if (part.text === '') {
1820
+ continue;
1764
1821
  }
1765
- if (Object.keys(newPart).length === 0) {
1766
- throw new AIError(AIErrorCode.INVALID_CONTENT, 'Part should have at least one property, but there are none. This is likely caused ' +
1767
- 'by a malformed response from the backend.');
1822
+ if (Object.keys(newPart).length > 0) {
1823
+ aggregatedResponse.candidates[i].content.parts.push(newPart);
1768
1824
  }
1769
- aggregatedResponse.candidates[i].content.parts.push(newPart);
1770
1825
  }
1771
1826
  }
1772
1827
  }
@@ -2472,6 +2527,25 @@ class LiveSession {
2472
2527
  this.webSocketHandler.send(JSON.stringify(message));
2473
2528
  });
2474
2529
  }
2530
+ /**
2531
+ * Sends function responses to the server.
2532
+ *
2533
+ * @param functionResponses - The function responses to send.
2534
+ * @throws If this session has been closed.
2535
+ *
2536
+ * @beta
2537
+ */
2538
+ async sendFunctionResponses(functionResponses) {
2539
+ if (this.isClosed) {
2540
+ throw new AIError(AIErrorCode.REQUEST_ERROR, 'This LiveSession has been closed and cannot be used.');
2541
+ }
2542
+ const message = {
2543
+ toolResponse: {
2544
+ functionResponses
2545
+ }
2546
+ };
2547
+ this.webSocketHandler.send(JSON.stringify(message));
2548
+ }
2475
2549
  /**
2476
2550
  * Sends a stream of {@link GenerativeContentBlob}.
2477
2551
  *
@@ -2686,7 +2760,7 @@ class LiveGenerativeModel extends AIModel {
2686
2760
  * }
2687
2761
  * ```
2688
2762
  *
2689
- * @beta
2763
+ * @public
2690
2764
  */
2691
2765
  class ImagenModel extends AIModel {
2692
2766
  /**
@@ -2722,7 +2796,7 @@ class ImagenModel extends AIModel {
2722
2796
  * returned object will have a `filteredReason` property.
2723
2797
  * If all images are filtered, the `images` array will be empty.
2724
2798
  *
2725
- * @beta
2799
+ * @public
2726
2800
  */
2727
2801
  async generateImages(prompt) {
2728
2802
  const body = createPredictRequestBody(prompt, {
@@ -3185,7 +3259,7 @@ class AnyOfSchema extends Schema {
3185
3259
  * }
3186
3260
  * ```
3187
3261
  *
3188
- * @beta
3262
+ * @public
3189
3263
  */
3190
3264
  class ImagenImageFormat {
3191
3265
  constructor() {
@@ -3197,7 +3271,7 @@ class ImagenImageFormat {
3197
3271
  * @param compressionQuality - The level of compression (a number between 0 and 100).
3198
3272
  * @returns An {@link ImagenImageFormat} object for a JPEG image.
3199
3273
  *
3200
- * @beta
3274
+ * @public
3201
3275
  */
3202
3276
  static jpeg(compressionQuality) {
3203
3277
  if (compressionQuality &&
@@ -3211,7 +3285,7 @@ class ImagenImageFormat {
3211
3285
  *
3212
3286
  * @returns An {@link ImagenImageFormat} object for a PNG image.
3213
3287
  *
3214
- * @beta
3288
+ * @public
3215
3289
  */
3216
3290
  static png() {
3217
3291
  return { mimeType: 'image/png' };
@@ -3453,9 +3527,9 @@ class AudioConversationRunner {
3453
3527
  }
3454
3528
  else {
3455
3529
  try {
3456
- const resultPart = await this.options.functionCallingHandler(message.functionCalls);
3530
+ const functionResponse = await this.options.functionCallingHandler(message.functionCalls);
3457
3531
  if (!this.isStopped) {
3458
- void this.liveSession.send([resultPart]);
3532
+ void this.liveSession.sendFunctionResponses([functionResponse]);
3459
3533
  }
3460
3534
  }
3461
3535
  catch (e) {
@@ -3675,7 +3749,7 @@ function getGenerativeModel(ai, modelParams, requestOptions) {
3675
3749
  * @throws If the `apiKey` or `projectId` fields are missing in your
3676
3750
  * Firebase config.
3677
3751
  *
3678
- * @beta
3752
+ * @public
3679
3753
  */
3680
3754
  function getImagenModel(ai, modelParams, requestOptions) {
3681
3755
  if (!modelParams.model) {
@@ -3765,6 +3839,7 @@ exports.ResponseModality = ResponseModality;
3765
3839
  exports.Schema = Schema;
3766
3840
  exports.SchemaType = SchemaType;
3767
3841
  exports.StringSchema = StringSchema;
3842
+ exports.URLRetrievalStatus = URLRetrievalStatus;
3768
3843
  exports.VertexAIBackend = VertexAIBackend;
3769
3844
  exports.getAI = getAI;
3770
3845
  exports.getGenerativeModel = getGenerativeModel;