@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
package/dist/index.cjs.js CHANGED
@@ -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
@@ -386,7 +386,7 @@ const InferenceMode = {
386
386
  /**
387
387
  * Represents the result of the code execution.
388
388
  *
389
- * @public
389
+ * @beta
390
390
  */
391
391
  const Outcome = {
392
392
  UNSPECIFIED: 'OUTCOME_UNSPECIFIED',
@@ -397,7 +397,7 @@ const Outcome = {
397
397
  /**
398
398
  * The programming language of the code.
399
399
  *
400
- * @public
400
+ * @beta
401
401
  */
402
402
  const Language = {
403
403
  UNSPECIFIED: 'LANGUAGE_UNSPECIFIED',
@@ -420,6 +420,45 @@ const Language = {
420
420
  * See the License for the specific language governing permissions and
421
421
  * limitations under the License.
422
422
  */
423
+ /**
424
+ * The status of a URL retrieval.
425
+ *
426
+ * @remarks
427
+ * <b>URL_RETRIEVAL_STATUS_UNSPECIFIED:</b> Unspecified retrieval status.
428
+ * <br/>
429
+ * <b>URL_RETRIEVAL_STATUS_SUCCESS:</b> The URL retrieval was successful.
430
+ * <br/>
431
+ * <b>URL_RETRIEVAL_STATUS_ERROR:</b> The URL retrieval failed.
432
+ * <br/>
433
+ * <b>URL_RETRIEVAL_STATUS_PAYWALL:</b> The URL retrieval failed because the content is behind a paywall.
434
+ * <br/>
435
+ * <b>URL_RETRIEVAL_STATUS_UNSAFE:</b> The URL retrieval failed because the content is unsafe.
436
+ * <br/>
437
+ *
438
+ * @beta
439
+ */
440
+ const URLRetrievalStatus = {
441
+ /**
442
+ * Unspecified retrieval status.
443
+ */
444
+ URL_RETRIEVAL_STATUS_UNSPECIFIED: 'URL_RETRIEVAL_STATUS_UNSPECIFIED',
445
+ /**
446
+ * The URL retrieval was successful.
447
+ */
448
+ URL_RETRIEVAL_STATUS_SUCCESS: 'URL_RETRIEVAL_STATUS_SUCCESS',
449
+ /**
450
+ * The URL retrieval failed.
451
+ */
452
+ URL_RETRIEVAL_STATUS_ERROR: 'URL_RETRIEVAL_STATUS_ERROR',
453
+ /**
454
+ * The URL retrieval failed because the content is behind a paywall.
455
+ */
456
+ URL_RETRIEVAL_STATUS_PAYWALL: 'URL_RETRIEVAL_STATUS_PAYWALL',
457
+ /**
458
+ * The URL retrieval failed because the content is unsafe.
459
+ */
460
+ URL_RETRIEVAL_STATUS_UNSAFE: 'URL_RETRIEVAL_STATUS_UNSAFE'
461
+ };
423
462
  /**
424
463
  * The types of responses that can be returned by {@link LiveSession.receive}.
425
464
  *
@@ -546,7 +585,7 @@ const SchemaType = {
546
585
  * and the {@link https://cloud.google.com/vertex-ai/generative-ai/docs/image/responsible-ai-imagen#safety-filters | Responsible AI and usage guidelines}
547
586
  * for more details.
548
587
  *
549
- * @beta
588
+ * @public
550
589
  */
551
590
  const ImagenSafetyFilterLevel = {
552
591
  /**
@@ -575,7 +614,7 @@ const ImagenSafetyFilterLevel = {
575
614
  * See the <a href="http://firebase.google.com/docs/vertex-ai/generate-images">personGeneration</a>
576
615
  * documentation for more details.
577
616
  *
578
- * @beta
617
+ * @public
579
618
  */
580
619
  const ImagenPersonFilterLevel = {
581
620
  /**
@@ -608,7 +647,7 @@ const ImagenPersonFilterLevel = {
608
647
  * See the {@link http://firebase.google.com/docs/vertex-ai/generate-images | documentation }
609
648
  * for more details and examples of the supported aspect ratios.
610
649
  *
611
- * @beta
650
+ * @public
612
651
  */
613
652
  const ImagenAspectRatio = {
614
653
  /**
@@ -1880,7 +1919,7 @@ function mapGenerateContentCandidates(candidates) {
1880
1919
  // videoMetadata is not supported.
1881
1920
  // Throw early since developers may send a long video as input and only expect to pay
1882
1921
  // for inference on a small portion of the video.
1883
- if (candidate.content?.parts.some(part => part?.videoMetadata)) {
1922
+ if (candidate.content?.parts?.some(part => part?.videoMetadata)) {
1884
1923
  throw new AIError(AIErrorCode.UNSUPPORTED, 'Part.videoMetadata is not supported in the Gemini Developer API. Please remove this property.');
1885
1924
  }
1886
1925
  const mappedCandidate = {
@@ -1890,7 +1929,8 @@ function mapGenerateContentCandidates(candidates) {
1890
1929
  finishMessage: candidate.finishMessage,
1891
1930
  safetyRatings: mappedSafetyRatings,
1892
1931
  citationMetadata,
1893
- groundingMetadata: candidate.groundingMetadata
1932
+ groundingMetadata: candidate.groundingMetadata,
1933
+ urlContextMetadata: candidate.urlContextMetadata
1894
1934
  };
1895
1935
  mappedCandidates.push(mappedCandidate);
1896
1936
  });
@@ -1981,6 +2021,14 @@ async function* generateResponseSequence(stream, apiSettings) {
1981
2021
  else {
1982
2022
  enhancedResponse = createEnhancedContentResponse(value);
1983
2023
  }
2024
+ const firstCandidate = enhancedResponse.candidates?.[0];
2025
+ // Don't yield a response with no useful data for the developer.
2026
+ if (!firstCandidate?.content?.parts &&
2027
+ !firstCandidate?.finishReason &&
2028
+ !firstCandidate?.citationMetadata &&
2029
+ !firstCandidate?.urlContextMetadata) {
2030
+ continue;
2031
+ }
1984
2032
  yield enhancedResponse;
1985
2033
  }
1986
2034
  }
@@ -2060,36 +2108,43 @@ function aggregateResponses(responses) {
2060
2108
  candidate.safetyRatings;
2061
2109
  aggregatedResponse.candidates[i].groundingMetadata =
2062
2110
  candidate.groundingMetadata;
2111
+ // The urlContextMetadata object is defined in the first chunk of the response stream.
2112
+ // In all subsequent chunks, the urlContextMetadata object will be undefined. We need to
2113
+ // make sure that we don't overwrite the first value urlContextMetadata object with undefined.
2114
+ // FIXME: What happens if we receive a second, valid urlContextMetadata object?
2115
+ const urlContextMetadata = candidate.urlContextMetadata;
2116
+ if (typeof urlContextMetadata === 'object' &&
2117
+ urlContextMetadata !== null &&
2118
+ Object.keys(urlContextMetadata).length > 0) {
2119
+ aggregatedResponse.candidates[i].urlContextMetadata =
2120
+ urlContextMetadata;
2121
+ }
2063
2122
  /**
2064
2123
  * Candidates should always have content and parts, but this handles
2065
2124
  * possible malformed responses.
2066
2125
  */
2067
- if (candidate.content && candidate.content.parts) {
2126
+ if (candidate.content) {
2127
+ // Skip a candidate without parts.
2128
+ if (!candidate.content.parts) {
2129
+ continue;
2130
+ }
2068
2131
  if (!aggregatedResponse.candidates[i].content) {
2069
2132
  aggregatedResponse.candidates[i].content = {
2070
2133
  role: candidate.content.role || 'user',
2071
2134
  parts: []
2072
2135
  };
2073
2136
  }
2074
- const newPart = {};
2075
2137
  for (const part of candidate.content.parts) {
2076
- if (part.text !== undefined) {
2077
- // The backend can send empty text parts. If these are sent back
2078
- // (e.g. in chat history), the backend will respond with an error.
2079
- // To prevent this, ignore empty text parts.
2080
- if (part.text === '') {
2081
- continue;
2082
- }
2083
- newPart.text = part.text;
2138
+ const newPart = { ...part };
2139
+ // The backend can send empty text parts. If these are sent back
2140
+ // (e.g. in chat history), the backend will respond with an error.
2141
+ // To prevent this, ignore empty text parts.
2142
+ if (part.text === '') {
2143
+ continue;
2084
2144
  }
2085
- if (part.functionCall) {
2086
- newPart.functionCall = part.functionCall;
2145
+ if (Object.keys(newPart).length > 0) {
2146
+ aggregatedResponse.candidates[i].content.parts.push(newPart);
2087
2147
  }
2088
- if (Object.keys(newPart).length === 0) {
2089
- throw new AIError(AIErrorCode.INVALID_CONTENT, 'Part should have at least one property, but there are none. This is likely caused ' +
2090
- 'by a malformed response from the backend.');
2091
- }
2092
- aggregatedResponse.candidates[i].content.parts.push(newPart);
2093
2148
  }
2094
2149
  }
2095
2150
  }
@@ -2795,6 +2850,25 @@ class LiveSession {
2795
2850
  this.webSocketHandler.send(JSON.stringify(message));
2796
2851
  });
2797
2852
  }
2853
+ /**
2854
+ * Sends function responses to the server.
2855
+ *
2856
+ * @param functionResponses - The function responses to send.
2857
+ * @throws If this session has been closed.
2858
+ *
2859
+ * @beta
2860
+ */
2861
+ async sendFunctionResponses(functionResponses) {
2862
+ if (this.isClosed) {
2863
+ throw new AIError(AIErrorCode.REQUEST_ERROR, 'This LiveSession has been closed and cannot be used.');
2864
+ }
2865
+ const message = {
2866
+ toolResponse: {
2867
+ functionResponses
2868
+ }
2869
+ };
2870
+ this.webSocketHandler.send(JSON.stringify(message));
2871
+ }
2798
2872
  /**
2799
2873
  * Sends a stream of {@link GenerativeContentBlob}.
2800
2874
  *
@@ -3009,7 +3083,7 @@ class LiveGenerativeModel extends AIModel {
3009
3083
  * }
3010
3084
  * ```
3011
3085
  *
3012
- * @beta
3086
+ * @public
3013
3087
  */
3014
3088
  class ImagenModel extends AIModel {
3015
3089
  /**
@@ -3045,7 +3119,7 @@ class ImagenModel extends AIModel {
3045
3119
  * returned object will have a `filteredReason` property.
3046
3120
  * If all images are filtered, the `images` array will be empty.
3047
3121
  *
3048
- * @beta
3122
+ * @public
3049
3123
  */
3050
3124
  async generateImages(prompt) {
3051
3125
  const body = createPredictRequestBody(prompt, {
@@ -3508,7 +3582,7 @@ class AnyOfSchema extends Schema {
3508
3582
  * }
3509
3583
  * ```
3510
3584
  *
3511
- * @beta
3585
+ * @public
3512
3586
  */
3513
3587
  class ImagenImageFormat {
3514
3588
  constructor() {
@@ -3520,7 +3594,7 @@ class ImagenImageFormat {
3520
3594
  * @param compressionQuality - The level of compression (a number between 0 and 100).
3521
3595
  * @returns An {@link ImagenImageFormat} object for a JPEG image.
3522
3596
  *
3523
- * @beta
3597
+ * @public
3524
3598
  */
3525
3599
  static jpeg(compressionQuality) {
3526
3600
  if (compressionQuality &&
@@ -3534,7 +3608,7 @@ class ImagenImageFormat {
3534
3608
  *
3535
3609
  * @returns An {@link ImagenImageFormat} object for a PNG image.
3536
3610
  *
3537
- * @beta
3611
+ * @public
3538
3612
  */
3539
3613
  static png() {
3540
3614
  return { mimeType: 'image/png' };
@@ -3776,9 +3850,9 @@ class AudioConversationRunner {
3776
3850
  }
3777
3851
  else {
3778
3852
  try {
3779
- const resultPart = await this.options.functionCallingHandler(message.functionCalls);
3853
+ const functionResponse = await this.options.functionCallingHandler(message.functionCalls);
3780
3854
  if (!this.isStopped) {
3781
- void this.liveSession.send([resultPart]);
3855
+ void this.liveSession.sendFunctionResponses([functionResponse]);
3782
3856
  }
3783
3857
  }
3784
3858
  catch (e) {
@@ -3998,7 +4072,7 @@ function getGenerativeModel(ai, modelParams, requestOptions) {
3998
4072
  * @throws If the `apiKey` or `projectId` fields are missing in your
3999
4073
  * Firebase config.
4000
4074
  *
4001
- * @beta
4075
+ * @public
4002
4076
  */
4003
4077
  function getImagenModel(ai, modelParams, requestOptions) {
4004
4078
  if (!modelParams.model) {
@@ -4078,6 +4152,7 @@ exports.ResponseModality = ResponseModality;
4078
4152
  exports.Schema = Schema;
4079
4153
  exports.SchemaType = SchemaType;
4080
4154
  exports.StringSchema = StringSchema;
4155
+ exports.URLRetrievalStatus = URLRetrievalStatus;
4081
4156
  exports.VertexAIBackend = VertexAIBackend;
4082
4157
  exports.getAI = getAI;
4083
4158
  exports.getGenerativeModel = getGenerativeModel;