@firebase/ai 2.5.0 → 2.6.0-20251112180857

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.5.0";
11
+ var version = "2.6.0-20251112180857";
12
12
 
13
13
  /**
14
14
  * @license
@@ -38,6 +38,62 @@ const DEFAULT_FETCH_TIMEOUT_MS = 180 * 1000;
38
38
  */
39
39
  const DEFAULT_HYBRID_IN_CLOUD_MODEL = 'gemini-2.0-flash-lite';
40
40
 
41
+ /**
42
+ * @license
43
+ * Copyright 2024 Google LLC
44
+ *
45
+ * Licensed under the Apache License, Version 2.0 (the "License");
46
+ * you may not use this file except in compliance with the License.
47
+ * You may obtain a copy of the License at
48
+ *
49
+ * http://www.apache.org/licenses/LICENSE-2.0
50
+ *
51
+ * Unless required by applicable law or agreed to in writing, software
52
+ * distributed under the License is distributed on an "AS IS" BASIS,
53
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
54
+ * See the License for the specific language governing permissions and
55
+ * limitations under the License.
56
+ */
57
+ /**
58
+ * Error class for the Firebase AI SDK.
59
+ *
60
+ * @public
61
+ */
62
+ class AIError extends util.FirebaseError {
63
+ /**
64
+ * Constructs a new instance of the `AIError` class.
65
+ *
66
+ * @param code - The error code from {@link (AIErrorCode:type)}.
67
+ * @param message - A human-readable message describing the error.
68
+ * @param customErrorData - Optional error data.
69
+ */
70
+ constructor(code, message, customErrorData) {
71
+ // Match error format used by FirebaseError from ErrorFactory
72
+ const service = AI_TYPE;
73
+ const fullCode = `${service}/${code}`;
74
+ const fullMessage = `${service}: ${message} (${fullCode})`;
75
+ super(code, fullMessage);
76
+ this.code = code;
77
+ this.customErrorData = customErrorData;
78
+ // FirebaseError initializes a stack trace, but it assumes the error is created from the error
79
+ // factory. Since we break this assumption, we set the stack trace to be originating from this
80
+ // constructor.
81
+ // This is only supported in V8.
82
+ if (Error.captureStackTrace) {
83
+ // Allows us to initialize the stack trace without including the constructor itself at the
84
+ // top level of the stack trace.
85
+ Error.captureStackTrace(this, AIError);
86
+ }
87
+ // Allows instanceof AIError in ES5/ES6
88
+ // https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
89
+ // TODO(dlarocque): Replace this with `new.target`: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget
90
+ // which we can now use since we no longer target ES5.
91
+ Object.setPrototypeOf(this, AIError.prototype);
92
+ // Since Error is an interface, we don't inherit toString and so we define it ourselves.
93
+ this.toString = () => fullMessage;
94
+ }
95
+ }
96
+
41
97
  /**
42
98
  * @license
43
99
  * Copyright 2024 Google LLC
@@ -714,6 +770,18 @@ class GoogleAIBackend extends Backend {
714
770
  constructor() {
715
771
  super(BackendType.GOOGLE_AI);
716
772
  }
773
+ /**
774
+ * @internal
775
+ */
776
+ _getModelPath(project, model) {
777
+ return `/${DEFAULT_API_VERSION}/projects/${project}/${model}`;
778
+ }
779
+ /**
780
+ * @internal
781
+ */
782
+ _getTemplatePath(project, templateId) {
783
+ return `/${DEFAULT_API_VERSION}/projects/${project}/templates/${templateId}`;
784
+ }
717
785
  }
