geminisdk 0.1.1

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/index.js ADDED
@@ -0,0 +1,1696 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
+
33
+ // src/types.ts
34
+ var types_exports = {};
35
+ __export(types_exports, {
36
+ EventType: () => EventType,
37
+ GEMINI_CLI_MODELS: () => GEMINI_CLI_MODELS,
38
+ GEMINI_CODE_ASSIST_API_VERSION: () => GEMINI_CODE_ASSIST_API_VERSION,
39
+ GEMINI_CODE_ASSIST_ENDPOINT: () => GEMINI_CODE_ASSIST_ENDPOINT,
40
+ GEMINI_CREDENTIAL_FILENAME: () => GEMINI_CREDENTIAL_FILENAME,
41
+ GEMINI_DIR: () => GEMINI_DIR,
42
+ GEMINI_ENV_FILENAME: () => GEMINI_ENV_FILENAME,
43
+ GEMINI_OAUTH_AUTH_ENDPOINT: () => GEMINI_OAUTH_AUTH_ENDPOINT,
44
+ GEMINI_OAUTH_BASE_URL: () => GEMINI_OAUTH_BASE_URL,
45
+ GEMINI_OAUTH_CLIENT_ID: () => GEMINI_OAUTH_CLIENT_ID,
46
+ GEMINI_OAUTH_CLIENT_SECRET: () => GEMINI_OAUTH_CLIENT_SECRET,
47
+ GEMINI_OAUTH_REDIRECT_URI: () => GEMINI_OAUTH_REDIRECT_URI,
48
+ GEMINI_OAUTH_SCOPES: () => GEMINI_OAUTH_SCOPES,
49
+ GEMINI_OAUTH_TOKEN_ENDPOINT: () => GEMINI_OAUTH_TOKEN_ENDPOINT,
50
+ HTTP_FORBIDDEN: () => HTTP_FORBIDDEN,
51
+ HTTP_OK: () => HTTP_OK,
52
+ HTTP_UNAUTHORIZED: () => HTTP_UNAUTHORIZED,
53
+ Role: () => Role,
54
+ TOKEN_REFRESH_BUFFER_MS: () => TOKEN_REFRESH_BUFFER_MS,
55
+ getGeminiCliCredentialPath: () => getGeminiCliCredentialPath,
56
+ getGeminiCliEnvPath: () => getGeminiCliEnvPath
57
+ });
58
+ function getGeminiCliCredentialPath(customPath) {
59
+ if (customPath) return customPath;
60
+ const home = process.env["HOME"] ?? process.env["USERPROFILE"] ?? "";
61
+ return `${home}/${GEMINI_DIR}/${GEMINI_CREDENTIAL_FILENAME}`;
62
+ }
63
+ function getGeminiCliEnvPath(customPath) {
64
+ if (customPath) return customPath;
65
+ const home = process.env["HOME"] ?? process.env["USERPROFILE"] ?? "";
66
+ return `${home}/${GEMINI_DIR}/${GEMINI_ENV_FILENAME}`;
67
+ }
68
+ var Role, EventType, GEMINI_OAUTH_REDIRECT_URI, GEMINI_OAUTH_BASE_URL, GEMINI_OAUTH_TOKEN_ENDPOINT, GEMINI_OAUTH_AUTH_ENDPOINT, GEMINI_OAUTH_CLIENT_ID, GEMINI_OAUTH_CLIENT_SECRET, GEMINI_OAUTH_SCOPES, GEMINI_CODE_ASSIST_ENDPOINT, GEMINI_CODE_ASSIST_API_VERSION, GEMINI_DIR, GEMINI_CREDENTIAL_FILENAME, GEMINI_ENV_FILENAME, TOKEN_REFRESH_BUFFER_MS, HTTP_OK, HTTP_UNAUTHORIZED, HTTP_FORBIDDEN, GEMINI_CLI_MODELS;
69
+ var init_types = __esm({
70
+ "src/types.ts"() {
71
+ "use strict";
72
+ Role = /* @__PURE__ */ ((Role2) => {
73
+ Role2["USER"] = "user";
74
+ Role2["ASSISTANT"] = "assistant";
75
+ Role2["SYSTEM"] = "system";
76
+ return Role2;
77
+ })(Role || {});
78
+ EventType = /* @__PURE__ */ ((EventType2) => {
79
+ EventType2["SESSION_CREATED"] = "session.created";
80
+ EventType2["SESSION_IDLE"] = "session.idle";
81
+ EventType2["SESSION_ERROR"] = "session.error";
82
+ EventType2["ASSISTANT_MESSAGE"] = "assistant.message";
83
+ EventType2["ASSISTANT_MESSAGE_DELTA"] = "assistant.message_delta";
84
+ EventType2["ASSISTANT_REASONING"] = "assistant.reasoning";
85
+ EventType2["ASSISTANT_REASONING_DELTA"] = "assistant.reasoning_delta";
86
+ EventType2["TOOL_CALL"] = "tool.call";
87
+ EventType2["TOOL_RESULT"] = "tool.result";
88
+ return EventType2;
89
+ })(EventType || {});
90
+ GEMINI_OAUTH_REDIRECT_URI = "http://localhost:45289";
91
+ GEMINI_OAUTH_BASE_URL = "https://accounts.google.com";
92
+ GEMINI_OAUTH_TOKEN_ENDPOINT = `${GEMINI_OAUTH_BASE_URL}/o/oauth2/token`;
93
+ GEMINI_OAUTH_AUTH_ENDPOINT = `${GEMINI_OAUTH_BASE_URL}/o/oauth2/v2/auth`;
94
+ GEMINI_OAUTH_CLIENT_ID = "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com";
95
+ GEMINI_OAUTH_CLIENT_SECRET = "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";
96
+ GEMINI_OAUTH_SCOPES = [
97
+ "https://www.googleapis.com/auth/cloud-platform",
98
+ "https://www.googleapis.com/auth/userinfo.email",
99
+ "https://www.googleapis.com/auth/userinfo.profile"
100
+ ];
101
+ GEMINI_CODE_ASSIST_ENDPOINT = "https://cloudcode-pa.googleapis.com";
102
+ GEMINI_CODE_ASSIST_API_VERSION = "v1internal";
103
+ GEMINI_DIR = ".gemini";
104
+ GEMINI_CREDENTIAL_FILENAME = "oauth_creds.json";
105
+ GEMINI_ENV_FILENAME = ".env";
106
+ TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1e3;
107
+ HTTP_OK = 200;
108
+ HTTP_UNAUTHORIZED = 401;
109
+ HTTP_FORBIDDEN = 403;
110
+ GEMINI_CLI_MODELS = {
111
+ "gemini-3-pro-preview": {
112
+ id: "gemini-3-pro-preview",
113
+ name: "Gemini 3 Pro Preview",
114
+ contextWindow: 1e6,
115
+ maxOutput: 65536,
116
+ inputPrice: 0,
117
+ outputPrice: 0,
118
+ supportsNativeTools: true,
119
+ supportsThinking: true
120
+ },
121
+ "gemini-3-flash-preview": {
122
+ id: "gemini-3-flash-preview",
123
+ name: "Gemini 3 Flash Preview",
124
+ contextWindow: 1e6,
125
+ maxOutput: 65536,
126
+ inputPrice: 0,
127
+ outputPrice: 0,
128
+ supportsNativeTools: true,
129
+ supportsThinking: true
130
+ },
131
+ "gemini-2.5-pro": {
132
+ id: "gemini-2.5-pro",
133
+ name: "Gemini 2.5 Pro",
134
+ contextWindow: 1048576,
135
+ maxOutput: 65536,
136
+ inputPrice: 0,
137
+ outputPrice: 0,
138
+ supportsNativeTools: true,
139
+ supportsThinking: true
140
+ },
141
+ "gemini-2.5-flash": {
142
+ id: "gemini-2.5-flash",
143
+ name: "Gemini 2.5 Flash",
144
+ contextWindow: 1048576,
145
+ maxOutput: 65536,
146
+ inputPrice: 0,
147
+ outputPrice: 0,
148
+ supportsNativeTools: true,
149
+ supportsThinking: true
150
+ },
151
+ "gemini-2.5-flash-lite": {
152
+ id: "gemini-2.5-flash-lite",
153
+ name: "Gemini 2.5 Flash Lite",
154
+ contextWindow: 1e6,
155
+ maxOutput: 32768,
156
+ inputPrice: 0,
157
+ outputPrice: 0,
158
+ supportsNativeTools: true,
159
+ supportsThinking: false
160
+ },
161
+ auto: {
162
+ id: "auto",
163
+ name: "Auto (Default)",
164
+ contextWindow: 1048576,
165
+ maxOutput: 65536,
166
+ inputPrice: 0,
167
+ outputPrice: 0,
168
+ supportsNativeTools: true,
169
+ supportsThinking: true
170
+ }
171
+ };
172
+ }
173
+ });
174
+
175
+ // src/index.ts
176
+ var index_exports = {};
177
+ __export(index_exports, {
178
+ APIError: () => APIError,
179
+ AuthenticationError: () => AuthenticationError,
180
+ CancellationError: () => CancellationError,
181
+ ConfigurationError: () => ConfigurationError,
182
+ ConnectionError: () => ConnectionError,
183
+ CredentialsNotFoundError: () => CredentialsNotFoundError,
184
+ EventType: () => EventType,
185
+ GEMINI_CLI_MODELS: () => GEMINI_CLI_MODELS,
186
+ GEMINI_CODE_ASSIST_API_VERSION: () => GEMINI_CODE_ASSIST_API_VERSION,
187
+ GEMINI_CODE_ASSIST_ENDPOINT: () => GEMINI_CODE_ASSIST_ENDPOINT,
188
+ GEMINI_CREDENTIAL_FILENAME: () => GEMINI_CREDENTIAL_FILENAME,
189
+ GEMINI_DIR: () => GEMINI_DIR,
190
+ GEMINI_ENV_FILENAME: () => GEMINI_ENV_FILENAME,
191
+ GEMINI_OAUTH_AUTH_ENDPOINT: () => GEMINI_OAUTH_AUTH_ENDPOINT,
192
+ GEMINI_OAUTH_BASE_URL: () => GEMINI_OAUTH_BASE_URL,
193
+ GEMINI_OAUTH_CLIENT_ID: () => GEMINI_OAUTH_CLIENT_ID,
194
+ GEMINI_OAUTH_CLIENT_SECRET: () => GEMINI_OAUTH_CLIENT_SECRET,
195
+ GEMINI_OAUTH_REDIRECT_URI: () => GEMINI_OAUTH_REDIRECT_URI,
196
+ GEMINI_OAUTH_SCOPES: () => GEMINI_OAUTH_SCOPES,
197
+ GEMINI_OAUTH_TOKEN_ENDPOINT: () => GEMINI_OAUTH_TOKEN_ENDPOINT,
198
+ GeminiBackend: () => GeminiBackend,
199
+ GeminiClient: () => GeminiClient,
200
+ GeminiOAuthManager: () => GeminiOAuthManager,
201
+ GeminiSDKError: () => GeminiSDKError,
202
+ GeminiSession: () => GeminiSession,
203
+ HTTP_FORBIDDEN: () => HTTP_FORBIDDEN,
204
+ HTTP_OK: () => HTTP_OK,
205
+ HTTP_UNAUTHORIZED: () => HTTP_UNAUTHORIZED,
206
+ NotFoundError: () => NotFoundError,
207
+ OnboardingError: () => OnboardingError,
208
+ PermissionDeniedError: () => PermissionDeniedError,
209
+ QuotaExceededError: () => QuotaExceededError,
210
+ RateLimitError: () => RateLimitError,
211
+ Role: () => Role,
212
+ SessionClosedError: () => SessionClosedError,
213
+ SessionError: () => SessionError,
214
+ SessionNotFoundError: () => SessionNotFoundError,
215
+ StreamError: () => StreamError,
216
+ TOKEN_REFRESH_BUFFER_MS: () => TOKEN_REFRESH_BUFFER_MS,
217
+ TimeoutError: () => TimeoutError,
218
+ TokenExpiredError: () => TokenExpiredError,
219
+ TokenRefreshError: () => TokenRefreshError,
220
+ ToolError: () => ToolError,
221
+ ToolExecutionError: () => ToolExecutionError,
222
+ ToolNotFoundError: () => ToolNotFoundError,
223
+ ToolRegistry: () => ToolRegistry,
224
+ VERSION: () => VERSION,
225
+ ValidationError: () => ValidationError,
226
+ createTool: () => createTool,
227
+ defineTool: () => defineTool,
228
+ getDefaultRegistry: () => getDefaultRegistry,
229
+ getGeminiCliCredentialPath: () => getGeminiCliCredentialPath,
230
+ getGeminiCliEnvPath: () => getGeminiCliEnvPath,
231
+ registerTool: () => registerTool
232
+ });
233
+ module.exports = __toCommonJS(index_exports);
234
+
235
+ // src/auth.ts
236
+ var fs = __toESM(require("fs"));
237
+ var path = __toESM(require("path"));
238
+
239
+ // src/exceptions.ts
240
+ var GeminiSDKError = class extends Error {
241
+ details;
242
+ constructor(message, details = {}) {
243
+ super(message);
244
+ this.name = "GeminiSDKError";
245
+ this.details = details;
246
+ Object.setPrototypeOf(this, new.target.prototype);
247
+ }
248
+ };
249
+ var AuthenticationError = class extends GeminiSDKError {
250
+ constructor(message = "Authentication failed", details = {}) {
251
+ super(message, details);
252
+ this.name = "AuthenticationError";
253
+ }
254
+ };
255
+ var CredentialsNotFoundError = class extends AuthenticationError {
256
+ credentialPath;
257
+ constructor(credentialPath, message) {
258
+ const msg = message ?? `Gemini OAuth credentials not found at ${credentialPath}. Please login using the Gemini CLI first: gemini auth login`;
259
+ super(msg, { credentialPath });
260
+ this.name = "CredentialsNotFoundError";
261
+ this.credentialPath = credentialPath;
262
+ }
263
+ };
264
+ var TokenRefreshError = class extends AuthenticationError {
265
+ statusCode;
266
+ responseBody;
267
+ constructor(message = "Failed to refresh access token", statusCode, responseBody) {
268
+ const details = {};
269
+ if (statusCode !== void 0) details["statusCode"] = statusCode;
270
+ if (responseBody !== void 0) details["responseBody"] = responseBody;
271
+ super(message, details);
272
+ this.name = "TokenRefreshError";
273
+ this.statusCode = statusCode;
274
+ this.responseBody = responseBody;
275
+ }
276
+ };
277
+ var TokenExpiredError = class extends AuthenticationError {
278
+ constructor(message = "Access token has expired") {
279
+ super(message);
280
+ this.name = "TokenExpiredError";
281
+ }
282
+ };
283
+ var ConnectionError = class extends GeminiSDKError {
284
+ endpoint;
285
+ constructor(message = "Failed to connect to Gemini API", endpoint, details = {}) {
286
+ if (endpoint) details["endpoint"] = endpoint;
287
+ super(message, details);
288
+ this.name = "ConnectionError";
289
+ this.endpoint = endpoint;
290
+ }
291
+ };
292
+ var APIError = class extends GeminiSDKError {
293
+ statusCode;
294
+ responseBody;
295
+ endpoint;
296
+ constructor(message, statusCode, responseBody, endpoint) {
297
+ const details = { statusCode };
298
+ if (responseBody !== void 0) details["responseBody"] = responseBody;
299
+ if (endpoint !== void 0) details["endpoint"] = endpoint;
300
+ super(message, details);
301
+ this.name = "APIError";
302
+ this.statusCode = statusCode;
303
+ this.responseBody = responseBody;
304
+ this.endpoint = endpoint;
305
+ }
306
+ };
307
+ var RateLimitError = class extends APIError {
308
+ retryAfter;
309
+ constructor(message = "Rate limit exceeded", statusCode = 429, retryAfter, responseBody) {
310
+ super(message, statusCode, responseBody);
311
+ this.name = "RateLimitError";
312
+ this.retryAfter = retryAfter;
313
+ if (retryAfter !== void 0) this.details["retryAfter"] = retryAfter;
314
+ }
315
+ };
316
+ var QuotaExceededError = class extends APIError {
317
+ resetTime;
318
+ constructor(message = "Quota exceeded", statusCode = 429, resetTime, responseBody) {
319
+ super(message, statusCode, responseBody);
320
+ this.name = "QuotaExceededError";
321
+ this.resetTime = resetTime;
322
+ if (resetTime !== void 0) this.details["resetTime"] = resetTime;
323
+ }
324
+ };
325
+ var PermissionDeniedError = class extends APIError {
326
+ constructor(message = "Permission denied", statusCode = 403, responseBody) {
327
+ super(message, statusCode, responseBody);
328
+ this.name = "PermissionDeniedError";
329
+ }
330
+ };
331
+ var NotFoundError = class extends APIError {
332
+ resource;
333
+ constructor(message = "Resource not found", statusCode = 404, resource, responseBody) {
334
+ super(message, statusCode, responseBody);
335
+ this.name = "NotFoundError";
336
+ this.resource = resource;
337
+ if (resource !== void 0) this.details["resource"] = resource;
338
+ }
339
+ };
340
+ var SessionError = class extends GeminiSDKError {
341
+ sessionId;
342
+ constructor(message, sessionId, details = {}) {
343
+ if (sessionId) details["sessionId"] = sessionId;
344
+ super(message, details);
345
+ this.name = "SessionError";
346
+ this.sessionId = sessionId;
347
+ }
348
+ };
349
+ var SessionNotFoundError = class extends SessionError {
350
+ constructor(sessionId) {
351
+ super(`Session not found: ${sessionId}`, sessionId);
352
+ this.name = "SessionNotFoundError";
353
+ }
354
+ };
355
+ var SessionClosedError = class extends SessionError {
356
+ constructor(sessionId) {
357
+ super("Session is closed", sessionId);
358
+ this.name = "SessionClosedError";
359
+ }
360
+ };
361
+ var ToolError = class extends GeminiSDKError {
362
+ toolName;
363
+ constructor(message, toolName, details = {}) {
364
+ if (toolName) details["toolName"] = toolName;
365
+ super(message, details);
366
+ this.name = "ToolError";
367
+ this.toolName = toolName;
368
+ }
369
+ };
370
+ var ToolNotFoundError = class extends ToolError {
371
+ constructor(toolName) {
372
+ super(`Tool not found: ${toolName}`, toolName);
373
+ this.name = "ToolNotFoundError";
374
+ }
375
+ };
376
+ var ToolExecutionError = class extends ToolError {
377
+ originalError;
378
+ constructor(message, toolName, originalError) {
379
+ const details = {};
380
+ if (originalError) details["originalError"] = originalError.message;
381
+ super(message, toolName, details);
382
+ this.name = "ToolExecutionError";
383
+ this.originalError = originalError;
384
+ }
385
+ };
386
+ var ValidationError = class extends GeminiSDKError {
387
+ field;
388
+ value;
389
+ constructor(message, field, value) {
390
+ const details = {};
391
+ if (field !== void 0) details["field"] = field;
392
+ if (value !== void 0) details["value"] = String(value);
393
+ super(message, details);
394
+ this.name = "ValidationError";
395
+ this.field = field;
396
+ this.value = value;
397
+ }
398
+ };
399
+ var ConfigurationError = class extends GeminiSDKError {
400
+ configKey;
401
+ constructor(message, configKey) {
402
+ const details = {};
403
+ if (configKey) details["configKey"] = configKey;
404
+ super(message, details);
405
+ this.name = "ConfigurationError";
406
+ this.configKey = configKey;
407
+ }
408
+ };
409
+ var StreamError = class extends GeminiSDKError {
410
+ partialContent;
411
+ constructor(message, partialContent) {
412
+ const details = {};
413
+ if (partialContent) details["partialContent"] = partialContent.slice(0, 500);
414
+ super(message, details);
415
+ this.name = "StreamError";
416
+ this.partialContent = partialContent;
417
+ }
418
+ };
419
+ var CancellationError = class extends GeminiSDKError {
420
+ constructor(message = "Operation was cancelled") {
421
+ super(message);
422
+ this.name = "CancellationError";
423
+ }
424
+ };
425
+ var TimeoutError = class extends GeminiSDKError {
426
+ timeout;
427
+ constructor(message = "Operation timed out", timeout) {
428
+ const details = {};
429
+ if (timeout !== void 0) details["timeout"] = timeout;
430
+ super(message, details);
431
+ this.name = "TimeoutError";
432
+ this.timeout = timeout;
433
+ }
434
+ };
435
+ var OnboardingError = class extends GeminiSDKError {
436
+ tierId;
437
+ constructor(message = "Failed to complete Gemini Code Assist onboarding", tierId) {
438
+ const details = {};
439
+ if (tierId) details["tierId"] = tierId;
440
+ super(message, details);
441
+ this.name = "OnboardingError";
442
+ this.tierId = tierId;
443
+ }
444
+ };
445
+
446
+ // src/auth.ts
447
+ init_types();
448
+ var GeminiOAuthManager = class {
449
+ oauthPath;
450
+ clientId;
451
+ clientSecret;
452
+ credentials = null;
453
+ refreshLock = null;
454
+ projectId = null;
455
+ constructor(oauthPath, clientId, clientSecret) {
456
+ this.oauthPath = oauthPath;
457
+ this.clientId = clientId ?? GEMINI_OAUTH_CLIENT_ID;
458
+ this.clientSecret = clientSecret ?? GEMINI_OAUTH_CLIENT_SECRET;
459
+ }
460
+ getCredentialPath() {
461
+ return getGeminiCliCredentialPath(this.oauthPath);
462
+ }
463
+ loadCachedCredentials() {
464
+ const keyFile = this.getCredentialPath();
465
+ try {
466
+ const data = JSON.parse(fs.readFileSync(keyFile, "utf-8"));
467
+ return {
468
+ accessToken: data["access_token"],
469
+ refreshToken: data["refresh_token"],
470
+ tokenType: data["token_type"] ?? "Bearer",
471
+ expiryDate: data["expiry_date"] ?? 0
472
+ };
473
+ } catch (error) {
474
+ if (error.code === "ENOENT") {
475
+ throw new CredentialsNotFoundError(keyFile);
476
+ }
477
+ throw new AuthenticationError(
478
+ `Invalid Gemini OAuth credentials file at ${keyFile}: ${error}`
479
+ );
480
+ }
481
+ }
482
+ saveCredentials(credentials) {
483
+ const keyFile = this.getCredentialPath();
484
+ const dir = path.dirname(keyFile);
485
+ if (!fs.existsSync(dir)) {
486
+ fs.mkdirSync(dir, { recursive: true });
487
+ }
488
+ const data = {
489
+ access_token: credentials.accessToken,
490
+ refresh_token: credentials.refreshToken,
491
+ token_type: credentials.tokenType,
492
+ expiry_date: credentials.expiryDate
493
+ };
494
+ fs.writeFileSync(keyFile, JSON.stringify(data, null, 2), "utf-8");
495
+ }
496
+ async refreshAccessToken(credentials) {
497
+ if (this.refreshLock) {
498
+ return this.refreshLock;
499
+ }
500
+ this.refreshLock = this.doRefresh(credentials);
501
+ try {
502
+ return await this.refreshLock;
503
+ } finally {
504
+ this.refreshLock = null;
505
+ }
506
+ }
507
+ async doRefresh(credentials) {
508
+ if (!credentials.refreshToken) {
509
+ throw new TokenRefreshError("No refresh token available in credentials.");
510
+ }
511
+ const bodyData = new URLSearchParams({
512
+ grant_type: "refresh_token",
513
+ refresh_token: credentials.refreshToken,
514
+ client_id: this.clientId,
515
+ client_secret: this.clientSecret,
516
+ scope: GEMINI_OAUTH_SCOPES.join(" ")
517
+ });
518
+ const response = await fetch(GEMINI_OAUTH_TOKEN_ENDPOINT, {
519
+ method: "POST",
520
+ headers: {
521
+ "Content-Type": "application/x-www-form-urlencoded",
522
+ Accept: "application/json",
523
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
524
+ },
525
+ body: bodyData.toString()
526
+ });
527
+ if (response.status !== HTTP_OK) {
528
+ throw new TokenRefreshError(
529
+ `Token refresh failed: ${response.status} ${response.statusText}`,
530
+ response.status,
531
+ await response.text()
532
+ );
533
+ }
534
+ const tokenData = await response.json();
535
+ if (tokenData["error"]) {
536
+ throw new TokenRefreshError(
537
+ `Token refresh failed: ${tokenData["error"]} - ${tokenData["error_description"] ?? "Unknown error"}`
538
+ );
539
+ }
540
+ const newCredentials = {
541
+ accessToken: tokenData["access_token"],
542
+ tokenType: tokenData["token_type"] ?? "Bearer",
543
+ refreshToken: tokenData["refresh_token"] ?? credentials.refreshToken,
544
+ expiryDate: Date.now() + (tokenData["expires_in"] ?? 3600) * 1e3
545
+ };
546
+ this.saveCredentials(newCredentials);
547
+ this.credentials = newCredentials;
548
+ return newCredentials;
549
+ }
550
+ isTokenValid(credentials) {
551
+ if (!credentials.expiryDate) return false;
552
+ return Date.now() < credentials.expiryDate - TOKEN_REFRESH_BUFFER_MS;
553
+ }
554
+ invalidateCredentials() {
555
+ this.credentials = null;
556
+ }
557
+ async ensureAuthenticated(forceRefresh = false) {
558
+ if (this.credentials === null) {
559
+ this.credentials = this.loadCachedCredentials();
560
+ }
561
+ if (forceRefresh || !this.isTokenValid(this.credentials)) {
562
+ this.credentials = await this.refreshAccessToken(this.credentials);
563
+ }
564
+ return this.credentials.accessToken;
565
+ }
566
+ async getCredentials() {
567
+ await this.ensureAuthenticated();
568
+ return this.credentials;
569
+ }
570
+ getApiEndpoint() {
571
+ return `${GEMINI_CODE_ASSIST_ENDPOINT}/${GEMINI_CODE_ASSIST_API_VERSION}`;
572
+ }
573
+ getProjectId() {
574
+ const envProjectId = process.env["GOOGLE_CLOUD_PROJECT"];
575
+ if (envProjectId) return envProjectId;
576
+ const envFile = getGeminiCliEnvPath(
577
+ this.oauthPath ? path.dirname(this.getCredentialPath()) : void 0
578
+ );
579
+ if (fs.existsSync(envFile)) {
580
+ try {
581
+ const content = fs.readFileSync(envFile, "utf-8");
582
+ for (const line of content.split("\n")) {
583
+ const trimmed = line.trim();
584
+ if (trimmed.startsWith("GOOGLE_CLOUD_PROJECT=")) {
585
+ return trimmed.split("=")[1]?.trim().replace(/['"]/g, "") ?? null;
586
+ }
587
+ }
588
+ } catch {
589
+ }
590
+ }
591
+ return this.projectId;
592
+ }
593
+ setProjectId(projectId) {
594
+ this.projectId = projectId;
595
+ }
596
+ generateAuthUrl(state, codeVerifier) {
597
+ const params = new URLSearchParams({
598
+ client_id: this.clientId,
599
+ redirect_uri: GEMINI_OAUTH_REDIRECT_URI,
600
+ response_type: "code",
601
+ scope: GEMINI_OAUTH_SCOPES.join(" "),
602
+ access_type: "offline",
603
+ state
604
+ });
605
+ if (codeVerifier) {
606
+ const encoder = new TextEncoder();
607
+ const data = encoder.encode(codeVerifier);
608
+ params.set("code_challenge_method", "S256");
609
+ }
610
+ return `${GEMINI_OAUTH_AUTH_ENDPOINT}?${params.toString()}`;
611
+ }
612
+ async exchangeCode(code, codeVerifier) {
613
+ const bodyData = new URLSearchParams({
614
+ grant_type: "authorization_code",
615
+ code,
616
+ client_id: this.clientId,
617
+ client_secret: this.clientSecret,
618
+ redirect_uri: GEMINI_OAUTH_REDIRECT_URI
619
+ });
620
+ if (codeVerifier) {
621
+ bodyData.set("code_verifier", codeVerifier);
622
+ }
623
+ const response = await fetch(GEMINI_OAUTH_TOKEN_ENDPOINT, {
624
+ method: "POST",
625
+ headers: {
626
+ "Content-Type": "application/x-www-form-urlencoded",
627
+ Accept: "application/json"
628
+ },
629
+ body: bodyData.toString()
630
+ });
631
+ if (response.status !== HTTP_OK) {
632
+ throw new AuthenticationError(
633
+ `Code exchange failed: ${response.status} - ${await response.text()}`
634
+ );
635
+ }
636
+ const tokenData = await response.json();
637
+ if (tokenData["error"]) {
638
+ throw new AuthenticationError(
639
+ `Code exchange failed: ${tokenData["error"]} - ${tokenData["error_description"] ?? "Unknown error"}`
640
+ );
641
+ }
642
+ const credentials = {
643
+ accessToken: tokenData["access_token"],
644
+ refreshToken: tokenData["refresh_token"],
645
+ tokenType: tokenData["token_type"] ?? "Bearer",
646
+ expiryDate: Date.now() + (tokenData["expires_in"] ?? 3600) * 1e3
647
+ };
648
+ this.saveCredentials(credentials);
649
+ this.credentials = credentials;
650
+ return credentials;
651
+ }
652
+ };
653
+
654
+ // src/backend.ts
655
+ var import_uuid = require("uuid");
656
+ init_types();
657
+ var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([HTTP_UNAUTHORIZED, HTTP_FORBIDDEN]);
658
+ var ONBOARD_MAX_RETRIES = 30;
659
+ var ONBOARD_SLEEP_SECONDS = 2;
660
+ function sleep(ms) {
661
+ return new Promise((resolve) => setTimeout(resolve, ms));
662
+ }
663
+ function generateUUID() {
664
+ try {
665
+ return (0, import_uuid.v4)();
666
+ } catch {
667
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
668
+ const r = Math.random() * 16 | 0;
669
+ const v = c === "x" ? r : r & 3 | 8;
670
+ return v.toString(16);
671
+ });
672
+ }
673
+ }
674
+ var GeminiBackend = class {
675
+ timeout;
676
+ oauthManager;
677
+ projectId = null;
678
+ constructor(options = {}) {
679
+ this.timeout = options.timeout ?? 72e4;
680
+ this.oauthManager = new GeminiOAuthManager(
681
+ options.oauthPath,
682
+ options.clientId,
683
+ options.clientSecret
684
+ );
685
+ }
686
+ async getAuthHeaders(forceRefresh = false) {
687
+ const accessToken = await this.oauthManager.ensureAuthenticated(forceRefresh);
688
+ return {
689
+ "Content-Type": "application/json",
690
+ Authorization: `Bearer ${accessToken}`
691
+ };
692
+ }
693
+ prepareMessages(messages) {
694
+ const result = [];
695
+ for (const msg of messages) {
696
+ const role = msg.role === "assistant" /* ASSISTANT */ ? "model" : "user";
697
+ const contentParts = [];
698
+ if (msg.content) {
699
+ if (typeof msg.content === "string") {
700
+ contentParts.push({ text: msg.content });
701
+ } else {
702
+ for (const part of msg.content) {
703
+ if (part.text) {
704
+ contentParts.push({ text: part.text });
705
+ } else if (part.imageData && part.imageMimeType) {
706
+ contentParts.push({
707
+ inlineData: {
708
+ mimeType: part.imageMimeType,
709
+ data: part.imageData instanceof Uint8Array ? Buffer.from(part.imageData).toString("base64") : part.imageData
710
+ }
711
+ });
712
+ }
713
+ }
714
+ }
715
+ }
716
+ if (msg.toolCalls) {
717
+ for (const tc of msg.toolCalls) {
718
+ const args = typeof tc.function.arguments === "string" ? JSON.parse(tc.function.arguments) : tc.function.arguments;
719
+ contentParts.push({
720
+ functionCall: {
721
+ name: tc.function.name,
722
+ args
723
+ }
724
+ });
725
+ }
726
+ }
727
+ if (msg.toolCallId) {
728
+ contentParts.push({
729
+ functionResponse: {
730
+ name: msg.name ?? "",
731
+ response: typeof msg.content === "string" ? { result: msg.content } : msg.content
732
+ }
733
+ });
734
+ }
735
+ if (contentParts.length > 0) {
736
+ result.push({ role, parts: contentParts });
737
+ }
738
+ }
739
+ return result;
740
+ }
741
+ prepareTools(tools) {
742
+ if (!tools || tools.length === 0) return void 0;
743
+ const funcDecls = [];
744
+ for (const tool of tools) {
745
+ const funcDef = {
746
+ name: tool.name,
747
+ description: tool.description ?? ""
748
+ };
749
+ if (tool.parameters) {
750
+ funcDef["parameters"] = {
751
+ type: "object",
752
+ properties: tool.parameters["properties"] ?? {},
753
+ required: tool.parameters["required"] ?? []
754
+ };
755
+ }
756
+ funcDecls.push(funcDef);
757
+ }
758
+ return [{ functionDeclarations: funcDecls }];
759
+ }
760
+ async ensureProjectId(accessToken) {
761
+ if (this.projectId !== null) return this.projectId;
762
+ const envProjectId = this.oauthManager.getProjectId();
763
+ const headers = {
764
+ Authorization: `Bearer ${accessToken}`,
765
+ "Content-Type": "application/json"
766
+ };
767
+ const clientMetadata = {
768
+ ideType: "IDE_UNSPECIFIED",
769
+ platform: "PLATFORM_UNSPECIFIED",
770
+ pluginType: "GEMINI",
771
+ duetProject: envProjectId
772
+ };
773
+ const loadRequest = {
774
+ cloudaicompanionProject: envProjectId,
775
+ metadata: clientMetadata
776
+ };
777
+ try {
778
+ const url = `${this.oauthManager.getApiEndpoint()}:loadCodeAssist`;
779
+ const response = await fetch(url, {
780
+ method: "POST",
781
+ headers,
782
+ body: JSON.stringify(loadRequest)
783
+ });
784
+ if (!response.ok) {
785
+ throw new Error(`HTTP ${response.status}`);
786
+ }
787
+ const data = await response.json();
788
+ if (data["currentTier"]) {
789
+ const projectFromApi = data["cloudaicompanionProject"];
790
+ if (projectFromApi) {
791
+ this.projectId = projectFromApi;
792
+ return projectFromApi;
793
+ }
794
+ if (envProjectId) {
795
+ this.projectId = envProjectId;
796
+ return envProjectId;
797
+ }
798
+ this.projectId = "";
799
+ return "";
800
+ }
801
+ const allowedTiers = data["allowedTiers"] ?? [];
802
+ let tierId = "free-tier";
803
+ for (const tier of allowedTiers) {
804
+ if (tier["isDefault"]) {
805
+ tierId = tier["id"] ?? "free-tier";
806
+ break;
807
+ }
808
+ }
809
+ return this.onboardForProject(headers, envProjectId, clientMetadata, tierId);
810
+ } catch (error) {
811
+ throw new APIError(
812
+ `Gemini Code Assist access denied: ${error}`,
813
+ 403,
814
+ String(error)
815
+ );
816
+ }
817
+ }
818
+ async onboardForProject(headers, envProjectId, clientMetadata, tierId) {
819
+ const onboardRequest = tierId === "free-tier" ? {
820
+ tierId,
821
+ cloudaicompanionProject: null,
822
+ metadata: clientMetadata
823
+ } : {
824
+ tierId,
825
+ cloudaicompanionProject: envProjectId,
826
+ metadata: { ...clientMetadata, duetProject: envProjectId }
827
+ };
828
+ const url = `${this.oauthManager.getApiEndpoint()}:onboardUser`;
829
+ for (let i = 0; i < ONBOARD_MAX_RETRIES; i++) {
830
+ const response = await fetch(url, {
831
+ method: "POST",
832
+ headers,
833
+ body: JSON.stringify(onboardRequest)
834
+ });
835
+ if (!response.ok) {
836
+ throw new Error(`Onboard failed: ${response.status}`);
837
+ }
838
+ const lroData = await response.json();
839
+ if (lroData["done"]) {
840
+ const responseData = lroData["response"] ?? {};
841
+ const cloudAiCompanion = responseData["cloudaicompanionProject"];
842
+ if (cloudAiCompanion?.["id"]) {
843
+ this.projectId = cloudAiCompanion["id"];
844
+ return this.projectId;
845
+ }
846
+ break;
847
+ }
848
+ await sleep(ONBOARD_SLEEP_SECONDS * 1e3);
849
+ }
850
+ if (tierId === "free-tier") {
851
+ this.projectId = "";
852
+ return "";
853
+ }
854
+ throw new OnboardingError(void 0, tierId);
855
+ }
856
+ buildRequestPayload(model, messages, generationConfig, thinkingConfig, tools, projectId = "") {
857
+ const genConfig = {
858
+ temperature: generationConfig?.temperature ?? 0.7
859
+ };
860
+ if (generationConfig?.maxOutputTokens) {
861
+ genConfig["maxOutputTokens"] = generationConfig.maxOutputTokens;
862
+ }
863
+ if (generationConfig?.topP !== void 0) {
864
+ genConfig["topP"] = generationConfig.topP;
865
+ }
866
+ if (generationConfig?.topK !== void 0) {
867
+ genConfig["topK"] = generationConfig.topK;
868
+ }
869
+ if (generationConfig?.stopSequences) {
870
+ genConfig["stopSequences"] = generationConfig.stopSequences;
871
+ }
872
+ if (thinkingConfig?.includeThoughts) {
873
+ genConfig["thinkingConfig"] = {
874
+ includeThoughts: thinkingConfig.includeThoughts,
875
+ ...thinkingConfig.thinkingBudget && {
876
+ thinkingBudget: thinkingConfig.thinkingBudget
877
+ }
878
+ };
879
+ }
880
+ const requestBody = {
881
+ contents: this.prepareMessages(messages),
882
+ generationConfig: genConfig
883
+ };
884
+ const preparedTools = this.prepareTools(tools);
885
+ if (preparedTools) {
886
+ requestBody["tools"] = preparedTools;
887
+ }
888
+ const payload = {
889
+ model,
890
+ request: requestBody
891
+ };
892
+ if (projectId) {
893
+ payload["project"] = projectId;
894
+ }
895
+ return payload;
896
+ }
897
+ parseCompletionResponse(data) {
898
+ const responseData = data["response"] ?? data;
899
+ const candidates = responseData["candidates"] ?? [];
900
+ if (candidates.length === 0) {
901
+ return {
902
+ content: "",
903
+ reasoningContent: void 0,
904
+ toolCalls: void 0,
905
+ usage: void 0,
906
+ finishReason: void 0
907
+ };
908
+ }
909
+ const candidate = candidates[0];
910
+ const contentObj = candidate["content"] ?? {};
911
+ const parts = contentObj["parts"] ?? [];
912
+ let textContent = "";
913
+ let reasoningContent;
914
+ let toolCalls;
915
+ for (const part of parts) {
916
+ if (part["text"]) {
917
+ textContent += part["text"];
918
+ }
919
+ if (part["thought"]) {
920
+ reasoningContent = part["thought"];
921
+ }
922
+ if (part["functionCall"]) {
923
+ const fc = part["functionCall"];
924
+ if (!toolCalls) toolCalls = [];
925
+ toolCalls.push({
926
+ id: generateUUID(),
927
+ type: "function",
928
+ function: {
929
+ name: fc["name"] ?? "",
930
+ arguments: fc["args"] ?? fc["arguments"] ?? {}
931
+ }
932
+ });
933
+ }
934
+ }
935
+ const usageData = data["usageMetadata"] ?? responseData["usageMetadata"] ?? {};
936
+ let usage;
937
+ if (Object.keys(usageData).length > 0) {
938
+ usage = {
939
+ promptTokens: usageData["promptTokenCount"] ?? 0,
940
+ completionTokens: usageData["candidatesTokenCount"] ?? 0,
941
+ totalTokens: usageData["totalTokenCount"] ?? 0
942
+ };
943
+ }
944
+ return {
945
+ content: textContent,
946
+ reasoningContent,
947
+ toolCalls,
948
+ usage,
949
+ finishReason: candidate["finishReason"]
950
+ };
951
+ }
952
+ async complete(options) {
953
+ return this.completeWithRetry(options, 0);
954
+ }
955
+ async completeWithRetry(options, retryCount) {
956
+ const headers = await this.getAuthHeaders(retryCount > 0);
957
+ if (options.extraHeaders) {
958
+ Object.assign(headers, options.extraHeaders);
959
+ }
960
+ const accessToken = headers["Authorization"].replace("Bearer ", "");
961
+ const projectId = await this.ensureProjectId(accessToken);
962
+ const url = `${this.oauthManager.getApiEndpoint()}:generateContent`;
963
+ const payload = this.buildRequestPayload(
964
+ options.model,
965
+ options.messages,
966
+ options.generationConfig,
967
+ options.thinkingConfig,
968
+ options.tools,
969
+ projectId
970
+ );
971
+ const controller = new AbortController();
972
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
973
+ try {
974
+ const response = await fetch(url, {
975
+ method: "POST",
976
+ headers,
977
+ body: JSON.stringify(payload),
978
+ signal: controller.signal
979
+ });
980
+ if (RETRYABLE_STATUS_CODES.has(response.status) && retryCount === 0) {
981
+ this.oauthManager.invalidateCredentials();
982
+ return this.completeWithRetry(options, 1);
983
+ }
984
+ if (!response.ok) {
985
+ this.handleHttpError(response.status, await response.text());
986
+ }
987
+ const data = await response.json();
988
+ return this.parseCompletionResponse(data);
989
+ } finally {
990
+ clearTimeout(timeoutId);
991
+ }
992
+ }
993
+ async *completeStreaming(options) {
994
+ yield* this.completeStreamingWithRetry(options, 0);
995
+ }
996
+ async *completeStreamingWithRetry(options, retryCount) {
997
+ const headers = await this.getAuthHeaders(retryCount > 0);
998
+ if (options.extraHeaders) {
999
+ Object.assign(headers, options.extraHeaders);
1000
+ }
1001
+ const accessToken = headers["Authorization"].replace("Bearer ", "");
1002
+ const projectId = await this.ensureProjectId(accessToken);
1003
+ const url = `${this.oauthManager.getApiEndpoint()}:streamGenerateContent?alt=sse`;
1004
+ const payload = this.buildRequestPayload(
1005
+ options.model,
1006
+ options.messages,
1007
+ options.generationConfig,
1008
+ options.thinkingConfig,
1009
+ options.tools,
1010
+ projectId
1011
+ );
1012
+ const controller = new AbortController();
1013
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
1014
+ try {
1015
+ const response = await fetch(url, {
1016
+ method: "POST",
1017
+ headers,
1018
+ body: JSON.stringify(payload),
1019
+ signal: controller.signal
1020
+ });
1021
+ if (RETRYABLE_STATUS_CODES.has(response.status) && retryCount === 0) {
1022
+ this.oauthManager.invalidateCredentials();
1023
+ yield* this.completeStreamingWithRetry(options, 1);
1024
+ return;
1025
+ }
1026
+ if (!response.ok) {
1027
+ this.handleHttpError(response.status, await response.text());
1028
+ }
1029
+ if (!response.body) {
1030
+ throw new APIError("No response body", 500);
1031
+ }
1032
+ const reader = response.body.getReader();
1033
+ const decoder = new TextDecoder();
1034
+ let buffer = "";
1035
+ while (true) {
1036
+ const { done, value } = await reader.read();
1037
+ if (done) break;
1038
+ buffer += decoder.decode(value, { stream: true });
1039
+ const lines = buffer.split("\n");
1040
+ buffer = lines.pop() ?? "";
1041
+ for (const line of lines) {
1042
+ const trimmed = line.trim();
1043
+ if (!trimmed || trimmed.startsWith(":")) continue;
1044
+ if (trimmed.startsWith("data:")) {
1045
+ const data = trimmed.slice(5).trim();
1046
+ if (data === "[DONE]") continue;
1047
+ try {
1048
+ const parsed = JSON.parse(data);
1049
+ if (parsed["error"]) {
1050
+ const errorMsg = typeof parsed["error"] === "object" ? parsed["error"]["message"] : String(parsed["error"]);
1051
+ throw new APIError(errorMsg, 500);
1052
+ }
1053
+ yield this.parseCompletionResponse(parsed);
1054
+ } catch (e) {
1055
+ if (e instanceof APIError) throw e;
1056
+ }
1057
+ }
1058
+ }
1059
+ }
1060
+ } finally {
1061
+ clearTimeout(timeoutId);
1062
+ }
1063
+ }
1064
+ handleHttpError(status, body) {
1065
+ let errorMsg = body;
1066
+ try {
1067
+ const errorData = JSON.parse(body);
1068
+ if (errorData["error"]) {
1069
+ const err = errorData["error"];
1070
+ errorMsg = err["message"] ?? body;
1071
+ }
1072
+ } catch {
1073
+ }
1074
+ if (status === 429) {
1075
+ throw new RateLimitError(`Rate limit exceeded: ${errorMsg}`, 429, void 0, body);
1076
+ } else if (status === 403) {
1077
+ throw new PermissionDeniedError(`Permission denied: ${errorMsg}`, 403, body);
1078
+ } else {
1079
+ throw new APIError(`API error: ${errorMsg}`, status, body);
1080
+ }
1081
+ }
1082
+ async listModels() {
1083
+ const { GEMINI_CLI_MODELS: GEMINI_CLI_MODELS2 } = await Promise.resolve().then(() => (init_types(), types_exports));
1084
+ return Object.keys(GEMINI_CLI_MODELS2);
1085
+ }
1086
+ async close() {
1087
+ }
1088
+ };
1089
+
1090
+ // src/session.ts
1091
+ init_types();
1092
+ var GeminiSession = class {
1093
+ _sessionId;
1094
+ _model;
1095
+ _backend;
1096
+ _tools;
1097
+ _toolHandlers;
1098
+ _systemMessage;
1099
+ _generationConfig;
1100
+ _thinkingConfig;
1101
+ _streaming;
1102
+ _messages = [];
1103
+ _eventHandlers = [];
1104
+ _closed = false;
1105
+ _startTime;
1106
+ _modifiedTime;
1107
+ constructor(options) {
1108
+ this._sessionId = options.sessionId;
1109
+ this._model = options.model;
1110
+ this._backend = options.backend;
1111
+ this._tools = options.tools ?? [];
1112
+ this._systemMessage = options.systemMessage;
1113
+ this._generationConfig = options.generationConfig;
1114
+ this._thinkingConfig = options.thinkingConfig;
1115
+ this._streaming = options.streaming ?? true;
1116
+ this._startTime = /* @__PURE__ */ new Date();
1117
+ this._modifiedTime = /* @__PURE__ */ new Date();
1118
+ this._toolHandlers = /* @__PURE__ */ new Map();
1119
+ for (const tool of this._tools) {
1120
+ if (tool.handler) {
1121
+ this._toolHandlers.set(tool.name, tool.handler);
1122
+ }
1123
+ }
1124
+ if (this._systemMessage) {
1125
+ this._messages.push({
1126
+ role: "system" /* SYSTEM */,
1127
+ content: this._systemMessage
1128
+ });
1129
+ }
1130
+ }
1131
+ get sessionId() {
1132
+ return this._sessionId;
1133
+ }
1134
+ get model() {
1135
+ return this._model;
1136
+ }
1137
+ get startTime() {
1138
+ return this._startTime;
1139
+ }
1140
+ get modifiedTime() {
1141
+ return this._modifiedTime;
1142
+ }
1143
+ get messages() {
1144
+ return [...this._messages];
1145
+ }
1146
+ on(handler) {
1147
+ this._eventHandlers.push(handler);
1148
+ return () => {
1149
+ const index = this._eventHandlers.indexOf(handler);
1150
+ if (index > -1) {
1151
+ this._eventHandlers.splice(index, 1);
1152
+ }
1153
+ };
1154
+ }
1155
+ emit(eventType, data) {
1156
+ const event = {
1157
+ type: eventType,
1158
+ data,
1159
+ sessionId: this._sessionId
1160
+ };
1161
+ for (const handler of this._eventHandlers) {
1162
+ try {
1163
+ handler(event);
1164
+ } catch (e) {
1165
+ console.warn("Event handler error:", e);
1166
+ }
1167
+ }
1168
+ }
1169
+ async send(options) {
1170
+ if (this._closed) {
1171
+ throw new SessionClosedError(this._sessionId);
1172
+ }
1173
+ const prompt = options.prompt;
1174
+ const context = options.context;
1175
+ let content = prompt;
1176
+ if (context) {
1177
+ content = `${context}
1178
+
1179
+ ${prompt}`;
1180
+ }
1181
+ const userMessage = {
1182
+ role: "user" /* USER */,
1183
+ content
1184
+ };
1185
+ this._messages.push(userMessage);
1186
+ this._modifiedTime = /* @__PURE__ */ new Date();
1187
+ try {
1188
+ if (this._streaming) {
1189
+ await this.streamResponse();
1190
+ } else {
1191
+ await this.getResponse();
1192
+ }
1193
+ } catch (e) {
1194
+ this.emit("session.error" /* SESSION_ERROR */, { error: String(e) });
1195
+ throw e;
1196
+ }
1197
+ }
1198
+ async sendAndWait(options) {
1199
+ return new Promise((resolve, reject) => {
1200
+ let responseEvent = null;
1201
+ const unsubscribe = this.on((event) => {
1202
+ if (event.type === "assistant.message" /* ASSISTANT_MESSAGE */) {
1203
+ responseEvent = event;
1204
+ } else if (event.type === "session.idle" /* SESSION_IDLE */ || event.type === "session.error" /* SESSION_ERROR */) {
1205
+ unsubscribe();
1206
+ if (responseEvent) {
1207
+ resolve(responseEvent);
1208
+ } else if (event.type === "session.error" /* SESSION_ERROR */) {
1209
+ reject(new Error(String(event.data?.["error"])));
1210
+ } else {
1211
+ reject(new Error("No response received"));
1212
+ }
1213
+ }
1214
+ });
1215
+ this.send(options).catch((e) => {
1216
+ unsubscribe();
1217
+ reject(e);
1218
+ });
1219
+ });
1220
+ }
1221
+ async streamResponse() {
1222
+ let fullContent = "";
1223
+ let fullReasoning = "";
1224
+ const allToolCalls = [];
1225
+ let finalUsage;
1226
+ for await (const chunk of this._backend.completeStreaming({
1227
+ model: this._model,
1228
+ messages: this._messages,
1229
+ generationConfig: this._generationConfig,
1230
+ thinkingConfig: this._thinkingConfig,
1231
+ tools: this._tools.length > 0 ? this._tools : void 0
1232
+ })) {
1233
+ if (chunk.content) {
1234
+ fullContent += chunk.content;
1235
+ this.emit("assistant.message_delta" /* ASSISTANT_MESSAGE_DELTA */, {
1236
+ deltaContent: chunk.content,
1237
+ content: fullContent
1238
+ });
1239
+ }
1240
+ if (chunk.reasoningContent) {
1241
+ fullReasoning += chunk.reasoningContent;
1242
+ this.emit("assistant.reasoning_delta" /* ASSISTANT_REASONING_DELTA */, {
1243
+ deltaContent: chunk.reasoningContent,
1244
+ content: fullReasoning
1245
+ });
1246
+ }
1247
+ if (chunk.toolCalls) {
1248
+ allToolCalls.push(...chunk.toolCalls);
1249
+ }
1250
+ if (chunk.usage) {
1251
+ finalUsage = chunk.usage;
1252
+ }
1253
+ }
1254
+ if (allToolCalls.length > 0) {
1255
+ await this.handleToolCalls(allToolCalls);
1256
+ }
1257
+ const assistantMessage = {
1258
+ role: "assistant" /* ASSISTANT */,
1259
+ content: fullContent,
1260
+ toolCalls: allToolCalls.length > 0 ? allToolCalls : void 0
1261
+ };
1262
+ this._messages.push(assistantMessage);
1263
+ if (fullReasoning) {
1264
+ this.emit("assistant.reasoning" /* ASSISTANT_REASONING */, {
1265
+ content: fullReasoning
1266
+ });
1267
+ }
1268
+ this.emit("assistant.message" /* ASSISTANT_MESSAGE */, {
1269
+ content: fullContent,
1270
+ toolCalls: allToolCalls.length > 0 ? allToolCalls : void 0,
1271
+ usage: finalUsage
1272
+ });
1273
+ this.emit("session.idle" /* SESSION_IDLE */, {});
1274
+ }
1275
+ async getResponse() {
1276
+ const chunk = await this._backend.complete({
1277
+ model: this._model,
1278
+ messages: this._messages,
1279
+ generationConfig: this._generationConfig,
1280
+ thinkingConfig: this._thinkingConfig,
1281
+ tools: this._tools.length > 0 ? this._tools : void 0
1282
+ });
1283
+ if (chunk.toolCalls) {
1284
+ await this.handleToolCalls(chunk.toolCalls);
1285
+ }
1286
+ const assistantMessage = {
1287
+ role: "assistant" /* ASSISTANT */,
1288
+ content: chunk.content,
1289
+ toolCalls: chunk.toolCalls
1290
+ };
1291
+ this._messages.push(assistantMessage);
1292
+ if (chunk.reasoningContent) {
1293
+ this.emit("assistant.reasoning" /* ASSISTANT_REASONING */, {
1294
+ content: chunk.reasoningContent
1295
+ });
1296
+ }
1297
+ this.emit("assistant.message" /* ASSISTANT_MESSAGE */, {
1298
+ content: chunk.content,
1299
+ toolCalls: chunk.toolCalls,
1300
+ usage: chunk.usage
1301
+ });
1302
+ this.emit("session.idle" /* SESSION_IDLE */, {});
1303
+ }
1304
+ async handleToolCalls(toolCalls) {
1305
+ for (const toolCall of toolCalls) {
1306
+ const toolName = toolCall.function.name;
1307
+ this.emit("tool.call" /* TOOL_CALL */, {
1308
+ name: toolName,
1309
+ arguments: toolCall.function.arguments,
1310
+ callId: toolCall.id
1311
+ });
1312
+ const handler = this._toolHandlers.get(toolName);
1313
+ if (!handler) {
1314
+ console.warn(`No handler for tool: ${toolName}`);
1315
+ this._messages.push({
1316
+ role: "user" /* USER */,
1317
+ content: `Error: Tool '${toolName}' not found`,
1318
+ toolCallId: toolCall.id,
1319
+ name: toolName
1320
+ });
1321
+ continue;
1322
+ }
1323
+ try {
1324
+ const invocation = {
1325
+ name: toolName,
1326
+ arguments: typeof toolCall.function.arguments === "object" ? toolCall.function.arguments : {},
1327
+ callId: toolCall.id
1328
+ };
1329
+ const result = await Promise.resolve(handler(invocation));
1330
+ const resultText = result.textResultForLlm ?? JSON.stringify(result);
1331
+ this.emit("tool.result" /* TOOL_RESULT */, {
1332
+ name: toolName,
1333
+ callId: toolCall.id,
1334
+ result: resultText
1335
+ });
1336
+ this._messages.push({
1337
+ role: "user" /* USER */,
1338
+ content: resultText,
1339
+ toolCallId: toolCall.id,
1340
+ name: toolName
1341
+ });
1342
+ } catch (e) {
1343
+ const errorMsg = `Error executing tool '${toolName}': ${e}`;
1344
+ console.error(errorMsg);
1345
+ this.emit("tool.result" /* TOOL_RESULT */, {
1346
+ name: toolName,
1347
+ callId: toolCall.id,
1348
+ error: String(e)
1349
+ });
1350
+ this._messages.push({
1351
+ role: "user" /* USER */,
1352
+ content: errorMsg,
1353
+ toolCallId: toolCall.id,
1354
+ name: toolName
1355
+ });
1356
+ }
1357
+ }
1358
+ }
1359
+ getMessages() {
1360
+ return [...this._messages];
1361
+ }
1362
+ addTool(tool) {
1363
+ this._tools.push(tool);
1364
+ if (tool.handler) {
1365
+ this._toolHandlers.set(tool.name, tool.handler);
1366
+ }
1367
+ }
1368
+ removeTool(toolName) {
1369
+ this._tools = this._tools.filter((t) => t.name !== toolName);
1370
+ this._toolHandlers.delete(toolName);
1371
+ }
1372
+ async clearHistory() {
1373
+ if (this._systemMessage) {
1374
+ this._messages = [{ role: "system" /* SYSTEM */, content: this._systemMessage }];
1375
+ } else {
1376
+ this._messages = [];
1377
+ }
1378
+ this._modifiedTime = /* @__PURE__ */ new Date();
1379
+ }
1380
+ async destroy() {
1381
+ this._closed = true;
1382
+ this._eventHandlers.length = 0;
1383
+ this._toolHandlers.clear();
1384
+ this._messages = [];
1385
+ }
1386
+ };
1387
+
1388
+ // src/client.ts
1389
+ init_types();
1390
+ function generateUUID2() {
1391
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
1392
+ const r = Math.random() * 16 | 0;
1393
+ const v = c === "x" ? r : r & 3 | 8;
1394
+ return v.toString(16);
1395
+ });
1396
+ }
1397
+ var GeminiClient = class {
1398
+ _options;
1399
+ _state = "disconnected";
1400
+ _backend = null;
1401
+ _oauthManager = null;
1402
+ _sessions = /* @__PURE__ */ new Map();
1403
+ _started = false;
1404
+ _autoRefreshInterval = null;
1405
+ constructor(options = {}) {
1406
+ this._options = options;
1407
+ }
1408
+ get options() {
1409
+ return this._options;
1410
+ }
1411
+ get state() {
1412
+ return this._state;
1413
+ }
1414
+ async start() {
1415
+ if (this._started) return;
1416
+ this._state = "connecting";
1417
+ try {
1418
+ this._oauthManager = new GeminiOAuthManager(
1419
+ this._options.oauthPath,
1420
+ this._options.clientId,
1421
+ this._options.clientSecret
1422
+ );
1423
+ this._backend = new GeminiBackend({
1424
+ timeout: this._options.timeout ?? 72e4,
1425
+ oauthPath: this._options.oauthPath,
1426
+ clientId: this._options.clientId,
1427
+ clientSecret: this._options.clientSecret
1428
+ });
1429
+ await this._oauthManager.ensureAuthenticated();
1430
+ this._state = "connected";
1431
+ this._started = true;
1432
+ if (this._options.autoRefresh !== false) {
1433
+ this.startAutoRefresh();
1434
+ }
1435
+ } catch (e) {
1436
+ this._state = "error";
1437
+ throw e;
1438
+ }
1439
+ }
1440
+ startAutoRefresh() {
1441
+ if (this._autoRefreshInterval) return;
1442
+ this._autoRefreshInterval = setInterval(async () => {
1443
+ try {
1444
+ if (this._oauthManager) {
1445
+ await this._oauthManager.ensureAuthenticated();
1446
+ }
1447
+ } catch (e) {
1448
+ }
1449
+ }, 3e4);
1450
+ }
1451
+ async stop() {
1452
+ if (this._autoRefreshInterval) {
1453
+ clearInterval(this._autoRefreshInterval);
1454
+ this._autoRefreshInterval = null;
1455
+ }
1456
+ for (const session of this._sessions.values()) {
1457
+ try {
1458
+ await session.destroy();
1459
+ } catch (e) {
1460
+ console.warn("Error destroying session:", e);
1461
+ }
1462
+ }
1463
+ this._sessions.clear();
1464
+ if (this._backend) {
1465
+ await this._backend.close();
1466
+ this._backend = null;
1467
+ }
1468
+ this._oauthManager = null;
1469
+ this._state = "disconnected";
1470
+ this._started = false;
1471
+ }
1472
+ async close() {
1473
+ await this.stop();
1474
+ }
1475
+ async createSession(config = {}) {
1476
+ if (!this._started) {
1477
+ await this.start();
1478
+ }
1479
+ if (!this._backend) {
1480
+ throw new Error("Client not connected. Call start() first.");
1481
+ }
1482
+ const sessionId = config.sessionId ?? generateUUID2();
1483
+ const model = config.model ?? "gemini-2.5-pro";
1484
+ const session = new GeminiSession({
1485
+ sessionId,
1486
+ model,
1487
+ backend: this._backend,
1488
+ tools: config.tools,
1489
+ systemMessage: config.systemMessage,
1490
+ generationConfig: config.generationConfig,
1491
+ thinkingConfig: config.thinkingConfig,
1492
+ streaming: config.streaming ?? true
1493
+ });
1494
+ this._sessions.set(sessionId, session);
1495
+ return session;
1496
+ }
1497
+ async getSession(sessionId) {
1498
+ const session = this._sessions.get(sessionId);
1499
+ if (!session) {
1500
+ throw new SessionNotFoundError(sessionId);
1501
+ }
1502
+ return session;
1503
+ }
1504
+ async listSessions() {
1505
+ const result = [];
1506
+ for (const session of this._sessions.values()) {
1507
+ result.push({
1508
+ sessionId: session.sessionId,
1509
+ startTime: session.startTime.toISOString(),
1510
+ modifiedTime: session.modifiedTime.toISOString(),
1511
+ model: session.model
1512
+ });
1513
+ }
1514
+ return result;
1515
+ }
1516
+ async deleteSession(sessionId) {
1517
+ const session = this._sessions.get(sessionId);
1518
+ if (session) {
1519
+ await session.destroy();
1520
+ this._sessions.delete(sessionId);
1521
+ }
1522
+ }
1523
+ getState() {
1524
+ return this._state;
1525
+ }
1526
+ async getAuthStatus() {
1527
+ if (!this._oauthManager) {
1528
+ return { authenticated: false };
1529
+ }
1530
+ try {
1531
+ const credentials = await this._oauthManager.getCredentials();
1532
+ return {
1533
+ authenticated: true,
1534
+ tokenType: credentials.tokenType,
1535
+ expiresAt: credentials.expiryDate
1536
+ };
1537
+ } catch {
1538
+ return { authenticated: false };
1539
+ }
1540
+ }
1541
+ async listModels() {
1542
+ const models = [];
1543
+ for (const [modelId, info] of Object.entries(GEMINI_CLI_MODELS)) {
1544
+ models.push({
1545
+ id: modelId,
1546
+ name: info.name,
1547
+ capabilities: {
1548
+ supports: {
1549
+ vision: false,
1550
+ tools: info.supportsNativeTools,
1551
+ thinking: info.supportsThinking
1552
+ },
1553
+ limits: {
1554
+ maxContextWindowTokens: info.contextWindow,
1555
+ maxPromptTokens: info.contextWindow
1556
+ }
1557
+ }
1558
+ });
1559
+ }
1560
+ return models;
1561
+ }
1562
+ async refreshAuth() {
1563
+ if (this._oauthManager) {
1564
+ await this._oauthManager.ensureAuthenticated(true);
1565
+ }
1566
+ }
1567
+ };
1568
+
1569
+ // src/tools.ts
1570
+ function defineTool(options, handler) {
1571
+ const toolName = options.name ?? handler.name ?? "unnamed_tool";
1572
+ const description = options.description ?? `Tool: ${toolName}`;
1573
+ const parameters = options.parameters ?? { type: "object", properties: {} };
1574
+ const wrappedHandler = async (invocation) => {
1575
+ const result = await Promise.resolve(handler(invocation.arguments));
1576
+ if (typeof result === "object" && result !== null && "textResultForLlm" in result) {
1577
+ return result;
1578
+ }
1579
+ return { textResultForLlm: String(result) };
1580
+ };
1581
+ return {
1582
+ name: toolName,
1583
+ description,
1584
+ parameters,
1585
+ handler: wrappedHandler
1586
+ };
1587
+ }
1588
+ function createTool(name, description, parameters, handler) {
1589
+ return {
1590
+ name,
1591
+ description,
1592
+ parameters: parameters ?? { type: "object", properties: {} },
1593
+ handler
1594
+ };
1595
+ }
1596
+ var ToolRegistry = class {
1597
+ tools = /* @__PURE__ */ new Map();
1598
+ categories = /* @__PURE__ */ new Map();
1599
+ register(tool, category) {
1600
+ this.tools.set(tool.name, tool);
1601
+ if (category) {
1602
+ if (!this.categories.has(category)) {
1603
+ this.categories.set(category, /* @__PURE__ */ new Set());
1604
+ }
1605
+ this.categories.get(category).add(tool.name);
1606
+ }
1607
+ }
1608
+ unregister(name) {
1609
+ this.tools.delete(name);
1610
+ for (const categoryTools of this.categories.values()) {
1611
+ categoryTools.delete(name);
1612
+ }
1613
+ }
1614
+ get(name) {
1615
+ return this.tools.get(name);
1616
+ }
1617
+ getAll() {
1618
+ return Array.from(this.tools.values());
1619
+ }
1620
+ getByCategory(category) {
1621
+ const toolNames = this.categories.get(category);
1622
+ if (!toolNames) return [];
1623
+ return Array.from(toolNames).map((name) => this.tools.get(name)).filter((tool) => tool !== void 0);
1624
+ }
1625
+ listCategories() {
1626
+ return Array.from(this.categories.keys());
1627
+ }
1628
+ };
1629
+ var defaultRegistry = new ToolRegistry();
1630
+ function getDefaultRegistry() {
1631
+ return defaultRegistry;
1632
+ }
1633
+ function registerTool(tool, category) {
1634
+ defaultRegistry.register(tool, category);
1635
+ }
1636
+
1637
+ // src/index.ts
1638
+ init_types();
1639
+ var VERSION = "0.1.1";
1640
+ // Annotate the CommonJS export names for ESM import in node:
1641
+ 0 && (module.exports = {
1642
+ APIError,
1643
+ AuthenticationError,
1644
+ CancellationError,
1645
+ ConfigurationError,
1646
+ ConnectionError,
1647
+ CredentialsNotFoundError,
1648
+ EventType,
1649
+ GEMINI_CLI_MODELS,
1650
+ GEMINI_CODE_ASSIST_API_VERSION,
1651
+ GEMINI_CODE_ASSIST_ENDPOINT,
1652
+ GEMINI_CREDENTIAL_FILENAME,
1653
+ GEMINI_DIR,
1654
+ GEMINI_ENV_FILENAME,
1655
+ GEMINI_OAUTH_AUTH_ENDPOINT,
1656
+ GEMINI_OAUTH_BASE_URL,
1657
+ GEMINI_OAUTH_CLIENT_ID,
1658
+ GEMINI_OAUTH_CLIENT_SECRET,
1659
+ GEMINI_OAUTH_REDIRECT_URI,
1660
+ GEMINI_OAUTH_SCOPES,
1661
+ GEMINI_OAUTH_TOKEN_ENDPOINT,
1662
+ GeminiBackend,
1663
+ GeminiClient,
1664
+ GeminiOAuthManager,
1665
+ GeminiSDKError,
1666
+ GeminiSession,
1667
+ HTTP_FORBIDDEN,
1668
+ HTTP_OK,
1669
+ HTTP_UNAUTHORIZED,
1670
+ NotFoundError,
1671
+ OnboardingError,
1672
+ PermissionDeniedError,
1673
+ QuotaExceededError,
1674
+ RateLimitError,
1675
+ Role,
1676
+ SessionClosedError,
1677
+ SessionError,
1678
+ SessionNotFoundError,
1679
+ StreamError,
1680
+ TOKEN_REFRESH_BUFFER_MS,
1681
+ TimeoutError,
1682
+ TokenExpiredError,
1683
+ TokenRefreshError,
1684
+ ToolError,
1685
+ ToolExecutionError,
1686
+ ToolNotFoundError,
1687
+ ToolRegistry,
1688
+ VERSION,
1689
+ ValidationError,
1690
+ createTool,
1691
+ defineTool,
1692
+ getDefaultRegistry,
1693
+ getGeminiCliCredentialPath,
1694
+ getGeminiCliEnvPath,
1695
+ registerTool
1696
+ });