@everworker/oneringai 0.4.2 → 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 +30 -8
- package/dist/{IProvider-CNJqZItJ.d.cts → IProvider-B8sqUzJG.d.cts} +36 -6
- package/dist/{IProvider-B6hqVVq8.d.ts → IProvider-CxDUGl6n.d.ts} +36 -6
- package/dist/{ImageModel-B64HX3lN.d.cts → ImageModel-Ds5_6sf7.d.cts} +1 -1
- package/dist/{ImageModel-DU-y_WOb.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-9VOnAX17.d.ts → index-CEjKTeSb.d.cts} +857 -2
- package/dist/{index-BMjyFNJQ.d.cts → index-CzGnmqOs.d.ts} +857 -2
- package/dist/index.cjs +1303 -432
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +234 -904
- package/dist/index.d.ts +234 -904
- package/dist/index.js +1286 -417
- 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();
|
|
@@ -16742,8 +16914,8 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
16742
16914
|
_agentId;
|
|
16743
16915
|
/** User ID for multi-user scenarios */
|
|
16744
16916
|
_userId;
|
|
16745
|
-
/**
|
|
16746
|
-
|
|
16917
|
+
/** Auth identities this agent is scoped to (connector + optional accountId) */
|
|
16918
|
+
_identities;
|
|
16747
16919
|
/** Storage backend */
|
|
16748
16920
|
_storage;
|
|
16749
16921
|
/** Destroyed flag */
|
|
@@ -16783,7 +16955,7 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
16783
16955
|
this._systemPrompt = config.systemPrompt;
|
|
16784
16956
|
this._agentId = this._config.agentId;
|
|
16785
16957
|
this._userId = config.userId;
|
|
16786
|
-
this.
|
|
16958
|
+
this._identities = config.identities;
|
|
16787
16959
|
const sessionFactory = exports.StorageRegistry.get("sessions");
|
|
16788
16960
|
const storageCtx = exports.StorageRegistry.getContext() ?? (config.userId ? { userId: config.userId } : void 0);
|
|
16789
16961
|
this._storage = config.storage ?? (sessionFactory ? sessionFactory(this._agentId, storageCtx) : void 0);
|
|
@@ -16855,7 +17027,7 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
16855
17027
|
* Merges with existing ToolContext to preserve other fields (memory, signal, taskId).
|
|
16856
17028
|
*
|
|
16857
17029
|
* Connector registry resolution order:
|
|
16858
|
-
* 1. If `
|
|
17030
|
+
* 1. If `identities` is set → filtered view showing only identity connectors
|
|
16859
17031
|
* 2. If access policy + userId → scoped view via Connector.scoped()
|
|
16860
17032
|
* 3. Otherwise → full global registry
|
|
16861
17033
|
*/
|
|
@@ -16865,6 +17037,7 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
16865
17037
|
...existing,
|
|
16866
17038
|
agentId: this._agentId,
|
|
16867
17039
|
userId: this._userId,
|
|
17040
|
+
identities: this._identities,
|
|
16868
17041
|
connectorRegistry: this.buildConnectorRegistry()
|
|
16869
17042
|
});
|
|
16870
17043
|
}
|
|
@@ -16872,13 +17045,13 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
16872
17045
|
* Build the connector registry appropriate for this agent's config.
|
|
16873
17046
|
*/
|
|
16874
17047
|
buildConnectorRegistry() {
|
|
16875
|
-
if (this.
|
|
16876
|
-
const allowedSet = new Set(this.
|
|
17048
|
+
if (this._identities?.length) {
|
|
17049
|
+
const allowedSet = new Set(this._identities.map((id) => id.connector));
|
|
16877
17050
|
const base = this._userId && exports.Connector.getAccessPolicy() ? exports.Connector.scoped({ userId: this._userId }) : exports.Connector.asRegistry();
|
|
16878
17051
|
return {
|
|
16879
17052
|
get: (name) => {
|
|
16880
17053
|
if (!allowedSet.has(name)) {
|
|
16881
|
-
const available =
|
|
17054
|
+
const available = [...allowedSet].filter((n) => base.has(n)).join(", ") || "none";
|
|
16882
17055
|
throw new Error(`Connector '${name}' not found. Available: ${available}`);
|
|
16883
17056
|
}
|
|
16884
17057
|
return base.get(name);
|
|
@@ -16930,13 +17103,13 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
|
|
|
16930
17103
|
this._userId = value;
|
|
16931
17104
|
this.syncToolContext();
|
|
16932
17105
|
}
|
|
16933
|
-
/** Get the
|
|
16934
|
-
get
|
|
16935
|
-
return this.
|
|
17106
|
+
/** Get the auth identities this agent is scoped to (undefined = all visible connectors) */
|
|
17107
|
+
get identities() {
|
|
17108
|
+
return this._identities;
|
|
16936
17109
|
}
|
|
16937
|
-
/** Set
|
|
16938
|
-
set
|
|
16939
|
-
this.
|
|
17110
|
+
/** Set auth identities. Updates ToolContext.connectorRegistry and identity-aware descriptions. */
|
|
17111
|
+
set identities(value) {
|
|
17112
|
+
this._identities = value;
|
|
16940
17113
|
this.syncToolContext();
|
|
16941
17114
|
}
|
|
16942
17115
|
/** Get/set system prompt */
|
|
@@ -21415,7 +21588,7 @@ var BaseAgent = class extends eventemitter3.EventEmitter {
|
|
|
21415
21588
|
model: config.model,
|
|
21416
21589
|
agentId: config.name,
|
|
21417
21590
|
userId: config.userId,
|
|
21418
|
-
|
|
21591
|
+
identities: config.identities,
|
|
21419
21592
|
// Include storage and sessionId if session config is provided
|
|
21420
21593
|
storage: config.session?.storage,
|
|
21421
21594
|
// Thread tool execution timeout to ToolManager
|
|
@@ -21585,16 +21758,16 @@ var BaseAgent = class extends eventemitter3.EventEmitter {
|
|
|
21585
21758
|
this._agentContext.userId = value;
|
|
21586
21759
|
}
|
|
21587
21760
|
/**
|
|
21588
|
-
* Get the
|
|
21761
|
+
* Get the auth identities this agent is scoped to (undefined = all visible connectors).
|
|
21589
21762
|
*/
|
|
21590
|
-
get
|
|
21591
|
-
return this._agentContext.
|
|
21763
|
+
get identities() {
|
|
21764
|
+
return this._agentContext.identities;
|
|
21592
21765
|
}
|
|
21593
21766
|
/**
|
|
21594
|
-
*
|
|
21767
|
+
* Set auth identities at runtime. Updates ToolContext.connectorRegistry and tool descriptions.
|
|
21595
21768
|
*/
|
|
21596
|
-
set
|
|
21597
|
-
this._agentContext.
|
|
21769
|
+
set identities(value) {
|
|
21770
|
+
this._agentContext.identities = value;
|
|
21598
21771
|
}
|
|
21599
21772
|
/**
|
|
21600
21773
|
* Permission management. Returns ToolPermissionManager for approval control.
|
|
@@ -21606,9 +21779,12 @@ var BaseAgent = class extends eventemitter3.EventEmitter {
|
|
|
21606
21779
|
/**
|
|
21607
21780
|
* Add a tool to the agent.
|
|
21608
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.)
|
|
21609
21785
|
*/
|
|
21610
|
-
addTool(tool) {
|
|
21611
|
-
this._agentContext.tools.register(tool);
|
|
21786
|
+
addTool(tool, options) {
|
|
21787
|
+
this._agentContext.tools.register(tool, options);
|
|
21612
21788
|
if (tool.permission) {
|
|
21613
21789
|
this._permissionManager.setToolConfig(tool.definition.function.name, tool.permission);
|
|
21614
21790
|
}
|
|
@@ -21648,7 +21824,34 @@ var BaseAgent = class extends eventemitter3.EventEmitter {
|
|
|
21648
21824
|
*/
|
|
21649
21825
|
getEnabledToolDefinitions() {
|
|
21650
21826
|
const toolContext = this._agentContext.tools.getToolContext();
|
|
21651
|
-
|
|
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;
|
|
21652
21855
|
if (tool.descriptionFactory) {
|
|
21653
21856
|
const dynamicDescription = tool.descriptionFactory(toolContext);
|
|
21654
21857
|
return {
|
|
@@ -24033,6 +24236,7 @@ function createTask(input) {
|
|
|
24033
24236
|
suggestedTools: input.suggestedTools,
|
|
24034
24237
|
validation: input.validation,
|
|
24035
24238
|
expectedOutput: input.expectedOutput,
|
|
24239
|
+
controlFlow: input.controlFlow,
|
|
24036
24240
|
attempts: 0,
|
|
24037
24241
|
maxAttempts: input.maxAttempts ?? 3,
|
|
24038
24242
|
createdAt: now,
|
|
@@ -24285,6 +24489,7 @@ function createRoutineDefinition(input) {
|
|
|
24285
24489
|
instructions: input.instructions,
|
|
24286
24490
|
concurrency: input.concurrency,
|
|
24287
24491
|
allowDynamicTasks: input.allowDynamicTasks ?? false,
|
|
24492
|
+
parameters: input.parameters,
|
|
24288
24493
|
tags: input.tags,
|
|
24289
24494
|
author: input.author,
|
|
24290
24495
|
createdAt: now,
|
|
@@ -24500,6 +24705,321 @@ function extractNumber(text, patterns = [
|
|
|
24500
24705
|
|
|
24501
24706
|
// src/core/routineRunner.ts
|
|
24502
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
|
|
24503
25023
|
function defaultSystemPrompt(definition) {
|
|
24504
25024
|
const parts = [];
|
|
24505
25025
|
if (definition.instructions) {
|
|
@@ -24628,6 +25148,14 @@ async function collectValidationContext(agent, responseText) {
|
|
|
24628
25148
|
toolCallLog
|
|
24629
25149
|
};
|
|
24630
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
|
+
}
|
|
24631
25159
|
function estimateTokens(text) {
|
|
24632
25160
|
return Math.ceil(text.length / 4);
|
|
24633
25161
|
}
|
|
@@ -24671,32 +25199,42 @@ function buildPlanOverview(execution, definition, currentTaskId) {
|
|
|
24671
25199
|
}
|
|
24672
25200
|
return parts.join("\n");
|
|
24673
25201
|
}
|
|
24674
|
-
async function
|
|
24675
|
-
const icmPlugin = agent.context.getPlugin("in_context_memory");
|
|
24676
|
-
const wmPlugin = agent.context.memory;
|
|
24677
|
-
if (!icmPlugin && !wmPlugin) {
|
|
24678
|
-
exports.logger.warn("injectRoutineContext: No ICM or WM plugin available \u2014 skipping context injection");
|
|
24679
|
-
return;
|
|
24680
|
-
}
|
|
24681
|
-
const planOverview = buildPlanOverview(execution, definition, currentTask.id);
|
|
24682
|
-
if (icmPlugin) {
|
|
24683
|
-
icmPlugin.set("__routine_plan", "Routine plan overview with task statuses", planOverview, "high");
|
|
24684
|
-
}
|
|
25202
|
+
async function cleanupMemoryKeys(icmPlugin, wmPlugin, config) {
|
|
24685
25203
|
if (icmPlugin) {
|
|
24686
25204
|
for (const entry of icmPlugin.list()) {
|
|
24687
|
-
|
|
24688
|
-
|
|
24689
|
-
}
|
|
25205
|
+
const shouldDelete = config.icmPrefixes.some((p) => entry.key.startsWith(p)) || (config.icmExactKeys?.includes(entry.key) ?? false);
|
|
25206
|
+
if (shouldDelete) icmPlugin.delete(entry.key);
|
|
24690
25207
|
}
|
|
24691
25208
|
}
|
|
24692
25209
|
if (wmPlugin) {
|
|
24693
25210
|
const { entries: wmEntries } = await wmPlugin.query();
|
|
24694
25211
|
for (const entry of wmEntries) {
|
|
24695
|
-
if (
|
|
25212
|
+
if (config.wmPrefixes.some((p) => entry.key.startsWith(p))) {
|
|
24696
25213
|
await wmPlugin.delete(entry.key);
|
|
24697
25214
|
}
|
|
24698
25215
|
}
|
|
24699
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);
|
|
24700
25238
|
if (currentTask.dependsOn.length === 0) return;
|
|
24701
25239
|
const inContextDeps = [];
|
|
24702
25240
|
const workingMemoryDeps = [];
|
|
@@ -24705,7 +25243,7 @@ async function injectRoutineContext(agent, execution, definition, currentTask) {
|
|
|
24705
25243
|
if (!depTask?.result?.output) continue;
|
|
24706
25244
|
const output = typeof depTask.result.output === "string" ? depTask.result.output : JSON.stringify(depTask.result.output);
|
|
24707
25245
|
const tokens = estimateTokens(output);
|
|
24708
|
-
const depKey =
|
|
25246
|
+
const depKey = `${ROUTINE_KEYS.DEP_RESULT_PREFIX}${depId}`;
|
|
24709
25247
|
const depLabel = `Result from task "${depTask.name}"`;
|
|
24710
25248
|
if (tokens < 5e3 && icmPlugin) {
|
|
24711
25249
|
icmPlugin.set(depKey, depLabel, output, "high");
|
|
@@ -24727,27 +25265,12 @@ async function injectRoutineContext(agent, execution, definition, currentTask) {
|
|
|
24727
25265
|
if (workingMemoryDeps.length > 0) {
|
|
24728
25266
|
summaryParts.push(`In working memory (use memory_retrieve): ${workingMemoryDeps.join(", ")}`);
|
|
24729
25267
|
}
|
|
24730
|
-
icmPlugin.set(
|
|
25268
|
+
icmPlugin.set(ROUTINE_KEYS.DEPS, "Dependency results location guide", summaryParts.join("\n"), "high");
|
|
24731
25269
|
}
|
|
24732
25270
|
}
|
|
24733
25271
|
async function cleanupRoutineContext(agent) {
|
|
24734
|
-
const icmPlugin = agent
|
|
24735
|
-
|
|
24736
|
-
if (icmPlugin) {
|
|
24737
|
-
for (const entry of icmPlugin.list()) {
|
|
24738
|
-
if (entry.key.startsWith("__routine_") || entry.key.startsWith("__dep_result_")) {
|
|
24739
|
-
icmPlugin.delete(entry.key);
|
|
24740
|
-
}
|
|
24741
|
-
}
|
|
24742
|
-
}
|
|
24743
|
-
if (wmPlugin) {
|
|
24744
|
-
const { entries: wmEntries } = await wmPlugin.query();
|
|
24745
|
-
for (const entry of wmEntries) {
|
|
24746
|
-
if (entry.key.startsWith("__dep_result_") || entry.key.startsWith("findings/__dep_result_")) {
|
|
24747
|
-
await wmPlugin.delete(entry.key);
|
|
24748
|
-
}
|
|
24749
|
-
}
|
|
24750
|
-
}
|
|
25272
|
+
const { icmPlugin, wmPlugin } = getPlugins(agent);
|
|
25273
|
+
await cleanupMemoryKeys(icmPlugin, wmPlugin, FULL_CLEANUP_CONFIG);
|
|
24751
25274
|
}
|
|
24752
25275
|
async function validateTaskCompletion(agent, task, responseText, validationPromptBuilder) {
|
|
24753
25276
|
const hasExplicitValidation = task.validation?.skipReflection === false && task.validation?.completionCriteria && task.validation.completionCriteria.length > 0;
|
|
@@ -24796,11 +25319,13 @@ async function executeRoutine(options) {
|
|
|
24796
25319
|
onTaskFailed,
|
|
24797
25320
|
onTaskValidation,
|
|
24798
25321
|
hooks,
|
|
24799
|
-
prompts
|
|
25322
|
+
prompts,
|
|
25323
|
+
inputs: rawInputs
|
|
24800
25324
|
} = options;
|
|
24801
25325
|
if (!existingAgent && (!connector || !model)) {
|
|
24802
25326
|
throw new Error("executeRoutine requires either `agent` or both `connector` and `model`");
|
|
24803
25327
|
}
|
|
25328
|
+
const resolvedInputs = validateAndResolveInputs(definition.parameters, rawInputs);
|
|
24804
25329
|
const ownsAgent = !existingAgent;
|
|
24805
25330
|
const log = exports.logger.child({ routine: definition.name });
|
|
24806
25331
|
const execution = createRoutineExecution(definition);
|
|
@@ -24893,85 +25418,115 @@ async function executeRoutine(options) {
|
|
|
24893
25418
|
return { shouldPause: false };
|
|
24894
25419
|
};
|
|
24895
25420
|
agent.registerHook("pause:check", iterationLimiter);
|
|
24896
|
-
|
|
24897
|
-
|
|
24898
|
-
|
|
24899
|
-
|
|
24900
|
-
|
|
24901
|
-
|
|
24902
|
-
|
|
24903
|
-
|
|
24904
|
-
|
|
24905
|
-
|
|
24906
|
-
|
|
24907
|
-
|
|
24908
|
-
|
|
24909
|
-
|
|
24910
|
-
|
|
24911
|
-
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "completed");
|
|
24912
|
-
execution.plan.tasks[taskIndex].result = {
|
|
24913
|
-
success: true,
|
|
24914
|
-
output: responseText,
|
|
24915
|
-
validationScore: validationResult.completionScore,
|
|
24916
|
-
validationExplanation: validationResult.explanation
|
|
24917
|
-
};
|
|
24918
|
-
taskCompleted = true;
|
|
24919
|
-
log.info(
|
|
24920
|
-
{ taskName: getTask().name, score: validationResult.completionScore },
|
|
24921
|
-
"Task completed"
|
|
24922
|
-
);
|
|
24923
|
-
execution.progress = getRoutineProgress(execution);
|
|
24924
|
-
execution.lastUpdatedAt = Date.now();
|
|
24925
|
-
onTaskComplete?.(execution.plan.tasks[taskIndex], execution);
|
|
24926
|
-
} else {
|
|
24927
|
-
log.warn(
|
|
24928
|
-
{
|
|
24929
|
-
taskName: getTask().name,
|
|
24930
|
-
score: validationResult.completionScore,
|
|
24931
|
-
attempt: getTask().attempts,
|
|
24932
|
-
maxAttempts: getTask().maxAttempts
|
|
24933
|
-
},
|
|
24934
|
-
"Task validation failed"
|
|
24935
|
-
);
|
|
24936
|
-
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 {
|
|
24937
25436
|
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
|
|
24938
|
-
execution.plan.tasks[taskIndex].result = {
|
|
24939
|
-
success: false,
|
|
24940
|
-
error: validationResult.explanation,
|
|
24941
|
-
validationScore: validationResult.completionScore,
|
|
24942
|
-
validationExplanation: validationResult.explanation
|
|
24943
|
-
};
|
|
24944
|
-
break;
|
|
25437
|
+
execution.plan.tasks[taskIndex].result = { success: false, error: cfResult.error };
|
|
24945
25438
|
}
|
|
24946
|
-
|
|
24947
|
-
|
|
24948
|
-
|
|
24949
|
-
const errorMessage = error.message;
|
|
24950
|
-
log.error({ taskName: getTask().name, error: errorMessage }, "Task execution error");
|
|
24951
|
-
if (getTask().attempts >= getTask().maxAttempts) {
|
|
25439
|
+
} catch (error) {
|
|
25440
|
+
const errorMessage = error.message;
|
|
25441
|
+
log.error({ taskName: getTask().name, error: errorMessage }, "Control flow error");
|
|
24952
25442
|
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
|
|
24953
|
-
execution.plan.tasks[taskIndex].result = {
|
|
24954
|
-
|
|
24955
|
-
|
|
24956
|
-
|
|
24957
|
-
|
|
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
|
+
}
|
|
24958
25510
|
}
|
|
24959
|
-
execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
|
|
24960
25511
|
}
|
|
24961
|
-
|
|
24962
|
-
|
|
24963
|
-
execution.progress = getRoutineProgress(execution);
|
|
24964
|
-
execution.lastUpdatedAt = Date.now();
|
|
24965
|
-
onTaskFailed?.(execution.plan.tasks[taskIndex], execution);
|
|
24966
|
-
if (failureMode === "fail-fast") {
|
|
24967
|
-
execution.status = "failed";
|
|
24968
|
-
execution.error = `Task "${getTask().name}" failed after ${getTask().attempts} attempt(s)`;
|
|
24969
|
-
execution.completedAt = Date.now();
|
|
25512
|
+
if (!taskCompleted) {
|
|
25513
|
+
execution.progress = getRoutineProgress(execution);
|
|
24970
25514
|
execution.lastUpdatedAt = Date.now();
|
|
24971
|
-
|
|
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 {
|
|
24972
25528
|
}
|
|
24973
25529
|
}
|
|
24974
|
-
agent.unregisterHook("pause:check", iterationLimiter);
|
|
24975
25530
|
agent.clearConversation("task-boundary");
|
|
24976
25531
|
nextTasks = getNextExecutableTasks(execution.plan);
|
|
24977
25532
|
}
|
|
@@ -24999,16 +25554,22 @@ async function executeRoutine(options) {
|
|
|
24999
25554
|
} finally {
|
|
25000
25555
|
try {
|
|
25001
25556
|
await cleanupRoutineContext(agent);
|
|
25002
|
-
} catch {
|
|
25557
|
+
} catch (e) {
|
|
25558
|
+
log.debug({ error: e.message }, "Failed to clean up routine context");
|
|
25003
25559
|
}
|
|
25004
25560
|
for (const { name, hook } of registeredHooks) {
|
|
25005
25561
|
try {
|
|
25006
25562
|
agent.unregisterHook(name, hook);
|
|
25007
|
-
} catch {
|
|
25563
|
+
} catch (e) {
|
|
25564
|
+
log.debug({ hookName: name, error: e.message }, "Failed to unregister hook");
|
|
25008
25565
|
}
|
|
25009
25566
|
}
|
|
25010
25567
|
if (ownsAgent) {
|
|
25011
|
-
|
|
25568
|
+
try {
|
|
25569
|
+
agent.destroy();
|
|
25570
|
+
} catch (e) {
|
|
25571
|
+
log.debug({ error: e.message }, "Failed to destroy agent");
|
|
25572
|
+
}
|
|
25012
25573
|
}
|
|
25013
25574
|
}
|
|
25014
25575
|
}
|
|
@@ -31815,7 +32376,7 @@ var TextToSpeech = class _TextToSpeech {
|
|
|
31815
32376
|
*/
|
|
31816
32377
|
async toFile(text, filePath, options) {
|
|
31817
32378
|
const response = await this.synthesize(text, options);
|
|
31818
|
-
await
|
|
32379
|
+
await fs17__namespace.writeFile(filePath, response.audio);
|
|
31819
32380
|
}
|
|
31820
32381
|
// ======================== Introspection Methods ========================
|
|
31821
32382
|
/**
|
|
@@ -32163,7 +32724,7 @@ var SpeechToText = class _SpeechToText {
|
|
|
32163
32724
|
* @param options - Optional transcription parameters
|
|
32164
32725
|
*/
|
|
32165
32726
|
async transcribeFile(filePath, options) {
|
|
32166
|
-
const audio = await
|
|
32727
|
+
const audio = await fs17__namespace.readFile(filePath);
|
|
32167
32728
|
return this.transcribe(audio, options);
|
|
32168
32729
|
}
|
|
32169
32730
|
/**
|
|
@@ -36309,7 +36870,7 @@ var DocumentReader = class _DocumentReader {
|
|
|
36309
36870
|
async resolveSource(source) {
|
|
36310
36871
|
switch (source.type) {
|
|
36311
36872
|
case "file": {
|
|
36312
|
-
const buffer = await
|
|
36873
|
+
const buffer = await fs17.readFile(source.path);
|
|
36313
36874
|
const filename = source.path.split("/").pop() || source.path;
|
|
36314
36875
|
return { buffer, filename };
|
|
36315
36876
|
}
|
|
@@ -38906,10 +39467,10 @@ var FileMediaStorage = class {
|
|
|
38906
39467
|
}
|
|
38907
39468
|
async save(data, metadata) {
|
|
38908
39469
|
const dir = metadata.userId ? path2__namespace.join(this.outputDir, metadata.userId) : this.outputDir;
|
|
38909
|
-
await
|
|
39470
|
+
await fs17__namespace.mkdir(dir, { recursive: true });
|
|
38910
39471
|
const filename = metadata.suggestedFilename ?? this.generateFilename(metadata);
|
|
38911
39472
|
const filePath = path2__namespace.join(dir, filename);
|
|
38912
|
-
await
|
|
39473
|
+
await fs17__namespace.writeFile(filePath, data);
|
|
38913
39474
|
const format = metadata.format.toLowerCase();
|
|
38914
39475
|
const mimeType = MIME_TYPES2[format] ?? "application/octet-stream";
|
|
38915
39476
|
return {
|
|
@@ -38920,7 +39481,7 @@ var FileMediaStorage = class {
|
|
|
38920
39481
|
}
|
|
38921
39482
|
async read(location) {
|
|
38922
39483
|
try {
|
|
38923
|
-
return await
|
|
39484
|
+
return await fs17__namespace.readFile(location);
|
|
38924
39485
|
} catch (err) {
|
|
38925
39486
|
if (err.code === "ENOENT") {
|
|
38926
39487
|
return null;
|
|
@@ -38930,7 +39491,7 @@ var FileMediaStorage = class {
|
|
|
38930
39491
|
}
|
|
38931
39492
|
async delete(location) {
|
|
38932
39493
|
try {
|
|
38933
|
-
await
|
|
39494
|
+
await fs17__namespace.unlink(location);
|
|
38934
39495
|
} catch (err) {
|
|
38935
39496
|
if (err.code === "ENOENT") {
|
|
38936
39497
|
return;
|
|
@@ -38940,7 +39501,7 @@ var FileMediaStorage = class {
|
|
|
38940
39501
|
}
|
|
38941
39502
|
async exists(location) {
|
|
38942
39503
|
try {
|
|
38943
|
-
await
|
|
39504
|
+
await fs17__namespace.access(location);
|
|
38944
39505
|
return true;
|
|
38945
39506
|
} catch {
|
|
38946
39507
|
return false;
|
|
@@ -38949,11 +39510,11 @@ var FileMediaStorage = class {
|
|
|
38949
39510
|
async list(options) {
|
|
38950
39511
|
await this.ensureDir();
|
|
38951
39512
|
let entries = [];
|
|
38952
|
-
const files = await
|
|
39513
|
+
const files = await fs17__namespace.readdir(this.outputDir);
|
|
38953
39514
|
for (const file of files) {
|
|
38954
39515
|
const filePath = path2__namespace.join(this.outputDir, file);
|
|
38955
39516
|
try {
|
|
38956
|
-
const stat6 = await
|
|
39517
|
+
const stat6 = await fs17__namespace.stat(filePath);
|
|
38957
39518
|
if (!stat6.isFile()) continue;
|
|
38958
39519
|
const ext = path2__namespace.extname(file).slice(1).toLowerCase();
|
|
38959
39520
|
const mimeType = MIME_TYPES2[ext] ?? "application/octet-stream";
|
|
@@ -38993,7 +39554,7 @@ var FileMediaStorage = class {
|
|
|
38993
39554
|
}
|
|
38994
39555
|
async ensureDir() {
|
|
38995
39556
|
if (!this.initialized) {
|
|
38996
|
-
await
|
|
39557
|
+
await fs17__namespace.mkdir(this.outputDir, { recursive: true });
|
|
38997
39558
|
this.initialized = true;
|
|
38998
39559
|
}
|
|
38999
39560
|
}
|
|
@@ -39845,6 +40406,15 @@ var SERVICE_DEFINITIONS = [
|
|
|
39845
40406
|
baseURL: "https://api.telegram.org",
|
|
39846
40407
|
docsURL: "https://core.telegram.org/bots/api"
|
|
39847
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
|
+
},
|
|
39848
40418
|
// ============ Development & Project Management ============
|
|
39849
40419
|
{
|
|
39850
40420
|
id: "github",
|
|
@@ -40332,19 +40902,30 @@ var ConnectorTools = class {
|
|
|
40332
40902
|
*/
|
|
40333
40903
|
static for(connectorOrName, userId, options) {
|
|
40334
40904
|
const connector = this.resolveConnector(connectorOrName, options?.registry);
|
|
40905
|
+
const accountId = options?.accountId;
|
|
40335
40906
|
const tools = [];
|
|
40907
|
+
const namePrefix = accountId ? `${sanitizeToolName(connector.name)}_${sanitizeToolName(accountId)}` : sanitizeToolName(connector.name);
|
|
40336
40908
|
if (connector.baseURL) {
|
|
40337
|
-
|
|
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
|
+
}));
|
|
40338
40916
|
}
|
|
40339
40917
|
const serviceType = this.detectService(connector);
|
|
40340
40918
|
if (serviceType && this.factories.has(serviceType)) {
|
|
40341
40919
|
const factory = this.factories.get(serviceType);
|
|
40342
40920
|
const serviceTools = factory(connector, userId);
|
|
40343
40921
|
for (const tool of serviceTools) {
|
|
40344
|
-
tool.definition.function.name = `${
|
|
40922
|
+
tool.definition.function.name = `${namePrefix}_${tool.definition.function.name}`;
|
|
40345
40923
|
}
|
|
40346
40924
|
tools.push(...serviceTools);
|
|
40347
40925
|
}
|
|
40926
|
+
if (accountId) {
|
|
40927
|
+
return tools.map((tool) => this.bindAccountId(tool, accountId));
|
|
40928
|
+
}
|
|
40348
40929
|
return tools;
|
|
40349
40930
|
}
|
|
40350
40931
|
/**
|
|
@@ -40494,6 +41075,56 @@ var ConnectorTools = class {
|
|
|
40494
41075
|
}
|
|
40495
41076
|
return connectorOrName;
|
|
40496
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
|
+
}
|
|
40497
41128
|
static createGenericAPITool(connector, options) {
|
|
40498
41129
|
const toolName = options?.toolName ?? `${sanitizeToolName(connector.name)}_api`;
|
|
40499
41130
|
const userId = options?.userId;
|
|
@@ -40535,6 +41166,7 @@ var ConnectorTools = class {
|
|
|
40535
41166
|
},
|
|
40536
41167
|
execute: async (args, context) => {
|
|
40537
41168
|
const effectiveUserId = context?.userId ?? userId;
|
|
41169
|
+
const effectiveAccountId = context?.accountId;
|
|
40538
41170
|
let url2 = args.endpoint;
|
|
40539
41171
|
if (args.queryParams && Object.keys(args.queryParams).length > 0) {
|
|
40540
41172
|
const params = new URLSearchParams();
|
|
@@ -40567,7 +41199,8 @@ var ConnectorTools = class {
|
|
|
40567
41199
|
},
|
|
40568
41200
|
body: bodyStr
|
|
40569
41201
|
},
|
|
40570
|
-
effectiveUserId
|
|
41202
|
+
effectiveUserId,
|
|
41203
|
+
effectiveAccountId
|
|
40571
41204
|
);
|
|
40572
41205
|
const text = await response.text();
|
|
40573
41206
|
let data;
|
|
@@ -40628,8 +41261,8 @@ var FileStorage = class {
|
|
|
40628
41261
|
}
|
|
40629
41262
|
async ensureDirectory() {
|
|
40630
41263
|
try {
|
|
40631
|
-
await
|
|
40632
|
-
await
|
|
41264
|
+
await fs17__namespace.mkdir(this.directory, { recursive: true });
|
|
41265
|
+
await fs17__namespace.chmod(this.directory, 448);
|
|
40633
41266
|
} catch (error) {
|
|
40634
41267
|
}
|
|
40635
41268
|
}
|
|
@@ -40643,24 +41276,27 @@ var FileStorage = class {
|
|
|
40643
41276
|
async storeToken(key, token) {
|
|
40644
41277
|
await this.ensureDirectory();
|
|
40645
41278
|
const filePath = this.getFilePath(key);
|
|
40646
|
-
const
|
|
41279
|
+
const tokenWithKey = { ...token, _storageKey: key };
|
|
41280
|
+
const plaintext = JSON.stringify(tokenWithKey);
|
|
40647
41281
|
const encrypted = encrypt(plaintext, this.encryptionKey);
|
|
40648
|
-
await
|
|
40649
|
-
await
|
|
41282
|
+
await fs17__namespace.writeFile(filePath, encrypted, "utf8");
|
|
41283
|
+
await fs17__namespace.chmod(filePath, 384);
|
|
40650
41284
|
}
|
|
40651
41285
|
async getToken(key) {
|
|
40652
41286
|
const filePath = this.getFilePath(key);
|
|
40653
41287
|
try {
|
|
40654
|
-
const encrypted = await
|
|
41288
|
+
const encrypted = await fs17__namespace.readFile(filePath, "utf8");
|
|
40655
41289
|
const decrypted = decrypt(encrypted, this.encryptionKey);
|
|
40656
|
-
|
|
41290
|
+
const parsed = JSON.parse(decrypted);
|
|
41291
|
+
const { _storageKey, ...token } = parsed;
|
|
41292
|
+
return token;
|
|
40657
41293
|
} catch (error) {
|
|
40658
41294
|
if (error.code === "ENOENT") {
|
|
40659
41295
|
return null;
|
|
40660
41296
|
}
|
|
40661
41297
|
console.error("Failed to read/decrypt token file:", error);
|
|
40662
41298
|
try {
|
|
40663
|
-
await
|
|
41299
|
+
await fs17__namespace.unlink(filePath);
|
|
40664
41300
|
} catch {
|
|
40665
41301
|
}
|
|
40666
41302
|
return null;
|
|
@@ -40669,7 +41305,7 @@ var FileStorage = class {
|
|
|
40669
41305
|
async deleteToken(key) {
|
|
40670
41306
|
const filePath = this.getFilePath(key);
|
|
40671
41307
|
try {
|
|
40672
|
-
await
|
|
41308
|
+
await fs17__namespace.unlink(filePath);
|
|
40673
41309
|
} catch (error) {
|
|
40674
41310
|
if (error.code !== "ENOENT") {
|
|
40675
41311
|
throw error;
|
|
@@ -40679,18 +41315,44 @@ var FileStorage = class {
|
|
|
40679
41315
|
async hasToken(key) {
|
|
40680
41316
|
const filePath = this.getFilePath(key);
|
|
40681
41317
|
try {
|
|
40682
|
-
await
|
|
41318
|
+
await fs17__namespace.access(filePath);
|
|
40683
41319
|
return true;
|
|
40684
41320
|
} catch {
|
|
40685
41321
|
return false;
|
|
40686
41322
|
}
|
|
40687
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
|
+
}
|
|
40688
41350
|
/**
|
|
40689
41351
|
* List all token keys (for debugging)
|
|
40690
41352
|
*/
|
|
40691
41353
|
async listTokens() {
|
|
40692
41354
|
try {
|
|
40693
|
-
const files = await
|
|
41355
|
+
const files = await fs17__namespace.readdir(this.directory);
|
|
40694
41356
|
return files.filter((f) => f.endsWith(".token")).map((f) => f.replace(".token", ""));
|
|
40695
41357
|
} catch {
|
|
40696
41358
|
return [];
|
|
@@ -40701,10 +41363,10 @@ var FileStorage = class {
|
|
|
40701
41363
|
*/
|
|
40702
41364
|
async clearAll() {
|
|
40703
41365
|
try {
|
|
40704
|
-
const files = await
|
|
41366
|
+
const files = await fs17__namespace.readdir(this.directory);
|
|
40705
41367
|
const tokenFiles = files.filter((f) => f.endsWith(".token"));
|
|
40706
41368
|
await Promise.all(
|
|
40707
|
-
tokenFiles.map((f) =>
|
|
41369
|
+
tokenFiles.map((f) => fs17__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
|
|
40708
41370
|
}))
|
|
40709
41371
|
);
|
|
40710
41372
|
} catch {
|
|
@@ -40714,14 +41376,14 @@ var FileStorage = class {
|
|
|
40714
41376
|
|
|
40715
41377
|
// src/connectors/authenticatedFetch.ts
|
|
40716
41378
|
init_Connector();
|
|
40717
|
-
async function authenticatedFetch(url2, options, authProvider, userId) {
|
|
41379
|
+
async function authenticatedFetch(url2, options, authProvider, userId, accountId) {
|
|
40718
41380
|
const connector = exports.Connector.get(authProvider);
|
|
40719
|
-
return connector.fetch(url2.toString(), options, userId);
|
|
41381
|
+
return connector.fetch(url2.toString(), options, userId, accountId);
|
|
40720
41382
|
}
|
|
40721
|
-
function createAuthenticatedFetch(authProvider, userId) {
|
|
41383
|
+
function createAuthenticatedFetch(authProvider, userId, accountId) {
|
|
40722
41384
|
const connector = exports.Connector.get(authProvider);
|
|
40723
41385
|
return async (url2, options) => {
|
|
40724
|
-
return connector.fetch(url2.toString(), options, userId);
|
|
41386
|
+
return connector.fetch(url2.toString(), options, userId, accountId);
|
|
40725
41387
|
};
|
|
40726
41388
|
}
|
|
40727
41389
|
|
|
@@ -41152,14 +41814,14 @@ var FileConnectorStorage = class {
|
|
|
41152
41814
|
await this.ensureDirectory();
|
|
41153
41815
|
const filePath = this.getFilePath(name);
|
|
41154
41816
|
const json = JSON.stringify(stored, null, 2);
|
|
41155
|
-
await
|
|
41156
|
-
await
|
|
41817
|
+
await fs17__namespace.writeFile(filePath, json, "utf8");
|
|
41818
|
+
await fs17__namespace.chmod(filePath, 384);
|
|
41157
41819
|
await this.updateIndex(name, "add");
|
|
41158
41820
|
}
|
|
41159
41821
|
async get(name) {
|
|
41160
41822
|
const filePath = this.getFilePath(name);
|
|
41161
41823
|
try {
|
|
41162
|
-
const json = await
|
|
41824
|
+
const json = await fs17__namespace.readFile(filePath, "utf8");
|
|
41163
41825
|
return JSON.parse(json);
|
|
41164
41826
|
} catch (error) {
|
|
41165
41827
|
const err = error;
|
|
@@ -41172,7 +41834,7 @@ var FileConnectorStorage = class {
|
|
|
41172
41834
|
async delete(name) {
|
|
41173
41835
|
const filePath = this.getFilePath(name);
|
|
41174
41836
|
try {
|
|
41175
|
-
await
|
|
41837
|
+
await fs17__namespace.unlink(filePath);
|
|
41176
41838
|
await this.updateIndex(name, "remove");
|
|
41177
41839
|
return true;
|
|
41178
41840
|
} catch (error) {
|
|
@@ -41186,7 +41848,7 @@ var FileConnectorStorage = class {
|
|
|
41186
41848
|
async has(name) {
|
|
41187
41849
|
const filePath = this.getFilePath(name);
|
|
41188
41850
|
try {
|
|
41189
|
-
await
|
|
41851
|
+
await fs17__namespace.access(filePath);
|
|
41190
41852
|
return true;
|
|
41191
41853
|
} catch {
|
|
41192
41854
|
return false;
|
|
@@ -41212,13 +41874,13 @@ var FileConnectorStorage = class {
|
|
|
41212
41874
|
*/
|
|
41213
41875
|
async clear() {
|
|
41214
41876
|
try {
|
|
41215
|
-
const files = await
|
|
41877
|
+
const files = await fs17__namespace.readdir(this.directory);
|
|
41216
41878
|
const connectorFiles = files.filter(
|
|
41217
41879
|
(f) => f.endsWith(".connector.json") || f === "_index.json"
|
|
41218
41880
|
);
|
|
41219
41881
|
await Promise.all(
|
|
41220
41882
|
connectorFiles.map(
|
|
41221
|
-
(f) =>
|
|
41883
|
+
(f) => fs17__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
|
|
41222
41884
|
})
|
|
41223
41885
|
)
|
|
41224
41886
|
);
|
|
@@ -41245,8 +41907,8 @@ var FileConnectorStorage = class {
|
|
|
41245
41907
|
async ensureDirectory() {
|
|
41246
41908
|
if (this.initialized) return;
|
|
41247
41909
|
try {
|
|
41248
|
-
await
|
|
41249
|
-
await
|
|
41910
|
+
await fs17__namespace.mkdir(this.directory, { recursive: true });
|
|
41911
|
+
await fs17__namespace.chmod(this.directory, 448);
|
|
41250
41912
|
this.initialized = true;
|
|
41251
41913
|
} catch {
|
|
41252
41914
|
this.initialized = true;
|
|
@@ -41257,7 +41919,7 @@ var FileConnectorStorage = class {
|
|
|
41257
41919
|
*/
|
|
41258
41920
|
async loadIndex() {
|
|
41259
41921
|
try {
|
|
41260
|
-
const json = await
|
|
41922
|
+
const json = await fs17__namespace.readFile(this.indexPath, "utf8");
|
|
41261
41923
|
return JSON.parse(json);
|
|
41262
41924
|
} catch {
|
|
41263
41925
|
return { connectors: {} };
|
|
@@ -41275,8 +41937,8 @@ var FileConnectorStorage = class {
|
|
|
41275
41937
|
delete index.connectors[hash];
|
|
41276
41938
|
}
|
|
41277
41939
|
const json = JSON.stringify(index, null, 2);
|
|
41278
|
-
await
|
|
41279
|
-
await
|
|
41940
|
+
await fs17__namespace.writeFile(this.indexPath, json, "utf8");
|
|
41941
|
+
await fs17__namespace.chmod(this.indexPath, 384);
|
|
41280
41942
|
}
|
|
41281
41943
|
};
|
|
41282
41944
|
|
|
@@ -41499,14 +42161,15 @@ var microsoftTemplate = {
|
|
|
41499
42161
|
name: "OAuth (Delegated Permissions)",
|
|
41500
42162
|
type: "oauth",
|
|
41501
42163
|
flow: "authorization_code",
|
|
41502
|
-
description: "User signs in with Microsoft account. Best for accessing user data (mail, calendar, files)",
|
|
41503
|
-
requiredFields: ["clientId", "
|
|
41504
|
-
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"],
|
|
41505
42167
|
defaults: {
|
|
41506
42168
|
type: "oauth",
|
|
41507
42169
|
flow: "authorization_code",
|
|
41508
42170
|
authorizationUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize",
|
|
41509
|
-
tokenUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token"
|
|
42171
|
+
tokenUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token",
|
|
42172
|
+
usePKCE: true
|
|
41510
42173
|
},
|
|
41511
42174
|
scopes: [
|
|
41512
42175
|
"User.Read",
|
|
@@ -41592,14 +42255,15 @@ var googleTemplate = {
|
|
|
41592
42255
|
name: "OAuth (User Consent)",
|
|
41593
42256
|
type: "oauth",
|
|
41594
42257
|
flow: "authorization_code",
|
|
41595
|
-
description: "User logs in with Google account. Best for accessing user data (Drive, Gmail, Calendar)",
|
|
41596
|
-
requiredFields: ["clientId", "
|
|
41597
|
-
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"],
|
|
41598
42261
|
defaults: {
|
|
41599
42262
|
type: "oauth",
|
|
41600
42263
|
flow: "authorization_code",
|
|
41601
42264
|
authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
41602
|
-
tokenUrl: "https://oauth2.googleapis.com/token"
|
|
42265
|
+
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
42266
|
+
usePKCE: true
|
|
41603
42267
|
},
|
|
41604
42268
|
scopes: [
|
|
41605
42269
|
"https://www.googleapis.com/auth/drive",
|
|
@@ -41678,14 +42342,15 @@ var slackTemplate = {
|
|
|
41678
42342
|
name: "OAuth (User Token)",
|
|
41679
42343
|
type: "oauth",
|
|
41680
42344
|
flow: "authorization_code",
|
|
41681
|
-
description: "Distributed app - users authorize via Slack OAuth",
|
|
41682
|
-
requiredFields: ["clientId", "
|
|
41683
|
-
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"],
|
|
41684
42348
|
defaults: {
|
|
41685
42349
|
type: "oauth",
|
|
41686
42350
|
flow: "authorization_code",
|
|
41687
42351
|
authorizationUrl: "https://slack.com/oauth/v2/authorize",
|
|
41688
|
-
tokenUrl: "https://slack.com/api/oauth.v2.access"
|
|
42352
|
+
tokenUrl: "https://slack.com/api/oauth.v2.access",
|
|
42353
|
+
usePKCE: true
|
|
41689
42354
|
},
|
|
41690
42355
|
scopes: ["chat:write", "channels:read", "users:read", "im:write", "groups:read", "files:read", "files:write", "reactions:read", "reactions:write", "team:read"],
|
|
41691
42356
|
scopeDescriptions: {
|
|
@@ -41731,14 +42396,15 @@ var discordTemplate = {
|
|
|
41731
42396
|
name: "OAuth (User Token)",
|
|
41732
42397
|
type: "oauth",
|
|
41733
42398
|
flow: "authorization_code",
|
|
41734
|
-
description: "OAuth2 for user authorization - users grant permissions to your app",
|
|
41735
|
-
requiredFields: ["clientId", "
|
|
41736
|
-
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"],
|
|
41737
42402
|
defaults: {
|
|
41738
42403
|
type: "oauth",
|
|
41739
42404
|
flow: "authorization_code",
|
|
41740
42405
|
authorizationUrl: "https://discord.com/api/oauth2/authorize",
|
|
41741
|
-
tokenUrl: "https://discord.com/api/oauth2/token"
|
|
42406
|
+
tokenUrl: "https://discord.com/api/oauth2/token",
|
|
42407
|
+
usePKCE: true
|
|
41742
42408
|
},
|
|
41743
42409
|
scopes: ["identify", "email", "guilds", "guilds.members.read", "messages.read", "bot", "connections"],
|
|
41744
42410
|
scopeDescriptions: {
|
|
@@ -41780,6 +42446,92 @@ var telegramTemplate = {
|
|
|
41780
42446
|
]
|
|
41781
42447
|
};
|
|
41782
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
|
+
|
|
41783
42535
|
// src/connectors/vendors/templates/github.ts
|
|
41784
42536
|
var githubTemplate = {
|
|
41785
42537
|
id: "github",
|
|
@@ -41807,14 +42559,15 @@ var githubTemplate = {
|
|
|
41807
42559
|
name: "OAuth App (User Authorization)",
|
|
41808
42560
|
type: "oauth",
|
|
41809
42561
|
flow: "authorization_code",
|
|
41810
|
-
description: "User logs in via GitHub and grants permissions to your app",
|
|
41811
|
-
requiredFields: ["clientId", "
|
|
41812
|
-
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"],
|
|
41813
42565
|
defaults: {
|
|
41814
42566
|
type: "oauth",
|
|
41815
42567
|
flow: "authorization_code",
|
|
41816
42568
|
authorizationUrl: "https://github.com/login/oauth/authorize",
|
|
41817
|
-
tokenUrl: "https://github.com/login/oauth/access_token"
|
|
42569
|
+
tokenUrl: "https://github.com/login/oauth/access_token",
|
|
42570
|
+
usePKCE: true
|
|
41818
42571
|
},
|
|
41819
42572
|
scopes: ["repo", "read:user", "user:email", "read:org", "workflow", "gist", "notifications", "delete_repo", "admin:org"],
|
|
41820
42573
|
scopeDescriptions: {
|
|
@@ -41873,14 +42626,15 @@ var gitlabTemplate = {
|
|
|
41873
42626
|
name: "OAuth (User Authorization)",
|
|
41874
42627
|
type: "oauth",
|
|
41875
42628
|
flow: "authorization_code",
|
|
41876
|
-
description: "OAuth2 application for user authorization",
|
|
41877
|
-
requiredFields: ["clientId", "
|
|
41878
|
-
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"],
|
|
41879
42632
|
defaults: {
|
|
41880
42633
|
type: "oauth",
|
|
41881
42634
|
flow: "authorization_code",
|
|
41882
42635
|
authorizationUrl: "https://gitlab.com/oauth/authorize",
|
|
41883
|
-
tokenUrl: "https://gitlab.com/oauth/token"
|
|
42636
|
+
tokenUrl: "https://gitlab.com/oauth/token",
|
|
42637
|
+
usePKCE: true
|
|
41884
42638
|
},
|
|
41885
42639
|
scopes: ["api", "read_user", "read_repository", "write_repository"],
|
|
41886
42640
|
scopeDescriptions: {
|
|
@@ -41921,14 +42675,15 @@ var jiraTemplate = {
|
|
|
41921
42675
|
name: "OAuth 2.0 (3LO)",
|
|
41922
42676
|
type: "oauth",
|
|
41923
42677
|
flow: "authorization_code",
|
|
41924
|
-
description: "Three-legged OAuth for user authorization. Create app at developer.atlassian.com",
|
|
41925
|
-
requiredFields: ["clientId", "
|
|
41926
|
-
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"],
|
|
41927
42681
|
defaults: {
|
|
41928
42682
|
type: "oauth",
|
|
41929
42683
|
flow: "authorization_code",
|
|
41930
42684
|
authorizationUrl: "https://auth.atlassian.com/authorize",
|
|
41931
|
-
tokenUrl: "https://auth.atlassian.com/oauth/token"
|
|
42685
|
+
tokenUrl: "https://auth.atlassian.com/oauth/token",
|
|
42686
|
+
usePKCE: true
|
|
41932
42687
|
},
|
|
41933
42688
|
scopes: ["read:jira-work", "write:jira-work", "read:jira-user", "manage:jira-project", "manage:jira-configuration"],
|
|
41934
42689
|
scopeDescriptions: {
|
|
@@ -41968,14 +42723,15 @@ var confluenceTemplate = {
|
|
|
41968
42723
|
name: "OAuth 2.0 (3LO)",
|
|
41969
42724
|
type: "oauth",
|
|
41970
42725
|
flow: "authorization_code",
|
|
41971
|
-
description: "Three-legged OAuth for user authorization",
|
|
41972
|
-
requiredFields: ["clientId", "
|
|
41973
|
-
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"],
|
|
41974
42729
|
defaults: {
|
|
41975
42730
|
type: "oauth",
|
|
41976
42731
|
flow: "authorization_code",
|
|
41977
42732
|
authorizationUrl: "https://auth.atlassian.com/authorize",
|
|
41978
|
-
tokenUrl: "https://auth.atlassian.com/oauth/token"
|
|
42733
|
+
tokenUrl: "https://auth.atlassian.com/oauth/token",
|
|
42734
|
+
usePKCE: true
|
|
41979
42735
|
},
|
|
41980
42736
|
scopes: ["read:confluence-content.all", "write:confluence-content", "read:confluence-space.summary", "write:confluence-space", "read:confluence-user"],
|
|
41981
42737
|
scopeDescriptions: {
|
|
@@ -42014,14 +42770,15 @@ var bitbucketTemplate = {
|
|
|
42014
42770
|
name: "OAuth Consumer",
|
|
42015
42771
|
type: "oauth",
|
|
42016
42772
|
flow: "authorization_code",
|
|
42017
|
-
description: "OAuth consumer for user authorization. Create at Workspace Settings > OAuth consumers",
|
|
42018
|
-
requiredFields: ["clientId", "
|
|
42019
|
-
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"],
|
|
42020
42776
|
defaults: {
|
|
42021
42777
|
type: "oauth",
|
|
42022
42778
|
flow: "authorization_code",
|
|
42023
42779
|
authorizationUrl: "https://bitbucket.org/site/oauth2/authorize",
|
|
42024
|
-
tokenUrl: "https://bitbucket.org/site/oauth2/access_token"
|
|
42780
|
+
tokenUrl: "https://bitbucket.org/site/oauth2/access_token",
|
|
42781
|
+
usePKCE: true
|
|
42025
42782
|
},
|
|
42026
42783
|
scopes: ["repository", "repository:write", "pullrequest", "pullrequest:write", "account", "pipeline", "wiki"],
|
|
42027
42784
|
scopeDescriptions: {
|
|
@@ -42063,14 +42820,15 @@ var trelloTemplate = {
|
|
|
42063
42820
|
name: "OAuth 1.0a",
|
|
42064
42821
|
type: "oauth",
|
|
42065
42822
|
flow: "authorization_code",
|
|
42066
|
-
description: "OAuth 1.0a for user authorization (legacy)",
|
|
42067
|
-
requiredFields: ["clientId", "
|
|
42068
|
-
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"],
|
|
42069
42826
|
defaults: {
|
|
42070
42827
|
type: "oauth",
|
|
42071
42828
|
flow: "authorization_code",
|
|
42072
42829
|
authorizationUrl: "https://trello.com/1/authorize",
|
|
42073
|
-
tokenUrl: "https://trello.com/1/OAuthGetAccessToken"
|
|
42830
|
+
tokenUrl: "https://trello.com/1/OAuthGetAccessToken",
|
|
42831
|
+
usePKCE: true
|
|
42074
42832
|
},
|
|
42075
42833
|
scopes: ["read", "write", "account"],
|
|
42076
42834
|
scopeDescriptions: {
|
|
@@ -42110,14 +42868,15 @@ var linearTemplate = {
|
|
|
42110
42868
|
name: "OAuth (User Authorization)",
|
|
42111
42869
|
type: "oauth",
|
|
42112
42870
|
flow: "authorization_code",
|
|
42113
|
-
description: "OAuth application for user authorization. Create at Settings > API > OAuth applications",
|
|
42114
|
-
requiredFields: ["clientId", "
|
|
42115
|
-
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"],
|
|
42116
42874
|
defaults: {
|
|
42117
42875
|
type: "oauth",
|
|
42118
42876
|
flow: "authorization_code",
|
|
42119
42877
|
authorizationUrl: "https://linear.app/oauth/authorize",
|
|
42120
|
-
tokenUrl: "https://api.linear.app/oauth/token"
|
|
42878
|
+
tokenUrl: "https://api.linear.app/oauth/token",
|
|
42879
|
+
usePKCE: true
|
|
42121
42880
|
},
|
|
42122
42881
|
scopes: ["read", "write", "issues:create", "comments:create"]
|
|
42123
42882
|
}
|
|
@@ -42151,14 +42910,15 @@ var asanaTemplate = {
|
|
|
42151
42910
|
name: "OAuth (User Authorization)",
|
|
42152
42911
|
type: "oauth",
|
|
42153
42912
|
flow: "authorization_code",
|
|
42154
|
-
description: "OAuth application for user authorization. Create at developer console",
|
|
42155
|
-
requiredFields: ["clientId", "
|
|
42156
|
-
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"],
|
|
42157
42916
|
defaults: {
|
|
42158
42917
|
type: "oauth",
|
|
42159
42918
|
flow: "authorization_code",
|
|
42160
42919
|
authorizationUrl: "https://app.asana.com/-/oauth_authorize",
|
|
42161
|
-
tokenUrl: "https://app.asana.com/-/oauth_token"
|
|
42920
|
+
tokenUrl: "https://app.asana.com/-/oauth_token",
|
|
42921
|
+
usePKCE: true
|
|
42162
42922
|
},
|
|
42163
42923
|
scopes: ["default"]
|
|
42164
42924
|
}
|
|
@@ -42192,14 +42952,15 @@ var notionTemplate = {
|
|
|
42192
42952
|
name: "Public Integration (OAuth)",
|
|
42193
42953
|
type: "oauth",
|
|
42194
42954
|
flow: "authorization_code",
|
|
42195
|
-
description: "Public integration for multi-workspace access",
|
|
42196
|
-
requiredFields: ["clientId", "
|
|
42197
|
-
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"],
|
|
42198
42958
|
defaults: {
|
|
42199
42959
|
type: "oauth",
|
|
42200
42960
|
flow: "authorization_code",
|
|
42201
42961
|
authorizationUrl: "https://api.notion.com/v1/oauth/authorize",
|
|
42202
|
-
tokenUrl: "https://api.notion.com/v1/oauth/token"
|
|
42962
|
+
tokenUrl: "https://api.notion.com/v1/oauth/token",
|
|
42963
|
+
usePKCE: true
|
|
42203
42964
|
}
|
|
42204
42965
|
}
|
|
42205
42966
|
]
|
|
@@ -42232,9 +42993,9 @@ var airtableTemplate = {
|
|
|
42232
42993
|
name: "OAuth (User Authorization)",
|
|
42233
42994
|
type: "oauth",
|
|
42234
42995
|
flow: "authorization_code",
|
|
42235
|
-
description: "OAuth integration for multi-user access. Register at airtable.com/create/oauth",
|
|
42236
|
-
requiredFields: ["clientId", "
|
|
42237
|
-
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"],
|
|
42238
42999
|
defaults: {
|
|
42239
43000
|
type: "oauth",
|
|
42240
43001
|
flow: "authorization_code",
|
|
@@ -42263,14 +43024,15 @@ var salesforceTemplate = {
|
|
|
42263
43024
|
name: "OAuth (User Authorization)",
|
|
42264
43025
|
type: "oauth",
|
|
42265
43026
|
flow: "authorization_code",
|
|
42266
|
-
description: "User logs in via Salesforce. Create Connected App in Setup",
|
|
42267
|
-
requiredFields: ["clientId", "
|
|
42268
|
-
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"],
|
|
42269
43030
|
defaults: {
|
|
42270
43031
|
type: "oauth",
|
|
42271
43032
|
flow: "authorization_code",
|
|
42272
43033
|
authorizationUrl: "https://login.salesforce.com/services/oauth2/authorize",
|
|
42273
|
-
tokenUrl: "https://login.salesforce.com/services/oauth2/token"
|
|
43034
|
+
tokenUrl: "https://login.salesforce.com/services/oauth2/token",
|
|
43035
|
+
usePKCE: true
|
|
42274
43036
|
},
|
|
42275
43037
|
scopes: ["api", "refresh_token", "offline_access", "chatter_api", "wave_api", "full"],
|
|
42276
43038
|
scopeDescriptions: {
|
|
@@ -42326,14 +43088,15 @@ var hubspotTemplate = {
|
|
|
42326
43088
|
name: "OAuth (User Authorization)",
|
|
42327
43089
|
type: "oauth",
|
|
42328
43090
|
flow: "authorization_code",
|
|
42329
|
-
description: "Public app OAuth for multi-portal access. Create app at developers.hubspot.com",
|
|
42330
|
-
requiredFields: ["clientId", "
|
|
42331
|
-
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"],
|
|
42332
43094
|
defaults: {
|
|
42333
43095
|
type: "oauth",
|
|
42334
43096
|
flow: "authorization_code",
|
|
42335
43097
|
authorizationUrl: "https://app.hubspot.com/oauth/authorize",
|
|
42336
|
-
tokenUrl: "https://api.hubapi.com/oauth/v1/token"
|
|
43098
|
+
tokenUrl: "https://api.hubapi.com/oauth/v1/token",
|
|
43099
|
+
usePKCE: true
|
|
42337
43100
|
},
|
|
42338
43101
|
scopes: [
|
|
42339
43102
|
"crm.objects.contacts.read",
|
|
@@ -42355,6 +43118,22 @@ var hubspotTemplate = {
|
|
|
42355
43118
|
"tickets": "Read and write support tickets",
|
|
42356
43119
|
"e-commerce": "Access e-commerce data (products, line items)"
|
|
42357
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
|
+
}
|
|
42358
43137
|
}
|
|
42359
43138
|
]
|
|
42360
43139
|
};
|
|
@@ -42386,14 +43165,15 @@ var pipedriveTemplate = {
|
|
|
42386
43165
|
name: "OAuth (App Authorization)",
|
|
42387
43166
|
type: "oauth",
|
|
42388
43167
|
flow: "authorization_code",
|
|
42389
|
-
description: "OAuth app for marketplace distribution. Create at developers.pipedrive.com",
|
|
42390
|
-
requiredFields: ["clientId", "
|
|
42391
|
-
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"],
|
|
42392
43171
|
defaults: {
|
|
42393
43172
|
type: "oauth",
|
|
42394
43173
|
flow: "authorization_code",
|
|
42395
43174
|
authorizationUrl: "https://oauth.pipedrive.com/oauth/authorize",
|
|
42396
|
-
tokenUrl: "https://oauth.pipedrive.com/oauth/token"
|
|
43175
|
+
tokenUrl: "https://oauth.pipedrive.com/oauth/token",
|
|
43176
|
+
usePKCE: true
|
|
42397
43177
|
}
|
|
42398
43178
|
}
|
|
42399
43179
|
]
|
|
@@ -42426,14 +43206,15 @@ var stripeTemplate = {
|
|
|
42426
43206
|
name: "OAuth (Stripe Connect)",
|
|
42427
43207
|
type: "oauth",
|
|
42428
43208
|
flow: "authorization_code",
|
|
42429
|
-
description: "Stripe Connect for marketplace platforms. Requires Connect setup in dashboard",
|
|
42430
|
-
requiredFields: ["clientId", "
|
|
42431
|
-
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"],
|
|
42432
43212
|
defaults: {
|
|
42433
43213
|
type: "oauth",
|
|
42434
43214
|
flow: "authorization_code",
|
|
42435
43215
|
authorizationUrl: "https://connect.stripe.com/oauth/authorize",
|
|
42436
|
-
tokenUrl: "https://connect.stripe.com/oauth/token"
|
|
43216
|
+
tokenUrl: "https://connect.stripe.com/oauth/token",
|
|
43217
|
+
usePKCE: true
|
|
42437
43218
|
},
|
|
42438
43219
|
scopes: ["read_write"]
|
|
42439
43220
|
}
|
|
@@ -42483,14 +43264,15 @@ var quickbooksTemplate = {
|
|
|
42483
43264
|
name: "OAuth (User Authorization)",
|
|
42484
43265
|
type: "oauth",
|
|
42485
43266
|
flow: "authorization_code",
|
|
42486
|
-
description: "Standard OAuth 2.0 flow for accessing QuickBooks on behalf of a user. Create an app at developer.intuit.com",
|
|
42487
|
-
requiredFields: ["clientId", "
|
|
42488
|
-
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"],
|
|
42489
43270
|
defaults: {
|
|
42490
43271
|
type: "oauth",
|
|
42491
43272
|
flow: "authorization_code",
|
|
42492
43273
|
authorizationUrl: "https://appcenter.intuit.com/connect/oauth2",
|
|
42493
|
-
tokenUrl: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"
|
|
43274
|
+
tokenUrl: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
|
|
43275
|
+
usePKCE: true
|
|
42494
43276
|
},
|
|
42495
43277
|
scopes: ["com.intuit.quickbooks.accounting", "com.intuit.quickbooks.payment"]
|
|
42496
43278
|
}
|
|
@@ -42525,14 +43307,15 @@ var rampTemplate = {
|
|
|
42525
43307
|
name: "OAuth (User Authorization)",
|
|
42526
43308
|
type: "oauth",
|
|
42527
43309
|
flow: "authorization_code",
|
|
42528
|
-
description: "OAuth 2.0 authorization code flow for accessing Ramp on behalf of a user",
|
|
42529
|
-
requiredFields: ["clientId", "
|
|
42530
|
-
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"],
|
|
42531
43313
|
defaults: {
|
|
42532
43314
|
type: "oauth",
|
|
42533
43315
|
flow: "authorization_code",
|
|
42534
43316
|
authorizationUrl: "https://app.ramp.com/v1/authorize",
|
|
42535
|
-
tokenUrl: "https://api.ramp.com/developer/v1/token"
|
|
43317
|
+
tokenUrl: "https://api.ramp.com/developer/v1/token",
|
|
43318
|
+
usePKCE: true
|
|
42536
43319
|
},
|
|
42537
43320
|
scopes: [
|
|
42538
43321
|
"transactions:read",
|
|
@@ -42589,9 +43372,9 @@ var dropboxTemplate = {
|
|
|
42589
43372
|
name: "OAuth (User Authorization)",
|
|
42590
43373
|
type: "oauth",
|
|
42591
43374
|
flow: "authorization_code",
|
|
42592
|
-
description: "OAuth app for user authorization. Create app at dropbox.com/developers/apps",
|
|
42593
|
-
requiredFields: ["clientId", "
|
|
42594
|
-
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"],
|
|
42595
43378
|
defaults: {
|
|
42596
43379
|
type: "oauth",
|
|
42597
43380
|
flow: "authorization_code",
|
|
@@ -42628,14 +43411,15 @@ var boxTemplate = {
|
|
|
42628
43411
|
name: "OAuth (User Authorization)",
|
|
42629
43412
|
type: "oauth",
|
|
42630
43413
|
flow: "authorization_code",
|
|
42631
|
-
description: "OAuth 2.0 for user authorization. Create app at developer.box.com/console",
|
|
42632
|
-
requiredFields: ["clientId", "
|
|
42633
|
-
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"],
|
|
42634
43417
|
defaults: {
|
|
42635
43418
|
type: "oauth",
|
|
42636
43419
|
flow: "authorization_code",
|
|
42637
43420
|
authorizationUrl: "https://account.box.com/api/oauth2/authorize",
|
|
42638
|
-
tokenUrl: "https://api.box.com/oauth2/token"
|
|
43421
|
+
tokenUrl: "https://api.box.com/oauth2/token",
|
|
43422
|
+
usePKCE: true
|
|
42639
43423
|
},
|
|
42640
43424
|
scopes: ["root_readwrite", "manage_users", "manage_groups", "manage_enterprise"],
|
|
42641
43425
|
scopeDescriptions: {
|
|
@@ -42713,13 +43497,15 @@ var mailchimpTemplate = {
|
|
|
42713
43497
|
name: "OAuth (User Authorization)",
|
|
42714
43498
|
type: "oauth",
|
|
42715
43499
|
flow: "authorization_code",
|
|
42716
|
-
description: "OAuth for multi-account access. Register app at mailchimp.com/developer",
|
|
42717
|
-
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"],
|
|
42718
43503
|
defaults: {
|
|
42719
43504
|
type: "oauth",
|
|
42720
43505
|
flow: "authorization_code",
|
|
42721
43506
|
authorizationUrl: "https://login.mailchimp.com/oauth2/authorize",
|
|
42722
|
-
tokenUrl: "https://login.mailchimp.com/oauth2/token"
|
|
43507
|
+
tokenUrl: "https://login.mailchimp.com/oauth2/token",
|
|
43508
|
+
usePKCE: true
|
|
42723
43509
|
}
|
|
42724
43510
|
}
|
|
42725
43511
|
]
|
|
@@ -42811,14 +43597,15 @@ var pagerdutyTemplate = {
|
|
|
42811
43597
|
name: "OAuth (App Authorization)",
|
|
42812
43598
|
type: "oauth",
|
|
42813
43599
|
flow: "authorization_code",
|
|
42814
|
-
description: "OAuth app for multi-account access. Register at developer.pagerduty.com",
|
|
42815
|
-
requiredFields: ["clientId", "
|
|
42816
|
-
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"],
|
|
42817
43603
|
defaults: {
|
|
42818
43604
|
type: "oauth",
|
|
42819
43605
|
flow: "authorization_code",
|
|
42820
43606
|
authorizationUrl: "https://app.pagerduty.com/oauth/authorize",
|
|
42821
|
-
tokenUrl: "https://app.pagerduty.com/oauth/token"
|
|
43607
|
+
tokenUrl: "https://app.pagerduty.com/oauth/token",
|
|
43608
|
+
usePKCE: true
|
|
42822
43609
|
},
|
|
42823
43610
|
scopes: ["read", "write"],
|
|
42824
43611
|
scopeDescriptions: {
|
|
@@ -42854,14 +43641,15 @@ var sentryTemplate = {
|
|
|
42854
43641
|
name: "OAuth (Integration)",
|
|
42855
43642
|
type: "oauth",
|
|
42856
43643
|
flow: "authorization_code",
|
|
42857
|
-
description: "OAuth integration. Create at Organization Settings > Integrations",
|
|
42858
|
-
requiredFields: ["clientId", "
|
|
42859
|
-
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"],
|
|
42860
43647
|
defaults: {
|
|
42861
43648
|
type: "oauth",
|
|
42862
43649
|
flow: "authorization_code",
|
|
42863
43650
|
authorizationUrl: "https://sentry.io/oauth/authorize/",
|
|
42864
|
-
tokenUrl: "https://sentry.io/oauth/token/"
|
|
43651
|
+
tokenUrl: "https://sentry.io/oauth/token/",
|
|
43652
|
+
usePKCE: true
|
|
42865
43653
|
},
|
|
42866
43654
|
scopes: ["project:read", "project:write", "event:read", "org:read", "member:read"],
|
|
42867
43655
|
scopeDescriptions: {
|
|
@@ -43058,14 +43846,15 @@ var zendeskTemplate = {
|
|
|
43058
43846
|
name: "OAuth (User Authorization)",
|
|
43059
43847
|
type: "oauth",
|
|
43060
43848
|
flow: "authorization_code",
|
|
43061
|
-
description: "OAuth client for user authorization. Create at Admin > Channels > API > OAuth Clients",
|
|
43062
|
-
requiredFields: ["clientId", "
|
|
43063
|
-
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"],
|
|
43064
43852
|
defaults: {
|
|
43065
43853
|
type: "oauth",
|
|
43066
43854
|
flow: "authorization_code",
|
|
43067
43855
|
authorizationUrl: "https://{subdomain}.zendesk.com/oauth/authorizations/new",
|
|
43068
|
-
tokenUrl: "https://{subdomain}.zendesk.com/oauth/tokens"
|
|
43856
|
+
tokenUrl: "https://{subdomain}.zendesk.com/oauth/tokens",
|
|
43857
|
+
usePKCE: true
|
|
43069
43858
|
},
|
|
43070
43859
|
scopes: ["read", "write", "tickets:read", "tickets:write"],
|
|
43071
43860
|
scopeDescriptions: {
|
|
@@ -43103,13 +43892,15 @@ var intercomTemplate = {
|
|
|
43103
43892
|
name: "OAuth (App Installation)",
|
|
43104
43893
|
type: "oauth",
|
|
43105
43894
|
flow: "authorization_code",
|
|
43106
|
-
description: "OAuth for Intercom app marketplace distribution",
|
|
43107
|
-
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"],
|
|
43108
43898
|
defaults: {
|
|
43109
43899
|
type: "oauth",
|
|
43110
43900
|
flow: "authorization_code",
|
|
43111
43901
|
authorizationUrl: "https://app.intercom.com/oauth",
|
|
43112
|
-
tokenUrl: "https://api.intercom.io/auth/eagle/token"
|
|
43902
|
+
tokenUrl: "https://api.intercom.io/auth/eagle/token",
|
|
43903
|
+
usePKCE: true
|
|
43113
43904
|
}
|
|
43114
43905
|
}
|
|
43115
43906
|
]
|
|
@@ -43142,14 +43933,15 @@ var shopifyTemplate = {
|
|
|
43142
43933
|
name: "OAuth (Public/Custom App)",
|
|
43143
43934
|
type: "oauth",
|
|
43144
43935
|
flow: "authorization_code",
|
|
43145
|
-
description: "OAuth for public apps or per-store custom apps. Create at partners.shopify.com",
|
|
43146
|
-
requiredFields: ["clientId", "
|
|
43147
|
-
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"],
|
|
43148
43939
|
defaults: {
|
|
43149
43940
|
type: "oauth",
|
|
43150
43941
|
flow: "authorization_code",
|
|
43151
43942
|
authorizationUrl: "https://{subdomain}.myshopify.com/admin/oauth/authorize",
|
|
43152
|
-
tokenUrl: "https://{subdomain}.myshopify.com/admin/oauth/access_token"
|
|
43943
|
+
tokenUrl: "https://{subdomain}.myshopify.com/admin/oauth/access_token",
|
|
43944
|
+
usePKCE: true
|
|
43153
43945
|
},
|
|
43154
43946
|
scopes: ["read_products", "write_products", "read_orders", "write_orders", "read_customers", "write_customers", "read_inventory", "write_inventory", "read_fulfillments", "write_fulfillments"],
|
|
43155
43947
|
scopeDescriptions: {
|
|
@@ -43177,6 +43969,7 @@ var allVendorTemplates = [
|
|
|
43177
43969
|
slackTemplate,
|
|
43178
43970
|
discordTemplate,
|
|
43179
43971
|
telegramTemplate,
|
|
43972
|
+
twitterTemplate,
|
|
43180
43973
|
// Development
|
|
43181
43974
|
githubTemplate,
|
|
43182
43975
|
gitlabTemplate,
|
|
@@ -43236,6 +44029,7 @@ var VENDOR_ICON_MAP = {
|
|
|
43236
44029
|
discord: "discord",
|
|
43237
44030
|
slack: "slack",
|
|
43238
44031
|
telegram: "telegram",
|
|
44032
|
+
twitter: "x",
|
|
43239
44033
|
"microsoft-teams": "microsoftteams",
|
|
43240
44034
|
// CRM
|
|
43241
44035
|
salesforce: "salesforce",
|
|
@@ -43300,6 +44094,7 @@ var FALLBACK_PLACEHOLDERS = {
|
|
|
43300
44094
|
// Communication (trademark removed)
|
|
43301
44095
|
slack: { color: "#4A154B", letter: "S" },
|
|
43302
44096
|
"microsoft-teams": { color: "#6264A7", letter: "T" },
|
|
44097
|
+
twitter: { color: "#000000", letter: "X" },
|
|
43303
44098
|
// CRM (trademark removed)
|
|
43304
44099
|
salesforce: { color: "#00A1E0", letter: "S" },
|
|
43305
44100
|
pipedrive: { color: "#1A1F26", letter: "P" },
|
|
@@ -44237,7 +45032,7 @@ EXAMPLES:
|
|
|
44237
45032
|
};
|
|
44238
45033
|
}
|
|
44239
45034
|
try {
|
|
44240
|
-
const stats = await
|
|
45035
|
+
const stats = await fs17.stat(resolvedPath);
|
|
44241
45036
|
if (!stats.isFile()) {
|
|
44242
45037
|
return {
|
|
44243
45038
|
success: false,
|
|
@@ -44279,7 +45074,7 @@ EXAMPLES:
|
|
|
44279
45074
|
} catch {
|
|
44280
45075
|
}
|
|
44281
45076
|
}
|
|
44282
|
-
const content = await
|
|
45077
|
+
const content = await fs17.readFile(resolvedPath, "utf-8");
|
|
44283
45078
|
const allLines = content.split("\n");
|
|
44284
45079
|
const totalLines = allLines.length;
|
|
44285
45080
|
const startIndex = Math.max(0, offset - 1);
|
|
@@ -44388,9 +45183,9 @@ EXAMPLES:
|
|
|
44388
45183
|
try {
|
|
44389
45184
|
const parentDir = path2.dirname(resolvedPath);
|
|
44390
45185
|
if (!fs19.existsSync(parentDir)) {
|
|
44391
|
-
await
|
|
45186
|
+
await fs17.mkdir(parentDir, { recursive: true });
|
|
44392
45187
|
}
|
|
44393
|
-
await
|
|
45188
|
+
await fs17.writeFile(resolvedPath, content, "utf-8");
|
|
44394
45189
|
return {
|
|
44395
45190
|
success: true,
|
|
44396
45191
|
path: file_path,
|
|
@@ -44501,7 +45296,7 @@ EXAMPLES:
|
|
|
44501
45296
|
};
|
|
44502
45297
|
}
|
|
44503
45298
|
try {
|
|
44504
|
-
const content = await
|
|
45299
|
+
const content = await fs17.readFile(resolvedPath, "utf-8");
|
|
44505
45300
|
let occurrences = 0;
|
|
44506
45301
|
let searchIndex = 0;
|
|
44507
45302
|
while (true) {
|
|
@@ -44540,7 +45335,7 @@ EXAMPLES:
|
|
|
44540
45335
|
} else {
|
|
44541
45336
|
newContent = content.replace(old_string, new_string);
|
|
44542
45337
|
}
|
|
44543
|
-
await
|
|
45338
|
+
await fs17.writeFile(resolvedPath, newContent, "utf-8");
|
|
44544
45339
|
const diffPreview = generateDiffPreview(old_string, new_string);
|
|
44545
45340
|
return {
|
|
44546
45341
|
success: true,
|
|
@@ -44596,7 +45391,7 @@ async function findFiles(dir, pattern, baseDir, config, results = [], depth = 0)
|
|
|
44596
45391
|
return results;
|
|
44597
45392
|
}
|
|
44598
45393
|
try {
|
|
44599
|
-
const entries = await
|
|
45394
|
+
const entries = await fs17.readdir(dir, { withFileTypes: true });
|
|
44600
45395
|
for (const entry of entries) {
|
|
44601
45396
|
if (results.length >= config.maxResults) break;
|
|
44602
45397
|
const fullPath = path2.join(dir, entry.name);
|
|
@@ -44610,7 +45405,7 @@ async function findFiles(dir, pattern, baseDir, config, results = [], depth = 0)
|
|
|
44610
45405
|
} else if (entry.isFile()) {
|
|
44611
45406
|
if (matchGlobPattern(pattern, relativePath)) {
|
|
44612
45407
|
try {
|
|
44613
|
-
const stats = await
|
|
45408
|
+
const stats = await fs17.stat(fullPath);
|
|
44614
45409
|
results.push({
|
|
44615
45410
|
path: relativePath,
|
|
44616
45411
|
mtime: stats.mtimeMs
|
|
@@ -44747,7 +45542,7 @@ async function findFilesToSearch(dir, baseDir, config, globPattern, fileType, fi
|
|
|
44747
45542
|
return files;
|
|
44748
45543
|
}
|
|
44749
45544
|
try {
|
|
44750
|
-
const entries = await
|
|
45545
|
+
const entries = await fs17.readdir(dir, { withFileTypes: true });
|
|
44751
45546
|
for (const entry of entries) {
|
|
44752
45547
|
const fullPath = path2.join(dir, entry.name);
|
|
44753
45548
|
if (entry.isDirectory()) {
|
|
@@ -44780,7 +45575,7 @@ async function findFilesToSearch(dir, baseDir, config, globPattern, fileType, fi
|
|
|
44780
45575
|
async function searchFile(filePath, regex, contextBefore, contextAfter) {
|
|
44781
45576
|
const matches = [];
|
|
44782
45577
|
try {
|
|
44783
|
-
const content = await
|
|
45578
|
+
const content = await fs17.readFile(filePath, "utf-8");
|
|
44784
45579
|
const lines = content.split("\n");
|
|
44785
45580
|
for (let i = 0; i < lines.length; i++) {
|
|
44786
45581
|
const line = lines[i] ?? "";
|
|
@@ -44937,7 +45732,7 @@ WHEN TO USE:
|
|
|
44937
45732
|
};
|
|
44938
45733
|
}
|
|
44939
45734
|
try {
|
|
44940
|
-
const stats = await
|
|
45735
|
+
const stats = await fs17.stat(resolvedPath);
|
|
44941
45736
|
let filesToSearch;
|
|
44942
45737
|
if (stats.isFile()) {
|
|
44943
45738
|
filesToSearch = [resolvedPath];
|
|
@@ -45025,7 +45820,7 @@ async function listDir(dir, baseDir, config, recursive, filter, maxDepth = 3, cu
|
|
|
45025
45820
|
return entries;
|
|
45026
45821
|
}
|
|
45027
45822
|
try {
|
|
45028
|
-
const dirEntries = await
|
|
45823
|
+
const dirEntries = await fs17.readdir(dir, { withFileTypes: true });
|
|
45029
45824
|
for (const entry of dirEntries) {
|
|
45030
45825
|
if (entries.length >= config.maxResults) break;
|
|
45031
45826
|
const fullPath = path2.join(dir, entry.name);
|
|
@@ -45043,7 +45838,7 @@ async function listDir(dir, baseDir, config, recursive, filter, maxDepth = 3, cu
|
|
|
45043
45838
|
}
|
|
45044
45839
|
if (filter === "directories" && !isDir) continue;
|
|
45045
45840
|
try {
|
|
45046
|
-
const stats = await
|
|
45841
|
+
const stats = await fs17.stat(fullPath);
|
|
45047
45842
|
const dirEntry = {
|
|
45048
45843
|
name: entry.name,
|
|
45049
45844
|
path: relativePath,
|
|
@@ -45146,7 +45941,7 @@ EXAMPLES:
|
|
|
45146
45941
|
};
|
|
45147
45942
|
}
|
|
45148
45943
|
try {
|
|
45149
|
-
const stats = await
|
|
45944
|
+
const stats = await fs17.stat(resolvedPath);
|
|
45150
45945
|
if (!stats.isDirectory()) {
|
|
45151
45946
|
return {
|
|
45152
45947
|
success: false,
|
|
@@ -46469,21 +47264,53 @@ registerWebTools();
|
|
|
46469
47264
|
init_Connector();
|
|
46470
47265
|
var DEFAULT_TIMEOUT = 1e4;
|
|
46471
47266
|
var DEFAULT_MAX_TIMEOUT = 3e4;
|
|
46472
|
-
function formatConnectorEntry(c) {
|
|
47267
|
+
function formatConnectorEntry(c, accountId) {
|
|
46473
47268
|
const parts = [];
|
|
46474
47269
|
const serviceOrVendor = c.serviceType ?? c.vendor ?? void 0;
|
|
46475
47270
|
if (serviceOrVendor) parts.push(`Service: ${serviceOrVendor}`);
|
|
47271
|
+
if (accountId) parts.push(`Account: "${accountId}"`);
|
|
46476
47272
|
if (c.config.description) parts.push(c.config.description);
|
|
46477
47273
|
if (c.baseURL) parts.push(`URL: ${c.baseURL}`);
|
|
47274
|
+
const label = accountId ? `"${c.name}" account "${accountId}"` : `"${c.name}"`;
|
|
46478
47275
|
const details = parts.map((p) => ` ${p}`).join("\n");
|
|
46479
|
-
return ` \u2022
|
|
47276
|
+
return ` \u2022 ${label} (${c.displayName})
|
|
46480
47277
|
${details}`;
|
|
46481
47278
|
}
|
|
46482
|
-
function
|
|
47279
|
+
function buildIdentityList(context) {
|
|
47280
|
+
const identities = context?.identities;
|
|
46483
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
|
+
}
|
|
46484
47294
|
const connectors = registry.listAll();
|
|
46485
|
-
|
|
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);
|
|
46486
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
|
+
` : "";
|
|
46487
47314
|
return `Execute JavaScript code in a secure sandbox with authenticated API access to external services.
|
|
46488
47315
|
|
|
46489
47316
|
Use this tool when you need to:
|
|
@@ -46494,7 +47321,7 @@ Use this tool when you need to:
|
|
|
46494
47321
|
|
|
46495
47322
|
SANDBOX API:
|
|
46496
47323
|
|
|
46497
|
-
1. authenticatedFetch(url, options, connectorName)
|
|
47324
|
+
1. authenticatedFetch(url, options, connectorName${showAccountId ? ", accountId?" : ""})
|
|
46498
47325
|
Makes authenticated HTTP requests using the connector's credentials.
|
|
46499
47326
|
The current user's identity (userId) is automatically included \u2014 no need to pass it.
|
|
46500
47327
|
Auth headers are added automatically \u2014 DO NOT set Authorization header manually.
|
|
@@ -46505,7 +47332,7 @@ SANDBOX API:
|
|
|
46505
47332
|
- Relative: "/user/repos" (resolved against connector's base URL)
|
|
46506
47333
|
\u2022 options: Standard fetch options { method, headers, body }
|
|
46507
47334
|
- For POST/PUT: set body to JSON.stringify(data) and headers to { 'Content-Type': 'application/json' }
|
|
46508
|
-
\u2022 connectorName: Name of a registered connector (see list below)
|
|
47335
|
+
\u2022 connectorName: Name of a registered connector (see list below)${accountIdParam}
|
|
46509
47336
|
|
|
46510
47337
|
Returns: Promise<Response>
|
|
46511
47338
|
\u2022 response.ok \u2014 true if status 200-299
|
|
@@ -46541,7 +47368,7 @@ const resp = await authenticatedFetch('/chat.postMessage', {
|
|
|
46541
47368
|
body: JSON.stringify({ channel: '#general', text: 'Hello!' })
|
|
46542
47369
|
}, 'slack');
|
|
46543
47370
|
output = await resp.json();
|
|
46544
|
-
|
|
47371
|
+
${accountIdExamples}
|
|
46545
47372
|
// Data processing (no API needed)
|
|
46546
47373
|
const items = input.data;
|
|
46547
47374
|
output = items.filter(i => i.score > 0.8).sort((a, b) => b.score - a.score);
|
|
@@ -46629,9 +47456,10 @@ async function executeInVM(code, input, timeout, logs, userId, registry) {
|
|
|
46629
47456
|
},
|
|
46630
47457
|
// Authenticated fetch — userId auto-injected from ToolContext.
|
|
46631
47458
|
// Only connectors visible in the scoped registry are accessible.
|
|
46632
|
-
|
|
47459
|
+
// Optional 4th param accountId for multi-account OAuth identities.
|
|
47460
|
+
authenticatedFetch: (url2, options, connectorName, accountId) => {
|
|
46633
47461
|
registry.get(connectorName);
|
|
46634
|
-
return authenticatedFetch(url2, options, connectorName, userId);
|
|
47462
|
+
return authenticatedFetch(url2, options, connectorName, userId, accountId);
|
|
46635
47463
|
},
|
|
46636
47464
|
// Standard fetch (no auth)
|
|
46637
47465
|
fetch: globalThis.fetch,
|
|
@@ -47319,7 +48147,8 @@ async function githubFetch(connector, endpoint, options) {
|
|
|
47319
48147
|
headers,
|
|
47320
48148
|
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
47321
48149
|
},
|
|
47322
|
-
options?.userId
|
|
48150
|
+
options?.userId,
|
|
48151
|
+
options?.accountId
|
|
47323
48152
|
);
|
|
47324
48153
|
const text = await response.text();
|
|
47325
48154
|
let data;
|
|
@@ -47401,6 +48230,7 @@ EXAMPLES:
|
|
|
47401
48230
|
},
|
|
47402
48231
|
execute: async (args, context) => {
|
|
47403
48232
|
const effectiveUserId = context?.userId ?? userId;
|
|
48233
|
+
const effectiveAccountId = context?.accountId;
|
|
47404
48234
|
const resolved = resolveRepository(args.repository, connector);
|
|
47405
48235
|
if (!resolved.success) {
|
|
47406
48236
|
return { success: false, error: resolved.error };
|
|
@@ -47412,7 +48242,7 @@ EXAMPLES:
|
|
|
47412
48242
|
const repoInfo = await githubFetch(
|
|
47413
48243
|
connector,
|
|
47414
48244
|
`/repos/${owner}/${repo}`,
|
|
47415
|
-
{ userId: effectiveUserId }
|
|
48245
|
+
{ userId: effectiveUserId, accountId: effectiveAccountId }
|
|
47416
48246
|
);
|
|
47417
48247
|
ref = repoInfo.default_branch;
|
|
47418
48248
|
}
|
|
@@ -47512,6 +48342,7 @@ EXAMPLES:
|
|
|
47512
48342
|
},
|
|
47513
48343
|
execute: async (args, context) => {
|
|
47514
48344
|
const effectiveUserId = context?.userId ?? userId;
|
|
48345
|
+
const effectiveAccountId = context?.accountId;
|
|
47515
48346
|
const resolved = resolveRepository(args.repository, connector);
|
|
47516
48347
|
if (!resolved.success) {
|
|
47517
48348
|
return { success: false, error: resolved.error };
|
|
@@ -47529,6 +48360,7 @@ EXAMPLES:
|
|
|
47529
48360
|
`/search/code`,
|
|
47530
48361
|
{
|
|
47531
48362
|
userId: effectiveUserId,
|
|
48363
|
+
accountId: effectiveAccountId,
|
|
47532
48364
|
// Request text-match fragments
|
|
47533
48365
|
accept: "application/vnd.github.text-match+json",
|
|
47534
48366
|
queryParams: { q, per_page: perPage }
|
|
@@ -47617,6 +48449,7 @@ NOTE: Files larger than 1MB are fetched via the Git Blob API. Very large files (
|
|
|
47617
48449
|
},
|
|
47618
48450
|
execute: async (args, context) => {
|
|
47619
48451
|
const effectiveUserId = context?.userId ?? userId;
|
|
48452
|
+
const effectiveAccountId = context?.accountId;
|
|
47620
48453
|
const resolved = resolveRepository(args.repository, connector);
|
|
47621
48454
|
if (!resolved.success) {
|
|
47622
48455
|
return { success: false, error: resolved.error };
|
|
@@ -47630,7 +48463,7 @@ NOTE: Files larger than 1MB are fetched via the Git Blob API. Very large files (
|
|
|
47630
48463
|
const contentResp = await githubFetch(
|
|
47631
48464
|
connector,
|
|
47632
48465
|
`/repos/${owner}/${repo}/contents/${args.path}${refParam}`,
|
|
47633
|
-
{ userId: effectiveUserId }
|
|
48466
|
+
{ userId: effectiveUserId, accountId: effectiveAccountId }
|
|
47634
48467
|
);
|
|
47635
48468
|
if (contentResp.type !== "file") {
|
|
47636
48469
|
return {
|
|
@@ -47647,7 +48480,7 @@ NOTE: Files larger than 1MB are fetched via the Git Blob API. Very large files (
|
|
|
47647
48480
|
const blob = await githubFetch(
|
|
47648
48481
|
connector,
|
|
47649
48482
|
contentResp.git_url,
|
|
47650
|
-
{ userId: effectiveUserId }
|
|
48483
|
+
{ userId: effectiveUserId, accountId: effectiveAccountId }
|
|
47651
48484
|
);
|
|
47652
48485
|
fileContent = Buffer.from(blob.content, "base64").toString("utf-8");
|
|
47653
48486
|
fileSize = blob.size;
|
|
@@ -47736,6 +48569,7 @@ EXAMPLES:
|
|
|
47736
48569
|
},
|
|
47737
48570
|
execute: async (args, context) => {
|
|
47738
48571
|
const effectiveUserId = context?.userId ?? userId;
|
|
48572
|
+
const effectiveAccountId = context?.accountId;
|
|
47739
48573
|
const resolved = resolveRepository(args.repository, connector);
|
|
47740
48574
|
if (!resolved.success) {
|
|
47741
48575
|
return { success: false, error: resolved.error };
|
|
@@ -47745,7 +48579,7 @@ EXAMPLES:
|
|
|
47745
48579
|
const pr = await githubFetch(
|
|
47746
48580
|
connector,
|
|
47747
48581
|
`/repos/${owner}/${repo}/pulls/${args.pull_number}`,
|
|
47748
|
-
{ userId: effectiveUserId }
|
|
48582
|
+
{ userId: effectiveUserId, accountId: effectiveAccountId }
|
|
47749
48583
|
);
|
|
47750
48584
|
return {
|
|
47751
48585
|
success: true,
|
|
@@ -47823,6 +48657,7 @@ NOTE: Very large diffs may be truncated by GitHub. Patch content may be absent f
|
|
|
47823
48657
|
},
|
|
47824
48658
|
execute: async (args, context) => {
|
|
47825
48659
|
const effectiveUserId = context?.userId ?? userId;
|
|
48660
|
+
const effectiveAccountId = context?.accountId;
|
|
47826
48661
|
const resolved = resolveRepository(args.repository, connector);
|
|
47827
48662
|
if (!resolved.success) {
|
|
47828
48663
|
return { success: false, error: resolved.error };
|
|
@@ -47834,6 +48669,7 @@ NOTE: Very large diffs may be truncated by GitHub. Patch content may be absent f
|
|
|
47834
48669
|
`/repos/${owner}/${repo}/pulls/${args.pull_number}/files`,
|
|
47835
48670
|
{
|
|
47836
48671
|
userId: effectiveUserId,
|
|
48672
|
+
accountId: effectiveAccountId,
|
|
47837
48673
|
queryParams: { per_page: 100 }
|
|
47838
48674
|
}
|
|
47839
48675
|
);
|
|
@@ -47906,6 +48742,7 @@ EXAMPLES:
|
|
|
47906
48742
|
},
|
|
47907
48743
|
execute: async (args, context) => {
|
|
47908
48744
|
const effectiveUserId = context?.userId ?? userId;
|
|
48745
|
+
const effectiveAccountId = context?.accountId;
|
|
47909
48746
|
const resolved = resolveRepository(args.repository, connector);
|
|
47910
48747
|
if (!resolved.success) {
|
|
47911
48748
|
return { success: false, error: resolved.error };
|
|
@@ -47913,7 +48750,7 @@ EXAMPLES:
|
|
|
47913
48750
|
const { owner, repo } = resolved.repo;
|
|
47914
48751
|
try {
|
|
47915
48752
|
const basePath = `/repos/${owner}/${repo}`;
|
|
47916
|
-
const queryOpts = { userId: effectiveUserId, queryParams: { per_page: 100 } };
|
|
48753
|
+
const queryOpts = { userId: effectiveUserId, accountId: effectiveAccountId, queryParams: { per_page: 100 } };
|
|
47917
48754
|
const [reviewComments, reviews, issueComments] = await Promise.all([
|
|
47918
48755
|
githubFetch(
|
|
47919
48756
|
connector,
|
|
@@ -48042,6 +48879,7 @@ EXAMPLES:
|
|
|
48042
48879
|
},
|
|
48043
48880
|
execute: async (args, context) => {
|
|
48044
48881
|
const effectiveUserId = context?.userId ?? userId;
|
|
48882
|
+
const effectiveAccountId = context?.accountId;
|
|
48045
48883
|
const resolved = resolveRepository(args.repository, connector);
|
|
48046
48884
|
if (!resolved.success) {
|
|
48047
48885
|
return { success: false, error: resolved.error };
|
|
@@ -48054,6 +48892,7 @@ EXAMPLES:
|
|
|
48054
48892
|
{
|
|
48055
48893
|
method: "POST",
|
|
48056
48894
|
userId: effectiveUserId,
|
|
48895
|
+
accountId: effectiveAccountId,
|
|
48057
48896
|
body: {
|
|
48058
48897
|
title: args.title,
|
|
48059
48898
|
body: args.body,
|
|
@@ -48145,7 +48984,8 @@ async function microsoftFetch(connector, endpoint, options) {
|
|
|
48145
48984
|
headers,
|
|
48146
48985
|
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
48147
48986
|
},
|
|
48148
|
-
options?.userId
|
|
48987
|
+
options?.userId,
|
|
48988
|
+
options?.accountId
|
|
48149
48989
|
);
|
|
48150
48990
|
const text = await response.text();
|
|
48151
48991
|
if (!response.ok) {
|
|
@@ -48198,7 +49038,7 @@ function isTeamsMeetingUrl(input) {
|
|
|
48198
49038
|
return false;
|
|
48199
49039
|
}
|
|
48200
49040
|
}
|
|
48201
|
-
async function resolveMeetingId(connector, input, prefix, effectiveUserId) {
|
|
49041
|
+
async function resolveMeetingId(connector, input, prefix, effectiveUserId, effectiveAccountId) {
|
|
48202
49042
|
if (!input || input.trim().length === 0) {
|
|
48203
49043
|
throw new Error("Meeting ID cannot be empty");
|
|
48204
49044
|
}
|
|
@@ -48211,6 +49051,7 @@ async function resolveMeetingId(connector, input, prefix, effectiveUserId) {
|
|
|
48211
49051
|
`${prefix}/onlineMeetings`,
|
|
48212
49052
|
{
|
|
48213
49053
|
userId: effectiveUserId,
|
|
49054
|
+
accountId: effectiveAccountId,
|
|
48214
49055
|
queryParams: { "$filter": `JoinWebUrl eq '${trimmed}'` }
|
|
48215
49056
|
}
|
|
48216
49057
|
);
|
|
@@ -48289,13 +49130,14 @@ EXAMPLES:
|
|
|
48289
49130
|
},
|
|
48290
49131
|
execute: async (args, context) => {
|
|
48291
49132
|
const effectiveUserId = context?.userId ?? userId;
|
|
49133
|
+
const effectiveAccountId = context?.accountId;
|
|
48292
49134
|
try {
|
|
48293
49135
|
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
48294
49136
|
if (args.replyToMessageId) {
|
|
48295
49137
|
const replyDraft = await microsoftFetch(
|
|
48296
49138
|
connector,
|
|
48297
49139
|
`${prefix}/messages/${args.replyToMessageId}/createReply`,
|
|
48298
|
-
{ method: "POST", userId: effectiveUserId, body: {} }
|
|
49140
|
+
{ method: "POST", userId: effectiveUserId, accountId: effectiveAccountId, body: {} }
|
|
48299
49141
|
);
|
|
48300
49142
|
const updated = await microsoftFetch(
|
|
48301
49143
|
connector,
|
|
@@ -48303,6 +49145,7 @@ EXAMPLES:
|
|
|
48303
49145
|
{
|
|
48304
49146
|
method: "PATCH",
|
|
48305
49147
|
userId: effectiveUserId,
|
|
49148
|
+
accountId: effectiveAccountId,
|
|
48306
49149
|
body: {
|
|
48307
49150
|
subject: args.subject,
|
|
48308
49151
|
body: { contentType: "HTML", content: args.body },
|
|
@@ -48323,6 +49166,7 @@ EXAMPLES:
|
|
|
48323
49166
|
{
|
|
48324
49167
|
method: "POST",
|
|
48325
49168
|
userId: effectiveUserId,
|
|
49169
|
+
accountId: effectiveAccountId,
|
|
48326
49170
|
body: {
|
|
48327
49171
|
isDraft: true,
|
|
48328
49172
|
subject: args.subject,
|
|
@@ -48411,6 +49255,7 @@ EXAMPLES:
|
|
|
48411
49255
|
},
|
|
48412
49256
|
execute: async (args, context) => {
|
|
48413
49257
|
const effectiveUserId = context?.userId ?? userId;
|
|
49258
|
+
const effectiveAccountId = context?.accountId;
|
|
48414
49259
|
try {
|
|
48415
49260
|
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
48416
49261
|
if (args.replyToMessageId) {
|
|
@@ -48420,6 +49265,7 @@ EXAMPLES:
|
|
|
48420
49265
|
{
|
|
48421
49266
|
method: "POST",
|
|
48422
49267
|
userId: effectiveUserId,
|
|
49268
|
+
accountId: effectiveAccountId,
|
|
48423
49269
|
body: {
|
|
48424
49270
|
message: {
|
|
48425
49271
|
toRecipients: formatRecipients(args.to),
|
|
@@ -48436,6 +49282,7 @@ EXAMPLES:
|
|
|
48436
49282
|
{
|
|
48437
49283
|
method: "POST",
|
|
48438
49284
|
userId: effectiveUserId,
|
|
49285
|
+
accountId: effectiveAccountId,
|
|
48439
49286
|
body: {
|
|
48440
49287
|
message: {
|
|
48441
49288
|
subject: args.subject,
|
|
@@ -48535,6 +49382,7 @@ EXAMPLES:
|
|
|
48535
49382
|
},
|
|
48536
49383
|
execute: async (args, context) => {
|
|
48537
49384
|
const effectiveUserId = context?.userId ?? userId;
|
|
49385
|
+
const effectiveAccountId = context?.accountId;
|
|
48538
49386
|
try {
|
|
48539
49387
|
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
48540
49388
|
const tz = args.timeZone ?? "UTC";
|
|
@@ -48557,7 +49405,7 @@ EXAMPLES:
|
|
|
48557
49405
|
const event = await microsoftFetch(
|
|
48558
49406
|
connector,
|
|
48559
49407
|
`${prefix}/events`,
|
|
48560
|
-
{ method: "POST", userId: effectiveUserId, body: eventBody }
|
|
49408
|
+
{ method: "POST", userId: effectiveUserId, accountId: effectiveAccountId, body: eventBody }
|
|
48561
49409
|
);
|
|
48562
49410
|
return {
|
|
48563
49411
|
success: true,
|
|
@@ -48661,6 +49509,7 @@ EXAMPLES:
|
|
|
48661
49509
|
},
|
|
48662
49510
|
execute: async (args, context) => {
|
|
48663
49511
|
const effectiveUserId = context?.userId ?? userId;
|
|
49512
|
+
const effectiveAccountId = context?.accountId;
|
|
48664
49513
|
try {
|
|
48665
49514
|
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
48666
49515
|
const tz = args.timeZone ?? "UTC";
|
|
@@ -48684,7 +49533,7 @@ EXAMPLES:
|
|
|
48684
49533
|
const event = await microsoftFetch(
|
|
48685
49534
|
connector,
|
|
48686
49535
|
`${prefix}/events/${args.eventId}`,
|
|
48687
|
-
{ method: "PATCH", userId: effectiveUserId, body: patchBody }
|
|
49536
|
+
{ method: "PATCH", userId: effectiveUserId, accountId: effectiveAccountId, body: patchBody }
|
|
48688
49537
|
);
|
|
48689
49538
|
return {
|
|
48690
49539
|
success: true,
|
|
@@ -48757,14 +49606,15 @@ EXAMPLES:
|
|
|
48757
49606
|
},
|
|
48758
49607
|
execute: async (args, context) => {
|
|
48759
49608
|
const effectiveUserId = context?.userId ?? userId;
|
|
49609
|
+
const effectiveAccountId = context?.accountId;
|
|
48760
49610
|
try {
|
|
48761
49611
|
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
48762
|
-
const resolved = await resolveMeetingId(connector, args.meetingId, prefix, effectiveUserId);
|
|
49612
|
+
const resolved = await resolveMeetingId(connector, args.meetingId, prefix, effectiveUserId, effectiveAccountId);
|
|
48763
49613
|
const meetingId = resolved.meetingId;
|
|
48764
49614
|
const transcriptList = await microsoftFetch(
|
|
48765
49615
|
connector,
|
|
48766
49616
|
`${prefix}/onlineMeetings/${meetingId}/transcripts`,
|
|
48767
|
-
{ userId: effectiveUserId }
|
|
49617
|
+
{ userId: effectiveUserId, accountId: effectiveAccountId }
|
|
48768
49618
|
);
|
|
48769
49619
|
if (!transcriptList.value || transcriptList.value.length === 0) {
|
|
48770
49620
|
return {
|
|
@@ -48777,7 +49627,8 @@ EXAMPLES:
|
|
|
48777
49627
|
const response = await connector.fetch(
|
|
48778
49628
|
contentUrl + "?$format=text/vtt",
|
|
48779
49629
|
{ method: "GET", headers: { "Accept": "text/vtt" } },
|
|
48780
|
-
effectiveUserId
|
|
49630
|
+
effectiveUserId,
|
|
49631
|
+
effectiveAccountId
|
|
48781
49632
|
);
|
|
48782
49633
|
if (!response.ok) {
|
|
48783
49634
|
const errorText = await response.text();
|
|
@@ -48869,6 +49720,7 @@ EXAMPLES:
|
|
|
48869
49720
|
},
|
|
48870
49721
|
execute: async (args, context) => {
|
|
48871
49722
|
const effectiveUserId = context?.userId ?? userId;
|
|
49723
|
+
const effectiveAccountId = context?.accountId;
|
|
48872
49724
|
try {
|
|
48873
49725
|
const prefix = getUserPathPrefix(connector, args.targetUser);
|
|
48874
49726
|
const tz = args.timeZone ?? "UTC";
|
|
@@ -48878,6 +49730,7 @@ EXAMPLES:
|
|
|
48878
49730
|
{
|
|
48879
49731
|
method: "POST",
|
|
48880
49732
|
userId: effectiveUserId,
|
|
49733
|
+
accountId: effectiveAccountId,
|
|
48881
49734
|
body: {
|
|
48882
49735
|
attendees: formatAttendees(args.attendees),
|
|
48883
49736
|
timeConstraint: {
|
|
@@ -49806,27 +50659,42 @@ var customToolDelete = createCustomToolDelete();
|
|
|
49806
50659
|
|
|
49807
50660
|
// src/tools/custom-tools/sandboxDescription.ts
|
|
49808
50661
|
init_Connector();
|
|
49809
|
-
function formatConnectorEntry2(c) {
|
|
50662
|
+
function formatConnectorEntry2(c, accountId) {
|
|
49810
50663
|
const parts = [];
|
|
49811
50664
|
const serviceOrVendor = c.serviceType ?? c.vendor ?? void 0;
|
|
49812
50665
|
if (serviceOrVendor) parts.push(`Service: ${serviceOrVendor}`);
|
|
50666
|
+
if (accountId) parts.push(`Account: "${accountId}"`);
|
|
49813
50667
|
if (c.config.description) parts.push(c.config.description);
|
|
49814
50668
|
if (c.baseURL) parts.push(`URL: ${c.baseURL}`);
|
|
50669
|
+
const label = accountId ? `"${c.name}" account "${accountId}"` : `"${c.name}"`;
|
|
49815
50670
|
const details = parts.map((p) => ` ${p}`).join("\n");
|
|
49816
|
-
return ` \u2022
|
|
50671
|
+
return ` \u2022 ${label} (${c.displayName})
|
|
49817
50672
|
${details}`;
|
|
49818
50673
|
}
|
|
49819
50674
|
function buildConnectorList(context) {
|
|
50675
|
+
const identities = context?.identities;
|
|
49820
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
|
+
}
|
|
49821
50689
|
const connectors = registry.listAll();
|
|
49822
50690
|
if (connectors.length === 0) {
|
|
49823
50691
|
return " No connectors registered.";
|
|
49824
50692
|
}
|
|
49825
|
-
return connectors.map(formatConnectorEntry2).join("\n\n");
|
|
50693
|
+
return connectors.map((c) => formatConnectorEntry2(c)).join("\n\n");
|
|
49826
50694
|
}
|
|
49827
50695
|
var SANDBOX_API_REFERENCE = `SANDBOX API (available inside custom tool code):
|
|
49828
50696
|
|
|
49829
|
-
1. authenticatedFetch(url, options, connectorName)
|
|
50697
|
+
1. authenticatedFetch(url, options, connectorName, accountId?)
|
|
49830
50698
|
Makes authenticated HTTP requests using the connector's credentials.
|
|
49831
50699
|
Auth headers are added automatically \u2014 DO NOT set Authorization header manually.
|
|
49832
50700
|
|
|
@@ -49837,6 +50705,7 @@ var SANDBOX_API_REFERENCE = `SANDBOX API (available inside custom tool code):
|
|
|
49837
50705
|
\u2022 options: Standard fetch options { method, headers, body }
|
|
49838
50706
|
- For POST/PUT: set body to JSON.stringify(data) and headers to { 'Content-Type': 'application/json' }
|
|
49839
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')
|
|
49840
50709
|
|
|
49841
50710
|
Returns: Promise<Response>
|
|
49842
50711
|
\u2022 response.ok \u2014 true if status 200-299
|
|
@@ -51008,6 +51877,7 @@ exports.ProviderError = ProviderError;
|
|
|
51008
51877
|
exports.ProviderErrorMapper = ProviderErrorMapper;
|
|
51009
51878
|
exports.ProviderNotFoundError = ProviderNotFoundError;
|
|
51010
51879
|
exports.ProviderRateLimitError = ProviderRateLimitError;
|
|
51880
|
+
exports.ROUTINE_KEYS = ROUTINE_KEYS;
|
|
51011
51881
|
exports.RapidAPIProvider = RapidAPIProvider;
|
|
51012
51882
|
exports.RateLimitError = RateLimitError;
|
|
51013
51883
|
exports.SERVICE_DEFINITIONS = SERVICE_DEFINITIONS;
|
|
@@ -51272,6 +52142,7 @@ exports.resolveMaxContextTokens = resolveMaxContextTokens;
|
|
|
51272
52142
|
exports.resolveMeetingId = resolveMeetingId;
|
|
51273
52143
|
exports.resolveModelCapabilities = resolveModelCapabilities;
|
|
51274
52144
|
exports.resolveRepository = resolveRepository;
|
|
52145
|
+
exports.resolveTemplates = resolveTemplates;
|
|
51275
52146
|
exports.retryWithBackoff = retryWithBackoff;
|
|
51276
52147
|
exports.sanitizeToolName = sanitizeToolName;
|
|
51277
52148
|
exports.scopeEquals = scopeEquals;
|