@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/dist/index.js CHANGED
@@ -19,7 +19,7 @@ import * as z from 'zod/v4';
19
19
  import spawn$1 from 'cross-spawn';
20
20
  import process2 from 'process';
21
21
  import { PassThrough } from 'stream';
22
- import * as fs18 from 'fs/promises';
22
+ import * as fs17 from 'fs/promises';
23
23
  import { stat, readFile, mkdir, writeFile, readdir } from 'fs/promises';
24
24
  import * as simpleIcons from 'simple-icons';
25
25
  import { exec, spawn } from 'child_process';
@@ -163,6 +163,12 @@ var init_MemoryStorage = __esm({
163
163
  size() {
164
164
  return this.tokens.size;
165
165
  }
166
+ /**
167
+ * List all storage keys (for account enumeration)
168
+ */
169
+ async listKeys() {
170
+ return Array.from(this.tokens.keys());
171
+ }
166
172
  };
167
173
  }
168
174
  });
@@ -180,14 +186,23 @@ var init_TokenStore = __esm({
180
186
  this.storage = storage || new MemoryStorage();
181
187
  }
182
188
  /**
183
- * Get user-scoped storage key
184
- * For multi-user support, keys are scoped per user: "provider:userId"
185
- * For single-user (backward compatible), userId is omitted or "default"
189
+ * Get user-scoped (and optionally account-scoped) storage key
190
+ *
191
+ * Key format (backward compatible):
192
+ * - No userId, no accountId → baseKey
193
+ * - userId only → baseKey:userId
194
+ * - userId + accountId → baseKey:userId:accountId
195
+ * - accountId only → baseKey:default:accountId
186
196
  *
187
197
  * @param userId - User identifier (optional, defaults to single-user mode)
188
- * @returns Storage key scoped to user
198
+ * @param accountId - Account alias for multi-account support (optional)
199
+ * @returns Storage key scoped to user and account
189
200
  */
190
- getScopedKey(userId) {
201
+ getScopedKey(userId, accountId) {
202
+ if (accountId) {
203
+ const userPart = userId && userId !== "default" ? userId : "default";
204
+ return `${this.baseStorageKey}:${userPart}:${accountId}`;
205
+ }
191
206
  if (!userId || userId === "default") {
192
207
  return this.baseStorageKey;
193
208
  }
@@ -197,8 +212,9 @@ var init_TokenStore = __esm({
197
212
  * Store token (encrypted by storage layer)
198
213
  * @param tokenResponse - Token response from OAuth provider
199
214
  * @param userId - Optional user identifier for multi-user support
215
+ * @param accountId - Optional account alias for multi-account support
200
216
  */
201
- async storeToken(tokenResponse, userId) {
217
+ async storeToken(tokenResponse, userId, accountId) {
202
218
  if (!tokenResponse.access_token) {
203
219
  throw new Error("OAuth response missing required access_token field");
204
220
  }
@@ -216,39 +232,46 @@ var init_TokenStore = __esm({
216
232
  scope: tokenResponse.scope,
217
233
  obtained_at: Date.now()
218
234
  };
219
- const key = this.getScopedKey(userId);
235
+ const key = this.getScopedKey(userId, accountId);
220
236
  await this.storage.storeToken(key, token);
221
237
  }
222
238
  /**
223
239
  * Get access token
224
240
  * @param userId - Optional user identifier for multi-user support
241
+ * @param accountId - Optional account alias for multi-account support
225
242
  */
226
- async getAccessToken(userId) {
227
- const key = this.getScopedKey(userId);
243
+ async getAccessToken(userId, accountId) {
244
+ const key = this.getScopedKey(userId, accountId);
228
245
  const token = await this.storage.getToken(key);
229
246
  if (!token) {
230
- throw new Error(`No token stored for ${userId ? `user: ${userId}` : "default user"}`);
247
+ const userLabel = userId ? `user: ${userId}` : "default user";
248
+ const accountLabel = accountId ? `, account: ${accountId}` : "";
249
+ throw new Error(`No token stored for ${userLabel}${accountLabel}`);
231
250
  }
232
251
  return token.access_token;
233
252
  }
234
253
  /**
235
254
  * Get refresh token
236
255
  * @param userId - Optional user identifier for multi-user support
256
+ * @param accountId - Optional account alias for multi-account support
237
257
  */
238
- async getRefreshToken(userId) {
239
- const key = this.getScopedKey(userId);
258
+ async getRefreshToken(userId, accountId) {
259
+ const key = this.getScopedKey(userId, accountId);
240
260
  const token = await this.storage.getToken(key);
241
261
  if (!token?.refresh_token) {
242
- throw new Error(`No refresh token available for ${userId ? `user: ${userId}` : "default user"}`);
262
+ const userLabel = userId ? `user: ${userId}` : "default user";
263
+ const accountLabel = accountId ? `, account: ${accountId}` : "";
264
+ throw new Error(`No refresh token available for ${userLabel}${accountLabel}`);
243
265
  }
244
266
  return token.refresh_token;
245
267
  }
246
268
  /**
247
269
  * Check if has refresh token
248
270
  * @param userId - Optional user identifier for multi-user support
271
+ * @param accountId - Optional account alias for multi-account support
249
272
  */
250
- async hasRefreshToken(userId) {
251
- const key = this.getScopedKey(userId);
273
+ async hasRefreshToken(userId, accountId) {
274
+ const key = this.getScopedKey(userId, accountId);
252
275
  const token = await this.storage.getToken(key);
253
276
  return !!token?.refresh_token;
254
277
  }
@@ -257,9 +280,10 @@ var init_TokenStore = __esm({
257
280
  *
258
281
  * @param bufferSeconds - Refresh this many seconds before expiry (default: 300 = 5 min)
259
282
  * @param userId - Optional user identifier for multi-user support
283
+ * @param accountId - Optional account alias for multi-account support
260
284
  */
261
- async isValid(bufferSeconds = 300, userId) {
262
- const key = this.getScopedKey(userId);
285
+ async isValid(bufferSeconds = 300, userId, accountId) {
286
+ const key = this.getScopedKey(userId, accountId);
263
287
  const token = await this.storage.getToken(key);
264
288
  if (!token) {
265
289
  return false;
@@ -271,19 +295,46 @@ var init_TokenStore = __esm({
271
295
  /**
272
296
  * Clear stored token
273
297
  * @param userId - Optional user identifier for multi-user support
298
+ * @param accountId - Optional account alias for multi-account support
274
299
  */
275
- async clear(userId) {
276
- const key = this.getScopedKey(userId);
300
+ async clear(userId, accountId) {
301
+ const key = this.getScopedKey(userId, accountId);
277
302
  await this.storage.deleteToken(key);
278
303
  }
279
304
  /**
280
305
  * Get full token info
281
306
  * @param userId - Optional user identifier for multi-user support
307
+ * @param accountId - Optional account alias for multi-account support
282
308
  */
283
- async getTokenInfo(userId) {
284
- const key = this.getScopedKey(userId);
309
+ async getTokenInfo(userId, accountId) {
310
+ const key = this.getScopedKey(userId, accountId);
285
311
  return this.storage.getToken(key);
286
312
  }
313
+ /**
314
+ * List account aliases for a user on this connector.
315
+ * Returns account IDs that have stored tokens.
316
+ *
317
+ * @param userId - Optional user identifier
318
+ * @returns Array of account aliases (e.g., ['work', 'personal'])
319
+ */
320
+ async listAccounts(userId) {
321
+ if (!this.storage.listKeys) {
322
+ return [];
323
+ }
324
+ const allKeys = await this.storage.listKeys();
325
+ const userPart = userId && userId !== "default" ? userId : "default";
326
+ const prefix = `${this.baseStorageKey}:${userPart}:`;
327
+ const accounts = [];
328
+ for (const key of allKeys) {
329
+ if (key.startsWith(prefix)) {
330
+ const accountId = key.slice(prefix.length);
331
+ if (accountId && !accountId.includes(":")) {
332
+ accounts.push(accountId);
333
+ }
334
+ }
335
+ }
336
+ return accounts;
337
+ }
287
338
  };
288
339
  }
289
340
  });
@@ -324,20 +375,28 @@ var init_AuthCodePKCE = __esm({
324
375
  this.tokenStore = new TokenStore(storageKey, config.storage);
325
376
  }
326
377
  tokenStore;
327
- // Store PKCE data per user with timestamps for cleanup
378
+ // Store PKCE data per user+account with timestamps for cleanup
328
379
  codeVerifiers = /* @__PURE__ */ new Map();
329
380
  states = /* @__PURE__ */ new Map();
330
- // Store refresh locks per user to prevent concurrent refresh
381
+ // Store refresh locks per user+account to prevent concurrent refresh
331
382
  refreshLocks = /* @__PURE__ */ new Map();
332
383
  // PKCE data TTL: 15 minutes (auth flows should complete within this time)
333
384
  PKCE_TTL = 15 * 60 * 1e3;
385
+ /**
386
+ * Build a map key from userId and accountId for internal PKCE/state/lock maps.
387
+ */
388
+ getMapKey(userId, accountId) {
389
+ const userPart = userId || "default";
390
+ return accountId ? `${userPart}:${accountId}` : userPart;
391
+ }
334
392
  /**
335
393
  * Generate authorization URL for user to visit
336
394
  * Opens browser or redirects user to this URL
337
395
  *
338
396
  * @param userId - User identifier for multi-user support (optional)
397
+ * @param accountId - Account alias for multi-account support (optional)
339
398
  */
340
- async getAuthorizationUrl(userId) {
399
+ async getAuthorizationUrl(userId, accountId) {
341
400
  if (!this.config.authorizationUrl) {
342
401
  throw new Error("authorizationUrl is required for authorization_code flow");
343
402
  }
@@ -345,11 +404,11 @@ var init_AuthCodePKCE = __esm({
345
404
  throw new Error("redirectUri is required for authorization_code flow");
346
405
  }
347
406
  this.cleanupExpiredPKCE();
348
- const userKey = userId || "default";
407
+ const mapKey = this.getMapKey(userId, accountId);
349
408
  const { codeVerifier, codeChallenge } = generatePKCE();
350
- this.codeVerifiers.set(userKey, { verifier: codeVerifier, timestamp: Date.now() });
409
+ this.codeVerifiers.set(mapKey, { verifier: codeVerifier, timestamp: Date.now() });
351
410
  const state = generateState();
352
- this.states.set(userKey, { state, timestamp: Date.now() });
411
+ this.states.set(mapKey, { state, timestamp: Date.now() });
353
412
  const params = new URLSearchParams({
354
413
  response_type: "code",
355
414
  client_id: this.config.clientId,
@@ -363,33 +422,48 @@ var init_AuthCodePKCE = __esm({
363
422
  params.append("code_challenge", codeChallenge);
364
423
  params.append("code_challenge_method", "S256");
365
424
  }
366
- const stateWithUser = userId ? `${state}::${userId}` : state;
367
- params.set("state", stateWithUser);
425
+ let stateWithMetadata = state;
426
+ if (userId || accountId) {
427
+ stateWithMetadata = `${state}::${userId || ""}`;
428
+ if (accountId) {
429
+ stateWithMetadata += `::${accountId}`;
430
+ }
431
+ }
432
+ params.set("state", stateWithMetadata);
368
433
  return `${this.config.authorizationUrl}?${params.toString()}`;
369
434
  }
370
435
  /**
371
436
  * Exchange authorization code for access token
372
437
  *
373
438
  * @param code - Authorization code from callback
374
- * @param state - State parameter from callback (for CSRF verification, may include userId)
439
+ * @param state - State parameter from callback (for CSRF verification, may include userId/accountId)
375
440
  * @param userId - User identifier (optional, can be extracted from state)
441
+ * @param accountId - Account alias (optional, can be extracted from state)
376
442
  */
377
- async exchangeCode(code, state, userId) {
443
+ async exchangeCode(code, state, userId, accountId) {
378
444
  let actualState = state;
379
445
  let actualUserId = userId;
446
+ let actualAccountId = accountId;
380
447
  if (state.includes("::")) {
381
448
  const parts = state.split("::");
382
449
  actualState = parts[0];
383
- actualUserId = parts[1];
450
+ if (!actualUserId && parts[1]) {
451
+ actualUserId = parts[1];
452
+ }
453
+ if (!actualAccountId && parts[2]) {
454
+ actualAccountId = parts[2];
455
+ }
384
456
  }
385
- const userKey = actualUserId || "default";
386
- const stateData = this.states.get(userKey);
457
+ const mapKey = this.getMapKey(actualUserId, actualAccountId);
458
+ const stateData = this.states.get(mapKey);
387
459
  if (!stateData) {
388
- throw new Error(`No PKCE state found for user ${actualUserId}. Authorization flow may have expired (15 min TTL).`);
460
+ const label = actualAccountId ? `user ${actualUserId}, account ${actualAccountId}` : `user ${actualUserId}`;
461
+ throw new Error(`No PKCE state found for ${label}. Authorization flow may have expired (15 min TTL).`);
389
462
  }
390
463
  const expectedState = stateData.state;
391
464
  if (actualState !== expectedState) {
392
- throw new Error(`State mismatch for user ${actualUserId} - possible CSRF attack. Expected: ${expectedState}, Got: ${actualState}`);
465
+ const label = actualAccountId ? `user ${actualUserId}, account ${actualAccountId}` : `user ${actualUserId}`;
466
+ throw new Error(`State mismatch for ${label} - possible CSRF attack. Expected: ${expectedState}, Got: ${actualState}`);
393
467
  }
394
468
  if (!this.config.redirectUri) {
395
469
  throw new Error("redirectUri is required");
@@ -403,7 +477,7 @@ var init_AuthCodePKCE = __esm({
403
477
  if (this.config.clientSecret) {
404
478
  params.append("client_secret", this.config.clientSecret);
405
479
  }
406
- const verifierData = this.codeVerifiers.get(userKey);
480
+ const verifierData = this.codeVerifiers.get(mapKey);
407
481
  if (this.config.usePKCE !== false && verifierData) {
408
482
  params.append("code_verifier", verifierData.verifier);
409
483
  }
@@ -437,39 +511,43 @@ var init_AuthCodePKCE = __esm({
437
511
  throw new Error(`Token exchange failed: ${response.status} ${response.statusText} - ${error}`);
438
512
  }
439
513
  const data = await response.json();
440
- await this.tokenStore.storeToken(data, actualUserId);
441
- this.codeVerifiers.delete(userKey);
442
- this.states.delete(userKey);
514
+ await this.tokenStore.storeToken(data, actualUserId, actualAccountId);
515
+ this.codeVerifiers.delete(mapKey);
516
+ this.states.delete(mapKey);
443
517
  }
444
518
  /**
445
519
  * Get valid token (auto-refreshes if needed)
446
520
  * @param userId - User identifier for multi-user support
521
+ * @param accountId - Account alias for multi-account support
447
522
  */
448
- async getToken(userId) {
449
- const key = userId || "default";
450
- if (this.refreshLocks.has(key)) {
451
- return this.refreshLocks.get(key);
523
+ async getToken(userId, accountId) {
524
+ const mapKey = this.getMapKey(userId, accountId);
525
+ if (this.refreshLocks.has(mapKey)) {
526
+ return this.refreshLocks.get(mapKey);
452
527
  }
453
- if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId)) {
454
- return this.tokenStore.getAccessToken(userId);
528
+ if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId)) {
529
+ return this.tokenStore.getAccessToken(userId, accountId);
455
530
  }
456
- if (await this.tokenStore.hasRefreshToken(userId)) {
457
- const refreshPromise = this.refreshToken(userId);
458
- this.refreshLocks.set(key, refreshPromise);
531
+ if (await this.tokenStore.hasRefreshToken(userId, accountId)) {
532
+ const refreshPromise = this.refreshToken(userId, accountId);
533
+ this.refreshLocks.set(mapKey, refreshPromise);
459
534
  try {
460
535
  return await refreshPromise;
461
536
  } finally {
462
- this.refreshLocks.delete(key);
537
+ this.refreshLocks.delete(mapKey);
463
538
  }
464
539
  }
465
- throw new Error(`No valid token available for ${userId ? `user: ${userId}` : "default user"}. User needs to authorize (call startAuthFlow).`);
540
+ const userLabel = userId ? `user: ${userId}` : "default user";
541
+ const accountLabel = accountId ? `, account: ${accountId}` : "";
542
+ throw new Error(`No valid token available for ${userLabel}${accountLabel}. User needs to authorize (call startAuthFlow).`);
466
543
  }
467
544
  /**
468
545
  * Refresh access token using refresh token
469
546
  * @param userId - User identifier for multi-user support
547
+ * @param accountId - Account alias for multi-account support
470
548
  */
471
- async refreshToken(userId) {
472
- const refreshToken = await this.tokenStore.getRefreshToken(userId);
549
+ async refreshToken(userId, accountId) {
550
+ const refreshToken = await this.tokenStore.getRefreshToken(userId, accountId);
473
551
  const params = new URLSearchParams({
474
552
  grant_type: "refresh_token",
475
553
  refresh_token: refreshToken,
@@ -508,28 +586,30 @@ var init_AuthCodePKCE = __esm({
508
586
  throw new Error(`Token refresh failed: ${response.status} ${response.statusText} - ${error}`);
509
587
  }
510
588
  const data = await response.json();
511
- await this.tokenStore.storeToken(data, userId);
589
+ await this.tokenStore.storeToken(data, userId, accountId);
512
590
  return data.access_token;
513
591
  }
514
592
  /**
515
593
  * Check if token is valid
516
594
  * @param userId - User identifier for multi-user support
595
+ * @param accountId - Account alias for multi-account support
517
596
  */
518
- async isTokenValid(userId) {
519
- return this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId);
597
+ async isTokenValid(userId, accountId) {
598
+ return this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId);
520
599
  }
521
600
  /**
522
601
  * Revoke token (if supported by provider)
523
602
  * @param revocationUrl - Optional revocation endpoint
524
603
  * @param userId - User identifier for multi-user support
604
+ * @param accountId - Account alias for multi-account support
525
605
  */
526
- async revokeToken(revocationUrl, userId) {
606
+ async revokeToken(revocationUrl, userId, accountId) {
527
607
  if (!revocationUrl) {
528
- await this.tokenStore.clear(userId);
608
+ await this.tokenStore.clear(userId, accountId);
529
609
  return;
530
610
  }
531
611
  try {
532
- const token = await this.tokenStore.getAccessToken(userId);
612
+ const token = await this.tokenStore.getAccessToken(userId, accountId);
533
613
  await fetch(revocationUrl, {
534
614
  method: "POST",
535
615
  headers: {
@@ -541,9 +621,16 @@ var init_AuthCodePKCE = __esm({
541
621
  })
542
622
  });
543
623
  } finally {
544
- await this.tokenStore.clear(userId);
624
+ await this.tokenStore.clear(userId, accountId);
545
625
  }
546
626
  }
627
+ /**
628
+ * List account aliases for a user.
629
+ * @param userId - User identifier (optional)
630
+ */
631
+ async listAccounts(userId) {
632
+ return this.tokenStore.listAccounts(userId);
633
+ }
547
634
  /**
548
635
  * Clean up expired PKCE data to prevent memory leaks
549
636
  * Removes verifiers and states older than PKCE_TTL (15 minutes)
@@ -575,17 +662,19 @@ var init_ClientCredentials = __esm({
575
662
  tokenStore;
576
663
  /**
577
664
  * Get token using client credentials
665
+ * @param userId - User identifier for multi-user support (optional, rarely used for client_credentials)
666
+ * @param accountId - Account alias for multi-account support (optional)
578
667
  */
579
- async getToken() {
580
- if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry)) {
581
- return this.tokenStore.getAccessToken();
668
+ async getToken(userId, accountId) {
669
+ if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId)) {
670
+ return this.tokenStore.getAccessToken(userId, accountId);
582
671
  }
583
- return this.requestToken();
672
+ return this.requestToken(userId, accountId);
584
673
  }
585
674
  /**
586
675
  * Request a new token from the authorization server
587
676
  */
588
- async requestToken() {
677
+ async requestToken(userId, accountId) {
589
678
  const auth2 = Buffer.from(`${this.config.clientId}:${this.config.clientSecret}`).toString(
590
679
  "base64"
591
680
  );
@@ -608,22 +697,26 @@ var init_ClientCredentials = __esm({
608
697
  throw new Error(`Token request failed: ${response.status} ${response.statusText} - ${error}`);
609
698
  }
610
699
  const data = await response.json();
611
- await this.tokenStore.storeToken(data);
700
+ await this.tokenStore.storeToken(data, userId, accountId);
612
701
  return data.access_token;
613
702
  }
614
703
  /**
615
704
  * Refresh token (client credentials don't use refresh tokens)
616
705
  * Just requests a new token
706
+ * @param userId - User identifier for multi-user support (optional)
707
+ * @param accountId - Account alias for multi-account support (optional)
617
708
  */
618
- async refreshToken() {
619
- await this.tokenStore.clear();
620
- return this.requestToken();
709
+ async refreshToken(userId, accountId) {
710
+ await this.tokenStore.clear(userId, accountId);
711
+ return this.requestToken(userId, accountId);
621
712
  }
622
713
  /**
623
714
  * Check if token is valid
715
+ * @param userId - User identifier for multi-user support (optional)
716
+ * @param accountId - Account alias for multi-account support (optional)
624
717
  */
625
- async isTokenValid() {
626
- return this.tokenStore.isValid(this.config.refreshBeforeExpiry);
718
+ async isTokenValid(userId, accountId) {
719
+ return this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId);
627
720
  }
628
721
  };
629
722
  }
@@ -665,17 +758,19 @@ var init_JWTBearer = __esm({
665
758
  }
666
759
  /**
667
760
  * Get token using JWT Bearer assertion
761
+ * @param userId - User identifier for multi-user support (optional)
762
+ * @param accountId - Account alias for multi-account support (optional)
668
763
  */
669
- async getToken() {
670
- if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry)) {
671
- return this.tokenStore.getAccessToken();
764
+ async getToken(userId, accountId) {
765
+ if (await this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId)) {
766
+ return this.tokenStore.getAccessToken(userId, accountId);
672
767
  }
673
- return this.requestToken();
768
+ return this.requestToken(userId, accountId);
674
769
  }
675
770
  /**
676
771
  * Request token using JWT assertion
677
772
  */
678
- async requestToken() {
773
+ async requestToken(userId, accountId) {
679
774
  const assertion = await this.generateJWT();
680
775
  const params = new URLSearchParams({
681
776
  grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
@@ -693,21 +788,25 @@ var init_JWTBearer = __esm({
693
788
  throw new Error(`JWT Bearer token request failed: ${response.status} ${response.statusText} - ${error}`);
694
789
  }
695
790
  const data = await response.json();
696
- await this.tokenStore.storeToken(data);
791
+ await this.tokenStore.storeToken(data, userId, accountId);
697
792
  return data.access_token;
698
793
  }
699
794
  /**
700
795
  * Refresh token (generate new JWT and request new token)
796
+ * @param userId - User identifier for multi-user support (optional)
797
+ * @param accountId - Account alias for multi-account support (optional)
701
798
  */
702
- async refreshToken() {
703
- await this.tokenStore.clear();
704
- return this.requestToken();
799
+ async refreshToken(userId, accountId) {
800
+ await this.tokenStore.clear(userId, accountId);
801
+ return this.requestToken(userId, accountId);
705
802
  }
706
803
  /**
707
804
  * Check if token is valid
805
+ * @param userId - User identifier for multi-user support (optional)
806
+ * @param accountId - Account alias for multi-account support (optional)
708
807
  */
709
- async isTokenValid() {
710
- return this.tokenStore.isValid(this.config.refreshBeforeExpiry);
808
+ async isTokenValid(userId, accountId) {
809
+ return this.tokenStore.isValid(this.config.refreshBeforeExpiry, userId, accountId);
711
810
  }
712
811
  };
713
812
  }
@@ -787,25 +886,28 @@ var init_OAuthManager = __esm({
787
886
  * Automatically refreshes if expired
788
887
  *
789
888
  * @param userId - User identifier for multi-user support (optional)
889
+ * @param accountId - Account alias for multi-account support (optional)
790
890
  */
791
- async getToken(userId) {
792
- return this.flow.getToken(userId);
891
+ async getToken(userId, accountId) {
892
+ return this.flow.getToken(userId, accountId);
793
893
  }
794
894
  /**
795
895
  * Force refresh the token
796
896
  *
797
897
  * @param userId - User identifier for multi-user support (optional)
898
+ * @param accountId - Account alias for multi-account support (optional)
798
899
  */
799
- async refreshToken(userId) {
800
- return this.flow.refreshToken(userId);
900
+ async refreshToken(userId, accountId) {
901
+ return this.flow.refreshToken(userId, accountId);
801
902
  }
802
903
  /**
803
904
  * Check if current token is valid
804
905
  *
805
906
  * @param userId - User identifier for multi-user support (optional)
907
+ * @param accountId - Account alias for multi-account support (optional)
806
908
  */
807
- async isTokenValid(userId) {
808
- return this.flow.isTokenValid(userId);
909
+ async isTokenValid(userId, accountId) {
910
+ return this.flow.isTokenValid(userId, accountId);
809
911
  }
810
912
  // ==================== Authorization Code Flow Methods ====================
811
913
  /**
@@ -813,13 +915,14 @@ var init_OAuthManager = __esm({
813
915
  * Returns URL for user to visit
814
916
  *
815
917
  * @param userId - User identifier for multi-user support (optional)
918
+ * @param accountId - Account alias for multi-account support (optional)
816
919
  * @returns Authorization URL for the user to visit
817
920
  */
818
- async startAuthFlow(userId) {
921
+ async startAuthFlow(userId, accountId) {
819
922
  if (!(this.flow instanceof AuthCodePKCEFlow)) {
820
923
  throw new Error("startAuthFlow() is only available for authorization_code flow");
821
924
  }
822
- return this.flow.getAuthorizationUrl(userId);
925
+ return this.flow.getAuthorizationUrl(userId, accountId);
823
926
  }
824
927
  /**
825
928
  * Handle OAuth callback (Authorization Code only)
@@ -827,8 +930,9 @@ var init_OAuthManager = __esm({
827
930
  *
828
931
  * @param callbackUrl - Full callback URL with code and state parameters
829
932
  * @param userId - Optional user identifier (can be extracted from state if embedded)
933
+ * @param accountId - Optional account alias (can be extracted from state if embedded)
830
934
  */
831
- async handleCallback(callbackUrl, userId) {
935
+ async handleCallback(callbackUrl, userId, accountId) {
832
936
  if (!(this.flow instanceof AuthCodePKCEFlow)) {
833
937
  throw new Error("handleCallback() is only available for authorization_code flow");
834
938
  }
@@ -841,21 +945,34 @@ var init_OAuthManager = __esm({
841
945
  if (!state) {
842
946
  throw new Error("Missing state parameter in callback URL");
843
947
  }
844
- await this.flow.exchangeCode(code, state, userId);
948
+ await this.flow.exchangeCode(code, state, userId, accountId);
845
949
  }
846
950
  /**
847
951
  * Revoke token (if supported by provider)
848
952
  *
849
953
  * @param revocationUrl - Optional revocation endpoint URL
850
954
  * @param userId - User identifier for multi-user support (optional)
955
+ * @param accountId - Account alias for multi-account support (optional)
851
956
  */
852
- async revokeToken(revocationUrl, userId) {
957
+ async revokeToken(revocationUrl, userId, accountId) {
853
958
  if (this.flow instanceof AuthCodePKCEFlow) {
854
- await this.flow.revokeToken(revocationUrl, userId);
959
+ await this.flow.revokeToken(revocationUrl, userId, accountId);
855
960
  } else {
856
961
  throw new Error("Token revocation not implemented for this flow");
857
962
  }
858
963
  }
964
+ /**
965
+ * List account aliases for a user (Authorization Code only)
966
+ *
967
+ * @param userId - User identifier (optional)
968
+ * @returns Array of account aliases (e.g., ['work', 'personal'])
969
+ */
970
+ async listAccounts(userId) {
971
+ if (this.flow instanceof AuthCodePKCEFlow) {
972
+ return this.flow.listAccounts(userId);
973
+ }
974
+ return [];
975
+ }
859
976
  // ==================== Validation ====================
860
977
  validateConfig(config) {
861
978
  if (!config.flow) {
@@ -2061,46 +2178,59 @@ var init_Connector = __esm({
2061
2178
  /**
2062
2179
  * Get the current access token (for OAuth, JWT, or API key)
2063
2180
  * Handles automatic refresh if needed
2181
+ *
2182
+ * @param userId - Optional user identifier for multi-user support
2183
+ * @param accountId - Optional account alias for multi-account support (e.g., 'work', 'personal')
2064
2184
  */
2065
- async getToken(userId) {
2185
+ async getToken(userId, accountId) {
2066
2186
  if (this.config.auth.type === "api_key") {
2067
2187
  return this.config.auth.apiKey;
2068
2188
  }
2069
2189
  if (!this.oauthManager) {
2070
2190
  throw new Error(`OAuth manager not initialized for connector '${this.name}'`);
2071
2191
  }
2072
- return this.oauthManager.getToken(userId);
2192
+ return this.oauthManager.getToken(userId, accountId);
2073
2193
  }
2074
2194
  /**
2075
2195
  * Start OAuth authorization flow
2076
2196
  * Returns the URL to redirect the user to
2197
+ *
2198
+ * @param userId - Optional user identifier for multi-user support
2199
+ * @param accountId - Optional account alias for multi-account support (e.g., 'work', 'personal')
2077
2200
  */
2078
- async startAuth(userId) {
2201
+ async startAuth(userId, accountId) {
2079
2202
  if (!this.oauthManager) {
2080
2203
  throw new Error(`Connector '${this.name}' is not an OAuth connector`);
2081
2204
  }
2082
- return this.oauthManager.startAuthFlow(userId);
2205
+ return this.oauthManager.startAuthFlow(userId, accountId);
2083
2206
  }
2084
2207
  /**
2085
2208
  * Handle OAuth callback
2086
2209
  * Call this after user is redirected back from OAuth provider
2210
+ *
2211
+ * @param callbackUrl - Full callback URL with code and state parameters
2212
+ * @param userId - Optional user identifier (can be extracted from state if embedded)
2213
+ * @param accountId - Optional account alias (can be extracted from state if embedded)
2087
2214
  */
2088
- async handleCallback(callbackUrl, userId) {
2215
+ async handleCallback(callbackUrl, userId, accountId) {
2089
2216
  if (!this.oauthManager) {
2090
2217
  throw new Error(`Connector '${this.name}' is not an OAuth connector`);
2091
2218
  }
2092
- await this.oauthManager.handleCallback(callbackUrl, userId);
2219
+ await this.oauthManager.handleCallback(callbackUrl, userId, accountId);
2093
2220
  }
2094
2221
  /**
2095
2222
  * Check if the connector has a valid token
2223
+ *
2224
+ * @param userId - Optional user identifier for multi-user support
2225
+ * @param accountId - Optional account alias for multi-account support
2096
2226
  */
2097
- async hasValidToken(userId) {
2227
+ async hasValidToken(userId, accountId) {
2098
2228
  try {
2099
2229
  if (this.config.auth.type === "api_key") {
2100
2230
  return true;
2101
2231
  }
2102
2232
  if (this.oauthManager) {
2103
- const token = await this.oauthManager.getToken(userId);
2233
+ const token = await this.oauthManager.getToken(userId, accountId);
2104
2234
  return !!token;
2105
2235
  }
2106
2236
  return false;
@@ -2108,6 +2238,19 @@ var init_Connector = __esm({
2108
2238
  return false;
2109
2239
  }
2110
2240
  }
2241
+ /**
2242
+ * List account aliases for a user on this connector.
2243
+ * Only applicable for OAuth connectors with multi-account support.
2244
+ *
2245
+ * @param userId - Optional user identifier
2246
+ * @returns Array of account aliases (e.g., ['work', 'personal'])
2247
+ */
2248
+ async listAccounts(userId) {
2249
+ if (!this.oauthManager) {
2250
+ return [];
2251
+ }
2252
+ return this.oauthManager.listAccounts(userId);
2253
+ }
2111
2254
  /**
2112
2255
  * Get vendor-specific options from config
2113
2256
  */
@@ -2151,9 +2294,10 @@ var init_Connector = __esm({
2151
2294
  * @param endpoint - API endpoint (relative to baseURL) or full URL
2152
2295
  * @param options - Fetch options with connector-specific settings
2153
2296
  * @param userId - Optional user ID for multi-user OAuth
2297
+ * @param accountId - Optional account alias for multi-account OAuth
2154
2298
  * @returns Fetch Response
2155
2299
  */
2156
- async fetch(endpoint, options, userId) {
2300
+ async fetch(endpoint, options, userId, accountId) {
2157
2301
  if (this.disposed) {
2158
2302
  throw new Error(`Connector '${this.name}' has been disposed`);
2159
2303
  }
@@ -2172,7 +2316,7 @@ var init_Connector = __esm({
2172
2316
  this.logRequest(url2, options);
2173
2317
  }
2174
2318
  const doFetch = async () => {
2175
- const token = await this.getToken(userId);
2319
+ const token = await this.getToken(userId, accountId);
2176
2320
  const auth2 = this.config.auth;
2177
2321
  let headerName = "Authorization";
2178
2322
  let headerValue = `Bearer ${token}`;
@@ -2284,10 +2428,11 @@ var init_Connector = __esm({
2284
2428
  * @param endpoint - API endpoint (relative to baseURL) or full URL
2285
2429
  * @param options - Fetch options with connector-specific settings
2286
2430
  * @param userId - Optional user ID for multi-user OAuth
2431
+ * @param accountId - Optional account alias for multi-account OAuth
2287
2432
  * @returns Parsed JSON response
2288
2433
  */
2289
- async fetchJSON(endpoint, options, userId) {
2290
- const response = await this.fetch(endpoint, options, userId);
2434
+ async fetchJSON(endpoint, options, userId, accountId) {
2435
+ const response = await this.fetch(endpoint, options, userId, accountId);
2291
2436
  const text = await response.text();
2292
2437
  let data;
2293
2438
  try {
@@ -11236,6 +11381,18 @@ var ToolManager = class extends EventEmitter {
11236
11381
  this.register(tool, options);
11237
11382
  }
11238
11383
  }
11384
+ /**
11385
+ * Register tools produced by a specific connector.
11386
+ * Sets `source: 'connector:<connectorName>'` (or `'connector:<name>:<accountId>'` for identity-bound tools)
11387
+ * so agent-level filtering can restrict which connector tools are visible to a given agent.
11388
+ */
11389
+ registerConnectorTools(connectorName, tools, options = {}) {
11390
+ const { accountId, ...toolOptions } = options;
11391
+ const source = accountId ? `connector:${connectorName}:${accountId}` : `connector:${connectorName}`;
11392
+ for (const tool of tools) {
11393
+ this.register(tool, { ...toolOptions, source });
11394
+ }
11395
+ }
11239
11396
  /**
11240
11397
  * Unregister a tool by name
11241
11398
  */
@@ -11426,6 +11583,14 @@ var ToolManager = class extends EventEmitter {
11426
11583
  getEnabled() {
11427
11584
  return this.getSortedByPriority().filter((reg) => reg.enabled).map((reg) => reg.tool);
11428
11585
  }
11586
+ /**
11587
+ * Get all enabled registrations (sorted by priority).
11588
+ * Includes full registration metadata (source, namespace, etc.)
11589
+ * for use in connector-aware filtering.
11590
+ */
11591
+ getEnabledRegistrations() {
11592
+ return this.getSortedByPriority().filter((reg) => reg.enabled);
11593
+ }
11429
11594
  /**
11430
11595
  * Get all tools (enabled and disabled)
11431
11596
  */
@@ -11618,6 +11783,13 @@ var ToolManager = class extends EventEmitter {
11618
11783
  if (!registration.enabled) {
11619
11784
  throw new ToolExecutionError(toolName, "Tool is disabled");
11620
11785
  }
11786
+ if (registration.source?.startsWith("connector:")) {
11787
+ const connName = registration.source.slice("connector:".length);
11788
+ const registry = this._toolContext?.connectorRegistry;
11789
+ if (registry && !registry.has(connName)) {
11790
+ throw new ToolExecutionError(toolName, `Connector '${connName}' is not available to this agent`);
11791
+ }
11792
+ }
11621
11793
  const breaker = this.getOrCreateCircuitBreaker(toolName, registration);
11622
11794
  this.toolLogger.debug({ toolName, args }, "Tool execution started");
11623
11795
  const startTime = Date.now();
@@ -16710,8 +16882,8 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
16710
16882
  _agentId;
16711
16883
  /** User ID for multi-user scenarios */
16712
16884
  _userId;
16713
- /** Allowed connector names (when agent is restricted to a subset) */
16714
- _allowedConnectors;
16885
+ /** Auth identities this agent is scoped to (connector + optional accountId) */
16886
+ _identities;
16715
16887
  /** Storage backend */
16716
16888
  _storage;
16717
16889
  /** Destroyed flag */
@@ -16751,7 +16923,7 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
16751
16923
  this._systemPrompt = config.systemPrompt;
16752
16924
  this._agentId = this._config.agentId;
16753
16925
  this._userId = config.userId;
16754
- this._allowedConnectors = config.connectors;
16926
+ this._identities = config.identities;
16755
16927
  const sessionFactory = StorageRegistry.get("sessions");
16756
16928
  const storageCtx = StorageRegistry.getContext() ?? (config.userId ? { userId: config.userId } : void 0);
16757
16929
  this._storage = config.storage ?? (sessionFactory ? sessionFactory(this._agentId, storageCtx) : void 0);
@@ -16823,7 +16995,7 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
16823
16995
  * Merges with existing ToolContext to preserve other fields (memory, signal, taskId).
16824
16996
  *
16825
16997
  * Connector registry resolution order:
16826
- * 1. If `connectors` (allowed names) is set → filtered view of global registry
16998
+ * 1. If `identities` is set → filtered view showing only identity connectors
16827
16999
  * 2. If access policy + userId → scoped view via Connector.scoped()
16828
17000
  * 3. Otherwise → full global registry
16829
17001
  */
@@ -16833,6 +17005,7 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
16833
17005
  ...existing,
16834
17006
  agentId: this._agentId,
16835
17007
  userId: this._userId,
17008
+ identities: this._identities,
16836
17009
  connectorRegistry: this.buildConnectorRegistry()
16837
17010
  });
16838
17011
  }
@@ -16840,13 +17013,13 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
16840
17013
  * Build the connector registry appropriate for this agent's config.
16841
17014
  */
16842
17015
  buildConnectorRegistry() {
16843
- if (this._allowedConnectors?.length) {
16844
- const allowedSet = new Set(this._allowedConnectors);
17016
+ if (this._identities?.length) {
17017
+ const allowedSet = new Set(this._identities.map((id) => id.connector));
16845
17018
  const base = this._userId && Connector.getAccessPolicy() ? Connector.scoped({ userId: this._userId }) : Connector.asRegistry();
16846
17019
  return {
16847
17020
  get: (name) => {
16848
17021
  if (!allowedSet.has(name)) {
16849
- const available = this._allowedConnectors.filter((n) => base.has(n)).join(", ") || "none";
17022
+ const available = [...allowedSet].filter((n) => base.has(n)).join(", ") || "none";
16850
17023
  throw new Error(`Connector '${name}' not found. Available: ${available}`);
16851
17024
  }
16852
17025
  return base.get(name);
@@ -16898,13 +17071,13 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
16898
17071
  this._userId = value;
16899
17072
  this.syncToolContext();
16900
17073
  }
16901
- /** Get the allowed connector names (undefined = all visible connectors) */
16902
- get connectors() {
16903
- return this._allowedConnectors;
17074
+ /** Get the auth identities this agent is scoped to (undefined = all visible connectors) */
17075
+ get identities() {
17076
+ return this._identities;
16904
17077
  }
16905
- /** Set allowed connector names. Updates ToolContext.connectorRegistry. */
16906
- set connectors(value) {
16907
- this._allowedConnectors = value;
17078
+ /** Set auth identities. Updates ToolContext.connectorRegistry and identity-aware descriptions. */
17079
+ set identities(value) {
17080
+ this._identities = value;
16908
17081
  this.syncToolContext();
16909
17082
  }
16910
17083
  /** Get/set system prompt */
@@ -21383,7 +21556,7 @@ var BaseAgent = class extends EventEmitter {
21383
21556
  model: config.model,
21384
21557
  agentId: config.name,
21385
21558
  userId: config.userId,
21386
- connectors: config.connectors,
21559
+ identities: config.identities,
21387
21560
  // Include storage and sessionId if session config is provided
21388
21561
  storage: config.session?.storage,
21389
21562
  // Thread tool execution timeout to ToolManager
@@ -21553,16 +21726,16 @@ var BaseAgent = class extends EventEmitter {
21553
21726
  this._agentContext.userId = value;
21554
21727
  }
21555
21728
  /**
21556
- * Get the allowed connector names (undefined = all visible connectors).
21729
+ * Get the auth identities this agent is scoped to (undefined = all visible connectors).
21557
21730
  */
21558
- get connectors() {
21559
- return this._agentContext.connectors;
21731
+ get identities() {
21732
+ return this._agentContext.identities;
21560
21733
  }
21561
21734
  /**
21562
- * Restrict this agent to a subset of connectors. Updates ToolContext.connectorRegistry.
21735
+ * Set auth identities at runtime. Updates ToolContext.connectorRegistry and tool descriptions.
21563
21736
  */
21564
- set connectors(value) {
21565
- this._agentContext.connectors = value;
21737
+ set identities(value) {
21738
+ this._agentContext.identities = value;
21566
21739
  }
21567
21740
  /**
21568
21741
  * Permission management. Returns ToolPermissionManager for approval control.
@@ -21574,9 +21747,12 @@ var BaseAgent = class extends EventEmitter {
21574
21747
  /**
21575
21748
  * Add a tool to the agent.
21576
21749
  * Tools are registered with AgentContext (single source of truth).
21750
+ *
21751
+ * @param tool - The tool function to register
21752
+ * @param options - Optional registration options (namespace, source, priority, etc.)
21577
21753
  */
21578
- addTool(tool) {
21579
- this._agentContext.tools.register(tool);
21754
+ addTool(tool, options) {
21755
+ this._agentContext.tools.register(tool, options);
21580
21756
  if (tool.permission) {
21581
21757
  this._permissionManager.setToolConfig(tool.definition.function.name, tool.permission);
21582
21758
  }
@@ -21616,7 +21792,34 @@ var BaseAgent = class extends EventEmitter {
21616
21792
  */
21617
21793
  getEnabledToolDefinitions() {
21618
21794
  const toolContext = this._agentContext.tools.getToolContext();
21619
- return this._agentContext.tools.getEnabled().map((tool) => {
21795
+ const identities = this._agentContext.identities;
21796
+ let allowedSources;
21797
+ let allowedConnectorNames;
21798
+ if (identities) {
21799
+ allowedSources = /* @__PURE__ */ new Set();
21800
+ allowedConnectorNames = /* @__PURE__ */ new Set();
21801
+ for (const id of identities) {
21802
+ allowedConnectorNames.add(id.connector);
21803
+ if (id.accountId) {
21804
+ allowedSources.add(`connector:${id.connector}:${id.accountId}`);
21805
+ } else {
21806
+ allowedSources.add(`connector:${id.connector}`);
21807
+ allowedConnectorNames.add(id.connector);
21808
+ }
21809
+ }
21810
+ }
21811
+ return this._agentContext.tools.getEnabledRegistrations().filter((reg) => {
21812
+ if (!allowedSources) return true;
21813
+ if (!reg.source?.startsWith("connector:")) return true;
21814
+ if (allowedSources.has(reg.source)) return true;
21815
+ const sourceParts = reg.source.slice("connector:".length).split(":");
21816
+ const connectorName = sourceParts[0];
21817
+ if (allowedConnectorNames.has(connectorName) && allowedSources.has(`connector:${connectorName}`)) {
21818
+ return true;
21819
+ }
21820
+ return false;
21821
+ }).map((reg) => {
21822
+ const tool = reg.tool;
21620
21823
  if (tool.descriptionFactory) {
21621
21824
  const dynamicDescription = tool.descriptionFactory(toolContext);
21622
21825
  return {
@@ -24001,6 +24204,7 @@ function createTask(input) {
24001
24204
  suggestedTools: input.suggestedTools,
24002
24205
  validation: input.validation,
24003
24206
  expectedOutput: input.expectedOutput,
24207
+ controlFlow: input.controlFlow,
24004
24208
  attempts: 0,
24005
24209
  maxAttempts: input.maxAttempts ?? 3,
24006
24210
  createdAt: now,
@@ -24253,6 +24457,7 @@ function createRoutineDefinition(input) {
24253
24457
  instructions: input.instructions,
24254
24458
  concurrency: input.concurrency,
24255
24459
  allowDynamicTasks: input.allowDynamicTasks ?? false,
24460
+ parameters: input.parameters,
24256
24461
  tags: input.tags,
24257
24462
  author: input.author,
24258
24463
  createdAt: now,
@@ -24468,6 +24673,321 @@ function extractNumber(text, patterns = [
24468
24673
 
24469
24674
  // src/core/routineRunner.ts
24470
24675
  init_Logger();
24676
+
24677
+ // src/core/routineControlFlow.ts
24678
+ init_Logger();
24679
+ var HARD_MAX_ITERATIONS = 1e3;
24680
+ var ICM_LARGE_THRESHOLD = 5e3;
24681
+ var ROUTINE_KEYS = {
24682
+ /** Plan overview with task statuses (ICM) */
24683
+ PLAN: "__routine_plan",
24684
+ /** Dependency results location guide (ICM) */
24685
+ DEPS: "__routine_deps",
24686
+ /** Prefix for per-dependency result keys (ICM/WM) */
24687
+ DEP_RESULT_PREFIX: "__dep_result_",
24688
+ /** Current map/fold item (ICM) */
24689
+ MAP_ITEM: "__map_item",
24690
+ /** Current map/fold index, 0-based (ICM) */
24691
+ MAP_INDEX: "__map_index",
24692
+ /** Total items in map/fold (ICM) */
24693
+ MAP_TOTAL: "__map_total",
24694
+ /** Running fold accumulator (ICM) */
24695
+ FOLD_ACCUMULATOR: "__fold_accumulator",
24696
+ /** Prefix for large dep results stored in WM findings tier */
24697
+ WM_DEP_FINDINGS_PREFIX: "findings/__dep_result_"
24698
+ };
24699
+ function resolveTemplates(text, inputs, icmPlugin) {
24700
+ return text.replace(/\{\{(\w+)\.(\w+)\}\}/g, (_match, namespace, key) => {
24701
+ let value;
24702
+ if (namespace === "param") {
24703
+ value = inputs[key];
24704
+ } else if (namespace === "map") {
24705
+ const icmKey = `__map_${key}`;
24706
+ value = icmPlugin?.get(icmKey);
24707
+ } else if (namespace === "fold") {
24708
+ const icmKey = `__fold_${key}`;
24709
+ value = icmPlugin?.get(icmKey);
24710
+ } else {
24711
+ return _match;
24712
+ }
24713
+ if (value === void 0) {
24714
+ return _match;
24715
+ }
24716
+ return typeof value === "string" ? value : JSON.stringify(value);
24717
+ });
24718
+ }
24719
+ function resolveTaskTemplates(task, inputs, icmPlugin) {
24720
+ const resolvedDescription = resolveTemplates(task.description, inputs, icmPlugin);
24721
+ const resolvedExpectedOutput = task.expectedOutput ? resolveTemplates(task.expectedOutput, inputs, icmPlugin) : task.expectedOutput;
24722
+ if (resolvedDescription === task.description && resolvedExpectedOutput === task.expectedOutput) {
24723
+ return task;
24724
+ }
24725
+ return {
24726
+ ...task,
24727
+ description: resolvedDescription,
24728
+ expectedOutput: resolvedExpectedOutput
24729
+ };
24730
+ }
24731
+ function validateAndResolveInputs(parameters, inputs) {
24732
+ const resolved = { ...inputs ?? {} };
24733
+ if (!parameters || parameters.length === 0) {
24734
+ return resolved;
24735
+ }
24736
+ for (const param of parameters) {
24737
+ if (resolved[param.name] === void 0) {
24738
+ if (param.required) {
24739
+ throw new Error(`Missing required parameter: "${param.name}"`);
24740
+ }
24741
+ if (param.default !== void 0) {
24742
+ resolved[param.name] = param.default;
24743
+ }
24744
+ }
24745
+ }
24746
+ return resolved;
24747
+ }
24748
+ async function readMemoryValue(key, icmPlugin, wmPlugin) {
24749
+ if (icmPlugin) {
24750
+ const icmValue = icmPlugin.get(key);
24751
+ if (icmValue !== void 0) return icmValue;
24752
+ }
24753
+ if (wmPlugin) {
24754
+ const wmValue = await wmPlugin.retrieve(key);
24755
+ if (wmValue !== void 0) return wmValue;
24756
+ }
24757
+ return void 0;
24758
+ }
24759
+ async function storeResult(key, description, value, icmPlugin, wmPlugin) {
24760
+ const serialized = typeof value === "string" ? value : JSON.stringify(value);
24761
+ const estimatedTokens = Math.ceil(serialized.length / 4);
24762
+ if (estimatedTokens < ICM_LARGE_THRESHOLD && icmPlugin) {
24763
+ icmPlugin.set(key, description, value, "high");
24764
+ } else if (wmPlugin) {
24765
+ await wmPlugin.store(key, description, serialized, { tier: "findings" });
24766
+ } else if (icmPlugin) {
24767
+ icmPlugin.set(key, description, value, "high");
24768
+ }
24769
+ }
24770
+ function resolveSubRoutine(spec, parentTaskName) {
24771
+ if (!Array.isArray(spec)) {
24772
+ return spec;
24773
+ }
24774
+ return createRoutineDefinition({
24775
+ name: `${parentTaskName} (sub-routine)`,
24776
+ description: `Sub-routine of ${parentTaskName}`,
24777
+ tasks: spec
24778
+ });
24779
+ }
24780
+ function getPlugins(agent) {
24781
+ const icmPlugin = agent.context.getPlugin("in_context_memory");
24782
+ const wmPlugin = agent.context.memory;
24783
+ return { icmPlugin, wmPlugin };
24784
+ }
24785
+ function cleanMapKeys(icmPlugin) {
24786
+ if (!icmPlugin) return;
24787
+ icmPlugin.delete(ROUTINE_KEYS.MAP_ITEM);
24788
+ icmPlugin.delete(ROUTINE_KEYS.MAP_INDEX);
24789
+ icmPlugin.delete(ROUTINE_KEYS.MAP_TOTAL);
24790
+ }
24791
+ function cleanFoldKeys(icmPlugin) {
24792
+ if (!icmPlugin) return;
24793
+ cleanMapKeys(icmPlugin);
24794
+ icmPlugin.delete(ROUTINE_KEYS.FOLD_ACCUMULATOR);
24795
+ }
24796
+ async function readSourceArray(flow, flowType, icmPlugin, wmPlugin) {
24797
+ const sourceValue = await readMemoryValue(flow.sourceKey, icmPlugin, wmPlugin);
24798
+ if (!Array.isArray(sourceValue)) {
24799
+ return {
24800
+ completed: false,
24801
+ error: `${flowType} sourceKey "${flow.sourceKey}" is not an array (got ${typeof sourceValue})`
24802
+ };
24803
+ }
24804
+ const maxIter = Math.min(sourceValue.length, flow.maxIterations ?? sourceValue.length, HARD_MAX_ITERATIONS);
24805
+ return { array: sourceValue, maxIter };
24806
+ }
24807
+ function prepareSubRoutine(tasks, parentTaskName) {
24808
+ const subRoutine = resolveSubRoutine(tasks, parentTaskName);
24809
+ return {
24810
+ augmented: { ...subRoutine },
24811
+ baseInstructions: subRoutine.instructions ?? ""
24812
+ };
24813
+ }
24814
+ function getSubRoutineOutput(execution) {
24815
+ const tasks = execution.plan.tasks;
24816
+ for (let i = tasks.length - 1; i >= 0; i--) {
24817
+ if (tasks[i].status === "completed") {
24818
+ return tasks[i].result?.output ?? null;
24819
+ }
24820
+ }
24821
+ return null;
24822
+ }
24823
+ function setIterationKeys(icmPlugin, item, index, total, label) {
24824
+ if (!icmPlugin) return;
24825
+ icmPlugin.set(ROUTINE_KEYS.MAP_ITEM, `Current ${label} item (${index + 1}/${total})`, item, "high");
24826
+ icmPlugin.set(ROUTINE_KEYS.MAP_INDEX, `Current ${label} index (0-based)`, index, "high");
24827
+ icmPlugin.set(ROUTINE_KEYS.MAP_TOTAL, `Total items in ${label}`, total, "high");
24828
+ }
24829
+ async function withTimeout(promise, timeoutMs, label) {
24830
+ if (!timeoutMs) return promise;
24831
+ let timer;
24832
+ const timeout = new Promise((_, reject) => {
24833
+ timer = setTimeout(() => reject(new Error(`${label} timed out after ${timeoutMs}ms`)), timeoutMs);
24834
+ });
24835
+ try {
24836
+ return await Promise.race([promise, timeout]);
24837
+ } finally {
24838
+ clearTimeout(timer);
24839
+ }
24840
+ }
24841
+ async function handleMap(agent, flow, task, inputs) {
24842
+ const { icmPlugin, wmPlugin } = getPlugins(agent);
24843
+ const log = logger.child({ controlFlow: "map", task: task.name });
24844
+ const sourceResult = await readSourceArray(flow, "Map", icmPlugin, wmPlugin);
24845
+ if ("completed" in sourceResult) return sourceResult;
24846
+ const { array: array3, maxIter } = sourceResult;
24847
+ const results = [];
24848
+ const { augmented, baseInstructions } = prepareSubRoutine(flow.tasks, task.name);
24849
+ log.info({ arrayLength: array3.length, maxIterations: maxIter }, "Starting map iteration");
24850
+ try {
24851
+ for (let i = 0; i < maxIter; i++) {
24852
+ setIterationKeys(icmPlugin, array3[i], i, array3.length, "map");
24853
+ augmented.instructions = [
24854
+ `You are processing item ${i + 1} of ${array3.length} in a map operation.`,
24855
+ "The current item is available in your live context as __map_item.",
24856
+ "Current index (0-based) is in __map_index, total count in __map_total.",
24857
+ "",
24858
+ baseInstructions
24859
+ ].join("\n");
24860
+ const subExecution = await withTimeout(
24861
+ executeRoutine({ definition: augmented, agent, inputs }),
24862
+ flow.iterationTimeoutMs,
24863
+ `Map iteration ${i}`
24864
+ );
24865
+ if (subExecution.status !== "completed") {
24866
+ return {
24867
+ completed: false,
24868
+ error: `Map iteration ${i} failed: ${subExecution.error ?? "sub-routine failed"}`
24869
+ };
24870
+ }
24871
+ results.push(getSubRoutineOutput(subExecution));
24872
+ }
24873
+ } finally {
24874
+ cleanMapKeys(icmPlugin);
24875
+ }
24876
+ if (flow.resultKey) {
24877
+ await storeResult(flow.resultKey, `Map results from "${task.name}"`, results, icmPlugin, wmPlugin);
24878
+ }
24879
+ log.info({ resultCount: results.length }, "Map completed");
24880
+ return { completed: true, result: results };
24881
+ }
24882
+ async function handleFold(agent, flow, task, inputs) {
24883
+ const { icmPlugin, wmPlugin } = getPlugins(agent);
24884
+ const log = logger.child({ controlFlow: "fold", task: task.name });
24885
+ const sourceResult = await readSourceArray(flow, "Fold", icmPlugin, wmPlugin);
24886
+ if ("completed" in sourceResult) return sourceResult;
24887
+ const { array: array3, maxIter } = sourceResult;
24888
+ let accumulator = flow.initialValue;
24889
+ const { augmented, baseInstructions } = prepareSubRoutine(flow.tasks, task.name);
24890
+ log.info({ arrayLength: array3.length, maxIterations: maxIter }, "Starting fold iteration");
24891
+ try {
24892
+ for (let i = 0; i < maxIter; i++) {
24893
+ setIterationKeys(icmPlugin, array3[i], i, array3.length, "fold");
24894
+ if (icmPlugin) {
24895
+ icmPlugin.set(ROUTINE_KEYS.FOLD_ACCUMULATOR, "Running accumulator \u2014 update via context_set", accumulator, "high");
24896
+ }
24897
+ augmented.instructions = [
24898
+ `You are processing item ${i + 1} of ${array3.length} in a fold/accumulate operation.`,
24899
+ "The current item is in __map_item. The running accumulator is in __fold_accumulator.",
24900
+ "After processing, use context_set to update __fold_accumulator with the new accumulated value.",
24901
+ "Your final text response will also be captured as the result.",
24902
+ "",
24903
+ baseInstructions
24904
+ ].join("\n");
24905
+ const subExecution = await withTimeout(
24906
+ executeRoutine({ definition: augmented, agent, inputs }),
24907
+ flow.iterationTimeoutMs,
24908
+ `Fold iteration ${i}`
24909
+ );
24910
+ if (subExecution.status !== "completed") {
24911
+ return {
24912
+ completed: false,
24913
+ error: `Fold iteration ${i} failed: ${subExecution.error ?? "sub-routine failed"}`
24914
+ };
24915
+ }
24916
+ const taskOutput = getSubRoutineOutput(subExecution);
24917
+ if (taskOutput !== null) {
24918
+ accumulator = taskOutput;
24919
+ } else if (icmPlugin) {
24920
+ const icmAccumulator = icmPlugin.get(ROUTINE_KEYS.FOLD_ACCUMULATOR);
24921
+ if (icmAccumulator !== void 0) {
24922
+ accumulator = icmAccumulator;
24923
+ }
24924
+ }
24925
+ }
24926
+ } finally {
24927
+ cleanFoldKeys(icmPlugin);
24928
+ }
24929
+ await storeResult(flow.resultKey, `Fold result from "${task.name}"`, accumulator, icmPlugin, wmPlugin);
24930
+ log.info("Fold completed");
24931
+ return { completed: true, result: accumulator };
24932
+ }
24933
+ async function handleUntil(agent, flow, task, inputs) {
24934
+ const { icmPlugin, wmPlugin } = getPlugins(agent);
24935
+ const log = logger.child({ controlFlow: "until", task: task.name });
24936
+ const { augmented, baseInstructions } = prepareSubRoutine(flow.tasks, task.name);
24937
+ log.info({ maxIterations: flow.maxIterations }, "Starting until loop");
24938
+ const memoryAccess = {
24939
+ get: (key) => readMemoryValue(key, icmPlugin, wmPlugin)
24940
+ };
24941
+ try {
24942
+ for (let i = 0; i < flow.maxIterations; i++) {
24943
+ if (flow.iterationKey && icmPlugin) {
24944
+ icmPlugin.set(flow.iterationKey, "Current iteration index", i, "high");
24945
+ }
24946
+ augmented.instructions = [
24947
+ `You are in iteration ${i + 1} of a repeating operation (max ${flow.maxIterations}).`,
24948
+ "Complete the task. The loop will continue until its exit condition is met.",
24949
+ "",
24950
+ baseInstructions
24951
+ ].join("\n");
24952
+ const subExecution = await withTimeout(
24953
+ executeRoutine({ definition: augmented, agent, inputs }),
24954
+ flow.iterationTimeoutMs,
24955
+ `Until iteration ${i}`
24956
+ );
24957
+ if (subExecution.status !== "completed") {
24958
+ return {
24959
+ completed: false,
24960
+ error: `Until iteration ${i} failed: ${subExecution.error ?? "sub-routine failed"}`
24961
+ };
24962
+ }
24963
+ const conditionMet = await evaluateCondition(flow.condition, memoryAccess);
24964
+ if (conditionMet) {
24965
+ log.info({ iteration: i + 1 }, "Until condition met");
24966
+ return { completed: true };
24967
+ }
24968
+ }
24969
+ } finally {
24970
+ if (flow.iterationKey && icmPlugin) {
24971
+ icmPlugin.delete(flow.iterationKey);
24972
+ }
24973
+ }
24974
+ return { completed: false, error: `Until loop: maxIterations (${flow.maxIterations}) exceeded` };
24975
+ }
24976
+ async function executeControlFlow(agent, task, inputs) {
24977
+ const flow = task.controlFlow;
24978
+ switch (flow.type) {
24979
+ case "map":
24980
+ return handleMap(agent, flow, task, inputs);
24981
+ case "fold":
24982
+ return handleFold(agent, flow, task, inputs);
24983
+ case "until":
24984
+ return handleUntil(agent, flow, task, inputs);
24985
+ default:
24986
+ return { completed: false, error: `Unknown control flow type: ${flow.type}` };
24987
+ }
24988
+ }
24989
+
24990
+ // src/core/routineRunner.ts
24471
24991
  function defaultSystemPrompt(definition) {
24472
24992
  const parts = [];
24473
24993
  if (definition.instructions) {
@@ -24596,6 +25116,14 @@ async function collectValidationContext(agent, responseText) {
24596
25116
  toolCallLog
24597
25117
  };
24598
25118
  }
25119
+ function isTransientError(error) {
25120
+ if (error instanceof ProviderAuthError) return false;
25121
+ if (error instanceof ProviderContextLengthError) return false;
25122
+ if (error instanceof ProviderNotFoundError) return false;
25123
+ if (error instanceof ModelNotSupportedError) return false;
25124
+ if (error instanceof InvalidConfigError) return false;
25125
+ return true;
25126
+ }
24599
25127
  function estimateTokens(text) {
24600
25128
  return Math.ceil(text.length / 4);
24601
25129
  }
@@ -24639,32 +25167,42 @@ function buildPlanOverview(execution, definition, currentTaskId) {
24639
25167
  }
24640
25168
  return parts.join("\n");
24641
25169
  }
24642
- async function injectRoutineContext(agent, execution, definition, currentTask) {
24643
- const icmPlugin = agent.context.getPlugin("in_context_memory");
24644
- const wmPlugin = agent.context.memory;
24645
- if (!icmPlugin && !wmPlugin) {
24646
- logger.warn("injectRoutineContext: No ICM or WM plugin available \u2014 skipping context injection");
24647
- return;
24648
- }
24649
- const planOverview = buildPlanOverview(execution, definition, currentTask.id);
24650
- if (icmPlugin) {
24651
- icmPlugin.set("__routine_plan", "Routine plan overview with task statuses", planOverview, "high");
24652
- }
25170
+ async function cleanupMemoryKeys(icmPlugin, wmPlugin, config) {
24653
25171
  if (icmPlugin) {
24654
25172
  for (const entry of icmPlugin.list()) {
24655
- if (entry.key.startsWith("__dep_result_") || entry.key === "__routine_deps") {
24656
- icmPlugin.delete(entry.key);
24657
- }
25173
+ const shouldDelete = config.icmPrefixes.some((p) => entry.key.startsWith(p)) || (config.icmExactKeys?.includes(entry.key) ?? false);
25174
+ if (shouldDelete) icmPlugin.delete(entry.key);
24658
25175
  }
24659
25176
  }
24660
25177
  if (wmPlugin) {
24661
25178
  const { entries: wmEntries } = await wmPlugin.query();
24662
25179
  for (const entry of wmEntries) {
24663
- if (entry.key.startsWith("__dep_result_") || entry.key.startsWith("findings/__dep_result_")) {
25180
+ if (config.wmPrefixes.some((p) => entry.key.startsWith(p))) {
24664
25181
  await wmPlugin.delete(entry.key);
24665
25182
  }
24666
25183
  }
24667
25184
  }
25185
+ }
25186
+ var DEP_CLEANUP_CONFIG = {
25187
+ icmPrefixes: [ROUTINE_KEYS.DEP_RESULT_PREFIX],
25188
+ icmExactKeys: [ROUTINE_KEYS.DEPS],
25189
+ wmPrefixes: [ROUTINE_KEYS.DEP_RESULT_PREFIX, ROUTINE_KEYS.WM_DEP_FINDINGS_PREFIX]
25190
+ };
25191
+ var FULL_CLEANUP_CONFIG = {
25192
+ icmPrefixes: ["__routine_", ROUTINE_KEYS.DEP_RESULT_PREFIX, "__map_", "__fold_"],
25193
+ wmPrefixes: [ROUTINE_KEYS.DEP_RESULT_PREFIX, ROUTINE_KEYS.WM_DEP_FINDINGS_PREFIX]
25194
+ };
25195
+ async function injectRoutineContext(agent, execution, definition, currentTask) {
25196
+ const { icmPlugin, wmPlugin } = getPlugins(agent);
25197
+ if (!icmPlugin && !wmPlugin) {
25198
+ logger.warn("injectRoutineContext: No ICM or WM plugin available \u2014 skipping context injection");
25199
+ return;
25200
+ }
25201
+ const planOverview = buildPlanOverview(execution, definition, currentTask.id);
25202
+ if (icmPlugin) {
25203
+ icmPlugin.set(ROUTINE_KEYS.PLAN, "Routine plan overview with task statuses", planOverview, "high");
25204
+ }
25205
+ await cleanupMemoryKeys(icmPlugin, wmPlugin, DEP_CLEANUP_CONFIG);
24668
25206
  if (currentTask.dependsOn.length === 0) return;
24669
25207
  const inContextDeps = [];
24670
25208
  const workingMemoryDeps = [];
@@ -24673,7 +25211,7 @@ async function injectRoutineContext(agent, execution, definition, currentTask) {
24673
25211
  if (!depTask?.result?.output) continue;
24674
25212
  const output = typeof depTask.result.output === "string" ? depTask.result.output : JSON.stringify(depTask.result.output);
24675
25213
  const tokens = estimateTokens(output);
24676
- const depKey = `__dep_result_${depId}`;
25214
+ const depKey = `${ROUTINE_KEYS.DEP_RESULT_PREFIX}${depId}`;
24677
25215
  const depLabel = `Result from task "${depTask.name}"`;
24678
25216
  if (tokens < 5e3 && icmPlugin) {
24679
25217
  icmPlugin.set(depKey, depLabel, output, "high");
@@ -24695,27 +25233,12 @@ async function injectRoutineContext(agent, execution, definition, currentTask) {
24695
25233
  if (workingMemoryDeps.length > 0) {
24696
25234
  summaryParts.push(`In working memory (use memory_retrieve): ${workingMemoryDeps.join(", ")}`);
24697
25235
  }
24698
- icmPlugin.set("__routine_deps", "Dependency results location guide", summaryParts.join("\n"), "high");
25236
+ icmPlugin.set(ROUTINE_KEYS.DEPS, "Dependency results location guide", summaryParts.join("\n"), "high");
24699
25237
  }
24700
25238
  }
24701
25239
  async function cleanupRoutineContext(agent) {
24702
- const icmPlugin = agent.context.getPlugin("in_context_memory");
24703
- const wmPlugin = agent.context.memory;
24704
- if (icmPlugin) {
24705
- for (const entry of icmPlugin.list()) {
24706
- if (entry.key.startsWith("__routine_") || entry.key.startsWith("__dep_result_")) {
24707
- icmPlugin.delete(entry.key);
24708
- }
24709
- }
24710
- }
24711
- if (wmPlugin) {
24712
- const { entries: wmEntries } = await wmPlugin.query();
24713
- for (const entry of wmEntries) {
24714
- if (entry.key.startsWith("__dep_result_") || entry.key.startsWith("findings/__dep_result_")) {
24715
- await wmPlugin.delete(entry.key);
24716
- }
24717
- }
24718
- }
25240
+ const { icmPlugin, wmPlugin } = getPlugins(agent);
25241
+ await cleanupMemoryKeys(icmPlugin, wmPlugin, FULL_CLEANUP_CONFIG);
24719
25242
  }
24720
25243
  async function validateTaskCompletion(agent, task, responseText, validationPromptBuilder) {
24721
25244
  const hasExplicitValidation = task.validation?.skipReflection === false && task.validation?.completionCriteria && task.validation.completionCriteria.length > 0;
@@ -24764,11 +25287,13 @@ async function executeRoutine(options) {
24764
25287
  onTaskFailed,
24765
25288
  onTaskValidation,
24766
25289
  hooks,
24767
- prompts
25290
+ prompts,
25291
+ inputs: rawInputs
24768
25292
  } = options;
24769
25293
  if (!existingAgent && (!connector || !model)) {
24770
25294
  throw new Error("executeRoutine requires either `agent` or both `connector` and `model`");
24771
25295
  }
25296
+ const resolvedInputs = validateAndResolveInputs(definition.parameters, rawInputs);
24772
25297
  const ownsAgent = !existingAgent;
24773
25298
  const log = logger.child({ routine: definition.name });
24774
25299
  const execution = createRoutineExecution(definition);
@@ -24861,85 +25386,115 @@ async function executeRoutine(options) {
24861
25386
  return { shouldPause: false };
24862
25387
  };
24863
25388
  agent.registerHook("pause:check", iterationLimiter);
24864
- const getTask = () => execution.plan.tasks[taskIndex];
24865
- await injectRoutineContext(agent, execution, definition, getTask());
24866
- while (!taskCompleted) {
24867
- try {
24868
- const taskPrompt = buildTaskPrompt(getTask());
24869
- const response = await agent.run(taskPrompt);
24870
- const responseText = response.output_text ?? "";
24871
- const validationResult = await validateTaskCompletion(
24872
- agent,
24873
- getTask(),
24874
- responseText,
24875
- buildValidationPrompt
24876
- );
24877
- onTaskValidation?.(getTask(), validationResult, execution);
24878
- if (validationResult.isComplete) {
24879
- execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "completed");
24880
- execution.plan.tasks[taskIndex].result = {
24881
- success: true,
24882
- output: responseText,
24883
- validationScore: validationResult.completionScore,
24884
- validationExplanation: validationResult.explanation
24885
- };
24886
- taskCompleted = true;
24887
- log.info(
24888
- { taskName: getTask().name, score: validationResult.completionScore },
24889
- "Task completed"
24890
- );
24891
- execution.progress = getRoutineProgress(execution);
24892
- execution.lastUpdatedAt = Date.now();
24893
- onTaskComplete?.(execution.plan.tasks[taskIndex], execution);
24894
- } else {
24895
- log.warn(
24896
- {
24897
- taskName: getTask().name,
24898
- score: validationResult.completionScore,
24899
- attempt: getTask().attempts,
24900
- maxAttempts: getTask().maxAttempts
24901
- },
24902
- "Task validation failed"
24903
- );
24904
- if (getTask().attempts >= getTask().maxAttempts) {
25389
+ try {
25390
+ const getTask = () => execution.plan.tasks[taskIndex];
25391
+ await injectRoutineContext(agent, execution, definition, getTask());
25392
+ const { icmPlugin } = getPlugins(agent);
25393
+ if (getTask().controlFlow) {
25394
+ try {
25395
+ const cfResult = await executeControlFlow(agent, getTask(), resolvedInputs);
25396
+ if (cfResult.completed) {
25397
+ execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "completed");
25398
+ execution.plan.tasks[taskIndex].result = { success: true, output: cfResult.result };
25399
+ taskCompleted = true;
25400
+ execution.progress = getRoutineProgress(execution);
25401
+ execution.lastUpdatedAt = Date.now();
25402
+ onTaskComplete?.(execution.plan.tasks[taskIndex], execution);
25403
+ } else {
24905
25404
  execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
24906
- execution.plan.tasks[taskIndex].result = {
24907
- success: false,
24908
- error: validationResult.explanation,
24909
- validationScore: validationResult.completionScore,
24910
- validationExplanation: validationResult.explanation
24911
- };
24912
- break;
25405
+ execution.plan.tasks[taskIndex].result = { success: false, error: cfResult.error };
24913
25406
  }
24914
- execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
24915
- }
24916
- } catch (error) {
24917
- const errorMessage = error.message;
24918
- log.error({ taskName: getTask().name, error: errorMessage }, "Task execution error");
24919
- if (getTask().attempts >= getTask().maxAttempts) {
25407
+ } catch (error) {
25408
+ const errorMessage = error.message;
25409
+ log.error({ taskName: getTask().name, error: errorMessage }, "Control flow error");
24920
25410
  execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
24921
- execution.plan.tasks[taskIndex].result = {
24922
- success: false,
24923
- error: errorMessage
24924
- };
24925
- break;
25411
+ execution.plan.tasks[taskIndex].result = { success: false, error: errorMessage };
25412
+ }
25413
+ } else {
25414
+ while (!taskCompleted) {
25415
+ try {
25416
+ const resolvedTask = resolveTaskTemplates(getTask(), resolvedInputs, icmPlugin);
25417
+ const taskPrompt = buildTaskPrompt(resolvedTask);
25418
+ const response = await agent.run(taskPrompt);
25419
+ const responseText = response.output_text ?? "";
25420
+ const validationResult = await validateTaskCompletion(
25421
+ agent,
25422
+ getTask(),
25423
+ responseText,
25424
+ buildValidationPrompt
25425
+ );
25426
+ onTaskValidation?.(getTask(), validationResult, execution);
25427
+ if (validationResult.isComplete) {
25428
+ execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "completed");
25429
+ execution.plan.tasks[taskIndex].result = {
25430
+ success: true,
25431
+ output: responseText,
25432
+ validationScore: validationResult.completionScore,
25433
+ validationExplanation: validationResult.explanation
25434
+ };
25435
+ taskCompleted = true;
25436
+ log.info(
25437
+ { taskName: getTask().name, score: validationResult.completionScore },
25438
+ "Task completed"
25439
+ );
25440
+ execution.progress = getRoutineProgress(execution);
25441
+ execution.lastUpdatedAt = Date.now();
25442
+ onTaskComplete?.(execution.plan.tasks[taskIndex], execution);
25443
+ } else {
25444
+ log.warn(
25445
+ {
25446
+ taskName: getTask().name,
25447
+ score: validationResult.completionScore,
25448
+ attempt: getTask().attempts,
25449
+ maxAttempts: getTask().maxAttempts
25450
+ },
25451
+ "Task validation failed"
25452
+ );
25453
+ if (getTask().attempts >= getTask().maxAttempts) {
25454
+ execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
25455
+ execution.plan.tasks[taskIndex].result = {
25456
+ success: false,
25457
+ error: validationResult.explanation,
25458
+ validationScore: validationResult.completionScore,
25459
+ validationExplanation: validationResult.explanation
25460
+ };
25461
+ break;
25462
+ }
25463
+ execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
25464
+ }
25465
+ } catch (error) {
25466
+ const errorMessage = error.message;
25467
+ log.error({ taskName: getTask().name, error: errorMessage }, "Task execution error");
25468
+ if (!isTransientError(error) || getTask().attempts >= getTask().maxAttempts) {
25469
+ execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
25470
+ execution.plan.tasks[taskIndex].result = {
25471
+ success: false,
25472
+ error: errorMessage
25473
+ };
25474
+ break;
25475
+ }
25476
+ execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
25477
+ }
24926
25478
  }
24927
- execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
24928
25479
  }
24929
- }
24930
- if (!taskCompleted) {
24931
- execution.progress = getRoutineProgress(execution);
24932
- execution.lastUpdatedAt = Date.now();
24933
- onTaskFailed?.(execution.plan.tasks[taskIndex], execution);
24934
- if (failureMode === "fail-fast") {
24935
- execution.status = "failed";
24936
- execution.error = `Task "${getTask().name}" failed after ${getTask().attempts} attempt(s)`;
24937
- execution.completedAt = Date.now();
25480
+ if (!taskCompleted) {
25481
+ execution.progress = getRoutineProgress(execution);
24938
25482
  execution.lastUpdatedAt = Date.now();
24939
- break;
25483
+ onTaskFailed?.(execution.plan.tasks[taskIndex], execution);
25484
+ if (failureMode === "fail-fast") {
25485
+ execution.status = "failed";
25486
+ execution.error = `Task "${getTask().name}" failed after ${getTask().attempts} attempt(s)`;
25487
+ execution.completedAt = Date.now();
25488
+ execution.lastUpdatedAt = Date.now();
25489
+ break;
25490
+ }
25491
+ }
25492
+ } finally {
25493
+ try {
25494
+ agent.unregisterHook("pause:check", iterationLimiter);
25495
+ } catch {
24940
25496
  }
24941
25497
  }
24942
- agent.unregisterHook("pause:check", iterationLimiter);
24943
25498
  agent.clearConversation("task-boundary");
24944
25499
  nextTasks = getNextExecutableTasks(execution.plan);
24945
25500
  }
@@ -24967,16 +25522,22 @@ async function executeRoutine(options) {
24967
25522
  } finally {
24968
25523
  try {
24969
25524
  await cleanupRoutineContext(agent);
24970
- } catch {
25525
+ } catch (e) {
25526
+ log.debug({ error: e.message }, "Failed to clean up routine context");
24971
25527
  }
24972
25528
  for (const { name, hook } of registeredHooks) {
24973
25529
  try {
24974
25530
  agent.unregisterHook(name, hook);
24975
- } catch {
25531
+ } catch (e) {
25532
+ log.debug({ hookName: name, error: e.message }, "Failed to unregister hook");
24976
25533
  }
24977
25534
  }
24978
25535
  if (ownsAgent) {
24979
- agent.destroy();
25536
+ try {
25537
+ agent.destroy();
25538
+ } catch (e) {
25539
+ log.debug({ error: e.message }, "Failed to destroy agent");
25540
+ }
24980
25541
  }
24981
25542
  }
24982
25543
  }
@@ -31783,7 +32344,7 @@ var TextToSpeech = class _TextToSpeech {
31783
32344
  */
31784
32345
  async toFile(text, filePath, options) {
31785
32346
  const response = await this.synthesize(text, options);
31786
- await fs18.writeFile(filePath, response.audio);
32347
+ await fs17.writeFile(filePath, response.audio);
31787
32348
  }
31788
32349
  // ======================== Introspection Methods ========================
31789
32350
  /**
@@ -32131,7 +32692,7 @@ var SpeechToText = class _SpeechToText {
32131
32692
  * @param options - Optional transcription parameters
32132
32693
  */
32133
32694
  async transcribeFile(filePath, options) {
32134
- const audio = await fs18.readFile(filePath);
32695
+ const audio = await fs17.readFile(filePath);
32135
32696
  return this.transcribe(audio, options);
32136
32697
  }
32137
32698
  /**
@@ -38874,10 +39435,10 @@ var FileMediaStorage = class {
38874
39435
  }
38875
39436
  async save(data, metadata) {
38876
39437
  const dir = metadata.userId ? path2.join(this.outputDir, metadata.userId) : this.outputDir;
38877
- await fs18.mkdir(dir, { recursive: true });
39438
+ await fs17.mkdir(dir, { recursive: true });
38878
39439
  const filename = metadata.suggestedFilename ?? this.generateFilename(metadata);
38879
39440
  const filePath = path2.join(dir, filename);
38880
- await fs18.writeFile(filePath, data);
39441
+ await fs17.writeFile(filePath, data);
38881
39442
  const format = metadata.format.toLowerCase();
38882
39443
  const mimeType = MIME_TYPES2[format] ?? "application/octet-stream";
38883
39444
  return {
@@ -38888,7 +39449,7 @@ var FileMediaStorage = class {
38888
39449
  }
38889
39450
  async read(location) {
38890
39451
  try {
38891
- return await fs18.readFile(location);
39452
+ return await fs17.readFile(location);
38892
39453
  } catch (err) {
38893
39454
  if (err.code === "ENOENT") {
38894
39455
  return null;
@@ -38898,7 +39459,7 @@ var FileMediaStorage = class {
38898
39459
  }
38899
39460
  async delete(location) {
38900
39461
  try {
38901
- await fs18.unlink(location);
39462
+ await fs17.unlink(location);
38902
39463
  } catch (err) {
38903
39464
  if (err.code === "ENOENT") {
38904
39465
  return;
@@ -38908,7 +39469,7 @@ var FileMediaStorage = class {
38908
39469
  }
38909
39470
  async exists(location) {
38910
39471
  try {
38911
- await fs18.access(location);
39472
+ await fs17.access(location);
38912
39473
  return true;
38913
39474
  } catch {
38914
39475
  return false;
@@ -38917,11 +39478,11 @@ var FileMediaStorage = class {
38917
39478
  async list(options) {
38918
39479
  await this.ensureDir();
38919
39480
  let entries = [];
38920
- const files = await fs18.readdir(this.outputDir);
39481
+ const files = await fs17.readdir(this.outputDir);
38921
39482
  for (const file of files) {
38922
39483
  const filePath = path2.join(this.outputDir, file);
38923
39484
  try {
38924
- const stat6 = await fs18.stat(filePath);
39485
+ const stat6 = await fs17.stat(filePath);
38925
39486
  if (!stat6.isFile()) continue;
38926
39487
  const ext = path2.extname(file).slice(1).toLowerCase();
38927
39488
  const mimeType = MIME_TYPES2[ext] ?? "application/octet-stream";
@@ -38961,7 +39522,7 @@ var FileMediaStorage = class {
38961
39522
  }
38962
39523
  async ensureDir() {
38963
39524
  if (!this.initialized) {
38964
- await fs18.mkdir(this.outputDir, { recursive: true });
39525
+ await fs17.mkdir(this.outputDir, { recursive: true });
38965
39526
  this.initialized = true;
38966
39527
  }
38967
39528
  }
@@ -39813,6 +40374,15 @@ var SERVICE_DEFINITIONS = [
39813
40374
  baseURL: "https://api.telegram.org",
39814
40375
  docsURL: "https://core.telegram.org/bots/api"
39815
40376
  },
40377
+ {
40378
+ id: "twitter",
40379
+ name: "X (Twitter)",
40380
+ category: "communication",
40381
+ urlPattern: /api\.x\.com|api\.twitter\.com/i,
40382
+ baseURL: "https://api.x.com/2",
40383
+ docsURL: "https://developer.x.com/en/docs/x-api",
40384
+ commonScopes: ["tweet.read", "tweet.write", "users.read", "offline.access"]
40385
+ },
39816
40386
  // ============ Development & Project Management ============
39817
40387
  {
39818
40388
  id: "github",
@@ -40300,19 +40870,30 @@ var ConnectorTools = class {
40300
40870
  */
40301
40871
  static for(connectorOrName, userId, options) {
40302
40872
  const connector = this.resolveConnector(connectorOrName, options?.registry);
40873
+ const accountId = options?.accountId;
40303
40874
  const tools = [];
40875
+ const namePrefix = accountId ? `${sanitizeToolName(connector.name)}_${sanitizeToolName(accountId)}` : sanitizeToolName(connector.name);
40304
40876
  if (connector.baseURL) {
40305
- tools.push(this.createGenericAPITool(connector, { userId }));
40877
+ const accountLabel = accountId ? ` (account: ${accountId})` : "";
40878
+ tools.push(this.createGenericAPITool(connector, {
40879
+ userId,
40880
+ accountId,
40881
+ toolName: `${namePrefix}_api`,
40882
+ 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.'
40883
+ }));
40306
40884
  }
40307
40885
  const serviceType = this.detectService(connector);
40308
40886
  if (serviceType && this.factories.has(serviceType)) {
40309
40887
  const factory = this.factories.get(serviceType);
40310
40888
  const serviceTools = factory(connector, userId);
40311
40889
  for (const tool of serviceTools) {
40312
- tool.definition.function.name = `${sanitizeToolName(connector.name)}_${tool.definition.function.name}`;
40890
+ tool.definition.function.name = `${namePrefix}_${tool.definition.function.name}`;
40313
40891
  }
40314
40892
  tools.push(...serviceTools);
40315
40893
  }
40894
+ if (accountId) {
40895
+ return tools.map((tool) => this.bindAccountId(tool, accountId));
40896
+ }
40316
40897
  return tools;
40317
40898
  }
40318
40899
  /**
@@ -40462,6 +41043,56 @@ var ConnectorTools = class {
40462
41043
  }
40463
41044
  return connectorOrName;
40464
41045
  }
41046
+ /**
41047
+ * Generate tools for a set of auth identities.
41048
+ * Each identity gets its own tool set with unique name prefixes.
41049
+ *
41050
+ * @param identities - Array of auth identities
41051
+ * @param userId - Optional user ID for multi-user OAuth
41052
+ * @param options - Optional registry for scoped connector lookup
41053
+ * @returns Map of identity key to tool array
41054
+ *
41055
+ * @example
41056
+ * ```typescript
41057
+ * const toolsByIdentity = ConnectorTools.forIdentities([
41058
+ * { connector: 'microsoft', accountId: 'work' },
41059
+ * { connector: 'microsoft', accountId: 'personal' },
41060
+ * { connector: 'github' },
41061
+ * ]);
41062
+ * // Keys: 'microsoft:work', 'microsoft:personal', 'github'
41063
+ * ```
41064
+ */
41065
+ static forIdentities(identities, userId, options) {
41066
+ const result = /* @__PURE__ */ new Map();
41067
+ for (const identity of identities) {
41068
+ const key = identity.accountId ? `${identity.connector}:${identity.accountId}` : identity.connector;
41069
+ try {
41070
+ const tools = this.for(identity.connector, userId, {
41071
+ registry: options?.registry,
41072
+ accountId: identity.accountId
41073
+ });
41074
+ if (tools.length > 0) {
41075
+ result.set(key, tools);
41076
+ }
41077
+ } catch (err) {
41078
+ logger.error(`[ConnectorTools.forIdentities] Error generating tools for identity ${key}: ${err instanceof Error ? err.message : String(err)}`);
41079
+ }
41080
+ }
41081
+ return result;
41082
+ }
41083
+ /**
41084
+ * Wrap a tool to inject accountId into ToolContext at execute time.
41085
+ * This allows identity-bound tools to use the correct account without
41086
+ * modifying every service tool factory.
41087
+ */
41088
+ static bindAccountId(tool, accountId) {
41089
+ return {
41090
+ ...tool,
41091
+ execute: async (args, context) => {
41092
+ return tool.execute(args, { ...context, accountId });
41093
+ }
41094
+ };
41095
+ }
40465
41096
  static createGenericAPITool(connector, options) {
40466
41097
  const toolName = options?.toolName ?? `${sanitizeToolName(connector.name)}_api`;
40467
41098
  const userId = options?.userId;
@@ -40503,6 +41134,7 @@ var ConnectorTools = class {
40503
41134
  },
40504
41135
  execute: async (args, context) => {
40505
41136
  const effectiveUserId = context?.userId ?? userId;
41137
+ const effectiveAccountId = context?.accountId;
40506
41138
  let url2 = args.endpoint;
40507
41139
  if (args.queryParams && Object.keys(args.queryParams).length > 0) {
40508
41140
  const params = new URLSearchParams();
@@ -40535,7 +41167,8 @@ var ConnectorTools = class {
40535
41167
  },
40536
41168
  body: bodyStr
40537
41169
  },
40538
- effectiveUserId
41170
+ effectiveUserId,
41171
+ effectiveAccountId
40539
41172
  );
40540
41173
  const text = await response.text();
40541
41174
  let data;
@@ -40596,8 +41229,8 @@ var FileStorage = class {
40596
41229
  }
40597
41230
  async ensureDirectory() {
40598
41231
  try {
40599
- await fs18.mkdir(this.directory, { recursive: true });
40600
- await fs18.chmod(this.directory, 448);
41232
+ await fs17.mkdir(this.directory, { recursive: true });
41233
+ await fs17.chmod(this.directory, 448);
40601
41234
  } catch (error) {
40602
41235
  }
40603
41236
  }
@@ -40611,24 +41244,27 @@ var FileStorage = class {
40611
41244
  async storeToken(key, token) {
40612
41245
  await this.ensureDirectory();
40613
41246
  const filePath = this.getFilePath(key);
40614
- const plaintext = JSON.stringify(token);
41247
+ const tokenWithKey = { ...token, _storageKey: key };
41248
+ const plaintext = JSON.stringify(tokenWithKey);
40615
41249
  const encrypted = encrypt(plaintext, this.encryptionKey);
40616
- await fs18.writeFile(filePath, encrypted, "utf8");
40617
- await fs18.chmod(filePath, 384);
41250
+ await fs17.writeFile(filePath, encrypted, "utf8");
41251
+ await fs17.chmod(filePath, 384);
40618
41252
  }
40619
41253
  async getToken(key) {
40620
41254
  const filePath = this.getFilePath(key);
40621
41255
  try {
40622
- const encrypted = await fs18.readFile(filePath, "utf8");
41256
+ const encrypted = await fs17.readFile(filePath, "utf8");
40623
41257
  const decrypted = decrypt(encrypted, this.encryptionKey);
40624
- return JSON.parse(decrypted);
41258
+ const parsed = JSON.parse(decrypted);
41259
+ const { _storageKey, ...token } = parsed;
41260
+ return token;
40625
41261
  } catch (error) {
40626
41262
  if (error.code === "ENOENT") {
40627
41263
  return null;
40628
41264
  }
40629
41265
  console.error("Failed to read/decrypt token file:", error);
40630
41266
  try {
40631
- await fs18.unlink(filePath);
41267
+ await fs17.unlink(filePath);
40632
41268
  } catch {
40633
41269
  }
40634
41270
  return null;
@@ -40637,7 +41273,7 @@ var FileStorage = class {
40637
41273
  async deleteToken(key) {
40638
41274
  const filePath = this.getFilePath(key);
40639
41275
  try {
40640
- await fs18.unlink(filePath);
41276
+ await fs17.unlink(filePath);
40641
41277
  } catch (error) {
40642
41278
  if (error.code !== "ENOENT") {
40643
41279
  throw error;
@@ -40647,18 +41283,44 @@ var FileStorage = class {
40647
41283
  async hasToken(key) {
40648
41284
  const filePath = this.getFilePath(key);
40649
41285
  try {
40650
- await fs18.access(filePath);
41286
+ await fs17.access(filePath);
40651
41287
  return true;
40652
41288
  } catch {
40653
41289
  return false;
40654
41290
  }
40655
41291
  }
41292
+ /**
41293
+ * List all storage keys by decrypting each token file and reading _storageKey.
41294
+ * Falls back to returning hashed filenames for tokens stored before multi-account support.
41295
+ */
41296
+ async listKeys() {
41297
+ try {
41298
+ const files = await fs17.readdir(this.directory);
41299
+ const tokenFiles = files.filter((f) => f.endsWith(".token"));
41300
+ const keys = [];
41301
+ for (const file of tokenFiles) {
41302
+ try {
41303
+ const filePath = path2.join(this.directory, file);
41304
+ const encrypted = await fs17.readFile(filePath, "utf8");
41305
+ const decrypted = decrypt(encrypted, this.encryptionKey);
41306
+ const parsed = JSON.parse(decrypted);
41307
+ if (parsed._storageKey) {
41308
+ keys.push(parsed._storageKey);
41309
+ }
41310
+ } catch {
41311
+ }
41312
+ }
41313
+ return keys;
41314
+ } catch {
41315
+ return [];
41316
+ }
41317
+ }
40656
41318
  /**
40657
41319
  * List all token keys (for debugging)
40658
41320
  */
40659
41321
  async listTokens() {
40660
41322
  try {
40661
- const files = await fs18.readdir(this.directory);
41323
+ const files = await fs17.readdir(this.directory);
40662
41324
  return files.filter((f) => f.endsWith(".token")).map((f) => f.replace(".token", ""));
40663
41325
  } catch {
40664
41326
  return [];
@@ -40669,10 +41331,10 @@ var FileStorage = class {
40669
41331
  */
40670
41332
  async clearAll() {
40671
41333
  try {
40672
- const files = await fs18.readdir(this.directory);
41334
+ const files = await fs17.readdir(this.directory);
40673
41335
  const tokenFiles = files.filter((f) => f.endsWith(".token"));
40674
41336
  await Promise.all(
40675
- tokenFiles.map((f) => fs18.unlink(path2.join(this.directory, f)).catch(() => {
41337
+ tokenFiles.map((f) => fs17.unlink(path2.join(this.directory, f)).catch(() => {
40676
41338
  }))
40677
41339
  );
40678
41340
  } catch {
@@ -40682,14 +41344,14 @@ var FileStorage = class {
40682
41344
 
40683
41345
  // src/connectors/authenticatedFetch.ts
40684
41346
  init_Connector();
40685
- async function authenticatedFetch(url2, options, authProvider, userId) {
41347
+ async function authenticatedFetch(url2, options, authProvider, userId, accountId) {
40686
41348
  const connector = Connector.get(authProvider);
40687
- return connector.fetch(url2.toString(), options, userId);
41349
+ return connector.fetch(url2.toString(), options, userId, accountId);
40688
41350
  }
40689
- function createAuthenticatedFetch(authProvider, userId) {
41351
+ function createAuthenticatedFetch(authProvider, userId, accountId) {
40690
41352
  const connector = Connector.get(authProvider);
40691
41353
  return async (url2, options) => {
40692
- return connector.fetch(url2.toString(), options, userId);
41354
+ return connector.fetch(url2.toString(), options, userId, accountId);
40693
41355
  };
40694
41356
  }
40695
41357
 
@@ -41120,14 +41782,14 @@ var FileConnectorStorage = class {
41120
41782
  await this.ensureDirectory();
41121
41783
  const filePath = this.getFilePath(name);
41122
41784
  const json = JSON.stringify(stored, null, 2);
41123
- await fs18.writeFile(filePath, json, "utf8");
41124
- await fs18.chmod(filePath, 384);
41785
+ await fs17.writeFile(filePath, json, "utf8");
41786
+ await fs17.chmod(filePath, 384);
41125
41787
  await this.updateIndex(name, "add");
41126
41788
  }
41127
41789
  async get(name) {
41128
41790
  const filePath = this.getFilePath(name);
41129
41791
  try {
41130
- const json = await fs18.readFile(filePath, "utf8");
41792
+ const json = await fs17.readFile(filePath, "utf8");
41131
41793
  return JSON.parse(json);
41132
41794
  } catch (error) {
41133
41795
  const err = error;
@@ -41140,7 +41802,7 @@ var FileConnectorStorage = class {
41140
41802
  async delete(name) {
41141
41803
  const filePath = this.getFilePath(name);
41142
41804
  try {
41143
- await fs18.unlink(filePath);
41805
+ await fs17.unlink(filePath);
41144
41806
  await this.updateIndex(name, "remove");
41145
41807
  return true;
41146
41808
  } catch (error) {
@@ -41154,7 +41816,7 @@ var FileConnectorStorage = class {
41154
41816
  async has(name) {
41155
41817
  const filePath = this.getFilePath(name);
41156
41818
  try {
41157
- await fs18.access(filePath);
41819
+ await fs17.access(filePath);
41158
41820
  return true;
41159
41821
  } catch {
41160
41822
  return false;
@@ -41180,13 +41842,13 @@ var FileConnectorStorage = class {
41180
41842
  */
41181
41843
  async clear() {
41182
41844
  try {
41183
- const files = await fs18.readdir(this.directory);
41845
+ const files = await fs17.readdir(this.directory);
41184
41846
  const connectorFiles = files.filter(
41185
41847
  (f) => f.endsWith(".connector.json") || f === "_index.json"
41186
41848
  );
41187
41849
  await Promise.all(
41188
41850
  connectorFiles.map(
41189
- (f) => fs18.unlink(path2.join(this.directory, f)).catch(() => {
41851
+ (f) => fs17.unlink(path2.join(this.directory, f)).catch(() => {
41190
41852
  })
41191
41853
  )
41192
41854
  );
@@ -41213,8 +41875,8 @@ var FileConnectorStorage = class {
41213
41875
  async ensureDirectory() {
41214
41876
  if (this.initialized) return;
41215
41877
  try {
41216
- await fs18.mkdir(this.directory, { recursive: true });
41217
- await fs18.chmod(this.directory, 448);
41878
+ await fs17.mkdir(this.directory, { recursive: true });
41879
+ await fs17.chmod(this.directory, 448);
41218
41880
  this.initialized = true;
41219
41881
  } catch {
41220
41882
  this.initialized = true;
@@ -41225,7 +41887,7 @@ var FileConnectorStorage = class {
41225
41887
  */
41226
41888
  async loadIndex() {
41227
41889
  try {
41228
- const json = await fs18.readFile(this.indexPath, "utf8");
41890
+ const json = await fs17.readFile(this.indexPath, "utf8");
41229
41891
  return JSON.parse(json);
41230
41892
  } catch {
41231
41893
  return { connectors: {} };
@@ -41243,8 +41905,8 @@ var FileConnectorStorage = class {
41243
41905
  delete index.connectors[hash];
41244
41906
  }
41245
41907
  const json = JSON.stringify(index, null, 2);
41246
- await fs18.writeFile(this.indexPath, json, "utf8");
41247
- await fs18.chmod(this.indexPath, 384);
41908
+ await fs17.writeFile(this.indexPath, json, "utf8");
41909
+ await fs17.chmod(this.indexPath, 384);
41248
41910
  }
41249
41911
  };
41250
41912
 
@@ -41467,14 +42129,15 @@ var microsoftTemplate = {
41467
42129
  name: "OAuth (Delegated Permissions)",
41468
42130
  type: "oauth",
41469
42131
  flow: "authorization_code",
41470
- description: "User signs in with Microsoft account. Best for accessing user data (mail, calendar, files)",
41471
- requiredFields: ["clientId", "clientSecret", "redirectUri", "tenantId"],
41472
- optionalFields: ["scope"],
42132
+ 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).",
42133
+ requiredFields: ["clientId", "redirectUri", "tenantId"],
42134
+ optionalFields: ["clientSecret", "scope"],
41473
42135
  defaults: {
41474
42136
  type: "oauth",
41475
42137
  flow: "authorization_code",
41476
42138
  authorizationUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize",
41477
- tokenUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token"
42139
+ tokenUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token",
42140
+ usePKCE: true
41478
42141
  },
41479
42142
  scopes: [
41480
42143
  "User.Read",
@@ -41560,14 +42223,15 @@ var googleTemplate = {
41560
42223
  name: "OAuth (User Consent)",
41561
42224
  type: "oauth",
41562
42225
  flow: "authorization_code",
41563
- description: "User logs in with Google account. Best for accessing user data (Drive, Gmail, Calendar)",
41564
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41565
- optionalFields: ["scope"],
42226
+ 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).",
42227
+ requiredFields: ["clientId", "redirectUri"],
42228
+ optionalFields: ["clientSecret", "scope"],
41566
42229
  defaults: {
41567
42230
  type: "oauth",
41568
42231
  flow: "authorization_code",
41569
42232
  authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",
41570
- tokenUrl: "https://oauth2.googleapis.com/token"
42233
+ tokenUrl: "https://oauth2.googleapis.com/token",
42234
+ usePKCE: true
41571
42235
  },
41572
42236
  scopes: [
41573
42237
  "https://www.googleapis.com/auth/drive",
@@ -41646,14 +42310,15 @@ var slackTemplate = {
41646
42310
  name: "OAuth (User Token)",
41647
42311
  type: "oauth",
41648
42312
  flow: "authorization_code",
41649
- description: "Distributed app - users authorize via Slack OAuth",
41650
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41651
- optionalFields: ["scope", "userScope"],
42313
+ description: "Distributed app - users authorize via Slack OAuth. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
42314
+ requiredFields: ["clientId", "redirectUri"],
42315
+ optionalFields: ["clientSecret", "scope", "userScope"],
41652
42316
  defaults: {
41653
42317
  type: "oauth",
41654
42318
  flow: "authorization_code",
41655
42319
  authorizationUrl: "https://slack.com/oauth/v2/authorize",
41656
- tokenUrl: "https://slack.com/api/oauth.v2.access"
42320
+ tokenUrl: "https://slack.com/api/oauth.v2.access",
42321
+ usePKCE: true
41657
42322
  },
41658
42323
  scopes: ["chat:write", "channels:read", "users:read", "im:write", "groups:read", "files:read", "files:write", "reactions:read", "reactions:write", "team:read"],
41659
42324
  scopeDescriptions: {
@@ -41699,14 +42364,15 @@ var discordTemplate = {
41699
42364
  name: "OAuth (User Token)",
41700
42365
  type: "oauth",
41701
42366
  flow: "authorization_code",
41702
- description: "OAuth2 for user authorization - users grant permissions to your app",
41703
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41704
- optionalFields: ["scope"],
42367
+ description: "OAuth2 for user authorization - users grant permissions to your app. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
42368
+ requiredFields: ["clientId", "redirectUri"],
42369
+ optionalFields: ["clientSecret", "scope"],
41705
42370
  defaults: {
41706
42371
  type: "oauth",
41707
42372
  flow: "authorization_code",
41708
42373
  authorizationUrl: "https://discord.com/api/oauth2/authorize",
41709
- tokenUrl: "https://discord.com/api/oauth2/token"
42374
+ tokenUrl: "https://discord.com/api/oauth2/token",
42375
+ usePKCE: true
41710
42376
  },
41711
42377
  scopes: ["identify", "email", "guilds", "guilds.members.read", "messages.read", "bot", "connections"],
41712
42378
  scopeDescriptions: {
@@ -41748,6 +42414,92 @@ var telegramTemplate = {
41748
42414
  ]
41749
42415
  };
41750
42416
 
42417
+ // src/connectors/vendors/templates/twitter.ts
42418
+ var twitterTemplate = {
42419
+ id: "twitter",
42420
+ name: "X (Twitter)",
42421
+ serviceType: "twitter",
42422
+ baseURL: "https://api.x.com/2",
42423
+ docsURL: "https://developer.x.com/en/docs/x-api",
42424
+ credentialsSetupURL: "https://developer.x.com/en/portal/dashboard",
42425
+ category: "communication",
42426
+ notes: "X (formerly Twitter) API v2. OAuth 2.0 with PKCE for user-context actions, Bearer Token for app-only access.",
42427
+ authTemplates: [
42428
+ {
42429
+ id: "oauth-user",
42430
+ name: "OAuth 2.0 (User Context)",
42431
+ type: "oauth",
42432
+ flow: "authorization_code",
42433
+ 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).",
42434
+ requiredFields: ["clientId", "redirectUri"],
42435
+ optionalFields: ["clientSecret", "scope"],
42436
+ defaults: {
42437
+ type: "oauth",
42438
+ flow: "authorization_code",
42439
+ authorizationUrl: "https://x.com/i/oauth2/authorize",
42440
+ tokenUrl: "https://api.x.com/2/oauth2/token",
42441
+ usePKCE: true
42442
+ },
42443
+ scopes: [
42444
+ "tweet.read",
42445
+ "tweet.write",
42446
+ "tweet.moderate.write",
42447
+ "users.read",
42448
+ "follows.read",
42449
+ "follows.write",
42450
+ "like.read",
42451
+ "like.write",
42452
+ "bookmark.read",
42453
+ "bookmark.write",
42454
+ "list.read",
42455
+ "list.write",
42456
+ "block.read",
42457
+ "block.write",
42458
+ "mute.read",
42459
+ "mute.write",
42460
+ "space.read",
42461
+ "dm.read",
42462
+ "dm.write",
42463
+ "offline.access"
42464
+ ],
42465
+ scopeDescriptions: {
42466
+ "tweet.read": "Read tweets and timelines",
42467
+ "tweet.write": "Post and delete tweets",
42468
+ "tweet.moderate.write": "Hide and unhide replies",
42469
+ "users.read": "Read user profile information",
42470
+ "follows.read": "Read following/followers lists",
42471
+ "follows.write": "Follow and unfollow users",
42472
+ "like.read": "Read liked tweets",
42473
+ "like.write": "Like and unlike tweets",
42474
+ "bookmark.read": "Read bookmarked tweets",
42475
+ "bookmark.write": "Bookmark and remove bookmarks",
42476
+ "list.read": "Read lists",
42477
+ "list.write": "Create, edit, and delete lists",
42478
+ "block.read": "Read blocked users",
42479
+ "block.write": "Block and unblock users",
42480
+ "mute.read": "Read muted users",
42481
+ "mute.write": "Mute and unmute users",
42482
+ "space.read": "Read Spaces information",
42483
+ "dm.read": "Read direct messages",
42484
+ "dm.write": "Send direct messages",
42485
+ "offline.access": "Stay connected (refresh token)"
42486
+ }
42487
+ },
42488
+ {
42489
+ id: "bearer-token",
42490
+ name: "Bearer Token (App-Only)",
42491
+ type: "api_key",
42492
+ description: "App-only access using Bearer Token from developer portal. Can read public tweets, users, and spaces but cannot post or access private data.",
42493
+ requiredFields: ["apiKey"],
42494
+ defaults: {
42495
+ type: "api_key",
42496
+ headerName: "Authorization",
42497
+ headerPrefix: "Bearer"
42498
+ }
42499
+ }
42500
+ ]
42501
+ };
42502
+
41751
42503
  // src/connectors/vendors/templates/github.ts
41752
42504
  var githubTemplate = {
41753
42505
  id: "github",
@@ -41775,14 +42527,15 @@ var githubTemplate = {
41775
42527
  name: "OAuth App (User Authorization)",
41776
42528
  type: "oauth",
41777
42529
  flow: "authorization_code",
41778
- description: "User logs in via GitHub and grants permissions to your app",
41779
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41780
- optionalFields: ["scope"],
42530
+ 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).",
42531
+ requiredFields: ["clientId", "redirectUri"],
42532
+ optionalFields: ["clientSecret", "scope"],
41781
42533
  defaults: {
41782
42534
  type: "oauth",
41783
42535
  flow: "authorization_code",
41784
42536
  authorizationUrl: "https://github.com/login/oauth/authorize",
41785
- tokenUrl: "https://github.com/login/oauth/access_token"
42537
+ tokenUrl: "https://github.com/login/oauth/access_token",
42538
+ usePKCE: true
41786
42539
  },
41787
42540
  scopes: ["repo", "read:user", "user:email", "read:org", "workflow", "gist", "notifications", "delete_repo", "admin:org"],
41788
42541
  scopeDescriptions: {
@@ -41841,14 +42594,15 @@ var gitlabTemplate = {
41841
42594
  name: "OAuth (User Authorization)",
41842
42595
  type: "oauth",
41843
42596
  flow: "authorization_code",
41844
- description: "OAuth2 application for user authorization",
41845
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41846
- optionalFields: ["scope"],
42597
+ description: "OAuth2 application for user authorization. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
42598
+ requiredFields: ["clientId", "redirectUri"],
42599
+ optionalFields: ["clientSecret", "scope"],
41847
42600
  defaults: {
41848
42601
  type: "oauth",
41849
42602
  flow: "authorization_code",
41850
42603
  authorizationUrl: "https://gitlab.com/oauth/authorize",
41851
- tokenUrl: "https://gitlab.com/oauth/token"
42604
+ tokenUrl: "https://gitlab.com/oauth/token",
42605
+ usePKCE: true
41852
42606
  },
41853
42607
  scopes: ["api", "read_user", "read_repository", "write_repository"],
41854
42608
  scopeDescriptions: {
@@ -41889,14 +42643,15 @@ var jiraTemplate = {
41889
42643
  name: "OAuth 2.0 (3LO)",
41890
42644
  type: "oauth",
41891
42645
  flow: "authorization_code",
41892
- description: "Three-legged OAuth for user authorization. Create app at developer.atlassian.com",
41893
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41894
- optionalFields: ["scope"],
42646
+ 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).",
42647
+ requiredFields: ["clientId", "redirectUri"],
42648
+ optionalFields: ["clientSecret", "scope"],
41895
42649
  defaults: {
41896
42650
  type: "oauth",
41897
42651
  flow: "authorization_code",
41898
42652
  authorizationUrl: "https://auth.atlassian.com/authorize",
41899
- tokenUrl: "https://auth.atlassian.com/oauth/token"
42653
+ tokenUrl: "https://auth.atlassian.com/oauth/token",
42654
+ usePKCE: true
41900
42655
  },
41901
42656
  scopes: ["read:jira-work", "write:jira-work", "read:jira-user", "manage:jira-project", "manage:jira-configuration"],
41902
42657
  scopeDescriptions: {
@@ -41936,14 +42691,15 @@ var confluenceTemplate = {
41936
42691
  name: "OAuth 2.0 (3LO)",
41937
42692
  type: "oauth",
41938
42693
  flow: "authorization_code",
41939
- description: "Three-legged OAuth for user authorization",
41940
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41941
- optionalFields: ["scope"],
42694
+ description: "Three-legged OAuth for user authorization. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
42695
+ requiredFields: ["clientId", "redirectUri"],
42696
+ optionalFields: ["clientSecret", "scope"],
41942
42697
  defaults: {
41943
42698
  type: "oauth",
41944
42699
  flow: "authorization_code",
41945
42700
  authorizationUrl: "https://auth.atlassian.com/authorize",
41946
- tokenUrl: "https://auth.atlassian.com/oauth/token"
42701
+ tokenUrl: "https://auth.atlassian.com/oauth/token",
42702
+ usePKCE: true
41947
42703
  },
41948
42704
  scopes: ["read:confluence-content.all", "write:confluence-content", "read:confluence-space.summary", "write:confluence-space", "read:confluence-user"],
41949
42705
  scopeDescriptions: {
@@ -41982,14 +42738,15 @@ var bitbucketTemplate = {
41982
42738
  name: "OAuth Consumer",
41983
42739
  type: "oauth",
41984
42740
  flow: "authorization_code",
41985
- description: "OAuth consumer for user authorization. Create at Workspace Settings > OAuth consumers",
41986
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41987
- optionalFields: ["scope"],
42741
+ 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).",
42742
+ requiredFields: ["clientId", "redirectUri"],
42743
+ optionalFields: ["clientSecret", "scope"],
41988
42744
  defaults: {
41989
42745
  type: "oauth",
41990
42746
  flow: "authorization_code",
41991
42747
  authorizationUrl: "https://bitbucket.org/site/oauth2/authorize",
41992
- tokenUrl: "https://bitbucket.org/site/oauth2/access_token"
42748
+ tokenUrl: "https://bitbucket.org/site/oauth2/access_token",
42749
+ usePKCE: true
41993
42750
  },
41994
42751
  scopes: ["repository", "repository:write", "pullrequest", "pullrequest:write", "account", "pipeline", "wiki"],
41995
42752
  scopeDescriptions: {
@@ -42031,14 +42788,15 @@ var trelloTemplate = {
42031
42788
  name: "OAuth 1.0a",
42032
42789
  type: "oauth",
42033
42790
  flow: "authorization_code",
42034
- description: "OAuth 1.0a for user authorization (legacy)",
42035
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42036
- optionalFields: ["scope"],
42791
+ description: "OAuth 1.0a for user authorization (legacy). Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
42792
+ requiredFields: ["clientId", "redirectUri"],
42793
+ optionalFields: ["clientSecret", "scope"],
42037
42794
  defaults: {
42038
42795
  type: "oauth",
42039
42796
  flow: "authorization_code",
42040
42797
  authorizationUrl: "https://trello.com/1/authorize",
42041
- tokenUrl: "https://trello.com/1/OAuthGetAccessToken"
42798
+ tokenUrl: "https://trello.com/1/OAuthGetAccessToken",
42799
+ usePKCE: true
42042
42800
  },
42043
42801
  scopes: ["read", "write", "account"],
42044
42802
  scopeDescriptions: {
@@ -42078,14 +42836,15 @@ var linearTemplate = {
42078
42836
  name: "OAuth (User Authorization)",
42079
42837
  type: "oauth",
42080
42838
  flow: "authorization_code",
42081
- description: "OAuth application for user authorization. Create at Settings > API > OAuth applications",
42082
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42083
- optionalFields: ["scope"],
42839
+ 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).",
42840
+ requiredFields: ["clientId", "redirectUri"],
42841
+ optionalFields: ["clientSecret", "scope"],
42084
42842
  defaults: {
42085
42843
  type: "oauth",
42086
42844
  flow: "authorization_code",
42087
42845
  authorizationUrl: "https://linear.app/oauth/authorize",
42088
- tokenUrl: "https://api.linear.app/oauth/token"
42846
+ tokenUrl: "https://api.linear.app/oauth/token",
42847
+ usePKCE: true
42089
42848
  },
42090
42849
  scopes: ["read", "write", "issues:create", "comments:create"]
42091
42850
  }
@@ -42119,14 +42878,15 @@ var asanaTemplate = {
42119
42878
  name: "OAuth (User Authorization)",
42120
42879
  type: "oauth",
42121
42880
  flow: "authorization_code",
42122
- description: "OAuth application for user authorization. Create at developer console",
42123
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42124
- optionalFields: ["scope"],
42881
+ description: "OAuth application for user authorization. Create at developer console. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
42882
+ requiredFields: ["clientId", "redirectUri"],
42883
+ optionalFields: ["clientSecret", "scope"],
42125
42884
  defaults: {
42126
42885
  type: "oauth",
42127
42886
  flow: "authorization_code",
42128
42887
  authorizationUrl: "https://app.asana.com/-/oauth_authorize",
42129
- tokenUrl: "https://app.asana.com/-/oauth_token"
42888
+ tokenUrl: "https://app.asana.com/-/oauth_token",
42889
+ usePKCE: true
42130
42890
  },
42131
42891
  scopes: ["default"]
42132
42892
  }
@@ -42160,14 +42920,15 @@ var notionTemplate = {
42160
42920
  name: "Public Integration (OAuth)",
42161
42921
  type: "oauth",
42162
42922
  flow: "authorization_code",
42163
- description: "Public integration for multi-workspace access",
42164
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42165
- optionalFields: ["scope"],
42923
+ description: "Public integration for multi-workspace access. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
42924
+ requiredFields: ["clientId", "redirectUri"],
42925
+ optionalFields: ["clientSecret", "scope"],
42166
42926
  defaults: {
42167
42927
  type: "oauth",
42168
42928
  flow: "authorization_code",
42169
42929
  authorizationUrl: "https://api.notion.com/v1/oauth/authorize",
42170
- tokenUrl: "https://api.notion.com/v1/oauth/token"
42930
+ tokenUrl: "https://api.notion.com/v1/oauth/token",
42931
+ usePKCE: true
42171
42932
  }
42172
42933
  }
42173
42934
  ]
@@ -42200,9 +42961,9 @@ var airtableTemplate = {
42200
42961
  name: "OAuth (User Authorization)",
42201
42962
  type: "oauth",
42202
42963
  flow: "authorization_code",
42203
- description: "OAuth integration for multi-user access. Register at airtable.com/create/oauth",
42204
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42205
- optionalFields: ["scope"],
42964
+ 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).",
42965
+ requiredFields: ["clientId", "redirectUri"],
42966
+ optionalFields: ["clientSecret", "scope"],
42206
42967
  defaults: {
42207
42968
  type: "oauth",
42208
42969
  flow: "authorization_code",
@@ -42231,14 +42992,15 @@ var salesforceTemplate = {
42231
42992
  name: "OAuth (User Authorization)",
42232
42993
  type: "oauth",
42233
42994
  flow: "authorization_code",
42234
- description: "User logs in via Salesforce. Create Connected App in Setup",
42235
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42236
- optionalFields: ["scope"],
42995
+ description: "User logs in via Salesforce. Create Connected App in Setup. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
42996
+ requiredFields: ["clientId", "redirectUri"],
42997
+ optionalFields: ["clientSecret", "scope"],
42237
42998
  defaults: {
42238
42999
  type: "oauth",
42239
43000
  flow: "authorization_code",
42240
43001
  authorizationUrl: "https://login.salesforce.com/services/oauth2/authorize",
42241
- tokenUrl: "https://login.salesforce.com/services/oauth2/token"
43002
+ tokenUrl: "https://login.salesforce.com/services/oauth2/token",
43003
+ usePKCE: true
42242
43004
  },
42243
43005
  scopes: ["api", "refresh_token", "offline_access", "chatter_api", "wave_api", "full"],
42244
43006
  scopeDescriptions: {
@@ -42294,14 +43056,15 @@ var hubspotTemplate = {
42294
43056
  name: "OAuth (User Authorization)",
42295
43057
  type: "oauth",
42296
43058
  flow: "authorization_code",
42297
- description: "Public app OAuth for multi-portal access. Create app at developers.hubspot.com",
42298
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42299
- optionalFields: ["scope"],
43059
+ 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).",
43060
+ requiredFields: ["clientId", "redirectUri"],
43061
+ optionalFields: ["clientSecret", "scope"],
42300
43062
  defaults: {
42301
43063
  type: "oauth",
42302
43064
  flow: "authorization_code",
42303
43065
  authorizationUrl: "https://app.hubspot.com/oauth/authorize",
42304
- tokenUrl: "https://api.hubapi.com/oauth/v1/token"
43066
+ tokenUrl: "https://api.hubapi.com/oauth/v1/token",
43067
+ usePKCE: true
42305
43068
  },
42306
43069
  scopes: [
42307
43070
  "crm.objects.contacts.read",
@@ -42323,6 +43086,22 @@ var hubspotTemplate = {
42323
43086
  "tickets": "Read and write support tickets",
42324
43087
  "e-commerce": "Access e-commerce data (products, line items)"
42325
43088
  }
43089
+ },
43090
+ {
43091
+ id: "oauth-mcp",
43092
+ name: "MCP Auth App (OAuth 2.1)",
43093
+ type: "oauth",
43094
+ flow: "authorization_code",
43095
+ 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.",
43096
+ requiredFields: ["clientId", "redirectUri"],
43097
+ optionalFields: ["clientSecret"],
43098
+ defaults: {
43099
+ type: "oauth",
43100
+ flow: "authorization_code",
43101
+ authorizationUrl: "https://mcp.hubspot.com/oauth/authorize/user",
43102
+ tokenUrl: "https://mcp.hubspot.com/oauth/v1/token",
43103
+ usePKCE: true
43104
+ }
42326
43105
  }
42327
43106
  ]
42328
43107
  };
@@ -42354,14 +43133,15 @@ var pipedriveTemplate = {
42354
43133
  name: "OAuth (App Authorization)",
42355
43134
  type: "oauth",
42356
43135
  flow: "authorization_code",
42357
- description: "OAuth app for marketplace distribution. Create at developers.pipedrive.com",
42358
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42359
- optionalFields: ["scope"],
43136
+ description: "OAuth app for marketplace distribution. Create at developers.pipedrive.com. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
43137
+ requiredFields: ["clientId", "redirectUri"],
43138
+ optionalFields: ["clientSecret", "scope"],
42360
43139
  defaults: {
42361
43140
  type: "oauth",
42362
43141
  flow: "authorization_code",
42363
43142
  authorizationUrl: "https://oauth.pipedrive.com/oauth/authorize",
42364
- tokenUrl: "https://oauth.pipedrive.com/oauth/token"
43143
+ tokenUrl: "https://oauth.pipedrive.com/oauth/token",
43144
+ usePKCE: true
42365
43145
  }
42366
43146
  }
42367
43147
  ]
@@ -42394,14 +43174,15 @@ var stripeTemplate = {
42394
43174
  name: "OAuth (Stripe Connect)",
42395
43175
  type: "oauth",
42396
43176
  flow: "authorization_code",
42397
- description: "Stripe Connect for marketplace platforms. Requires Connect setup in dashboard",
42398
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42399
- optionalFields: ["scope"],
43177
+ description: "Stripe Connect for marketplace platforms. Requires Connect setup in dashboard. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
43178
+ requiredFields: ["clientId", "redirectUri"],
43179
+ optionalFields: ["clientSecret", "scope"],
42400
43180
  defaults: {
42401
43181
  type: "oauth",
42402
43182
  flow: "authorization_code",
42403
43183
  authorizationUrl: "https://connect.stripe.com/oauth/authorize",
42404
- tokenUrl: "https://connect.stripe.com/oauth/token"
43184
+ tokenUrl: "https://connect.stripe.com/oauth/token",
43185
+ usePKCE: true
42405
43186
  },
42406
43187
  scopes: ["read_write"]
42407
43188
  }
@@ -42451,14 +43232,15 @@ var quickbooksTemplate = {
42451
43232
  name: "OAuth (User Authorization)",
42452
43233
  type: "oauth",
42453
43234
  flow: "authorization_code",
42454
- description: "Standard OAuth 2.0 flow for accessing QuickBooks on behalf of a user. Create an app at developer.intuit.com",
42455
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42456
- optionalFields: ["scope"],
43235
+ 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).",
43236
+ requiredFields: ["clientId", "redirectUri"],
43237
+ optionalFields: ["clientSecret", "scope"],
42457
43238
  defaults: {
42458
43239
  type: "oauth",
42459
43240
  flow: "authorization_code",
42460
43241
  authorizationUrl: "https://appcenter.intuit.com/connect/oauth2",
42461
- tokenUrl: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"
43242
+ tokenUrl: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
43243
+ usePKCE: true
42462
43244
  },
42463
43245
  scopes: ["com.intuit.quickbooks.accounting", "com.intuit.quickbooks.payment"]
42464
43246
  }
@@ -42493,14 +43275,15 @@ var rampTemplate = {
42493
43275
  name: "OAuth (User Authorization)",
42494
43276
  type: "oauth",
42495
43277
  flow: "authorization_code",
42496
- description: "OAuth 2.0 authorization code flow for accessing Ramp on behalf of a user",
42497
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42498
- optionalFields: ["scope"],
43278
+ 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).",
43279
+ requiredFields: ["clientId", "redirectUri"],
43280
+ optionalFields: ["clientSecret", "scope"],
42499
43281
  defaults: {
42500
43282
  type: "oauth",
42501
43283
  flow: "authorization_code",
42502
43284
  authorizationUrl: "https://app.ramp.com/v1/authorize",
42503
- tokenUrl: "https://api.ramp.com/developer/v1/token"
43285
+ tokenUrl: "https://api.ramp.com/developer/v1/token",
43286
+ usePKCE: true
42504
43287
  },
42505
43288
  scopes: [
42506
43289
  "transactions:read",
@@ -42557,9 +43340,9 @@ var dropboxTemplate = {
42557
43340
  name: "OAuth (User Authorization)",
42558
43341
  type: "oauth",
42559
43342
  flow: "authorization_code",
42560
- description: "OAuth app for user authorization. Create app at dropbox.com/developers/apps",
42561
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42562
- optionalFields: ["scope"],
43343
+ 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).",
43344
+ requiredFields: ["clientId", "redirectUri"],
43345
+ optionalFields: ["clientSecret", "scope"],
42563
43346
  defaults: {
42564
43347
  type: "oauth",
42565
43348
  flow: "authorization_code",
@@ -42596,14 +43379,15 @@ var boxTemplate = {
42596
43379
  name: "OAuth (User Authorization)",
42597
43380
  type: "oauth",
42598
43381
  flow: "authorization_code",
42599
- description: "OAuth 2.0 for user authorization. Create app at developer.box.com/console",
42600
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42601
- optionalFields: ["scope"],
43382
+ 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).",
43383
+ requiredFields: ["clientId", "redirectUri"],
43384
+ optionalFields: ["clientSecret", "scope"],
42602
43385
  defaults: {
42603
43386
  type: "oauth",
42604
43387
  flow: "authorization_code",
42605
43388
  authorizationUrl: "https://account.box.com/api/oauth2/authorize",
42606
- tokenUrl: "https://api.box.com/oauth2/token"
43389
+ tokenUrl: "https://api.box.com/oauth2/token",
43390
+ usePKCE: true
42607
43391
  },
42608
43392
  scopes: ["root_readwrite", "manage_users", "manage_groups", "manage_enterprise"],
42609
43393
  scopeDescriptions: {
@@ -42681,13 +43465,15 @@ var mailchimpTemplate = {
42681
43465
  name: "OAuth (User Authorization)",
42682
43466
  type: "oauth",
42683
43467
  flow: "authorization_code",
42684
- description: "OAuth for multi-account access. Register app at mailchimp.com/developer",
42685
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
43468
+ 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).",
43469
+ requiredFields: ["clientId", "redirectUri"],
43470
+ optionalFields: ["clientSecret"],
42686
43471
  defaults: {
42687
43472
  type: "oauth",
42688
43473
  flow: "authorization_code",
42689
43474
  authorizationUrl: "https://login.mailchimp.com/oauth2/authorize",
42690
- tokenUrl: "https://login.mailchimp.com/oauth2/token"
43475
+ tokenUrl: "https://login.mailchimp.com/oauth2/token",
43476
+ usePKCE: true
42691
43477
  }
42692
43478
  }
42693
43479
  ]
@@ -42779,14 +43565,15 @@ var pagerdutyTemplate = {
42779
43565
  name: "OAuth (App Authorization)",
42780
43566
  type: "oauth",
42781
43567
  flow: "authorization_code",
42782
- description: "OAuth app for multi-account access. Register at developer.pagerduty.com",
42783
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42784
- optionalFields: ["scope"],
43568
+ 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).",
43569
+ requiredFields: ["clientId", "redirectUri"],
43570
+ optionalFields: ["clientSecret", "scope"],
42785
43571
  defaults: {
42786
43572
  type: "oauth",
42787
43573
  flow: "authorization_code",
42788
43574
  authorizationUrl: "https://app.pagerduty.com/oauth/authorize",
42789
- tokenUrl: "https://app.pagerduty.com/oauth/token"
43575
+ tokenUrl: "https://app.pagerduty.com/oauth/token",
43576
+ usePKCE: true
42790
43577
  },
42791
43578
  scopes: ["read", "write"],
42792
43579
  scopeDescriptions: {
@@ -42822,14 +43609,15 @@ var sentryTemplate = {
42822
43609
  name: "OAuth (Integration)",
42823
43610
  type: "oauth",
42824
43611
  flow: "authorization_code",
42825
- description: "OAuth integration. Create at Organization Settings > Integrations",
42826
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42827
- optionalFields: ["scope"],
43612
+ description: "OAuth integration. Create at Organization Settings > Integrations. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
43613
+ requiredFields: ["clientId", "redirectUri"],
43614
+ optionalFields: ["clientSecret", "scope"],
42828
43615
  defaults: {
42829
43616
  type: "oauth",
42830
43617
  flow: "authorization_code",
42831
43618
  authorizationUrl: "https://sentry.io/oauth/authorize/",
42832
- tokenUrl: "https://sentry.io/oauth/token/"
43619
+ tokenUrl: "https://sentry.io/oauth/token/",
43620
+ usePKCE: true
42833
43621
  },
42834
43622
  scopes: ["project:read", "project:write", "event:read", "org:read", "member:read"],
42835
43623
  scopeDescriptions: {
@@ -43026,14 +43814,15 @@ var zendeskTemplate = {
43026
43814
  name: "OAuth (User Authorization)",
43027
43815
  type: "oauth",
43028
43816
  flow: "authorization_code",
43029
- description: "OAuth client for user authorization. Create at Admin > Channels > API > OAuth Clients",
43030
- requiredFields: ["clientId", "clientSecret", "redirectUri", "subdomain"],
43031
- optionalFields: ["scope"],
43817
+ 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).",
43818
+ requiredFields: ["clientId", "redirectUri", "subdomain"],
43819
+ optionalFields: ["clientSecret", "scope"],
43032
43820
  defaults: {
43033
43821
  type: "oauth",
43034
43822
  flow: "authorization_code",
43035
43823
  authorizationUrl: "https://{subdomain}.zendesk.com/oauth/authorizations/new",
43036
- tokenUrl: "https://{subdomain}.zendesk.com/oauth/tokens"
43824
+ tokenUrl: "https://{subdomain}.zendesk.com/oauth/tokens",
43825
+ usePKCE: true
43037
43826
  },
43038
43827
  scopes: ["read", "write", "tickets:read", "tickets:write"],
43039
43828
  scopeDescriptions: {
@@ -43071,13 +43860,15 @@ var intercomTemplate = {
43071
43860
  name: "OAuth (App Installation)",
43072
43861
  type: "oauth",
43073
43862
  flow: "authorization_code",
43074
- description: "OAuth for Intercom app marketplace distribution",
43075
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
43863
+ description: "OAuth for Intercom app marketplace distribution. Provide clientSecret for web apps; omit for native/desktop apps (secured via PKCE).",
43864
+ requiredFields: ["clientId", "redirectUri"],
43865
+ optionalFields: ["clientSecret"],
43076
43866
  defaults: {
43077
43867
  type: "oauth",
43078
43868
  flow: "authorization_code",
43079
43869
  authorizationUrl: "https://app.intercom.com/oauth",
43080
- tokenUrl: "https://api.intercom.io/auth/eagle/token"
43870
+ tokenUrl: "https://api.intercom.io/auth/eagle/token",
43871
+ usePKCE: true
43081
43872
  }
43082
43873
  }
43083
43874
  ]
@@ -43110,14 +43901,15 @@ var shopifyTemplate = {
43110
43901
  name: "OAuth (Public/Custom App)",
43111
43902
  type: "oauth",
43112
43903
  flow: "authorization_code",
43113
- description: "OAuth for public apps or per-store custom apps. Create at partners.shopify.com",
43114
- requiredFields: ["clientId", "clientSecret", "redirectUri", "subdomain"],
43115
- optionalFields: ["scope"],
43904
+ 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).",
43905
+ requiredFields: ["clientId", "redirectUri", "subdomain"],
43906
+ optionalFields: ["clientSecret", "scope"],
43116
43907
  defaults: {
43117
43908
  type: "oauth",
43118
43909
  flow: "authorization_code",
43119
43910
  authorizationUrl: "https://{subdomain}.myshopify.com/admin/oauth/authorize",
43120
- tokenUrl: "https://{subdomain}.myshopify.com/admin/oauth/access_token"
43911
+ tokenUrl: "https://{subdomain}.myshopify.com/admin/oauth/access_token",
43912
+ usePKCE: true
43121
43913
  },
43122
43914
  scopes: ["read_products", "write_products", "read_orders", "write_orders", "read_customers", "write_customers", "read_inventory", "write_inventory", "read_fulfillments", "write_fulfillments"],
43123
43915
  scopeDescriptions: {
@@ -43145,6 +43937,7 @@ var allVendorTemplates = [
43145
43937
  slackTemplate,
43146
43938
  discordTemplate,
43147
43939
  telegramTemplate,
43940
+ twitterTemplate,
43148
43941
  // Development
43149
43942
  githubTemplate,
43150
43943
  gitlabTemplate,
@@ -43204,6 +43997,7 @@ var VENDOR_ICON_MAP = {
43204
43997
  discord: "discord",
43205
43998
  slack: "slack",
43206
43999
  telegram: "telegram",
44000
+ twitter: "x",
43207
44001
  "microsoft-teams": "microsoftteams",
43208
44002
  // CRM
43209
44003
  salesforce: "salesforce",
@@ -43268,6 +44062,7 @@ var FALLBACK_PLACEHOLDERS = {
43268
44062
  // Communication (trademark removed)
43269
44063
  slack: { color: "#4A154B", letter: "S" },
43270
44064
  "microsoft-teams": { color: "#6264A7", letter: "T" },
44065
+ twitter: { color: "#000000", letter: "X" },
43271
44066
  // CRM (trademark removed)
43272
44067
  salesforce: { color: "#00A1E0", letter: "S" },
43273
44068
  pipedrive: { color: "#1A1F26", letter: "P" },
@@ -46437,21 +47232,53 @@ registerWebTools();
46437
47232
  init_Connector();
46438
47233
  var DEFAULT_TIMEOUT = 1e4;
46439
47234
  var DEFAULT_MAX_TIMEOUT = 3e4;
46440
- function formatConnectorEntry(c) {
47235
+ function formatConnectorEntry(c, accountId) {
46441
47236
  const parts = [];
46442
47237
  const serviceOrVendor = c.serviceType ?? c.vendor ?? void 0;
46443
47238
  if (serviceOrVendor) parts.push(`Service: ${serviceOrVendor}`);
47239
+ if (accountId) parts.push(`Account: "${accountId}"`);
46444
47240
  if (c.config.description) parts.push(c.config.description);
46445
47241
  if (c.baseURL) parts.push(`URL: ${c.baseURL}`);
47242
+ const label = accountId ? `"${c.name}" account "${accountId}"` : `"${c.name}"`;
46446
47243
  const details = parts.map((p) => ` ${p}`).join("\n");
46447
- return ` \u2022 "${c.name}" (${c.displayName})
47244
+ return ` \u2022 ${label} (${c.displayName})
46448
47245
  ${details}`;
46449
47246
  }
46450
- function generateDescription(context, maxTimeout) {
47247
+ function buildIdentityList(context) {
47248
+ const identities = context?.identities;
46451
47249
  const registry = context?.connectorRegistry ?? Connector.asRegistry();
47250
+ if (identities?.length) {
47251
+ const entries = [];
47252
+ for (const id of identities) {
47253
+ try {
47254
+ const connector = registry.get(id.connector);
47255
+ entries.push(formatConnectorEntry(connector, id.accountId));
47256
+ } catch {
47257
+ entries.push(` \u2022 "${id.connector}"${id.accountId ? ` account "${id.accountId}"` : ""} \u2014 not available`);
47258
+ }
47259
+ }
47260
+ return entries.length > 0 ? entries.join("\n\n") : " No connectors registered.";
47261
+ }
46452
47262
  const connectors = registry.listAll();
46453
- const connectorList = connectors.length > 0 ? connectors.map(formatConnectorEntry).join("\n\n") : " No connectors registered.";
47263
+ return connectors.length > 0 ? connectors.map((c) => formatConnectorEntry(c)).join("\n\n") : " No connectors registered.";
47264
+ }
47265
+ function hasAccountIds(context) {
47266
+ return !!context?.identities?.some((id) => id.accountId);
47267
+ }
47268
+ function generateDescription(context, maxTimeout) {
47269
+ const connectorList = buildIdentityList(context);
47270
+ const showAccountId = hasAccountIds(context);
46454
47271
  const timeoutSec = Math.round(maxTimeout / 1e3);
47272
+ const accountIdParam = showAccountId ? `
47273
+ \u2022 accountId (optional): Account alias for multi-account connectors.
47274
+ Required when a connector has multiple accounts (see list below).
47275
+ Example: authenticatedFetch('/v1.0/me', {}, 'microsoft', 'work')` : "";
47276
+ const accountIdExamples = showAccountId ? `
47277
+ // Multi-account: specify accountId for connectors with multiple accounts
47278
+ const resp = await authenticatedFetch('/v1.0/me', { method: 'GET' }, 'microsoft', 'work');
47279
+ const profile = await resp.json();
47280
+ output = profile;
47281
+ ` : "";
46455
47282
  return `Execute JavaScript code in a secure sandbox with authenticated API access to external services.
46456
47283
 
46457
47284
  Use this tool when you need to:
@@ -46462,7 +47289,7 @@ Use this tool when you need to:
46462
47289
 
46463
47290
  SANDBOX API:
46464
47291
 
46465
- 1. authenticatedFetch(url, options, connectorName)
47292
+ 1. authenticatedFetch(url, options, connectorName${showAccountId ? ", accountId?" : ""})
46466
47293
  Makes authenticated HTTP requests using the connector's credentials.
46467
47294
  The current user's identity (userId) is automatically included \u2014 no need to pass it.
46468
47295
  Auth headers are added automatically \u2014 DO NOT set Authorization header manually.
@@ -46473,7 +47300,7 @@ SANDBOX API:
46473
47300
  - Relative: "/user/repos" (resolved against connector's base URL)
46474
47301
  \u2022 options: Standard fetch options { method, headers, body }
46475
47302
  - For POST/PUT: set body to JSON.stringify(data) and headers to { 'Content-Type': 'application/json' }
46476
- \u2022 connectorName: Name of a registered connector (see list below)
47303
+ \u2022 connectorName: Name of a registered connector (see list below)${accountIdParam}
46477
47304
 
46478
47305
  Returns: Promise<Response>
46479
47306
  \u2022 response.ok \u2014 true if status 200-299
@@ -46509,7 +47336,7 @@ const resp = await authenticatedFetch('/chat.postMessage', {
46509
47336
  body: JSON.stringify({ channel: '#general', text: 'Hello!' })
46510
47337
  }, 'slack');
46511
47338
  output = await resp.json();
46512
-
47339
+ ${accountIdExamples}
46513
47340
  // Data processing (no API needed)
46514
47341
  const items = input.data;
46515
47342
  output = items.filter(i => i.score > 0.8).sort((a, b) => b.score - a.score);
@@ -46597,9 +47424,10 @@ async function executeInVM(code, input, timeout, logs, userId, registry) {
46597
47424
  },
46598
47425
  // Authenticated fetch — userId auto-injected from ToolContext.
46599
47426
  // Only connectors visible in the scoped registry are accessible.
46600
- authenticatedFetch: (url2, options, connectorName) => {
47427
+ // Optional 4th param accountId for multi-account OAuth identities.
47428
+ authenticatedFetch: (url2, options, connectorName, accountId) => {
46601
47429
  registry.get(connectorName);
46602
- return authenticatedFetch(url2, options, connectorName, userId);
47430
+ return authenticatedFetch(url2, options, connectorName, userId, accountId);
46603
47431
  },
46604
47432
  // Standard fetch (no auth)
46605
47433
  fetch: globalThis.fetch,
@@ -47287,7 +48115,8 @@ async function githubFetch(connector, endpoint, options) {
47287
48115
  headers,
47288
48116
  body: options?.body ? JSON.stringify(options.body) : void 0
47289
48117
  },
47290
- options?.userId
48118
+ options?.userId,
48119
+ options?.accountId
47291
48120
  );
47292
48121
  const text = await response.text();
47293
48122
  let data;
@@ -47369,6 +48198,7 @@ EXAMPLES:
47369
48198
  },
47370
48199
  execute: async (args, context) => {
47371
48200
  const effectiveUserId = context?.userId ?? userId;
48201
+ const effectiveAccountId = context?.accountId;
47372
48202
  const resolved = resolveRepository(args.repository, connector);
47373
48203
  if (!resolved.success) {
47374
48204
  return { success: false, error: resolved.error };
@@ -47380,7 +48210,7 @@ EXAMPLES:
47380
48210
  const repoInfo = await githubFetch(
47381
48211
  connector,
47382
48212
  `/repos/${owner}/${repo}`,
47383
- { userId: effectiveUserId }
48213
+ { userId: effectiveUserId, accountId: effectiveAccountId }
47384
48214
  );
47385
48215
  ref = repoInfo.default_branch;
47386
48216
  }
@@ -47480,6 +48310,7 @@ EXAMPLES:
47480
48310
  },
47481
48311
  execute: async (args, context) => {
47482
48312
  const effectiveUserId = context?.userId ?? userId;
48313
+ const effectiveAccountId = context?.accountId;
47483
48314
  const resolved = resolveRepository(args.repository, connector);
47484
48315
  if (!resolved.success) {
47485
48316
  return { success: false, error: resolved.error };
@@ -47497,6 +48328,7 @@ EXAMPLES:
47497
48328
  `/search/code`,
47498
48329
  {
47499
48330
  userId: effectiveUserId,
48331
+ accountId: effectiveAccountId,
47500
48332
  // Request text-match fragments
47501
48333
  accept: "application/vnd.github.text-match+json",
47502
48334
  queryParams: { q, per_page: perPage }
@@ -47585,6 +48417,7 @@ NOTE: Files larger than 1MB are fetched via the Git Blob API. Very large files (
47585
48417
  },
47586
48418
  execute: async (args, context) => {
47587
48419
  const effectiveUserId = context?.userId ?? userId;
48420
+ const effectiveAccountId = context?.accountId;
47588
48421
  const resolved = resolveRepository(args.repository, connector);
47589
48422
  if (!resolved.success) {
47590
48423
  return { success: false, error: resolved.error };
@@ -47598,7 +48431,7 @@ NOTE: Files larger than 1MB are fetched via the Git Blob API. Very large files (
47598
48431
  const contentResp = await githubFetch(
47599
48432
  connector,
47600
48433
  `/repos/${owner}/${repo}/contents/${args.path}${refParam}`,
47601
- { userId: effectiveUserId }
48434
+ { userId: effectiveUserId, accountId: effectiveAccountId }
47602
48435
  );
47603
48436
  if (contentResp.type !== "file") {
47604
48437
  return {
@@ -47615,7 +48448,7 @@ NOTE: Files larger than 1MB are fetched via the Git Blob API. Very large files (
47615
48448
  const blob = await githubFetch(
47616
48449
  connector,
47617
48450
  contentResp.git_url,
47618
- { userId: effectiveUserId }
48451
+ { userId: effectiveUserId, accountId: effectiveAccountId }
47619
48452
  );
47620
48453
  fileContent = Buffer.from(blob.content, "base64").toString("utf-8");
47621
48454
  fileSize = blob.size;
@@ -47704,6 +48537,7 @@ EXAMPLES:
47704
48537
  },
47705
48538
  execute: async (args, context) => {
47706
48539
  const effectiveUserId = context?.userId ?? userId;
48540
+ const effectiveAccountId = context?.accountId;
47707
48541
  const resolved = resolveRepository(args.repository, connector);
47708
48542
  if (!resolved.success) {
47709
48543
  return { success: false, error: resolved.error };
@@ -47713,7 +48547,7 @@ EXAMPLES:
47713
48547
  const pr = await githubFetch(
47714
48548
  connector,
47715
48549
  `/repos/${owner}/${repo}/pulls/${args.pull_number}`,
47716
- { userId: effectiveUserId }
48550
+ { userId: effectiveUserId, accountId: effectiveAccountId }
47717
48551
  );
47718
48552
  return {
47719
48553
  success: true,
@@ -47791,6 +48625,7 @@ NOTE: Very large diffs may be truncated by GitHub. Patch content may be absent f
47791
48625
  },
47792
48626
  execute: async (args, context) => {
47793
48627
  const effectiveUserId = context?.userId ?? userId;
48628
+ const effectiveAccountId = context?.accountId;
47794
48629
  const resolved = resolveRepository(args.repository, connector);
47795
48630
  if (!resolved.success) {
47796
48631
  return { success: false, error: resolved.error };
@@ -47802,6 +48637,7 @@ NOTE: Very large diffs may be truncated by GitHub. Patch content may be absent f
47802
48637
  `/repos/${owner}/${repo}/pulls/${args.pull_number}/files`,
47803
48638
  {
47804
48639
  userId: effectiveUserId,
48640
+ accountId: effectiveAccountId,
47805
48641
  queryParams: { per_page: 100 }
47806
48642
  }
47807
48643
  );
@@ -47874,6 +48710,7 @@ EXAMPLES:
47874
48710
  },
47875
48711
  execute: async (args, context) => {
47876
48712
  const effectiveUserId = context?.userId ?? userId;
48713
+ const effectiveAccountId = context?.accountId;
47877
48714
  const resolved = resolveRepository(args.repository, connector);
47878
48715
  if (!resolved.success) {
47879
48716
  return { success: false, error: resolved.error };
@@ -47881,7 +48718,7 @@ EXAMPLES:
47881
48718
  const { owner, repo } = resolved.repo;
47882
48719
  try {
47883
48720
  const basePath = `/repos/${owner}/${repo}`;
47884
- const queryOpts = { userId: effectiveUserId, queryParams: { per_page: 100 } };
48721
+ const queryOpts = { userId: effectiveUserId, accountId: effectiveAccountId, queryParams: { per_page: 100 } };
47885
48722
  const [reviewComments, reviews, issueComments] = await Promise.all([
47886
48723
  githubFetch(
47887
48724
  connector,
@@ -48010,6 +48847,7 @@ EXAMPLES:
48010
48847
  },
48011
48848
  execute: async (args, context) => {
48012
48849
  const effectiveUserId = context?.userId ?? userId;
48850
+ const effectiveAccountId = context?.accountId;
48013
48851
  const resolved = resolveRepository(args.repository, connector);
48014
48852
  if (!resolved.success) {
48015
48853
  return { success: false, error: resolved.error };
@@ -48022,6 +48860,7 @@ EXAMPLES:
48022
48860
  {
48023
48861
  method: "POST",
48024
48862
  userId: effectiveUserId,
48863
+ accountId: effectiveAccountId,
48025
48864
  body: {
48026
48865
  title: args.title,
48027
48866
  body: args.body,
@@ -48113,7 +48952,8 @@ async function microsoftFetch(connector, endpoint, options) {
48113
48952
  headers,
48114
48953
  body: options?.body ? JSON.stringify(options.body) : void 0
48115
48954
  },
48116
- options?.userId
48955
+ options?.userId,
48956
+ options?.accountId
48117
48957
  );
48118
48958
  const text = await response.text();
48119
48959
  if (!response.ok) {
@@ -48166,7 +49006,7 @@ function isTeamsMeetingUrl(input) {
48166
49006
  return false;
48167
49007
  }
48168
49008
  }
48169
- async function resolveMeetingId(connector, input, prefix, effectiveUserId) {
49009
+ async function resolveMeetingId(connector, input, prefix, effectiveUserId, effectiveAccountId) {
48170
49010
  if (!input || input.trim().length === 0) {
48171
49011
  throw new Error("Meeting ID cannot be empty");
48172
49012
  }
@@ -48179,6 +49019,7 @@ async function resolveMeetingId(connector, input, prefix, effectiveUserId) {
48179
49019
  `${prefix}/onlineMeetings`,
48180
49020
  {
48181
49021
  userId: effectiveUserId,
49022
+ accountId: effectiveAccountId,
48182
49023
  queryParams: { "$filter": `JoinWebUrl eq '${trimmed}'` }
48183
49024
  }
48184
49025
  );
@@ -48257,13 +49098,14 @@ EXAMPLES:
48257
49098
  },
48258
49099
  execute: async (args, context) => {
48259
49100
  const effectiveUserId = context?.userId ?? userId;
49101
+ const effectiveAccountId = context?.accountId;
48260
49102
  try {
48261
49103
  const prefix = getUserPathPrefix(connector, args.targetUser);
48262
49104
  if (args.replyToMessageId) {
48263
49105
  const replyDraft = await microsoftFetch(
48264
49106
  connector,
48265
49107
  `${prefix}/messages/${args.replyToMessageId}/createReply`,
48266
- { method: "POST", userId: effectiveUserId, body: {} }
49108
+ { method: "POST", userId: effectiveUserId, accountId: effectiveAccountId, body: {} }
48267
49109
  );
48268
49110
  const updated = await microsoftFetch(
48269
49111
  connector,
@@ -48271,6 +49113,7 @@ EXAMPLES:
48271
49113
  {
48272
49114
  method: "PATCH",
48273
49115
  userId: effectiveUserId,
49116
+ accountId: effectiveAccountId,
48274
49117
  body: {
48275
49118
  subject: args.subject,
48276
49119
  body: { contentType: "HTML", content: args.body },
@@ -48291,6 +49134,7 @@ EXAMPLES:
48291
49134
  {
48292
49135
  method: "POST",
48293
49136
  userId: effectiveUserId,
49137
+ accountId: effectiveAccountId,
48294
49138
  body: {
48295
49139
  isDraft: true,
48296
49140
  subject: args.subject,
@@ -48379,6 +49223,7 @@ EXAMPLES:
48379
49223
  },
48380
49224
  execute: async (args, context) => {
48381
49225
  const effectiveUserId = context?.userId ?? userId;
49226
+ const effectiveAccountId = context?.accountId;
48382
49227
  try {
48383
49228
  const prefix = getUserPathPrefix(connector, args.targetUser);
48384
49229
  if (args.replyToMessageId) {
@@ -48388,6 +49233,7 @@ EXAMPLES:
48388
49233
  {
48389
49234
  method: "POST",
48390
49235
  userId: effectiveUserId,
49236
+ accountId: effectiveAccountId,
48391
49237
  body: {
48392
49238
  message: {
48393
49239
  toRecipients: formatRecipients(args.to),
@@ -48404,6 +49250,7 @@ EXAMPLES:
48404
49250
  {
48405
49251
  method: "POST",
48406
49252
  userId: effectiveUserId,
49253
+ accountId: effectiveAccountId,
48407
49254
  body: {
48408
49255
  message: {
48409
49256
  subject: args.subject,
@@ -48503,6 +49350,7 @@ EXAMPLES:
48503
49350
  },
48504
49351
  execute: async (args, context) => {
48505
49352
  const effectiveUserId = context?.userId ?? userId;
49353
+ const effectiveAccountId = context?.accountId;
48506
49354
  try {
48507
49355
  const prefix = getUserPathPrefix(connector, args.targetUser);
48508
49356
  const tz = args.timeZone ?? "UTC";
@@ -48525,7 +49373,7 @@ EXAMPLES:
48525
49373
  const event = await microsoftFetch(
48526
49374
  connector,
48527
49375
  `${prefix}/events`,
48528
- { method: "POST", userId: effectiveUserId, body: eventBody }
49376
+ { method: "POST", userId: effectiveUserId, accountId: effectiveAccountId, body: eventBody }
48529
49377
  );
48530
49378
  return {
48531
49379
  success: true,
@@ -48629,6 +49477,7 @@ EXAMPLES:
48629
49477
  },
48630
49478
  execute: async (args, context) => {
48631
49479
  const effectiveUserId = context?.userId ?? userId;
49480
+ const effectiveAccountId = context?.accountId;
48632
49481
  try {
48633
49482
  const prefix = getUserPathPrefix(connector, args.targetUser);
48634
49483
  const tz = args.timeZone ?? "UTC";
@@ -48652,7 +49501,7 @@ EXAMPLES:
48652
49501
  const event = await microsoftFetch(
48653
49502
  connector,
48654
49503
  `${prefix}/events/${args.eventId}`,
48655
- { method: "PATCH", userId: effectiveUserId, body: patchBody }
49504
+ { method: "PATCH", userId: effectiveUserId, accountId: effectiveAccountId, body: patchBody }
48656
49505
  );
48657
49506
  return {
48658
49507
  success: true,
@@ -48725,14 +49574,15 @@ EXAMPLES:
48725
49574
  },
48726
49575
  execute: async (args, context) => {
48727
49576
  const effectiveUserId = context?.userId ?? userId;
49577
+ const effectiveAccountId = context?.accountId;
48728
49578
  try {
48729
49579
  const prefix = getUserPathPrefix(connector, args.targetUser);
48730
- const resolved = await resolveMeetingId(connector, args.meetingId, prefix, effectiveUserId);
49580
+ const resolved = await resolveMeetingId(connector, args.meetingId, prefix, effectiveUserId, effectiveAccountId);
48731
49581
  const meetingId = resolved.meetingId;
48732
49582
  const transcriptList = await microsoftFetch(
48733
49583
  connector,
48734
49584
  `${prefix}/onlineMeetings/${meetingId}/transcripts`,
48735
- { userId: effectiveUserId }
49585
+ { userId: effectiveUserId, accountId: effectiveAccountId }
48736
49586
  );
48737
49587
  if (!transcriptList.value || transcriptList.value.length === 0) {
48738
49588
  return {
@@ -48745,7 +49595,8 @@ EXAMPLES:
48745
49595
  const response = await connector.fetch(
48746
49596
  contentUrl + "?$format=text/vtt",
48747
49597
  { method: "GET", headers: { "Accept": "text/vtt" } },
48748
- effectiveUserId
49598
+ effectiveUserId,
49599
+ effectiveAccountId
48749
49600
  );
48750
49601
  if (!response.ok) {
48751
49602
  const errorText = await response.text();
@@ -48837,6 +49688,7 @@ EXAMPLES:
48837
49688
  },
48838
49689
  execute: async (args, context) => {
48839
49690
  const effectiveUserId = context?.userId ?? userId;
49691
+ const effectiveAccountId = context?.accountId;
48840
49692
  try {
48841
49693
  const prefix = getUserPathPrefix(connector, args.targetUser);
48842
49694
  const tz = args.timeZone ?? "UTC";
@@ -48846,6 +49698,7 @@ EXAMPLES:
48846
49698
  {
48847
49699
  method: "POST",
48848
49700
  userId: effectiveUserId,
49701
+ accountId: effectiveAccountId,
48849
49702
  body: {
48850
49703
  attendees: formatAttendees(args.attendees),
48851
49704
  timeConstraint: {
@@ -49774,27 +50627,42 @@ var customToolDelete = createCustomToolDelete();
49774
50627
 
49775
50628
  // src/tools/custom-tools/sandboxDescription.ts
49776
50629
  init_Connector();
49777
- function formatConnectorEntry2(c) {
50630
+ function formatConnectorEntry2(c, accountId) {
49778
50631
  const parts = [];
49779
50632
  const serviceOrVendor = c.serviceType ?? c.vendor ?? void 0;
49780
50633
  if (serviceOrVendor) parts.push(`Service: ${serviceOrVendor}`);
50634
+ if (accountId) parts.push(`Account: "${accountId}"`);
49781
50635
  if (c.config.description) parts.push(c.config.description);
49782
50636
  if (c.baseURL) parts.push(`URL: ${c.baseURL}`);
50637
+ const label = accountId ? `"${c.name}" account "${accountId}"` : `"${c.name}"`;
49783
50638
  const details = parts.map((p) => ` ${p}`).join("\n");
49784
- return ` \u2022 "${c.name}" (${c.displayName})
50639
+ return ` \u2022 ${label} (${c.displayName})
49785
50640
  ${details}`;
49786
50641
  }
49787
50642
  function buildConnectorList(context) {
50643
+ const identities = context?.identities;
49788
50644
  const registry = context?.connectorRegistry ?? Connector.asRegistry();
50645
+ if (identities?.length) {
50646
+ const entries = [];
50647
+ for (const id of identities) {
50648
+ try {
50649
+ const connector = registry.get(id.connector);
50650
+ entries.push(formatConnectorEntry2(connector, id.accountId));
50651
+ } catch {
50652
+ entries.push(` \u2022 "${id.connector}"${id.accountId ? ` account "${id.accountId}"` : ""} \u2014 not available`);
50653
+ }
50654
+ }
50655
+ return entries.length > 0 ? entries.join("\n\n") : " No connectors registered.";
50656
+ }
49789
50657
  const connectors = registry.listAll();
49790
50658
  if (connectors.length === 0) {
49791
50659
  return " No connectors registered.";
49792
50660
  }
49793
- return connectors.map(formatConnectorEntry2).join("\n\n");
50661
+ return connectors.map((c) => formatConnectorEntry2(c)).join("\n\n");
49794
50662
  }
49795
50663
  var SANDBOX_API_REFERENCE = `SANDBOX API (available inside custom tool code):
49796
50664
 
49797
- 1. authenticatedFetch(url, options, connectorName)
50665
+ 1. authenticatedFetch(url, options, connectorName, accountId?)
49798
50666
  Makes authenticated HTTP requests using the connector's credentials.
49799
50667
  Auth headers are added automatically \u2014 DO NOT set Authorization header manually.
49800
50668
 
@@ -49805,6 +50673,7 @@ var SANDBOX_API_REFERENCE = `SANDBOX API (available inside custom tool code):
49805
50673
  \u2022 options: Standard fetch options { method, headers, body }
49806
50674
  - For POST/PUT: set body to JSON.stringify(data) and headers to { 'Content-Type': 'application/json' }
49807
50675
  \u2022 connectorName: Name of a registered connector (see REGISTERED CONNECTORS below)
50676
+ \u2022 accountId (optional): Account alias for multi-account connectors (e.g., 'work', 'personal')
49808
50677
 
49809
50678
  Returns: Promise<Response>
49810
50679
  \u2022 response.ok \u2014 true if status 200-299
@@ -50888,6 +51757,6 @@ REMEMBER: Keep it conversational, ask one question at a time, and only output th
50888
51757
  }
50889
51758
  };
50890
51759
 
50891
- export { AGENT_DEFINITION_FORMAT_VERSION, AIError, APPROVAL_STATE_VERSION, Agent, AgentContextNextGen, ApproximateTokenEstimator, BaseMediaProvider, BasePluginNextGen, BaseProvider, BaseTextProvider, BraveProvider, CONNECTOR_CONFIG_VERSION, CONTEXT_SESSION_FORMAT_VERSION, CUSTOM_TOOL_DEFINITION_VERSION, CheckpointManager, CircuitBreaker, CircuitOpenError, Connector, ConnectorConfigStore, ConnectorTools, ConsoleMetrics, ContentType, ContextOverflowError, DEFAULT_ALLOWLIST, DEFAULT_BACKOFF_CONFIG, DEFAULT_BASE_DELAY_MS, DEFAULT_CHECKPOINT_STRATEGY, DEFAULT_CIRCUIT_BREAKER_CONFIG, DEFAULT_CONFIG2 as DEFAULT_CONFIG, DEFAULT_CONNECTOR_TIMEOUT, DEFAULT_CONTEXT_CONFIG, DEFAULT_DESKTOP_CONFIG, DEFAULT_FEATURES, DEFAULT_FILESYSTEM_CONFIG, DEFAULT_HISTORY_MANAGER_CONFIG, DEFAULT_MAX_DELAY_MS, DEFAULT_MAX_RETRIES, DEFAULT_MEMORY_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_RATE_LIMITER_CONFIG, DEFAULT_RETRYABLE_STATUSES, DEFAULT_SHELL_CONFIG, DESKTOP_TOOL_NAMES, DefaultCompactionStrategy, DependencyCycleError, DocumentReader, ErrorHandler, ExecutionContext, ExternalDependencyHandler, FileAgentDefinitionStorage, FileConnectorStorage, FileContextStorage, FileCustomToolStorage, FileMediaStorage as FileMediaOutputHandler, FileMediaStorage, FilePersistentInstructionsStorage, FileRoutineDefinitionStorage, FileStorage, FileUserInfoStorage, FormatDetector, FrameworkLogger, HookManager, IMAGE_MODELS, IMAGE_MODEL_REGISTRY, ImageGeneration, InContextMemoryPluginNextGen, InMemoryAgentStateStorage, InMemoryHistoryStorage, InMemoryMetrics, InMemoryPlanStorage, InMemoryStorage, InvalidConfigError, InvalidToolArgumentsError, LLM_MODELS, LoggingPlugin, MCPClient, MCPConnectionError, MCPError, MCPProtocolError, MCPRegistry, MCPResourceError, MCPTimeoutError, MCPToolError, MEMORY_PRIORITY_VALUES, MODEL_REGISTRY, MemoryConnectorStorage, MemoryEvictionCompactor, MemoryStorage, MessageBuilder, MessageRole, ModelNotSupportedError, NoOpMetrics, NutTreeDriver, OAuthManager, ParallelTasksError, PersistentInstructionsPluginNextGen, PlanningAgent, ProviderAuthError, ProviderConfigAgent, ProviderContextLengthError, ProviderError, ProviderErrorMapper, ProviderNotFoundError, ProviderRateLimitError, RapidAPIProvider, RateLimitError, SERVICE_DEFINITIONS, SERVICE_INFO, SERVICE_URL_PATTERNS, SIMPLE_ICONS_CDN, STT_MODELS, STT_MODEL_REGISTRY, ScopedConnectorRegistry, ScrapeProvider, SearchProvider, SerperProvider, Services, SpeechToText, StorageRegistry, StrategyRegistry, StreamEventType, StreamHelpers, StreamState, SummarizeCompactor, TERMINAL_TASK_STATUSES, TTS_MODELS, TTS_MODEL_REGISTRY, TaskTimeoutError, TaskValidationError, TavilyProvider, TextToSpeech, TokenBucketRateLimiter, ToolCallState, ToolExecutionError, ToolExecutionPipeline, ToolManager, ToolNotFoundError, ToolPermissionManager, ToolRegistry, ToolTimeoutError, TruncateCompactor, UserInfoPluginNextGen, VENDORS, VENDOR_ICON_MAP, VIDEO_MODELS, VIDEO_MODEL_REGISTRY, Vendor, VideoGeneration, WorkingMemory, WorkingMemoryPluginNextGen, addJitter, allVendorTemplates, assertNotDestroyed, authenticatedFetch, backoffSequence, backoffWait, bash, buildAuthConfig, buildEndpointWithQuery, buildQueryString, calculateBackoff, calculateCost, calculateEntrySize, calculateImageCost, calculateSTTCost, calculateTTSCost, calculateVideoCost, canTaskExecute, createAgentStorage, createAuthenticatedFetch, createBashTool, createConnectorFromTemplate, createCreatePRTool, createCustomToolDelete, createCustomToolDraft, createCustomToolList, createCustomToolLoad, createCustomToolMetaTools, createCustomToolSave, createCustomToolTest, createDesktopGetCursorTool, createDesktopGetScreenSizeTool, createDesktopKeyboardKeyTool, createDesktopKeyboardTypeTool, createDesktopMouseClickTool, createDesktopMouseDragTool, createDesktopMouseMoveTool, createDesktopMouseScrollTool, createDesktopScreenshotTool, createDesktopWindowFocusTool, createDesktopWindowListTool, createDraftEmailTool, createEditFileTool, createEditMeetingTool, createEstimator, createExecuteJavaScriptTool, createFileAgentDefinitionStorage, createFileContextStorage, createFileCustomToolStorage, createFileMediaStorage, createFileRoutineDefinitionStorage, createFindMeetingSlotsTool, createGetMeetingTranscriptTool, createGetPRTool, createGitHubReadFileTool, createGlobTool, createGrepTool, createImageGenerationTool, createImageProvider, createListDirectoryTool, createMeetingTool, createMessageWithImages, createMetricsCollector, createPRCommentsTool, createPRFilesTool, createPlan, createProvider, createReadFileTool, createRoutineDefinition, createRoutineExecution, createSearchCodeTool, createSearchFilesTool, createSendEmailTool, createSpeechToTextTool, createTask, createTextMessage, createTextToSpeechTool, createVideoProvider, createVideoTools, createWriteFileTool, customToolDelete, customToolDraft, customToolList, customToolLoad, customToolSave, customToolTest, defaultDescribeCall, desktopGetCursor, desktopGetScreenSize, desktopKeyboardKey, desktopKeyboardType, desktopMouseClick, desktopMouseDrag, desktopMouseMove, desktopMouseScroll, desktopScreenshot, desktopTools, desktopWindowFocus, desktopWindowList, detectDependencyCycle, detectServiceFromURL, developerTools, documentToContent, editFile, evaluateCondition, executeRoutine, extractJSON, extractJSONField, extractNumber, findConnectorByServiceTypes, forPlan, forTasks, formatAttendees, formatPluginDisplayName, formatRecipients, generateEncryptionKey, generateSimplePlan, generateWebAPITool, getActiveImageModels, getActiveModels, getActiveSTTModels, getActiveTTSModels, getActiveVideoModels, getAllBuiltInTools, getAllServiceIds, getAllVendorLogos, getAllVendorTemplates, getBackgroundOutput, getConnectorTools, getCredentialsSetupURL, getDesktopDriver, getDocsURL, getImageModelInfo, getImageModelsByVendor, getImageModelsWithFeature, getMediaOutputHandler, getMediaStorage, getModelInfo, getModelsByVendor, getNextExecutableTasks, getRegisteredScrapeProviders, getRoutineProgress, getSTTModelInfo, getSTTModelsByVendor, getSTTModelsWithFeature, getServiceDefinition, getServiceInfo, getServicesByCategory, getTTSModelInfo, getTTSModelsByVendor, getTTSModelsWithFeature, getTaskDependencies, getToolByName, getToolCallDescription, getToolCategories, getToolRegistry, getToolsByCategory, getToolsRequiringConnector, getUserPathPrefix, getVendorAuthTemplate, getVendorColor, getVendorDefaultBaseURL, getVendorInfo, getVendorLogo, getVendorLogoCdnUrl, getVendorLogoSvg, getVendorTemplate, getVideoModelInfo, getVideoModelsByVendor, getVideoModelsWithAudio, getVideoModelsWithFeature, glob, globalErrorHandler, grep, hasClipboardImage, hasVendorLogo, hydrateCustomTool, isBlockedCommand, isErrorEvent, isExcludedExtension, isKnownService, isOutputTextDelta, isReasoningDelta, isReasoningDone, isResponseComplete, isSimpleScope, isStreamEvent, isTaskAwareScope, isTaskBlocked, isTeamsMeetingUrl, isTerminalMemoryStatus, isTerminalStatus, isToolCallArgumentsDelta, isToolCallArgumentsDone, isToolCallStart, isVendor, killBackgroundProcess, listConnectorsByServiceTypes, listDirectory, listVendorIds, listVendors, listVendorsByAuthType, listVendorsByCategory, listVendorsWithLogos, logger, mergeTextPieces, metrics, microsoftFetch, normalizeEmails, parseKeyCombo, parseRepository, readClipboardImage, readDocumentAsContent, readFile5 as readFile, registerScrapeProvider, resetDefaultDriver, resolveConnector, resolveDependencies, resolveMaxContextTokens, resolveMeetingId, resolveModelCapabilities, resolveRepository, retryWithBackoff, sanitizeToolName, scopeEquals, scopeMatches, setMediaOutputHandler, setMediaStorage, setMetricsCollector, simpleTokenEstimator, toConnectorOptions, toolRegistry, tools_exports as tools, updateTaskStatus, validatePath, writeFile5 as writeFile };
51760
+ export { AGENT_DEFINITION_FORMAT_VERSION, AIError, APPROVAL_STATE_VERSION, Agent, AgentContextNextGen, ApproximateTokenEstimator, BaseMediaProvider, BasePluginNextGen, BaseProvider, BaseTextProvider, BraveProvider, CONNECTOR_CONFIG_VERSION, CONTEXT_SESSION_FORMAT_VERSION, CUSTOM_TOOL_DEFINITION_VERSION, CheckpointManager, CircuitBreaker, CircuitOpenError, Connector, ConnectorConfigStore, ConnectorTools, ConsoleMetrics, ContentType, ContextOverflowError, DEFAULT_ALLOWLIST, DEFAULT_BACKOFF_CONFIG, DEFAULT_BASE_DELAY_MS, DEFAULT_CHECKPOINT_STRATEGY, DEFAULT_CIRCUIT_BREAKER_CONFIG, DEFAULT_CONFIG2 as DEFAULT_CONFIG, DEFAULT_CONNECTOR_TIMEOUT, DEFAULT_CONTEXT_CONFIG, DEFAULT_DESKTOP_CONFIG, DEFAULT_FEATURES, DEFAULT_FILESYSTEM_CONFIG, DEFAULT_HISTORY_MANAGER_CONFIG, DEFAULT_MAX_DELAY_MS, DEFAULT_MAX_RETRIES, DEFAULT_MEMORY_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_RATE_LIMITER_CONFIG, DEFAULT_RETRYABLE_STATUSES, DEFAULT_SHELL_CONFIG, DESKTOP_TOOL_NAMES, DefaultCompactionStrategy, DependencyCycleError, DocumentReader, ErrorHandler, ExecutionContext, ExternalDependencyHandler, FileAgentDefinitionStorage, FileConnectorStorage, FileContextStorage, FileCustomToolStorage, FileMediaStorage as FileMediaOutputHandler, FileMediaStorage, FilePersistentInstructionsStorage, FileRoutineDefinitionStorage, FileStorage, FileUserInfoStorage, FormatDetector, FrameworkLogger, HookManager, IMAGE_MODELS, IMAGE_MODEL_REGISTRY, ImageGeneration, InContextMemoryPluginNextGen, InMemoryAgentStateStorage, InMemoryHistoryStorage, InMemoryMetrics, InMemoryPlanStorage, InMemoryStorage, InvalidConfigError, InvalidToolArgumentsError, LLM_MODELS, LoggingPlugin, MCPClient, MCPConnectionError, MCPError, MCPProtocolError, MCPRegistry, MCPResourceError, MCPTimeoutError, MCPToolError, MEMORY_PRIORITY_VALUES, MODEL_REGISTRY, MemoryConnectorStorage, MemoryEvictionCompactor, MemoryStorage, MessageBuilder, MessageRole, ModelNotSupportedError, NoOpMetrics, NutTreeDriver, OAuthManager, ParallelTasksError, PersistentInstructionsPluginNextGen, PlanningAgent, ProviderAuthError, ProviderConfigAgent, ProviderContextLengthError, ProviderError, ProviderErrorMapper, ProviderNotFoundError, ProviderRateLimitError, ROUTINE_KEYS, RapidAPIProvider, RateLimitError, SERVICE_DEFINITIONS, SERVICE_INFO, SERVICE_URL_PATTERNS, SIMPLE_ICONS_CDN, STT_MODELS, STT_MODEL_REGISTRY, ScopedConnectorRegistry, ScrapeProvider, SearchProvider, SerperProvider, Services, SpeechToText, StorageRegistry, StrategyRegistry, StreamEventType, StreamHelpers, StreamState, SummarizeCompactor, TERMINAL_TASK_STATUSES, TTS_MODELS, TTS_MODEL_REGISTRY, TaskTimeoutError, TaskValidationError, TavilyProvider, TextToSpeech, TokenBucketRateLimiter, ToolCallState, ToolExecutionError, ToolExecutionPipeline, ToolManager, ToolNotFoundError, ToolPermissionManager, ToolRegistry, ToolTimeoutError, TruncateCompactor, UserInfoPluginNextGen, VENDORS, VENDOR_ICON_MAP, VIDEO_MODELS, VIDEO_MODEL_REGISTRY, Vendor, VideoGeneration, WorkingMemory, WorkingMemoryPluginNextGen, addJitter, allVendorTemplates, assertNotDestroyed, authenticatedFetch, backoffSequence, backoffWait, bash, buildAuthConfig, buildEndpointWithQuery, buildQueryString, calculateBackoff, calculateCost, calculateEntrySize, calculateImageCost, calculateSTTCost, calculateTTSCost, calculateVideoCost, canTaskExecute, createAgentStorage, createAuthenticatedFetch, createBashTool, createConnectorFromTemplate, createCreatePRTool, createCustomToolDelete, createCustomToolDraft, createCustomToolList, createCustomToolLoad, createCustomToolMetaTools, createCustomToolSave, createCustomToolTest, createDesktopGetCursorTool, createDesktopGetScreenSizeTool, createDesktopKeyboardKeyTool, createDesktopKeyboardTypeTool, createDesktopMouseClickTool, createDesktopMouseDragTool, createDesktopMouseMoveTool, createDesktopMouseScrollTool, createDesktopScreenshotTool, createDesktopWindowFocusTool, createDesktopWindowListTool, createDraftEmailTool, createEditFileTool, createEditMeetingTool, createEstimator, createExecuteJavaScriptTool, createFileAgentDefinitionStorage, createFileContextStorage, createFileCustomToolStorage, createFileMediaStorage, createFileRoutineDefinitionStorage, createFindMeetingSlotsTool, createGetMeetingTranscriptTool, createGetPRTool, createGitHubReadFileTool, createGlobTool, createGrepTool, createImageGenerationTool, createImageProvider, createListDirectoryTool, createMeetingTool, createMessageWithImages, createMetricsCollector, createPRCommentsTool, createPRFilesTool, createPlan, createProvider, createReadFileTool, createRoutineDefinition, createRoutineExecution, createSearchCodeTool, createSearchFilesTool, createSendEmailTool, createSpeechToTextTool, createTask, createTextMessage, createTextToSpeechTool, createVideoProvider, createVideoTools, createWriteFileTool, customToolDelete, customToolDraft, customToolList, customToolLoad, customToolSave, customToolTest, defaultDescribeCall, desktopGetCursor, desktopGetScreenSize, desktopKeyboardKey, desktopKeyboardType, desktopMouseClick, desktopMouseDrag, desktopMouseMove, desktopMouseScroll, desktopScreenshot, desktopTools, desktopWindowFocus, desktopWindowList, detectDependencyCycle, detectServiceFromURL, developerTools, documentToContent, editFile, evaluateCondition, executeRoutine, extractJSON, extractJSONField, extractNumber, findConnectorByServiceTypes, forPlan, forTasks, formatAttendees, formatPluginDisplayName, formatRecipients, generateEncryptionKey, generateSimplePlan, generateWebAPITool, getActiveImageModels, getActiveModels, getActiveSTTModels, getActiveTTSModels, getActiveVideoModels, getAllBuiltInTools, getAllServiceIds, getAllVendorLogos, getAllVendorTemplates, getBackgroundOutput, getConnectorTools, getCredentialsSetupURL, getDesktopDriver, getDocsURL, getImageModelInfo, getImageModelsByVendor, getImageModelsWithFeature, getMediaOutputHandler, getMediaStorage, getModelInfo, getModelsByVendor, getNextExecutableTasks, getRegisteredScrapeProviders, getRoutineProgress, getSTTModelInfo, getSTTModelsByVendor, getSTTModelsWithFeature, getServiceDefinition, getServiceInfo, getServicesByCategory, getTTSModelInfo, getTTSModelsByVendor, getTTSModelsWithFeature, getTaskDependencies, getToolByName, getToolCallDescription, getToolCategories, getToolRegistry, getToolsByCategory, getToolsRequiringConnector, getUserPathPrefix, getVendorAuthTemplate, getVendorColor, getVendorDefaultBaseURL, getVendorInfo, getVendorLogo, getVendorLogoCdnUrl, getVendorLogoSvg, getVendorTemplate, getVideoModelInfo, getVideoModelsByVendor, getVideoModelsWithAudio, getVideoModelsWithFeature, glob, globalErrorHandler, grep, hasClipboardImage, hasVendorLogo, hydrateCustomTool, isBlockedCommand, isErrorEvent, isExcludedExtension, isKnownService, isOutputTextDelta, isReasoningDelta, isReasoningDone, isResponseComplete, isSimpleScope, isStreamEvent, isTaskAwareScope, isTaskBlocked, isTeamsMeetingUrl, isTerminalMemoryStatus, isTerminalStatus, isToolCallArgumentsDelta, isToolCallArgumentsDone, isToolCallStart, isVendor, killBackgroundProcess, listConnectorsByServiceTypes, listDirectory, listVendorIds, listVendors, listVendorsByAuthType, listVendorsByCategory, listVendorsWithLogos, logger, mergeTextPieces, metrics, microsoftFetch, normalizeEmails, parseKeyCombo, parseRepository, readClipboardImage, readDocumentAsContent, readFile5 as readFile, registerScrapeProvider, resetDefaultDriver, resolveConnector, resolveDependencies, resolveMaxContextTokens, resolveMeetingId, resolveModelCapabilities, resolveRepository, resolveTemplates, retryWithBackoff, sanitizeToolName, scopeEquals, scopeMatches, setMediaOutputHandler, setMediaStorage, setMetricsCollector, simpleTokenEstimator, toConnectorOptions, toolRegistry, tools_exports as tools, updateTaskStatus, validatePath, writeFile5 as writeFile };
50892
51761
  //# sourceMappingURL=index.js.map
50893
51762
  //# sourceMappingURL=index.js.map