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/README.md +129 -0
- package/dist/chunk-Y4MC6YDW.mjs +135 -0
- package/dist/index.d.mts +511 -0
- package/dist/index.d.ts +511 -0
- package/dist/index.js +1696 -0
- package/dist/index.mjs +1480 -0
- package/dist/types-ADTG4FSI.mjs +46 -0
- package/package.json +60 -0
- package/src/auth.ts +293 -0
- package/src/backend.ts +615 -0
- package/src/client.ts +230 -0
- package/src/exceptions.ts +289 -0
- package/src/index.ts +148 -0
- package/src/session.ts +380 -0
- package/src/tools.ts +127 -0
- package/src/types.ts +352 -0
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
|
+
};
|