718
786
  /**
719
787
  * Configuration class for the Vertex AI Gemini API.
@@ -740,6 +808,76 @@ class VertexAIBackend extends Backend {
740
808
  this.location = location;
741
809
  }
742
810
  }
811
+ /**
812
+ * @internal
813
+ */
814
+ _getModelPath(project, model) {
815
+ return `/${DEFAULT_API_VERSION}/projects/${project}/locations/${this.location}/${model}`;
816
+ }
817
+ /**
818
+ * @internal
819
+ */
820
+ _getTemplatePath(project, templateId) {
821
+ return `/${DEFAULT_API_VERSION}/projects/${project}/locations/${this.location}/templates/${templateId}`;
822
+ }
823
+ }
824
+
825
+ /**
826
+ * @license
827
+ * Copyright 2025 Google LLC
828
+ *
829
+ * Licensed under the Apache License, Version 2.0 (the "License");
830
+ * you may not use this file except in compliance with the License.
831
+ * You may obtain a copy of the License at
832
+ *
833
+ * http://www.apache.org/licenses/LICENSE-2.0
834
+ *
835
+ * Unless required by applicable law or agreed to in writing, software
836
+ * distributed under the License is distributed on an "AS IS" BASIS,
837
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
838
+ * See the License for the specific language governing permissions and
839
+ * limitations under the License.
840
+ */
841
+ /**
842
+ * Encodes a {@link Backend} into a string that will be used to uniquely identify {@link AI}
843
+ * instances by backend type.
844
+ *
845
+ * @internal
846
+ */
847
+ function encodeInstanceIdentifier(backend) {
848
+ if (backend instanceof GoogleAIBackend) {
849
+ return `${AI_TYPE}/googleai`;
850
+ }
851
+ else if (backend instanceof VertexAIBackend) {
852
+ return `${AI_TYPE}/vertexai/${backend.location}`;
853
+ }
854
+ else {
855
+ throw new AIError(AIErrorCode.ERROR, `Invalid backend: ${JSON.stringify(backend.backendType)}`);
856
+ }
857
+ }
858
+ /**
859
+ * Decodes an instance identifier string into a {@link Backend}.
860
+ *
861
+ * @internal
862
+ */
863
+ function decodeInstanceIdentifier(instanceIdentifier) {
864
+ const identifierParts = instanceIdentifier.split('/');
865
+ if (identifierParts[0] !== AI_TYPE) {
866
+ throw new AIError(AIErrorCode.ERROR, `Invalid instance identifier, unknown prefix '${identifierParts[0]}'`);
867
+ }
868
+ const backendType = identifierParts[1];
869
+ switch (backendType) {
870
+ case 'vertexai':
871
+ const location = identifierParts[2];
872
+ if (!location) {
873
+ throw new AIError(AIErrorCode.ERROR, `Invalid instance identifier, unknown location '${instanceIdentifier}'`);
874
+ }
875
+ return new VertexAIBackend(location);
876
+ case 'googleai':
877
+ return new GoogleAIBackend();
878
+ default:
879
+ throw new AIError(AIErrorCode.ERROR, `Invalid instance identifier string: '${instanceIdentifier}'`);
880
+ }
743
881
  }
744
882
 
745
883
  /**
@@ -787,7 +925,7 @@ class AIService {
787
925
 
788
926
  /**
789
927
  * @license
790
- * Copyright 2024 Google LLC
928
+ * Copyright 2025 Google LLC
791
929
  *
792
930
  * Licensed under the Apache License, Version 2.0 (the "License");
793
931
  * you may not use this file except in compliance with the License.
@@ -801,44 +939,16 @@ class AIService {
801
939
  * See the License for the specific language governing permissions and
802
940
  * limitations under the License.
803
941
  */
