@everworker/oneringai 0.4.1 → 0.4.3
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 +34 -8
- package/dist/{IProvider-Br817mKc.d.cts → IProvider-B8sqUzJG.d.cts} +37 -7
- package/dist/{IProvider-BUbU5UwV.d.ts → IProvider-CxDUGl6n.d.ts} +37 -7
- package/dist/{ImageModel-zh19LiVM.d.cts → ImageModel-Ds5_6sf7.d.cts} +1 -1
- package/dist/{ImageModel-B2KUs-ps.d.ts → ImageModel-OWbA277F.d.ts} +1 -1
- package/dist/capabilities/agents/index.d.cts +2 -2
- package/dist/capabilities/agents/index.d.ts +2 -2
- package/dist/capabilities/images/index.cjs +251 -106
- package/dist/capabilities/images/index.cjs.map +1 -1
- package/dist/capabilities/images/index.d.cts +2 -2
- package/dist/capabilities/images/index.d.ts +2 -2
- package/dist/capabilities/images/index.js +251 -106
- package/dist/capabilities/images/index.js.map +1 -1
- package/dist/{index-CR5PHkck.d.cts → index-CEjKTeSb.d.cts} +902 -7
- package/dist/{index-Cb7N9QIj.d.ts → index-CzGnmqOs.d.ts} +902 -7
- package/dist/index.cjs +2023 -484
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +440 -908
- package/dist/index.d.ts +440 -908
- package/dist/index.js +2003 -469
- package/dist/index.js.map +1 -1
- package/dist/shared/index.cjs +9 -0
- package/dist/shared/index.cjs.map +1 -1
- package/dist/shared/index.js +9 -0
- package/dist/shared/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -17,7 +17,7 @@ var z = require('zod/v4');
|
|
|
17
17
|
var spawn = require('cross-spawn');
|
|
18
18
|
var process2 = require('process');
|
|
19
19
|
var stream = require('stream');
|
|
20
|
-
var
|
|
20
|
+
var fs17 = require('fs/promises');
|
|
21
21
|
var simpleIcons = require('simple-icons');
|
|
22
22
|
var child_process = require('child_process');
|
|
23
23
|
var util = require('util');
|
|
@@ -55,7 +55,7 @@ var z4mini__namespace = /*#__PURE__*/_interopNamespace(z4mini);
|
|
|
55
55
|
var z__namespace = /*#__PURE__*/_interopNamespace(z);
|
|
56
56
|
var spawn__default = /*#__PURE__*/_interopDefault(spawn);
|
|
57
57
|
var process2__default = /*#__PURE__*/_interopDefault(process2);
|
|
58
|
-
var
|
|
58
|
+
var fs17__namespace = /*#__PURE__*/_interopNamespace(fs17);
|
|
59
59
|
var simpleIcons__namespace = /*#__PURE__*/_interopNamespace(simpleIcons);
|
|
60
60
|
var vm__namespace = /*#__PURE__*/_interopNamespace(vm);
|
|
61
61
|
|
|
@@ -195,6 +195,12 @@ var init_MemoryStorage = __esm({
|
|
|
195
195
|
size() {
|
|
196
196
|
return this.tokens.size;
|
|
197
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* List all storage keys (for account enumeration)
|
|
200
|
+
*/
|
|
201
|
+
async listKeys() {
|
|
202
|
+
return Array.from(this.tokens.keys());
|
|
203
|
+
}
|
|
198
204
|
};
|
|
199
205
|
}
|
|
200
206
|
});
|
|
@@ -212,14 +218,23 @@ var init_TokenStore = __esm({
|
|
|
212
218
|
this.storage = storage || new exports.MemoryStorage();
|
|
213
219
|
}
|
|
214
220
|
/**
|
|
215
|
-
* Get user-scoped storage key
|
|
216
|
-
*
|
|
217
|
-
*
|
|
221
|
+
* Get user-scoped (and optionally account-scoped) storage key
|
|
222
|
+
*
|
|
223
|
+
* Key format (backward compatible):
|
|
224
|
+
* - No userId, no accountId → baseKey
|
|
225
|
+
* - userId only → baseKey:userId
|
|
226
|
+
* - userId + accountId → baseKey:userId:accountId
|
|
227
|
+
* - accountId only → baseKey:default:accountId
|
|
218
228
|
*
|
|
219
229
|
* @param userId - User identifier (optional, defaults to single-user mode)
|
|
220
|
-
* @
|
|
230
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
231
|
+
* @returns Storage key scoped to user and account
|
|
221
232
|
*/
|
|
222
|
-
getScopedKey(userId) {
|
|
233
|
+
getScopedKey(userId, accountId) {
|
|
234
|
+
if (accountId) {
|
|
235
|
+
const userPart = userId && userId !== "default" ? userId : "default";
|
|
236
|
+
return `${this.baseStorageKey}:${userPart}:${accountId}`;
|
|
237
|
+
}
|
|
223
238
|
if (!userId || userId === "default") {
|
|
224
239
|
return this.baseStorageKey;
|
|
225
240
|
}
|
|
@@ -229,8 +244,9 @@ var init_TokenStore = __esm({
|
|
|
229
244
|
* Store token (encrypted by storage layer)
|
|
230
245
|
* @param tokenResponse - Token response from OAuth provider
|
|
231
246
|
* @param userId - Optional user identifier for multi-user support
|
|
247
|
+
* @param accountId - Optional account alias for multi-account support
|
|
232
248
|
*/
|
|
233
|
-
async storeToken(tokenResponse, userId) {
|
|
249
|
+
async storeToken(tokenResponse, userId, accountId) {
|
|
234
250
|
if (!tokenResponse.access_token) {
|
|
235
251
|
throw new Error("OAuth response missing required access_token field");
|
|
236
252
|
}
|
|
@@ -248,39 +264,46 @@ var init_TokenStore = __esm({
|
|
|
248
264
|
scope: tokenResponse.scope,
|
|
249
265
|
obtained_at: Date.now()
|
|
250
266
|
};
|
|
251
|
-
const key = this.getScopedKey(userId);
|
|
267
|
+
const key = this.getScopedKey(userId, accountId);
|
|
252
268
|
await this.storage.storeToken(key, token);
|
|
253
269
|
}
|
|
254
270
|
/**
|
|
255
271
|
* Get access token
|
|
256
272
|
* @param userId - Optional user identifier for multi-user support
|
|
273
|
+
* @param accountId - Optional account alias for multi-account support
|
|
257
274
|
*/
|
|
258
|
-
async getAccessToken(userId) {
|
|
259
|
-
const key = this.getScopedKey(userId);
|
|
275
|
+
async getAccessToken(userId, accountId) {
|
|
276
|
+
const key = this.getScopedKey(userId, accountId);
|
|
260
277
|
const token = await this.storage.getToken(key);
|
|
261
278
|
if (!token) {
|
|
262
|
-
|
|
279
|
+
const userLabel = userId ? `user: ${userId}` : "default user";
|
|
280
|
+
const accountLabel = accountId ? `, account: ${accountId}` : "";
|
|
281
|
+
throw new Error(`No token stored for ${userLabel}${accountLabel}`);
|
|
263
282
|
}
|
|
264
283
|
return token.access_token;
|
|
265
284
|
}
|
|
266
285
|
/**
|
|
267
286
|
* Get refresh token
|
|
268
287
|
* @param userId - Optional user identifier for multi-user support
|
|
288
|
+
* @param accountId - Optional account alias for multi-account support
|
|
269
289
|
*/
|
|
270
|
-
async getRefreshToken(userId) {
|
|
271
|
-
const key = this.getScopedKey(userId);
|
|
290
|
+
async getRefreshToken(userId, accountId) {
|
|
291
|
+
const key = this.getScopedKey(userId, accountId);
|
|
272
292
|
const token = await this.storage.getToken(key);
|
|
273
293
|
if (!token?.refresh_token) {
|
|
274
|
-
|
|
294
|
+
const userLabel = userId ? `user: ${userId}` : "default user";
|
|
295
|
+
const accountLabel = accountId ? `, account: ${accountId}` : "";
|
|
296
|
+
throw new Error(`No refresh token available for ${userLabel}${accountLabel}`);
|
|
275
297
|
}
|
|
276
298
|
return token.refresh_token;
|
|
277
299
|
}
|
|
278
300
|
/**
|
|
279
301
|
* Check if has refresh token
|
|
280
302
|
* @param userId - Optional user identifier for multi-user support
|
|
303
|
+
* @param accountId - Optional account alias for multi-account support
|
|
281
304
|
*/
|
|
282
|
-
async hasRefreshToken(userId) {
|
|
283
|
-
const key = this.getScopedKey(userId);
|
|
305
|
+
async hasRefreshToken(userId, accountId) {
|
|
306
|
+
const key = this.getScopedKey(userId, accountId);
|
|
284
307
|
const token = await this.storage.getToken(key);
|
|
285
308
|
return !!token?.refresh_token;
|
|
286
309
|
}
|
|
@@ -289,9 +312,10 @@ var init_TokenStore = __esm({
|
|
|
289
312
|
*
|
|
290
313
|
* @param bufferSeconds - Refresh this many seconds before expiry (default: 300 = 5 min)
|
|
291
314
|
* @param userId - Optional user identifier for multi-user support
|
|
315
|
+
* @param accountId - Optional account alias for multi-account support
|
|
292
316
|
*/
|
|
293
|
-
async isValid(bufferSeconds = 300, userId) {
|
|
294
|
-
const key = this.getScopedKey(userId);
|
|
317
|
+
async isValid(bufferSeconds = 300, userId, accountId) {
|
|
318
|
+
const key = this.getScopedKey(userId, accountId);
|
|
295
319
|
const token = await this.storage.getToken(key);
|
|
296
320
|
if (!token) {
|
|
297
321
|
return false;
|
|
@@ -303,19 +327,46 @@ var init_TokenStore = __esm({
|
|
|
303
327
|
/**
|
|
304
328
|
* Clear stored token
|
|
305
329
|
* @param userId - Optional user identifier for multi-user support
|
|
330
|
+
* @param accountId - Optional account alias for multi-account support
|
|
306
331
|
*/
|
|
307
|
-
async clear(userId) {
|
|
308
|
-
const key = this.getScopedKey(userId);
|
|
332
|
+
async clear(userId, accountId) {
|
|
333
|
+
const key = this.getScopedKey(userId, accountId);
|
|
309
334
|
await this.storage.deleteToken(key);
|
|
310
335
|
}
|
|
311
336
|
/**
|
|
312
337
|
* Get full token info
|
|
313
338
|
* @param userId - Optional user identifier for multi-user support
|
|
339
|
+
* @param accountId - Optional account alias for multi-account support
|
|
314
340
|
*/
|
|
315
|
-
async getTokenInfo(userId) {
|
|
316
|
-
const key = this.getScopedKey(userId);
|
|
341
|
+
async getTokenInfo(userId, accountId) {
|
|
342
|
+
const key = this.getScopedKey(userId, accountId);
|
|
317
343
|
return this.storage.getToken(key);
|
|
318
344
|
}
|
|
345
|
+
/**
|
|
346
|
+
* List account aliases for a user on this connector.
|
|
347
|
+
* Returns account IDs that have stored tokens.
|
|
348
|
+
*
|
|
349
|
+
* @param userId - Optional user identifier
|
|
350
|
+
* @returns Array of account aliases (e.g., ['work', 'personal'])
|
|
351
|
+
*/
|
|
352
|
+
async listAccounts(userId) {
|
|
353
|
+
if (!this.storage.listKeys) {
|
|
354
|
+
return [];
|
|
355
|
+
}
|
|
356
|
+
const allKeys = await this.storage.listKeys();
|
|
357
|
+
const userPart = userId && userId !== "default" ? userId : "default";
|
|
358
|
+
const prefix = `${this.baseStorageKey}:${userPart}:`;
|
|
359
|
+
const accounts = [];
|
|
360
|
+
for (const key of allKeys) {
|
|
361
|
+
if (key.startsWith(prefix)) {
|
|
362
|
+
const accountId = key.slice(prefix.length);
|
|
363
|
+
if (accountId && !accountId.includes(":")) {
|
|
364
|
+
accounts.push(accountId);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return accounts;
|
|
369
|
+
}
|
|
319
370
|
};
|
|
320
371
|
}
|
|
321
372
|
});
|
|
@@ -356,20 +407,28 @@ var init_AuthCodePKCE = __esm({
|
|
|
356
407
|
this.tokenStore = new TokenStore(storageKey, config.storage);
|
|
357
408
|
}
|
|
358
409
|
tokenStore;
|
|
359
|
-
// Store PKCE data per user with timestamps for cleanup
|
|
410
|
+
// Store PKCE data per user+account with timestamps for cleanup
|
|
360
411
|
codeVerifiers = /* @__PURE__ */ new Map();
|
|
361
412
|
states = /* @__PURE__ */ new Map();
|
|
362
|
-
// Store refresh locks per user to prevent concurrent refresh
|
|
413
|
+
// Store refresh locks per user+account to prevent concurrent refresh
|
|
363
414
|
refreshLocks = /* @__PURE__ */ new Map();
|
|
364
415
|
// PKCE data TTL: 15 minutes (auth flows should complete within this time)
|
|
365
416
|
PKCE_TTL = 15 * 60 * 1e3;
|
|
417
|
+
/**
|
|
418
|
+
* Build a map key from userId and accountId for internal PKCE/state/lock maps.
|
|
419
|
+
*/
|
|
420
|
+
getMapKey(userId, accountId) {
|
|
421
|
+
const userPart = userId || "default";
|
|
422
|
+
return accountId ? `${userPart}:${accountId}` : userPart;
|
|
423
|
+
}
|
|
366
424
|
/**
|
|
367
425
|
* Generate authorization URL for user to visit
|
|
368
426
|
* Opens browser or redirects user to this URL
|
|
369
427
|
*
|
|
370
428
|
* @param userId - User identifier for multi-user support (optional)
|
|
429
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
371
430
|
*/
|
|
372
|
-
async getAuthorizationUrl(userId) {
|
|
431
|
+
async getAuthorizationUrl(userId, accountId) {
|
|
373
432
|
if (!this.config.authorizationUrl) {
|
|
374
433
|
throw new Error("authorizationUrl is required for authorization_code flow");
|
|
375
434
|
}
|
|
@@ -377,11 +436,11 @@ var init_AuthCodePKCE = __esm({
|
|
|
377
436
|
throw new Error("redirectUri is required for authorization_code flow");
|
|
378
437
|
}
|
|
379
438
|
this.cleanupExpiredPKCE();
|
|
380
|
-
const
|
|
439
|
+
const mapKey = this.getMapKey(userId, accountId);
|
|
381
440
|
const { codeVerifier, codeChallenge } = generatePKCE();
|
|
382
|
-
this.codeVerifiers.set(
|
|
441
|
+
this.codeVerifiers.set(mapKey, { verifier: codeVerifier, timestamp: Date.now() });
|
|
383
442
|
const state = generateState();
|
|
384
|
-
this.states.set(
|
|
443
|
+
this.states.set(mapKey, { state, timestamp: Date.now() });
|
|
385
444
|
const params = new URLSearchParams({
|
|
386
445
|
response_type: "code",
|
|
387
446
|
client_id: this.config.clientId,
|
|
@@ -395,33 +454,48 @@ var init_AuthCodePKCE = __esm({
|
|
|
395
454
|
params.append("code_challenge", codeChallenge);
|
|
396
455
|
params.append("code_challenge_method", "S256");
|
|
397
456
|
}
|
|
398
|
-
|
|
399
|
-
|
|
457
|
+
let stateWithMetadata = state;
|
|
458
|
+
if (userId || accountId) {
|
|
459
|
+
stateWithMetadata = `${state}::${userId || ""}`;
|
|
460
|
+
if (accountId) {
|
|
461
|
+
stateWithMetadata += `::${accountId}`;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
params.set("state", stateWithMetadata);
|
|
400
465
|
return `${this.config.authorizationUrl}?${params.toString()}`;
|
|
401
466
|
}
|
|
402
467
|
/**
|
|
403
468
|
* Exchange authorization code for access token
|
|
404
469
|
*
|
|
405
470
|
* @param code - Authorization code from callback
|
|
406
|
-
* @param state - State parameter from callback (for CSRF verification, may include userId)
|
|
471
|
+
* @param state - State parameter from callback (for CSRF verification, may include userId/accountId)
|
|
407
472
|
* @param userId - User identifier (optional, can be extracted from state)
|
|
473
|
+
* @param accountId - Account alias (optional, can be extracted from state)
|
|
408
474
|
*/
|
|
409
|
-
async exchangeCode(code, state, userId) {
|
|
475
|
+
async exchangeCode(code, state, userId, accountId) {
|
|
410
476
|
let actualState = state;
|
|
411
477
|
let actualUserId = userId;
|
|
478
|
+
let actualAccountId = accountId;
|
|
412
479
|
if (state.includes("::")) {
|
|
413
480
|
const parts = state.split("::");
|
|
414
481
|
actualState = parts[0];
|
|
415
|
-
actualUserId
|
|
482
|
+
if (!actualUserId && parts[1]) {
|
|
483
|
+
actualUserId = parts[1];
|
|
484
|
+
}
|
|
485
|
+
if (!actualAccountId && parts[2]) {
|
|
486
|
+
actualAccountId = parts[2];
|
|
487
|
+
}
|
|
416
488
|
}
|
|
417
|
-
const
|
|
418
|
-
const stateData = this.states.get(
|
|
489
|
+
const mapKey = this.getMapKey(actualUserId, actualAccountId);
|
|
490
|
+
const stateData = this.states.get(mapKey);
|
|
419
491
|
if (!stateData) {
|
|
420
|
-
|
|
492
|
+
const label = actualAccountId ? `user ${actualUserId}, account ${actualAccountId}` : `user ${actualUserId}`;
|
|
493
|
+
throw new Error(`No PKCE state found for ${label}. Authorization flow may have expired (15 min TTL).`);
|
|
421
494
|
}
|
|
422
495
|
const expectedState = stateData.state;
|
|
423
496
|
if (actualState !== expectedState) {
|
|
424
|
-
|
|
497
|
+
const label = actualAccountId ? `user ${actualUserId}, account ${actualAccountId}` : `user ${actualUserId}`;
|
|
498
|
+
throw new Error(`State mismatch for ${label} - possible CSRF attack. Expected: ${expectedState}, Got: ${actualState}`);
|
|
425
499
|
}
|
|
426
500
|
if (!this.config.redirectUri) {
|
|
427
501
|
throw new Error("redirectUri is required");
|
|
@@ -435,7 +509,7 @@ var init_AuthCodePKCE = __esm({
|
|
|
435
509
|
if (this.config.clientSecret) {
|
|
436
510
|
params.append("client_secret", this.config.clientSecret);
|
|
437
511
|
}
|
|
438
|
-
const verifierData = this.codeVerifiers.get(
|
|
512
|
+
const verifierData = this.codeVerifiers.get(mapKey);
|
|
439
513
|
if (this.config.usePKCE !== false && verifierData) {
|
|
440
514
|
params.append("code_verifier", verifierData.verifier);
|
|
441
515
|
}
|
|
@@ -469,39 +543,43 @@ var init_AuthCodePKCE = __esm({
|
|
|
469
543
|
throw new Error(`Token exchange failed: ${response.status} ${response.statusText} - ${error}`);
|
|
470
544
|
}
|
|
471
545
|
const data = await response.json();
|
|
472
|
-
await this.tokenStore.storeToken(data, actualUserId);
|
|
473
|
-
this.codeVerifiers.delete(
|
|
474
|
-
this.states.delete(
|
|
546
|
+
await this.tokenStore.storeToken(data, actualUserId, actualAccountId);
|
|
547
|
+
this.codeVerifiers.delete(mapKey);
|
|
548
|
+
this.states.delete(mapKey);
|
|
475
549
|
}
|
|
476
550
|
/**
|
|
477
551
|
* Get valid token (auto-refreshes if needed)
|
|
478
552
|
* @param userId - User identifier for multi-user support
|
|
553
|
+
* @param accountId - Account alias for multi-account support
|
|
479
554
|
*/
|
|
480
|
-
async getToken(userId) {
|
|
481
|
-
const
|
|
482
|
-
if (this.refreshLocks.has(
|
|
483
|
-
return this.refreshLocks.get(
|
|
555
|
+
async getToken(userId, accountId) {
|
|
556
|
+
const mapKey = this.getMapKey(userId, accountId);
|
|
557
|
+
if (this.refreshLocks.has(mapKey)) {
|
|
558
|
+
return this.refreshLocks.get(mapKey);
|
|
484
559
|
}
|
|
485
|
-
if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId)) {
|
|
486
|
-
return this.tokenStore.getAccessToken(userId);
|
|
560
|
+
if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId)) {
|
|
561
|
+
return this.tokenStore.getAccessToken(userId, accountId);
|
|
487
562
|
}
|
|
488
|
-
if (await this.tokenStore.hasRefreshToken(userId)) {
|
|
489
|
-
const refreshPromise = this.refreshToken(userId);
|
|
490
|
-
this.refreshLocks.set(
|
|
563
|
+
if (await this.tokenStore.hasRefreshToken(userId, accountId)) {
|
|
564
|
+
const refreshPromise = this.refreshToken(userId, accountId);
|
|
565
|
+
this.refreshLocks.set(mapKey, refreshPromise);
|
|
491
566
|
try {
|
|
492
567
|
return await refreshPromise;
|
|
493
568
|
} finally {
|
|
494
|
-
this.refreshLocks.delete(
|
|
569
|
+
this.refreshLocks.delete(mapKey);
|
|
495
570
|
}
|
|
496
571
|
}
|
|
497
|
-
|
|
572
|
+
const userLabel = userId ? `user: ${userId}` : "default user";
|
|
573
|
+
const accountLabel = accountId ? `, account: ${accountId}` : "";
|
|
574
|
+
throw new Error(`No valid token available for ${userLabel}${accountLabel}. User needs to authorize (call startAuthFlow).`);
|
|
498
575
|
}
|
|
499
576
|
/**
|
|
500
577
|
* Refresh access token using refresh token
|
|
501
578
|
* @param userId - User identifier for multi-user support
|
|
579
|
+
* @param accountId - Account alias for multi-account support
|
|
502
580
|
*/
|
|
503
|
-
async refreshToken(userId) {
|
|
504
|
-
const refreshToken = await this.tokenStore.getRefreshToken(userId);
|
|
581
|
+
async refreshToken(userId, accountId) {
|
|
582
|
+
const refreshToken = await this.tokenStore.getRefreshToken(userId, accountId);
|
|
505
583
|
const params = new URLSearchParams({
|
|
506
584
|
grant_type: "refresh_token",
|
|
507
585
|
refresh_token: refreshToken,
|
|
@@ -540,28 +618,30 @@ var init_AuthCodePKCE = __esm({
|
|
|
540
618
|
throw new Error(`Token refresh failed: ${response.status} ${response.statusText} - ${error}`);
|
|
541
619
|
}
|
|
542
620
|
const data = await response.json();
|
|
543
|
-
await this.tokenStore.storeToken(data, userId);
|
|
621
|
+
await this.tokenStore.storeToken(data, userId, accountId);
|
|
544
622
|
return data.access_token;
|
|
545
623
|
}
|
|
546
624
|
/**
|
|
547
625
|
* Check if token is valid
|
|
548
626
|
* @param userId - User identifier for multi-user support
|
|
627
|
+
* @param accountId - Account alias for multi-account support
|
|
549
628
|
*/
|
|
550
|
-
async isTokenValid(userId) {
|
|
551
|
-
return this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId);
|
|
629
|
+
async isTokenValid(userId, accountId) {
|
|
630
|
+
return this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId);
|
|
552
631
|
}
|
|
553
632
|
/**
|
|
554
633
|
* Revoke token (if supported by provider)
|
|
555
634
|
* @param revocationUrl - Optional revocation endpoint
|
|
556
635
|
* @param userId - User identifier for multi-user support
|
|
636
|
+
* @param accountId - Account alias for multi-account support
|
|
557
637
|
*/
|
|
558
|
-
async revokeToken(revocationUrl, userId) {
|
|
638
|
+
async revokeToken(revocationUrl, userId, accountId) {
|
|
559
639
|
if (!revocationUrl) {
|
|
560
|
-
await this.tokenStore.clear(userId);
|
|
640
|
+
await this.tokenStore.clear(userId, accountId);
|
|
561
641
|
return;
|
|
562
642
|
}
|
|
563
643
|
try {
|
|
564
|
-
const token = await this.tokenStore.getAccessToken(userId);
|
|
644
|
+
const token = await this.tokenStore.getAccessToken(userId, accountId);
|
|
565
645
|
await fetch(revocationUrl, {
|
|
566
646
|
method: "POST",
|
|
567
647
|
headers: {
|
|
@@ -573,9 +653,16 @@ var init_AuthCodePKCE = __esm({
|
|
|
573
653
|
})
|
|
574
654
|
});
|
|
575
655
|
} finally {
|
|
576
|
-
await this.tokenStore.clear(userId);
|
|
656
|
+
await this.tokenStore.clear(userId, accountId);
|
|
577
657
|
}
|
|
578
658
|
}
|
|
659
|
+
/**
|
|
660
|
+
* List account aliases for a user.
|
|
661
|
+
* @param userId - User identifier (optional)
|
|
662
|
+
*/
|
|
663
|
+
async listAccounts(userId) {
|
|
664
|
+
return this.tokenStore.listAccounts(userId);
|
|
665
|
+
}
|
|
579
666
|
/**
|
|
580
667
|
* Clean up expired PKCE data to prevent memory leaks
|
|
581
668
|
* Removes verifiers and states older than PKCE_TTL (15 minutes)
|
|
@@ -607,17 +694,19 @@ var init_ClientCredentials = __esm({
|
|
|
607
694
|
tokenStore;
|
|
608
695
|
/**
|
|
609
696
|
* Get token using client credentials
|
|
697
|
+
* @param userId - User identifier for multi-user support (optional, rarely used for client_credentials)
|
|
698
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
610
699
|
*/
|
|
611
|
-
async getToken() {
|
|
612
|
-
if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry)) {
|
|
613
|
-
return this.tokenStore.getAccessToken();
|
|
700
|
+
async getToken(userId, accountId) {
|
|
701
|
+
if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId)) {
|
|
702
|
+
return this.tokenStore.getAccessToken(userId, accountId);
|
|
614
703
|
}
|
|
615
|
-
return this.requestToken();
|
|
704
|
+
return this.requestToken(userId, accountId);
|
|
616
705
|
}
|
|
617
706
|
/**
|
|
618
707
|
* Request a new token from the authorization server
|
|
619
708
|
*/
|
|
620
|
-
async requestToken() {
|
|
709
|
+
async requestToken(userId, accountId) {
|
|
621
710
|
const auth2 = Buffer.from(`${this.config.clientId}:${this.config.clientSecret}`).toString(
|
|
622
711
|
"base64"
|
|
623
712
|
);
|
|
@@ -640,22 +729,26 @@ var init_ClientCredentials = __esm({
|
|
|
640
729
|
throw new Error(`Token request failed: ${response.status} ${response.statusText} - ${error}`);
|
|
641
730
|
}
|
|
642
731
|
const data = await response.json();
|
|
643
|
-
await this.tokenStore.storeToken(data);
|
|
732
|
+
await this.tokenStore.storeToken(data, userId, accountId);
|
|
644
733
|
return data.access_token;
|
|
645
734
|
}
|
|
646
735
|
/**
|
|
647
736
|
* Refresh token (client credentials don't use refresh tokens)
|
|
648
737
|
* Just requests a new token
|
|
738
|
+
* @param userId - User identifier for multi-user support (optional)
|
|
739
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
649
740
|
*/
|
|
650
|
-
async refreshToken() {
|
|
651
|
-
await this.tokenStore.clear();
|
|
652
|
-
return this.requestToken();
|
|
741
|
+
async refreshToken(userId, accountId) {
|
|
742
|
+
await this.tokenStore.clear(userId, accountId);
|
|
743
|
+
return this.requestToken(userId, accountId);
|
|
653
744
|
}
|
|
654
745
|
/**
|
|
655
746
|
* Check if token is valid
|
|
747
|
+
* @param userId - User identifier for multi-user support (optional)
|
|
748
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
656
749
|
*/
|
|
657
|
-
async isTokenValid() {
|
|
658
|
-
return this.tokenStore.isValid(this.config.refreshBeforeExpiry);
|
|
750
|
+
async isTokenValid(userId, accountId) {
|
|
751
|
+
return this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId);
|
|
659
752
|
}
|
|
660
753
|
};
|
|
661
754
|
}
|
|
@@ -697,17 +790,19 @@ var init_JWTBearer = __esm({
|
|
|
697
790
|
}
|
|
698
791
|
/**
|
|
699
792
|
* Get token using JWT Bearer assertion
|
|
793
|
+
* @param userId - User identifier for multi-user support (optional)
|
|
794
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
700
795
|
*/
|
|
701
|
-
async getToken() {
|
|
702
|
-
if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry)) {
|
|
703
|
-
return this.tokenStore.getAccessToken();
|
|
796
|
+
async getToken(userId, accountId) {
|
|
797
|
+
if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId)) {
|
|
798
|
+
return this.tokenStore.getAccessToken(userId, accountId);
|
|
704
799
|
}
|
|
705
|
-
return this.requestToken();
|
|
800
|
+
return this.requestToken(userId, accountId);
|
|
706
801
|
}
|
|
707
802
|
/**
|
|
708
803
|
* Request token using JWT assertion
|
|
709
804
|
*/
|
|
710
|
-
async requestToken() {
|
|
805
|
+
async requestToken(userId, accountId) {
|
|
711
806
|
const assertion = await this.generateJWT();
|
|
712
807
|
const params = new URLSearchParams({
|
|
713
808
|
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
@@ -725,21 +820,25 @@ var init_JWTBearer = __esm({
|
|
|
725
820
|
throw new Error(`JWT Bearer token request failed: ${response.status} ${response.statusText} - ${error}`);
|
|
726
821
|
}
|
|
727
822
|
const data = await response.json();
|
|
728
|
-
await this.tokenStore.storeToken(data);
|
|
823
|
+
await this.tokenStore.storeToken(data, userId, accountId);
|
|
729
824
|
return data.access_token;
|
|
730
825
|
}
|
|
731
826
|
/**
|
|
732
827
|
* Refresh token (generate new JWT and request new token)
|
|
828
|
+
* @param userId - User identifier for multi-user support (optional)
|
|
829
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
733
830
|
*/
|
|
734
|
-
async refreshToken() {
|
|
735
|
-
await this.tokenStore.clear();
|
|
736
|
-
return this.requestToken();
|
|
831
|
+
async refreshToken(userId, accountId) {
|
|
832
|
+
await this.tokenStore.clear(userId, accountId);
|
|
833
|
+
return this.requestToken(userId, accountId);
|
|
737
834
|
}
|
|
738
835
|
/**
|
|
739
836
|
* Check if token is valid
|
|
837
|
+
* @param userId - User identifier for multi-user support (optional)
|
|
838
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
740
839
|
*/
|
|
741
|
-
async isTokenValid() {
|
|
742
|
-
return this.tokenStore.isValid(this.config.refreshBeforeExpiry);
|
|
840
|
+
async isTokenValid(userId, accountId) {
|
|
841
|
+
return this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId);
|
|
743
842
|
}
|
|
744
843
|
};
|
|
745
844
|
}
|
|
@@ -819,25 +918,28 @@ var init_OAuthManager = __esm({
|
|
|
819
918
|
* Automatically refreshes if expired
|
|
820
919
|
*
|
|
821
920
|
* @param userId - User identifier for multi-user support (optional)
|
|
921
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
822
922
|
*/
|
|
823
|
-
async getToken(userId) {
|
|
824
|
-
return this.flow.getToken(userId);
|
|
923
|
+
async getToken(userId, accountId) {
|
|
924
|
+
return this.flow.getToken(userId, accountId);
|
|
825
925
|
}
|
|
826
926
|
/**
|
|
827
927
|
* Force refresh the token
|
|
828
928
|
*
|
|
829
929
|
* @param userId - User identifier for multi-user support (optional)
|
|
930
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
830
931
|
*/
|
|
831
|
-
async refreshToken(userId) {
|
|
832
|
-
return this.flow.refreshToken(userId);
|
|
932
|
+
async refreshToken(userId, accountId) {
|
|
933
|
+
return this.flow.refreshToken(userId, accountId);
|
|
833
934
|
}
|
|
834
935
|
/**
|
|
835
936
|
* Check if current token is valid
|
|
836
937
|
*
|
|
837
938
|
* @param userId - User identifier for multi-user support (optional)
|
|
939
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
838
940
|
*/
|
|
839
|
-
async isTokenValid(userId) {
|
|
840
|
-
return this.flow.isTokenValid(userId);
|
|
941
|
+
async isTokenValid(userId, accountId) {
|
|
942
|
+
return this.flow.isTokenValid(userId, accountId);
|
|
841
943
|
}
|
|
842
944
|
// ==================== Authorization Code Flow Methods ====================
|
|
843
945
|
/**
|
|
@@ -845,13 +947,14 @@ var init_OAuthManager = __esm({
|
|
|
845
947
|
* Returns URL for user to visit
|
|
846
948
|
*
|
|
847
949
|
* @param userId - User identifier for multi-user support (optional)
|
|
950
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
848
951
|
* @returns Authorization URL for the user to visit
|
|
849
952
|
*/
|
|
850
|
-
async startAuthFlow(userId) {
|
|
953
|
+
async startAuthFlow(userId, accountId) {
|
|
851
954
|
if (!(this.flow instanceof AuthCodePKCEFlow)) {
|
|
852
955
|
throw new Error("startAuthFlow() is only available for authorization_code flow");
|
|
853
956
|
}
|
|
854
|
-
return this.flow.getAuthorizationUrl(userId);
|
|
957
|
+
return this.flow.getAuthorizationUrl(userId, accountId);
|
|
855
958
|
}
|
|
856
959
|
/**
|
|
857
960
|
* Handle OAuth callback (Authorization Code only)
|
|
@@ -859,8 +962,9 @@ var init_OAuthManager = __esm({
|
|
|
859
962
|
*
|
|
860
963
|
* @param callbackUrl - Full callback URL with code and state parameters
|
|
861
964
|
* @param userId - Optional user identifier (can be extracted from state if embedded)
|
|
965
|
+
* @param accountId - Optional account alias (can be extracted from state if embedded)
|
|
862
966
|
*/
|
|
863
|
-
async handleCallback(callbackUrl, userId) {
|
|
967
|
+
async handleCallback(callbackUrl, userId, accountId) {
|
|
864
968
|
if (!(this.flow instanceof AuthCodePKCEFlow)) {
|
|
865
969
|
throw new Error("handleCallback() is only available for authorization_code flow");
|
|
866
970
|
}
|
|
@@ -873,21 +977,34 @@ var init_OAuthManager = __esm({
|
|
|
873
977
|
if (!state) {
|
|
874
978
|
throw new Error("Missing state parameter in callback URL");
|
|
875
979
|
}
|
|
876
|
-
await this.flow.exchangeCode(code, state, userId);
|
|
980
|
+
await this.flow.exchangeCode(code, state, userId, accountId);
|
|
877
981
|
}
|
|
878
982
|
/**
|
|
879
983
|
* Revoke token (if supported by provider)
|
|
880
984
|
*
|
|
881
985
|
* @param revocationUrl - Optional revocation endpoint URL
|
|
882
986
|
* @param userId - User identifier for multi-user support (optional)
|
|
987
|
+
* @param accountId - Account alias for multi-account support (optional)
|
|
883
988
|
*/
|
|
884
|
-
async revokeToken(revocationUrl, userId) {
|
|
989
|
+
async revokeToken(revocationUrl, userId, accountId) {
|
|
885
990
|
if (this.flow instanceof AuthCodePKCEFlow) {
|
|
886
|
-
await this.flow.revokeToken(revocationUrl, userId);
|
|
991
|
+
await this.flow.revokeToken(revocationUrl, userId, accountId);
|
|
887
992
|
} else {
|
|
888
993
|
throw new Error("Token revocation not implemented for this flow");
|
|
889
994
|
}
|
|
890
995
|
}
|
|
996
|
+
/**
|
|
997
|
+
* List account aliases for a user (Authorization Code only)
|
|
998
|
+
*
|
|
999
|
+
* @param userId - User identifier (optional)
|
|
1000
|
+
* @returns Array of account aliases (e.g., ['work', 'personal'])
|
|
1001
|
+
*/
|
|
1002
|
+
async listAccounts(userId) {
|
|
1003
|
+
if (this.flow instanceof AuthCodePKCEFlow) {
|
|
1004
|
+
return this.flow.listAccounts(userId);
|
|
1005
|
+
}
|
|
1006
|
+
return [];
|
|
1007
|
+
}
|
|
891
1008
|
// ==================== Validation ====================
|
|
892
1009
|
validateConfig(config) {
|
|
893
1010
|
if (!config.flow) {
|
|
@@ -2093,46 +2210,59 @@ var init_Connector = __esm({
|
|
|
2093
2210
|
/**
|
|
2094
2211
|
* Get the current access token (for OAuth, JWT, or API key)
|
|
2095
2212
|
* Handles automatic refresh if needed
|
|
2213
|
+
*
|
|
2214
|
+
* @param userId - Optional user identifier for multi-user support
|
|
2215
|
+
* @param accountId - Optional account alias for multi-account support (e.g., 'work', 'personal')
|
|
2096
2216
|
*/
|
|
2097
|
-
async getToken(userId) {
|
|
2217
|
+
async getToken(userId, accountId) {
|
|
2098
2218
|
if (this.config.auth.type === "api_key") {
|
|
2099
2219
|
return this.config.auth.apiKey;
|
|
2100
2220
|
}
|
|
2101
2221
|
if (!this.oauthManager) {
|
|
2102
2222
|
throw new Error(`OAuth manager not initialized for connector '${this.name}'`);
|
|
2103
2223
|
}
|
|
2104
|
-
return this.oauthManager.getToken(userId);
|
|
2224
|
+
return this.oauthManager.getToken(userId, accountId);
|
|
2105
2225
|
}
|
|
2106
2226
|
/**
|
|
2107
2227
|
* Start OAuth authorization flow
|
|
2108
2228
|
* Returns the URL to redirect the user to
|
|
2229
|
+
*
|
|
2230
|
+
* @param userId - Optional user identifier for multi-user support
|
|
2231
|
+
* @param accountId - Optional account alias for multi-account support (e.g., 'work', 'personal')
|
|
2109
2232
|
*/
|
|
2110
|
-
async startAuth(userId) {
|
|
2233
|
+
async startAuth(userId, accountId) {
|
|
2111
2234
|
if (!this.oauthManager) {
|
|
2112
2235
|
throw new Error(`Connector '${this.name}' is not an OAuth connector`);
|
|
2113
2236
|
}
|
|
2114
|
-
return this.oauthManager.startAuthFlow(userId);
|
|
2237
|
+
return this.oauthManager.startAuthFlow(userId, accountId);
|
|
2115
2238
|
}
|
|
2116
2239
|
/**
|
|
2117
2240
|
* Handle OAuth callback
|
|
2118
2241
|
* Call this after user is redirected back from OAuth provider
|
|
2242
|
+
*
|
|
2243
|
+
* @param callbackUrl - Full callback URL with code and state parameters
|
|
2244
|
+
* @param userId - Optional user identifier (can be extracted from state if embedded)
|
|
2245
|
+
* @param accountId - Optional account alias (can be extracted from state if embedded)
|
|
2119
2246
|
*/
|
|
2120
|
-
async handleCallback(callbackUrl, userId) {
|
|
2247
|
+
async handleCallback(callbackUrl, userId, accountId) {
|
|
2121
2248
|
if (!this.oauthManager) {
|
|
2122
2249
|
throw new Error(`Connector '${this.name}' is not an OAuth connector`);
|
|
2123
2250
|
}
|
|
2124
|
-
await this.oauthManager.handleCallback(callbackUrl, userId);
|
|
2251
|
+
await this.oauthManager.handleCallback(callbackUrl, userId, accountId);
|
|
2125
2252
|
}
|
|
2126
2253
|
/**
|
|
2127
2254
|
* Check if the connector has a valid token
|
|
2255
|
+
*
|
|
2256
|
+
* @param userId - Optional user identifier for multi-user support
|
|
2257
|
+
* @param accountId - Optional account alias for multi-account support
|
|
2128
2258
|
*/
|
|
2129
|
-
async hasValidToken(userId) {
|
|
2259
|
+
async hasValidToken(userId, accountId) {
|
|
2130
2260
|
try {
|
|
2131
2261
|
if (this.config.auth.type === "api_key") {
|
|
2132
2262
|
return true;
|
|
2133
2263
|
}
|
|
2134
2264
|
if (this.oauthManager) {
|
|
2135
|
-
const token = await this.oauthManager.getToken(userId);
|
|
2265
|
+
const token = await this.oauthManager.getToken(userId, accountId);
|
|
2136
2266
|
return !!token;
|
|
2137
2267
|
}
|
|
2138
2268
|
return false;
|
|
@@ -2140,6 +2270,19 @@ var init_Connector = __esm({
|
|
|
2140
2270
|
return false;
|
|
2141
2271
|
}
|
|
2142
2272
|
}
|
|
2273
|
+
/**
|
|
2274
|
+
* List account aliases for a user on this connector.
|
|
2275
|
+
* Only applicable for OAuth connectors with multi-account support.
|
|
2276
|
+
*
|
|
2277
|
+
* @param userId - Optional user identifier
|
|
2278
|
+
* @returns Array of account aliases (e.g., ['work', 'personal'])
|
|
2279
|
+
*/
|
|
2280
|
+
async listAccounts(userId) {
|
|
2281
|
+
if (!this.oauthManager) {
|
|
2282
|
+
return [];
|
|
2283
|
+
}
|
|
2284
|
+
return this.oauthManager.listAccounts(userId);
|
|
2285
|
+
}
|
|
2143
2286
|
/**
|
|
2144
2287
|
* Get vendor-specific options from config
|
|
2145
2288
|
*/
|
|
@@ -2183,9 +2326,10 @@ var init_Connector = __esm({
|
|
|
2183
2326
|
* @param endpoint - API endpoint (relative to baseURL) or full URL
|
|
2184
2327
|
* @param options - Fetch options with connector-specific settings
|
|
2185
2328
|
* @param userId - Optional user ID for multi-user OAuth
|
|
2329
|
+
* @param accountId - Optional account alias for multi-account OAuth
|
|
2186
2330
|
* @returns Fetch Response
|
|
2187
2331
|
*/
|
|
2188
|
-
async fetch(endpoint, options, userId) {
|
|
2332
|
+
async fetch(endpoint, options, userId, accountId) {
|
|
2189
2333
|
if (this.disposed) {
|
|
2190
2334
|
throw new Error(`Connector '${this.name}' has been disposed`);
|
|
2191
2335
|
}
|
|
@@ -2204,7 +2348,7 @@ var init_Connector = __esm({
|
|
|
2204
2348
|
this.logRequest(url2, options);
|
|
2205
2349
|
}
|
|
2206
2350
|
const doFetch = async () => {
|
|
2207
|
-
const token = await this.getToken(userId);
|
|
2351
|
+
const token = await this.getToken(userId, accountId);
|
|
2208
2352
|
const auth2 = this.config.auth;
|
|
2209
2353
|
let headerName = "Authorization";
|
|
2210
2354
|
let headerValue = `Bearer ${token}`;
|
|
@@ -2316,10 +2460,11 @@ var init_Connector = __esm({
|
|
|
2316
2460
|
* @param endpoint - API endpoint (relative to baseURL) or full URL
|
|
2317
2461
|
* @param options - Fetch options with connector-specific settings
|
|
2318
2462
|
* @param userId - Optional user ID for multi-user OAuth
|
|
2463
|
+
* @param accountId - Optional account alias for multi-account OAuth
|
|
2319
2464
|
* @returns Parsed JSON response
|
|
2320
2465
|
*/
|
|
2321
|
-
async fetchJSON(endpoint, options, userId) {
|
|
2322
|
-
const response = await this.fetch(endpoint, options, userId);
|
|
2466
|
+
async fetchJSON(endpoint, options, userId, accountId) {
|
|
2467
|
+
const response = await this.fetch(endpoint, options, userId, accountId);
|
|
2323
2468
|
const text = await response.text();
|
|
2324
2469
|
let data;
|
|
2325
2470
|
try {
|
|
@@ -11268,6 +11413,18 @@ var ToolManager = class extends eventemitter3.EventEmitter {
|
|
|
11268
11413
|
this.register(tool, options);
|
|
11269
11414
|
}
|
|
11270
11415
|
}
|
|
11416
|
+
/**
|
|
11417
|
+
* Register tools produced by a specific connector.
|
|
11418
|
+
* Sets `source: 'connector:<connectorName>'` (or `'connector:<name>:<accountId>'` for identity-bound tools)
|
|
11419
|
+
* so agent-level filtering can restrict which connector tools are visible to a given agent.
|
|
11420
|
+
*/
|
|
11421
|
+
registerConnectorTools(connectorName, tools, options = {}) {
|
|
11422
|
+
const { accountId, ...toolOptions } = options;
|
|
11423
|
+
const source = accountId ? `connector:${connectorName}:${accountId}` : `connector:${connectorName}`;
|
|
11424
|
+
for (const tool of tools) {
|
|
11425
|
+
this.register(tool, { ...toolOptions, source });
|
|
11426
|
+
}
|
|
11427
|
+
}
|
|
11271
11428
|
/**
|
|
11272
11429
|
* Unregister a tool by name
|
|
11273
11430
|
*/
|
|
@@ -11458,6 +11615,14 @@ var ToolManager = class extends eventemitter3.EventEmitter {
|
|
|
11458
11615
|
getEnabled() {
|
|
11459
11616
|
return this.getSortedByPriority().filter((reg) => reg.enabled).map((reg) => reg.tool);
|
|
11460
11617
|
}
|
|
11618
|
+
/**
|
|
11619
|
+
* Get all enabled registrations (sorted by priority).
|
|
11620
|
+
* Includes full registration metadata (source, namespace, etc.)
|
|
11621
|
+
* for use in connector-aware filtering.
|
|
11622
|
+
*/
|
|
11623
|
+
getEnabledRegistrations() {
|
|
11624
|
+
return this.getSortedByPriority().filter((reg) => reg.enabled);
|
|
11625
|
+
}
|
|
11461
11626
|
/**
|
|
11462
11627
|
* Get all tools (enabled and disabled)
|
|
11463
11628
|
*/
|
|
@@ -11650,6 +11815,13 @@ var ToolManager = class extends eventemitter3.EventEmitter {
|
|
|
11650
11815
|
if (!registration.enabled) {
|
|
11651
11816
|
throw new ToolExecutionError(toolName, "Tool is disabled");
|
|
11652
11817
|
}
|
|
11818
|
+
if (registration.source?.startsWith("connector:")) {
|
|
11819
|
+
const connName = registration.source.slice("connector:".length);
|
|
11820
|
+
const registry = this._toolContext?.connectorRegistry;
|
|
11821
|
+
if (registry && !registry.has(connName)) {
|
|
11822
|
+
throw new ToolExecutionError(toolName, `Connector '${connName}' is not available to this agent`);
|
|
11823
|
+
}
|
|
11824
|
+
}
|
|
11653
11825
|
const breaker = this.getOrCreateCircuitBreaker(toolName, registration);
|
|
11654
11826
|
this.toolLogger.debug({ toolName, args }, "Tool execution started");
|
|
11655
11827
|
const startTime = Date.now();
|
|
@@ -11943,6 +12115,9 @@ var ToolManager = class extends eventemitter3.EventEmitter {
|
|
|
11943
12115
|
}
|
|
11944
12116
|
};
|
|
11945
12117
|
|
|
12118
|
+
// src/core/context-nextgen/AgentContextNextGen.ts
|
|
12119
|
+
init_Logger();
|
|
12120
|
+
|
|
11946
12121
|
// src/core/Vendor.ts
|
|
11947
12122
|
var Vendor = {
|
|
11948
12123
|
OpenAI: "openai",
|
|
@@ -13316,6 +13491,7 @@ var ContentType = /* @__PURE__ */ ((ContentType2) => {
|
|
|
13316
13491
|
ContentType2["OUTPUT_TEXT"] = "output_text";
|
|
13317
13492
|
ContentType2["TOOL_USE"] = "tool_use";
|
|
13318
13493
|
ContentType2["TOOL_RESULT"] = "tool_result";
|
|
13494
|
+
ContentType2["THINKING"] = "thinking";
|
|
13319
13495
|
return ContentType2;
|
|
13320
13496
|
})(ContentType || {});
|
|
13321
13497
|
|
|
@@ -13578,6 +13754,11 @@ var BasePluginNextGen = class {
|
|
|
13578
13754
|
}
|
|
13579
13755
|
};
|
|
13580
13756
|
|
|
13757
|
+
// src/core/context-nextgen/snapshot.ts
|
|
13758
|
+
function formatPluginDisplayName(name) {
|
|
13759
|
+
return name.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
13760
|
+
}
|
|
13761
|
+
|
|
13581
13762
|
// src/core/context-nextgen/AgentContextNextGen.ts
|
|
13582
13763
|
init_Connector();
|
|
13583
13764
|
|
|
@@ -16256,8 +16437,11 @@ var AlgorithmicCompactionStrategy = class {
|
|
|
16256
16437
|
* Emergency compaction when context exceeds threshold.
|
|
16257
16438
|
*
|
|
16258
16439
|
* Strategy:
|
|
16259
|
-
* 1. Run consolidate() first to move tool results to memory
|
|
16440
|
+
* 1. Run consolidate() first to move tool results to memory (if working memory available)
|
|
16260
16441
|
* 2. If still need space, apply rolling window (remove oldest messages)
|
|
16442
|
+
*
|
|
16443
|
+
* Gracefully degrades: if working memory plugin is not registered,
|
|
16444
|
+
* skips step 1 and only uses rolling window compaction.
|
|
16261
16445
|
*/
|
|
16262
16446
|
async compact(context, targetToFree) {
|
|
16263
16447
|
const log = [];
|
|
@@ -16270,7 +16454,7 @@ var AlgorithmicCompactionStrategy = class {
|
|
|
16270
16454
|
tokensFreed += Math.abs(consolidateResult.tokensChanged);
|
|
16271
16455
|
log.push(...consolidateResult.actions);
|
|
16272
16456
|
}
|
|
16273
|
-
|
|
16457
|
+
const remaining = targetToFree - tokensFreed;
|
|
16274
16458
|
if (remaining > 0 && context.conversation.length > 0) {
|
|
16275
16459
|
log.push(`Rolling window: need to free ~${remaining} more tokens`);
|
|
16276
16460
|
const result = await this.applyRollingWindow(context, remaining, log);
|
|
@@ -16284,8 +16468,11 @@ var AlgorithmicCompactionStrategy = class {
|
|
|
16284
16468
|
* Post-cycle consolidation.
|
|
16285
16469
|
*
|
|
16286
16470
|
* 1. Find all tool pairs in conversation
|
|
16287
|
-
* 2. Move large tool results (> threshold) to Working Memory
|
|
16471
|
+
* 2. Move large tool results (> threshold) to Working Memory (if available)
|
|
16288
16472
|
* 3. Limit remaining tool pairs to maxToolPairs
|
|
16473
|
+
*
|
|
16474
|
+
* Gracefully degrades: if working memory is not available, skips step 2
|
|
16475
|
+
* and only limits tool pairs + removes excess via rolling window.
|
|
16289
16476
|
*/
|
|
16290
16477
|
async consolidate(context) {
|
|
16291
16478
|
const log = [];
|
|
@@ -16296,23 +16483,25 @@ var AlgorithmicCompactionStrategy = class {
|
|
|
16296
16483
|
return { performed: false, tokensChanged: 0, actions: [] };
|
|
16297
16484
|
}
|
|
16298
16485
|
const indicesToRemove = [];
|
|
16299
|
-
|
|
16300
|
-
|
|
16301
|
-
|
|
16302
|
-
|
|
16303
|
-
|
|
16304
|
-
|
|
16305
|
-
|
|
16306
|
-
|
|
16307
|
-
|
|
16308
|
-
indicesToRemove.
|
|
16309
|
-
|
|
16310
|
-
|
|
16311
|
-
indicesToRemove.
|
|
16486
|
+
if (memory) {
|
|
16487
|
+
for (const pair of toolPairs) {
|
|
16488
|
+
if (pair.resultSizeBytes > this.toolResultSizeThreshold) {
|
|
16489
|
+
const key = this.generateKey(pair.toolName, pair.toolUseId);
|
|
16490
|
+
const desc = this.generateDescription(pair.toolName, pair.toolArgs);
|
|
16491
|
+
await memory.store(key, desc, pair.resultContent, {
|
|
16492
|
+
tier: "raw",
|
|
16493
|
+
priority: "normal"
|
|
16494
|
+
});
|
|
16495
|
+
if (!indicesToRemove.includes(pair.toolUseIndex)) {
|
|
16496
|
+
indicesToRemove.push(pair.toolUseIndex);
|
|
16497
|
+
}
|
|
16498
|
+
if (!indicesToRemove.includes(pair.toolResultIndex)) {
|
|
16499
|
+
indicesToRemove.push(pair.toolResultIndex);
|
|
16500
|
+
}
|
|
16501
|
+
log.push(
|
|
16502
|
+
`Moved ${pair.toolName} result (${this.formatBytes(pair.resultSizeBytes)}) to memory: ${key}`
|
|
16503
|
+
);
|
|
16312
16504
|
}
|
|
16313
|
-
log.push(
|
|
16314
|
-
`Moved ${pair.toolName} result (${this.formatBytes(pair.resultSizeBytes)}) to memory: ${key}`
|
|
16315
|
-
);
|
|
16316
16505
|
}
|
|
16317
16506
|
}
|
|
16318
16507
|
const remainingPairs = toolPairs.filter(
|
|
@@ -16341,15 +16530,12 @@ var AlgorithmicCompactionStrategy = class {
|
|
|
16341
16530
|
};
|
|
16342
16531
|
}
|
|
16343
16532
|
/**
|
|
16344
|
-
* Get the Working Memory plugin from context.
|
|
16345
|
-
*
|
|
16533
|
+
* Get the Working Memory plugin from context, or null if not available.
|
|
16534
|
+
* When null, the strategy degrades gracefully (skips memory operations).
|
|
16346
16535
|
*/
|
|
16347
16536
|
getWorkingMemory(context) {
|
|
16348
16537
|
const plugin = context.plugins.find((p) => p.name === "working_memory");
|
|
16349
|
-
|
|
16350
|
-
throw new Error("AlgorithmicCompactionStrategy requires working_memory plugin");
|
|
16351
|
-
}
|
|
16352
|
-
return plugin;
|
|
16538
|
+
return plugin ? plugin : null;
|
|
16353
16539
|
}
|
|
16354
16540
|
/**
|
|
16355
16541
|
* Find all tool_use/tool_result pairs in conversation.
|
|
@@ -16728,12 +16914,14 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
16728
16914
|
_agentId;
|
|
16729
16915
|
/** User ID for multi-user scenarios */
|
|
16730
16916
|
_userId;
|
|
16731
|
-
/**
|
|
16732
|
-
|
|
16917
|
+
/** Auth identities this agent is scoped to (connector + optional accountId) */
|
|
16918
|
+
_identities;
|
|
16733
16919
|
/** Storage backend */
|
|
16734
16920
|
_storage;
|
|
16735
16921
|
/** Destroyed flag */
|
|
16736
16922
|
_destroyed = false;
|
|
16923
|
+
/** Last thinking/reasoning content from the most recent assistant response */
|
|
16924
|
+
_lastThinking = null;
|
|
16737
16925
|
/** Cached budget from last prepare() call */
|
|
16738
16926
|
_cachedBudget = null;
|
|
16739
16927
|
/** Callback for beforeCompaction hook (set by Agent) */
|
|
@@ -16767,7 +16955,7 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
16767
16955
|
this._systemPrompt = config.systemPrompt;
|
|
16768
16956
|
this._agentId = this._config.agentId;
|
|
16769
16957
|
this._userId = config.userId;
|
|
16770
|
-
this.
|
|
16958
|
+
this._identities = config.identities;
|
|
16771
16959
|
const sessionFactory = exports.StorageRegistry.get("sessions");
|
|
16772
16960
|
const storageCtx = exports.StorageRegistry.getContext() ?? (config.userId ? { userId: config.userId } : void 0);
|
|
16773
16961
|
this._storage = config.storage ?? (sessionFactory ? sessionFactory(this._agentId, storageCtx) : void 0);
|
|
@@ -16821,15 +17009,16 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
16821
17009
|
}
|
|
16822
17010
|
/**
|
|
16823
17011
|
* Validate that a strategy's required plugins are registered.
|
|
16824
|
-
*
|
|
17012
|
+
* Logs a warning if required plugins are missing — the strategy should degrade gracefully.
|
|
16825
17013
|
*/
|
|
16826
17014
|
validateStrategyDependencies(strategy) {
|
|
16827
17015
|
if (!strategy.requiredPlugins?.length) return;
|
|
16828
17016
|
const availablePlugins = new Set(this._plugins.keys());
|
|
16829
17017
|
const missing = strategy.requiredPlugins.filter((name) => !availablePlugins.has(name));
|
|
16830
17018
|
if (missing.length > 0) {
|
|
16831
|
-
|
|
16832
|
-
|
|
17019
|
+
exports.logger.warn(
|
|
17020
|
+
{ strategy: strategy.name, missing, available: Array.from(availablePlugins) },
|
|
17021
|
+
`Strategy '${strategy.name}' recommends plugins that are not registered: ${missing.join(", ")}. Strategy will degrade gracefully.`
|
|
16833
17022
|
);
|
|
16834
17023
|
}
|
|
16835
17024
|
}
|
|
@@ -16838,7 +17027,7 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
16838
17027
|
* Merges with existing ToolContext to preserve other fields (memory, signal, taskId).
|
|
16839
17028
|
*
|
|
16840
17029
|
* Connector registry resolution order:
|
|
16841
|
-
* 1. If `
|
|
17030
|
+
* 1. If `identities` is set → filtered view showing only identity connectors
|
|
16842
17031
|
* 2. If access policy + userId → scoped view via Connector.scoped()
|
|
16843
17032
|
* 3. Otherwise → full global registry
|
|
16844
17033
|
*/
|
|
@@ -16848,6 +17037,7 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
16848
17037
|
...existing,
|
|
16849
17038
|
agentId: this._agentId,
|
|
16850
17039
|
userId: this._userId,
|
|
17040
|
+
identities: this._identities,
|
|
16851
17041
|
connectorRegistry: this.buildConnectorRegistry()
|
|
16852
17042
|
});
|
|
16853
17043
|
}
|
|
@@ -16855,13 +17045,13 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
16855
17045
|
* Build the connector registry appropriate for this agent's config.
|
|
16856
17046
|
*/
|
|
16857
17047
|
buildConnectorRegistry() {
|
|
16858
|
-
if (this.
|
|
16859
|
-
const allowedSet = new Set(this.
|
|
17048
|
+
if (this._identities?.length) {
|
|
17049
|
+
const allowedSet = new Set(this._identities.map((id) => id.connector));
|
|
16860
17050
|
const base = this._userId && exports.Connector.getAccessPolicy() ? exports.Connector.scoped({ userId: this._userId }) : exports.Connector.asRegistry();
|
|
16861
17051
|
return {
|
|
16862
17052
|
get: (name) => {
|
|
16863
17053
|
if (!allowedSet.has(name)) {
|
|
16864
|
-
const available =
|
|
17054
|
+
const available = [...allowedSet].filter((n) => base.has(n)).join(", ") || "none";
|
|
16865
17055
|
throw new Error(`Connector '${name}' not found. Available: ${available}`);
|
|
16866
17056
|
}
|
|
16867
17057
|
return base.get(name);
|
|
@@ -16913,13 +17103,13 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
16913
17103
|
this._userId = value;
|
|
16914
17104
|
this.syncToolContext();
|
|
16915
17105
|
}
|
|
16916
|
-
/** Get the
|
|
16917
|
-
get
|
|
16918
|
-
return this.
|
|
17106
|
+
/** Get the auth identities this agent is scoped to (undefined = all visible connectors) */
|
|
17107
|
+
get identities() {
|
|
17108
|
+
return this._identities;
|
|
16919
17109
|
}
|
|
16920
|
-
/** Set
|
|
16921
|
-
set
|
|
16922
|
-
this.
|
|
17110
|
+
/** Set auth identities. Updates ToolContext.connectorRegistry and identity-aware descriptions. */
|
|
17111
|
+
set identities(value) {
|
|
17112
|
+
this._identities = value;
|
|
16923
17113
|
this.syncToolContext();
|
|
16924
17114
|
}
|
|
16925
17115
|
/** Get/set system prompt */
|
|
@@ -16945,6 +17135,13 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
16945
17135
|
get storage() {
|
|
16946
17136
|
return this._storage ?? null;
|
|
16947
17137
|
}
|
|
17138
|
+
/**
|
|
17139
|
+
* Get the last thinking/reasoning content from the most recent assistant response.
|
|
17140
|
+
* Updated on every assistant response, always available regardless of persistence setting.
|
|
17141
|
+
*/
|
|
17142
|
+
get lastThinking() {
|
|
17143
|
+
return this._lastThinking;
|
|
17144
|
+
}
|
|
16948
17145
|
/** Get max context tokens */
|
|
16949
17146
|
get maxContextTokens() {
|
|
16950
17147
|
return this._maxContextTokens;
|
|
@@ -17126,6 +17323,7 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
17126
17323
|
}
|
|
17127
17324
|
const id = this.generateId();
|
|
17128
17325
|
const contentArray = [];
|
|
17326
|
+
let thinkingText = null;
|
|
17129
17327
|
for (const item of output) {
|
|
17130
17328
|
if (item.type === "message" && "content" in item) {
|
|
17131
17329
|
const msg = item;
|
|
@@ -17137,12 +17335,19 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
17137
17335
|
});
|
|
17138
17336
|
} else if (c.type === "tool_use" /* TOOL_USE */) {
|
|
17139
17337
|
contentArray.push(c);
|
|
17338
|
+
} else if (c.type === "thinking" /* THINKING */) {
|
|
17339
|
+
const thinking = c;
|
|
17340
|
+
thinkingText = thinking.thinking;
|
|
17341
|
+
if (thinking.persistInHistory) {
|
|
17342
|
+
contentArray.push(c);
|
|
17343
|
+
}
|
|
17140
17344
|
}
|
|
17141
17345
|
}
|
|
17142
17346
|
} else if (item.type === "compaction" || item.type === "reasoning") {
|
|
17143
17347
|
continue;
|
|
17144
17348
|
}
|
|
17145
17349
|
}
|
|
17350
|
+
this._lastThinking = thinkingText;
|
|
17146
17351
|
if (contentArray.length > 0) {
|
|
17147
17352
|
const message = {
|
|
17148
17353
|
type: "message",
|
|
@@ -17241,6 +17446,7 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
17241
17446
|
*/
|
|
17242
17447
|
async prepare() {
|
|
17243
17448
|
this.assertNotDestroyed();
|
|
17449
|
+
this._lastThinking = null;
|
|
17244
17450
|
const compactionLog = [];
|
|
17245
17451
|
const toolsTokens = this.calculateToolsTokens();
|
|
17246
17452
|
const availableForContent = this._maxContextTokens - this._config.responseReserve - toolsTokens;
|
|
@@ -17453,6 +17659,8 @@ ${content}`);
|
|
|
17453
17659
|
total += this._estimateImageTokens();
|
|
17454
17660
|
}
|
|
17455
17661
|
}
|
|
17662
|
+
} else if (c.type === "thinking" /* THINKING */) {
|
|
17663
|
+
total += this._estimator.estimateTokens(c.thinking || "");
|
|
17456
17664
|
} else if (c.type === "input_image_url" /* INPUT_IMAGE_URL */) {
|
|
17457
17665
|
const imgContent = c;
|
|
17458
17666
|
const detail = imgContent.image_url?.detail;
|
|
@@ -17950,6 +18158,188 @@ ${content}`);
|
|
|
17950
18158
|
get strategy() {
|
|
17951
18159
|
return this._compactionStrategy.name;
|
|
17952
18160
|
}
|
|
18161
|
+
/**
|
|
18162
|
+
* Get a complete, serializable snapshot of the context state.
|
|
18163
|
+
*
|
|
18164
|
+
* Returns all data needed by UI "Look Inside" panels without reaching
|
|
18165
|
+
* into plugin internals. Plugin data is auto-discovered from the plugin
|
|
18166
|
+
* registry — new/custom plugins appear automatically.
|
|
18167
|
+
*
|
|
18168
|
+
* @param toolStats - Optional tool usage stats (from ToolManager.getStats())
|
|
18169
|
+
* @returns Serializable context snapshot
|
|
18170
|
+
*/
|
|
18171
|
+
async getSnapshot(toolStats) {
|
|
18172
|
+
const resolveContents = async (raw) => {
|
|
18173
|
+
const resolved = raw instanceof Promise ? await raw : raw;
|
|
18174
|
+
if (resolved instanceof Map) return Array.from(resolved.values());
|
|
18175
|
+
return resolved;
|
|
18176
|
+
};
|
|
18177
|
+
if (this._destroyed) {
|
|
18178
|
+
const emptyBudget = this._cachedBudget ?? {
|
|
18179
|
+
maxTokens: this._maxContextTokens,
|
|
18180
|
+
responseReserve: this._config.responseReserve,
|
|
18181
|
+
systemMessageTokens: 0,
|
|
18182
|
+
toolsTokens: 0,
|
|
18183
|
+
conversationTokens: 0,
|
|
18184
|
+
currentInputTokens: 0,
|
|
18185
|
+
totalUsed: 0,
|
|
18186
|
+
available: this._maxContextTokens - this._config.responseReserve,
|
|
18187
|
+
utilizationPercent: 0,
|
|
18188
|
+
breakdown: {
|
|
18189
|
+
systemPrompt: 0,
|
|
18190
|
+
persistentInstructions: 0,
|
|
18191
|
+
pluginInstructions: 0,
|
|
18192
|
+
pluginContents: {},
|
|
18193
|
+
tools: 0,
|
|
18194
|
+
conversation: 0,
|
|
18195
|
+
currentInput: 0
|
|
18196
|
+
}
|
|
18197
|
+
};
|
|
18198
|
+
return {
|
|
18199
|
+
available: false,
|
|
18200
|
+
agentId: this._agentId,
|
|
18201
|
+
model: this._config.model,
|
|
18202
|
+
features: this._config.features,
|
|
18203
|
+
budget: emptyBudget,
|
|
18204
|
+
strategy: this._compactionStrategy.name,
|
|
18205
|
+
messagesCount: 0,
|
|
18206
|
+
toolCallsCount: 0,
|
|
18207
|
+
systemPrompt: null,
|
|
18208
|
+
plugins: [],
|
|
18209
|
+
tools: []
|
|
18210
|
+
};
|
|
18211
|
+
}
|
|
18212
|
+
const budget = await this.calculateBudget();
|
|
18213
|
+
const plugins = [];
|
|
18214
|
+
for (const plugin of this._plugins.values()) {
|
|
18215
|
+
let formattedContent = null;
|
|
18216
|
+
try {
|
|
18217
|
+
formattedContent = await plugin.getContent();
|
|
18218
|
+
} catch {
|
|
18219
|
+
}
|
|
18220
|
+
plugins.push({
|
|
18221
|
+
name: plugin.name,
|
|
18222
|
+
displayName: formatPluginDisplayName(plugin.name),
|
|
18223
|
+
enabled: true,
|
|
18224
|
+
tokenSize: plugin.getTokenSize(),
|
|
18225
|
+
instructionsTokenSize: plugin.getInstructionsTokenSize(),
|
|
18226
|
+
compactable: plugin.isCompactable(),
|
|
18227
|
+
contents: await resolveContents(plugin.getContents()),
|
|
18228
|
+
formattedContent
|
|
18229
|
+
});
|
|
18230
|
+
}
|
|
18231
|
+
const usageCounts = /* @__PURE__ */ new Map();
|
|
18232
|
+
if (toolStats?.mostUsed) {
|
|
18233
|
+
for (const { name, count } of toolStats.mostUsed) {
|
|
18234
|
+
usageCounts.set(name, count);
|
|
18235
|
+
}
|
|
18236
|
+
}
|
|
18237
|
+
const tools = [];
|
|
18238
|
+
for (const toolName of this._tools.list()) {
|
|
18239
|
+
const reg = this._tools.getRegistration(toolName);
|
|
18240
|
+
if (!reg) continue;
|
|
18241
|
+
tools.push({
|
|
18242
|
+
name: toolName,
|
|
18243
|
+
description: reg.tool.definition.function.description || "",
|
|
18244
|
+
enabled: reg.enabled,
|
|
18245
|
+
callCount: reg.metadata.usageCount ?? usageCounts.get(toolName) ?? 0,
|
|
18246
|
+
namespace: reg.namespace || void 0
|
|
18247
|
+
});
|
|
18248
|
+
}
|
|
18249
|
+
let toolCallsCount = 0;
|
|
18250
|
+
for (const item of this._conversation) {
|
|
18251
|
+
if (item.type === "message" && item.role === "assistant" /* ASSISTANT */) {
|
|
18252
|
+
for (const c of item.content) {
|
|
18253
|
+
if (c.type === "tool_use" /* TOOL_USE */) toolCallsCount++;
|
|
18254
|
+
}
|
|
18255
|
+
}
|
|
18256
|
+
}
|
|
18257
|
+
return {
|
|
18258
|
+
available: true,
|
|
18259
|
+
agentId: this._agentId,
|
|
18260
|
+
model: this._config.model,
|
|
18261
|
+
features: this._config.features,
|
|
18262
|
+
budget,
|
|
18263
|
+
strategy: this._compactionStrategy.name,
|
|
18264
|
+
messagesCount: this._conversation.length,
|
|
18265
|
+
toolCallsCount,
|
|
18266
|
+
systemPrompt: this._systemPrompt ?? null,
|
|
18267
|
+
plugins,
|
|
18268
|
+
tools
|
|
18269
|
+
};
|
|
18270
|
+
}
|
|
18271
|
+
/**
|
|
18272
|
+
* Get a human-readable breakdown of the prepared context.
|
|
18273
|
+
*
|
|
18274
|
+
* Calls `prepare()` internally, then maps each InputItem to a named
|
|
18275
|
+
* component with content text and token estimate. Used by "View Full Context" UIs.
|
|
18276
|
+
*
|
|
18277
|
+
* @returns View context data with components and raw text for "Copy All"
|
|
18278
|
+
*/
|
|
18279
|
+
async getViewContext() {
|
|
18280
|
+
if (this._destroyed) {
|
|
18281
|
+
return { available: false, components: [], totalTokens: 0, rawContext: "" };
|
|
18282
|
+
}
|
|
18283
|
+
const { input, budget } = await this.prepare();
|
|
18284
|
+
const components = [];
|
|
18285
|
+
let rawParts = [];
|
|
18286
|
+
for (const item of input) {
|
|
18287
|
+
if (item.type === "compaction") {
|
|
18288
|
+
components.push({
|
|
18289
|
+
name: "Compaction Block",
|
|
18290
|
+
content: "[Compacted content]",
|
|
18291
|
+
tokenEstimate: 0
|
|
18292
|
+
});
|
|
18293
|
+
continue;
|
|
18294
|
+
}
|
|
18295
|
+
const msg = item;
|
|
18296
|
+
const roleName = msg.role === "developer" /* DEVELOPER */ ? "System Message" : msg.role === "user" /* USER */ ? "User Message" : "Assistant Message";
|
|
18297
|
+
for (const block of msg.content) {
|
|
18298
|
+
let name = roleName;
|
|
18299
|
+
let text = "";
|
|
18300
|
+
switch (block.type) {
|
|
18301
|
+
case "input_text" /* INPUT_TEXT */:
|
|
18302
|
+
text = block.text;
|
|
18303
|
+
break;
|
|
18304
|
+
case "output_text" /* OUTPUT_TEXT */:
|
|
18305
|
+
text = block.text;
|
|
18306
|
+
break;
|
|
18307
|
+
case "tool_use" /* TOOL_USE */:
|
|
18308
|
+
name = `Tool Call: ${block.name}`;
|
|
18309
|
+
text = `${block.name}(${block.arguments})`;
|
|
18310
|
+
break;
|
|
18311
|
+
case "tool_result" /* TOOL_RESULT */:
|
|
18312
|
+
name = `Tool Result: ${block.tool_use_id}`;
|
|
18313
|
+
text = typeof block.content === "string" ? block.content : JSON.stringify(block.content, null, 2);
|
|
18314
|
+
if (block.error) text = `[Error] ${block.error}
|
|
18315
|
+
${text}`;
|
|
18316
|
+
break;
|
|
18317
|
+
case "input_image_url" /* INPUT_IMAGE_URL */:
|
|
18318
|
+
name = "Image Input";
|
|
18319
|
+
text = `[Image: ${block.image_url.url.substring(0, 100)}...]`;
|
|
18320
|
+
break;
|
|
18321
|
+
case "input_file" /* INPUT_FILE */:
|
|
18322
|
+
name = "File Input";
|
|
18323
|
+
text = `[File: ${block.file_id}]`;
|
|
18324
|
+
break;
|
|
18325
|
+
case "thinking" /* THINKING */:
|
|
18326
|
+
name = "Thinking";
|
|
18327
|
+
text = block.thinking || "";
|
|
18328
|
+
break;
|
|
18329
|
+
}
|
|
18330
|
+
const tokenEstimate = this._estimator.estimateTokens(text);
|
|
18331
|
+
components.push({ name, content: text, tokenEstimate });
|
|
18332
|
+
rawParts.push(`--- ${name} ---
|
|
18333
|
+
${text}`);
|
|
18334
|
+
}
|
|
18335
|
+
}
|
|
18336
|
+
return {
|
|
18337
|
+
available: true,
|
|
18338
|
+
components,
|
|
18339
|
+
totalTokens: budget.totalUsed,
|
|
18340
|
+
rawContext: rawParts.join("\n\n")
|
|
18341
|
+
};
|
|
18342
|
+
}
|
|
17953
18343
|
// ============================================================================
|
|
17954
18344
|
// Utilities
|
|
17955
18345
|
// ============================================================================
|
|
@@ -18208,6 +18598,13 @@ var BaseTextProvider = class extends BaseProvider {
|
|
|
18208
18598
|
}
|
|
18209
18599
|
return textParts.join("\n");
|
|
18210
18600
|
}
|
|
18601
|
+
/**
|
|
18602
|
+
* List available models from the provider's API.
|
|
18603
|
+
* Default returns empty array; providers override when they have SDK support.
|
|
18604
|
+
*/
|
|
18605
|
+
async listModels() {
|
|
18606
|
+
return [];
|
|
18607
|
+
}
|
|
18211
18608
|
/**
|
|
18212
18609
|
* Clean up provider resources (circuit breaker listeners, etc.)
|
|
18213
18610
|
* Should be called when the provider is no longer needed.
|
|
@@ -18360,12 +18757,21 @@ var OpenAIResponsesConverter = class {
|
|
|
18360
18757
|
} else if (item.type === "reasoning") {
|
|
18361
18758
|
const reasoning = item;
|
|
18362
18759
|
if (reasoning.summary) {
|
|
18363
|
-
|
|
18364
|
-
|
|
18365
|
-
|
|
18366
|
-
|
|
18367
|
-
|
|
18368
|
-
}
|
|
18760
|
+
let summaryText;
|
|
18761
|
+
if (typeof reasoning.summary === "string") {
|
|
18762
|
+
summaryText = reasoning.summary;
|
|
18763
|
+
} else if (Array.isArray(reasoning.summary)) {
|
|
18764
|
+
summaryText = reasoning.summary.map((s) => s.text || "").filter(Boolean).join("\n");
|
|
18765
|
+
} else {
|
|
18766
|
+
summaryText = "";
|
|
18767
|
+
}
|
|
18768
|
+
if (summaryText) {
|
|
18769
|
+
content.push({
|
|
18770
|
+
type: "thinking" /* THINKING */,
|
|
18771
|
+
thinking: summaryText,
|
|
18772
|
+
persistInHistory: false
|
|
18773
|
+
});
|
|
18774
|
+
}
|
|
18369
18775
|
}
|
|
18370
18776
|
}
|
|
18371
18777
|
}
|
|
@@ -18388,10 +18794,20 @@ var OpenAIResponsesConverter = class {
|
|
|
18388
18794
|
}
|
|
18389
18795
|
],
|
|
18390
18796
|
output_text: outputText,
|
|
18797
|
+
// Extract thinking text from content for convenience field
|
|
18798
|
+
...(() => {
|
|
18799
|
+
const thinkingTexts = content.filter((c) => c.type === "thinking" /* THINKING */).map((c) => c.thinking).filter(Boolean);
|
|
18800
|
+
return thinkingTexts.length > 0 ? { thinking: thinkingTexts.join("\n") } : {};
|
|
18801
|
+
})(),
|
|
18391
18802
|
usage: {
|
|
18392
18803
|
input_tokens: response.usage?.input_tokens || 0,
|
|
18393
18804
|
output_tokens: response.usage?.output_tokens || 0,
|
|
18394
|
-
total_tokens: response.usage?.total_tokens || 0
|
|
18805
|
+
total_tokens: response.usage?.total_tokens || 0,
|
|
18806
|
+
...response.usage?.output_tokens_details?.reasoning_tokens != null && {
|
|
18807
|
+
output_tokens_details: {
|
|
18808
|
+
reasoning_tokens: response.usage.output_tokens_details.reasoning_tokens
|
|
18809
|
+
}
|
|
18810
|
+
}
|
|
18395
18811
|
}
|
|
18396
18812
|
};
|
|
18397
18813
|
}
|
|
@@ -18496,6 +18912,8 @@ var StreamEventType = /* @__PURE__ */ ((StreamEventType2) => {
|
|
|
18496
18912
|
StreamEventType2["TOOL_EXECUTION_START"] = "response.tool_execution.start";
|
|
18497
18913
|
StreamEventType2["TOOL_EXECUTION_DONE"] = "response.tool_execution.done";
|
|
18498
18914
|
StreamEventType2["ITERATION_COMPLETE"] = "response.iteration.complete";
|
|
18915
|
+
StreamEventType2["REASONING_DELTA"] = "response.reasoning.delta";
|
|
18916
|
+
StreamEventType2["REASONING_DONE"] = "response.reasoning.done";
|
|
18499
18917
|
StreamEventType2["RESPONSE_COMPLETE"] = "response.complete";
|
|
18500
18918
|
StreamEventType2["ERROR"] = "response.error";
|
|
18501
18919
|
return StreamEventType2;
|
|
@@ -18515,6 +18933,12 @@ function isToolCallArgumentsDelta(event) {
|
|
|
18515
18933
|
function isToolCallArgumentsDone(event) {
|
|
18516
18934
|
return event.type === "response.tool_call_arguments.done" /* TOOL_CALL_ARGUMENTS_DONE */;
|
|
18517
18935
|
}
|
|
18936
|
+
function isReasoningDelta(event) {
|
|
18937
|
+
return event.type === "response.reasoning.delta" /* REASONING_DELTA */;
|
|
18938
|
+
}
|
|
18939
|
+
function isReasoningDone(event) {
|
|
18940
|
+
return event.type === "response.reasoning.done" /* REASONING_DONE */;
|
|
18941
|
+
}
|
|
18518
18942
|
function isResponseComplete(event) {
|
|
18519
18943
|
return event.type === "response.complete" /* RESPONSE_COMPLETE */;
|
|
18520
18944
|
}
|
|
@@ -18532,6 +18956,8 @@ var OpenAIResponsesStreamConverter = class {
|
|
|
18532
18956
|
let sequenceNumber = 0;
|
|
18533
18957
|
const activeItems = /* @__PURE__ */ new Map();
|
|
18534
18958
|
const toolCallBuffers = /* @__PURE__ */ new Map();
|
|
18959
|
+
const reasoningBuffers = /* @__PURE__ */ new Map();
|
|
18960
|
+
const reasoningDoneEmitted = /* @__PURE__ */ new Set();
|
|
18535
18961
|
for await (const event of stream) {
|
|
18536
18962
|
if (process.env.DEBUG_OPENAI) {
|
|
18537
18963
|
console.error("[DEBUG] Responses API event:", event.type);
|
|
@@ -18553,6 +18979,12 @@ var OpenAIResponsesStreamConverter = class {
|
|
|
18553
18979
|
activeItems.set(addedEvent.output_index.toString(), {
|
|
18554
18980
|
type: item.type
|
|
18555
18981
|
});
|
|
18982
|
+
if (item.type === "reasoning") {
|
|
18983
|
+
activeItems.set(addedEvent.output_index.toString(), {
|
|
18984
|
+
type: "reasoning"
|
|
18985
|
+
});
|
|
18986
|
+
reasoningBuffers.set(addedEvent.output_index.toString(), []);
|
|
18987
|
+
}
|
|
18556
18988
|
if (item.type === "function_call") {
|
|
18557
18989
|
const functionCall = item;
|
|
18558
18990
|
const toolCallId = functionCall.call_id;
|
|
@@ -18610,9 +19042,53 @@ var OpenAIResponsesStreamConverter = class {
|
|
|
18610
19042
|
}
|
|
18611
19043
|
break;
|
|
18612
19044
|
}
|
|
19045
|
+
case "response.reasoning_summary_text.delta":
|
|
19046
|
+
case "response.reasoning_text.delta": {
|
|
19047
|
+
const reasoningEvent = event;
|
|
19048
|
+
const outputIdx = reasoningEvent.output_index?.toString();
|
|
19049
|
+
const buffer = outputIdx ? reasoningBuffers.get(outputIdx) : void 0;
|
|
19050
|
+
if (buffer) {
|
|
19051
|
+
buffer.push(reasoningEvent.delta || "");
|
|
19052
|
+
}
|
|
19053
|
+
yield {
|
|
19054
|
+
type: "response.reasoning.delta" /* REASONING_DELTA */,
|
|
19055
|
+
response_id: responseId,
|
|
19056
|
+
item_id: reasoningEvent.item_id || `reasoning_${responseId}`,
|
|
19057
|
+
delta: reasoningEvent.delta || "",
|
|
19058
|
+
sequence_number: sequenceNumber++
|
|
19059
|
+
};
|
|
19060
|
+
break;
|
|
19061
|
+
}
|
|
19062
|
+
case "response.reasoning_text.done": {
|
|
19063
|
+
const doneEvent = event;
|
|
19064
|
+
const outputIdx = doneEvent.output_index.toString();
|
|
19065
|
+
const rBuf = reasoningBuffers.get(outputIdx);
|
|
19066
|
+
const thinkingText = rBuf ? rBuf.join("") : doneEvent.text || "";
|
|
19067
|
+
reasoningDoneEmitted.add(outputIdx);
|
|
19068
|
+
yield {
|
|
19069
|
+
type: "response.reasoning.done" /* REASONING_DONE */,
|
|
19070
|
+
response_id: responseId,
|
|
19071
|
+
item_id: doneEvent.item_id || `reasoning_${responseId}`,
|
|
19072
|
+
thinking: thinkingText
|
|
19073
|
+
};
|
|
19074
|
+
break;
|
|
19075
|
+
}
|
|
18613
19076
|
case "response.output_item.done": {
|
|
18614
19077
|
const doneEvent = event;
|
|
18615
19078
|
const item = doneEvent.item;
|
|
19079
|
+
if (item.type === "reasoning") {
|
|
19080
|
+
const outputIdx = doneEvent.output_index.toString();
|
|
19081
|
+
if (!reasoningDoneEmitted.has(outputIdx)) {
|
|
19082
|
+
const rBuf = reasoningBuffers.get(outputIdx);
|
|
19083
|
+
const thinkingText = rBuf ? rBuf.join("") : "";
|
|
19084
|
+
yield {
|
|
19085
|
+
type: "response.reasoning.done" /* REASONING_DONE */,
|
|
19086
|
+
response_id: responseId,
|
|
19087
|
+
item_id: item.id || `reasoning_${responseId}`,
|
|
19088
|
+
thinking: thinkingText
|
|
19089
|
+
};
|
|
19090
|
+
}
|
|
19091
|
+
}
|
|
18616
19092
|
if (item.type === "function_call") {
|
|
18617
19093
|
const functionCall = item;
|
|
18618
19094
|
const buffer = toolCallBuffers.get(functionCall.call_id);
|
|
@@ -18644,7 +19120,12 @@ var OpenAIResponsesStreamConverter = class {
|
|
|
18644
19120
|
usage: {
|
|
18645
19121
|
input_tokens: response.usage?.input_tokens || 0,
|
|
18646
19122
|
output_tokens: response.usage?.output_tokens || 0,
|
|
18647
|
-
total_tokens: response.usage?.total_tokens || 0
|
|
19123
|
+
total_tokens: response.usage?.total_tokens || 0,
|
|
19124
|
+
...response.usage?.output_tokens_details?.reasoning_tokens != null && {
|
|
19125
|
+
output_tokens_details: {
|
|
19126
|
+
reasoning_tokens: response.usage.output_tokens_details.reasoning_tokens
|
|
19127
|
+
}
|
|
19128
|
+
}
|
|
18648
19129
|
},
|
|
18649
19130
|
iterations: 1
|
|
18650
19131
|
};
|
|
@@ -18685,6 +19166,26 @@ function resolveMaxContextTokens(model, fallback) {
|
|
|
18685
19166
|
return info ? info.features.input.tokens : fallback;
|
|
18686
19167
|
}
|
|
18687
19168
|
|
|
19169
|
+
// src/infrastructure/providers/shared/validateThinkingConfig.ts
|
|
19170
|
+
function validateThinkingConfig(thinking) {
|
|
19171
|
+
if (!thinking.enabled) return;
|
|
19172
|
+
if (thinking.budgetTokens !== void 0) {
|
|
19173
|
+
if (typeof thinking.budgetTokens !== "number" || thinking.budgetTokens < 1) {
|
|
19174
|
+
throw new Error(
|
|
19175
|
+
`Invalid thinking budgetTokens: ${thinking.budgetTokens}. Must be a positive number.`
|
|
19176
|
+
);
|
|
19177
|
+
}
|
|
19178
|
+
}
|
|
19179
|
+
if (thinking.effort !== void 0) {
|
|
19180
|
+
const validEfforts = ["low", "medium", "high"];
|
|
19181
|
+
if (!validEfforts.includes(thinking.effort)) {
|
|
19182
|
+
throw new Error(
|
|
19183
|
+
`Invalid thinking effort: '${thinking.effort}'. Must be one of: ${validEfforts.join(", ")}`
|
|
19184
|
+
);
|
|
19185
|
+
}
|
|
19186
|
+
}
|
|
19187
|
+
}
|
|
19188
|
+
|
|
18688
19189
|
// src/infrastructure/providers/openai/OpenAITextProvider.ts
|
|
18689
19190
|
var OpenAITextProvider = class extends BaseTextProvider {
|
|
18690
19191
|
name = "openai";
|
|
@@ -18752,6 +19253,7 @@ var OpenAITextProvider = class extends BaseTextProvider {
|
|
|
18752
19253
|
},
|
|
18753
19254
|
...options.metadata && { metadata: options.metadata }
|
|
18754
19255
|
};
|
|
19256
|
+
this.applyReasoningConfig(params, options);
|
|
18755
19257
|
const response = await this.client.responses.create(params);
|
|
18756
19258
|
return this.converter.convertResponse(response);
|
|
18757
19259
|
} catch (error) {
|
|
@@ -18793,6 +19295,7 @@ var OpenAITextProvider = class extends BaseTextProvider {
|
|
|
18793
19295
|
...options.metadata && { metadata: options.metadata },
|
|
18794
19296
|
stream: true
|
|
18795
19297
|
};
|
|
19298
|
+
this.applyReasoningConfig(params, options);
|
|
18796
19299
|
const stream = await this.client.responses.create(params);
|
|
18797
19300
|
yield* this.streamConverter.convertStream(stream);
|
|
18798
19301
|
} catch (error) {
|
|
@@ -18814,6 +19317,27 @@ var OpenAITextProvider = class extends BaseTextProvider {
|
|
|
18814
19317
|
maxOutputTokens: 16384
|
|
18815
19318
|
});
|
|
18816
19319
|
}
|
|
19320
|
+
/**
|
|
19321
|
+
* List available models from the OpenAI API
|
|
19322
|
+
*/
|
|
19323
|
+
async listModels() {
|
|
19324
|
+
const models = [];
|
|
19325
|
+
for await (const model of this.client.models.list()) {
|
|
19326
|
+
models.push(model.id);
|
|
19327
|
+
}
|
|
19328
|
+
return models.sort();
|
|
19329
|
+
}
|
|
19330
|
+
/**
|
|
19331
|
+
* Apply reasoning config from unified thinking option to request params
|
|
19332
|
+
*/
|
|
19333
|
+
applyReasoningConfig(params, options) {
|
|
19334
|
+
if (options.thinking?.enabled) {
|
|
19335
|
+
validateThinkingConfig(options.thinking);
|
|
19336
|
+
params.reasoning = {
|
|
19337
|
+
effort: options.thinking.effort || "medium"
|
|
19338
|
+
};
|
|
19339
|
+
}
|
|
19340
|
+
}
|
|
18817
19341
|
/**
|
|
18818
19342
|
* Handle OpenAI-specific errors
|
|
18819
19343
|
*/
|
|
@@ -18856,6 +19380,7 @@ function buildLLMResponse(options) {
|
|
|
18856
19380
|
}
|
|
18857
19381
|
];
|
|
18858
19382
|
const outputText = extractTextFromContent(content);
|
|
19383
|
+
const thinking = extractThinkingFromContent(content);
|
|
18859
19384
|
return {
|
|
18860
19385
|
id: responseId,
|
|
18861
19386
|
object: "response",
|
|
@@ -18864,6 +19389,7 @@ function buildLLMResponse(options) {
|
|
|
18864
19389
|
model,
|
|
18865
19390
|
output,
|
|
18866
19391
|
output_text: outputText,
|
|
19392
|
+
...thinking && { thinking },
|
|
18867
19393
|
usage: {
|
|
18868
19394
|
input_tokens: usage.inputTokens,
|
|
18869
19395
|
output_tokens: usage.outputTokens,
|
|
@@ -18876,6 +19402,10 @@ function extractTextFromContent(content) {
|
|
|
18876
19402
|
(c) => c.type === "output_text" /* OUTPUT_TEXT */
|
|
18877
19403
|
).map((c) => c.text).join("\n");
|
|
18878
19404
|
}
|
|
19405
|
+
function extractThinkingFromContent(content) {
|
|
19406
|
+
const thinkingTexts = content.filter((c) => c.type === "thinking" /* THINKING */).map((c) => c.thinking).filter(Boolean);
|
|
19407
|
+
return thinkingTexts.length > 0 ? thinkingTexts.join("\n") : void 0;
|
|
19408
|
+
}
|
|
18879
19409
|
function createTextContent(text) {
|
|
18880
19410
|
return {
|
|
18881
19411
|
type: "output_text" /* OUTPUT_TEXT */,
|
|
@@ -19125,7 +19655,15 @@ var AnthropicConverter = class extends BaseConverter {
|
|
|
19125
19655
|
if (tools && tools.length > 0) {
|
|
19126
19656
|
params.tools = tools;
|
|
19127
19657
|
}
|
|
19128
|
-
if (options.
|
|
19658
|
+
if (options.thinking?.enabled) {
|
|
19659
|
+
validateThinkingConfig(options.thinking);
|
|
19660
|
+
const budgetTokens = options.thinking.budgetTokens || 1e4;
|
|
19661
|
+
params.thinking = {
|
|
19662
|
+
type: "enabled",
|
|
19663
|
+
budget_tokens: budgetTokens
|
|
19664
|
+
};
|
|
19665
|
+
params.temperature = 1;
|
|
19666
|
+
} else if (options.temperature !== void 0) {
|
|
19129
19667
|
params.temperature = options.temperature;
|
|
19130
19668
|
}
|
|
19131
19669
|
return params;
|
|
@@ -19171,6 +19709,14 @@ var AnthropicConverter = class extends BaseConverter {
|
|
|
19171
19709
|
content.push(this.createText(block.text));
|
|
19172
19710
|
} else if (block.type === "tool_use") {
|
|
19173
19711
|
content.push(this.createToolUse(block.id, block.name, block.input));
|
|
19712
|
+
} else if (block.type === "thinking") {
|
|
19713
|
+
const thinkingBlock = block;
|
|
19714
|
+
content.push({
|
|
19715
|
+
type: "thinking" /* THINKING */,
|
|
19716
|
+
thinking: thinkingBlock.thinking || "",
|
|
19717
|
+
signature: thinkingBlock.signature,
|
|
19718
|
+
persistInHistory: true
|
|
19719
|
+
});
|
|
19174
19720
|
}
|
|
19175
19721
|
}
|
|
19176
19722
|
return content;
|
|
@@ -19249,6 +19795,17 @@ var AnthropicConverter = class extends BaseConverter {
|
|
|
19249
19795
|
});
|
|
19250
19796
|
break;
|
|
19251
19797
|
}
|
|
19798
|
+
case "thinking" /* THINKING */: {
|
|
19799
|
+
const thinkingContent = c;
|
|
19800
|
+
if (thinkingContent.signature) {
|
|
19801
|
+
blocks.push({
|
|
19802
|
+
type: "thinking",
|
|
19803
|
+
thinking: thinkingContent.thinking,
|
|
19804
|
+
signature: thinkingContent.signature
|
|
19805
|
+
});
|
|
19806
|
+
}
|
|
19807
|
+
break;
|
|
19808
|
+
}
|
|
19252
19809
|
}
|
|
19253
19810
|
}
|
|
19254
19811
|
if (blocks.length === 1 && blocks[0]?.type === "text") {
|
|
@@ -19381,6 +19938,8 @@ var BaseStreamConverter = class {
|
|
|
19381
19938
|
usage = { inputTokens: 0, outputTokens: 0 };
|
|
19382
19939
|
/** Buffers for accumulating tool call arguments */
|
|
19383
19940
|
toolCallBuffers = /* @__PURE__ */ new Map();
|
|
19941
|
+
/** Buffer for accumulating reasoning/thinking content */
|
|
19942
|
+
reasoningBuffer = "";
|
|
19384
19943
|
// ==========================================================================
|
|
19385
19944
|
// Public API
|
|
19386
19945
|
// ==========================================================================
|
|
@@ -19415,6 +19974,7 @@ var BaseStreamConverter = class {
|
|
|
19415
19974
|
this.sequenceNumber = 0;
|
|
19416
19975
|
this.usage = { inputTokens: 0, outputTokens: 0 };
|
|
19417
19976
|
this.toolCallBuffers.clear();
|
|
19977
|
+
this.reasoningBuffer = "";
|
|
19418
19978
|
}
|
|
19419
19979
|
/**
|
|
19420
19980
|
* Reset converter state for a new stream
|
|
@@ -19469,6 +20029,33 @@ var BaseStreamConverter = class {
|
|
|
19469
20029
|
sequence_number: this.nextSequence()
|
|
19470
20030
|
};
|
|
19471
20031
|
}
|
|
20032
|
+
/**
|
|
20033
|
+
* Create REASONING_DELTA event and accumulate reasoning buffer
|
|
20034
|
+
*/
|
|
20035
|
+
emitReasoningDelta(delta, itemId) {
|
|
20036
|
+
this.reasoningBuffer += delta;
|
|
20037
|
+
return {
|
|
20038
|
+
type: "response.reasoning.delta" /* REASONING_DELTA */,
|
|
20039
|
+
response_id: this.responseId,
|
|
20040
|
+
item_id: itemId || `reasoning_${this.responseId}`,
|
|
20041
|
+
delta,
|
|
20042
|
+
sequence_number: this.nextSequence()
|
|
20043
|
+
};
|
|
20044
|
+
}
|
|
20045
|
+
/**
|
|
20046
|
+
* Create REASONING_DONE event with accumulated reasoning
|
|
20047
|
+
*/
|
|
20048
|
+
emitReasoningDone(itemId) {
|
|
20049
|
+
const id = itemId || `reasoning_${this.responseId}`;
|
|
20050
|
+
const thinking = this.reasoningBuffer;
|
|
20051
|
+
this.reasoningBuffer = "";
|
|
20052
|
+
return {
|
|
20053
|
+
type: "response.reasoning.done" /* REASONING_DONE */,
|
|
20054
|
+
response_id: this.responseId,
|
|
20055
|
+
item_id: id,
|
|
20056
|
+
thinking
|
|
20057
|
+
};
|
|
20058
|
+
}
|
|
19472
20059
|
/**
|
|
19473
20060
|
* Create TOOL_CALL_START event
|
|
19474
20061
|
*/
|
|
@@ -19613,7 +20200,10 @@ var AnthropicStreamConverter = class extends BaseStreamConverter {
|
|
|
19613
20200
|
handleContentBlockStart(event) {
|
|
19614
20201
|
const index = event.index;
|
|
19615
20202
|
const block = event.content_block;
|
|
19616
|
-
if (block.type === "
|
|
20203
|
+
if (block.type === "thinking") {
|
|
20204
|
+
this.contentBlockIndex.set(index, { type: "thinking" });
|
|
20205
|
+
return [];
|
|
20206
|
+
} else if (block.type === "text") {
|
|
19617
20207
|
this.contentBlockIndex.set(index, { type: "text" });
|
|
19618
20208
|
return [];
|
|
19619
20209
|
} else if (block.type === "tool_use") {
|
|
@@ -19634,7 +20224,12 @@ var AnthropicStreamConverter = class extends BaseStreamConverter {
|
|
|
19634
20224
|
const delta = event.delta;
|
|
19635
20225
|
const blockInfo = this.contentBlockIndex.get(index);
|
|
19636
20226
|
if (!blockInfo) return [];
|
|
19637
|
-
if (delta.type === "
|
|
20227
|
+
if (delta.type === "thinking_delta") {
|
|
20228
|
+
const thinkingDelta = delta;
|
|
20229
|
+
return [
|
|
20230
|
+
this.emitReasoningDelta(thinkingDelta.thinking || "", `thinking_${this.responseId}`)
|
|
20231
|
+
];
|
|
20232
|
+
} else if (delta.type === "text_delta") {
|
|
19638
20233
|
return [
|
|
19639
20234
|
this.emitTextDelta(delta.text, {
|
|
19640
20235
|
itemId: `msg_${this.responseId}`,
|
|
@@ -19654,6 +20249,9 @@ var AnthropicStreamConverter = class extends BaseStreamConverter {
|
|
|
19654
20249
|
const index = event.index;
|
|
19655
20250
|
const blockInfo = this.contentBlockIndex.get(index);
|
|
19656
20251
|
if (!blockInfo) return [];
|
|
20252
|
+
if (blockInfo.type === "thinking") {
|
|
20253
|
+
return [this.emitReasoningDone(`thinking_${this.responseId}`)];
|
|
20254
|
+
}
|
|
19657
20255
|
if (blockInfo.type === "tool_use") {
|
|
19658
20256
|
return [this.emitToolCallArgsDone(blockInfo.id || "", blockInfo.name)];
|
|
19659
20257
|
}
|
|
@@ -19752,6 +20350,16 @@ var AnthropicTextProvider = class extends BaseTextProvider {
|
|
|
19752
20350
|
caps.supportsJSONSchema = false;
|
|
19753
20351
|
return caps;
|
|
19754
20352
|
}
|
|
20353
|
+
/**
|
|
20354
|
+
* List available models from the Anthropic API
|
|
20355
|
+
*/
|
|
20356
|
+
async listModels() {
|
|
20357
|
+
const models = [];
|
|
20358
|
+
for await (const model of this.client.models.list()) {
|
|
20359
|
+
models.push(model.id);
|
|
20360
|
+
}
|
|
20361
|
+
return models.sort();
|
|
20362
|
+
}
|
|
19755
20363
|
/**
|
|
19756
20364
|
* Handle Anthropic-specific errors
|
|
19757
20365
|
*/
|
|
@@ -19930,6 +20538,11 @@ var GoogleConverter = class {
|
|
|
19930
20538
|
request.generationConfig.thinkingConfig = {
|
|
19931
20539
|
thinkingLevel: options.vendorOptions.thinkingLevel
|
|
19932
20540
|
};
|
|
20541
|
+
} else if (options.thinking?.enabled) {
|
|
20542
|
+
validateThinkingConfig(options.thinking);
|
|
20543
|
+
request.generationConfig.thinkingConfig = {
|
|
20544
|
+
thinkingBudget: options.thinking.budgetTokens || 8192
|
|
20545
|
+
};
|
|
19933
20546
|
}
|
|
19934
20547
|
if (tools && tools.length > 0) {
|
|
19935
20548
|
request.generationConfig.allowCodeExecution = false;
|
|
@@ -20145,7 +20758,13 @@ var GoogleConverter = class {
|
|
|
20145
20758
|
convertGeminiPartsToContent(parts) {
|
|
20146
20759
|
const content = [];
|
|
20147
20760
|
for (const part of parts) {
|
|
20148
|
-
if ("text" in part && part.text) {
|
|
20761
|
+
if ("thought" in part && part.thought === true && "text" in part && part.text) {
|
|
20762
|
+
content.push({
|
|
20763
|
+
type: "thinking" /* THINKING */,
|
|
20764
|
+
thinking: part.text,
|
|
20765
|
+
persistInHistory: false
|
|
20766
|
+
});
|
|
20767
|
+
} else if ("text" in part && part.text) {
|
|
20149
20768
|
content.push(createTextContent(part.text));
|
|
20150
20769
|
} else if ("functionCall" in part && part.functionCall) {
|
|
20151
20770
|
const toolId = generateToolCallId("google");
|
|
@@ -20223,6 +20842,8 @@ var GoogleStreamConverter = class {
|
|
|
20223
20842
|
isFirst = true;
|
|
20224
20843
|
toolCallBuffers = /* @__PURE__ */ new Map();
|
|
20225
20844
|
hadToolCalls = false;
|
|
20845
|
+
reasoningBuffer = "";
|
|
20846
|
+
wasThinking = false;
|
|
20226
20847
|
// External storage for thought signatures (shared with GoogleConverter)
|
|
20227
20848
|
thoughtSignatureStorage = null;
|
|
20228
20849
|
// External storage for tool call ID → name mapping (shared with GoogleConverter)
|
|
@@ -20250,6 +20871,8 @@ var GoogleStreamConverter = class {
|
|
|
20250
20871
|
this.isFirst = true;
|
|
20251
20872
|
this.toolCallBuffers.clear();
|
|
20252
20873
|
this.hadToolCalls = false;
|
|
20874
|
+
this.reasoningBuffer = "";
|
|
20875
|
+
this.wasThinking = false;
|
|
20253
20876
|
let lastUsage = {
|
|
20254
20877
|
input_tokens: 0,
|
|
20255
20878
|
output_tokens: 0,
|
|
@@ -20275,6 +20898,16 @@ var GoogleStreamConverter = class {
|
|
|
20275
20898
|
yield event;
|
|
20276
20899
|
}
|
|
20277
20900
|
}
|
|
20901
|
+
if (this.wasThinking && this.reasoningBuffer) {
|
|
20902
|
+
yield {
|
|
20903
|
+
type: "response.reasoning.done" /* REASONING_DONE */,
|
|
20904
|
+
response_id: this.responseId,
|
|
20905
|
+
item_id: `thinking_${this.responseId}`,
|
|
20906
|
+
thinking: this.reasoningBuffer
|
|
20907
|
+
};
|
|
20908
|
+
this.reasoningBuffer = "";
|
|
20909
|
+
this.wasThinking = false;
|
|
20910
|
+
}
|
|
20278
20911
|
if (this.toolCallBuffers.size > 0) {
|
|
20279
20912
|
for (const [toolCallId, buffer] of this.toolCallBuffers) {
|
|
20280
20913
|
yield {
|
|
@@ -20314,7 +20947,28 @@ var GoogleStreamConverter = class {
|
|
|
20314
20947
|
const candidate = chunk.candidates?.[0];
|
|
20315
20948
|
if (!candidate?.content?.parts) return events;
|
|
20316
20949
|
for (const part of candidate.content.parts) {
|
|
20317
|
-
|
|
20950
|
+
const isThought = "thought" in part && part.thought === true;
|
|
20951
|
+
if (isThought && part.text) {
|
|
20952
|
+
this.wasThinking = true;
|
|
20953
|
+
this.reasoningBuffer += part.text;
|
|
20954
|
+
events.push({
|
|
20955
|
+
type: "response.reasoning.delta" /* REASONING_DELTA */,
|
|
20956
|
+
response_id: this.responseId,
|
|
20957
|
+
item_id: `thinking_${this.responseId}`,
|
|
20958
|
+
delta: part.text,
|
|
20959
|
+
sequence_number: this.sequenceNumber++
|
|
20960
|
+
});
|
|
20961
|
+
} else if (part.text) {
|
|
20962
|
+
if (this.wasThinking) {
|
|
20963
|
+
this.wasThinking = false;
|
|
20964
|
+
events.push({
|
|
20965
|
+
type: "response.reasoning.done" /* REASONING_DONE */,
|
|
20966
|
+
response_id: this.responseId,
|
|
20967
|
+
item_id: `thinking_${this.responseId}`,
|
|
20968
|
+
thinking: this.reasoningBuffer
|
|
20969
|
+
});
|
|
20970
|
+
this.reasoningBuffer = "";
|
|
20971
|
+
}
|
|
20318
20972
|
events.push({
|
|
20319
20973
|
type: "response.output_text.delta" /* OUTPUT_TEXT_DELTA */,
|
|
20320
20974
|
response_id: this.responseId,
|
|
@@ -20413,6 +21067,8 @@ var GoogleStreamConverter = class {
|
|
|
20413
21067
|
this.isFirst = true;
|
|
20414
21068
|
this.toolCallBuffers.clear();
|
|
20415
21069
|
this.hadToolCalls = false;
|
|
21070
|
+
this.reasoningBuffer = "";
|
|
21071
|
+
this.wasThinking = false;
|
|
20416
21072
|
}
|
|
20417
21073
|
/**
|
|
20418
21074
|
* Reset converter state for a new stream
|
|
@@ -20542,6 +21198,18 @@ var GoogleTextProvider = class extends BaseTextProvider {
|
|
|
20542
21198
|
maxOutputTokens: 65536
|
|
20543
21199
|
});
|
|
20544
21200
|
}
|
|
21201
|
+
/**
|
|
21202
|
+
* List available models from the Google Gemini API
|
|
21203
|
+
*/
|
|
21204
|
+
async listModels() {
|
|
21205
|
+
const models = [];
|
|
21206
|
+
const pager = await this.client.models.list();
|
|
21207
|
+
for await (const model of pager) {
|
|
21208
|
+
const name = model.name?.replace(/^models\//, "") ?? "";
|
|
21209
|
+
if (name) models.push(name);
|
|
21210
|
+
}
|
|
21211
|
+
return models.sort();
|
|
21212
|
+
}
|
|
20545
21213
|
/**
|
|
20546
21214
|
* Handle Google-specific errors
|
|
20547
21215
|
*/
|
|
@@ -20649,6 +21317,18 @@ var VertexAITextProvider = class extends BaseTextProvider {
|
|
|
20649
21317
|
maxOutputTokens: 65536
|
|
20650
21318
|
});
|
|
20651
21319
|
}
|
|
21320
|
+
/**
|
|
21321
|
+
* List available models from the Vertex AI API
|
|
21322
|
+
*/
|
|
21323
|
+
async listModels() {
|
|
21324
|
+
const models = [];
|
|
21325
|
+
const pager = await this.client.models.list();
|
|
21326
|
+
for await (const model of pager) {
|
|
21327
|
+
const name = model.name?.replace(/^models\//, "") ?? "";
|
|
21328
|
+
if (name) models.push(name);
|
|
21329
|
+
}
|
|
21330
|
+
return models.sort();
|
|
21331
|
+
}
|
|
20652
21332
|
/**
|
|
20653
21333
|
* Handle Vertex AI-specific errors
|
|
20654
21334
|
*/
|
|
@@ -20694,6 +21374,23 @@ var GenericOpenAIProvider = class extends OpenAITextProvider {
|
|
|
20694
21374
|
};
|
|
20695
21375
|
}
|
|
20696
21376
|
}
|
|
21377
|
+
/**
|
|
21378
|
+
* Override API key validation for generic providers.
|
|
21379
|
+
* Services like Ollama don't require authentication, so accept any key including mock/placeholder keys.
|
|
21380
|
+
*/
|
|
21381
|
+
validateApiKey() {
|
|
21382
|
+
return { isValid: true };
|
|
21383
|
+
}
|
|
21384
|
+
/**
|
|
21385
|
+
* Override listModels for error safety — some OpenAI-compatible APIs may not support /v1/models
|
|
21386
|
+
*/
|
|
21387
|
+
async listModels() {
|
|
21388
|
+
try {
|
|
21389
|
+
return await super.listModels();
|
|
21390
|
+
} catch {
|
|
21391
|
+
return [];
|
|
21392
|
+
}
|
|
21393
|
+
}
|
|
20697
21394
|
/**
|
|
20698
21395
|
* Override model capabilities for generic providers (registry-driven with conservative defaults)
|
|
20699
21396
|
*/
|
|
@@ -20891,7 +21588,7 @@ var BaseAgent = class extends eventemitter3.EventEmitter {
|
|
|
20891
21588
|
model: config.model,
|
|
20892
21589
|
agentId: config.name,
|
|
20893
21590
|
userId: config.userId,
|
|
20894
|
-
|
|
21591
|
+
identities: config.identities,
|
|
20895
21592
|
// Include storage and sessionId if session config is provided
|
|
20896
21593
|
storage: config.session?.storage,
|
|
20897
21594
|
// Thread tool execution timeout to ToolManager
|
|
@@ -21061,16 +21758,16 @@ var BaseAgent = class extends eventemitter3.EventEmitter {
|
|
|
21061
21758
|
this._agentContext.userId = value;
|
|
21062
21759
|
}
|
|
21063
21760
|
/**
|
|
21064
|
-
* Get the
|
|
21761
|
+
* Get the auth identities this agent is scoped to (undefined = all visible connectors).
|
|
21065
21762
|
*/
|
|
21066
|
-
get
|
|
21067
|
-
return this._agentContext.
|
|
21763
|
+
get identities() {
|
|
21764
|
+
return this._agentContext.identities;
|
|
21068
21765
|
}
|
|
21069
21766
|
/**
|
|
21070
|
-
*
|
|
21767
|
+
* Set auth identities at runtime. Updates ToolContext.connectorRegistry and tool descriptions.
|
|
21071
21768
|
*/
|
|
21072
|
-
set
|
|
21073
|
-
this._agentContext.
|
|
21769
|
+
set identities(value) {
|
|
21770
|
+
this._agentContext.identities = value;
|
|
21074
21771
|
}
|
|
21075
21772
|
/**
|
|
21076
21773
|
* Permission management. Returns ToolPermissionManager for approval control.
|
|
@@ -21082,9 +21779,12 @@ var BaseAgent = class extends eventemitter3.EventEmitter {
|
|
|
21082
21779
|
/**
|
|
21083
21780
|
* Add a tool to the agent.
|
|
21084
21781
|
* Tools are registered with AgentContext (single source of truth).
|
|
21782
|
+
*
|
|
21783
|
+
* @param tool - The tool function to register
|
|
21784
|
+
* @param options - Optional registration options (namespace, source, priority, etc.)
|
|
21085
21785
|
*/
|
|
21086
|
-
addTool(tool) {
|
|
21087
|
-
this._agentContext.tools.register(tool);
|
|
21786
|
+
addTool(tool, options) {
|
|
21787
|
+
this._agentContext.tools.register(tool, options);
|
|
21088
21788
|
if (tool.permission) {
|
|
21089
21789
|
this._permissionManager.setToolConfig(tool.definition.function.name, tool.permission);
|
|
21090
21790
|
}
|
|
@@ -21124,7 +21824,34 @@ var BaseAgent = class extends eventemitter3.EventEmitter {
|
|
|
21124
21824
|
*/
|
|
21125
21825
|
getEnabledToolDefinitions() {
|
|
21126
21826
|
const toolContext = this._agentContext.tools.getToolContext();
|
|
21127
|
-
|
|
21827
|
+
const identities = this._agentContext.identities;
|
|
21828
|
+
let allowedSources;
|
|
21829
|
+
let allowedConnectorNames;
|
|
21830
|
+
if (identities) {
|
|
21831
|
+
allowedSources = /* @__PURE__ */ new Set();
|
|
21832
|
+
allowedConnectorNames = /* @__PURE__ */ new Set();
|
|
21833
|
+
for (const id of identities) {
|
|
21834
|
+
allowedConnectorNames.add(id.connector);
|
|
21835
|
+
if (id.accountId) {
|
|
21836
|
+
allowedSources.add(`connector:${id.connector}:${id.accountId}`);
|
|
21837
|
+
} else {
|
|
21838
|
+
allowedSources.add(`connector:${id.connector}`);
|
|
21839
|
+
allowedConnectorNames.add(id.connector);
|
|
21840
|
+
}
|
|
21841
|
+
}
|
|
21842
|
+
}
|
|
21843
|
+
return this._agentContext.tools.getEnabledRegistrations().filter((reg) => {
|
|
21844
|
+
if (!allowedSources) return true;
|
|
21845
|
+
if (!reg.source?.startsWith("connector:")) return true;
|
|
21846
|
+
if (allowedSources.has(reg.source)) return true;
|
|
21847
|
+
const sourceParts = reg.source.slice("connector:".length).split(":");
|
|
21848
|
+
const connectorName = sourceParts[0];
|
|
21849
|
+
if (allowedConnectorNames.has(connectorName) && allowedSources.has(`connector:${connectorName}`)) {
|
|
21850
|
+
return true;
|
|
21851
|
+
}
|
|
21852
|
+
return false;
|
|
21853
|
+
}).map((reg) => {
|
|
21854
|
+
const tool = reg.tool;
|
|
21128
21855
|
if (tool.descriptionFactory) {
|
|
21129
21856
|
const dynamicDescription = tool.descriptionFactory(toolContext);
|
|
21130
21857
|
return {
|
|
@@ -21138,6 +21865,34 @@ var BaseAgent = class extends eventemitter3.EventEmitter {
|
|
|
21138
21865
|
return tool.definition;
|
|
21139
21866
|
});
|
|
21140
21867
|
}
|
|
21868
|
+
// ===== Model Discovery =====
|
|
21869
|
+
/**
|
|
21870
|
+
* List available models from the provider's API.
|
|
21871
|
+
* Useful for discovering models dynamically (e.g., Ollama local models).
|
|
21872
|
+
*/
|
|
21873
|
+
async listModels() {
|
|
21874
|
+
return this._provider.listModels();
|
|
21875
|
+
}
|
|
21876
|
+
// ===== Snapshot / Inspection =====
|
|
21877
|
+
/**
|
|
21878
|
+
* Get a complete, serializable snapshot of the agent's context state.
|
|
21879
|
+
*
|
|
21880
|
+
* Convenience method that auto-wires tool usage stats from ToolManager.
|
|
21881
|
+
* Used by UI "Look Inside" panels.
|
|
21882
|
+
*/
|
|
21883
|
+
async getSnapshot() {
|
|
21884
|
+
const stats = this._agentContext.tools.getStats();
|
|
21885
|
+
return this._agentContext.getSnapshot({ mostUsed: stats.mostUsed });
|
|
21886
|
+
}
|
|
21887
|
+
/**
|
|
21888
|
+
* Get a human-readable breakdown of the prepared context.
|
|
21889
|
+
*
|
|
21890
|
+
* Convenience method that delegates to AgentContextNextGen.
|
|
21891
|
+
* Used by "View Full Context" UI panels.
|
|
21892
|
+
*/
|
|
21893
|
+
async getViewContext() {
|
|
21894
|
+
return this._agentContext.getViewContext();
|
|
21895
|
+
}
|
|
21141
21896
|
// ===== Direct LLM Access (Bypasses AgentContext) =====
|
|
21142
21897
|
/**
|
|
21143
21898
|
* Get the provider for LLM calls.
|
|
@@ -21901,6 +22656,8 @@ var StreamState = class {
|
|
|
21901
22656
|
createdAt;
|
|
21902
22657
|
// Text accumulation: item_id -> text chunks
|
|
21903
22658
|
textBuffers;
|
|
22659
|
+
// Reasoning accumulation: item_id -> reasoning chunks
|
|
22660
|
+
reasoningBuffers;
|
|
21904
22661
|
// Tool call accumulation: tool_call_id -> buffer
|
|
21905
22662
|
toolCallBuffers;
|
|
21906
22663
|
// Completed tool calls
|
|
@@ -21922,6 +22679,7 @@ var StreamState = class {
|
|
|
21922
22679
|
this.model = model;
|
|
21923
22680
|
this.createdAt = createdAt || Date.now();
|
|
21924
22681
|
this.textBuffers = /* @__PURE__ */ new Map();
|
|
22682
|
+
this.reasoningBuffers = /* @__PURE__ */ new Map();
|
|
21925
22683
|
this.toolCallBuffers = /* @__PURE__ */ new Map();
|
|
21926
22684
|
this.completedToolCalls = [];
|
|
21927
22685
|
this.toolResults = /* @__PURE__ */ new Map();
|
|
@@ -21965,6 +22723,39 @@ var StreamState = class {
|
|
|
21965
22723
|
}
|
|
21966
22724
|
return allText.join("");
|
|
21967
22725
|
}
|
|
22726
|
+
/**
|
|
22727
|
+
* Accumulate reasoning delta for a specific item
|
|
22728
|
+
*/
|
|
22729
|
+
accumulateReasoningDelta(itemId, delta) {
|
|
22730
|
+
if (!this.reasoningBuffers.has(itemId)) {
|
|
22731
|
+
this.reasoningBuffers.set(itemId, []);
|
|
22732
|
+
}
|
|
22733
|
+
this.reasoningBuffers.get(itemId).push(delta);
|
|
22734
|
+
this.totalChunks++;
|
|
22735
|
+
}
|
|
22736
|
+
/**
|
|
22737
|
+
* Get complete accumulated reasoning for an item
|
|
22738
|
+
*/
|
|
22739
|
+
getCompleteReasoning(itemId) {
|
|
22740
|
+
const chunks = this.reasoningBuffers.get(itemId);
|
|
22741
|
+
return chunks ? chunks.join("") : "";
|
|
22742
|
+
}
|
|
22743
|
+
/**
|
|
22744
|
+
* Get all accumulated reasoning (all items concatenated)
|
|
22745
|
+
*/
|
|
22746
|
+
getAllReasoning() {
|
|
22747
|
+
const allReasoning = [];
|
|
22748
|
+
for (const chunks of this.reasoningBuffers.values()) {
|
|
22749
|
+
allReasoning.push(chunks.join(""));
|
|
22750
|
+
}
|
|
22751
|
+
return allReasoning.join("");
|
|
22752
|
+
}
|
|
22753
|
+
/**
|
|
22754
|
+
* Check if stream has any accumulated reasoning
|
|
22755
|
+
*/
|
|
22756
|
+
hasReasoning() {
|
|
22757
|
+
return this.reasoningBuffers.size > 0;
|
|
22758
|
+
}
|
|
21968
22759
|
/**
|
|
21969
22760
|
* Start accumulating tool call arguments
|
|
21970
22761
|
*/
|
|
@@ -22133,6 +22924,7 @@ var StreamState = class {
|
|
|
22133
22924
|
*/
|
|
22134
22925
|
clear() {
|
|
22135
22926
|
this.textBuffers.clear();
|
|
22927
|
+
this.reasoningBuffers.clear();
|
|
22136
22928
|
this.toolCallBuffers.clear();
|
|
22137
22929
|
this.completedToolCalls = [];
|
|
22138
22930
|
this.toolResults.clear();
|
|
@@ -22146,6 +22938,7 @@ var StreamState = class {
|
|
|
22146
22938
|
model: this.model,
|
|
22147
22939
|
createdAt: this.createdAt,
|
|
22148
22940
|
textBuffers: new Map(this.textBuffers),
|
|
22941
|
+
reasoningBuffers: new Map(this.reasoningBuffers),
|
|
22149
22942
|
toolCallBuffers: new Map(this.toolCallBuffers),
|
|
22150
22943
|
completedToolCalls: [...this.completedToolCalls],
|
|
22151
22944
|
toolResults: new Map(this.toolResults),
|
|
@@ -22575,6 +23368,20 @@ var Agent = class _Agent extends BaseAgent {
|
|
|
22575
23368
|
_addStreamingAssistantMessage(streamState, toolCalls) {
|
|
22576
23369
|
const assistantText = streamState.getAllText();
|
|
22577
23370
|
const assistantContent = [];
|
|
23371
|
+
if (streamState.hasReasoning()) {
|
|
23372
|
+
const reasoning = streamState.getAllReasoning();
|
|
23373
|
+
if (reasoning) {
|
|
23374
|
+
const isAnthropic = this.connector.vendor === Vendor.Anthropic;
|
|
23375
|
+
assistantContent.push({
|
|
23376
|
+
type: "thinking" /* THINKING */,
|
|
23377
|
+
thinking: reasoning,
|
|
23378
|
+
// Streaming doesn't carry Anthropic signatures, so signature is undefined here.
|
|
23379
|
+
// Non-streaming responses (via convertResponse) capture signatures correctly.
|
|
23380
|
+
signature: void 0,
|
|
23381
|
+
persistInHistory: isAnthropic
|
|
23382
|
+
});
|
|
23383
|
+
}
|
|
23384
|
+
}
|
|
22578
23385
|
if (assistantText && assistantText.trim()) {
|
|
22579
23386
|
assistantContent.push({
|
|
22580
23387
|
type: "output_text" /* OUTPUT_TEXT */,
|
|
@@ -22813,6 +23620,7 @@ var Agent = class _Agent extends BaseAgent {
|
|
|
22813
23620
|
tools: this.getEnabledToolDefinitions(),
|
|
22814
23621
|
tool_choice: "auto",
|
|
22815
23622
|
temperature: this._config.temperature,
|
|
23623
|
+
thinking: this._config.thinking,
|
|
22816
23624
|
vendorOptions: this._config.vendorOptions
|
|
22817
23625
|
};
|
|
22818
23626
|
const beforeLLM = await this.hookManager.executeHooks("before:llm", {
|
|
@@ -22878,6 +23686,7 @@ var Agent = class _Agent extends BaseAgent {
|
|
|
22878
23686
|
tools: this.getEnabledToolDefinitions(),
|
|
22879
23687
|
tool_choice: "auto",
|
|
22880
23688
|
temperature: this._config.temperature,
|
|
23689
|
+
thinking: this._config.thinking,
|
|
22881
23690
|
vendorOptions: this._config.vendorOptions
|
|
22882
23691
|
};
|
|
22883
23692
|
await this.hookManager.executeHooks("before:llm", {
|
|
@@ -22895,7 +23704,9 @@ var Agent = class _Agent extends BaseAgent {
|
|
|
22895
23704
|
});
|
|
22896
23705
|
try {
|
|
22897
23706
|
for await (const event of this._provider.streamGenerate(generateOptions)) {
|
|
22898
|
-
if (event
|
|
23707
|
+
if (isReasoningDelta(event)) {
|
|
23708
|
+
streamState.accumulateReasoningDelta(event.item_id, event.delta);
|
|
23709
|
+
} else if (event.type === "response.output_text.delta" /* OUTPUT_TEXT_DELTA */) {
|
|
22899
23710
|
streamState.accumulateTextDelta(event.item_id, event.delta);
|
|
22900
23711
|
} else if (event.type === "response.tool_call.start" /* TOOL_CALL_START */) {
|
|
22901
23712
|
streamState.startToolCall(event.tool_call_id, event.tool_name);
|
|
@@ -23425,6 +24236,7 @@ function createTask(input) {
|
|
|
23425
24236
|
suggestedTools: input.suggestedTools,
|
|
23426
24237
|
validation: input.validation,
|
|
23427
24238
|
expectedOutput: input.expectedOutput,
|
|
24239
|
+
controlFlow: input.controlFlow,
|
|
23428
24240
|
attempts: 0,
|
|
23429
24241
|
maxAttempts: input.maxAttempts ?? 3,
|
|
23430
24242
|
createdAt: now,
|
|
@@ -23677,6 +24489,7 @@ function createRoutineDefinition(input) {
|
|
|
23677
24489
|
instructions: input.instructions,
|
|
23678
24490
|
concurrency: input.concurrency,
|
|
23679
24491
|
allowDynamicTasks: input.allowDynamicTasks ?? false,
|
|
24492
|
+
parameters: input.parameters,
|
|
23680
24493
|
tags: input.tags,
|
|
23681
24494
|
author: input.author,
|
|
23682
24495
|
createdAt: now,
|
|
@@ -23892,6 +24705,321 @@ function extractNumber(text, patterns = [
|
|
|
23892
24705
|
|
|
23893
24706
|
// src/core/routineRunner.ts
|
|
23894
24707
|
init_Logger();
|
|
24708
|
+
|
|
24709
|
+
// src/core/routineControlFlow.ts
|
|
24710
|
+
init_Logger();
|
|
24711
|
+
var HARD_MAX_ITERATIONS = 1e3;
|
|
24712
|
+
var ICM_LARGE_THRESHOLD = 5e3;
|
|
24713
|
+
var ROUTINE_KEYS = {
|
|
24714
|
+
/** Plan overview with task statuses (ICM) */
|
|
24715
|
+
PLAN: "__routine_plan",
|
|
24716
|
+
/** Dependency results location guide (ICM) */
|
|
24717
|
+
DEPS: "__routine_deps",
|
|
24718
|
+
/** Prefix for per-dependency result keys (ICM/WM) */
|
|
24719
|
+
DEP_RESULT_PREFIX: "__dep_result_",
|
|
24720
|
+
/** Current map/fold item (ICM) */
|
|
24721
|
+
MAP_ITEM: "__map_item",
|
|
24722
|
+
/** Current map/fold index, 0-based (ICM) */
|
|
24723
|
+
MAP_INDEX: "__map_index",
|
|
24724
|
+
/** Total items in map/fold (ICM) */
|
|
24725
|
+
MAP_TOTAL: "__map_total",
|
|
24726
|
+
/** Running fold accumulator (ICM) */
|
|
24727
|
+
FOLD_ACCUMULATOR: "__fold_accumulator",
|
|
24728
|
+
/** Prefix for large dep results stored in WM findings tier */
|
|
24729
|
+
WM_DEP_FINDINGS_PREFIX: "findings/__dep_result_"
|
|
24730
|
+
};
|
|
24731
|
+
function resolveTemplates(text, inputs, icmPlugin) {
|
|
24732
|
+
return text.replace(/\{\{(\w+)\.(\w+)\}\}/g, (_match, namespace, key) => {
|
|
24733
|
+
let value;
|
|
24734
|
+
if (namespace === "param") {
|
|
24735
|
+
value = inputs[key];
|
|
24736
|
+
} else if (namespace === "map") {
|
|
24737
|
+
const icmKey = `__map_${key}`;
|
|
24738
|
+
value = icmPlugin?.get(icmKey);
|
|
24739
|
+
} else if (namespace === "fold") {
|
|
24740
|
+
const icmKey = `__fold_${key}`;
|
|
24741
|
+
value = icmPlugin?.get(icmKey);
|
|
24742
|
+
} else {
|
|
24743
|
+
return _match;
|
|
24744
|
+
}
|
|
24745
|
+
if (value === void 0) {
|
|
24746
|
+
return _match;
|
|
24747
|
+
}
|
|
24748
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
24749
|
+
});
|
|
24750
|
+
}
|
|
24751
|
+
function resolveTaskTemplates(task, inputs, icmPlugin) {
|
|
24752
|
+
const resolvedDescription = resolveTemplates(task.description, inputs, icmPlugin);
|
|
24753
|
+
const resolvedExpectedOutput = task.expectedOutput ? resolveTemplates(task.expectedOutput, inputs, icmPlugin) : task.expectedOutput;
|
|
24754
|
+
if (resolvedDescription === task.description && resolvedExpectedOutput === task.expectedOutput) {
|
|
24755
|
+
return task;
|
|
24756
|
+
}
|
|
24757
|
+
return {
|
|
24758
|
+
...task,
|
|
24759
|
+
description: resolvedDescription,
|
|
24760
|
+
expectedOutput: resolvedExpectedOutput
|
|
24761
|
+
};
|
|
24762
|
+
}
|
|
24763
|
+
function validateAndResolveInputs(parameters, inputs) {
|
|
24764
|
+
const resolved = { ...inputs ?? {} };
|
|
24765
|
+
if (!parameters || parameters.length === 0) {
|
|
24766
|
+
return resolved;
|
|
24767
|
+
}
|
|
24768
|
+
for (const param of parameters) {
|
|
24769
|
+
if (resolved[param.name] === void 0) {
|
|
24770
|
+
if (param.required) {
|
|
24771
|
+
throw new Error(`Missing required parameter: "${param.name}"`);
|
|
24772
|
+
}
|
|
24773
|
+
if (param.default !== void 0) {
|
|
24774
|
+
resolved[param.name] = param.default;
|
|
24775
|
+
}
|
|
24776
|
+
}
|
|
24777
|
+
}
|
|
24778
|
+
return resolved;
|
|
24779
|
+
}
|
|
24780
|
+
async function readMemoryValue(key, icmPlugin, wmPlugin) {
|
|
24781
|
+
if (icmPlugin) {
|
|
24782
|
+
const icmValue = icmPlugin.get(key);
|
|
24783
|
+
if (icmValue !== void 0) return icmValue;
|
|
24784
|
+
}
|
|
24785
|
+
if (wmPlugin) {
|
|
24786
|
+
const wmValue = await wmPlugin.retrieve(key);
|
|
24787
|
+
if (wmValue !== void 0) return wmValue;
|
|
24788
|
+
}
|
|
24789
|
+
return void 0;
|
|
24790
|
+
}
|
|
24791
|
+
async function storeResult(key, description, value, icmPlugin, wmPlugin) {
|
|
24792
|
+
const serialized = typeof value === "string" ? value : JSON.stringify(value);
|
|
24793
|
+
const estimatedTokens = Math.ceil(serialized.length / 4);
|
|
24794
|
+
if (estimatedTokens < ICM_LARGE_THRESHOLD && icmPlugin) {
|
|
24795
|
+
icmPlugin.set(key, description, value, "high");
|
|
24796
|
+
} else if (wmPlugin) {
|
|
24797
|
+
await wmPlugin.store(key, description, serialized, { tier: "findings" });
|
|
24798
|
+
} else if (icmPlugin) {
|
|
24799
|
+
icmPlugin.set(key, description, value, "high");
|
|
24800
|
+
}
|
|
24801
|
+
}
|
|
24802
|
+
function resolveSubRoutine(spec, parentTaskName) {
|
|
24803
|
+
if (!Array.isArray(spec)) {
|
|
24804
|
+
return spec;
|
|
24805
|
+
}
|
|
24806
|
+
return createRoutineDefinition({
|
|
24807
|
+
name: `${parentTaskName} (sub-routine)`,
|
|
24808
|
+
description: `Sub-routine of ${parentTaskName}`,
|
|
24809
|
+
tasks: spec
|
|
24810
|
+
});
|
|
24811
|
+
}
|
|
24812
|
+
function getPlugins(agent) {
|
|
24813
|
+
const icmPlugin = agent.context.getPlugin("in_context_memory");
|
|
24814
|
+
const wmPlugin = agent.context.memory;
|
|
24815
|
+
return { icmPlugin, wmPlugin };
|
|
24816
|
+
}
|
|
24817
|
+
function cleanMapKeys(icmPlugin) {
|
|
24818
|
+
if (!icmPlugin) return;
|
|
24819
|
+
icmPlugin.delete(ROUTINE_KEYS.MAP_ITEM);
|
|
24820
|
+
icmPlugin.delete(ROUTINE_KEYS.MAP_INDEX);
|
|
24821
|
+
icmPlugin.delete(ROUTINE_KEYS.MAP_TOTAL);
|
|
24822
|
+
}
|
|
24823
|
+
function cleanFoldKeys(icmPlugin) {
|
|
24824
|
+
if (!icmPlugin) return;
|
|
24825
|
+
cleanMapKeys(icmPlugin);
|
|
24826
|
+
icmPlugin.delete(ROUTINE_KEYS.FOLD_ACCUMULATOR);
|
|
24827
|
+
}
|
|
24828
|
+
async function readSourceArray(flow, flowType, icmPlugin, wmPlugin) {
|
|
24829
|
+
const sourceValue = await readMemoryValue(flow.sourceKey, icmPlugin, wmPlugin);
|
|
24830
|
+
if (!Array.isArray(sourceValue)) {
|
|
24831
|
+
return {
|
|
24832
|
+
completed: false,
|
|
24833
|
+
error: `${flowType} sourceKey "${flow.sourceKey}" is not an array (got ${typeof sourceValue})`
|
|
24834
|
+
};
|
|
24835
|
+
}
|
|
24836
|
+
const maxIter = Math.min(sourceValue.length, flow.maxIterations ?? sourceValue.length, HARD_MAX_ITERATIONS);
|
|
24837
|
+
return { array: sourceValue, maxIter };
|
|
24838
|
+
}
|
|
24839
|
+
function prepareSubRoutine(tasks, parentTaskName) {
|
|
24840
|
+
const subRoutine = resolveSubRoutine(tasks, parentTaskName);
|
|
24841
|
+
return {
|
|
24842
|
+
augmented: { ...subRoutine },
|
|
24843
|
+
baseInstructions: subRoutine.instructions ?? ""
|
|
24844
|
+
};
|
|
24845
|
+
}
|
|
24846
|
+
function getSubRoutineOutput(execution) {
|
|
24847
|
+
const tasks = execution.plan.tasks;
|
|
24848
|
+
for (let i = tasks.length - 1; i >= 0; i--) {
|
|
24849
|
+
if (tasks[i].status === "completed") {
|
|
24850
|
+
return tasks[i].result?.output ?? null;
|
|
24851
|
+
}
|
|
24852
|
+
}
|
|
24853
|
+
return null;
|
|
24854
|
+
}
|
|
24855
|
+
function setIterationKeys(icmPlugin, item, index, total, label) {
|
|
24856
|
+
if (!icmPlugin) return;
|
|
24857
|
+
icmPlugin.set(ROUTINE_KEYS.MAP_ITEM, `Current ${label} item (${index + 1}/${total})`, item, "high");
|
|
24858
|
+
icmPlugin.set(ROUTINE_KEYS.MAP_INDEX, `Current ${label} index (0-based)`, index, "high");
|
|
24859
|
+
icmPlugin.set(ROUTINE_KEYS.MAP_TOTAL, `Total items in ${label}`, total, "high");
|
|
24860
|
+
}
|
|
24861
|
+
async function withTimeout(promise, timeoutMs, label) {
|
|
24862
|
+
if (!timeoutMs) return promise;
|
|
24863
|
+
let timer;
|
|
24864
|
+
const timeout = new Promise((_, reject) => {
|
|
24865
|
+
timer = setTimeout(() => reject(new Error(`${label} timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
24866
|
+
});
|
|
24867
|
+
try {
|
|
24868
|
+
return await Promise.race([promise, timeout]);
|
|
24869
|
+
} finally {
|
|
24870
|
+
clearTimeout(timer);
|
|
24871
|
+
}
|
|
24872
|
+
}
|
|
24873
|
+
async function handleMap(agent, flow, task, inputs) {
|
|
24874
|
+
const { icmPlugin, wmPlugin } = getPlugins(agent);
|
|
24875
|
+
const log = exports.logger.child({ controlFlow: "map", task: task.name });
|
|
24876
|
+
const sourceResult = await readSourceArray(flow, "Map", icmPlugin, wmPlugin);
|
|
24877
|
+
if ("completed" in sourceResult) return sourceResult;
|
|
24878
|
+
const { array: array3, maxIter } = sourceResult;
|
|
24879
|
+
const results = [];
|
|
24880
|
+
const { augmented, baseInstructions } = prepareSubRoutine(flow.tasks, task.name);
|
|
24881
|
+
log.info({ arrayLength: array3.length, maxIterations: maxIter }, "Starting map iteration");
|
|
24882
|
+
try {
|
|
24883
|
+
for (let i = 0; i < maxIter; i++) {
|
|
24884
|
+
setIterationKeys(icmPlugin, array3[i], i, array3.length, "map");
|
|
24885
|
+
augmented.instructions = [
|
|
24886
|
+
`You are processing item ${i + 1} of ${array3.length} in a map operation.`,
|
|
24887
|
+
"The current item is available in your live context as __map_item.",
|
|
24888
|
+
"Current index (0-based) is in __map_index, total count in __map_total.",
|
|
24889
|
+
"",
|
|
24890
|
+
baseInstructions
|
|
24891
|
+
].join("\n");
|
|
24892
|
+
const subExecution = await withTimeout(
|
|
24893
|
+
executeRoutine({ definition: augmented, agent, inputs }),
|
|
24894
|
+
flow.iterationTimeoutMs,
|
|
24895
|
+
`Map iteration ${i}`
|
|
24896
|
+
);
|
|
24897
|
+
if (subExecution.status !== "completed") {
|
|
24898
|
+
return {
|
|
24899
|
+
completed: false,
|
|
24900
|
+
error: `Map iteration ${i} failed: ${subExecution.error ?? "sub-routine failed"}`
|
|
24901
|
+
};
|
|
24902
|
+
}
|
|
24903
|
+
results.push(getSubRoutineOutput(subExecution));
|
|
24904
|
+
}
|
|
24905
|
+
} finally {
|
|
24906
|
+
cleanMapKeys(icmPlugin);
|
|
24907
|
+
}
|
|
24908
|
+
if (flow.resultKey) {
|
|
24909
|
+
await storeResult(flow.resultKey, `Map results from "${task.name}"`, results, icmPlugin, wmPlugin);
|
|
24910
|
+
}
|
|
24911
|
+
log.info({ resultCount: results.length }, "Map completed");
|
|
24912
|
+
return { completed: true, result: results };
|
|
24913
|
+
}
|
|
24914
|
+
async function handleFold(agent, flow, task, inputs) {
|
|
24915
|
+
const { icmPlugin, wmPlugin } = getPlugins(agent);
|
|
24916
|
+
const log = exports.logger.child({ controlFlow: "fold", task: task.name });
|
|
24917
|
+
const sourceResult = await readSourceArray(flow, "Fold", icmPlugin, wmPlugin);
|
|
24918
|
+
if ("completed" in sourceResult) return sourceResult;
|
|
24919
|
+
const { array: array3, maxIter } = sourceResult;
|
|
24920
|
+
let accumulator = flow.initialValue;
|
|
24921
|
+
const { augmented, baseInstructions } = prepareSubRoutine(flow.tasks, task.name);
|
|
24922
|
+
log.info({ arrayLength: array3.length, maxIterations: maxIter }, "Starting fold iteration");
|
|
24923
|
+
try {
|
|
24924
|
+
for (let i = 0; i < maxIter; i++) {
|
|
24925
|
+
setIterationKeys(icmPlugin, array3[i], i, array3.length, "fold");
|
|
24926
|
+
if (icmPlugin) {
|
|
24927
|
+
icmPlugin.set(ROUTINE_KEYS.FOLD_ACCUMULATOR, "Running accumulator \u2014 update via context_set", accumulator, "high");
|
|
24928
|
+
}
|
|
24929
|
+
augmented.instructions = [
|
|
24930
|
+
`You are processing item ${i + 1} of ${array3.length} in a fold/accumulate operation.`,
|
|
24931
|
+
"The current item is in __map_item. The running accumulator is in __fold_accumulator.",
|
|
24932
|
+
"After processing, use context_set to update __fold_accumulator with the new accumulated value.",
|
|
24933
|
+
"Your final text response will also be captured as the result.",
|
|
24934
|
+
"",
|
|
24935
|
+
baseInstructions
|
|
24936
|
+
].join("\n");
|
|
24937
|
+
const subExecution = await withTimeout(
|
|
24938
|
+
executeRoutine({ definition: augmented, agent, inputs }),
|
|
24939
|
+
flow.iterationTimeoutMs,
|
|
24940
|
+
`Fold iteration ${i}`
|
|
24941
|
+
);
|
|
24942
|
+
if (subExecution.status !== "completed") {
|
|
24943
|
+
return {
|
|
24944
|
+
completed: false,
|
|
24945
|
+
error: `Fold iteration ${i} failed: ${subExecution.error ?? "sub-routine failed"}`
|
|
24946
|
+
};
|
|
24947
|
+
}
|
|
24948
|
+
const taskOutput = getSubRoutineOutput(subExecution);
|
|
24949
|
+
if (taskOutput !== null) {
|
|
24950
|
+
accumulator = taskOutput;
|
|
24951
|
+
} else if (icmPlugin) {
|
|
24952
|
+
const icmAccumulator = icmPlugin.get(ROUTINE_KEYS.FOLD_ACCUMULATOR);
|
|
24953
|
+
if (icmAccumulator !== void 0) {
|
|
24954
|
+
accumulator = icmAccumulator;
|
|
24955
|
+
}
|
|
24956
|
+
}
|
|
24957
|
+
}
|
|
24958
|
+
} finally {
|
|
24959
|
+
cleanFoldKeys(icmPlugin);
|
|
24960
|
+
}
|
|
24961
|
+
await storeResult(flow.resultKey, `Fold result from "${task.name}"`, accumulator, icmPlugin, wmPlugin);
|
|
24962
|
+
log.info("Fold completed");
|
|
24963
|
+
return { completed: true, result: accumulator };
|
|
24964
|
+
}
|
|
24965
|
+
async function handleUntil(agent, flow, task, inputs) {
|
|
24966
|
+
const { icmPlugin, wmPlugin } = getPlugins(agent);
|
|
24967
|
+
const log = exports.logger.child({ controlFlow: "until", task: task.name });
|
|
24968
|
+
const { augmented, baseInstructions } = prepareSubRoutine(flow.tasks, task.name);
|
|
24969
|
+
log.info({ maxIterations: flow.maxIterations }, "Starting until loop");
|
|
24970
|
+
const memoryAccess = {
|
|
24971
|
+
get: (key) => readMemoryValue(key, icmPlugin, wmPlugin)
|
|
24972
|
+
};
|
|
24973
|
+
try {
|
|
24974
|
+
for (let i = 0; i < flow.maxIterations; i++) {
|
|
24975
|
+
if (flow.iterationKey && icmPlugin) {
|
|
24976
|
+
icmPlugin.set(flow.iterationKey, "Current iteration index", i, "high");
|
|
24977
|
+
}
|
|
24978
|
+
augmented.instructions = [
|
|
24979
|
+
`You are in iteration ${i + 1} of a repeating operation (max ${flow.maxIterations}).`,
|
|
24980
|
+
"Complete the task. The loop will continue until its exit condition is met.",
|
|
24981
|
+
"",
|
|
24982
|
+
baseInstructions
|
|
24983
|
+
].join("\n");
|
|
24984
|
+
const subExecution = await withTimeout(
|
|
24985
|
+
executeRoutine({ definition: augmented, agent, inputs }),
|
|
24986
|
+
flow.iterationTimeoutMs,
|
|
24987
|
+
`Until iteration ${i}`
|
|
24988
|
+
);
|
|
24989
|
+
if (subExecution.status !== "completed") {
|
|
24990
|
+
return {
|
|
24991
|
+
completed: false,
|
|
24992
|
+
error: `Until iteration ${i} failed: ${subExecution.error ?? "sub-routine failed"}`
|
|
24993
|
+
};
|
|
24994
|
+
}
|
|
24995
|
+
const conditionMet = await evaluateCondition(flow.condition, memoryAccess);
|
|
24996
|
+
if (conditionMet) {
|
|
24997
|
+
log.info({ iteration: i + 1 }, "Until condition met");
|
|
24998
|
+
return { completed: true };
|
|
24999
|
+
}
|
|
25000
|
+
}
|
|
25001
|
+
} finally {
|
|
25002
|
+
if (flow.iterationKey && icmPlugin) {
|
|
25003
|
+
icmPlugin.delete(flow.iterationKey);
|
|
25004
|
+
}
|
|
25005
|
+
}
|
|
25006
|
+
return { completed: false, error: `Until loop: maxIterations (${flow.maxIterations}) exceeded` };
|
|
25007
|
+
}
|
|
25008
|
+
async function executeControlFlow(agent, task, inputs) {
|
|
25009
|
+
const flow = task.controlFlow;
|
|
25010
|
+
switch (flow.type) {
|
|
25011
|
+
case "map":
|
|
25012
|
+
return handleMap(agent, flow, task, inputs);
|
|
25013
|
+
case "fold":
|
|
25014
|
+
return handleFold(agent, flow, task, inputs);
|
|
25015
|
+
case "until":
|
|
25016
|
+
return handleUntil(agent, flow, task, inputs);
|
|
25017
|
+
default:
|
|
25018
|
+
return { completed: false, error: `Unknown control flow type: ${flow.type}` };
|
|
25019
|
+
}
|
|
25020
|
+
}
|
|
25021
|
+
|
|
25022
|
+
// src/core/routineRunner.ts
|
|
23895
25023
|
function defaultSystemPrompt(definition) {
|
|
23896
25024
|
const parts = [];
|
|
23897
25025
|
if (definition.instructions) {
|
|
@@ -24020,6 +25148,14 @@ async function collectValidationContext(agent, responseText) {
|
|
|
24020
25148
|
toolCallLog
|
|
24021
25149
|
};
|
|
24022
25150
|
}
|
|
25151
|
+
function isTransientError(error) {
|
|
25152
|
+
if (error instanceof ProviderAuthError) return false;
|
|
25153
|
+
if (error instanceof ProviderContextLengthError) return false;
|
|
25154
|
+
if (error instanceof ProviderNotFoundError) return false;
|
|
25155
|
+
if (error instanceof ModelNotSupportedError) return false;
|
|
25156
|
+
if (error instanceof InvalidConfigError) return false;
|
|
25157
|
+
return true;
|
|
25158
|
+
}
|
|
24023
25159
|
function estimateTokens(text) {
|
|
24024
25160
|
return Math.ceil(text.length / 4);
|
|
24025
25161
|
}
|
|
@@ -24063,32 +25199,42 @@ function buildPlanOverview(execution, definition, currentTaskId) {
|
|
|
24063
25199
|
}
|
|
24064
25200
|
return parts.join("\n");
|
|
24065
25201
|
}
|
|
24066
|
-
async function
|
|
24067
|
-
const icmPlugin = agent.context.getPlugin("in_context_memory");
|
|
24068
|
-
const wmPlugin = agent.context.memory;
|
|
24069
|
-
if (!icmPlugin && !wmPlugin) {
|
|
24070
|
-
exports.logger.warn("injectRoutineContext: No ICM or WM plugin available \u2014 skipping context injection");
|
|
24071
|
-
return;
|
|
24072
|
-
}
|
|
24073
|
-
const planOverview = buildPlanOverview(execution, definition, currentTask.id);
|
|
24074
|
-
if (icmPlugin) {
|
|
24075
|
-
icmPlugin.set("__routine_plan", "Routine plan overview with task statuses", planOverview, "high");
|
|
24076
|
-
}
|
|
25202
|
+
async function cleanupMemoryKeys(icmPlugin, wmPlugin, config) {
|
|
24077
25203
|
if (icmPlugin) {
|
|
24078
25204
|
for (const entry of icmPlugin.list()) {
|
|
24079
|
-
|
|
24080
|
-
|
|
24081
|
-
}
|
|
25205
|
+
const shouldDelete = config.icmPrefixes.some((p) => entry.key.startsWith(p)) || (config.icmExactKeys?.includes(entry.key) ?? false);
|
|
25206
|
+
if (shouldDelete) icmPlugin.delete(entry.key);
|
|
24082
25207
|
}
|
|
24083
25208
|
}
|
|
24084
25209
|
if (wmPlugin) {
|
|
24085
25210
|
const { entries: wmEntries } = await wmPlugin.query();
|
|
24086
25211
|
for (const entry of wmEntries) {
|
|
24087
|
-
if (
|
|
25212
|
+
if (config.wmPrefixes.some((p) => entry.key.startsWith(p))) {
|
|
24088
25213
|
await wmPlugin.delete(entry.key);
|
|
24089
25214
|
}
|
|
24090
25215
|
}
|
|
24091
25216
|
}
|
|
25217
|
+
}
|
|
25218
|
+
var DEP_CLEANUP_CONFIG = {
|
|
25219
|
+
icmPrefixes: [ROUTINE_KEYS.DEP_RESULT_PREFIX],
|
|
25220
|
+
icmExactKeys: [ROUTINE_KEYS.DEPS],
|
|
25221
|
+
wmPrefixes: [ROUTINE_KEYS.DEP_RESULT_PREFIX, ROUTINE_KEYS.WM_DEP_FINDINGS_PREFIX]
|
|
25222
|
+
};
|
|
25223
|
+
var FULL_CLEANUP_CONFIG = {
|
|
25224
|
+
icmPrefixes: ["__routine_", ROUTINE_KEYS.DEP_RESULT_PREFIX, "__map_", "__fold_"],
|
|
25225
|
+
wmPrefixes: [ROUTINE_KEYS.DEP_RESULT_PREFIX, ROUTINE_KEYS.WM_DEP_FINDINGS_PREFIX]
|
|
25226
|
+
};
|
|
25227
|
+
async function injectRoutineContext(agent, execution, definition, currentTask) {
|
|
25228
|
+
const { icmPlugin, wmPlugin } = getPlugins(agent);
|
|
25229
|
+
if (!icmPlugin && !wmPlugin) {
|
|
25230
|
+
exports.logger.warn("injectRoutineContext: No ICM or WM plugin available \u2014 skipping context injection");
|
|
25231
|
+
return;
|
|
25232
|
+
}
|
|
25233
|
+
const planOverview = buildPlanOverview(execution, definition, currentTask.id);
|
|
25234
|
+
if (icmPlugin) {
|
|
25235
|
+
icmPlugin.set(ROUTINE_KEYS.PLAN, "Routine plan overview with task statuses", planOverview, "high");
|
|
25236
|
+
}
|
|
25237
|
+
await cleanupMemoryKeys(icmPlugin, wmPlugin, DEP_CLEANUP_CONFIG);
|
|
24092
25238
|
if (currentTask.dependsOn.length === 0) return;
|
|
24093
25239
|
const inContextDeps = [];
|
|
24094
25240
|
const workingMemoryDeps = [];
|
|
@@ -24097,7 +25243,7 @@ async function injectRoutineContext(agent, execution, definition, currentTask) {
|
|
|
24097
25243
|
if (!depTask?.result?.output) continue;
|
|
24098
25244
|
const output = typeof depTask.result.output === "string" ? depTask.result.output : JSON.stringify(depTask.result.output);
|
|
24099
25245
|
const tokens = estimateTokens(output);
|
|
24100
|
-
const depKey =
|
|
25246
|
+
const depKey = `${ROUTINE_KEYS.DEP_RESULT_PREFIX}${depId}`;
|
|
24101
25247
|
const depLabel = `Result from task "${depTask.name}"`;
|
|
24102
25248
|
if (tokens < 5e3 && icmPlugin) {
|
|
24103
25249
|
icmPlugin.set(depKey, depLabel, output, "high");
|
|
@@ -24119,27 +25265,12 @@ async function injectRoutineContext(agent, execution, definition, currentTask) {
|
|
|
24119
25265
|
if (workingMemoryDeps.length > 0) {
|
|
24120
25266
|
summaryParts.push(`In working memory (use memory_retrieve): ${workingMemoryDeps.join(", ")}`);
|
|
24121
25267
|
}
|
|
24122
|
-
icmPlugin.set(
|
|
25268
|
+
icmPlugin.set(ROUTINE_KEYS.DEPS, "Dependency results location guide", summaryParts.join("\n"), "high");
|
|
24123
25269
|
}
|
|
24124
25270
|
}
|
|
24125
25271
|
async function cleanupRoutineContext(agent) {
|
|
24126
|
-
const icmPlugin = agent
|
|
24127
|
-
|
|
24128
|
-
if (icmPlugin) {
|
|
24129
|
-
for (const entry of icmPlugin.list()) {
|
|
24130
|
-
if (entry.key.startsWith("__routine_") || entry.key.startsWith("__dep_result_")) {
|
|
24131
|
-
icmPlugin.delete(entry.key);
|
|
24132
|
-
}
|
|
24133
|
-
}
|
|
24134
|
-
}
|
|
24135
|
-
if (wmPlugin) {
|
|
24136
|
-
const { entries: wmEntries } = await wmPlugin.query();
|
|
24137
|
-
for (const entry of wmEntries) {
|
|
24138
|
-
if (entry.key.startsWith("__dep_result_") || entry.key.startsWith("findings/__dep_result_")) {
|
|
24139
|
-
await wmPlugin.delete(entry.key);
|
|
24140
|
-
}
|
|
24141
|
-
}
|
|
24142
|
-
}
|
|
25272
|
+
const { icmPlugin, wmPlugin } = getPlugins(agent);
|
|
25273
|
+
await cleanupMemoryKeys(icmPlugin, wmPlugin, FULL_CLEANUP_CONFIG);
|
|
24143
25274
|
}
|
|
24144
25275
|
async function validateTaskCompletion(agent, task, responseText, validationPromptBuilder) {
|
|
24145
25276
|
const hasExplicitValidation = task.validation?.skipReflection === false && task.validation?.completionCriteria && task.validation.completionCriteria.length > 0;
|
|
@@ -24188,11 +25319,13 @@ async function executeRoutine(options) {
|
|
|
24188
25319
|
onTaskFailed,
|
|
24189
25320
|
onTaskValidation,
|
|
24190
25321
|
hooks,
|
|
24191
|
-
prompts
|
|
25322
|
+
prompts,
|
|
25323
|
+
inputs: rawInputs
|
|
24192
25324
|
} = options;
|
|
24193
25325
|
if (!existingAgent && (!connector || !model)) {
|
|
24194
25326
|
throw new Error("executeRoutine requires either `agent` or both `connector` and `model`");
|
|
24195
25327
|
}
|
|
25328
|
+
const resolvedInputs = validateAndResolveInputs(definition.parameters, rawInputs);
|
|
24196
25329
|
const ownsAgent = !existingAgent;
|
|
24197
25330
|
const log = exports.logger.child({ routine: definition.name });
|
|
24198
25331
|
const execution = createRoutineExecution(definition);
|
|
@@ -24277,7 +25410,7 @@ async function executeRoutine(options) {
|
|
|
24277
25410
|
execution.lastUpdatedAt = Date.now();
|
|
24278
25411
|
onTaskStarted?.(execution.plan.tasks[taskIndex], execution);
|
|
24279
25412
|
let taskCompleted = false;
|
|
24280
|
-
const maxTaskIterations = task.execution?.maxIterations ??
|
|
25413
|
+
const maxTaskIterations = task.execution?.maxIterations ?? 50;
|
|
24281
25414
|
const iterationLimiter = async (ctx) => {
|
|
24282
25415
|
if (ctx.iteration >= maxTaskIterations) {
|
|
24283
25416
|
agent.cancel(`Task "${task.name}" exceeded max iterations (${maxTaskIterations})`);
|
|
@@ -24285,85 +25418,115 @@ async function executeRoutine(options) {
|
|
|
24285
25418
|
return { shouldPause: false };
|
|
24286
25419
|
};
|
|
24287
25420
|
agent.registerHook("pause:check", iterationLimiter);
|
|
24288
|
-
|
|
24289
|
-
|
|
24290
|
-
|
|
24291
|
-
|
|
24292
|
-
|
|
24293
|
-
|
|
24294
|
-
|
|
24295
|
-
|
|
24296
|
-
|
|
24297
|
-
|
|
24298
|
-
|
|
24299
|
-
|
|
24300
|
-
|
|
24301
|
-
|
|
24302
|
-
|
|
24303
|
-
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "completed");
|
|
24304
|
-
execution.plan.tasks[taskIndex].result = {
|
|
24305
|
-
success: true,
|
|
24306
|
-
output: responseText,
|
|
24307
|
-
validationScore: validationResult.completionScore,
|
|
24308
|
-
validationExplanation: validationResult.explanation
|
|
24309
|
-
};
|
|
24310
|
-
taskCompleted = true;
|
|
24311
|
-
log.info(
|
|
24312
|
-
{ taskName: getTask().name, score: validationResult.completionScore },
|
|
24313
|
-
"Task completed"
|
|
24314
|
-
);
|
|
24315
|
-
execution.progress = getRoutineProgress(execution);
|
|
24316
|
-
execution.lastUpdatedAt = Date.now();
|
|
24317
|
-
onTaskComplete?.(execution.plan.tasks[taskIndex], execution);
|
|
24318
|
-
} else {
|
|
24319
|
-
log.warn(
|
|
24320
|
-
{
|
|
24321
|
-
taskName: getTask().name,
|
|
24322
|
-
score: validationResult.completionScore,
|
|
24323
|
-
attempt: getTask().attempts,
|
|
24324
|
-
maxAttempts: getTask().maxAttempts
|
|
24325
|
-
},
|
|
24326
|
-
"Task validation failed"
|
|
24327
|
-
);
|
|
24328
|
-
if (getTask().attempts >= getTask().maxAttempts) {
|
|
25421
|
+
try {
|
|
25422
|
+
const getTask = () => execution.plan.tasks[taskIndex];
|
|
25423
|
+
await injectRoutineContext(agent, execution, definition, getTask());
|
|
25424
|
+
const { icmPlugin } = getPlugins(agent);
|
|
25425
|
+
if (getTask().controlFlow) {
|
|
25426
|
+
try {
|
|
25427
|
+
const cfResult = await executeControlFlow(agent, getTask(), resolvedInputs);
|
|
25428
|
+
if (cfResult.completed) {
|
|
25429
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "completed");
|
|
25430
|
+
execution.plan.tasks[taskIndex].result = { success: true, output: cfResult.result };
|
|
25431
|
+
taskCompleted = true;
|
|
25432
|
+
execution.progress = getRoutineProgress(execution);
|
|
25433
|
+
execution.lastUpdatedAt = Date.now();
|
|
25434
|
+
onTaskComplete?.(execution.plan.tasks[taskIndex], execution);
|
|
25435
|
+
} else {
|
|
24329
25436
|
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
|
|
24330
|
-
execution.plan.tasks[taskIndex].result = {
|
|
24331
|
-
success: false,
|
|
24332
|
-
error: validationResult.explanation,
|
|
24333
|
-
validationScore: validationResult.completionScore,
|
|
24334
|
-
validationExplanation: validationResult.explanation
|
|
24335
|
-
};
|
|
24336
|
-
break;
|
|
25437
|
+
execution.plan.tasks[taskIndex].result = { success: false, error: cfResult.error };
|
|
24337
25438
|
}
|
|
24338
|
-
|
|
24339
|
-
|
|
24340
|
-
|
|
24341
|
-
const errorMessage = error.message;
|
|
24342
|
-
log.error({ taskName: getTask().name, error: errorMessage }, "Task execution error");
|
|
24343
|
-
if (getTask().attempts >= getTask().maxAttempts) {
|
|
25439
|
+
} catch (error) {
|
|
25440
|
+
const errorMessage = error.message;
|
|
25441
|
+
log.error({ taskName: getTask().name, error: errorMessage }, "Control flow error");
|
|
24344
25442
|
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
|
|
24345
|
-
execution.plan.tasks[taskIndex].result = {
|
|
24346
|
-
|
|
24347
|
-
|
|
24348
|
-
|
|
24349
|
-
|
|
25443
|
+
execution.plan.tasks[taskIndex].result = { success: false, error: errorMessage };
|
|
25444
|
+
}
|
|
25445
|
+
} else {
|
|
25446
|
+
while (!taskCompleted) {
|
|
25447
|
+
try {
|
|
25448
|
+
const resolvedTask = resolveTaskTemplates(getTask(), resolvedInputs, icmPlugin);
|
|
25449
|
+
const taskPrompt = buildTaskPrompt(resolvedTask);
|
|
25450
|
+
const response = await agent.run(taskPrompt);
|
|
25451
|
+
const responseText = response.output_text ?? "";
|
|
25452
|
+
const validationResult = await validateTaskCompletion(
|
|
25453
|
+
agent,
|
|
25454
|
+
getTask(),
|
|
25455
|
+
responseText,
|
|
25456
|
+
buildValidationPrompt
|
|
25457
|
+
);
|
|
25458
|
+
onTaskValidation?.(getTask(), validationResult, execution);
|
|
25459
|
+
if (validationResult.isComplete) {
|
|
25460
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "completed");
|
|
25461
|
+
execution.plan.tasks[taskIndex].result = {
|
|
25462
|
+
success: true,
|
|
25463
|
+
output: responseText,
|
|
25464
|
+
validationScore: validationResult.completionScore,
|
|
25465
|
+
validationExplanation: validationResult.explanation
|
|
25466
|
+
};
|
|
25467
|
+
taskCompleted = true;
|
|
25468
|
+
log.info(
|
|
25469
|
+
{ taskName: getTask().name, score: validationResult.completionScore },
|
|
25470
|
+
"Task completed"
|
|
25471
|
+
);
|
|
25472
|
+
execution.progress = getRoutineProgress(execution);
|
|
25473
|
+
execution.lastUpdatedAt = Date.now();
|
|
25474
|
+
onTaskComplete?.(execution.plan.tasks[taskIndex], execution);
|
|
25475
|
+
} else {
|
|
25476
|
+
log.warn(
|
|
25477
|
+
{
|
|
25478
|
+
taskName: getTask().name,
|
|
25479
|
+
score: validationResult.completionScore,
|
|
25480
|
+
attempt: getTask().attempts,
|
|
25481
|
+
maxAttempts: getTask().maxAttempts
|
|
25482
|
+
},
|
|
25483
|
+
"Task validation failed"
|
|
25484
|
+
);
|
|
25485
|
+
if (getTask().attempts >= getTask().maxAttempts) {
|
|
25486
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
|
|
25487
|
+
execution.plan.tasks[taskIndex].result = {
|
|
25488
|
+
success: false,
|
|
25489
|
+
error: validationResult.explanation,
|
|
25490
|
+
validationScore: validationResult.completionScore,
|
|
25491
|
+
validationExplanation: validationResult.explanation
|
|
25492
|
+
};
|
|
25493
|
+
break;
|
|
25494
|
+
}
|
|
25495
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
|
|
25496
|
+
}
|
|
25497
|
+
} catch (error) {
|
|
25498
|
+
const errorMessage = error.message;
|
|
25499
|
+
log.error({ taskName: getTask().name, error: errorMessage }, "Task execution error");
|
|
25500
|
+
if (!isTransientError(error) || getTask().attempts >= getTask().maxAttempts) {
|
|
25501
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
|
|
25502
|
+
execution.plan.tasks[taskIndex].result = {
|
|
25503
|
+
success: false,
|
|
25504
|
+
error: errorMessage
|
|
25505
|
+
};
|
|
25506
|
+
break;
|
|
25507
|
+
}
|
|
25508
|
+
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
|
|
25509
|
+
}
|
|
24350
25510
|
}
|
|
24351
|
-
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
|
|
24352
25511
|
}
|
|
24353
|
-
|
|
24354
|
-
|
|
24355
|
-
execution.progress = getRoutineProgress(execution);
|
|
24356
|
-
execution.lastUpdatedAt = Date.now();
|
|
24357
|
-
onTaskFailed?.(execution.plan.tasks[taskIndex], execution);
|
|
24358
|
-
if (failureMode === "fail-fast") {
|
|
24359
|
-
execution.status = "failed";
|
|
24360
|
-
execution.error = `Task "${getTask().name}" failed after ${getTask().attempts} attempt(s)`;
|
|
24361
|
-
execution.completedAt = Date.now();
|
|
25512
|
+
if (!taskCompleted) {
|
|
25513
|
+
execution.progress = getRoutineProgress(execution);
|
|
24362
25514
|
execution.lastUpdatedAt = Date.now();
|
|
24363
|
-
|
|
25515
|
+
onTaskFailed?.(execution.plan.tasks[taskIndex], execution);
|
|
25516
|
+
if (failureMode === "fail-fast") {
|
|
25517
|
+
execution.status = "failed";
|
|
25518
|
+
execution.error = `Task "${getTask().name}" failed after ${getTask().attempts} attempt(s)`;
|
|
25519
|
+
execution.completedAt = Date.now();
|
|
25520
|
+
execution.lastUpdatedAt = Date.now();
|
|
25521
|
+
break;
|
|
25522
|
+
}
|
|
25523
|
+
}
|
|
25524
|
+
} finally {
|
|
25525
|
+
try {
|
|
25526
|
+
agent.unregisterHook("pause:check", iterationLimiter);
|
|
25527
|
+
} catch {
|
|
24364
25528
|
}
|
|
24365
25529
|
}
|
|
24366
|
-
agent.unregisterHook("pause:check", iterationLimiter);
|
|
24367
25530
|
agent.clearConversation("task-boundary");
|
|
24368
25531
|
nextTasks = getNextExecutableTasks(execution.plan);
|
|
24369
25532
|
}
|
|
@@ -24391,16 +25554,22 @@ async function executeRoutine(options) {
|
|
|
24391
25554
|
} finally {
|
|
24392
25555
|
try {
|
|
24393
25556
|
await cleanupRoutineContext(agent);
|
|
24394
|
-
} catch {
|
|
25557
|
+
} catch (e) {
|
|
25558
|
+
log.debug({ error: e.message }, "Failed to clean up routine context");
|
|
24395
25559
|
}
|
|
24396
25560
|
for (const { name, hook } of registeredHooks) {
|
|
24397
25561
|
try {
|
|
24398
25562
|
agent.unregisterHook(name, hook);
|
|
24399
|
-
} catch {
|
|
25563
|
+
} catch (e) {
|
|
25564
|
+
log.debug({ hookName: name, error: e.message }, "Failed to unregister hook");
|
|
24400
25565
|
}
|
|
24401
25566
|
}
|
|
24402
25567
|
if (ownsAgent) {
|
|
24403
|
-
|
|
25568
|
+
try {
|
|
25569
|
+
agent.destroy();
|
|
25570
|
+
} catch (e) {
|
|
25571
|
+
log.debug({ error: e.message }, "Failed to destroy agent");
|
|
25572
|
+
}
|
|
24404
25573
|
}
|
|
24405
25574
|
}
|
|
24406
25575
|
}
|
|
@@ -31207,7 +32376,7 @@ var TextToSpeech = class _TextToSpeech {
|
|
|
31207
32376
|
*/
|
|
31208
32377
|
async toFile(text, filePath, options) {
|
|
31209
32378
|
const response = await this.synthesize(text, options);
|
|
31210
|
-
await
|
|
32379
|
+
await fs17__namespace.writeFile(filePath, response.audio);
|
|
31211
32380
|
}
|
|
31212
32381
|
// ======================== Introspection Methods ========================
|
|
31213
32382
|
/**
|
|
@@ -31555,7 +32724,7 @@ var SpeechToText = class _SpeechToText {
|
|
|
31555
32724
|
* @param options - Optional transcription parameters
|
|
31556
32725
|
*/
|
|
31557
32726
|
async transcribeFile(filePath, options) {
|
|
31558
|
-
const audio = await
|
|
32727
|
+
const audio = await fs17__namespace.readFile(filePath);
|
|
31559
32728
|
return this.transcribe(audio, options);
|
|
31560
32729
|
}
|
|
31561
32730
|
/**
|
|
@@ -35701,7 +36870,7 @@ var DocumentReader = class _DocumentReader {
|
|
|
35701
36870
|
async resolveSource(source) {
|
|
35702
36871
|
switch (source.type) {
|
|
35703
36872
|
case "file": {
|
|
35704
|
-
const buffer = await
|
|
36873
|
+
const buffer = await fs17.readFile(source.path);
|
|
35705
36874
|
const filename = source.path.split("/").pop() || source.path;
|
|
35706
36875
|
return { buffer, filename };
|
|
35707
36876
|
}
|
|
@@ -38298,10 +39467,10 @@ var FileMediaStorage = class {
|
|
|
38298
39467
|
}
|
|
38299
39468
|
async save(data, metadata) {
|
|
38300
39469
|
const dir = metadata.userId ? path2__namespace.join(this.outputDir, metadata.userId) : this.outputDir;
|
|
38301
|
-
await
|
|
39470
|
+
await fs17__namespace.mkdir(dir, { recursive: true });
|
|
38302
39471
|
const filename = metadata.suggestedFilename ?? this.generateFilename(metadata);
|
|
38303
39472
|
const filePath = path2__namespace.join(dir, filename);
|
|
38304
|
-
await
|
|
39473
|
+
await fs17__namespace.writeFile(filePath, data);
|
|
38305
39474
|
const format = metadata.format.toLowerCase();
|
|
38306
39475
|
const mimeType = MIME_TYPES2[format] ?? "application/octet-stream";
|
|
38307
39476
|
return {
|
|
@@ -38312,7 +39481,7 @@ var FileMediaStorage = class {
|
|
|
38312
39481
|
}
|
|
38313
39482
|
async read(location) {
|
|
38314
39483
|
try {
|
|
38315
|
-
return await
|
|
39484
|
+
return await fs17__namespace.readFile(location);
|
|
38316
39485
|
} catch (err) {
|
|
38317
39486
|
if (err.code === "ENOENT") {
|
|
38318
39487
|
return null;
|
|
@@ -38322,7 +39491,7 @@ var FileMediaStorage = class {
|
|
|
38322
39491
|
}
|
|
38323
39492
|
async delete(location) {
|
|
38324
39493
|
try {
|
|
38325
|
-
await
|
|
39494
|
+
await fs17__namespace.unlink(location);
|
|
38326
39495
|
} catch (err) {
|
|
38327
39496
|
if (err.code === "ENOENT") {
|
|
38328
39497
|
return;
|
|
@@ -38332,7 +39501,7 @@ var FileMediaStorage = class {
|
|
|
38332
39501
|
}
|
|
38333
39502
|
async exists(location) {
|
|
38334
39503
|
try {
|
|
38335
|
-
await
|
|
39504
|
+
await fs17__namespace.access(location);
|
|
38336
39505
|
return true;
|
|
38337
39506
|
} catch {
|
|
38338
39507
|
return false;
|
|
@@ -38341,11 +39510,11 @@ var FileMediaStorage = class {
|
|
|
38341
39510
|
async list(options) {
|
|
38342
39511
|
await this.ensureDir();
|
|
38343
39512
|
let entries = [];
|
|
38344
|
-
const files = await
|
|
39513
|
+
const files = await fs17__namespace.readdir(this.outputDir);
|
|
38345
39514
|
for (const file of files) {
|
|
38346
39515
|
const filePath = path2__namespace.join(this.outputDir, file);
|
|
38347
39516
|
try {
|
|
38348
|
-
const stat6 = await
|
|
39517
|
+
const stat6 = await fs17__namespace.stat(filePath);
|
|
38349
39518
|
if (!stat6.isFile()) continue;
|
|
38350
39519
|
const ext = path2__namespace.extname(file).slice(1).toLowerCase();
|
|
38351
39520
|
const mimeType = MIME_TYPES2[ext] ?? "application/octet-stream";
|
|
@@ -38385,7 +39554,7 @@ var FileMediaStorage = class {
|
|
|
38385
39554
|
}
|
|
38386
39555
|
async ensureDir() {
|
|
38387
39556
|
if (!this.initialized) {
|
|
38388
|
-
await
|
|
39557
|
+
await fs17__namespace.mkdir(this.outputDir, { recursive: true });
|
|
38389
39558
|
this.initialized = true;
|
|
38390
39559
|
}
|
|
38391
39560
|
}
|
|
@@ -38920,6 +40089,42 @@ var StreamHelpers = class {
|
|
|
38920
40089
|
}
|
|
38921
40090
|
return chunks.join("");
|
|
38922
40091
|
}
|
|
40092
|
+
/**
|
|
40093
|
+
* Get only reasoning/thinking deltas from stream
|
|
40094
|
+
* Filters out all other event types
|
|
40095
|
+
*/
|
|
40096
|
+
static async *thinkingOnly(stream) {
|
|
40097
|
+
for await (const event of stream) {
|
|
40098
|
+
if (isReasoningDelta(event)) {
|
|
40099
|
+
yield event.delta;
|
|
40100
|
+
}
|
|
40101
|
+
}
|
|
40102
|
+
}
|
|
40103
|
+
/**
|
|
40104
|
+
* Get both text and thinking deltas from stream
|
|
40105
|
+
* Yields tagged objects so consumers can distinguish them
|
|
40106
|
+
*/
|
|
40107
|
+
static async *textAndThinking(stream) {
|
|
40108
|
+
for await (const event of stream) {
|
|
40109
|
+
if (isOutputTextDelta(event)) {
|
|
40110
|
+
yield { type: "text", delta: event.delta };
|
|
40111
|
+
} else if (isReasoningDelta(event)) {
|
|
40112
|
+
yield { type: "thinking", delta: event.delta };
|
|
40113
|
+
}
|
|
40114
|
+
}
|
|
40115
|
+
}
|
|
40116
|
+
/**
|
|
40117
|
+
* Accumulate all thinking/reasoning content from stream into a single string
|
|
40118
|
+
*/
|
|
40119
|
+
static async accumulateThinking(stream) {
|
|
40120
|
+
const chunks = [];
|
|
40121
|
+
for await (const event of stream) {
|
|
40122
|
+
if (isReasoningDelta(event)) {
|
|
40123
|
+
chunks.push(event.delta);
|
|
40124
|
+
}
|
|
40125
|
+
}
|
|
40126
|
+
return chunks.join("");
|
|
40127
|
+
}
|
|
38923
40128
|
/**
|
|
38924
40129
|
* Buffer stream events into batches
|
|
38925
40130
|
*/
|
|
@@ -38979,6 +40184,11 @@ var StreamHelpers = class {
|
|
|
38979
40184
|
case "response.output_text.delta" /* OUTPUT_TEXT_DELTA */:
|
|
38980
40185
|
state.accumulateTextDelta(event.item_id, event.delta);
|
|
38981
40186
|
break;
|
|
40187
|
+
case "response.reasoning.delta" /* REASONING_DELTA */:
|
|
40188
|
+
state.accumulateReasoningDelta(event.item_id, event.delta);
|
|
40189
|
+
break;
|
|
40190
|
+
case "response.reasoning.done" /* REASONING_DONE */:
|
|
40191
|
+
break;
|
|
38982
40192
|
case "response.tool_call.start" /* TOOL_CALL_START */:
|
|
38983
40193
|
state.startToolCall(event.tool_call_id, event.tool_name);
|
|
38984
40194
|
break;
|
|
@@ -39009,21 +40219,36 @@ var StreamHelpers = class {
|
|
|
39009
40219
|
*/
|
|
39010
40220
|
static reconstructLLMResponse(state) {
|
|
39011
40221
|
const output = [];
|
|
40222
|
+
const contentParts = [];
|
|
40223
|
+
let thinkingText;
|
|
40224
|
+
if (state.hasReasoning()) {
|
|
40225
|
+
const reasoning = state.getAllReasoning();
|
|
40226
|
+
if (reasoning) {
|
|
40227
|
+
thinkingText = reasoning;
|
|
40228
|
+
contentParts.push({
|
|
40229
|
+
type: "thinking" /* THINKING */,
|
|
40230
|
+
thinking: reasoning,
|
|
40231
|
+
persistInHistory: false
|
|
40232
|
+
// Vendor-agnostic default; caller can adjust
|
|
40233
|
+
});
|
|
40234
|
+
}
|
|
40235
|
+
}
|
|
39012
40236
|
if (state.hasText()) {
|
|
39013
40237
|
const textContent = state.getAllText();
|
|
39014
40238
|
if (textContent) {
|
|
39015
|
-
|
|
39016
|
-
type: "
|
|
39017
|
-
|
|
39018
|
-
content: [
|
|
39019
|
-
{
|
|
39020
|
-
type: "output_text" /* OUTPUT_TEXT */,
|
|
39021
|
-
text: textContent
|
|
39022
|
-
}
|
|
39023
|
-
]
|
|
40239
|
+
contentParts.push({
|
|
40240
|
+
type: "output_text" /* OUTPUT_TEXT */,
|
|
40241
|
+
text: textContent
|
|
39024
40242
|
});
|
|
39025
40243
|
}
|
|
39026
40244
|
}
|
|
40245
|
+
if (contentParts.length > 0) {
|
|
40246
|
+
output.push({
|
|
40247
|
+
type: "message",
|
|
40248
|
+
role: "assistant" /* ASSISTANT */,
|
|
40249
|
+
content: contentParts
|
|
40250
|
+
});
|
|
40251
|
+
}
|
|
39027
40252
|
const toolCalls = state.getCompletedToolCalls();
|
|
39028
40253
|
if (toolCalls.length > 0) {
|
|
39029
40254
|
const toolUseContent = toolCalls.map((tc) => ({
|
|
@@ -39052,6 +40277,7 @@ var StreamHelpers = class {
|
|
|
39052
40277
|
model: state.model,
|
|
39053
40278
|
output,
|
|
39054
40279
|
output_text: outputText,
|
|
40280
|
+
thinking: thinkingText,
|
|
39055
40281
|
usage: state.usage
|
|
39056
40282
|
};
|
|
39057
40283
|
}
|
|
@@ -39180,6 +40406,15 @@ var SERVICE_DEFINITIONS = [
|
|
|
39180
40406
|
baseURL: "https://api.telegram.org",
|
|
39181
40407
|
docsURL: "https://core.telegram.org/bots/api"
|
|
39182
40408
|
},
|
|
40409
|
+
{
|
|
40410
|
+
id: "twitter",
|
|
40411
|
+
name: "X (Twitter)",
|
|
40412
|
+
category: "communication",
|
|
40413
|
+
urlPattern: /api\.x\.com|api\.twitter\.com/i,
|
|
40414
|
+
baseURL: "https://api.x.com/2",
|
|
40415
|
+
docsURL: "https://developer.x.com/en/docs/x-api",
|
|
40416
|
+
commonScopes: ["tweet.read", "tweet.write", "users.read", "offline.access"]
|
|
40417
|
+
},
|
|
39183
40418
|
// ============ Development & Project Management ============
|
|
39184
40419
|
{
|
|
39185
40420
|
id: "github",
|
|
@@ -39667,19 +40902,30 @@ var ConnectorTools = class {
|
|
|
39667
40902
|
*/
|
|
39668
40903
|
static for(connectorOrName, userId, options) {
|
|
39669
40904
|
const connector = this.resolveConnector(connectorOrName, options?.registry);
|
|
40905
|
+
const accountId = options?.accountId;
|
|
39670
40906
|
const tools = [];
|
|
40907
|
+
const namePrefix = accountId ? `${sanitizeToolName(connector.name)}_${sanitizeToolName(accountId)}` : sanitizeToolName(connector.name);
|
|
39671
40908
|
if (connector.baseURL) {
|
|
39672
|
-
|
|
40909
|
+
const accountLabel = accountId ? ` (account: ${accountId})` : "";
|
|
40910
|
+
tools.push(this.createGenericAPITool(connector, {
|
|
40911
|
+
userId,
|
|
40912
|
+
accountId,
|
|
40913
|
+
toolName: `${namePrefix}_api`,
|
|
40914
|
+
description: `Make an authenticated API call to ${connector.displayName}${accountLabel}.` + (connector.baseURL ? ` Base URL: ${connector.baseURL}.` : " Provide full URL in endpoint.") + ' IMPORTANT: For POST/PUT/PATCH requests, pass data in the "body" parameter as a JSON object, NOT as query string parameters in the endpoint URL. The body is sent as application/json.'
|
|
40915
|
+
}));
|
|
39673
40916
|
}
|
|
39674
40917
|
const serviceType = this.detectService(connector);
|
|
39675
40918
|
if (serviceType && this.factories.has(serviceType)) {
|
|
39676
40919
|
const factory = this.factories.get(serviceType);
|
|
39677
40920
|
const serviceTools = factory(connector, userId);
|
|
39678
40921
|
for (const tool of serviceTools) {
|
|
39679
|
-
tool.definition.function.name = `${
|
|
40922
|
+
tool.definition.function.name = `${namePrefix}_${tool.definition.function.name}`;
|
|
39680
40923
|
}
|
|
39681
40924
|
tools.push(...serviceTools);
|
|
39682
40925
|
}
|
|
40926
|
+
if (accountId) {
|
|
40927
|
+
return tools.map((tool) => this.bindAccountId(tool, accountId));
|
|
40928
|
+
}
|
|
39683
40929
|
return tools;
|
|
39684
40930
|
}
|
|
39685
40931
|
/**
|
|
@@ -39829,6 +41075,56 @@ var ConnectorTools = class {
|
|
|
39829
41075
|
}
|
|
39830
41076
|
return connectorOrName;
|
|
39831
41077
|
}
|
|
41078
|
+
/**
|
|
41079
|
+
* Generate tools for a set of auth identities.
|
|
41080
|
+
* Each identity gets its own tool set with unique name prefixes.
|
|
41081
|
+
*
|
|
41082
|
+
* @param identities - Array of auth identities
|
|
41083
|
+
* @param userId - Optional user ID for multi-user OAuth
|
|
41084
|
+
* @param options - Optional registry for scoped connector lookup
|
|
41085
|
+
* @returns Map of identity key to tool array
|
|
41086
|
+
*
|
|
41087
|
+
* @example
|
|
41088
|
+
* ```typescript
|
|
41089
|
+
* const toolsByIdentity = ConnectorTools.forIdentities([
|
|
41090
|
+
* { connector: 'microsoft', accountId: 'work' },
|
|
41091
|
+
* { connector: 'microsoft', accountId: 'personal' },
|
|
41092
|
+
* { connector: 'github' },
|
|
41093
|
+
* ]);
|
|
41094
|
+
* // Keys: 'microsoft:work', 'microsoft:personal', 'github'
|
|
41095
|
+
* ```
|
|
41096
|
+
*/
|
|
41097
|
+
static forIdentities(identities, userId, options) {
|
|
41098
|
+
const result = /* @__PURE__ */ new Map();
|
|
41099
|
+
for (const identity of identities) {
|
|
41100
|
+
const key = identity.accountId ? `${identity.connector}:${identity.accountId}` : identity.connector;
|
|
41101
|
+
try {
|
|
41102
|
+
const tools = this.for(identity.connector, userId, {
|
|
41103
|
+
registry: options?.registry,
|
|
41104
|
+
accountId: identity.accountId
|
|
41105
|
+
});
|
|
41106
|
+
if (tools.length > 0) {
|
|
41107
|
+
result.set(key, tools);
|
|
41108
|
+
}
|
|
41109
|
+
} catch (err) {
|
|
41110
|
+
exports.logger.error(`[ConnectorTools.forIdentities] Error generating tools for identity ${key}: ${err instanceof Error ? err.message : String(err)}`);
|
|
41111
|
+
}
|
|
41112
|
+
}
|
|
41113
|
+
return result;
|
|
41114
|
+
}
|
|
41115
|
+
/**
|
|
41116
|
+
* Wrap a tool to inject accountId into ToolContext at execute time.
|
|
41117
|
+
* This allows identity-bound tools to use the correct account without
|
|
41118
|
+
* modifying every service tool factory.
|
|
41119
|
+
*/
|
|
41120
|
+
static bindAccountId(tool, accountId) {
|
|
41121
|
+
return {
|
|
41122
|
+
...tool,
|
|
41123
|
+
execute: async (args, context) => {
|
|
41124
|
+
return tool.execute(args, { ...context, accountId });
|
|
41125
|
+
}
|
|
41126
|
+
};
|
|
41127
|
+
}
|
|
39832
41128
|
static createGenericAPITool(connector, options) {
|
|
39833
41129
|
const toolName = options?.toolName ?? `${sanitizeToolName(connector.name)}_api`;
|
|
39834
41130
|
const userId = options?.userId;
|
|
@@ -39870,6 +41166,7 @@ var ConnectorTools = class {
|
|
|
39870
41166
|
},
|
|
39871
41167
|
execute: async (args, context) => {
|
|
39872
41168
|
const effectiveUserId = context?.userId ?? userId;
|
|
41169
|
+
const effectiveAccountId = context?.accountId;
|
|
39873
41170
|
let url2 = args.endpoint;
|
|
39874
41171
|
if (args.queryParams && Object.keys(args.queryParams).length > 0) {
|
|
39875
41172
|
const params = new URLSearchParams();
|
|
@@ -39902,7 +41199,8 @@ var ConnectorTools = class {
|
|
|
39902
41199
|
},
|
|
39903
41200
|
body: bodyStr
|
|
39904
41201
|
},
|
|
39905
|
-
effectiveUserId
|
|
41202
|
+
effectiveUserId,
|
|
41203
|
+
effectiveAccountId
|
|
39906
41204
|
);
|
|
39907
41205
|
const text = await response.text();
|
|
39908
41206
|
let data;
|
|
@@ -39963,8 +41261,8 @@ var FileStorage = class {
|
|
|
39963
41261
|
}
|
|
39964
41262
|
async ensureDirectory() {
|
|
39965
41263
|
try {
|
|
39966
|
-
await
|
|
39967
|
-
await
|
|
41264
|
+
await fs17__namespace.mkdir(this.directory, { recursive: true });
|
|
41265
|
+
await fs17__namespace.chmod(this.directory, 448);
|
|
39968
41266
|
} catch (error) {
|
|
39969
41267
|
}
|
|
39970
41268
|
}
|
|
@@ -39978,24 +41276,27 @@ var FileStorage = class {
|
|
|
39978
41276
|
async storeToken(key, token) {
|
|
39979
41277
|
await this.ensureDirectory();
|
|
39980
41278
|
const filePath = this.getFilePath(key);
|
|
39981
|
-
const
|
|
41279
|
+
const tokenWithKey = { ...token, _storageKey: key };
|
|
41280
|
+
const plaintext = JSON.stringify(tokenWithKey);
|
|
39982
41281
|
const encrypted = encrypt(plaintext, this.encryptionKey);
|
|
39983
|
-
await
|
|
39984
|
-
await
|
|
41282
|
+
await fs17__namespace.writeFile(filePath, encrypted, "utf8");
|
|
41283
|
+
await fs17__namespace.chmod(filePath, 384);
|
|
39985
41284
|
}
|
|
39986
41285
|
async getToken(key) {
|
|
39987
41286
|
const filePath = this.getFilePath(key);
|
|
39988
41287
|
try {
|
|
39989
|
-
const encrypted = await
|
|
41288
|
+
const encrypted = await fs17__namespace.readFile(filePath, "utf8");
|
|
39990
41289
|
const decrypted = decrypt(encrypted, this.encryptionKey);
|
|
39991
|
-
|
|
41290
|
+
const parsed = JSON.parse(decrypted);
|
|
41291
|
+
const { _storageKey, ...token } = parsed;
|
|
41292
|
+
return token;
|
|
39992
41293
|
} catch (error) {
|
|
39993
41294
|
if (error.code === "ENOENT") {
|
|
39994
41295
|
return null;
|
|
39995
41296
|
}
|
|
39996
41297
|
console.error("Failed to read/decrypt token file:", error);
|
|
39997
41298
|
try {
|
|
39998
|
-
await
|
|
41299
|
+
await fs17__namespace.unlink(filePath);
|
|
39999
41300
|
} catch {
|
|
40000
41301
|
}
|
|
40001
41302
|
return null;
|
|
@@ -40004,7 +41305,7 @@ var FileStorage = class {
|
|
|
40004
41305
|
async deleteToken(key) {
|
|
40005
41306
|
const filePath = this.getFilePath(key);
|
|
40006
41307
|
try {
|
|
40007
|
-
await
|
|
41308
|
+
await fs17__namespace.unlink(filePath);
|
|
40008
41309
|
} catch (error) {
|
|
40009
41310
|
if (error.code !== "ENOENT") {
|
|
40010
41311
|
throw error;
|
|
@@ -40014,18 +41315,44 @@ var FileStorage = class {
|
|
|
40014
41315
|
async hasToken(key) {
|
|
40015
41316
|
const filePath = this.getFilePath(key);
|
|
40016
41317
|
try {
|
|
40017
|
-
await
|
|
41318
|
+
await fs17__namespace.access(filePath);
|
|
40018
41319
|
return true;
|
|
40019
41320
|
} catch {
|
|
40020
41321
|
return false;
|
|
40021
41322
|
}
|
|
40022
41323
|
}
|
|
41324
|
+
/**
|
|
41325
|
+
* List all storage keys by decrypting each token file and reading _storageKey.
|
|
41326
|
+
* Falls back to returning hashed filenames for tokens stored before multi-account support.
|
|
41327
|
+
*/
|
|
41328
|
+
async listKeys() {
|
|
41329
|
+
try {
|
|
41330
|
+
const files = await fs17__namespace.readdir(this.directory);
|
|
41331
|
+
const tokenFiles = files.filter((f) => f.endsWith(".token"));
|
|
41332
|
+
const keys = [];
|
|
41333
|
+
for (const file of tokenFiles) {
|
|
41334
|
+
try {
|
|
41335
|
+
const filePath = path2__namespace.join(this.directory, file);
|
|
41336
|
+
const encrypted = await fs17__namespace.readFile(filePath, "utf8");
|
|
41337
|
+
const decrypted = decrypt(encrypted, this.encryptionKey);
|
|
41338
|
+
const parsed = JSON.parse(decrypted);
|
|
41339
|
+
if (parsed._storageKey) {
|
|
41340
|
+
keys.push(parsed._storageKey);
|
|
41341
|
+
}
|
|
41342
|
+
} catch {
|
|
41343
|
+
}
|
|
41344
|
+
}
|
|
41345
|
+
return keys;
|
|
41346
|
+
} catch {
|
|
41347
|
+
return [];
|
|
41348
|
+
}
|
|
41349
|
+
}
|
|
40023
41350
|
/**
|
|
40024
41351
|
* List all token keys (for debugging)
|
|
40025
41352
|
*/
|
|
40026
41353
|
async listTokens() {
|
|
40027
41354
|
try {
|
|
40028
|
-
const files = await
|
|
41355
|
+
const files = await fs17__namespace.readdir(this.directory);
|
|
40029
41356
|
return files.filter((f) => f.endsWith(".token")).map((f) => f.replace(".token", ""));
|
|
40030
41357
|
} catch {
|
|
40031
41358
|
return [];
|
|
@@ -40036,10 +41363,10 @@ var FileStorage = class {
|
|
|
40036
41363
|
*/
|
|
40037
41364
|
async clearAll() {
|
|
40038
41365
|
try {
|
|
40039
|
-
const files = await
|
|
41366
|
+
const files = await fs17__namespace.readdir(this.directory);
|
|
40040
41367
|
const tokenFiles = files.filter((f) => f.endsWith(".token"));
|
|
40041
41368
|
await Promise.all(
|
|
40042
|
-
tokenFiles.map((f) =>
|
|
41369
|
+
tokenFiles.map((f) => fs17__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
|
|
40043
41370
|
}))
|
|
40044
41371
|
);
|
|
40045
41372
|
} catch {
|
|
@@ -40049,14 +41376,14 @@ var FileStorage = class {
|
|
|
40049
41376
|
|
|
40050
41377
|
// src/connectors/authenticatedFetch.ts
|
|
40051
41378
|
init_Connector();
|
|
40052
|
-
async function authenticatedFetch(url2, options, authProvider, userId) {
|
|
41379
|
+
async function authenticatedFetch(url2, options, authProvider, userId, accountId) {
|
|
40053
41380
|
const connector = exports.Connector.get(authProvider);
|
|
40054
|
-
return connector.fetch(url2.toString(), options, userId);
|
|
41381
|
+
return connector.fetch(url2.toString(), options, userId, accountId);
|
|
40055
41382
|
}
|
|
40056
|
-
function createAuthenticatedFetch(authProvider, userId) {
|
|
41383
|
+
function createAuthenticatedFetch(authProvider, userId, accountId) {
|
|
40057
41384
|
const connector = exports.Connector.get(authProvider);
|
|
40058
41385
|
return async (url2, options) => {
|
|
40059
|
-
return connector.fetch(url2.toString(), options, userId);
|
|
41386
|
+
return connector.fetch(url2.toString(), options, userId, accountId);
|
|
40060
41387
|
};
|
|
40061
41388
|
}
|
|
40062
41389
|
|
|
@@ -40487,14 +41814,14 @@ var FileConnectorStorage = class {
|
|
|
40487
41814
|
await this.ensureDirectory();
|
|
40488
41815
|
const filePath = this.getFilePath(name);
|
|
40489
41816
|
const json = JSON.stringify(stored, null, 2);
|
|
40490
|
-
await
|
|
40491
|
-
await
|
|
41817
|
+
await fs17__namespace.writeFile(filePath, json, "utf8");
|
|
41818
|
+
await fs17__namespace.chmod(filePath, 384);
|
|
40492
41819
|
await this.updateIndex(name, "add");
|
|
40493
41820
|
}
|
|
40494
41821
|
async get(name) {
|
|
40495
41822
|
const filePath = this.getFilePath(name);
|
|
40496
41823
|
try {
|
|
40497
|
-
const json = await
|
|
41824
|
+
const json = await fs17__namespace.readFile(filePath, "utf8");
|
|
40498
41825
|
return JSON.parse(json);
|
|
40499
41826
|
} catch (error) {
|
|
40500
41827
|
const err = error;
|
|
@@ -40507,7 +41834,7 @@ var FileConnectorStorage = class {
|
|
|
40507
41834
|
async delete(name) {
|
|
40508
41835
|
const filePath = this.getFilePath(name);
|
|
40509
41836
|
try {
|
|
40510
|
-
await
|
|
41837
|
+
await fs17__namespace.unlink(filePath);
|
|
40511
41838
|
await this.updateIndex(name, "remove");
|
|
40512
41839
|
return true;
|
|
40513
41840
|
} catch (error) {
|
|
@@ -40521,7 +41848,7 @@ var FileConnectorStorage = class {
|
|
|
40521
41848
|
async has(name) {
|
|
40522
41849
|
const filePath = this.getFilePath(name);
|
|
40523
41850
|
try {
|
|
40524
|
-
await
|
|
41851
|
+
await fs17__namespace.access(filePath);
|
|
40525
41852
|
return true;
|
|
40526
41853
|
} catch {
|
|
40527
41854
|
return false;
|
|
@@ -40547,13 +41874,13 @@ var FileConnectorStorage = class {
|
|
|
40547
41874
|
*/
|
|
40548
41875
|
async clear() {
|
|
40549
41876
|
try {
|
|
40550
|
-
const files = await
|
|
41877
|
+
const files = await fs17__namespace.readdir(this.directory);
|
|
40551
41878
|
const connectorFiles = files.filter(
|
|
40552
41879
|
(f) => f.endsWith(".connector.json") || f === "_index.json"
|
|
40553
41880
|
);
|
|
40554
41881
|
await Promise.all(
|
|
40555
41882
|
connectorFiles.map(
|
|
40556
|
-
(f) =>
|
|
41883
|
+
(f) => fs17__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
|
|
40557
41884
|
})
|
|
40558
41885
|
)
|
|
40559
41886
|
);
|
|
@@ -40580,8 +41907,8 @@ var FileConnectorStorage = class {
|
|
|
40580
41907
|
async ensureDirectory() {
|
|
40581
41908
|
if (this.initialized) return;
|
|
40582
41909
|
try {
|
|
40583
|
-
await
|
|
40584
|
-
await
|
|
41910
|
+
await fs17__namespace.mkdir(this.directory, { recursive: true });
|
|
41911
|
+
await fs17__namespace.chmod(this.directory, 448);
|
|
40585
41912
|
this.initialized = true;
|
|
40586
41913
|
} catch {
|
|
40587
41914
|
this.initialized = true;
|
|
@@ -40592,7 +41919,7 @@ var FileConnectorStorage = class {
|
|
|
40592
41919
|
*/
|
|
40593
41920
|
async loadIndex() {
|
|
40594
41921
|
try {
|
|
40595
|
-
const json = await
|
|
41922
|
+
const json = await fs17__namespace.readFile(this.indexPath, "utf8");
|
|
40596
41923
|
return JSON.parse(json);
|
|
40597
41924
|
} catch {
|
|
40598
41925
|
return { connectors: {} };
|
|
@@ -40610,8 +41937,8 @@ var FileConnectorStorage = class {
|
|
|
40610
41937
|
delete index.connectors[hash];
|
|
40611
41938
|
}
|
|
40612
41939
|
const json = JSON.stringify(index, null, 2);
|
|
40613
|
-
await
|
|
40614
|
-
await
|
|
41940
|
+
await fs17__namespace.writeFile(this.indexPath, json, "utf8");
|
|
41941
|
+
await fs17__namespace.chmod(this.indexPath, 384);
|
|
40615
41942
|
}
|
|
40616
41943
|
};
|
|
40617
41944
|
|
|
@@ -40834,14 +42161,15 @@ var microsoftTemplate = {
|
|
|
40834
42161
|
name: "OAuth (Delegated Permissions)",
|
|
40835
42162
|
type: "oauth",
|
|
40836
42163
|
flow: "authorization_code",
|
|
40837
|
-
description: "User signs in with Microsoft account. Best for accessing user data (mail, calendar, files)",
|
|
40838
|
-
requiredFields: ["clientId", "
|
|
40839
|
-
optionalFields: ["scope"],
|
|
42164
|
+
description: "User signs in with Microsoft account. Best for accessing user data (mail, calendar, files). Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
42165
|
+
requiredFields: ["clientId", "redirectUri", "tenantId"],
|
|
42166
|
+
optionalFields: ["clientSecret", "scope"],
|
|
40840
42167
|
defaults: {
|
|
40841
42168
|
type: "oauth",
|
|
40842
42169
|
flow: "authorization_code",
|
|
40843
42170
|
authorizationUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize",
|
|
40844
|
-
tokenUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token"
|
|
42171
|
+
tokenUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token",
|
|
42172
|
+
usePKCE: true
|
|
40845
42173
|
},
|
|
40846
42174
|
scopes: [
|
|
40847
42175
|
"User.Read",
|
|
@@ -40927,14 +42255,15 @@ var googleTemplate = {
|
|
|
40927
42255
|
name: "OAuth (User Consent)",
|
|
40928
42256
|
type: "oauth",
|
|
40929
42257
|
flow: "authorization_code",
|
|
40930
|
-
description: "User logs in with Google account. Best for accessing user data (Drive, Gmail, Calendar)",
|
|
40931
|
-
requiredFields: ["clientId", "
|
|
40932
|
-
optionalFields: ["scope"],
|
|
42258
|
+
description: "User logs in with Google account. Best for accessing user data (Drive, Gmail, Calendar). Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
42259
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
42260
|
+
optionalFields: ["clientSecret", "scope"],
|
|
40933
42261
|
defaults: {
|
|
40934
42262
|
type: "oauth",
|
|
40935
42263
|
flow: "authorization_code",
|
|
40936
42264
|
authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
40937
|
-
tokenUrl: "https://oauth2.googleapis.com/token"
|
|
42265
|
+
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
42266
|
+
usePKCE: true
|
|
40938
42267
|
},
|
|
40939
42268
|
scopes: [
|
|
40940
42269
|
"https://www.googleapis.com/auth/drive",
|
|
@@ -41013,14 +42342,15 @@ var slackTemplate = {
|
|
|
41013
42342
|
name: "OAuth (User Token)",
|
|
41014
42343
|
type: "oauth",
|
|
41015
42344
|
flow: "authorization_code",
|
|
41016
|
-
description: "Distributed app - users authorize via Slack OAuth",
|
|
41017
|
-
requiredFields: ["clientId", "
|
|
41018
|
-
optionalFields: ["scope", "userScope"],
|
|
42345
|
+
description: "Distributed app - users authorize via Slack OAuth. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
42346
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
42347
|
+
optionalFields: ["clientSecret", "scope", "userScope"],
|
|
41019
42348
|
defaults: {
|
|
41020
42349
|
type: "oauth",
|
|
41021
42350
|
flow: "authorization_code",
|
|
41022
42351
|
authorizationUrl: "https://slack.com/oauth/v2/authorize",
|
|
41023
|
-
tokenUrl: "https://slack.com/api/oauth.v2.access"
|
|
42352
|
+
tokenUrl: "https://slack.com/api/oauth.v2.access",
|
|
42353
|
+
usePKCE: true
|
|
41024
42354
|
},
|
|
41025
42355
|
scopes: ["chat:write", "channels:read", "users:read", "im:write", "groups:read", "files:read", "files:write", "reactions:read", "reactions:write", "team:read"],
|
|
41026
42356
|
scopeDescriptions: {
|
|
@@ -41066,14 +42396,15 @@ var discordTemplate = {
|
|
|
41066
42396
|
name: "OAuth (User Token)",
|
|
41067
42397
|
type: "oauth",
|
|
41068
42398
|
flow: "authorization_code",
|
|
41069
|
-
description: "OAuth2 for user authorization - users grant permissions to your app",
|
|
41070
|
-
requiredFields: ["clientId", "
|
|
41071
|
-
optionalFields: ["scope"],
|
|
42399
|
+
description: "OAuth2 for user authorization - users grant permissions to your app. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
42400
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
42401
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41072
42402
|
defaults: {
|
|
41073
42403
|
type: "oauth",
|
|
41074
42404
|
flow: "authorization_code",
|
|
41075
42405
|
authorizationUrl: "https://discord.com/api/oauth2/authorize",
|
|
41076
|
-
tokenUrl: "https://discord.com/api/oauth2/token"
|
|
42406
|
+
tokenUrl: "https://discord.com/api/oauth2/token",
|
|
42407
|
+
usePKCE: true
|
|
41077
42408
|
},
|
|
41078
42409
|
scopes: ["identify", "email", "guilds", "guilds.members.read", "messages.read", "bot", "connections"],
|
|
41079
42410
|
scopeDescriptions: {
|
|
@@ -41115,6 +42446,92 @@ var telegramTemplate = {
|
|
|
41115
42446
|
]
|
|
41116
42447
|
};
|
|
41117
42448
|
|
|
42449
|
+
// src/connectors/vendors/templates/twitter.ts
|
|
42450
|
+
var twitterTemplate = {
|
|
42451
|
+
id: "twitter",
|
|
42452
|
+
name: "X (Twitter)",
|
|
42453
|
+
serviceType: "twitter",
|
|
42454
|
+
baseURL: "https://api.x.com/2",
|
|
42455
|
+
docsURL: "https://developer.x.com/en/docs/x-api",
|
|
42456
|
+
credentialsSetupURL: "https://developer.x.com/en/portal/dashboard",
|
|
42457
|
+
category: "communication",
|
|
42458
|
+
notes: "X (formerly Twitter) API v2. OAuth 2.0 with PKCE for user-context actions, Bearer Token for app-only access.",
|
|
42459
|
+
authTemplates: [
|
|
42460
|
+
{
|
|
42461
|
+
id: "oauth-user",
|
|
42462
|
+
name: "OAuth 2.0 (User Context)",
|
|
42463
|
+
type: "oauth",
|
|
42464
|
+
flow: "authorization_code",
|
|
42465
|
+
description: "User authorizes via X login - required for posting tweets, managing likes/follows, and accessing private data. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
42466
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
42467
|
+
optionalFields: ["clientSecret", "scope"],
|
|
42468
|
+
defaults: {
|
|
42469
|
+
type: "oauth",
|
|
42470
|
+
flow: "authorization_code",
|
|
42471
|
+
authorizationUrl: "https://x.com/i/oauth2/authorize",
|
|
42472
|
+
tokenUrl: "https://api.x.com/2/oauth2/token",
|
|
42473
|
+
usePKCE: true
|
|
42474
|
+
},
|
|
42475
|
+
scopes: [
|
|
42476
|
+
"tweet.read",
|
|
42477
|
+
"tweet.write",
|
|
42478
|
+
"tweet.moderate.write",
|
|
42479
|
+
"users.read",
|
|
42480
|
+
"follows.read",
|
|
42481
|
+
"follows.write",
|
|
42482
|
+
"like.read",
|
|
42483
|
+
"like.write",
|
|
42484
|
+
"bookmark.read",
|
|
42485
|
+
"bookmark.write",
|
|
42486
|
+
"list.read",
|
|
42487
|
+
"list.write",
|
|
42488
|
+
"block.read",
|
|
42489
|
+
"block.write",
|
|
42490
|
+
"mute.read",
|
|
42491
|
+
"mute.write",
|
|
42492
|
+
"space.read",
|
|
42493
|
+
"dm.read",
|
|
42494
|
+
"dm.write",
|
|
42495
|
+
"offline.access"
|
|
42496
|
+
],
|
|
42497
|
+
scopeDescriptions: {
|
|
42498
|
+
"tweet.read": "Read tweets and timelines",
|
|
42499
|
+
"tweet.write": "Post and delete tweets",
|
|
42500
|
+
"tweet.moderate.write": "Hide and unhide replies",
|
|
42501
|
+
"users.read": "Read user profile information",
|
|
42502
|
+
"follows.read": "Read following/followers lists",
|
|
42503
|
+
"follows.write": "Follow and unfollow users",
|
|
42504
|
+
"like.read": "Read liked tweets",
|
|
42505
|
+
"like.write": "Like and unlike tweets",
|
|
42506
|
+
"bookmark.read": "Read bookmarked tweets",
|
|
42507
|
+
"bookmark.write": "Bookmark and remove bookmarks",
|
|
42508
|
+
"list.read": "Read lists",
|
|
42509
|
+
"list.write": "Create, edit, and delete lists",
|
|
42510
|
+
"block.read": "Read blocked users",
|
|
42511
|
+
"block.write": "Block and unblock users",
|
|
42512
|
+
"mute.read": "Read muted users",
|
|
42513
|
+
"mute.write": "Mute and unmute users",
|
|
42514
|
+
"space.read": "Read Spaces information",
|
|
42515
|
+
"dm.read": "Read direct messages",
|
|
42516
|
+
"dm.write": "Send direct messages",
|
|
42517
|
+
"offline.access": "Stay connected (refresh token)"
|
|
42518
|
+
}
|
|
42519
|
+
},
|
|
42520
|
+
{
|
|
42521
|
+
id: "bearer-token",
|
|
42522
|
+
name: "Bearer Token (App-Only)",
|
|
42523
|
+
type: "api_key",
|
|
42524
|
+
description: "App-only access using Bearer Token from developer portal. Can read public tweets, users, and spaces but cannot post or access private data.",
|
|
42525
|
+
requiredFields: ["apiKey"],
|
|
42526
|
+
defaults: {
|
|
42527
|
+
type: "api_key",
|
|
42528
|
+
headerName: "Authorization",
|
|
42529
|
+
headerPrefix: "Bearer"
|
|
42530
|
+
}
|
|
42531
|
+
}
|
|
42532
|
+
]
|
|
42533
|
+
};
|
|
42534
|
+
|
|
41118
42535
|
// src/connectors/vendors/templates/github.ts
|
|
41119
42536
|
var githubTemplate = {
|
|
41120
42537
|
id: "github",
|
|
@@ -41142,14 +42559,15 @@ var githubTemplate = {
|
|
|
41142
42559
|
name: "OAuth App (User Authorization)",
|
|
41143
42560
|
type: "oauth",
|
|
41144
42561
|
flow: "authorization_code",
|
|
41145
|
-
description: "User logs in via GitHub and grants permissions to your app",
|
|
41146
|
-
requiredFields: ["clientId", "
|
|
41147
|
-
optionalFields: ["scope"],
|
|
42562
|
+
description: "User logs in via GitHub and grants permissions to your app. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
42563
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
42564
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41148
42565
|
defaults: {
|
|
41149
42566
|
type: "oauth",
|
|
41150
42567
|
flow: "authorization_code",
|
|
41151
42568
|
authorizationUrl: "https://github.com/login/oauth/authorize",
|
|
41152
|
-
tokenUrl: "https://github.com/login/oauth/access_token"
|
|
42569
|
+
tokenUrl: "https://github.com/login/oauth/access_token",
|
|
42570
|
+
usePKCE: true
|
|
41153
42571
|
},
|
|
41154
42572
|
scopes: ["repo", "read:user", "user:email", "read:org", "workflow", "gist", "notifications", "delete_repo", "admin:org"],
|
|
41155
42573
|
scopeDescriptions: {
|
|
@@ -41208,14 +42626,15 @@ var gitlabTemplate = {
|
|
|
41208
42626
|
name: "OAuth (User Authorization)",
|
|
41209
42627
|
type: "oauth",
|
|
41210
42628
|
flow: "authorization_code",
|
|
41211
|
-
description: "OAuth2 application for user authorization",
|
|
41212
|
-
requiredFields: ["clientId", "
|
|
41213
|
-
optionalFields: ["scope"],
|
|
42629
|
+
description: "OAuth2 application for user authorization. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
42630
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
42631
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41214
42632
|
defaults: {
|
|
41215
42633
|
type: "oauth",
|
|
41216
42634
|
flow: "authorization_code",
|
|
41217
42635
|
authorizationUrl: "https://gitlab.com/oauth/authorize",
|
|
41218
|
-
tokenUrl: "https://gitlab.com/oauth/token"
|
|
42636
|
+
tokenUrl: "https://gitlab.com/oauth/token",
|
|
42637
|
+
usePKCE: true
|
|
41219
42638
|
},
|
|
41220
42639
|
scopes: ["api", "read_user", "read_repository", "write_repository"],
|
|
41221
42640
|
scopeDescriptions: {
|
|
@@ -41256,14 +42675,15 @@ var jiraTemplate = {
|
|
|
41256
42675
|
name: "OAuth 2.0 (3LO)",
|
|
41257
42676
|
type: "oauth",
|
|
41258
42677
|
flow: "authorization_code",
|
|
41259
|
-
description: "Three-legged OAuth for user authorization. Create app at developer.atlassian.com",
|
|
41260
|
-
requiredFields: ["clientId", "
|
|
41261
|
-
optionalFields: ["scope"],
|
|
42678
|
+
description: "Three-legged OAuth for user authorization. Create app at developer.atlassian.com. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
42679
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
42680
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41262
42681
|
defaults: {
|
|
41263
42682
|
type: "oauth",
|
|
41264
42683
|
flow: "authorization_code",
|
|
41265
42684
|
authorizationUrl: "https://auth.atlassian.com/authorize",
|
|
41266
|
-
tokenUrl: "https://auth.atlassian.com/oauth/token"
|
|
42685
|
+
tokenUrl: "https://auth.atlassian.com/oauth/token",
|
|
42686
|
+
usePKCE: true
|
|
41267
42687
|
},
|
|
41268
42688
|
scopes: ["read:jira-work", "write:jira-work", "read:jira-user", "manage:jira-project", "manage:jira-configuration"],
|
|
41269
42689
|
scopeDescriptions: {
|
|
@@ -41303,14 +42723,15 @@ var confluenceTemplate = {
|
|
|
41303
42723
|
name: "OAuth 2.0 (3LO)",
|
|
41304
42724
|
type: "oauth",
|
|
41305
42725
|
flow: "authorization_code",
|
|
41306
|
-
description: "Three-legged OAuth for user authorization",
|
|
41307
|
-
requiredFields: ["clientId", "
|
|
41308
|
-
optionalFields: ["scope"],
|
|
42726
|
+
description: "Three-legged OAuth for user authorization. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
42727
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
42728
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41309
42729
|
defaults: {
|
|
41310
42730
|
type: "oauth",
|
|
41311
42731
|
flow: "authorization_code",
|
|
41312
42732
|
authorizationUrl: "https://auth.atlassian.com/authorize",
|
|
41313
|
-
tokenUrl: "https://auth.atlassian.com/oauth/token"
|
|
42733
|
+
tokenUrl: "https://auth.atlassian.com/oauth/token",
|
|
42734
|
+
usePKCE: true
|
|
41314
42735
|
},
|
|
41315
42736
|
scopes: ["read:confluence-content.all", "write:confluence-content", "read:confluence-space.summary", "write:confluence-space", "read:confluence-user"],
|
|
41316
42737
|
scopeDescriptions: {
|
|
@@ -41349,14 +42770,15 @@ var bitbucketTemplate = {
|
|
|
41349
42770
|
name: "OAuth Consumer",
|
|
41350
42771
|
type: "oauth",
|
|
41351
42772
|
flow: "authorization_code",
|
|
41352
|
-
description: "OAuth consumer for user authorization. Create at Workspace Settings > OAuth consumers",
|
|
41353
|
-
requiredFields: ["clientId", "
|
|
41354
|
-
optionalFields: ["scope"],
|
|
42773
|
+
description: "OAuth consumer for user authorization. Create at Workspace Settings > OAuth consumers. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
42774
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
42775
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41355
42776
|
defaults: {
|
|
41356
42777
|
type: "oauth",
|
|
41357
42778
|
flow: "authorization_code",
|
|
41358
42779
|
authorizationUrl: "https://bitbucket.org/site/oauth2/authorize",
|
|
41359
|
-
tokenUrl: "https://bitbucket.org/site/oauth2/access_token"
|
|
42780
|
+
tokenUrl: "https://bitbucket.org/site/oauth2/access_token",
|
|
42781
|
+
usePKCE: true
|
|
41360
42782
|
},
|
|
41361
42783
|
scopes: ["repository", "repository:write", "pullrequest", "pullrequest:write", "account", "pipeline", "wiki"],
|
|
41362
42784
|
scopeDescriptions: {
|
|
@@ -41398,14 +42820,15 @@ var trelloTemplate = {
|
|
|
41398
42820
|
name: "OAuth 1.0a",
|
|
41399
42821
|
type: "oauth",
|
|
41400
42822
|
flow: "authorization_code",
|
|
41401
|
-
description: "OAuth 1.0a for user authorization (legacy)",
|
|
41402
|
-
requiredFields: ["clientId", "
|
|
41403
|
-
optionalFields: ["scope"],
|
|
42823
|
+
description: "OAuth 1.0a for user authorization (legacy). Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
42824
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
42825
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41404
42826
|
defaults: {
|
|
41405
42827
|
type: "oauth",
|
|
41406
42828
|
flow: "authorization_code",
|
|
41407
42829
|
authorizationUrl: "https://trello.com/1/authorize",
|
|
41408
|
-
tokenUrl: "https://trello.com/1/OAuthGetAccessToken"
|
|
42830
|
+
tokenUrl: "https://trello.com/1/OAuthGetAccessToken",
|
|
42831
|
+
usePKCE: true
|
|
41409
42832
|
},
|
|
41410
42833
|
scopes: ["read", "write", "account"],
|
|
41411
42834
|
scopeDescriptions: {
|
|
@@ -41445,14 +42868,15 @@ var linearTemplate = {
|
|
|
41445
42868
|
name: "OAuth (User Authorization)",
|
|
41446
42869
|
type: "oauth",
|
|
41447
42870
|
flow: "authorization_code",
|
|
41448
|
-
description: "OAuth application for user authorization. Create at Settings > API > OAuth applications",
|
|
41449
|
-
requiredFields: ["clientId", "
|
|
41450
|
-
optionalFields: ["scope"],
|
|
42871
|
+
description: "OAuth application for user authorization. Create at Settings > API > OAuth applications. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
42872
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
42873
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41451
42874
|
defaults: {
|
|
41452
42875
|
type: "oauth",
|
|
41453
42876
|
flow: "authorization_code",
|
|
41454
42877
|
authorizationUrl: "https://linear.app/oauth/authorize",
|
|
41455
|
-
tokenUrl: "https://api.linear.app/oauth/token"
|
|
42878
|
+
tokenUrl: "https://api.linear.app/oauth/token",
|
|
42879
|
+
usePKCE: true
|
|
41456
42880
|
},
|
|
41457
42881
|
scopes: ["read", "write", "issues:create", "comments:create"]
|
|
41458
42882
|
}
|
|
@@ -41486,14 +42910,15 @@ var asanaTemplate = {
|
|
|
41486
42910
|
name: "OAuth (User Authorization)",
|
|
41487
42911
|
type: "oauth",
|
|
41488
42912
|
flow: "authorization_code",
|
|
41489
|
-
description: "OAuth application for user authorization. Create at developer console",
|
|
41490
|
-
requiredFields: ["clientId", "
|
|
41491
|
-
optionalFields: ["scope"],
|
|
42913
|
+
description: "OAuth application for user authorization. Create at developer console. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
42914
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
42915
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41492
42916
|
defaults: {
|
|
41493
42917
|
type: "oauth",
|
|
41494
42918
|
flow: "authorization_code",
|
|
41495
42919
|
authorizationUrl: "https://app.asana.com/-/oauth_authorize",
|
|
41496
|
-
tokenUrl: "https://app.asana.com/-/oauth_token"
|
|
42920
|
+
tokenUrl: "https://app.asana.com/-/oauth_token",
|
|
42921
|
+
usePKCE: true
|
|
41497
42922
|
},
|
|
41498
42923
|
scopes: ["default"]
|
|
41499
42924
|
}
|
|
@@ -41527,14 +42952,15 @@ var notionTemplate = {
|
|
|
41527
42952
|
name: "Public Integration (OAuth)",
|
|
41528
42953
|
type: "oauth",
|
|
41529
42954
|
flow: "authorization_code",
|
|
41530
|
-
description: "Public integration for multi-workspace access",
|
|
41531
|
-
requiredFields: ["clientId", "
|
|
41532
|
-
optionalFields: ["scope"],
|
|
42955
|
+
description: "Public integration for multi-workspace access. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
42956
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
42957
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41533
42958
|
defaults: {
|
|
41534
42959
|
type: "oauth",
|
|
41535
42960
|
flow: "authorization_code",
|
|
41536
42961
|
authorizationUrl: "https://api.notion.com/v1/oauth/authorize",
|
|
41537
|
-
tokenUrl: "https://api.notion.com/v1/oauth/token"
|
|
42962
|
+
tokenUrl: "https://api.notion.com/v1/oauth/token",
|
|
42963
|
+
usePKCE: true
|
|
41538
42964
|
}
|
|
41539
42965
|
}
|
|
41540
42966
|
]
|
|
@@ -41567,9 +42993,9 @@ var airtableTemplate = {
|
|
|
41567
42993
|
name: "OAuth (User Authorization)",
|
|
41568
42994
|
type: "oauth",
|
|
41569
42995
|
flow: "authorization_code",
|
|
41570
|
-
description: "OAuth integration for multi-user access. Register at airtable.com/create/oauth",
|
|
41571
|
-
requiredFields: ["clientId", "
|
|
41572
|
-
optionalFields: ["scope"],
|
|
42996
|
+
description: "OAuth integration for multi-user access. Register at airtable.com/create/oauth. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
42997
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
42998
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41573
42999
|
defaults: {
|
|
41574
43000
|
type: "oauth",
|
|
41575
43001
|
flow: "authorization_code",
|
|
@@ -41598,14 +43024,15 @@ var salesforceTemplate = {
|
|
|
41598
43024
|
name: "OAuth (User Authorization)",
|
|
41599
43025
|
type: "oauth",
|
|
41600
43026
|
flow: "authorization_code",
|
|
41601
|
-
description: "User logs in via Salesforce. Create Connected App in Setup",
|
|
41602
|
-
requiredFields: ["clientId", "
|
|
41603
|
-
optionalFields: ["scope"],
|
|
43027
|
+
description: "User logs in via Salesforce. Create Connected App in Setup. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
43028
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
43029
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41604
43030
|
defaults: {
|
|
41605
43031
|
type: "oauth",
|
|
41606
43032
|
flow: "authorization_code",
|
|
41607
43033
|
authorizationUrl: "https://login.salesforce.com/services/oauth2/authorize",
|
|
41608
|
-
tokenUrl: "https://login.salesforce.com/services/oauth2/token"
|
|
43034
|
+
tokenUrl: "https://login.salesforce.com/services/oauth2/token",
|
|
43035
|
+
usePKCE: true
|
|
41609
43036
|
},
|
|
41610
43037
|
scopes: ["api", "refresh_token", "offline_access", "chatter_api", "wave_api", "full"],
|
|
41611
43038
|
scopeDescriptions: {
|
|
@@ -41661,14 +43088,15 @@ var hubspotTemplate = {
|
|
|
41661
43088
|
name: "OAuth (User Authorization)",
|
|
41662
43089
|
type: "oauth",
|
|
41663
43090
|
flow: "authorization_code",
|
|
41664
|
-
description: "Public app OAuth for multi-portal access. Create app at developers.hubspot.com",
|
|
41665
|
-
requiredFields: ["clientId", "
|
|
41666
|
-
optionalFields: ["scope"],
|
|
43091
|
+
description: "Public app OAuth for multi-portal access. Create app at developers.hubspot.com. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
43092
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
43093
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41667
43094
|
defaults: {
|
|
41668
43095
|
type: "oauth",
|
|
41669
43096
|
flow: "authorization_code",
|
|
41670
43097
|
authorizationUrl: "https://app.hubspot.com/oauth/authorize",
|
|
41671
|
-
tokenUrl: "https://api.hubapi.com/oauth/v1/token"
|
|
43098
|
+
tokenUrl: "https://api.hubapi.com/oauth/v1/token",
|
|
43099
|
+
usePKCE: true
|
|
41672
43100
|
},
|
|
41673
43101
|
scopes: [
|
|
41674
43102
|
"crm.objects.contacts.read",
|
|
@@ -41690,6 +43118,22 @@ var hubspotTemplate = {
|
|
|
41690
43118
|
"tickets": "Read and write support tickets",
|
|
41691
43119
|
"e-commerce": "Access e-commerce data (products, line items)"
|
|
41692
43120
|
}
|
|
43121
|
+
},
|
|
43122
|
+
{
|
|
43123
|
+
id: "oauth-mcp",
|
|
43124
|
+
name: "MCP Auth App (OAuth 2.1)",
|
|
43125
|
+
type: "oauth",
|
|
43126
|
+
flow: "authorization_code",
|
|
43127
|
+
description: "HubSpot MCP Auth app using OAuth 2.1 with PKCE. Scopes are auto-granted based on user permissions at install time. Create app at developers.hubspot.com under MCP Auth Apps.",
|
|
43128
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
43129
|
+
optionalFields: ["clientSecret"],
|
|
43130
|
+
defaults: {
|
|
43131
|
+
type: "oauth",
|
|
43132
|
+
flow: "authorization_code",
|
|
43133
|
+
authorizationUrl: "https://mcp.hubspot.com/oauth/authorize/user",
|
|
43134
|
+
tokenUrl: "https://mcp.hubspot.com/oauth/v1/token",
|
|
43135
|
+
usePKCE: true
|
|
43136
|
+
}
|
|
41693
43137
|
}
|
|
41694
43138
|
]
|
|
41695
43139
|
};
|
|
@@ -41721,14 +43165,15 @@ var pipedriveTemplate = {
|
|
|
41721
43165
|
name: "OAuth (App Authorization)",
|
|
41722
43166
|
type: "oauth",
|
|
41723
43167
|
flow: "authorization_code",
|
|
41724
|
-
description: "OAuth app for marketplace distribution. Create at developers.pipedrive.com",
|
|
41725
|
-
requiredFields: ["clientId", "
|
|
41726
|
-
optionalFields: ["scope"],
|
|
43168
|
+
description: "OAuth app for marketplace distribution. Create at developers.pipedrive.com. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
43169
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
43170
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41727
43171
|
defaults: {
|
|
41728
43172
|
type: "oauth",
|
|
41729
43173
|
flow: "authorization_code",
|
|
41730
43174
|
authorizationUrl: "https://oauth.pipedrive.com/oauth/authorize",
|
|
41731
|
-
tokenUrl: "https://oauth.pipedrive.com/oauth/token"
|
|
43175
|
+
tokenUrl: "https://oauth.pipedrive.com/oauth/token",
|
|
43176
|
+
usePKCE: true
|
|
41732
43177
|
}
|
|
41733
43178
|
}
|
|
41734
43179
|
]
|
|
@@ -41761,14 +43206,15 @@ var stripeTemplate = {
|
|
|
41761
43206
|
name: "OAuth (Stripe Connect)",
|
|
41762
43207
|
type: "oauth",
|
|
41763
43208
|
flow: "authorization_code",
|
|
41764
|
-
description: "Stripe Connect for marketplace platforms. Requires Connect setup in dashboard",
|
|
41765
|
-
requiredFields: ["clientId", "
|
|
41766
|
-
optionalFields: ["scope"],
|
|
43209
|
+
description: "Stripe Connect for marketplace platforms. Requires Connect setup in dashboard. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
43210
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
43211
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41767
43212
|
defaults: {
|
|
41768
43213
|
type: "oauth",
|
|
41769
43214
|
flow: "authorization_code",
|
|
41770
43215
|
authorizationUrl: "https://connect.stripe.com/oauth/authorize",
|
|
41771
|
-
tokenUrl: "https://connect.stripe.com/oauth/token"
|
|
43216
|
+
tokenUrl: "https://connect.stripe.com/oauth/token",
|
|
43217
|
+
usePKCE: true
|
|
41772
43218
|
},
|
|
41773
43219
|
scopes: ["read_write"]
|
|
41774
43220
|
}
|
|
@@ -41818,14 +43264,15 @@ var quickbooksTemplate = {
|
|
|
41818
43264
|
name: "OAuth (User Authorization)",
|
|
41819
43265
|
type: "oauth",
|
|
41820
43266
|
flow: "authorization_code",
|
|
41821
|
-
description: "Standard OAuth 2.0 flow for accessing QuickBooks on behalf of a user. Create an app at developer.intuit.com",
|
|
41822
|
-
requiredFields: ["clientId", "
|
|
41823
|
-
optionalFields: ["scope"],
|
|
43267
|
+
description: "Standard OAuth 2.0 flow for accessing QuickBooks on behalf of a user. Create an app at developer.intuit.com. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
43268
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
43269
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41824
43270
|
defaults: {
|
|
41825
43271
|
type: "oauth",
|
|
41826
43272
|
flow: "authorization_code",
|
|
41827
43273
|
authorizationUrl: "https://appcenter.intuit.com/connect/oauth2",
|
|
41828
|
-
tokenUrl: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"
|
|
43274
|
+
tokenUrl: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
|
|
43275
|
+
usePKCE: true
|
|
41829
43276
|
},
|
|
41830
43277
|
scopes: ["com.intuit.quickbooks.accounting", "com.intuit.quickbooks.payment"]
|
|
41831
43278
|
}
|
|
@@ -41860,14 +43307,15 @@ var rampTemplate = {
|
|
|
41860
43307
|
name: "OAuth (User Authorization)",
|
|
41861
43308
|
type: "oauth",
|
|
41862
43309
|
flow: "authorization_code",
|
|
41863
|
-
description: "OAuth 2.0 authorization code flow for accessing Ramp on behalf of a user",
|
|
41864
|
-
requiredFields: ["clientId", "
|
|
41865
|
-
optionalFields: ["scope"],
|
|
43310
|
+
description: "OAuth 2.0 authorization code flow for accessing Ramp on behalf of a user. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
43311
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
43312
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41866
43313
|
defaults: {
|
|
41867
43314
|
type: "oauth",
|
|
41868
43315
|
flow: "authorization_code",
|
|
41869
43316
|
authorizationUrl: "https://app.ramp.com/v1/authorize",
|
|
41870
|
-
tokenUrl: "https://api.ramp.com/developer/v1/token"
|
|
43317
|
+
tokenUrl: "https://api.ramp.com/developer/v1/token",
|
|
43318
|
+
usePKCE: true
|
|
41871
43319
|
},
|
|
41872
43320
|
scopes: [
|
|
41873
43321
|
"transactions:read",
|
|
@@ -41924,9 +43372,9 @@ var dropboxTemplate = {
|
|
|
41924
43372
|
name: "OAuth (User Authorization)",
|
|
41925
43373
|
type: "oauth",
|
|
41926
43374
|
flow: "authorization_code",
|
|
41927
|
-
description: "OAuth app for user authorization. Create app at dropbox.com/developers/apps",
|
|
41928
|
-
requiredFields: ["clientId", "
|
|
41929
|
-
optionalFields: ["scope"],
|
|
43375
|
+
description: "OAuth app for user authorization. Create app at dropbox.com/developers/apps. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
43376
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
43377
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41930
43378
|
defaults: {
|
|
41931
43379
|
type: "oauth",
|
|
41932
43380
|
flow: "authorization_code",
|
|
@@ -41963,14 +43411,15 @@ var boxTemplate = {
|
|
|
41963
43411
|
name: "OAuth (User Authorization)",
|
|
41964
43412
|
type: "oauth",
|
|
41965
43413
|
flow: "authorization_code",
|
|
41966
|
-
description: "OAuth 2.0 for user authorization. Create app at developer.box.com/console",
|
|
41967
|
-
requiredFields: ["clientId", "
|
|
41968
|
-
optionalFields: ["scope"],
|
|
43414
|
+
description: "OAuth 2.0 for user authorization. Create app at developer.box.com/console. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
43415
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
43416
|
+
optionalFields: ["clientSecret", "scope"],
|
|
41969
43417
|
defaults: {
|
|
41970
43418
|
type: "oauth",
|
|
41971
43419
|
flow: "authorization_code",
|
|
41972
43420
|
authorizationUrl: "https://account.box.com/api/oauth2/authorize",
|
|
41973
|
-
tokenUrl: "https://api.box.com/oauth2/token"
|
|
43421
|
+
tokenUrl: "https://api.box.com/oauth2/token",
|
|
43422
|
+
usePKCE: true
|
|
41974
43423
|
},
|
|
41975
43424
|
scopes: ["root_readwrite", "manage_users", "manage_groups", "manage_enterprise"],
|
|
41976
43425
|
scopeDescriptions: {
|
|
@@ -42048,13 +43497,15 @@ var mailchimpTemplate = {
|
|
|
42048
43497
|
name: "OAuth (User Authorization)",
|
|
42049
43498
|
type: "oauth",
|
|
42050
43499
|
flow: "authorization_code",
|
|
42051
|
-
description: "OAuth for multi-account access. Register app at mailchimp.com/developer",
|
|
42052
|
-
requiredFields: ["clientId", "
|
|
43500
|
+
description: "OAuth for multi-account access. Register app at mailchimp.com/developer. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
43501
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
43502
|
+
optionalFields: ["clientSecret"],
|
|
42053
43503
|
defaults: {
|
|
42054
43504
|
type: "oauth",
|
|
42055
43505
|
flow: "authorization_code",
|
|
42056
43506
|
authorizationUrl: "https://login.mailchimp.com/oauth2/authorize",
|
|
42057
|
-
tokenUrl: "https://login.mailchimp.com/oauth2/token"
|
|
43507
|
+
tokenUrl: "https://login.mailchimp.com/oauth2/token",
|
|
43508
|
+
usePKCE: true
|
|
42058
43509
|
}
|
|
42059
43510
|
}
|
|
42060
43511
|
]
|
|
@@ -42146,14 +43597,15 @@ var pagerdutyTemplate = {
|
|
|
42146
43597
|
name: "OAuth (App Authorization)",
|
|
42147
43598
|
type: "oauth",
|
|
42148
43599
|
flow: "authorization_code",
|
|
42149
|
-
description: "OAuth app for multi-account access. Register at developer.pagerduty.com",
|
|
42150
|
-
requiredFields: ["clientId", "
|
|
42151
|
-
optionalFields: ["scope"],
|
|
43600
|
+
description: "OAuth app for multi-account access. Register at developer.pagerduty.com. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
43601
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
43602
|
+
optionalFields: ["clientSecret", "scope"],
|
|
42152
43603
|
defaults: {
|
|
42153
43604
|
type: "oauth",
|
|
42154
43605
|
flow: "authorization_code",
|
|
42155
43606
|
authorizationUrl: "https://app.pagerduty.com/oauth/authorize",
|
|
42156
|
-
tokenUrl: "https://app.pagerduty.com/oauth/token"
|
|
43607
|
+
tokenUrl: "https://app.pagerduty.com/oauth/token",
|
|
43608
|
+
usePKCE: true
|
|
42157
43609
|
},
|
|
42158
43610
|
scopes: ["read", "write"],
|
|
42159
43611
|
scopeDescriptions: {
|
|
@@ -42189,14 +43641,15 @@ var sentryTemplate = {
|
|
|
42189
43641
|
name: "OAuth (Integration)",
|
|
42190
43642
|
type: "oauth",
|
|
42191
43643
|
flow: "authorization_code",
|
|
42192
|
-
description: "OAuth integration. Create at Organization Settings > Integrations",
|
|
42193
|
-
requiredFields: ["clientId", "
|
|
42194
|
-
optionalFields: ["scope"],
|
|
43644
|
+
description: "OAuth integration. Create at Organization Settings > Integrations. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
43645
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
43646
|
+
optionalFields: ["clientSecret", "scope"],
|
|
42195
43647
|
defaults: {
|
|
42196
43648
|
type: "oauth",
|
|
42197
43649
|
flow: "authorization_code",
|
|
42198
43650
|
authorizationUrl: "https://sentry.io/oauth/authorize/",
|
|
42199
|
-
tokenUrl: "https://sentry.io/oauth/token/"
|
|
43651
|
+
tokenUrl: "https://sentry.io/oauth/token/",
|
|
43652
|
+
usePKCE: true
|
|
42200
43653
|
},
|
|
42201
43654
|
scopes: ["project:read", "project:write", "event:read", "org:read", "member:read"],
|
|
42202
43655
|
scopeDescriptions: {
|
|
@@ -42393,14 +43846,15 @@ var zendeskTemplate = {
|
|
|
42393
43846
|
name: "OAuth (User Authorization)",
|
|
42394
43847
|
type: "oauth",
|
|
42395
43848
|
flow: "authorization_code",
|
|
42396
|
-
description: "OAuth client for user authorization. Create at Admin > Channels > API > OAuth Clients",
|
|
42397
|
-
requiredFields: ["clientId", "
|
|
42398
|
-
optionalFields: ["scope"],
|
|
43849
|
+
description: "OAuth client for user authorization. Create at Admin > Channels > API > OAuth Clients. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
43850
|
+
requiredFields: ["clientId", "redirectUri", "subdomain"],
|
|
43851
|
+
optionalFields: ["clientSecret", "scope"],
|
|
42399
43852
|
defaults: {
|
|
42400
43853
|
type: "oauth",
|
|
42401
43854
|
flow: "authorization_code",
|
|
42402
43855
|
authorizationUrl: "https://{subdomain}.zendesk.com/oauth/authorizations/new",
|
|
42403
|
-
tokenUrl: "https://{subdomain}.zendesk.com/oauth/tokens"
|
|
43856
|
+
tokenUrl: "https://{subdomain}.zendesk.com/oauth/tokens",
|
|
43857
|
+
usePKCE: true
|
|
42404
43858
|
},
|
|
42405
43859
|
scopes: ["read", "write", "tickets:read", "tickets:write"],
|
|
42406
43860
|
scopeDescriptions: {
|
|
@@ -42438,13 +43892,15 @@ var intercomTemplate = {
|
|
|
42438
43892
|
name: "OAuth (App Installation)",
|
|
42439
43893
|
type: "oauth",
|
|
42440
43894
|
flow: "authorization_code",
|
|
42441
|
-
description: "OAuth for Intercom app marketplace distribution",
|
|
42442
|
-
requiredFields: ["clientId", "
|
|
43895
|
+
description: "OAuth for Intercom app marketplace distribution. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
43896
|
+
requiredFields: ["clientId", "redirectUri"],
|
|
43897
|
+
optionalFields: ["clientSecret"],
|
|
42443
43898
|
defaults: {
|
|
42444
43899
|
type: "oauth",
|
|
42445
43900
|
flow: "authorization_code",
|
|
42446
43901
|
authorizationUrl: "https://app.intercom.com/oauth",
|
|
42447
|
-
tokenUrl: "https://api.intercom.io/auth/eagle/token"
|
|
43902
|
+
tokenUrl: "https://api.intercom.io/auth/eagle/token",
|
|
43903
|
+
usePKCE: true
|
|
42448
43904
|
}
|
|
42449
43905
|
}
|
|
42450
43906
|
]
|
|
@@ -42477,14 +43933,15 @@ var shopifyTemplate = {
|
|
|
42477
43933
|
name: "OAuth (Public/Custom App)",
|
|
42478
43934
|
type: "oauth",
|
|
42479
43935
|
flow: "authorization_code",
|
|
42480
|
-
description: "OAuth for public apps or per-store custom apps. Create at partners.shopify.com",
|
|
42481
|
-
requiredFields: ["clientId", "
|
|
42482
|
-
optionalFields: ["scope"],
|
|
43936
|
+
description: "OAuth for public apps or per-store custom apps. Create at partners.shopify.com. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
|
|
43937
|
+
requiredFields: ["clientId", "redirectUri", "subdomain"],
|
|
43938
|
+
optionalFields: ["clientSecret", "scope"],
|
|
42483
43939
|
defaults: {
|
|
42484
43940
|
type: "oauth",
|
|
42485
43941
|
flow: "authorization_code",
|
|
42486
43942
|
authorizationUrl: "https://{subdomain}.myshopify.com/admin/oauth/authorize",
|
|
42487
|
-
tokenUrl: "https://{subdomain}.myshopify.com/admin/oauth/access_token"
|
|
43943
|
+
tokenUrl: "https://{subdomain}.myshopify.com/admin/oauth/access_token",
|
|
43944
|
+
usePKCE: true
|
|
42488
43945
|
},
|
|
42489
43946
|
scopes: ["read_products", "write_products", "read_orders", "write_orders", "read_customers", "write_customers", "read_inventory", "write_inventory", "read_fulfillments", "write_fulfillments"],
|
|
42490
43947
|
scopeDescriptions: {
|
|
@@ -42512,6 +43969,7 @@ var allVendorTemplates = [
|
|
|
42512
43969
|
slackTemplate,
|
|
42513
43970
|
discordTemplate,
|
|
42514
43971
|
telegramTemplate,
|
|
43972
|
+
twitterTemplate,
|
|
42515
43973
|
// Development
|
|
42516
43974
|
githubTemplate,
|
|
42517
43975
|
gitlabTemplate,
|
|
@@ -42571,6 +44029,7 @@ var VENDOR_ICON_MAP = {
|
|
|
42571
44029
|
discord: "discord",
|
|
42572
44030
|
slack: "slack",
|
|
42573
44031
|
telegram: "telegram",
|
|
44032
|
+
twitter: "x",
|
|
42574
44033
|
"microsoft-teams": "microsoftteams",
|
|
42575
44034
|
// CRM
|
|
42576
44035
|
salesforce: "salesforce",
|
|
@@ -42635,6 +44094,7 @@ var FALLBACK_PLACEHOLDERS = {
|
|
|
42635
44094
|
// Communication (trademark removed)
|
|
42636
44095
|
slack: { color: "#4A154B", letter: "S" },
|
|
42637
44096
|
"microsoft-teams": { color: "#6264A7", letter: "T" },
|
|
44097
|
+
twitter: { color: "#000000", letter: "X" },
|
|
42638
44098
|
// CRM (trademark removed)
|
|
42639
44099
|
salesforce: { color: "#00A1E0", letter: "S" },
|
|
42640
44100
|
pipedrive: { color: "#1A1F26", letter: "P" },
|
|
@@ -43572,7 +45032,7 @@ EXAMPLES:
|
|
|
43572
45032
|
};
|
|
43573
45033
|
}
|
|
43574
45034
|
try {
|
|
43575
|
-
const stats = await
|
|
45035
|
+
const stats = await fs17.stat(resolvedPath);
|
|
43576
45036
|
if (!stats.isFile()) {
|
|
43577
45037
|
return {
|
|
43578
45038
|
success: false,
|
|
@@ -43614,7 +45074,7 @@ EXAMPLES:
|
|
|
43614
45074
|
} catch {
|
|
43615
45075
|
}
|
|
43616
45076
|
}
|
|
43617
|
-
const content = await
|
|
45077
|
+
const content = await fs17.readFile(resolvedPath, "utf-8");
|
|
43618
45078
|
const allLines = content.split("\n");
|
|
43619
45079
|
const totalLines = allLines.length;
|
|
43620
45080
|
const startIndex = Math.max(0, offset - 1);
|
|
@@ -43723,9 +45183,9 @@ EXAMPLES:
|
|
|
43723
45183
|
try {
|
|
43724
45184
|
const parentDir = path2.dirname(resolvedPath);
|
|
43725
45185
|
if (!fs19.existsSync(parentDir)) {
|
|
43726
|
-
await
|
|
45186
|
+
await fs17.mkdir(parentDir, { recursive: true });
|
|
43727
45187
|
}
|
|
43728
|
-
await
|
|
45188
|
+
await fs17.writeFile(resolvedPath, content, "utf-8");
|
|
43729
45189
|
return {
|
|
43730
45190
|
success: true,
|
|
43731
45191
|
path: file_path,
|
|
@@ -43836,7 +45296,7 @@ EXAMPLES:
|
|
|
43836
45296
|
};
|
|
43837
45297
|
}
|
|
43838
45298
|
try {
|
|
43839
|
-
const content = await
|
|
45299
|
+
const content = await fs17.readFile(resolvedPath, "utf-8");
|
|
43840
45300
|
let occurrences = 0;
|
|
43841
45301
|
let searchIndex = 0;
|
|
43842
45302
|
while (true) {
|
|
@@ -43875,7 +45335,7 @@ EXAMPLES:
|
|
|
43875
45335
|
} else {
|
|
43876
45336
|
newContent = content.replace(old_string, new_string);
|
|
43877
45337
|
}
|
|
43878
|
-
await
|
|
45338
|
+
await fs17.writeFile(resolvedPath, newContent, "utf-8");
|
|
43879
45339
|
const diffPreview = generateDiffPreview(old_string, new_string);
|
|
43880
45340
|
return {
|
|
43881
45341
|
success: true,
|
|
@@ -43931,7 +45391,7 @@ async function findFiles(dir, pattern, baseDir, config, results = [], depth = 0)
|
|
|
43931
45391
|
return results;
|
|
43932
45392
|
}
|
|
43933
45393
|
try {
|
|
43934
|
-
const entries = await
|
|
45394
|
+
const entries = await fs17.readdir(dir, { withFileTypes: true });
|
|
43935
45395
|
for (const entry of entries) {
|
|
43936
45396
|
if (results.length >= config.maxResults) break;
|
|
43937
45397
|
const fullPath = path2.join(dir, entry.name);
|
|
@@ -43945,7 +45405,7 @@ async function findFiles(dir, pattern, baseDir, config, results = [], depth = 0)
|
|
|
43945
45405
|
} else if (entry.isFile()) {
|
|
43946
45406
|
if (matchGlobPattern(pattern, relativePath)) {
|
|
43947
45407
|
try {
|
|
43948
|
-
const stats = await
|
|
45408
|
+
const stats = await fs17.stat(fullPath);
|
|
43949
45409
|
results.push({
|
|
43950
45410
|
path: relativePath,
|
|
43951
45411
|
mtime: stats.mtimeMs
|
|
@@ -44082,7 +45542,7 @@ async function findFilesToSearch(dir, baseDir, config, globPattern, fileType, fi
|
|
|
44082
45542
|
return files;
|
|
44083
45543
|
}
|
|
44084
45544
|
try {
|
|
44085
|
-
const entries = await
|
|
45545
|
+
const entries = await fs17.readdir(dir, { withFileTypes: true });
|
|
44086
45546
|
for (const entry of entries) {
|
|
44087
45547
|
const fullPath = path2.join(dir, entry.name);
|
|
44088
45548
|
if (entry.isDirectory()) {
|
|
@@ -44115,7 +45575,7 @@ async function findFilesToSearch(dir, baseDir, config, globPattern, fileType, fi
|
|
|
44115
45575
|
async function searchFile(filePath, regex, contextBefore, contextAfter) {
|
|
44116
45576
|
const matches = [];
|
|
44117
45577
|
try {
|
|
44118
|
-
const content = await
|
|
45578
|
+
const content = await fs17.readFile(filePath, "utf-8");
|
|
44119
45579
|
const lines = content.split("\n");
|
|
44120
45580
|
for (let i = 0; i < lines.length; i++) {
|
|
44121
45581
|
const line = lines[i] ?? "";
|
|
@@ -44272,7 +45732,7 @@ WHEN TO USE:
|
|
|
44272
45732
|
};
|
|
44273
45733
|
}
|
|
44274
45734
|
try {
|
|
44275
|
-
const stats = await
|
|
45735
|
+
const stats = await fs17.stat(resolvedPath);
|
|
44276
45736
|
let filesToSearch;
|
|
44277
45737
|
if (stats.isFile()) {
|
|
44278
45738
|
filesToSearch = [resolvedPath];
|
|
@@ -44360,7 +45820,7 @@ async function listDir(dir, baseDir, config, recursive, filter, maxDepth = 3, cu
|
|
|
44360
45820
|
return entries;
|
|
44361
45821
|
}
|
|
44362
45822
|
try {
|
|
44363
|
-
const dirEntries = await
|
|
45823
|
+
const dirEntries = await fs17.readdir(dir, { withFileTypes: true });
|
|
44364
45824
|
for (const entry of dirEntries) {
|
|
44365
45825
|
if (entries.length >= config.maxResults) break;
|
|
44366
45826
|
const fullPath = path2.join(dir, entry.name);
|
|
@@ -44378,7 +45838,7 @@ async function listDir(dir, baseDir, config, recursive, filter, maxDepth = 3, cu
|
|
|
44378
45838
|
}
|
|
44379
45839
|
if (filter === "directories" && !isDir) continue;
|
|
44380
45840
|
try {
|
|
44381
|
-
const stats = await
|
|
45841
|
+
const stats = await fs17.stat(fullPath);
|
|
44382
45842
|
const dirEntry = {
|
|
44383
45843
|
name: entry.name,
|
|
44384
45844
|
path: relativePath,
|
|
@@ -44481,7 +45941,7 @@ EXAMPLES:
|
|
|
44481
45941
|
};
|
|
44482
45942
|
}
|
|
44483
45943
|
try {
|
|
44484
|
-
const stats = await
|
|
45944
|
+
const stats = await fs17.stat(resolvedPath);
|
|
44485
45945
|
if (!stats.isDirectory()) {
|
|
44486
45946
|
return {
|
|
44487
45947
|
success: false,
|
|
@@ -45804,21 +47264,53 @@ registerWebTools();
|
|
|
45804
47264
|
init_Connector();
|
|
45805
47265
|
var DEFAULT_TIMEOUT = 1e4;
|
|
45806
47266
|
var DEFAULT_MAX_TIMEOUT = 3e4;
|
|
45807
|
-
function formatConnectorEntry(c) {
|
|
47267
|
+
function formatConnectorEntry(c, accountId) {
|
|
45808
47268
|
const parts = [];
|
|
45809
47269
|
const serviceOrVendor = c.serviceType ?? c.vendor ?? void 0;
|
|
45810
47270
|
if (serviceOrVendor) parts.push(`Service: ${serviceOrVendor}`);
|
|
47271
|
+
if (accountId) parts.push(`Account: "${accountId}"`);
|
|
45811
47272
|
if (c.config.description) parts.push(c.config.description);
|
|
45812
47273
|
if (c.baseURL) parts.push(`URL: ${c.baseURL}`);
|
|
47274
|
+
const label = accountId ? `"${c.name}" account "${accountId}"` : `"${c.name}"`;
|
|
45813
47275
|
const details = parts.map((p) => ` ${p}`).join("\n");
|
|
45814
|
-
return ` \u2022
|
|
47276
|
+
return ` \u2022 ${label} (${c.displayName})
|
|
45815
47277
|
${details}`;
|
|
45816
47278
|
}
|
|
45817
|
-
function
|
|
47279
|
+
function buildIdentityList(context) {
|
|
47280
|
+
const identities = context?.identities;
|
|
45818
47281
|
const registry = context?.connectorRegistry ?? exports.Connector.asRegistry();
|
|
47282
|
+
if (identities?.length) {
|
|
47283
|
+
const entries = [];
|
|
47284
|
+
for (const id of identities) {
|
|
47285
|
+
try {
|
|
47286
|
+
const connector = registry.get(id.connector);
|
|
47287
|
+
entries.push(formatConnectorEntry(connector, id.accountId));
|
|
47288
|
+
} catch {
|
|
47289
|
+
entries.push(` \u2022 "${id.connector}"${id.accountId ? ` account "${id.accountId}"` : ""} \u2014 not available`);
|
|
47290
|
+
}
|
|
47291
|
+
}
|
|
47292
|
+
return entries.length > 0 ? entries.join("\n\n") : " No connectors registered.";
|
|
47293
|
+
}
|
|
45819
47294
|
const connectors = registry.listAll();
|
|
45820
|
-
|
|
47295
|
+
return connectors.length > 0 ? connectors.map((c) => formatConnectorEntry(c)).join("\n\n") : " No connectors registered.";
|
|
47296
|
+
}
|
|
47297
|
+
function hasAccountIds(context) {
|
|
47298
|
+
return !!context?.identities?.some((id) => id.accountId);
|
|
47299
|
+
}
|
|
47300
|
+
function generateDescription(context, maxTimeout) {
|
|
47301
|
+
const connectorList = buildIdentityList(context);
|
|
47302
|
+
const showAccountId = hasAccountIds(context);
|
|
45821
47303
|
const timeoutSec = Math.round(maxTimeout / 1e3);
|
|
47304
|
+
const accountIdParam = showAccountId ? `
|
|
47305
|
+
\u2022 accountId (optional): Account alias for multi-account connectors.
|
|
47306
|
+
Required when a connector has multiple accounts (see list below).
|
|
47307
|
+
Example: authenticatedFetch('/v1.0/me', {}, 'microsoft', 'work')` : "";
|
|
47308
|
+
const accountIdExamples = showAccountId ? `
|
|
47309
|
+
// Multi-account: specify accountId for connectors with multiple accounts
|
|
47310
|
+
const resp = await authenticatedFetch('/v1.0/me', { method: 'GET' }, 'microsoft', 'work');
|
|
47311
|
+
const profile = await resp.json();
|
|
47312
|
+
output = profile;
|
|
47313
|
+
` : "";
|
|
45822
47314
|
return `Execute JavaScript code in a secure sandbox with authenticated API access to external services.
|
|
45823
47315
|
|
|
45824
47316
|
Use this tool when you need to:
|
|
@@ -45829,7 +47321,7 @@ Use this tool when you need to:
|
|
|
45829
47321
|
|
|
45830
47322
|
SANDBOX API:
|
|
45831
47323
|
|
|
45832
|
-
1. authenticatedFetch(url, options, connectorName)
|
|
47324
|
+
1. authenticatedFetch(url, options, connectorName${showAccountId ? ", accountId?" : ""})
|
|
45833
47325
|
Makes authenticated HTTP requests using the connector's credentials.
|
|
45834
47326
|
The current user's identity (userId) is automatically included \u2014 no need to pass it.
|
|
45835
47327
|
Auth headers are added automatically \u2014 DO NOT set Authorization header manually.
|
|
@@ -45840,7 +47332,7 @@ SANDBOX API:
|
|
|
45840
47332
|
- Relative: "/user/repos" (resolved against connector's base URL)
|
|
45841
47333
|
\u2022 options: Standard fetch options { method, headers, body }
|
|
45842
47334
|
- For POST/PUT: set body to JSON.stringify(data) and headers to { 'Content-Type': 'application/json' }
|
|
45843
|
-
\u2022 connectorName: Name of a registered connector (see list below)
|
|
47335
|
+
\u2022 connectorName: Name of a registered connector (see list below)${accountIdParam}
|
|
45844
47336
|
|
|
45845
47337
|
Returns: Promise<Response>
|
|
45846
47338
|
\u2022 response.ok \u2014 true if status 200-299
|
|
@@ -45876,7 +47368,7 @@ const resp = await authenticatedFetch('/chat.postMessage', {
|
|
|
45876
47368
|
body: JSON.stringify({ channel: '#general', text: 'Hello!' })
|
|
45877
47369
|
}, 'slack');
|
|
45878
47370
|
output = await resp.json();
|
|
45879
|
-
|
|
47371
|
+
${accountIdExamples}
|
|
45880
47372
|
// Data processing (no API needed)
|
|
45881
47373
|
const items = input.data;
|
|
45882
47374
|
output = items.filter(i => i.score > 0.8).sort((a, b) => b.score - a.score);
|
|
@@ -45964,9 +47456,10 @@ async function executeInVM(code, input, timeout, logs, userId, registry) {
|
|
|
45964
47456
|
},
|
|
45965
47457
|
// Authenticated fetch — userId auto-injected from ToolContext.
|
|
45966
47458
|
// Only connectors visible in the scoped registry are accessible.
|
|
45967
|
-
|
|
47459
|
+
// Optional 4th param accountId for multi-account OAuth identities.
|
|
47460
|
+
authenticatedFetch: (url2, options, connectorName, accountId) => {
|
|
45968
47461
|
registry.get(connectorName);
|
|
45969
|
-
return authenticatedFetch(url2, options, connectorName, userId);
|
|
47462
|
+
return authenticatedFetch(url2, options, connectorName, userId, accountId);
|
|
45970
47463
|
},
|
|
45971
47464
|
// Standard fetch (no auth)
|
|
45972
47465
|
fetch: globalThis.fetch,
|
|
@@ -46654,7 +48147,8 @@ async function githubFetch(connector, endpoint, options) {
|
|
|
46654
48147
|
headers,
|
|
46655
48148
|
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
46656
48149
|
},
|
|
46657
|
-
options?.userId
|
|
48150
|
+
options?.userId,
|
|
48151
|
+
options?.accountId
|
|
46658
48152
|
);
|
|
46659
48153
|
const text = await response.text();
|
|
46660
48154
|
let data;
|
|
@@ -46736,6 +48230,7 @@ EXAMPLES:
|
|
|
46736
48230
|
},
|
|
46737
48231
|
execute: async (args, context) => {
|
|
46738
48232
|
const effectiveUserId = context?.userId ?? userId;
|
|
48233
|
+
const effectiveAccountId = context?.accountId;
|
|
46739
48234
|
const resolved = resolveRepository(args.repository, connector);
|
|
46740
48235
|
if (!resolved.success) {
|
|
46741
48236
|
return { success: false, error: resolved.error };
|
|
@@ -46747,7 +48242,7 @@ EXAMPLES:
|
|
|
46747
48242
|
const repoInfo = await githubFetch(
|
|
46748
48243
|
connector,
|
|
46749
48244
|
`/repos/${owner}/${repo}`,
|
|
46750
|
-
{ userId: effectiveUserId }
|
|
48245
|
+
{ userId: effectiveUserId, accountId: effectiveAccountId }
|
|
46751
48246
|
);
|
|
46752
48247
|
ref = repoInfo.default_branch;
|
|
46753
48248
|
}
|
|
@@ -46847,6 +48342,7 @@ EXAMPLES:
|
|
|
46847
48342
|
},
|
|
46848
48343
|
execute: async (args, context) => {
|
|
46849
48344
|
const effectiveUserId = context?.userId ?? userId;
|
|
48345
|
+
const effectiveAccountId = context?.accountId;
|
|
46850
48346
|
const resolved = resolveRepository(args.repository, connector);
|
|
46851
48347
|
if (!resolved.success) {
|
|
46852
48348
|
return { success: false, error: resolved.error };
|
|
@@ -46864,6 +48360,7 @@ EXAMPLES:
|
|
|
46864
48360
|
`/search/code`,
|
|
46865
48361
|
{
|
|
46866
48362
|
userId: effectiveUserId,
|
|
48363
|
+
accountId: effectiveAccountId,
|
|
46867
48364
|
// Request text-match fragments
|
|
46868
48365
|
accept: "application/vnd.github.text-match+json",
|
|
46869
48366
|
queryParams: { q, per_page: perPage }
|
|
@@ -46952,6 +48449,7 @@ NOTE: Files larger than 1MB are fetched via the Git Blob API. Very large files (
|
|
|
46952
48449
|
},
|
|
46953
48450
|
execute: async (args, context) => {
|
|
46954
48451
|
const effectiveUserId = context?.userId ?? userId;
|
|
48452
|
+
const effectiveAccountId = context?.accountId;
|
|
46955
48453
|
const resolved = resolveRepository(args.repository, connector);
|
|
46956
48454
|
if (!resolved.success) {
|
|
46957
48455
|
return { success: false, error: resolved.error };
|
|
@@ -46965,7 +48463,7 @@ NOTE: Files larger than 1MB are fetched via the Git Blob API. Very large files (
|
|
|
46965
48463
|
const contentResp = await githubFetch(
|
|
46966
48464
|
connector,
|
|
46967
48465
|
`/repos/${owner}/${repo}/contents/${args.path}${refParam}`,
|
|
46968
|
-
{ userId: effectiveUserId }
|
|
48466
|
+
{ userId: effectiveUserId, accountId: effectiveAccountId }
|
|
46969
48467
|
);
|
|
46970
48468
|
if (contentResp.type !== "file") {
|
|
46971
48469
|
return {
|
|
@@ -46982,7 +48480,7 @@ NOTE: Files larger than 1MB are fetched via the Git Blob API. Very large files (
|
|
|
46982
48480
|
const blob = await githubFetch(
|
|
46983
48481
|
connector,
|
|
46984
48482
|
contentResp.git_url,
|
|
46985
|
-
{ userId: effectiveUserId }
|
|
48483
|
+
{ userId: effectiveUserId, accountId: effectiveAccountId }
|
|
46986
48484
|
);
|
|
46987
48485
|
fileContent = Buffer.from(blob.content, "base64").toString("utf-8");
|
|
46988
48486
|
fileSize = blob.size;
|
|
@@ -47071,6 +48569,7 @@ EXAMPLES:
|
|
|
47071
48569
|
},
|
|
47072
48570
|
execute: async (args, context) => {
|
|
47073
48571
|
const effectiveUserId = context?.userId ?? userId;
|
|
48572
|
+
const effectiveAccountId = context?.accountId;
|
|
47074
48573
|
const resolved = resolveRepository(args.repository, connector);
|
|
47075
48574
|
if (!resolved.success) {
|
|
47076
48575
|
return { success: false, error: resolved.error };
|
|
@@ -47080,7 +48579,7 @@ EXAMPLES:
|
|
|
47080
48579
|
const pr = await githubFetch(
|
|
47081
48580
|
connector,
|
|
47082
48581
|
`/repos/${owner}/${repo}/pulls/${args.pull_number}`,
|
|
47083
|
-
{ userId: effectiveUserId }
|
|
48582
|
+
{ userId: effectiveUserId, accountId: effectiveAccountId }
|
|
47084
48583
|
);
|
|
47085
48584
|
return {
|
|
47086
48585
|
success: true,
|
|
@@ -47158,6 +48657,7 @@ NOTE: Very large diffs may be truncated by GitHub. Patch content may be absent f
|
|
|
47158
48657
|
},
|
|
47159
48658
|
execute: async (args, context) => {
|
|
47160
48659
|
const effectiveUserId = context?.userId ?? userId;
|
|
48660
|
+
const effectiveAccountId = context?.accountId;
|
|
47161
48661
|
const resolved = resolveRepository(args.repository, connector);
|
|
47162
48662
|
if (!resolved.success) {
|
|
47163
48663
|
return { success: false, error: resolved.error };
|
|
@@ -47169,6 +48669,7 @@ NOTE: Very large diffs may be truncated by GitHub. Patch content may be absent f
|
|
|
47169
48669
|
`/repos/${owner}/${repo}/pulls/${args.pull_number}/files`,
|
|
47170
48670
|
{
|
|
47171
48671
|
userId: effectiveUserId,
|
|
48672
|
+
accountId: effectiveAccountId,
|
|
47172
48673
|
queryParams: { per_page: 100 }
|
|
47173
48674
|
}
|
|
47174
48675
|
);
|
|
@@ -47241,6 +48742,7 @@ EXAMPLES:
|
|
|
47241
48742
|
},
|
|
47242
48743
|
execute: async (args, context) => {
|
|
47243
48744
|
const effectiveUserId = context?.userId ?? userId;
|
|
48745
|
+
const effectiveAccountId = context?.accountId;
|
|
47244
48746
|
const resolved = resolveRepository(args.repository, connector);
|
|
47245
48747
|
if (!resolved.success) {
|
|
47246
48748
|
return { success: false, error: resolved.error };
|
|
@@ -47248,7 +48750,7 @@ EXAMPLES:
|
|
|
47248
48750
|
const { owner, repo } = resolved.repo;
|
|
47249
48751
|
try {
|
|
47250
48752
|
const basePath = `/repos/${owner}/${repo}`;
|
|
47251
|
-
const queryOpts = { userId: effectiveUserId, queryParams: { per_page: 100 } };
|
|
48753
|
+
const queryOpts = { userId: effectiveUserId, accountId: effectiveAccountId, queryParams: { per_page: 100 } };
|
|
47252
48754
|
const [reviewComments, reviews, issueComments] = await Promise.all([
|
|
47253
48755
|
githubFetch(
|
|
47254
48756
|
connector,
|
|
@@ -47377,6 +48879,7 @@ EXAMPLES:
|
|
|
47377
48879
|
},
|
|
47378
48880
|
execute: async (args, context) => {
|
|
47379
48881
|
const effectiveUserId = context?.userId ?? userId;
|
|
48882
|
+
const effectiveAccountId = context?.accountId;
|
|
47380
48883
|
const resolved = resolveRepository(args.repository, connector);
|
|
47381
48884
|
if (!resolved.success) {
|
|
47382
48885
|
return { success: false, error: resolved.error };
|
|
@@ -47389,6 +48892,7 @@ EXAMPLES:
|
|
|
47389
48892
|
{
|
|
47390
48893
|
method: "POST",
|
|
47391
48894
|
userId: effectiveUserId,
|
|
48895
|
+
accountId: effectiveAccountId,
|
|
47392
48896
|
body: {
|
|
47393
48897
|
title: args.title,
|
|
47394
48898
|
body: args.body,
|
|
@@ -47480,7 +48984,8 @@ async function microsoftFetch(connector, endpoint, options) {
|
|
|
47480
48984
|
headers,
|
|
47481
48985
|
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
47482
48986
|
},
|
|
47483
|
-
options?.userId
|
|
48987
|
+
options?.userId,
|
|
48988
|
+
options?.accountId
|
|
47484
48989
|
);
|
|
47485
48990
|
const text = await response.text();
|
|
47486
48991
|
if (!response.ok) {
|
|
@@ -47533,7 +49038,7 @@ function isTeamsMeetingUrl(input) {
|
|
|
47533
49038
|
return false;
|
|
47534
49039
|
}
|
|
47535
49040
|
}
|
|
47536
|
-
async function resolveMeetingId(connector, input, prefix, effectiveUserId) {
|
|
49041
|
+
async function resolveMeetingId(connector, input, prefix, effectiveUserId, effectiveAccountId) {
|
|
47537
49042
|
if (!input || input.trim().length === 0) {
|
|
47538
49043
|
throw new Error("Meeting ID cannot be empty");
|
|
47539
49044
|
}
|
|
@@ -47546,6 +49051,7 @@ async function resolveMeetingId(connector, input, prefix, effectiveUserId) {
|
|
|
47546
49051
|
`${prefix}/onlineMeetings`,
|
|
47547
49052
|
{
|
|
47548
49053
|
userId: effectiveUserId,
|
|
49054
|
+
accountId: effectiveAccountId,
|
|
47549
49055
|
queryParams: { "$filter": `JoinWebUrl eq '${trimmed}'` }
|
|
47550
49056
|
}
|
|
47551
49057
|
);
|
|
@@ -47624,13 +49130,14 @@ EXAMPLES:
|
|
|
47624
49130
|
},
|
|
47625
49131
|
execute: async (args, context) => {
|
|
47626
49132
|
const effectiveUserId = context?.userId ?? userId;
|
|
49133
|
+
const effectiveAccountId = context?.accountId;
|
|
47627
49134
|
try {
|
|
47628
49135
|
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
47629
49136
|
if (args.replyToMessageId) {
|
|
47630
49137
|
const replyDraft = await microsoftFetch(
|
|
47631
49138
|
connector,
|
|
47632
49139
|
`${prefix}/messages/${args.replyToMessageId}/createReply`,
|
|
47633
|
-
{ method: "POST", userId: effectiveUserId, body: {} }
|
|
49140
|
+
{ method: "POST", userId: effectiveUserId, accountId: effectiveAccountId, body: {} }
|
|
47634
49141
|
);
|
|
47635
49142
|
const updated = await microsoftFetch(
|
|
47636
49143
|
connector,
|
|
@@ -47638,6 +49145,7 @@ EXAMPLES:
|
|
|
47638
49145
|
{
|
|
47639
49146
|
method: "PATCH",
|
|
47640
49147
|
userId: effectiveUserId,
|
|
49148
|
+
accountId: effectiveAccountId,
|
|
47641
49149
|
body: {
|
|
47642
49150
|
subject: args.subject,
|
|
47643
49151
|
body: { contentType: "HTML", content: args.body },
|
|
@@ -47658,6 +49166,7 @@ EXAMPLES:
|
|
|
47658
49166
|
{
|
|
47659
49167
|
method: "POST",
|
|
47660
49168
|
userId: effectiveUserId,
|
|
49169
|
+
accountId: effectiveAccountId,
|
|
47661
49170
|
body: {
|
|
47662
49171
|
isDraft: true,
|
|
47663
49172
|
subject: args.subject,
|
|
@@ -47746,6 +49255,7 @@ EXAMPLES:
|
|
|
47746
49255
|
},
|
|
47747
49256
|
execute: async (args, context) => {
|
|
47748
49257
|
const effectiveUserId = context?.userId ?? userId;
|
|
49258
|
+
const effectiveAccountId = context?.accountId;
|
|
47749
49259
|
try {
|
|
47750
49260
|
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
47751
49261
|
if (args.replyToMessageId) {
|
|
@@ -47755,6 +49265,7 @@ EXAMPLES:
|
|
|
47755
49265
|
{
|
|
47756
49266
|
method: "POST",
|
|
47757
49267
|
userId: effectiveUserId,
|
|
49268
|
+
accountId: effectiveAccountId,
|
|
47758
49269
|
body: {
|
|
47759
49270
|
message: {
|
|
47760
49271
|
toRecipients: formatRecipients(args.to),
|
|
@@ -47771,6 +49282,7 @@ EXAMPLES:
|
|
|
47771
49282
|
{
|
|
47772
49283
|
method: "POST",
|
|
47773
49284
|
userId: effectiveUserId,
|
|
49285
|
+
accountId: effectiveAccountId,
|
|
47774
49286
|
body: {
|
|
47775
49287
|
message: {
|
|
47776
49288
|
subject: args.subject,
|
|
@@ -47870,6 +49382,7 @@ EXAMPLES:
|
|
|
47870
49382
|
},
|
|
47871
49383
|
execute: async (args, context) => {
|
|
47872
49384
|
const effectiveUserId = context?.userId ?? userId;
|
|
49385
|
+
const effectiveAccountId = context?.accountId;
|
|
47873
49386
|
try {
|
|
47874
49387
|
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
47875
49388
|
const tz = args.timeZone ?? "UTC";
|
|
@@ -47892,7 +49405,7 @@ EXAMPLES:
|
|
|
47892
49405
|
const event = await microsoftFetch(
|
|
47893
49406
|
connector,
|
|
47894
49407
|
`${prefix}/events`,
|
|
47895
|
-
{ method: "POST", userId: effectiveUserId, body: eventBody }
|
|
49408
|
+
{ method: "POST", userId: effectiveUserId, accountId: effectiveAccountId, body: eventBody }
|
|
47896
49409
|
);
|
|
47897
49410
|
return {
|
|
47898
49411
|
success: true,
|
|
@@ -47996,6 +49509,7 @@ EXAMPLES:
|
|
|
47996
49509
|
},
|
|
47997
49510
|
execute: async (args, context) => {
|
|
47998
49511
|
const effectiveUserId = context?.userId ?? userId;
|
|
49512
|
+
const effectiveAccountId = context?.accountId;
|
|
47999
49513
|
try {
|
|
48000
49514
|
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
48001
49515
|
const tz = args.timeZone ?? "UTC";
|
|
@@ -48019,7 +49533,7 @@ EXAMPLES:
|
|
|
48019
49533
|
const event = await microsoftFetch(
|
|
48020
49534
|
connector,
|
|
48021
49535
|
`${prefix}/events/${args.eventId}`,
|
|
48022
|
-
{ method: "PATCH", userId: effectiveUserId, body: patchBody }
|
|
49536
|
+
{ method: "PATCH", userId: effectiveUserId, accountId: effectiveAccountId, body: patchBody }
|
|
48023
49537
|
);
|
|
48024
49538
|
return {
|
|
48025
49539
|
success: true,
|
|
@@ -48092,14 +49606,15 @@ EXAMPLES:
|
|
|
48092
49606
|
},
|
|
48093
49607
|
execute: async (args, context) => {
|
|
48094
49608
|
const effectiveUserId = context?.userId ?? userId;
|
|
49609
|
+
const effectiveAccountId = context?.accountId;
|
|
48095
49610
|
try {
|
|
48096
49611
|
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
48097
|
-
const resolved = await resolveMeetingId(connector, args.meetingId, prefix, effectiveUserId);
|
|
49612
|
+
const resolved = await resolveMeetingId(connector, args.meetingId, prefix, effectiveUserId, effectiveAccountId);
|
|
48098
49613
|
const meetingId = resolved.meetingId;
|
|
48099
49614
|
const transcriptList = await microsoftFetch(
|
|
48100
49615
|
connector,
|
|
48101
49616
|
`${prefix}/onlineMeetings/${meetingId}/transcripts`,
|
|
48102
|
-
{ userId: effectiveUserId }
|
|
49617
|
+
{ userId: effectiveUserId, accountId: effectiveAccountId }
|
|
48103
49618
|
);
|
|
48104
49619
|
if (!transcriptList.value || transcriptList.value.length === 0) {
|
|
48105
49620
|
return {
|
|
@@ -48112,7 +49627,8 @@ EXAMPLES:
|
|
|
48112
49627
|
const response = await connector.fetch(
|
|
48113
49628
|
contentUrl + "?$format=text/vtt",
|
|
48114
49629
|
{ method: "GET", headers: { "Accept": "text/vtt" } },
|
|
48115
|
-
effectiveUserId
|
|
49630
|
+
effectiveUserId,
|
|
49631
|
+
effectiveAccountId
|
|
48116
49632
|
);
|
|
48117
49633
|
if (!response.ok) {
|
|
48118
49634
|
const errorText = await response.text();
|
|
@@ -48204,6 +49720,7 @@ EXAMPLES:
|
|
|
48204
49720
|
},
|
|
48205
49721
|
execute: async (args, context) => {
|
|
48206
49722
|
const effectiveUserId = context?.userId ?? userId;
|
|
49723
|
+
const effectiveAccountId = context?.accountId;
|
|
48207
49724
|
try {
|
|
48208
49725
|
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
48209
49726
|
const tz = args.timeZone ?? "UTC";
|
|
@@ -48213,6 +49730,7 @@ EXAMPLES:
|
|
|
48213
49730
|
{
|
|
48214
49731
|
method: "POST",
|
|
48215
49732
|
userId: effectiveUserId,
|
|
49733
|
+
accountId: effectiveAccountId,
|
|
48216
49734
|
body: {
|
|
48217
49735
|
attendees: formatAttendees(args.attendees),
|
|
48218
49736
|
timeConstraint: {
|
|
@@ -49141,27 +50659,42 @@ var customToolDelete = createCustomToolDelete();
|
|
|
49141
50659
|
|
|
49142
50660
|
// src/tools/custom-tools/sandboxDescription.ts
|
|
49143
50661
|
init_Connector();
|
|
49144
|
-
function formatConnectorEntry2(c) {
|
|
50662
|
+
function formatConnectorEntry2(c, accountId) {
|
|
49145
50663
|
const parts = [];
|
|
49146
50664
|
const serviceOrVendor = c.serviceType ?? c.vendor ?? void 0;
|
|
49147
50665
|
if (serviceOrVendor) parts.push(`Service: ${serviceOrVendor}`);
|
|
50666
|
+
if (accountId) parts.push(`Account: "${accountId}"`);
|
|
49148
50667
|
if (c.config.description) parts.push(c.config.description);
|
|
49149
50668
|
if (c.baseURL) parts.push(`URL: ${c.baseURL}`);
|
|
50669
|
+
const label = accountId ? `"${c.name}" account "${accountId}"` : `"${c.name}"`;
|
|
49150
50670
|
const details = parts.map((p) => ` ${p}`).join("\n");
|
|
49151
|
-
return ` \u2022
|
|
50671
|
+
return ` \u2022 ${label} (${c.displayName})
|
|
49152
50672
|
${details}`;
|
|
49153
50673
|
}
|
|
49154
50674
|
function buildConnectorList(context) {
|
|
50675
|
+
const identities = context?.identities;
|
|
49155
50676
|
const registry = context?.connectorRegistry ?? exports.Connector.asRegistry();
|
|
50677
|
+
if (identities?.length) {
|
|
50678
|
+
const entries = [];
|
|
50679
|
+
for (const id of identities) {
|
|
50680
|
+
try {
|
|
50681
|
+
const connector = registry.get(id.connector);
|
|
50682
|
+
entries.push(formatConnectorEntry2(connector, id.accountId));
|
|
50683
|
+
} catch {
|
|
50684
|
+
entries.push(` \u2022 "${id.connector}"${id.accountId ? ` account "${id.accountId}"` : ""} \u2014 not available`);
|
|
50685
|
+
}
|
|
50686
|
+
}
|
|
50687
|
+
return entries.length > 0 ? entries.join("\n\n") : " No connectors registered.";
|
|
50688
|
+
}
|
|
49156
50689
|
const connectors = registry.listAll();
|
|
49157
50690
|
if (connectors.length === 0) {
|
|
49158
50691
|
return " No connectors registered.";
|
|
49159
50692
|
}
|
|
49160
|
-
return connectors.map(formatConnectorEntry2).join("\n\n");
|
|
50693
|
+
return connectors.map((c) => formatConnectorEntry2(c)).join("\n\n");
|
|
49161
50694
|
}
|
|
49162
50695
|
var SANDBOX_API_REFERENCE = `SANDBOX API (available inside custom tool code):
|
|
49163
50696
|
|
|
49164
|
-
1. authenticatedFetch(url, options, connectorName)
|
|
50697
|
+
1. authenticatedFetch(url, options, connectorName, accountId?)
|
|
49165
50698
|
Makes authenticated HTTP requests using the connector's credentials.
|
|
49166
50699
|
Auth headers are added automatically \u2014 DO NOT set Authorization header manually.
|
|
49167
50700
|
|
|
@@ -49172,6 +50705,7 @@ var SANDBOX_API_REFERENCE = `SANDBOX API (available inside custom tool code):
|
|
|
49172
50705
|
\u2022 options: Standard fetch options { method, headers, body }
|
|
49173
50706
|
- For POST/PUT: set body to JSON.stringify(data) and headers to { 'Content-Type': 'application/json' }
|
|
49174
50707
|
\u2022 connectorName: Name of a registered connector (see REGISTERED CONNECTORS below)
|
|
50708
|
+
\u2022 accountId (optional): Account alias for multi-account connectors (e.g., 'work', 'personal')
|
|
49175
50709
|
|
|
49176
50710
|
Returns: Promise<Response>
|
|
49177
50711
|
\u2022 response.ok \u2014 true if status 200-299
|
|
@@ -50343,6 +51877,7 @@ exports.ProviderError = ProviderError;
|
|
|
50343
51877
|
exports.ProviderErrorMapper = ProviderErrorMapper;
|
|
50344
51878
|
exports.ProviderNotFoundError = ProviderNotFoundError;
|
|
50345
51879
|
exports.ProviderRateLimitError = ProviderRateLimitError;
|
|
51880
|
+
exports.ROUTINE_KEYS = ROUTINE_KEYS;
|
|
50346
51881
|
exports.RapidAPIProvider = RapidAPIProvider;
|
|
50347
51882
|
exports.RateLimitError = RateLimitError;
|
|
50348
51883
|
exports.SERVICE_DEFINITIONS = SERVICE_DEFINITIONS;
|
|
@@ -50500,6 +52035,7 @@ exports.findConnectorByServiceTypes = findConnectorByServiceTypes;
|
|
|
50500
52035
|
exports.forPlan = forPlan;
|
|
50501
52036
|
exports.forTasks = forTasks;
|
|
50502
52037
|
exports.formatAttendees = formatAttendees;
|
|
52038
|
+
exports.formatPluginDisplayName = formatPluginDisplayName;
|
|
50503
52039
|
exports.formatRecipients = formatRecipients;
|
|
50504
52040
|
exports.generateEncryptionKey = generateEncryptionKey;
|
|
50505
52041
|
exports.generateSimplePlan = generateSimplePlan;
|
|
@@ -50568,6 +52104,8 @@ exports.isErrorEvent = isErrorEvent;
|
|
|
50568
52104
|
exports.isExcludedExtension = isExcludedExtension;
|
|
50569
52105
|
exports.isKnownService = isKnownService;
|
|
50570
52106
|
exports.isOutputTextDelta = isOutputTextDelta;
|
|
52107
|
+
exports.isReasoningDelta = isReasoningDelta;
|
|
52108
|
+
exports.isReasoningDone = isReasoningDone;
|
|
50571
52109
|
exports.isResponseComplete = isResponseComplete;
|
|
50572
52110
|
exports.isSimpleScope = isSimpleScope;
|
|
50573
52111
|
exports.isStreamEvent = isStreamEvent;
|
|
@@ -50604,6 +52142,7 @@ exports.resolveMaxContextTokens = resolveMaxContextTokens;
|
|
|
50604
52142
|
exports.resolveMeetingId = resolveMeetingId;
|
|
50605
52143
|
exports.resolveModelCapabilities = resolveModelCapabilities;
|
|
50606
52144
|
exports.resolveRepository = resolveRepository;
|
|
52145
|
+
exports.resolveTemplates = resolveTemplates;
|
|
50607
52146
|
exports.retryWithBackoff = retryWithBackoff;
|
|
50608
52147
|
exports.sanitizeToolName = sanitizeToolName;
|
|
50609
52148
|
exports.scopeEquals = scopeEquals;
|