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