@firebase/ai 2.6.1-canary.9cf4b7e35 → 2.6.1-canary.b2827448b
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.
- package/dist/ai-public.d.ts +104 -11
- package/dist/ai.d.ts +105 -12
- package/dist/esm/index.esm.js +157 -77
- package/dist/esm/index.esm.js.map +1 -1
- package/dist/esm/src/constants.d.ts +1 -1
- package/dist/esm/src/methods/chat-session.d.ts +7 -3
- package/dist/esm/src/methods/count-tokens.d.ts +2 -2
- package/dist/esm/src/methods/generate-content.d.ts +5 -5
- package/dist/esm/src/models/generative-model.d.ts +4 -4
- package/dist/esm/src/models/imagen-model.d.ts +3 -3
- package/dist/esm/src/models/template-generative-model.d.ts +3 -3
- package/dist/esm/src/models/template-imagen-model.d.ts +2 -2
- package/dist/esm/src/requests/request.d.ts +4 -2
- package/dist/esm/src/requests/stream-reader.d.ts +1 -3
- package/dist/esm/src/types/enums.d.ts +21 -0
- package/dist/esm/src/types/imagen/internal.d.ts +1 -1
- package/dist/esm/src/types/requests.d.ts +68 -3
- package/dist/index.cjs.js +157 -76
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.node.cjs.js +157 -76
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/index.node.mjs +157 -77
- package/dist/index.node.mjs.map +1 -1
- package/dist/src/constants.d.ts +1 -1
- package/dist/src/methods/chat-session.d.ts +7 -3
- package/dist/src/methods/count-tokens.d.ts +2 -2
- package/dist/src/methods/generate-content.d.ts +5 -5
- package/dist/src/models/generative-model.d.ts +4 -4
- package/dist/src/models/imagen-model.d.ts +3 -3
- package/dist/src/models/template-generative-model.d.ts +3 -3
- package/dist/src/models/template-imagen-model.d.ts +2 -2
- package/dist/src/requests/request.d.ts +4 -2
- package/dist/src/requests/stream-reader.d.ts +1 -3
- package/dist/src/types/enums.d.ts +21 -0
- package/dist/src/types/imagen/internal.d.ts +1 -1
- package/dist/src/types/requests.d.ts +68 -3
- package/package.json +8 -8
package/dist/index.node.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { FirebaseError, Deferred, getModularInstance } from '@firebase/util';
|
|
|
4
4
|
import { Logger } from '@firebase/logger';
|
|
5
5
|
|
|
6
6
|
var name = "@firebase/ai";
|
|
7
|
-
var version = "2.6.1-canary.
|
|
7
|
+
var version = "2.6.1-canary.b2827448b";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @license
|
|
@@ -32,7 +32,7 @@ const DEFAULT_FETCH_TIMEOUT_MS = 180 * 1000;
|
|
|
32
32
|
/**
|
|
33
33
|
* Defines the name of the default in-cloud model to use for hybrid inference.
|
|
34
34
|
*/
|
|
35
|
-
const DEFAULT_HYBRID_IN_CLOUD_MODEL = 'gemini-2.
|
|
35
|
+
const DEFAULT_HYBRID_IN_CLOUD_MODEL = 'gemini-2.5-flash-lite';
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* @license
|
|
@@ -408,6 +408,19 @@ const Language = {
|
|
|
408
408
|
UNSPECIFIED: 'LANGUAGE_UNSPECIFIED',
|
|
409
409
|
PYTHON: 'PYTHON'
|
|
410
410
|
};
|
|
411
|
+
/**
|
|
412
|
+
* A preset that controls the model's "thinking" process. Use
|
|
413
|
+
* `ThinkingLevel.LOW` for faster responses on less complex tasks, and
|
|
414
|
+
* `ThinkingLevel.HIGH` for better reasoning on more complex tasks.
|
|
415
|
+
*
|
|
416
|
+
* @public
|
|
417
|
+
*/
|
|
418
|
+
const ThinkingLevel = {
|
|
419
|
+
MINIMAL: 'MINIMAL',
|
|
420
|
+
LOW: 'LOW',
|
|
421
|
+
MEDIUM: 'MEDIUM',
|
|
422
|
+
HIGH: 'HIGH'
|
|
423
|
+
};
|
|
411
424
|
|
|
412
425
|
/**
|
|
413
426
|
* @license
|
|
@@ -1133,6 +1146,8 @@ const logger = new Logger('@firebase/vertexai');
|
|
|
1133
1146
|
* See the License for the specific language governing permissions and
|
|
1134
1147
|
* limitations under the License.
|
|
1135
1148
|
*/
|
|
1149
|
+
const TIMEOUT_EXPIRED_MESSAGE = 'Timeout has expired.';
|
|
1150
|
+
const ABORT_ERROR_NAME = 'AbortError';
|
|
1136
1151
|
class RequestURL {
|
|
1137
1152
|
constructor(params) {
|
|
1138
1153
|
this.params = params;
|
|
@@ -1155,7 +1170,7 @@ class RequestURL {
|
|
|
1155
1170
|
}
|
|
1156
1171
|
}
|
|
1157
1172
|
get baseUrl() {
|
|
1158
|
-
return this.params.
|
|
1173
|
+
return (this.params.singleRequestOptions?.baseUrl ?? `https://${DEFAULT_DOMAIN}`);
|
|
1159
1174
|
}
|
|
1160
1175
|
get queryParams() {
|
|
1161
1176
|
const params = new URLSearchParams();
|
|
@@ -1223,21 +1238,32 @@ async function getHeaders(url) {
|
|
|
1223
1238
|
async function makeRequest(requestUrlParams, body) {
|
|
1224
1239
|
const url = new RequestURL(requestUrlParams);
|
|
1225
1240
|
let response;
|
|
1226
|
-
|
|
1241
|
+
const externalSignal = requestUrlParams.singleRequestOptions?.signal;
|
|
1242
|
+
const timeoutMillis = requestUrlParams.singleRequestOptions?.timeout != null &&
|
|
1243
|
+
requestUrlParams.singleRequestOptions.timeout >= 0
|
|
1244
|
+
? requestUrlParams.singleRequestOptions.timeout
|
|
1245
|
+
: DEFAULT_FETCH_TIMEOUT_MS;
|
|
1246
|
+
const internalAbortController = new AbortController();
|
|
1247
|
+
const fetchTimeoutId = setTimeout(() => {
|
|
1248
|
+
internalAbortController.abort(new DOMException(TIMEOUT_EXPIRED_MESSAGE, ABORT_ERROR_NAME));
|
|
1249
|
+
logger.debug(`Aborting request to ${url} due to timeout (${timeoutMillis}ms)`);
|
|
1250
|
+
}, timeoutMillis);
|
|
1251
|
+
// Used to abort the fetch if either the user-defined `externalSignal` is aborted, or if the
|
|
1252
|
+
// internal signal (triggered by timeouts) is aborted.
|
|
1253
|
+
const combinedSignal = AbortSignal.any(externalSignal
|
|
1254
|
+
? [externalSignal, internalAbortController.signal]
|
|
1255
|
+
: [internalAbortController.signal]);
|
|
1256
|
+
if (externalSignal && externalSignal.aborted) {
|
|
1257
|
+
clearTimeout(fetchTimeoutId);
|
|
1258
|
+
throw new DOMException(externalSignal.reason ?? 'Aborted externally before fetch', ABORT_ERROR_NAME);
|
|
1259
|
+
}
|
|
1227
1260
|
try {
|
|
1228
1261
|
const fetchOptions = {
|
|
1229
1262
|
method: 'POST',
|
|
1230
1263
|
headers: await getHeaders(url),
|
|
1264
|
+
signal: combinedSignal,
|
|
1231
1265
|
body
|
|
1232
1266
|
};
|
|
1233
|
-
// Timeout is 180s by default.
|
|
1234
|
-
const timeoutMillis = requestUrlParams.requestOptions?.timeout != null &&
|
|
1235
|
-
requestUrlParams.requestOptions.timeout >= 0
|
|
1236
|
-
? requestUrlParams.requestOptions.timeout
|
|
1237
|
-
: DEFAULT_FETCH_TIMEOUT_MS;
|
|
1238
|
-
const abortController = new AbortController();
|
|
1239
|
-
fetchTimeoutId = setTimeout(() => abortController.abort(), timeoutMillis);
|
|
1240
|
-
fetchOptions.signal = abortController.signal;
|
|
1241
1267
|
response = await fetch(url.toString(), fetchOptions);
|
|
1242
1268
|
if (!response.ok) {
|
|
1243
1269
|
let message = '';
|
|
@@ -1280,16 +1306,18 @@ async function makeRequest(requestUrlParams, body) {
|
|
|
1280
1306
|
let err = e;
|
|
1281
1307
|
if (e.code !== AIErrorCode.FETCH_ERROR &&
|
|
1282
1308
|
e.code !== AIErrorCode.API_NOT_ENABLED &&
|
|
1283
|
-
e instanceof Error
|
|
1309
|
+
e instanceof Error &&
|
|
1310
|
+
e.name !== ABORT_ERROR_NAME) {
|
|
1284
1311
|
err = new AIError(AIErrorCode.ERROR, `Error fetching from ${url.toString()}: ${e.message}`);
|
|
1285
1312
|
err.stack = e.stack;
|
|
1286
1313
|
}
|
|
1287
1314
|
throw err;
|
|
1288
1315
|
}
|
|
1289
1316
|
finally {
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1317
|
+
// When doing streaming requests, this will clear the timeout once the stream begins.
|
|
1318
|
+
// If a timeout it 3000ms, and the stream starts after 300ms and ends after 5000ms, the
|
|
1319
|
+
// timeout will be cleared after 300ms, so it won't abort the request.
|
|
1320
|
+
clearTimeout(fetchTimeoutId);
|
|
1293
1321
|
}
|
|
1294
1322
|
return response;
|
|
1295
1323
|
}
|
|
@@ -1727,6 +1755,8 @@ const responseLineRE = /^data\: (.*)(?:\n\n|\r\r|\r\n\r\n)/;
|
|
|
1727
1755
|
function processStream(response, apiSettings, inferenceSource) {
|
|
1728
1756
|
const inputStream = response.body.pipeThrough(new TextDecoderStream('utf8', { fatal: true }));
|
|
1729
1757
|
const responseStream = getResponseStream(inputStream);
|
|
1758
|
+
// We split the stream so the user can iterate over partial results (stream1)
|
|
1759
|
+
// while we aggregate the full result for history/final response (stream2).
|
|
1730
1760
|
const [stream1, stream2] = responseStream.tee();
|
|
1731
1761
|
return {
|
|
1732
1762
|
stream: generateResponseSequence(stream1, apiSettings, inferenceSource),
|
|
@@ -1763,7 +1793,6 @@ async function* generateResponseSequence(stream, apiSettings, inferenceSource) {
|
|
|
1763
1793
|
enhancedResponse = createEnhancedContentResponse(value, inferenceSource);
|
|
1764
1794
|
}
|
|
1765
1795
|
const firstCandidate = enhancedResponse.candidates?.[0];
|
|
1766
|
-
// Don't yield a response with no useful data for the developer.
|
|
1767
1796
|
if (!firstCandidate?.content?.parts &&
|
|
1768
1797
|
!firstCandidate?.finishReason &&
|
|
1769
1798
|
!firstCandidate?.citationMetadata &&
|
|
@@ -1774,9 +1803,7 @@ async function* generateResponseSequence(stream, apiSettings, inferenceSource) {
|
|
|
1774
1803
|
}
|
|
1775
1804
|
}
|
|
1776
1805
|
/**
|
|
1777
|
-
* Reads a raw stream
|
|
1778
|
-
* chunks, returning a new stream that provides a single complete
|
|
1779
|
-
* GenerateContentResponse in each iteration.
|
|
1806
|
+
* Reads a raw string stream, buffers incomplete chunks, and yields parsed JSON objects.
|
|
1780
1807
|
*/
|
|
1781
1808
|
function getResponseStream(inputStream) {
|
|
1782
1809
|
const reader = inputStream.getReader();
|
|
@@ -1795,6 +1822,8 @@ function getResponseStream(inputStream) {
|
|
|
1795
1822
|
return;
|
|
1796
1823
|
}
|
|
1797
1824
|
currentText += value;
|
|
1825
|
+
// SSE events may span chunk boundaries, so we buffer until we match
|
|
1826
|
+
// the full "data: {json}\n\n" pattern.
|
|
1798
1827
|
let match = currentText.match(responseLineRE);
|
|
1799
1828
|
let parsedResponse;
|
|
1800
1829
|
while (match) {
|
|
@@ -1828,8 +1857,7 @@ function aggregateResponses(responses) {
|
|
|
1828
1857
|
for (const response of responses) {
|
|
1829
1858
|
if (response.candidates) {
|
|
1830
1859
|
for (const candidate of response.candidates) {
|
|
1831
|
-
//
|
|
1832
|
-
// See: https://github.com/firebase/firebase-js-sdk/issues/8566
|
|
1860
|
+
// Use 0 if index is undefined (protobuf default value omission).
|
|
1833
1861
|
const i = candidate.index || 0;
|
|
1834
1862
|
if (!aggregatedResponse.candidates) {
|
|
1835
1863
|
aggregatedResponse.candidates = [];
|
|
@@ -1839,7 +1867,7 @@ function aggregateResponses(responses) {
|
|
|
1839
1867
|
index: candidate.index
|
|
1840
1868
|
};
|
|
1841
1869
|
}
|
|
1842
|
-
//
|
|
1870
|
+
// Overwrite with the latest metadata
|
|
1843
1871
|
aggregatedResponse.candidates[i].citationMetadata =
|
|
1844
1872
|
candidate.citationMetadata;
|
|
1845
1873
|
aggregatedResponse.candidates[i].finishReason = candidate.finishReason;
|
|
@@ -1860,12 +1888,7 @@ function aggregateResponses(responses) {
|
|
|
1860
1888
|
aggregatedResponse.candidates[i].urlContextMetadata =
|
|
1861
1889
|
urlContextMetadata;
|
|
1862
1890
|
}
|
|
1863
|
-
/**
|
|
1864
|
-
* Candidates should always have content and parts, but this handles
|
|
1865
|
-
* possible malformed responses.
|
|
1866
|
-
*/
|
|
1867
1891
|
if (candidate.content) {
|
|
1868
|
-
// Skip a candidate without parts.
|
|
1869
1892
|
if (!candidate.content.parts) {
|
|
1870
1893
|
continue;
|
|
1871
1894
|
}
|
|
@@ -1997,7 +2020,7 @@ async function callCloudOrDevice(request, chromeAdapter, onDeviceCall, inCloudCa
|
|
|
1997
2020
|
* See the License for the specific language governing permissions and
|
|
1998
2021
|
* limitations under the License.
|
|
1999
2022
|
*/
|
|
2000
|
-
async function generateContentStreamOnCloud(apiSettings, model, params,
|
|
2023
|
+
async function generateContentStreamOnCloud(apiSettings, model, params, singleRequestOptions) {
|
|
2001
2024
|
if (apiSettings.backend.backendType === BackendType.GOOGLE_AI) {
|
|
2002
2025
|
params = mapGenerateContentRequest(params);
|
|
2003
2026
|
}
|
|
@@ -2006,14 +2029,14 @@ async function generateContentStreamOnCloud(apiSettings, model, params, requestO
|
|
|
2006
2029
|
model,
|
|
2007
2030
|
apiSettings,
|
|
2008
2031
|
stream: true,
|
|
2009
|
-
|
|
2032
|
+
singleRequestOptions
|
|
2010
2033
|
}, JSON.stringify(params));
|
|
2011
2034
|
}
|
|
2012
|
-
async function generateContentStream(apiSettings, model, params, chromeAdapter,
|
|
2013
|
-
const callResult = await callCloudOrDevice(params, chromeAdapter, () => chromeAdapter.generateContentStream(params), () => generateContentStreamOnCloud(apiSettings, model, params,
|
|
2035
|
+
async function generateContentStream(apiSettings, model, params, chromeAdapter, singleRequestOptions) {
|
|
2036
|
+
const callResult = await callCloudOrDevice(params, chromeAdapter, () => chromeAdapter.generateContentStream(params), () => generateContentStreamOnCloud(apiSettings, model, params, singleRequestOptions));
|
|
2014
2037
|
return processStream(callResult.response, apiSettings, callResult.inferenceSource);
|
|
2015
2038
|
}
|
|
2016
|
-
async function generateContentOnCloud(apiSettings, model, params,
|
|
2039
|
+
async function generateContentOnCloud(apiSettings, model, params, singleRequestOptions) {
|
|
2017
2040
|
if (apiSettings.backend.backendType === BackendType.GOOGLE_AI) {
|
|
2018
2041
|
params = mapGenerateContentRequest(params);
|
|
2019
2042
|
}
|
|
@@ -2022,16 +2045,16 @@ async function generateContentOnCloud(apiSettings, model, params, requestOptions
|
|
|
2022
2045
|
task: "generateContent" /* Task.GENERATE_CONTENT */,
|
|
2023
2046
|
apiSettings,
|
|
2024
2047
|
stream: false,
|
|
2025
|
-
|
|
2048
|
+
singleRequestOptions
|
|
2026
2049
|
}, JSON.stringify(params));
|
|
2027
2050
|
}
|
|
2028
|
-
async function templateGenerateContent(apiSettings, templateId, templateParams,
|
|
2051
|
+
async function templateGenerateContent(apiSettings, templateId, templateParams, singleRequestOptions) {
|
|
2029
2052
|
const response = await makeRequest({
|
|
2030
2053
|
task: "templateGenerateContent" /* ServerPromptTemplateTask.TEMPLATE_GENERATE_CONTENT */,
|
|
2031
2054
|
templateId,
|
|
2032
2055
|
apiSettings,
|
|
2033
2056
|
stream: false,
|
|
2034
|
-
|
|
2057
|
+
singleRequestOptions
|
|
2035
2058
|
}, JSON.stringify(templateParams));
|
|
2036
2059
|
const generateContentResponse = await processGenerateContentResponse(response, apiSettings);
|
|
2037
2060
|
const enhancedResponse = createEnhancedContentResponse(generateContentResponse);
|
|
@@ -2039,18 +2062,18 @@ async function templateGenerateContent(apiSettings, templateId, templateParams,
|
|
|
2039
2062
|
response: enhancedResponse
|
|
2040
2063
|
};
|
|
2041
2064
|
}
|
|
2042
|
-
async function templateGenerateContentStream(apiSettings, templateId, templateParams,
|
|
2065
|
+
async function templateGenerateContentStream(apiSettings, templateId, templateParams, singleRequestOptions) {
|
|
2043
2066
|
const response = await makeRequest({
|
|
2044
2067
|
task: "templateStreamGenerateContent" /* ServerPromptTemplateTask.TEMPLATE_STREAM_GENERATE_CONTENT */,
|
|
2045
2068
|
templateId,
|
|
2046
2069
|
apiSettings,
|
|
2047
2070
|
stream: true,
|
|
2048
|
-
|
|
2071
|
+
singleRequestOptions
|
|
2049
2072
|
}, JSON.stringify(templateParams));
|
|
2050
2073
|
return processStream(response, apiSettings);
|
|
2051
2074
|
}
|
|
2052
|
-
async function generateContent(apiSettings, model, params, chromeAdapter,
|
|
2053
|
-
const callResult = await callCloudOrDevice(params, chromeAdapter, () => chromeAdapter.generateContent(params), () => generateContentOnCloud(apiSettings, model, params,
|
|
2075
|
+
async function generateContent(apiSettings, model, params, chromeAdapter, singleRequestOptions) {
|
|
2076
|
+
const callResult = await callCloudOrDevice(params, chromeAdapter, () => chromeAdapter.generateContent(params), () => generateContentOnCloud(apiSettings, model, params, singleRequestOptions));
|
|
2054
2077
|
const generateContentResponse = await processGenerateContentResponse(callResult.response, apiSettings);
|
|
2055
2078
|
const enhancedResponse = createEnhancedContentResponse(generateContentResponse, callResult.inferenceSource);
|
|
2056
2079
|
return {
|
|
@@ -2304,7 +2327,8 @@ function validateChatHistory(history) {
|
|
|
2304
2327
|
* limitations under the License.
|
|
2305
2328
|
*/
|
|
2306
2329
|
/**
|
|
2307
|
-
*
|
|
2330
|
+
* Used to break the internal promise chain when an error is already handled
|
|
2331
|
+
* by the user, preventing duplicate console logs.
|
|
2308
2332
|
*/
|
|
2309
2333
|
const SILENT_ERROR = 'SILENT_ERROR';
|
|
2310
2334
|
/**
|
|
@@ -2320,6 +2344,10 @@ class ChatSession {
|
|
|
2320
2344
|
this.params = params;
|
|
2321
2345
|
this.requestOptions = requestOptions;
|
|
2322
2346
|
this._history = [];
|
|
2347
|
+
/**
|
|
2348
|
+
* Ensures sequential execution of chat messages to maintain history order.
|
|
2349
|
+
* Each call waits for the previous one to settle before proceeding.
|
|
2350
|
+
*/
|
|
2323
2351
|
this._sendPromise = Promise.resolve();
|
|
2324
2352
|
this._apiSettings = apiSettings;
|
|
2325
2353
|
if (params?.history) {
|
|
@@ -2340,7 +2368,7 @@ class ChatSession {
|
|
|
2340
2368
|
* Sends a chat message and receives a non-streaming
|
|
2341
2369
|
* {@link GenerateContentResult}
|
|
2342
2370
|
*/
|
|
2343
|
-
async sendMessage(request) {
|
|
2371
|
+
async sendMessage(request, singleRequestOptions) {
|
|
2344
2372
|
await this._sendPromise;
|
|
2345
2373
|
const newContent = formatNewContent(request);
|
|
2346
2374
|
const generateContentRequest = {
|
|
@@ -2352,16 +2380,20 @@ class ChatSession {
|
|
|
2352
2380
|
contents: [...this._history, newContent]
|
|
2353
2381
|
};
|
|
2354
2382
|
let finalResult = {};
|
|
2355
|
-
// Add onto the chain.
|
|
2356
2383
|
this._sendPromise = this._sendPromise
|
|
2357
|
-
.then(() => generateContent(this._apiSettings, this.model, generateContentRequest, this.chromeAdapter,
|
|
2384
|
+
.then(() => generateContent(this._apiSettings, this.model, generateContentRequest, this.chromeAdapter, {
|
|
2385
|
+
...this.requestOptions,
|
|
2386
|
+
...singleRequestOptions
|
|
2387
|
+
}))
|
|
2358
2388
|
.then(result => {
|
|
2389
|
+
// TODO: Make this update atomic. If creating `responseContent` throws,
|
|
2390
|
+
// history will contain the user message but not the response, causing
|
|
2391
|
+
// validation errors on the next request.
|
|
2359
2392
|
if (result.response.candidates &&
|
|
2360
2393
|
result.response.candidates.length > 0) {
|
|
2361
2394
|
this._history.push(newContent);
|
|
2362
2395
|
const responseContent = {
|
|
2363
2396
|
parts: result.response.candidates?.[0].content.parts || [],
|
|
2364
|
-
// Response seems to come back without a role set.
|
|
2365
2397
|
role: result.response.candidates?.[0].content.role || 'model'
|
|
2366
2398
|
};
|
|
2367
2399
|
this._history.push(responseContent);
|
|
@@ -2382,7 +2414,7 @@ class ChatSession {
|
|
|
2382
2414
|
* {@link GenerateContentStreamResult} containing an iterable stream
|
|
2383
2415
|
* and a response promise.
|
|
2384
2416
|
*/
|
|
2385
|
-
async sendMessageStream(request) {
|
|
2417
|
+
async sendMessageStream(request, singleRequestOptions) {
|
|
2386
2418
|
await this._sendPromise;
|
|
2387
2419
|
const newContent = formatNewContent(request);
|
|
2388
2420
|
const generateContentRequest = {
|
|
@@ -2393,21 +2425,29 @@ class ChatSession {
|
|
|
2393
2425
|
systemInstruction: this.params?.systemInstruction,
|
|
2394
2426
|
contents: [...this._history, newContent]
|
|
2395
2427
|
};
|
|
2396
|
-
const streamPromise = generateContentStream(this._apiSettings, this.model, generateContentRequest, this.chromeAdapter,
|
|
2397
|
-
|
|
2428
|
+
const streamPromise = generateContentStream(this._apiSettings, this.model, generateContentRequest, this.chromeAdapter, {
|
|
2429
|
+
...this.requestOptions,
|
|
2430
|
+
...singleRequestOptions
|
|
2431
|
+
});
|
|
2432
|
+
// We hook into the chain to update history, but we don't block the
|
|
2433
|
+
// return of `streamPromise` to the user.
|
|
2398
2434
|
this._sendPromise = this._sendPromise
|
|
2399
2435
|
.then(() => streamPromise)
|
|
2400
|
-
// This must be handled to avoid unhandled rejection, but jump
|
|
2401
|
-
// to the final catch block with a label to not log this error.
|
|
2402
2436
|
.catch(_ignored => {
|
|
2437
|
+
// If the initial fetch fails, the user's `streamPromise` rejects.
|
|
2438
|
+
// We swallow the error here to prevent double logging in the final catch.
|
|
2403
2439
|
throw new Error(SILENT_ERROR);
|
|
2404
2440
|
})
|
|
2405
2441
|
.then(streamResult => streamResult.response)
|
|
2406
2442
|
.then(response => {
|
|
2443
|
+
// This runs after the stream completes. Runtime errors here cannot be
|
|
2444
|
+
// caught by the user because their promise has likely already resolved.
|
|
2445
|
+
// TODO: Move response validation logic upstream to `stream-reader` so
|
|
2446
|
+
// errors propagate to the user's `result.response` promise.
|
|
2407
2447
|
if (response.candidates && response.candidates.length > 0) {
|
|
2408
2448
|
this._history.push(newContent);
|
|
2449
|
+
// TODO: Validate that `response.candidates[0].content` is not null.
|
|
2409
2450
|
const responseContent = { ...response.candidates[0].content };
|
|
2410
|
-
// Response seems to come back without a role set.
|
|
2411
2451
|
if (!responseContent.role) {
|
|
2412
2452
|
responseContent.role = 'model';
|
|
2413
2453
|
}
|
|
@@ -2421,12 +2461,8 @@ class ChatSession {
|
|
|
2421
2461
|
}
|
|
2422
2462
|
})
|
|
2423
2463
|
.catch(e => {
|
|
2424
|
-
//
|
|
2425
|
-
|
|
2426
|
-
// Avoid duplicating the error message in logs.
|
|
2427
|
-
if (e.message !== SILENT_ERROR) {
|
|
2428
|
-
// Users do not have access to _sendPromise to catch errors
|
|
2429
|
-
// downstream from streamPromise, so they should not throw.
|
|
2464
|
+
// Filter out errors already handled by the user or initiated by them.
|
|
2465
|
+
if (e.message !== SILENT_ERROR && e.name !== 'AbortError') {
|
|
2430
2466
|
logger.error(e);
|
|
2431
2467
|
}
|
|
2432
2468
|
});
|
|
@@ -2450,7 +2486,7 @@ class ChatSession {
|
|
|
2450
2486
|
* See the License for the specific language governing permissions and
|
|
2451
2487
|
* limitations under the License.
|
|
2452
2488
|
*/
|
|
2453
|
-
async function countTokensOnCloud(apiSettings, model, params,
|
|
2489
|
+
async function countTokensOnCloud(apiSettings, model, params, singleRequestOptions) {
|
|
2454
2490
|
let body = '';
|
|
2455
2491
|
if (apiSettings.backend.backendType === BackendType.GOOGLE_AI) {
|
|
2456
2492
|
const mappedParams = mapCountTokensRequest(params, model);
|
|
@@ -2464,7 +2500,7 @@ async function countTokensOnCloud(apiSettings, model, params, requestOptions) {
|
|
|
2464
2500
|
task: "countTokens" /* Task.COUNT_TOKENS */,
|
|
2465
2501
|
apiSettings,
|
|
2466
2502
|
stream: false,
|
|
2467
|
-
|
|
2503
|
+
singleRequestOptions
|
|
2468
2504
|
}, body);
|
|
2469
2505
|
return response.json();
|
|
2470
2506
|
}
|
|
@@ -2500,6 +2536,7 @@ class GenerativeModel extends AIModel {
|
|
|
2500
2536
|
super(ai, modelParams.model);
|
|
2501
2537
|
this.chromeAdapter = chromeAdapter;
|
|
2502
2538
|
this.generationConfig = modelParams.generationConfig || {};
|
|
2539
|
+
validateGenerationConfig(this.generationConfig);
|
|
2503
2540
|
this.safetySettings = modelParams.safetySettings || [];
|
|
2504
2541
|
this.tools = modelParams.tools;
|
|
2505
2542
|
this.toolConfig = modelParams.toolConfig;
|
|
@@ -2510,7 +2547,7 @@ class GenerativeModel extends AIModel {
|
|
|
2510
2547
|
* Makes a single non-streaming call to the model
|
|
2511
2548
|
* and returns an object containing a single {@link GenerateContentResponse}.
|
|
2512
2549
|
*/
|
|
2513
|
-
async generateContent(request) {
|
|
2550
|
+
async generateContent(request, singleRequestOptions) {
|
|
2514
2551
|
const formattedParams = formatGenerateContentInput(request);
|
|
2515
2552
|
return generateContent(this._apiSettings, this.model, {
|
|
2516
2553
|
generationConfig: this.generationConfig,
|
|
@@ -2519,7 +2556,12 @@ class GenerativeModel extends AIModel {
|
|
|
2519
2556
|
toolConfig: this.toolConfig,
|
|
2520
2557
|
systemInstruction: this.systemInstruction,
|
|
2521
2558
|
...formattedParams
|
|
2522
|
-
}, this.chromeAdapter,
|
|
2559
|
+
}, this.chromeAdapter,
|
|
2560
|
+
// Merge request options
|
|
2561
|
+
{
|
|
2562
|
+
...this.requestOptions,
|
|
2563
|
+
...singleRequestOptions
|
|
2564
|
+
});
|
|
2523
2565
|
}
|
|
2524
2566
|
/**
|
|
2525
2567
|
* Makes a single streaming call to the model
|
|
@@ -2527,7 +2569,7 @@ class GenerativeModel extends AIModel {
|
|
|
2527
2569
|
* over all chunks in the streaming response as well as
|
|
2528
2570
|
* a promise that returns the final aggregated response.
|
|
2529
2571
|
*/
|
|
2530
|
-
async generateContentStream(request) {
|
|
2572
|
+
async generateContentStream(request, singleRequestOptions) {
|
|
2531
2573
|
const formattedParams = formatGenerateContentInput(request);
|
|
2532
2574
|
return generateContentStream(this._apiSettings, this.model, {
|
|
2533
2575
|
generationConfig: this.generationConfig,
|
|
@@ -2536,7 +2578,12 @@ class GenerativeModel extends AIModel {
|
|
|
2536
2578
|
toolConfig: this.toolConfig,
|
|
2537
2579
|
systemInstruction: this.systemInstruction,
|
|
2538
2580
|
...formattedParams
|
|
2539
|
-
}, this.chromeAdapter,
|
|
2581
|
+
}, this.chromeAdapter,
|
|
2582
|
+
// Merge request options
|
|
2583
|
+
{
|
|
2584
|
+
...this.requestOptions,
|
|
2585
|
+
...singleRequestOptions
|
|
2586
|
+
});
|
|
2540
2587
|
}
|
|
2541
2588
|
/**
|
|
2542
2589
|
* Gets a new {@link ChatSession} instance which can be used for
|
|
@@ -2560,9 +2607,26 @@ class GenerativeModel extends AIModel {
|
|
|
2560
2607
|
/**
|
|
2561
2608
|
* Counts the tokens in the provided request.
|
|
2562
2609
|
*/
|
|
2563
|
-
async countTokens(request) {
|
|
2610
|
+
async countTokens(request, singleRequestOptions) {
|
|
2564
2611
|
const formattedParams = formatGenerateContentInput(request);
|
|
2565
|
-
return countTokens(this._apiSettings, this.model, formattedParams, this.chromeAdapter
|
|
2612
|
+
return countTokens(this._apiSettings, this.model, formattedParams, this.chromeAdapter,
|
|
2613
|
+
// Merge request options
|
|
2614
|
+
{
|
|
2615
|
+
...this.requestOptions,
|
|
2616
|
+
...singleRequestOptions
|
|
2617
|
+
});
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
/**
|
|
2621
|
+
* Client-side validation of some common `GenerationConfig` pitfalls, in order
|
|
2622
|
+
* to save the developer a wasted request.
|
|
2623
|
+
*/
|
|
2624
|
+
function validateGenerationConfig(generationConfig) {
|
|
2625
|
+
if (
|
|
2626
|
+
// != allows for null and undefined. 0 is considered "set" by the model
|
|
2627
|
+
generationConfig.thinkingConfig?.thinkingBudget != null &&
|
|
2628
|
+
generationConfig.thinkingConfig?.thinkingLevel) {
|
|
2629
|
+
throw new AIError(AIErrorCode.UNSUPPORTED, `Cannot set both thinkingBudget and thinkingLevel in a config.`);
|
|
2566
2630
|
}
|
|
2567
2631
|
}
|
|
2568
2632
|
|
|
@@ -3013,7 +3077,7 @@ class ImagenModel extends AIModel {
|
|
|
3013
3077
|
*
|
|
3014
3078
|
* @public
|
|
3015
3079
|
*/
|
|
3016
|
-
async generateImages(prompt) {
|
|
3080
|
+
async generateImages(prompt, singleRequestOptions) {
|
|
3017
3081
|
const body = createPredictRequestBody(prompt, {
|
|
3018
3082
|
...this.generationConfig,
|
|
3019
3083
|
...this.safetySettings
|
|
@@ -3023,7 +3087,11 @@ class ImagenModel extends AIModel {
|
|
|
3023
3087
|
model: this.model,
|
|
3024
3088
|
apiSettings: this._apiSettings,
|
|
3025
3089
|
stream: false,
|
|
3026
|
-
|
|
3090
|
+
// Merge request options. Single request options overwrite the model's request options.
|
|
3091
|
+
singleRequestOptions: {
|
|
3092
|
+
...this.requestOptions,
|
|
3093
|
+
...singleRequestOptions
|
|
3094
|
+
}
|
|
3027
3095
|
}, JSON.stringify(body));
|
|
3028
3096
|
return handlePredictResponse(response);
|
|
3029
3097
|
}
|
|
@@ -3046,7 +3114,7 @@ class ImagenModel extends AIModel {
|
|
|
3046
3114
|
* returned object will have a `filteredReason` property.
|
|
3047
3115
|
* If all images are filtered, the `images` array will be empty.
|
|
3048
3116
|
*/
|
|
3049
|
-
async generateImagesGCS(prompt, gcsURI) {
|
|
3117
|
+
async generateImagesGCS(prompt, gcsURI, singleRequestOptions) {
|
|
3050
3118
|
const body = createPredictRequestBody(prompt, {
|
|
3051
3119
|
gcsURI,
|
|
3052
3120
|
...this.generationConfig,
|
|
@@ -3057,7 +3125,11 @@ class ImagenModel extends AIModel {
|
|
|
3057
3125
|
model: this.model,
|
|
3058
3126
|
apiSettings: this._apiSettings,
|
|
3059
3127
|
stream: false,
|
|
3060
|
-
|
|
3128
|
+
// Merge request options. Single request options overwrite the model's request options.
|
|
3129
|
+
singleRequestOptions: {
|
|
3130
|
+
...this.requestOptions,
|
|
3131
|
+
...singleRequestOptions
|
|
3132
|
+
}
|
|
3061
3133
|
}, JSON.stringify(body));
|
|
3062
3134
|
return handlePredictResponse(response);
|
|
3063
3135
|
}
|
|
@@ -3251,9 +3323,11 @@ class TemplateGenerativeModel {
|
|
|
3251
3323
|
*
|
|
3252
3324
|
* @beta
|
|
3253
3325
|
*/
|
|
3254
|
-
async generateContent(templateId, templateVariables
|
|
3255
|
-
|
|
3256
|
-
|
|
3326
|
+
async generateContent(templateId, templateVariables, singleRequestOptions) {
|
|
3327
|
+
return templateGenerateContent(this._apiSettings, templateId, { inputs: templateVariables }, {
|
|
3328
|
+
...this.requestOptions,
|
|
3329
|
+
...singleRequestOptions
|
|
3330
|
+
});
|
|
3257
3331
|
}
|
|
3258
3332
|
/**
|
|
3259
3333
|
* Makes a single streaming call to the model and returns an object
|
|
@@ -3267,8 +3341,11 @@ class TemplateGenerativeModel {
|
|
|
3267
3341
|
*
|
|
3268
3342
|
* @beta
|
|
3269
3343
|
*/
|
|
3270
|
-
async generateContentStream(templateId, templateVariables) {
|
|
3271
|
-
return templateGenerateContentStream(this._apiSettings, templateId, { inputs: templateVariables },
|
|
3344
|
+
async generateContentStream(templateId, templateVariables, singleRequestOptions) {
|
|
3345
|
+
return templateGenerateContentStream(this._apiSettings, templateId, { inputs: templateVariables }, {
|
|
3346
|
+
...this.requestOptions,
|
|
3347
|
+
...singleRequestOptions
|
|
3348
|
+
});
|
|
3272
3349
|
}
|
|
3273
3350
|
}
|
|
3274
3351
|
|
|
@@ -3313,13 +3390,16 @@ class TemplateImagenModel {
|
|
|
3313
3390
|
*
|
|
3314
3391
|
* @beta
|
|
3315
3392
|
*/
|
|
3316
|
-
async generateImages(templateId, templateVariables) {
|
|
3393
|
+
async generateImages(templateId, templateVariables, singleRequestOptions) {
|
|
3317
3394
|
const response = await makeRequest({
|
|
3318
3395
|
task: "templatePredict" /* ServerPromptTemplateTask.TEMPLATE_PREDICT */,
|
|
3319
3396
|
templateId,
|
|
3320
3397
|
apiSettings: this._apiSettings,
|
|
3321
3398
|
stream: false,
|
|
3322
|
-
|
|
3399
|
+
singleRequestOptions: {
|
|
3400
|
+
...this.requestOptions,
|
|
3401
|
+
...singleRequestOptions
|
|
3402
|
+
}
|
|
3323
3403
|
}, JSON.stringify({ inputs: templateVariables }));
|
|
3324
3404
|
return handlePredictResponse(response);
|
|
3325
3405
|
}
|
|
@@ -4154,5 +4234,5 @@ function registerAI() {
|
|
|
4154
4234
|
}
|
|
4155
4235
|
registerAI();
|
|
4156
4236
|
|
|
4157
|
-
export { AIError, AIErrorCode, AIModel, AnyOfSchema, ArraySchema, Backend, BackendType, BlockReason, BooleanSchema, ChatSession, FinishReason, FunctionCallingMode, GenerativeModel, GoogleAIBackend, HarmBlockMethod, HarmBlockThreshold, HarmCategory, HarmProbability, HarmSeverity, ImagenAspectRatio, ImagenImageFormat, ImagenModel, ImagenPersonFilterLevel, ImagenSafetyFilterLevel, InferenceMode, InferenceSource, IntegerSchema, Language, LiveGenerativeModel, LiveResponseType, LiveSession, Modality, NumberSchema, ObjectSchema, Outcome, POSSIBLE_ROLES, ResponseModality, Schema, SchemaType, StringSchema, TemplateGenerativeModel, TemplateImagenModel, URLRetrievalStatus, VertexAIBackend, getAI, getGenerativeModel, getImagenModel, getLiveGenerativeModel, getTemplateGenerativeModel, getTemplateImagenModel, startAudioConversation };
|
|
4237
|
+
export { AIError, AIErrorCode, AIModel, AnyOfSchema, ArraySchema, Backend, BackendType, BlockReason, BooleanSchema, ChatSession, FinishReason, FunctionCallingMode, GenerativeModel, GoogleAIBackend, HarmBlockMethod, HarmBlockThreshold, HarmCategory, HarmProbability, HarmSeverity, ImagenAspectRatio, ImagenImageFormat, ImagenModel, ImagenPersonFilterLevel, ImagenSafetyFilterLevel, InferenceMode, InferenceSource, IntegerSchema, Language, LiveGenerativeModel, LiveResponseType, LiveSession, Modality, NumberSchema, ObjectSchema, Outcome, POSSIBLE_ROLES, ResponseModality, Schema, SchemaType, StringSchema, TemplateGenerativeModel, TemplateImagenModel, ThinkingLevel, URLRetrievalStatus, VertexAIBackend, getAI, getGenerativeModel, getImagenModel, getLiveGenerativeModel, getTemplateGenerativeModel, getTemplateImagenModel, startAudioConversation };
|
|
4158
4238
|
//# sourceMappingURL=index.node.mjs.map
|