804
- /**
805
- * Error class for the Firebase AI SDK.
806
- *
807
- * @public
808
- */
809
- class AIError extends util.FirebaseError {
810
- /**
811
- * Constructs a new instance of the `AIError` class.
812
- *
813
- * @param code - The error code from {@link (AIErrorCode:type)}.
814
- * @param message - A human-readable message describing the error.
815
- * @param customErrorData - Optional error data.
816
- */
817
- constructor(code, message, customErrorData) {
818
- // Match error format used by FirebaseError from ErrorFactory
819
- const service = AI_TYPE;
820
- const fullCode = `${service}/${code}`;
821
- const fullMessage = `${service}: ${message} (${fullCode})`;
822
- super(code, fullMessage);
823
- this.code = code;
824
- this.customErrorData = customErrorData;
825
- // FirebaseError initializes a stack trace, but it assumes the error is created from the error
826
- // factory. Since we break this assumption, we set the stack trace to be originating from this
827
- // constructor.
828
- // This is only supported in V8.
829
- if (Error.captureStackTrace) {
830
- // Allows us to initialize the stack trace without including the constructor itself at the
831
- // top level of the stack trace.
832
- Error.captureStackTrace(this, AIError);
833
- }
834
- // Allows instanceof AIError in ES5/ES6
835
- // https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
836
- // TODO(dlarocque): Replace this with `new.target`: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget
837
- // which we can now use since we no longer target ES5.
838
- Object.setPrototypeOf(this, AIError.prototype);
839
- // Since Error is an interface, we don't inherit toString and so we define it ourselves.
840
- this.toString = () => fullMessage;
841
- }
942
+ function factory(container, { instanceIdentifier }) {
943
+ if (!instanceIdentifier) {
944
+ throw new AIError(AIErrorCode.ERROR, 'AIService instance identifier is undefined.');
945
+ }
946
+ const backend = decodeInstanceIdentifier(instanceIdentifier);
947
+ // getImmediate for FirebaseApp will always succeed
948
+ const app = container.getProvider('app').getImmediate();
949
+ const auth = container.getProvider('auth-internal');
950
+ const appCheckProvider = container.getProvider('app-check-internal');
951
+ return new AIService(app, backend, auth, appCheckProvider);
842
952
  }
843
953
 
844
954
  /**
@@ -858,45 +968,48 @@ class AIError extends util.FirebaseError {
858
968
  * limitations under the License.
859
969
  */
860
970
  /**
861
- * Encodes a {@link Backend} into a string that will be used to uniquely identify {@link AI}
862
- * instances by backend type.
971
+ * Initializes an {@link ApiSettings} object from an {@link AI} instance.
863
972
  *
864
- * @internal
973
+ * If this is a Server App, the {@link ApiSettings} object's `getAppCheckToken()` will resolve
974
+ * with the `FirebaseServerAppSettings.appCheckToken`, instead of requiring that an App Check
975
+ * instance is initialized.
865
976
  */
866
- function encodeInstanceIdentifier(backend) {
867
- if (backend instanceof GoogleAIBackend) {
868
- return `${AI_TYPE}/googleai`;
869
- }
870
- else if (backend instanceof VertexAIBackend) {
871
- return `${AI_TYPE}/vertexai/${backend.location}`;
872
- }
873
- else {
874
- throw new AIError(AIErrorCode.ERROR, `Invalid backend: ${JSON.stringify(backend.backendType)}`);
977
+ function initApiSettings(ai) {
978
+ if (!ai.app?.options?.apiKey) {
979
+ throw new AIError(AIErrorCode.NO_API_KEY, `The "apiKey" field is empty in the local Firebase config. Firebase AI requires this field to contain a valid API key.`);
980
+ }
981
+ else if (!ai.app?.options?.projectId) {
982
+ throw new AIError(AIErrorCode.NO_PROJECT_ID, `The "projectId" field is empty in the local Firebase config. Firebase AI requires this field to contain a valid project ID.`);
983
+ }
984
+ else if (!ai.app?.options?.appId) {
985
+ throw new AIError(AIErrorCode.NO_APP_ID, `The "appId" field is empty in the local Firebase config. Firebase AI requires this field to contain a valid app ID.`);
986
+ }
987
+ const apiSettings = {
988
+ apiKey: ai.app.options.apiKey,
989
+ project: ai.app.options.projectId,
990
+ appId: ai.app.options.appId,
991
+ automaticDataCollectionEnabled: ai.app.automaticDataCollectionEnabled,
992
+ location: ai.location,
993
+ backend: ai.backend
994
+ };
995
+ if (app._isFirebaseServerApp(ai.app) && ai.app.settings.appCheckToken) {
996
+ const token = ai.app.settings.appCheckToken;
997
+ apiSettings.getAppCheckToken = () => {
998
+ return Promise.resolve({ token });
999
+ };
875
1000
  }
876
- }
877
- /**
878
- * Decodes an instance identifier string into a {@link Backend}.
879
- *
880
- * @internal
881
- */
882
- function decodeInstanceIdentifier(instanceIdentifier) {
883
- const identifierParts = instanceIdentifier.split('/');
884
- if (identifierParts[0] !== AI_TYPE) {
885
- throw new AIError(AIErrorCode.ERROR, `Invalid instance identifier, unknown prefix '${identifierParts[0]}'`);
1001
+ else if (ai.appCheck) {
1002
+ if (ai.options?.useLimitedUseAppCheckTokens) {
1003
+ apiSettings.getAppCheckToken = () => ai.appCheck.getLimitedUseToken();
1004
+ }
1005
+ else {
1006
+ apiSettings.getAppCheckToken = () => ai.appCheck.getToken();
1007
+ }
886
1008
  }
887
- const backendType = identifierParts[1];
888
- switch (backendType) {
889
- case 'vertexai':
890
- const location = identifierParts[2];
891
- if (!location) {
892
- throw new AIError(AIErrorCode.ERROR, `Invalid instance identifier, unknown location '${instanceIdentifier}'`);
893
- }
894
- return new VertexAIBackend(location);
895
- case 'googleai':
896
- return new GoogleAIBackend();
897
- default:
898
- throw new AIError(AIErrorCode.ERROR, `Invalid instance identifier string: '${instanceIdentifier}'`);
1009
+ if (ai.auth) {
1010
+ apiSettings.getAuthToken = () => ai.auth.getToken();
899
1011
  }
1012
+ return apiSettings;
900
1013
  }
901
1014
 
902
1015
  /**
@@ -942,43 +1055,8 @@ class AIModel {
942
1055
  * @internal
943
1056
  */
944
1057
  constructor(ai, modelName) {
945
- if (!ai.app?.options?.apiKey) {
946
- throw new AIError(AIErrorCode.NO_API_KEY, `The "apiKey" field is empty in the local Firebase config. Firebase AI requires this field to contain a valid API key.`);
947
- }
948
- else if (!ai.app?.options?.projectId) {
949
- throw new AIError(AIErrorCode.NO_PROJECT_ID, `The "projectId" field is empty in the local Firebase config. Firebase AI requires this field to contain a valid project ID.`);
950
- }
951
- else if (!ai.app?.options?.appId) {
952
- throw new AIError(AIErrorCode.NO_APP_ID, `The "appId" field is empty in the local Firebase config. Firebase AI requires this field to contain a valid app ID.`);
953
- }
954
- else {
955
- this._apiSettings = {
956
- apiKey: ai.app.options.apiKey,
957
- project: ai.app.options.projectId,
958
- appId: ai.app.options.appId,
959
- automaticDataCollectionEnabled: ai.app.automaticDataCollectionEnabled,
960
- location: ai.location,
961
- backend: ai.backend
962
- };
963
- if (app._isFirebaseServerApp(ai.app) && ai.app.settings.appCheckToken) {
964
- const token = ai.app.settings.appCheckToken;
965
- this._apiSettings.getAppCheckToken = () => {
966
- return Promise.resolve({ token });
967
- };
968
- }
969
- else if (ai.appCheck) {
970
- if (ai.options?.useLimitedUseAppCheckTokens) {
971
- this._apiSettings.getAppCheckToken = () => ai.appCheck.getLimitedUseToken();
972
- }
973
- else {
974
- this._apiSettings.getAppCheckToken = () => ai.appCheck.getToken();
975
- }
976
- }
977
- if (ai.auth) {
978
- this._apiSettings.getAuthToken = () => ai.auth.getToken();
979
- }
980
- this.model = AIModel.normalizeModelName(modelName, this._apiSettings.backend.backendType);
981
- }
1058
+ this._apiSettings = initApiSettings(ai);
1059
+ this.model = AIModel.normalizeModelName(modelName, this._apiSettings.backend.backendType);
982
1060
  }
983
1061
  /**
984
1062
  * Normalizes the given model name to a fully qualified model resource name.
@@ -1045,7 +1123,7 @@ const logger = new logger$1.Logger('@firebase/vertexai');
1045
1123
 
1046
1124
  /**
1047
1125
  * @license
1048
- * Copyright 2024 Google LLC
1126
+ * Copyright 2025 Google LLC
1049
1127
  *
1050
1128
  * Licensed under the Apache License, Version 2.0 (the "License");
1051
1129
  * you may not use this file except in compliance with the License.
@@ -1059,47 +1137,33 @@ const logger = new logger$1.Logger('@firebase/vertexai');
1059
1137
  * See the License for the specific language governing permissions and
1060
1138
  * limitations under the License.
1061
1139
  */
1062
- var Task;
1063
- (function (Task) {
1064
- Task["GENERATE_CONTENT"] = "generateContent";
1065
- Task["STREAM_GENERATE_CONTENT"] = "streamGenerateContent";
1066
- Task["COUNT_TOKENS"] = "countTokens";
1067
- Task["PREDICT"] = "predict";
1068
- })(Task || (Task = {}));
1069
- class RequestUrl {
1070
- constructor(model, task, apiSettings, stream, requestOptions) {
1071
- this.model = model;
1072
- this.task = task;
1073
- this.apiSettings = apiSettings;
1074
- this.stream = stream;
1075
- this.requestOptions = requestOptions;
1140
+ class RequestURL {
1141
+ constructor(params) {
1142
+ this.params = params;
1076
1143
  }
1077
1144
  toString() {
1078
1145
  const url = new URL(this.baseUrl); // Throws if the URL is invalid
1079
- url.pathname = `/${this.apiVersion}/${this.modelPath}:${this.task}`;
1146
+ url.pathname = this.pathname;
1080
1147
  url.search = this.queryParams.toString();
1081
1148
  return url.toString();
1082
1149
  }
1083
- get baseUrl() {
1084
- return this.requestOptions?.baseUrl || `https://${DEFAULT_DOMAIN}`;
1085
- }
1086
- get apiVersion() {
1087
- return DEFAULT_API_VERSION; // TODO: allow user-set options if that feature becomes available
1088
- }
1089
- get modelPath() {
1090
- if (this.apiSettings.backend instanceof GoogleAIBackend) {
1091
- return `projects/${this.apiSettings.project}/${this.model}`;
1092
- }
1093
- else if (this.apiSettings.backend instanceof VertexAIBackend) {
1094
- return `projects/${this.apiSettings.project}/locations/${this.apiSettings.backend.location}/${this.model}`;
1150
+ get pathname() {
1151
+ // We need to construct a different URL if the request is for server side prompt templates,
1152
+ // since the URL patterns are different. Server side prompt templates expect a templateId
1153
+ // instead of a model name.
1154
+ if (this.params.templateId) {
1155
+ return `${this.params.apiSettings.backend._getTemplatePath(this.params.apiSettings.project, this.params.templateId)}:${this.params.task}`;
1095
1156
  }
1096
1157
  else {
1097
- throw new AIError(AIErrorCode.ERROR, `Invalid backend: ${JSON.stringify(this.apiSettings.backend)}`);
1158
+ return `${this.params.apiSettings.backend._getModelPath(this.params.apiSettings.project, this.params.model)}:${this.params.task}`;
1098
1159
  }
1099
1160
  }
1161
+ get baseUrl() {
1162
+ return this.params.requestOptions?.baseUrl ?? `https://${DEFAULT_DOMAIN}`;
1163
+ }
1100
1164
  get queryParams() {
1101
1165
  const params = new URLSearchParams();
1102
- if (this.stream) {
1166
+ if (this.params.stream) {
1103
1167
  params.set('alt', 'sse');
1104
1168
  }
1105
1169
  return params;
@@ -1139,12 +1203,12 @@ async function getHeaders(url) {
1139
1203
  const headers = new Headers();
1140
1204
  headers.append('Content-Type', 'application/json');
1141
1205
  headers.append('x-goog-api-client', getClientHeaders());
1142
- headers.append('x-goog-api-key', url.apiSettings.apiKey);
1143
- if (url.apiSettings.automaticDataCollectionEnabled) {
1144
- headers.append('X-Firebase-Appid', url.apiSettings.appId);
1206
+ headers.append('x-goog-api-key', url.params.apiSettings.apiKey);
1207
+ if (url.params.apiSettings.automaticDataCollectionEnabled) {
1208
+ headers.append('X-Firebase-Appid', url.params.apiSettings.appId);
1145
1209
  }
1146
- if (url.apiSettings.getAppCheckToken) {
1147
- const appCheckToken = await url.apiSettings.getAppCheckToken();
1210
+ if (url.params.apiSettings.getAppCheckToken) {
1211
+ const appCheckToken = await url.params.apiSettings.getAppCheckToken();
1148
1212
  if (appCheckToken) {
1149
1213
  headers.append('X-Firebase-AppCheck', appCheckToken.token);
1150
1214
  if (appCheckToken.error) {
@@ -1152,39 +1216,33 @@ async function getHeaders(url) {
1152
1216
  }
1153
1217
  }
1154
1218
  }
1155
- if (url.apiSettings.getAuthToken) {
1156
- const authToken = await url.apiSettings.getAuthToken();
1219
+ if (url.params.apiSettings.getAuthToken) {
1220
+ const authToken = await url.params.apiSettings.getAuthToken();
1157
1221
  if (authToken) {
1158
1222
  headers.append('Authorization', `Firebase ${authToken.accessToken}`);
1159
1223
  }
1160
1224
  }
1161
1225
  return headers;
1162
1226
  }
1163
- async function constructRequest(model, task, apiSettings, stream, body, requestOptions) {
1164
- const url = new RequestUrl(model, task, apiSettings, stream, requestOptions);
1165
- return {
1166
- url: url.toString(),
1167
- fetchOptions: {
1168
- method: 'POST',
1169
- headers: await getHeaders(url),
1170
- body
1171
- }
1172
- };
1173
- }
1174
- async function makeRequest(model, task, apiSettings, stream, body, requestOptions) {
1175
- const url = new RequestUrl(model, task, apiSettings, stream, requestOptions);
1227
+ async function makeRequest(requestUrlParams, body) {
1228
+ const url = new RequestURL(requestUrlParams);
1176
1229
  let response;
1177
1230
  let fetchTimeoutId;
1178
1231
  try {
1179
- const request = await constructRequest(model, task, apiSettings, stream, body, requestOptions);
1180
- // Timeout is 180s by default
1181
- const timeoutMillis = requestOptions?.timeout != null && requestOptions.timeout >= 0
1182
- ? requestOptions.timeout
1232
+ const fetchOptions = {
1233
+ method: 'POST',
1234
+ headers: await getHeaders(url),
1235
+ body
1236
+ };
1237
+ // Timeout is 180s by default.
1238
+ const timeoutMillis = requestUrlParams.requestOptions?.timeout != null &&
1239
+ requestUrlParams.requestOptions.timeout >= 0
1240
+ ? requestUrlParams.requestOptions.timeout
1183
1241
  : DEFAULT_FETCH_TIMEOUT_MS;
1184
1242
  const abortController = new AbortController();
1185
1243
  fetchTimeoutId = setTimeout(() => abortController.abort(), timeoutMillis);
1186
- request.fetchOptions.signal = abortController.signal;
1187
- response = await fetch(request.url, request.fetchOptions);
1244
+ fetchOptions.signal = abortController.signal;
1245
+ response = await fetch(url.toString(), fetchOptions);
1188
1246
  if (!response.ok) {
1189
1247
  let message = '';
1190
1248
  let errorDetails;
@@ -1206,7 +1264,7 @@ async function makeRequest(model, task, apiSettings, stream, body, requestOption
1206
1264
  throw new AIError(AIErrorCode.API_NOT_ENABLED, `The Firebase AI SDK requires the Firebase AI ` +
1207
1265
  `API ('firebasevertexai.googleapis.com') to be enabled in your ` +
1208
1266
  `Firebase project. Enable this API by visiting the Firebase Console ` +
1209
- `at https://console.firebase.google.com/project/${url.apiSettings.project}/genai/ ` +
1267
+ `at https://console.firebase.google.com/project/${url.params.apiSettings.project}/genai/ ` +
1210
1268
  `and clicking "Get started". If you enabled this API recently, ` +
1211
1269
  `wait a few minutes for the action to propagate to our systems and ` +
1212
1270
  `then retry.`, {
@@ -1947,8 +2005,13 @@ async function generateContentStreamOnCloud(apiSettings, model, params, requestO
1947
2005
  if (apiSettings.backend.backendType === BackendType.GOOGLE_AI) {
1948
2006
  params = mapGenerateContentRequest(params);
1949
2007
  }
1950
- return makeRequest(model, Task.STREAM_GENERATE_CONTENT, apiSettings,
1951
- /* stream */ true, JSON.stringify(params), requestOptions);
2008
+ return makeRequest({
2009
+ task: "streamGenerateContent" /* Task.STREAM_GENERATE_CONTENT */,
2010
+ model,
2011
+ apiSettings,
2012
+ stream: true,
2013
+ requestOptions
2014
+ }, JSON.stringify(params));
1952
2015
  }
1953
2016
  async function generateContentStream(apiSettings, model, params, chromeAdapter, requestOptions) {
1954
2017
  const callResult = await callCloudOrDevice(params, chromeAdapter, () => chromeAdapter.generateContentStream(params), () => generateContentStreamOnCloud(apiSettings, model, params, requestOptions));
@@ -1958,8 +2021,37 @@ async function generateContentOnCloud(apiSettings, model, params, requestOptions
1958
2021
  if (apiSettings.backend.backendType === BackendType.GOOGLE_AI) {
1959
2022
  params = mapGenerateContentRequest(params);
1960
2023
  }
1961
- return makeRequest(model, Task.GENERATE_CONTENT, apiSettings,
1962
- /* stream */ false, JSON.stringify(params), requestOptions);
2024
+ return makeRequest({
2025
+ model,
2026
+ task: "generateContent" /* Task.GENERATE_CONTENT */,
2027
+ apiSettings,
2028
+ stream: false,
2029
+ requestOptions
2030
+ }, JSON.stringify(params));
2031
+ }
2032
+ async function templateGenerateContent(apiSettings, templateId, templateParams, requestOptions) {
2033
+ const response = await makeRequest({
2034
+ task: "templateGenerateContent" /* ServerPromptTemplateTask.TEMPLATE_GENERATE_CONTENT */,
2035
+ templateId,
2036
+ apiSettings,
2037
+ stream: false,
2038
+ requestOptions
2039
+ }, JSON.stringify(templateParams));
2040
+ const generateContentResponse = await processGenerateContentResponse(response, apiSettings);
2041
+ const enhancedResponse = createEnhancedContentResponse(generateContentResponse);
2042
+ return {
2043
+ response: enhancedResponse
2044
+ };
2045
+ }
2046
+ async function templateGenerateContentStream(apiSettings, templateId, templateParams, requestOptions) {
2047
+ const response = await makeRequest({
2048
+ task: "templateStreamGenerateContent" /* ServerPromptTemplateTask.TEMPLATE_STREAM_GENERATE_CONTENT */,
2049
+ templateId,
2050
+ apiSettings,
2051
+ stream: true,
2052
+ requestOptions
2053
+ }, JSON.stringify(templateParams));
2054
+ return processStream(response, apiSettings);
1963
2055
  }
1964
2056
  async function generateContent(apiSettings, model, params, chromeAdapter, requestOptions) {
1965
2057
  const callResult = await callCloudOrDevice(params, chromeAdapter, () => chromeAdapter.generateContent(params), () => generateContentOnCloud(apiSettings, model, params, requestOptions));
@@ -2371,7 +2463,13 @@ async function countTokensOnCloud(apiSettings, model, params, requestOptions) {
2371
2463
  else {
2372
2464
  body = JSON.stringify(params);
2373
2465
  }
2374
- const response = await makeRequest(model, Task.COUNT_TOKENS, apiSettings, false, body, requestOptions);
2466
+ const response = await makeRequest({
2467
+ model,
2468
+ task: "countTokens" /* Task.COUNT_TOKENS */,
2469
+ apiSettings,
2470
+ stream: false,
2471
+ requestOptions
2472
+ }, body);
2375
2473
  return response.json();
2376
2474
  }
2377
2475
  async function countTokens(apiSettings, model, params, chromeAdapter, requestOptions) {
@@ -2924,8 +3022,13 @@ class ImagenModel extends AIModel {
2924
3022
  ...this.generationConfig,
2925
3023
  ...this.safetySettings
2926
3024
  });
2927
- const response = await makeRequest(this.model, Task.PREDICT, this._apiSettings,
2928
- /* stream */ false, JSON.stringify(body), this.requestOptions);
3025
+ const response = await makeRequest({
3026
+ task: "predict" /* Task.PREDICT */,
3027
+ model: this.model,
3028
+ apiSettings: this._apiSettings,
3029
+ stream: false,
3030
+ requestOptions: this.requestOptions
3031
+ }, JSON.stringify(body));
2929
3032
  return handlePredictResponse(response);
2930
3033
  }
2931
3034
  /**
@@ -2953,8 +3056,13 @@ class ImagenModel extends AIModel {
2953
3056
  ...this.generationConfig,
2954
3057
  ...this.safetySettings
2955
3058
  });
2956
- const response = await makeRequest(this.model, Task.PREDICT, this._apiSettings,
2957
- /* stream */ false, JSON.stringify(body), this.requestOptions);
3059
+ const response = await makeRequest({
3060
+ task: "predict" /* Task.PREDICT */,
3061
+ model: this.model,
3062
+ apiSettings: this._apiSettings,
3063
+ stream: false,
3064
+ requestOptions: this.requestOptions
3065
+ }, JSON.stringify(body));
2958
3066
  return handlePredictResponse(response);
2959
3067
  }
2960
3068
  }
@@ -3106,6 +3214,121 @@ class WebSocketHandlerImpl {
3106
3214
  }
3107
3215
  }
3108
3216
 
3217
+ /**
3218
+ * @license
3219
+ * Copyright 2025 Google LLC
3220
+ *
3221
+ * Licensed under the Apache License, Version 2.0 (the "License");
3222
+ * you may not use this file except in compliance with the License.
3223
+ * You may obtain a copy of the License at
3224
+ *
3225
+ * http://www.apache.org/licenses/LICENSE-2.0
3226
+ *
3227
+ * Unless required by applicable law or agreed to in writing, software
3228
+ * distributed under the License is distributed on an "AS IS" BASIS,
3229
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3230
+ * See the License for the specific language governing permissions and
3231
+ * limitations under the License.
3232
+ */
3233
+ /**
3234
+ * {@link GenerativeModel} APIs that execute on a server-side template.
3235
+ *
3236
+ * This class should only be instantiated with {@link getTemplateGenerativeModel}.
3237
+ *
3238
+ * @beta
3239
+ */
3240
+ class TemplateGenerativeModel {
3241
+ /**
3242
+ * @hideconstructor
3243
+ */
3244
+ constructor(ai, requestOptions) {
3245
+ this.requestOptions = requestOptions || {};
3246
+ this._apiSettings = initApiSettings(ai);
3247
+ }
3248
+ /**
3249
+ * Makes a single non-streaming call to the model and returns an object
3250
+ * containing a single {@link GenerateContentResponse}.
3251
+ *
3252
+ * @param templateId - The ID of the server-side template to execute.
3253
+ * @param templateVariables - A key-value map of variables to populate the
3254
+ * template with.
3255
+ *
3256
+ * @beta
3257
+ */
3258
+ async generateContent(templateId, templateVariables // anything!
3259
+ ) {
3260
+ return templateGenerateContent(this._apiSettings, templateId, { inputs: templateVariables }, this.requestOptions);
3261
+ }
3262
+ /**
3263
+ * Makes a single streaming call to the model and returns an object
3264
+ * containing an iterable stream that iterates over all chunks in the
3265
+ * streaming response as well as a promise that returns the final aggregated
3266
+ * response.
3267
+ *
3268
+ * @param templateId - The ID of the server-side template to execute.
3269
+ * @param templateVariables - A key-value map of variables to populate the
3270
+ * template with.
3271
+ *
3272
+ * @beta
3273
+ */
3274
+ async generateContentStream(templateId, templateVariables) {
3275
+ return templateGenerateContentStream(this._apiSettings, templateId, { inputs: templateVariables }, this.requestOptions);
3276
+ }
3277
+ }
3278
+
3279
+ /**
3280
+ * @license
3281
+ * Copyright 2025 Google LLC
3282
+ *
3283
+ * Licensed under the Apache License, Version 2.0 (the "License");
3284
+ * you may not use this file except in compliance with the License.
3285
+ * You may obtain a copy of the License at
3286
+ *
3287
+ * http://www.apache.org/licenses/LICENSE-2.0
3288
+ *
3289
+ * Unless required by applicable law or agreed to in writing, software
3290
+ * distributed under the License is distributed on an "AS IS" BASIS,
3291
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3292
+ * See the License for the specific language governing permissions and
3293
+ * limitations under the License.
3294
+ */
3295
+ /**
3296
+ * Class for Imagen model APIs that execute on a server-side template.
3297
+ *
3298
+ * This class should only be instantiated with {@link getTemplateImagenModel}.
3299
+ *
3300
+ * @beta
3301
+ */
3302
+ class TemplateImagenModel {
3303
+ /**
3304
+ * @hideconstructor
3305
+ */
3306
+ constructor(ai, requestOptions) {
3307
+ this.requestOptions = requestOptions || {};
3308
+ this._apiSettings = initApiSettings(ai);
3309
+ }
3310
+ /**
3311
+ * Makes a single call to the model and returns an object containing a single
3312
+ * {@link ImagenGenerationResponse}.
3313
+ *
3314
+ * @param templateId - The ID of the server-side template to execute.
3315
+ * @param templateVariables - A key-value map of variables to populate the
3316
+ * template with.
3317
+ *
3318
+ * @beta
3319
+ */
3320
+ async generateImages(templateId, templateVariables) {
3321
+ const response = await makeRequest({
3322
+ task: "templatePredict" /* ServerPromptTemplateTask.TEMPLATE_PREDICT */,
3323
+ templateId,
3324
+ apiSettings: this._apiSettings,
3325
+ stream: false,
3326
+ requestOptions: this.requestOptions
3327
+ }, JSON.stringify({ inputs: templateVariables }));
3328
+ return handlePredictResponse(response);
3329
+ }
3330
+ }
3331
+
3109
3332
  /**
3110
3333
  * @license
3111
3334
  * Copyright 2024 Google LLC
@@ -3897,6 +4120,30 @@ function getLiveGenerativeModel(ai, modelParams) {
3897
4120
  const webSocketHandler = new WebSocketHandlerImpl();
3898
4121
  return new LiveGenerativeModel(ai, modelParams, webSocketHandler);
3899
4122
  }
4123
+ /**
4124
+ * Returns a {@link TemplateGenerativeModel} class for executing server-side
4125
+ * templates.
4126
+ *
4127
+ * @param ai - An {@link AI} instance.
4128
+ * @param requestOptions - Additional options to use when making requests.
4129
+ *
4130
+ * @beta
4131
+ */
4132
+ function getTemplateGenerativeModel(ai, requestOptions) {
4133
+ return new TemplateGenerativeModel(ai, requestOptions);
4134
+ }
4135
+ /**
4136
+ * Returns a {@link TemplateImagenModel} class for executing server-side
4137
+ * Imagen templates.
4138
+ *
4139
+ * @param ai - An {@link AI} instance.
4140
+ * @param requestOptions - Additional options to use when making requests.
4141
+ *
4142
+ * @beta
4143
+ */
4144
+ function getTemplateImagenModel(ai, requestOptions) {
4145
+ return new TemplateImagenModel(ai, requestOptions);
4146
+ }
3900
4147
 
3901
4148
  /**
3902
4149
  * The Firebase AI Web SDK.
@@ -3904,17 +4151,7 @@ function getLiveGenerativeModel(ai, modelParams) {
3904
4151
  * @packageDocumentation
3905
4152
  */
3906
4153
  function registerAI() {
3907
- app._registerComponent(new component.Component(AI_TYPE, (container, { instanceIdentifier }) => {
3908
- if (!instanceIdentifier) {
3909
- throw new AIError(AIErrorCode.ERROR, 'AIService instance identifier is undefined.');
3910
- }
3911
- const backend = decodeInstanceIdentifier(instanceIdentifier);
3912
- // getImmediate for FirebaseApp will always succeed
3913
- const app = container.getProvider('app').getImmediate();
3914
- const auth = container.getProvider('auth-internal');
3915
- const appCheckProvider = container.getProvider('app-check-internal');
3916
- return new AIService(app, backend, auth, appCheckProvider);
3917
- }, "PUBLIC" /* ComponentType.PUBLIC */).setMultipleInstances(true));
4154
+ app._registerComponent(new component.Component(AI_TYPE, factory, "PUBLIC" /* ComponentType.PUBLIC */).setMultipleInstances(true));
3918
4155
  app.registerVersion(name, version, 'node');
3919
4156
  // BUILD_TARGET will be replaced by values like esm, cjs, etc during the compilation
3920
4157
  app.registerVersion(name, version, 'cjs2020');
@@ -3961,11 +4198,15 @@ exports.ResponseModality = ResponseModality;
3961
4198
  exports.Schema = Schema;
3962
4199
  exports.SchemaType = SchemaType;
3963
4200
  exports.StringSchema = StringSchema;
4201
+ exports.TemplateGenerativeModel = TemplateGenerativeModel;
4202
+ exports.TemplateImagenModel = TemplateImagenModel;
3964
4203
  exports.URLRetrievalStatus = URLRetrievalStatus;
3965
4204
  exports.VertexAIBackend = VertexAIBackend;
3966
4205
  exports.getAI = getAI;
3967
4206
  exports.getGenerativeModel = getGenerativeModel;
3968
4207
  exports.getImagenModel = getImagenModel;
3969
4208
  exports.getLiveGenerativeModel = getLiveGenerativeModel;
4209
+ exports.getTemplateGenerativeModel = getTemplateGenerativeModel;
4210
+ exports.getTemplateImagenModel = getTemplateImagenModel;
3970
4211
  exports.startAudioConversation = startAudioConversation;
3971
4212
  //# sourceMappingURL=index.node.cjs.js.map