@everworker/oneringai 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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();
@@ -11911,6 +12083,9 @@ var ToolManager = class extends EventEmitter {
11911
12083
  }
11912
12084
  };
11913
12085
 
12086
+ // src/core/context-nextgen/AgentContextNextGen.ts
12087
+ init_Logger();
12088
+
11914
12089
  // src/core/Vendor.ts
11915
12090
  var Vendor = {
11916
12091
  OpenAI: "openai",
@@ -13284,6 +13459,7 @@ var ContentType = /* @__PURE__ */ ((ContentType2) => {
13284
13459
  ContentType2["OUTPUT_TEXT"] = "output_text";
13285
13460
  ContentType2["TOOL_USE"] = "tool_use";
13286
13461
  ContentType2["TOOL_RESULT"] = "tool_result";
13462
+ ContentType2["THINKING"] = "thinking";
13287
13463
  return ContentType2;
13288
13464
  })(ContentType || {});
13289
13465
 
@@ -13546,6 +13722,11 @@ var BasePluginNextGen = class {
13546
13722
  }
13547
13723
  };
13548
13724
 
13725
+ // src/core/context-nextgen/snapshot.ts
13726
+ function formatPluginDisplayName(name) {
13727
+ return name.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
13728
+ }
13729
+
13549
13730
  // src/core/context-nextgen/AgentContextNextGen.ts
13550
13731
  init_Connector();
13551
13732
 
@@ -16224,8 +16405,11 @@ var AlgorithmicCompactionStrategy = class {
16224
16405
  * Emergency compaction when context exceeds threshold.
16225
16406
  *
16226
16407
  * Strategy:
16227
- * 1. Run consolidate() first to move tool results to memory
16408
+ * 1. Run consolidate() first to move tool results to memory (if working memory available)
16228
16409
  * 2. If still need space, apply rolling window (remove oldest messages)
16410
+ *
16411
+ * Gracefully degrades: if working memory plugin is not registered,
16412
+ * skips step 1 and only uses rolling window compaction.
16229
16413
  */
16230
16414
  async compact(context, targetToFree) {
16231
16415
  const log = [];
@@ -16238,7 +16422,7 @@ var AlgorithmicCompactionStrategy = class {
16238
16422
  tokensFreed += Math.abs(consolidateResult.tokensChanged);
16239
16423
  log.push(...consolidateResult.actions);
16240
16424
  }
16241
- let remaining = targetToFree - tokensFreed;
16425
+ const remaining = targetToFree - tokensFreed;
16242
16426
  if (remaining > 0 && context.conversation.length > 0) {
16243
16427
  log.push(`Rolling window: need to free ~${remaining} more tokens`);
16244
16428
  const result = await this.applyRollingWindow(context, remaining, log);
@@ -16252,8 +16436,11 @@ var AlgorithmicCompactionStrategy = class {
16252
16436
  * Post-cycle consolidation.
16253
16437
  *
16254
16438
  * 1. Find all tool pairs in conversation
16255
- * 2. Move large tool results (> threshold) to Working Memory
16439
+ * 2. Move large tool results (> threshold) to Working Memory (if available)
16256
16440
  * 3. Limit remaining tool pairs to maxToolPairs
16441
+ *
16442
+ * Gracefully degrades: if working memory is not available, skips step 2
16443
+ * and only limits tool pairs + removes excess via rolling window.
16257
16444
  */
16258
16445
  async consolidate(context) {
16259
16446
  const log = [];
@@ -16264,23 +16451,25 @@ var AlgorithmicCompactionStrategy = class {
16264
16451
  return { performed: false, tokensChanged: 0, actions: [] };
16265
16452
  }
16266
16453
  const indicesToRemove = [];
16267
- for (const pair of toolPairs) {
16268
- if (pair.resultSizeBytes > this.toolResultSizeThreshold) {
16269
- const key = this.generateKey(pair.toolName, pair.toolUseId);
16270
- const desc = this.generateDescription(pair.toolName, pair.toolArgs);
16271
- await memory.store(key, desc, pair.resultContent, {
16272
- tier: "raw",
16273
- priority: "normal"
16274
- });
16275
- if (!indicesToRemove.includes(pair.toolUseIndex)) {
16276
- indicesToRemove.push(pair.toolUseIndex);
16277
- }
16278
- if (!indicesToRemove.includes(pair.toolResultIndex)) {
16279
- indicesToRemove.push(pair.toolResultIndex);
16454
+ if (memory) {
16455
+ for (const pair of toolPairs) {
16456
+ if (pair.resultSizeBytes > this.toolResultSizeThreshold) {
16457
+ const key = this.generateKey(pair.toolName, pair.toolUseId);
16458
+ const desc = this.generateDescription(pair.toolName, pair.toolArgs);
16459
+ await memory.store(key, desc, pair.resultContent, {
16460
+ tier: "raw",
16461
+ priority: "normal"
16462
+ });
16463
+ if (!indicesToRemove.includes(pair.toolUseIndex)) {
16464
+ indicesToRemove.push(pair.toolUseIndex);
16465
+ }
16466
+ if (!indicesToRemove.includes(pair.toolResultIndex)) {
16467
+ indicesToRemove.push(pair.toolResultIndex);
16468
+ }
16469
+ log.push(
16470
+ `Moved ${pair.toolName} result (${this.formatBytes(pair.resultSizeBytes)}) to memory: ${key}`
16471
+ );
16280
16472
  }
16281
- log.push(
16282
- `Moved ${pair.toolName} result (${this.formatBytes(pair.resultSizeBytes)}) to memory: ${key}`
16283
- );
16284
16473
  }
16285
16474
  }
16286
16475
  const remainingPairs = toolPairs.filter(
@@ -16309,15 +16498,12 @@ var AlgorithmicCompactionStrategy = class {
16309
16498
  };
16310
16499
  }
16311
16500
  /**
16312
- * Get the Working Memory plugin from context.
16313
- * @throws Error if plugin is not available
16501
+ * Get the Working Memory plugin from context, or null if not available.
16502
+ * When null, the strategy degrades gracefully (skips memory operations).
16314
16503
  */
16315
16504
  getWorkingMemory(context) {
16316
16505
  const plugin = context.plugins.find((p) => p.name === "working_memory");
16317
- if (!plugin) {
16318
- throw new Error("AlgorithmicCompactionStrategy requires working_memory plugin");
16319
- }
16320
- return plugin;
16506
+ return plugin ? plugin : null;
16321
16507
  }
16322
16508
  /**
16323
16509
  * Find all tool_use/tool_result pairs in conversation.
@@ -16696,12 +16882,14 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
16696
16882
  _agentId;
16697
16883
  /** User ID for multi-user scenarios */
16698
16884
  _userId;
16699
- /** Allowed connector names (when agent is restricted to a subset) */
16700
- _allowedConnectors;
16885
+ /** Auth identities this agent is scoped to (connector + optional accountId) */
16886
+ _identities;
16701
16887
  /** Storage backend */
16702
16888
  _storage;
16703
16889
  /** Destroyed flag */
16704
16890
  _destroyed = false;
16891
+ /** Last thinking/reasoning content from the most recent assistant response */
16892
+ _lastThinking = null;
16705
16893
  /** Cached budget from last prepare() call */
16706
16894
  _cachedBudget = null;
16707
16895
  /** Callback for beforeCompaction hook (set by Agent) */
@@ -16735,7 +16923,7 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
16735
16923
  this._systemPrompt = config.systemPrompt;
16736
16924
  this._agentId = this._config.agentId;
16737
16925
  this._userId = config.userId;
16738
- this._allowedConnectors = config.connectors;
16926
+ this._identities = config.identities;
16739
16927
  const sessionFactory = StorageRegistry.get("sessions");
16740
16928
  const storageCtx = StorageRegistry.getContext() ?? (config.userId ? { userId: config.userId } : void 0);
16741
16929
  this._storage = config.storage ?? (sessionFactory ? sessionFactory(this._agentId, storageCtx) : void 0);
@@ -16789,15 +16977,16 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
16789
16977
  }
16790
16978
  /**
16791
16979
  * Validate that a strategy's required plugins are registered.
16792
- * @throws Error if any required plugin is missing
16980
+ * Logs a warning if required plugins are missing — the strategy should degrade gracefully.
16793
16981
  */
16794
16982
  validateStrategyDependencies(strategy) {
16795
16983
  if (!strategy.requiredPlugins?.length) return;
16796
16984
  const availablePlugins = new Set(this._plugins.keys());
16797
16985
  const missing = strategy.requiredPlugins.filter((name) => !availablePlugins.has(name));
16798
16986
  if (missing.length > 0) {
16799
- throw new Error(
16800
- `Strategy '${strategy.name}' requires plugins that are not registered: ${missing.join(", ")}. Available plugins: ${Array.from(availablePlugins).join(", ") || "none"}`
16987
+ logger.warn(
16988
+ { strategy: strategy.name, missing, available: Array.from(availablePlugins) },
16989
+ `Strategy '${strategy.name}' recommends plugins that are not registered: ${missing.join(", ")}. Strategy will degrade gracefully.`
16801
16990
  );
16802
16991
  }
16803
16992
  }
@@ -16806,7 +16995,7 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
16806
16995
  * Merges with existing ToolContext to preserve other fields (memory, signal, taskId).
16807
16996
  *
16808
16997
  * Connector registry resolution order:
16809
- * 1. If `connectors` (allowed names) is set → filtered view of global registry
16998
+ * 1. If `identities` is set → filtered view showing only identity connectors
16810
16999
  * 2. If access policy + userId → scoped view via Connector.scoped()
16811
17000
  * 3. Otherwise → full global registry
16812
17001
  */
@@ -16816,6 +17005,7 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
16816
17005
  ...existing,
16817
17006
  agentId: this._agentId,
16818
17007
  userId: this._userId,
17008
+ identities: this._identities,
16819
17009
  connectorRegistry: this.buildConnectorRegistry()
16820
17010
  });
16821
17011
  }
@@ -16823,13 +17013,13 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
16823
17013
  * Build the connector registry appropriate for this agent's config.
16824
17014
  */
16825
17015
  buildConnectorRegistry() {
16826
- if (this._allowedConnectors?.length) {
16827
- const allowedSet = new Set(this._allowedConnectors);
17016
+ if (this._identities?.length) {
17017
+ const allowedSet = new Set(this._identities.map((id) => id.connector));
16828
17018
  const base = this._userId && Connector.getAccessPolicy() ? Connector.scoped({ userId: this._userId }) : Connector.asRegistry();
16829
17019
  return {
16830
17020
  get: (name) => {
16831
17021
  if (!allowedSet.has(name)) {
16832
- const available = this._allowedConnectors.filter((n) => base.has(n)).join(", ") || "none";
17022
+ const available = [...allowedSet].filter((n) => base.has(n)).join(", ") || "none";
16833
17023
  throw new Error(`Connector '${name}' not found. Available: ${available}`);
16834
17024
  }
16835
17025
  return base.get(name);
@@ -16881,13 +17071,13 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
16881
17071
  this._userId = value;
16882
17072
  this.syncToolContext();
16883
17073
  }
16884
- /** Get the allowed connector names (undefined = all visible connectors) */
16885
- get connectors() {
16886
- return this._allowedConnectors;
17074
+ /** Get the auth identities this agent is scoped to (undefined = all visible connectors) */
17075
+ get identities() {
17076
+ return this._identities;
16887
17077
  }
16888
- /** Set allowed connector names. Updates ToolContext.connectorRegistry. */
16889
- set connectors(value) {
16890
- this._allowedConnectors = value;
17078
+ /** Set auth identities. Updates ToolContext.connectorRegistry and identity-aware descriptions. */
17079
+ set identities(value) {
17080
+ this._identities = value;
16891
17081
  this.syncToolContext();
16892
17082
  }
16893
17083
  /** Get/set system prompt */
@@ -16913,6 +17103,13 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
16913
17103
  get storage() {
16914
17104
  return this._storage ?? null;
16915
17105
  }
17106
+ /**
17107
+ * Get the last thinking/reasoning content from the most recent assistant response.
17108
+ * Updated on every assistant response, always available regardless of persistence setting.
17109
+ */
17110
+ get lastThinking() {
17111
+ return this._lastThinking;
17112
+ }
16916
17113
  /** Get max context tokens */
16917
17114
  get maxContextTokens() {
16918
17115
  return this._maxContextTokens;
@@ -17094,6 +17291,7 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
17094
17291
  }
17095
17292
  const id = this.generateId();
17096
17293
  const contentArray = [];
17294
+ let thinkingText = null;
17097
17295
  for (const item of output) {
17098
17296
  if (item.type === "message" && "content" in item) {
17099
17297
  const msg = item;
@@ -17105,12 +17303,19 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
17105
17303
  });
17106
17304
  } else if (c.type === "tool_use" /* TOOL_USE */) {
17107
17305
  contentArray.push(c);
17306
+ } else if (c.type === "thinking" /* THINKING */) {
17307
+ const thinking = c;
17308
+ thinkingText = thinking.thinking;
17309
+ if (thinking.persistInHistory) {
17310
+ contentArray.push(c);
17311
+ }
17108
17312
  }
17109
17313
  }
17110
17314
  } else if (item.type === "compaction" || item.type === "reasoning") {
17111
17315
  continue;
17112
17316
  }
17113
17317
  }
17318
+ this._lastThinking = thinkingText;
17114
17319
  if (contentArray.length > 0) {
17115
17320
  const message = {
17116
17321
  type: "message",
@@ -17209,6 +17414,7 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
17209
17414
  */
17210
17415
  async prepare() {
17211
17416
  this.assertNotDestroyed();
17417
+ this._lastThinking = null;
17212
17418
  const compactionLog = [];
17213
17419
  const toolsTokens = this.calculateToolsTokens();
17214
17420
  const availableForContent = this._maxContextTokens - this._config.responseReserve - toolsTokens;
@@ -17421,6 +17627,8 @@ ${content}`);
17421
17627
  total += this._estimateImageTokens();
17422
17628
  }
17423
17629
  }
17630
+ } else if (c.type === "thinking" /* THINKING */) {
17631
+ total += this._estimator.estimateTokens(c.thinking || "");
17424
17632
  } else if (c.type === "input_image_url" /* INPUT_IMAGE_URL */) {
17425
17633
  const imgContent = c;
17426
17634
  const detail = imgContent.image_url?.detail;
@@ -17918,6 +18126,188 @@ ${content}`);
17918
18126
  get strategy() {
17919
18127
  return this._compactionStrategy.name;
17920
18128
  }
18129
+ /**
18130
+ * Get a complete, serializable snapshot of the context state.
18131
+ *
18132
+ * Returns all data needed by UI "Look Inside" panels without reaching
18133
+ * into plugin internals. Plugin data is auto-discovered from the plugin
18134
+ * registry — new/custom plugins appear automatically.
18135
+ *
18136
+ * @param toolStats - Optional tool usage stats (from ToolManager.getStats())
18137
+ * @returns Serializable context snapshot
18138
+ */
18139
+ async getSnapshot(toolStats) {
18140
+ const resolveContents = async (raw) => {
18141
+ const resolved = raw instanceof Promise ? await raw : raw;
18142
+ if (resolved instanceof Map) return Array.from(resolved.values());
18143
+ return resolved;
18144
+ };
18145
+ if (this._destroyed) {
18146
+ const emptyBudget = this._cachedBudget ?? {
18147
+ maxTokens: this._maxContextTokens,
18148
+ responseReserve: this._config.responseReserve,
18149
+ systemMessageTokens: 0,
18150
+ toolsTokens: 0,
18151
+ conversationTokens: 0,
18152
+ currentInputTokens: 0,
18153
+ totalUsed: 0,
18154
+ available: this._maxContextTokens - this._config.responseReserve,
18155
+ utilizationPercent: 0,
18156
+ breakdown: {
18157
+ systemPrompt: 0,
18158
+ persistentInstructions: 0,
18159
+ pluginInstructions: 0,
18160
+ pluginContents: {},
18161
+ tools: 0,
18162
+ conversation: 0,
18163
+ currentInput: 0
18164
+ }
18165
+ };
18166
+ return {
18167
+ available: false,
18168
+ agentId: this._agentId,
18169
+ model: this._config.model,
18170
+ features: this._config.features,
18171
+ budget: emptyBudget,
18172
+ strategy: this._compactionStrategy.name,
18173
+ messagesCount: 0,
18174
+ toolCallsCount: 0,
18175
+ systemPrompt: null,
18176
+ plugins: [],
18177
+ tools: []
18178
+ };
18179
+ }
18180
+ const budget = await this.calculateBudget();
18181
+ const plugins = [];
18182
+ for (const plugin of this._plugins.values()) {
18183
+ let formattedContent = null;
18184
+ try {
18185
+ formattedContent = await plugin.getContent();
18186
+ } catch {
18187
+ }
18188
+ plugins.push({
18189
+ name: plugin.name,
18190
+ displayName: formatPluginDisplayName(plugin.name),
18191
+ enabled: true,
18192
+ tokenSize: plugin.getTokenSize(),
18193
+ instructionsTokenSize: plugin.getInstructionsTokenSize(),
18194
+ compactable: plugin.isCompactable(),
18195
+ contents: await resolveContents(plugin.getContents()),
18196
+ formattedContent
18197
+ });
18198
+ }
18199
+ const usageCounts = /* @__PURE__ */ new Map();
18200
+ if (toolStats?.mostUsed) {
18201
+ for (const { name, count } of toolStats.mostUsed) {
18202
+ usageCounts.set(name, count);
18203
+ }
18204
+ }
18205
+ const tools = [];
18206
+ for (const toolName of this._tools.list()) {
18207
+ const reg = this._tools.getRegistration(toolName);
18208
+ if (!reg) continue;
18209
+ tools.push({
18210
+ name: toolName,
18211
+ description: reg.tool.definition.function.description || "",
18212
+ enabled: reg.enabled,
18213
+ callCount: reg.metadata.usageCount ?? usageCounts.get(toolName) ?? 0,
18214
+ namespace: reg.namespace || void 0
18215
+ });
18216
+ }
18217
+ let toolCallsCount = 0;
18218
+ for (const item of this._conversation) {
18219
+ if (item.type === "message" && item.role === "assistant" /* ASSISTANT */) {
18220
+ for (const c of item.content) {
18221
+ if (c.type === "tool_use" /* TOOL_USE */) toolCallsCount++;
18222
+ }
18223
+ }
18224
+ }
18225
+ return {
18226
+ available: true,
18227
+ agentId: this._agentId,
18228
+ model: this._config.model,
18229
+ features: this._config.features,
18230
+ budget,
18231
+ strategy: this._compactionStrategy.name,
18232
+ messagesCount: this._conversation.length,
18233
+ toolCallsCount,
18234
+ systemPrompt: this._systemPrompt ?? null,
18235
+ plugins,
18236
+ tools
18237
+ };
18238
+ }
18239
+ /**
18240
+ * Get a human-readable breakdown of the prepared context.
18241
+ *
18242
+ * Calls `prepare()` internally, then maps each InputItem to a named
18243
+ * component with content text and token estimate. Used by "View Full Context" UIs.
18244
+ *
18245
+ * @returns View context data with components and raw text for "Copy All"
18246
+ */
18247
+ async getViewContext() {
18248
+ if (this._destroyed) {
18249
+ return { available: false, components: [], totalTokens: 0, rawContext: "" };
18250
+ }
18251
+ const { input, budget } = await this.prepare();
18252
+ const components = [];
18253
+ let rawParts = [];
18254
+ for (const item of input) {
18255
+ if (item.type === "compaction") {
18256
+ components.push({
18257
+ name: "Compaction Block",
18258
+ content: "[Compacted content]",
18259
+ tokenEstimate: 0
18260
+ });
18261
+ continue;
18262
+ }
18263
+ const msg = item;
18264
+ const roleName = msg.role === "developer" /* DEVELOPER */ ? "System Message" : msg.role === "user" /* USER */ ? "User Message" : "Assistant Message";
18265
+ for (const block of msg.content) {
18266
+ let name = roleName;
18267
+ let text = "";
18268
+ switch (block.type) {
18269
+ case "input_text" /* INPUT_TEXT */:
18270
+ text = block.text;
18271
+ break;
18272
+ case "output_text" /* OUTPUT_TEXT */:
18273
+ text = block.text;
18274
+ break;
18275
+ case "tool_use" /* TOOL_USE */:
18276
+ name = `Tool Call: ${block.name}`;
18277
+ text = `${block.name}(${block.arguments})`;
18278
+ break;
18279
+ case "tool_result" /* TOOL_RESULT */:
18280
+ name = `Tool Result: ${block.tool_use_id}`;
18281
+ text = typeof block.content === "string" ? block.content : JSON.stringify(block.content, null, 2);
18282
+ if (block.error) text = `[Error] ${block.error}
18283
+ ${text}`;
18284
+ break;
18285
+ case "input_image_url" /* INPUT_IMAGE_URL */:
18286
+ name = "Image Input";
18287
+ text = `[Image: ${block.image_url.url.substring(0, 100)}...]`;
18288
+ break;
18289
+ case "input_file" /* INPUT_FILE */:
18290
+ name = "File Input";
18291
+ text = `[File: ${block.file_id}]`;
18292
+ break;
18293
+ case "thinking" /* THINKING */:
18294
+ name = "Thinking";
18295
+ text = block.thinking || "";
18296
+ break;
18297
+ }
18298
+ const tokenEstimate = this._estimator.estimateTokens(text);
18299
+ components.push({ name, content: text, tokenEstimate });
18300
+ rawParts.push(`--- ${name} ---
18301
+ ${text}`);
18302
+ }
18303
+ }
18304
+ return {
18305
+ available: true,
18306
+ components,
18307
+ totalTokens: budget.totalUsed,
18308
+ rawContext: rawParts.join("\n\n")
18309
+ };
18310
+ }
17921
18311
  // ============================================================================
17922
18312
  // Utilities
17923
18313
  // ============================================================================
@@ -18176,6 +18566,13 @@ var BaseTextProvider = class extends BaseProvider {
18176
18566
  }
18177
18567
  return textParts.join("\n");
18178
18568
  }
18569
+ /**
18570
+ * List available models from the provider's API.
18571
+ * Default returns empty array; providers override when they have SDK support.
18572
+ */
18573
+ async listModels() {
18574
+ return [];
18575
+ }
18179
18576
  /**
18180
18577
  * Clean up provider resources (circuit breaker listeners, etc.)
18181
18578
  * Should be called when the provider is no longer needed.
@@ -18328,12 +18725,21 @@ var OpenAIResponsesConverter = class {
18328
18725
  } else if (item.type === "reasoning") {
18329
18726
  const reasoning = item;
18330
18727
  if (reasoning.summary) {
18331
- content.push({
18332
- type: "reasoning",
18333
- summary: reasoning.summary,
18334
- // effort field may not exist in all versions
18335
- ..."effort" in reasoning && { effort: reasoning.effort }
18336
- });
18728
+ let summaryText;
18729
+ if (typeof reasoning.summary === "string") {
18730
+ summaryText = reasoning.summary;
18731
+ } else if (Array.isArray(reasoning.summary)) {
18732
+ summaryText = reasoning.summary.map((s) => s.text || "").filter(Boolean).join("\n");
18733
+ } else {
18734
+ summaryText = "";
18735
+ }
18736
+ if (summaryText) {
18737
+ content.push({
18738
+ type: "thinking" /* THINKING */,
18739
+ thinking: summaryText,
18740
+ persistInHistory: false
18741
+ });
18742
+ }
18337
18743
  }
18338
18744
  }
18339
18745
  }
@@ -18356,10 +18762,20 @@ var OpenAIResponsesConverter = class {
18356
18762
  }
18357
18763
  ],
18358
18764
  output_text: outputText,
18765
+ // Extract thinking text from content for convenience field
18766
+ ...(() => {
18767
+ const thinkingTexts = content.filter((c) => c.type === "thinking" /* THINKING */).map((c) => c.thinking).filter(Boolean);
18768
+ return thinkingTexts.length > 0 ? { thinking: thinkingTexts.join("\n") } : {};
18769
+ })(),
18359
18770
  usage: {
18360
18771
  input_tokens: response.usage?.input_tokens || 0,
18361
18772
  output_tokens: response.usage?.output_tokens || 0,
18362
- total_tokens: response.usage?.total_tokens || 0
18773
+ total_tokens: response.usage?.total_tokens || 0,
18774
+ ...response.usage?.output_tokens_details?.reasoning_tokens != null && {
18775
+ output_tokens_details: {
18776
+ reasoning_tokens: response.usage.output_tokens_details.reasoning_tokens
18777
+ }
18778
+ }
18363
18779
  }
18364
18780
  };
18365
18781
  }
@@ -18464,6 +18880,8 @@ var StreamEventType = /* @__PURE__ */ ((StreamEventType2) => {
18464
18880
  StreamEventType2["TOOL_EXECUTION_START"] = "response.tool_execution.start";
18465
18881
  StreamEventType2["TOOL_EXECUTION_DONE"] = "response.tool_execution.done";
18466
18882
  StreamEventType2["ITERATION_COMPLETE"] = "response.iteration.complete";
18883
+ StreamEventType2["REASONING_DELTA"] = "response.reasoning.delta";
18884
+ StreamEventType2["REASONING_DONE"] = "response.reasoning.done";
18467
18885
  StreamEventType2["RESPONSE_COMPLETE"] = "response.complete";
18468
18886
  StreamEventType2["ERROR"] = "response.error";
18469
18887
  return StreamEventType2;
@@ -18483,6 +18901,12 @@ function isToolCallArgumentsDelta(event) {
18483
18901
  function isToolCallArgumentsDone(event) {
18484
18902
  return event.type === "response.tool_call_arguments.done" /* TOOL_CALL_ARGUMENTS_DONE */;
18485
18903
  }
18904
+ function isReasoningDelta(event) {
18905
+ return event.type === "response.reasoning.delta" /* REASONING_DELTA */;
18906
+ }
18907
+ function isReasoningDone(event) {
18908
+ return event.type === "response.reasoning.done" /* REASONING_DONE */;
18909
+ }
18486
18910
  function isResponseComplete(event) {
18487
18911
  return event.type === "response.complete" /* RESPONSE_COMPLETE */;
18488
18912
  }
@@ -18500,6 +18924,8 @@ var OpenAIResponsesStreamConverter = class {
18500
18924
  let sequenceNumber = 0;
18501
18925
  const activeItems = /* @__PURE__ */ new Map();
18502
18926
  const toolCallBuffers = /* @__PURE__ */ new Map();
18927
+ const reasoningBuffers = /* @__PURE__ */ new Map();
18928
+ const reasoningDoneEmitted = /* @__PURE__ */ new Set();
18503
18929
  for await (const event of stream) {
18504
18930
  if (process.env.DEBUG_OPENAI) {
18505
18931
  console.error("[DEBUG] Responses API event:", event.type);
@@ -18521,6 +18947,12 @@ var OpenAIResponsesStreamConverter = class {
18521
18947
  activeItems.set(addedEvent.output_index.toString(), {
18522
18948
  type: item.type
18523
18949
  });
18950
+ if (item.type === "reasoning") {
18951
+ activeItems.set(addedEvent.output_index.toString(), {
18952
+ type: "reasoning"
18953
+ });
18954
+ reasoningBuffers.set(addedEvent.output_index.toString(), []);
18955
+ }
18524
18956
  if (item.type === "function_call") {
18525
18957
  const functionCall = item;
18526
18958
  const toolCallId = functionCall.call_id;
@@ -18578,9 +19010,53 @@ var OpenAIResponsesStreamConverter = class {
18578
19010
  }
18579
19011
  break;
18580
19012
  }
19013
+ case "response.reasoning_summary_text.delta":
19014
+ case "response.reasoning_text.delta": {
19015
+ const reasoningEvent = event;
19016
+ const outputIdx = reasoningEvent.output_index?.toString();
19017
+ const buffer = outputIdx ? reasoningBuffers.get(outputIdx) : void 0;
19018
+ if (buffer) {
19019
+ buffer.push(reasoningEvent.delta || "");
19020
+ }
19021
+ yield {
19022
+ type: "response.reasoning.delta" /* REASONING_DELTA */,
19023
+ response_id: responseId,
19024
+ item_id: reasoningEvent.item_id || `reasoning_${responseId}`,
19025
+ delta: reasoningEvent.delta || "",
19026
+ sequence_number: sequenceNumber++
19027
+ };
19028
+ break;
19029
+ }
19030
+ case "response.reasoning_text.done": {
19031
+ const doneEvent = event;
19032
+ const outputIdx = doneEvent.output_index.toString();
19033
+ const rBuf = reasoningBuffers.get(outputIdx);
19034
+ const thinkingText = rBuf ? rBuf.join("") : doneEvent.text || "";
19035
+ reasoningDoneEmitted.add(outputIdx);
19036
+ yield {
19037
+ type: "response.reasoning.done" /* REASONING_DONE */,
19038
+ response_id: responseId,
19039
+ item_id: doneEvent.item_id || `reasoning_${responseId}`,
19040
+ thinking: thinkingText
19041
+ };
19042
+ break;
19043
+ }
18581
19044
  case "response.output_item.done": {
18582
19045
  const doneEvent = event;
18583
19046
  const item = doneEvent.item;
19047
+ if (item.type === "reasoning") {
19048
+ const outputIdx = doneEvent.output_index.toString();
19049
+ if (!reasoningDoneEmitted.has(outputIdx)) {
19050
+ const rBuf = reasoningBuffers.get(outputIdx);
19051
+ const thinkingText = rBuf ? rBuf.join("") : "";
19052
+ yield {
19053
+ type: "response.reasoning.done" /* REASONING_DONE */,
19054
+ response_id: responseId,
19055
+ item_id: item.id || `reasoning_${responseId}`,
19056
+ thinking: thinkingText
19057
+ };
19058
+ }
19059
+ }
18584
19060
  if (item.type === "function_call") {
18585
19061
  const functionCall = item;
18586
19062
  const buffer = toolCallBuffers.get(functionCall.call_id);
@@ -18612,7 +19088,12 @@ var OpenAIResponsesStreamConverter = class {
18612
19088
  usage: {
18613
19089
  input_tokens: response.usage?.input_tokens || 0,
18614
19090
  output_tokens: response.usage?.output_tokens || 0,
18615
- total_tokens: response.usage?.total_tokens || 0
19091
+ total_tokens: response.usage?.total_tokens || 0,
19092
+ ...response.usage?.output_tokens_details?.reasoning_tokens != null && {
19093
+ output_tokens_details: {
19094
+ reasoning_tokens: response.usage.output_tokens_details.reasoning_tokens
19095
+ }
19096
+ }
18616
19097
  },
18617
19098
  iterations: 1
18618
19099
  };
@@ -18653,6 +19134,26 @@ function resolveMaxContextTokens(model, fallback) {
18653
19134
  return info ? info.features.input.tokens : fallback;
18654
19135
  }
18655
19136
 
19137
+ // src/infrastructure/providers/shared/validateThinkingConfig.ts
19138
+ function validateThinkingConfig(thinking) {
19139
+ if (!thinking.enabled) return;
19140
+ if (thinking.budgetTokens !== void 0) {
19141
+ if (typeof thinking.budgetTokens !== "number" || thinking.budgetTokens < 1) {
19142
+ throw new Error(
19143
+ `Invalid thinking budgetTokens: ${thinking.budgetTokens}. Must be a positive number.`
19144
+ );
19145
+ }
19146
+ }
19147
+ if (thinking.effort !== void 0) {
19148
+ const validEfforts = ["low", "medium", "high"];
19149
+ if (!validEfforts.includes(thinking.effort)) {
19150
+ throw new Error(
19151
+ `Invalid thinking effort: '${thinking.effort}'. Must be one of: ${validEfforts.join(", ")}`
19152
+ );
19153
+ }
19154
+ }
19155
+ }
19156
+
18656
19157
  // src/infrastructure/providers/openai/OpenAITextProvider.ts
18657
19158
  var OpenAITextProvider = class extends BaseTextProvider {
18658
19159
  name = "openai";
@@ -18720,6 +19221,7 @@ var OpenAITextProvider = class extends BaseTextProvider {
18720
19221
  },
18721
19222
  ...options.metadata && { metadata: options.metadata }
18722
19223
  };
19224
+ this.applyReasoningConfig(params, options);
18723
19225
  const response = await this.client.responses.create(params);
18724
19226
  return this.converter.convertResponse(response);
18725
19227
  } catch (error) {
@@ -18761,6 +19263,7 @@ var OpenAITextProvider = class extends BaseTextProvider {
18761
19263
  ...options.metadata && { metadata: options.metadata },
18762
19264
  stream: true
18763
19265
  };
19266
+ this.applyReasoningConfig(params, options);
18764
19267
  const stream = await this.client.responses.create(params);
18765
19268
  yield* this.streamConverter.convertStream(stream);
18766
19269
  } catch (error) {
@@ -18782,6 +19285,27 @@ var OpenAITextProvider = class extends BaseTextProvider {
18782
19285
  maxOutputTokens: 16384
18783
19286
  });
18784
19287
  }
19288
+ /**
19289
+ * List available models from the OpenAI API
19290
+ */
19291
+ async listModels() {
19292
+ const models = [];
19293
+ for await (const model of this.client.models.list()) {
19294
+ models.push(model.id);
19295
+ }
19296
+ return models.sort();
19297
+ }
19298
+ /**
19299
+ * Apply reasoning config from unified thinking option to request params
19300
+ */
19301
+ applyReasoningConfig(params, options) {
19302
+ if (options.thinking?.enabled) {
19303
+ validateThinkingConfig(options.thinking);
19304
+ params.reasoning = {
19305
+ effort: options.thinking.effort || "medium"
19306
+ };
19307
+ }
19308
+ }
18785
19309
  /**
18786
19310
  * Handle OpenAI-specific errors
18787
19311
  */
@@ -18824,6 +19348,7 @@ function buildLLMResponse(options) {
18824
19348
  }
18825
19349
  ];
18826
19350
  const outputText = extractTextFromContent(content);
19351
+ const thinking = extractThinkingFromContent(content);
18827
19352
  return {
18828
19353
  id: responseId,
18829
19354
  object: "response",
@@ -18832,6 +19357,7 @@ function buildLLMResponse(options) {
18832
19357
  model,
18833
19358
  output,
18834
19359
  output_text: outputText,
19360
+ ...thinking && { thinking },
18835
19361
  usage: {
18836
19362
  input_tokens: usage.inputTokens,
18837
19363
  output_tokens: usage.outputTokens,
@@ -18844,6 +19370,10 @@ function extractTextFromContent(content) {
18844
19370
  (c) => c.type === "output_text" /* OUTPUT_TEXT */
18845
19371
  ).map((c) => c.text).join("\n");
18846
19372
  }
19373
+ function extractThinkingFromContent(content) {
19374
+ const thinkingTexts = content.filter((c) => c.type === "thinking" /* THINKING */).map((c) => c.thinking).filter(Boolean);
19375
+ return thinkingTexts.length > 0 ? thinkingTexts.join("\n") : void 0;
19376
+ }
18847
19377
  function createTextContent(text) {
18848
19378
  return {
18849
19379
  type: "output_text" /* OUTPUT_TEXT */,
@@ -19093,7 +19623,15 @@ var AnthropicConverter = class extends BaseConverter {
19093
19623
  if (tools && tools.length > 0) {
19094
19624
  params.tools = tools;
19095
19625
  }
19096
- if (options.temperature !== void 0) {
19626
+ if (options.thinking?.enabled) {
19627
+ validateThinkingConfig(options.thinking);
19628
+ const budgetTokens = options.thinking.budgetTokens || 1e4;
19629
+ params.thinking = {
19630
+ type: "enabled",
19631
+ budget_tokens: budgetTokens
19632
+ };
19633
+ params.temperature = 1;
19634
+ } else if (options.temperature !== void 0) {
19097
19635
  params.temperature = options.temperature;
19098
19636
  }
19099
19637
  return params;
@@ -19139,6 +19677,14 @@ var AnthropicConverter = class extends BaseConverter {
19139
19677
  content.push(this.createText(block.text));
19140
19678
  } else if (block.type === "tool_use") {
19141
19679
  content.push(this.createToolUse(block.id, block.name, block.input));
19680
+ } else if (block.type === "thinking") {
19681
+ const thinkingBlock = block;
19682
+ content.push({
19683
+ type: "thinking" /* THINKING */,
19684
+ thinking: thinkingBlock.thinking || "",
19685
+ signature: thinkingBlock.signature,
19686
+ persistInHistory: true
19687
+ });
19142
19688
  }
19143
19689
  }
19144
19690
  return content;
@@ -19217,6 +19763,17 @@ var AnthropicConverter = class extends BaseConverter {
19217
19763
  });
19218
19764
  break;
19219
19765
  }
19766
+ case "thinking" /* THINKING */: {
19767
+ const thinkingContent = c;
19768
+ if (thinkingContent.signature) {
19769
+ blocks.push({
19770
+ type: "thinking",
19771
+ thinking: thinkingContent.thinking,
19772
+ signature: thinkingContent.signature
19773
+ });
19774
+ }
19775
+ break;
19776
+ }
19220
19777
  }
19221
19778
  }
19222
19779
  if (blocks.length === 1 && blocks[0]?.type === "text") {
@@ -19349,6 +19906,8 @@ var BaseStreamConverter = class {
19349
19906
  usage = { inputTokens: 0, outputTokens: 0 };
19350
19907
  /** Buffers for accumulating tool call arguments */
19351
19908
  toolCallBuffers = /* @__PURE__ */ new Map();
19909
+ /** Buffer for accumulating reasoning/thinking content */
19910
+ reasoningBuffer = "";
19352
19911
  // ==========================================================================
19353
19912
  // Public API
19354
19913
  // ==========================================================================
@@ -19383,6 +19942,7 @@ var BaseStreamConverter = class {
19383
19942
  this.sequenceNumber = 0;
19384
19943
  this.usage = { inputTokens: 0, outputTokens: 0 };
19385
19944
  this.toolCallBuffers.clear();
19945
+ this.reasoningBuffer = "";
19386
19946
  }
19387
19947
  /**
19388
19948
  * Reset converter state for a new stream
@@ -19437,6 +19997,33 @@ var BaseStreamConverter = class {
19437
19997
  sequence_number: this.nextSequence()
19438
19998
  };
19439
19999
  }
20000
+ /**
20001
+ * Create REASONING_DELTA event and accumulate reasoning buffer
20002
+ */
20003
+ emitReasoningDelta(delta, itemId) {
20004
+ this.reasoningBuffer += delta;
20005
+ return {
20006
+ type: "response.reasoning.delta" /* REASONING_DELTA */,
20007
+ response_id: this.responseId,
20008
+ item_id: itemId || `reasoning_${this.responseId}`,
20009
+ delta,
20010
+ sequence_number: this.nextSequence()
20011
+ };
20012
+ }
20013
+ /**
20014
+ * Create REASONING_DONE event with accumulated reasoning
20015
+ */
20016
+ emitReasoningDone(itemId) {
20017
+ const id = itemId || `reasoning_${this.responseId}`;
20018
+ const thinking = this.reasoningBuffer;
20019
+ this.reasoningBuffer = "";
20020
+ return {
20021
+ type: "response.reasoning.done" /* REASONING_DONE */,
20022
+ response_id: this.responseId,
20023
+ item_id: id,
20024
+ thinking
20025
+ };
20026
+ }
19440
20027
  /**
19441
20028
  * Create TOOL_CALL_START event
19442
20029
  */
@@ -19581,7 +20168,10 @@ var AnthropicStreamConverter = class extends BaseStreamConverter {
19581
20168
  handleContentBlockStart(event) {
19582
20169
  const index = event.index;
19583
20170
  const block = event.content_block;
19584
- if (block.type === "text") {
20171
+ if (block.type === "thinking") {
20172
+ this.contentBlockIndex.set(index, { type: "thinking" });
20173
+ return [];
20174
+ } else if (block.type === "text") {
19585
20175
  this.contentBlockIndex.set(index, { type: "text" });
19586
20176
  return [];
19587
20177
  } else if (block.type === "tool_use") {
@@ -19602,7 +20192,12 @@ var AnthropicStreamConverter = class extends BaseStreamConverter {
19602
20192
  const delta = event.delta;
19603
20193
  const blockInfo = this.contentBlockIndex.get(index);
19604
20194
  if (!blockInfo) return [];
19605
- if (delta.type === "text_delta") {
20195
+ if (delta.type === "thinking_delta") {
20196
+ const thinkingDelta = delta;
20197
+ return [
20198
+ this.emitReasoningDelta(thinkingDelta.thinking || "", `thinking_${this.responseId}`)
20199
+ ];
20200
+ } else if (delta.type === "text_delta") {
19606
20201
  return [
19607
20202
  this.emitTextDelta(delta.text, {
19608
20203
  itemId: `msg_${this.responseId}`,
@@ -19622,6 +20217,9 @@ var AnthropicStreamConverter = class extends BaseStreamConverter {
19622
20217
  const index = event.index;
19623
20218
  const blockInfo = this.contentBlockIndex.get(index);
19624
20219
  if (!blockInfo) return [];
20220
+ if (blockInfo.type === "thinking") {
20221
+ return [this.emitReasoningDone(`thinking_${this.responseId}`)];
20222
+ }
19625
20223
  if (blockInfo.type === "tool_use") {
19626
20224
  return [this.emitToolCallArgsDone(blockInfo.id || "", blockInfo.name)];
19627
20225
  }
@@ -19720,6 +20318,16 @@ var AnthropicTextProvider = class extends BaseTextProvider {
19720
20318
  caps.supportsJSONSchema = false;
19721
20319
  return caps;
19722
20320
  }
20321
+ /**
20322
+ * List available models from the Anthropic API
20323
+ */
20324
+ async listModels() {
20325
+ const models = [];
20326
+ for await (const model of this.client.models.list()) {
20327
+ models.push(model.id);
20328
+ }
20329
+ return models.sort();
20330
+ }
19723
20331
  /**
19724
20332
  * Handle Anthropic-specific errors
19725
20333
  */
@@ -19898,6 +20506,11 @@ var GoogleConverter = class {
19898
20506
  request.generationConfig.thinkingConfig = {
19899
20507
  thinkingLevel: options.vendorOptions.thinkingLevel
19900
20508
  };
20509
+ } else if (options.thinking?.enabled) {
20510
+ validateThinkingConfig(options.thinking);
20511
+ request.generationConfig.thinkingConfig = {
20512
+ thinkingBudget: options.thinking.budgetTokens || 8192
20513
+ };
19901
20514
  }
19902
20515
  if (tools && tools.length > 0) {
19903
20516
  request.generationConfig.allowCodeExecution = false;
@@ -20113,7 +20726,13 @@ var GoogleConverter = class {
20113
20726
  convertGeminiPartsToContent(parts) {
20114
20727
  const content = [];
20115
20728
  for (const part of parts) {
20116
- if ("text" in part && part.text) {
20729
+ if ("thought" in part && part.thought === true && "text" in part && part.text) {
20730
+ content.push({
20731
+ type: "thinking" /* THINKING */,
20732
+ thinking: part.text,
20733
+ persistInHistory: false
20734
+ });
20735
+ } else if ("text" in part && part.text) {
20117
20736
  content.push(createTextContent(part.text));
20118
20737
  } else if ("functionCall" in part && part.functionCall) {
20119
20738
  const toolId = generateToolCallId("google");
@@ -20191,6 +20810,8 @@ var GoogleStreamConverter = class {
20191
20810
  isFirst = true;
20192
20811
  toolCallBuffers = /* @__PURE__ */ new Map();
20193
20812
  hadToolCalls = false;
20813
+ reasoningBuffer = "";
20814
+ wasThinking = false;
20194
20815
  // External storage for thought signatures (shared with GoogleConverter)
20195
20816
  thoughtSignatureStorage = null;
20196
20817
  // External storage for tool call ID → name mapping (shared with GoogleConverter)
@@ -20218,6 +20839,8 @@ var GoogleStreamConverter = class {
20218
20839
  this.isFirst = true;
20219
20840
  this.toolCallBuffers.clear();
20220
20841
  this.hadToolCalls = false;
20842
+ this.reasoningBuffer = "";
20843
+ this.wasThinking = false;
20221
20844
  let lastUsage = {
20222
20845
  input_tokens: 0,
20223
20846
  output_tokens: 0,
@@ -20243,6 +20866,16 @@ var GoogleStreamConverter = class {
20243
20866
  yield event;
20244
20867
  }
20245
20868
  }
20869
+ if (this.wasThinking && this.reasoningBuffer) {
20870
+ yield {
20871
+ type: "response.reasoning.done" /* REASONING_DONE */,
20872
+ response_id: this.responseId,
20873
+ item_id: `thinking_${this.responseId}`,
20874
+ thinking: this.reasoningBuffer
20875
+ };
20876
+ this.reasoningBuffer = "";
20877
+ this.wasThinking = false;
20878
+ }
20246
20879
  if (this.toolCallBuffers.size > 0) {
20247
20880
  for (const [toolCallId, buffer] of this.toolCallBuffers) {
20248
20881
  yield {
@@ -20282,7 +20915,28 @@ var GoogleStreamConverter = class {
20282
20915
  const candidate = chunk.candidates?.[0];
20283
20916
  if (!candidate?.content?.parts) return events;
20284
20917
  for (const part of candidate.content.parts) {
20285
- if (part.text) {
20918
+ const isThought = "thought" in part && part.thought === true;
20919
+ if (isThought && part.text) {
20920
+ this.wasThinking = true;
20921
+ this.reasoningBuffer += part.text;
20922
+ events.push({
20923
+ type: "response.reasoning.delta" /* REASONING_DELTA */,
20924
+ response_id: this.responseId,
20925
+ item_id: `thinking_${this.responseId}`,
20926
+ delta: part.text,
20927
+ sequence_number: this.sequenceNumber++
20928
+ });
20929
+ } else if (part.text) {
20930
+ if (this.wasThinking) {
20931
+ this.wasThinking = false;
20932
+ events.push({
20933
+ type: "response.reasoning.done" /* REASONING_DONE */,
20934
+ response_id: this.responseId,
20935
+ item_id: `thinking_${this.responseId}`,
20936
+ thinking: this.reasoningBuffer
20937
+ });
20938
+ this.reasoningBuffer = "";
20939
+ }
20286
20940
  events.push({
20287
20941
  type: "response.output_text.delta" /* OUTPUT_TEXT_DELTA */,
20288
20942
  response_id: this.responseId,
@@ -20381,6 +21035,8 @@ var GoogleStreamConverter = class {
20381
21035
  this.isFirst = true;
20382
21036
  this.toolCallBuffers.clear();
20383
21037
  this.hadToolCalls = false;
21038
+ this.reasoningBuffer = "";
21039
+ this.wasThinking = false;
20384
21040
  }
20385
21041
  /**
20386
21042
  * Reset converter state for a new stream
@@ -20510,6 +21166,18 @@ var GoogleTextProvider = class extends BaseTextProvider {
20510
21166
  maxOutputTokens: 65536
20511
21167
  });
20512
21168
  }
21169
+ /**
21170
+ * List available models from the Google Gemini API
21171
+ */
21172
+ async listModels() {
21173
+ const models = [];
21174
+ const pager = await this.client.models.list();
21175
+ for await (const model of pager) {
21176
+ const name = model.name?.replace(/^models\//, "") ?? "";
21177
+ if (name) models.push(name);
21178
+ }
21179
+ return models.sort();
21180
+ }
20513
21181
  /**
20514
21182
  * Handle Google-specific errors
20515
21183
  */
@@ -20617,6 +21285,18 @@ var VertexAITextProvider = class extends BaseTextProvider {
20617
21285
  maxOutputTokens: 65536
20618
21286
  });
20619
21287
  }
21288
+ /**
21289
+ * List available models from the Vertex AI API
21290
+ */
21291
+ async listModels() {
21292
+ const models = [];
21293
+ const pager = await this.client.models.list();
21294
+ for await (const model of pager) {
21295
+ const name = model.name?.replace(/^models\//, "") ?? "";
21296
+ if (name) models.push(name);
21297
+ }
21298
+ return models.sort();
21299
+ }
20620
21300
  /**
20621
21301
  * Handle Vertex AI-specific errors
20622
21302
  */
@@ -20662,6 +21342,23 @@ var GenericOpenAIProvider = class extends OpenAITextProvider {
20662
21342
  };
20663
21343
  }
20664
21344
  }
21345
+ /**
21346
+ * Override API key validation for generic providers.
21347
+ * Services like Ollama don't require authentication, so accept any key including mock/placeholder keys.
21348
+ */
21349
+ validateApiKey() {
21350
+ return { isValid: true };
21351
+ }
21352
+ /**
21353
+ * Override listModels for error safety — some OpenAI-compatible APIs may not support /v1/models
21354
+ */
21355
+ async listModels() {
21356
+ try {
21357
+ return await super.listModels();
21358
+ } catch {
21359
+ return [];
21360
+ }
21361
+ }
20665
21362
  /**
20666
21363
  * Override model capabilities for generic providers (registry-driven with conservative defaults)
20667
21364
  */
@@ -20859,7 +21556,7 @@ var BaseAgent = class extends EventEmitter {
20859
21556
  model: config.model,
20860
21557
  agentId: config.name,
20861
21558
  userId: config.userId,
20862
- connectors: config.connectors,
21559
+ identities: config.identities,
20863
21560
  // Include storage and sessionId if session config is provided
20864
21561
  storage: config.session?.storage,
20865
21562
  // Thread tool execution timeout to ToolManager
@@ -21029,16 +21726,16 @@ var BaseAgent = class extends EventEmitter {
21029
21726
  this._agentContext.userId = value;
21030
21727
  }
21031
21728
  /**
21032
- * Get the allowed connector names (undefined = all visible connectors).
21729
+ * Get the auth identities this agent is scoped to (undefined = all visible connectors).
21033
21730
  */
21034
- get connectors() {
21035
- return this._agentContext.connectors;
21731
+ get identities() {
21732
+ return this._agentContext.identities;
21036
21733
  }
21037
21734
  /**
21038
- * Restrict this agent to a subset of connectors. Updates ToolContext.connectorRegistry.
21735
+ * Set auth identities at runtime. Updates ToolContext.connectorRegistry and tool descriptions.
21039
21736
  */
21040
- set connectors(value) {
21041
- this._agentContext.connectors = value;
21737
+ set identities(value) {
21738
+ this._agentContext.identities = value;
21042
21739
  }
21043
21740
  /**
21044
21741
  * Permission management. Returns ToolPermissionManager for approval control.
@@ -21050,9 +21747,12 @@ var BaseAgent = class extends EventEmitter {
21050
21747
  /**
21051
21748
  * Add a tool to the agent.
21052
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.)
21053
21753
  */
21054
- addTool(tool) {
21055
- this._agentContext.tools.register(tool);
21754
+ addTool(tool, options) {
21755
+ this._agentContext.tools.register(tool, options);
21056
21756
  if (tool.permission) {
21057
21757
  this._permissionManager.setToolConfig(tool.definition.function.name, tool.permission);
21058
21758
  }
@@ -21092,7 +21792,34 @@ var BaseAgent = class extends EventEmitter {
21092
21792
  */
21093
21793
  getEnabledToolDefinitions() {
21094
21794
  const toolContext = this._agentContext.tools.getToolContext();
21095
- 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;
21096
21823
  if (tool.descriptionFactory) {
21097
21824
  const dynamicDescription = tool.descriptionFactory(toolContext);
21098
21825
  return {
@@ -21106,6 +21833,34 @@ var BaseAgent = class extends EventEmitter {
21106
21833
  return tool.definition;
21107
21834
  });
21108
21835
  }
21836
+ // ===== Model Discovery =====
21837
+ /**
21838
+ * List available models from the provider's API.
21839
+ * Useful for discovering models dynamically (e.g., Ollama local models).
21840
+ */
21841
+ async listModels() {
21842
+ return this._provider.listModels();
21843
+ }
21844
+ // ===== Snapshot / Inspection =====
21845
+ /**
21846
+ * Get a complete, serializable snapshot of the agent's context state.
21847
+ *
21848
+ * Convenience method that auto-wires tool usage stats from ToolManager.
21849
+ * Used by UI "Look Inside" panels.
21850
+ */
21851
+ async getSnapshot() {
21852
+ const stats = this._agentContext.tools.getStats();
21853
+ return this._agentContext.getSnapshot({ mostUsed: stats.mostUsed });
21854
+ }
21855
+ /**
21856
+ * Get a human-readable breakdown of the prepared context.
21857
+ *
21858
+ * Convenience method that delegates to AgentContextNextGen.
21859
+ * Used by "View Full Context" UI panels.
21860
+ */
21861
+ async getViewContext() {
21862
+ return this._agentContext.getViewContext();
21863
+ }
21109
21864
  // ===== Direct LLM Access (Bypasses AgentContext) =====
21110
21865
  /**
21111
21866
  * Get the provider for LLM calls.
@@ -21869,6 +22624,8 @@ var StreamState = class {
21869
22624
  createdAt;
21870
22625
  // Text accumulation: item_id -> text chunks
21871
22626
  textBuffers;
22627
+ // Reasoning accumulation: item_id -> reasoning chunks
22628
+ reasoningBuffers;
21872
22629
  // Tool call accumulation: tool_call_id -> buffer
21873
22630
  toolCallBuffers;
21874
22631
  // Completed tool calls
@@ -21890,6 +22647,7 @@ var StreamState = class {
21890
22647
  this.model = model;
21891
22648
  this.createdAt = createdAt || Date.now();
21892
22649
  this.textBuffers = /* @__PURE__ */ new Map();
22650
+ this.reasoningBuffers = /* @__PURE__ */ new Map();
21893
22651
  this.toolCallBuffers = /* @__PURE__ */ new Map();
21894
22652
  this.completedToolCalls = [];
21895
22653
  this.toolResults = /* @__PURE__ */ new Map();
@@ -21933,6 +22691,39 @@ var StreamState = class {
21933
22691
  }
21934
22692
  return allText.join("");
21935
22693
  }
22694
+ /**
22695
+ * Accumulate reasoning delta for a specific item
22696
+ */
22697
+ accumulateReasoningDelta(itemId, delta) {
22698
+ if (!this.reasoningBuffers.has(itemId)) {
22699
+ this.reasoningBuffers.set(itemId, []);
22700
+ }
22701
+ this.reasoningBuffers.get(itemId).push(delta);
22702
+ this.totalChunks++;
22703
+ }
22704
+ /**
22705
+ * Get complete accumulated reasoning for an item
22706
+ */
22707
+ getCompleteReasoning(itemId) {
22708
+ const chunks = this.reasoningBuffers.get(itemId);
22709
+ return chunks ? chunks.join("") : "";
22710
+ }
22711
+ /**
22712
+ * Get all accumulated reasoning (all items concatenated)
22713
+ */
22714
+ getAllReasoning() {
22715
+ const allReasoning = [];
22716
+ for (const chunks of this.reasoningBuffers.values()) {
22717
+ allReasoning.push(chunks.join(""));
22718
+ }
22719
+ return allReasoning.join("");
22720
+ }
22721
+ /**
22722
+ * Check if stream has any accumulated reasoning
22723
+ */
22724
+ hasReasoning() {
22725
+ return this.reasoningBuffers.size > 0;
22726
+ }
21936
22727
  /**
21937
22728
  * Start accumulating tool call arguments
21938
22729
  */
@@ -22101,6 +22892,7 @@ var StreamState = class {
22101
22892
  */
22102
22893
  clear() {
22103
22894
  this.textBuffers.clear();
22895
+ this.reasoningBuffers.clear();
22104
22896
  this.toolCallBuffers.clear();
22105
22897
  this.completedToolCalls = [];
22106
22898
  this.toolResults.clear();
@@ -22114,6 +22906,7 @@ var StreamState = class {
22114
22906
  model: this.model,
22115
22907
  createdAt: this.createdAt,
22116
22908
  textBuffers: new Map(this.textBuffers),
22909
+ reasoningBuffers: new Map(this.reasoningBuffers),
22117
22910
  toolCallBuffers: new Map(this.toolCallBuffers),
22118
22911
  completedToolCalls: [...this.completedToolCalls],
22119
22912
  toolResults: new Map(this.toolResults),
@@ -22543,6 +23336,20 @@ var Agent = class _Agent extends BaseAgent {
22543
23336
  _addStreamingAssistantMessage(streamState, toolCalls) {
22544
23337
  const assistantText = streamState.getAllText();
22545
23338
  const assistantContent = [];
23339
+ if (streamState.hasReasoning()) {
23340
+ const reasoning = streamState.getAllReasoning();
23341
+ if (reasoning) {
23342
+ const isAnthropic = this.connector.vendor === Vendor.Anthropic;
23343
+ assistantContent.push({
23344
+ type: "thinking" /* THINKING */,
23345
+ thinking: reasoning,
23346
+ // Streaming doesn't carry Anthropic signatures, so signature is undefined here.
23347
+ // Non-streaming responses (via convertResponse) capture signatures correctly.
23348
+ signature: void 0,
23349
+ persistInHistory: isAnthropic
23350
+ });
23351
+ }
23352
+ }
22546
23353
  if (assistantText && assistantText.trim()) {
22547
23354
  assistantContent.push({
22548
23355
  type: "output_text" /* OUTPUT_TEXT */,
@@ -22781,6 +23588,7 @@ var Agent = class _Agent extends BaseAgent {
22781
23588
  tools: this.getEnabledToolDefinitions(),
22782
23589
  tool_choice: "auto",
22783
23590
  temperature: this._config.temperature,
23591
+ thinking: this._config.thinking,
22784
23592
  vendorOptions: this._config.vendorOptions
22785
23593
  };
22786
23594
  const beforeLLM = await this.hookManager.executeHooks("before:llm", {
@@ -22846,6 +23654,7 @@ var Agent = class _Agent extends BaseAgent {
22846
23654
  tools: this.getEnabledToolDefinitions(),
22847
23655
  tool_choice: "auto",
22848
23656
  temperature: this._config.temperature,
23657
+ thinking: this._config.thinking,
22849
23658
  vendorOptions: this._config.vendorOptions
22850
23659
  };
22851
23660
  await this.hookManager.executeHooks("before:llm", {
@@ -22863,7 +23672,9 @@ var Agent = class _Agent extends BaseAgent {
22863
23672
  });
22864
23673
  try {
22865
23674
  for await (const event of this._provider.streamGenerate(generateOptions)) {
22866
- if (event.type === "response.output_text.delta" /* OUTPUT_TEXT_DELTA */) {
23675
+ if (isReasoningDelta(event)) {
23676
+ streamState.accumulateReasoningDelta(event.item_id, event.delta);
23677
+ } else if (event.type === "response.output_text.delta" /* OUTPUT_TEXT_DELTA */) {
22867
23678
  streamState.accumulateTextDelta(event.item_id, event.delta);
22868
23679
  } else if (event.type === "response.tool_call.start" /* TOOL_CALL_START */) {
22869
23680
  streamState.startToolCall(event.tool_call_id, event.tool_name);
@@ -23393,6 +24204,7 @@ function createTask(input) {
23393
24204
  suggestedTools: input.suggestedTools,
23394
24205
  validation: input.validation,
23395
24206
  expectedOutput: input.expectedOutput,
24207
+ controlFlow: input.controlFlow,
23396
24208
  attempts: 0,
23397
24209
  maxAttempts: input.maxAttempts ?? 3,
23398
24210
  createdAt: now,
@@ -23645,6 +24457,7 @@ function createRoutineDefinition(input) {
23645
24457
  instructions: input.instructions,
23646
24458
  concurrency: input.concurrency,
23647
24459
  allowDynamicTasks: input.allowDynamicTasks ?? false,
24460
+ parameters: input.parameters,
23648
24461
  tags: input.tags,
23649
24462
  author: input.author,
23650
24463
  createdAt: now,
@@ -23860,6 +24673,321 @@ function extractNumber(text, patterns = [
23860
24673
 
23861
24674
  // src/core/routineRunner.ts
23862
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
23863
24991
  function defaultSystemPrompt(definition) {
23864
24992
  const parts = [];
23865
24993
  if (definition.instructions) {
@@ -23988,6 +25116,14 @@ async function collectValidationContext(agent, responseText) {
23988
25116
  toolCallLog
23989
25117
  };
23990
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
+ }
23991
25127
  function estimateTokens(text) {
23992
25128
  return Math.ceil(text.length / 4);
23993
25129
  }
@@ -24031,32 +25167,42 @@ function buildPlanOverview(execution, definition, currentTaskId) {
24031
25167
  }
24032
25168
  return parts.join("\n");
24033
25169
  }
24034
- async function injectRoutineContext(agent, execution, definition, currentTask) {
24035
- const icmPlugin = agent.context.getPlugin("in_context_memory");
24036
- const wmPlugin = agent.context.memory;
24037
- if (!icmPlugin && !wmPlugin) {
24038
- logger.warn("injectRoutineContext: No ICM or WM plugin available \u2014 skipping context injection");
24039
- return;
24040
- }
24041
- const planOverview = buildPlanOverview(execution, definition, currentTask.id);
24042
- if (icmPlugin) {
24043
- icmPlugin.set("__routine_plan", "Routine plan overview with task statuses", planOverview, "high");
24044
- }
25170
+ async function cleanupMemoryKeys(icmPlugin, wmPlugin, config) {
24045
25171
  if (icmPlugin) {
24046
25172
  for (const entry of icmPlugin.list()) {
24047
- if (entry.key.startsWith("__dep_result_") || entry.key === "__routine_deps") {
24048
- icmPlugin.delete(entry.key);
24049
- }
25173
+ const shouldDelete = config.icmPrefixes.some((p) => entry.key.startsWith(p)) || (config.icmExactKeys?.includes(entry.key) ?? false);
25174
+ if (shouldDelete) icmPlugin.delete(entry.key);
24050
25175
  }
24051
25176
  }
24052
25177
  if (wmPlugin) {
24053
25178
  const { entries: wmEntries } = await wmPlugin.query();
24054
25179
  for (const entry of wmEntries) {
24055
- if (entry.key.startsWith("__dep_result_") || entry.key.startsWith("findings/__dep_result_")) {
25180
+ if (config.wmPrefixes.some((p) => entry.key.startsWith(p))) {
24056
25181
  await wmPlugin.delete(entry.key);
24057
25182
  }
24058
25183
  }
24059
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);
24060
25206
  if (currentTask.dependsOn.length === 0) return;
24061
25207
  const inContextDeps = [];
24062
25208
  const workingMemoryDeps = [];
@@ -24065,7 +25211,7 @@ async function injectRoutineContext(agent, execution, definition, currentTask) {
24065
25211
  if (!depTask?.result?.output) continue;
24066
25212
  const output = typeof depTask.result.output === "string" ? depTask.result.output : JSON.stringify(depTask.result.output);
24067
25213
  const tokens = estimateTokens(output);
24068
- const depKey = `__dep_result_${depId}`;
25214
+ const depKey = `${ROUTINE_KEYS.DEP_RESULT_PREFIX}${depId}`;
24069
25215
  const depLabel = `Result from task "${depTask.name}"`;
24070
25216
  if (tokens < 5e3 && icmPlugin) {
24071
25217
  icmPlugin.set(depKey, depLabel, output, "high");
@@ -24087,27 +25233,12 @@ async function injectRoutineContext(agent, execution, definition, currentTask) {
24087
25233
  if (workingMemoryDeps.length > 0) {
24088
25234
  summaryParts.push(`In working memory (use memory_retrieve): ${workingMemoryDeps.join(", ")}`);
24089
25235
  }
24090
- 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");
24091
25237
  }
24092
25238
  }
24093
25239
  async function cleanupRoutineContext(agent) {
24094
- const icmPlugin = agent.context.getPlugin("in_context_memory");
24095
- const wmPlugin = agent.context.memory;
24096
- if (icmPlugin) {
24097
- for (const entry of icmPlugin.list()) {
24098
- if (entry.key.startsWith("__routine_") || entry.key.startsWith("__dep_result_")) {
24099
- icmPlugin.delete(entry.key);
24100
- }
24101
- }
24102
- }
24103
- if (wmPlugin) {
24104
- const { entries: wmEntries } = await wmPlugin.query();
24105
- for (const entry of wmEntries) {
24106
- if (entry.key.startsWith("__dep_result_") || entry.key.startsWith("findings/__dep_result_")) {
24107
- await wmPlugin.delete(entry.key);
24108
- }
24109
- }
24110
- }
25240
+ const { icmPlugin, wmPlugin } = getPlugins(agent);
25241
+ await cleanupMemoryKeys(icmPlugin, wmPlugin, FULL_CLEANUP_CONFIG);
24111
25242
  }
24112
25243
  async function validateTaskCompletion(agent, task, responseText, validationPromptBuilder) {
24113
25244
  const hasExplicitValidation = task.validation?.skipReflection === false && task.validation?.completionCriteria && task.validation.completionCriteria.length > 0;
@@ -24156,11 +25287,13 @@ async function executeRoutine(options) {
24156
25287
  onTaskFailed,
24157
25288
  onTaskValidation,
24158
25289
  hooks,
24159
- prompts
25290
+ prompts,
25291
+ inputs: rawInputs
24160
25292
  } = options;
24161
25293
  if (!existingAgent && (!connector || !model)) {
24162
25294
  throw new Error("executeRoutine requires either `agent` or both `connector` and `model`");
24163
25295
  }
25296
+ const resolvedInputs = validateAndResolveInputs(definition.parameters, rawInputs);
24164
25297
  const ownsAgent = !existingAgent;
24165
25298
  const log = logger.child({ routine: definition.name });
24166
25299
  const execution = createRoutineExecution(definition);
@@ -24245,7 +25378,7 @@ async function executeRoutine(options) {
24245
25378
  execution.lastUpdatedAt = Date.now();
24246
25379
  onTaskStarted?.(execution.plan.tasks[taskIndex], execution);
24247
25380
  let taskCompleted = false;
24248
- const maxTaskIterations = task.execution?.maxIterations ?? 15;
25381
+ const maxTaskIterations = task.execution?.maxIterations ?? 50;
24249
25382
  const iterationLimiter = async (ctx) => {
24250
25383
  if (ctx.iteration >= maxTaskIterations) {
24251
25384
  agent.cancel(`Task "${task.name}" exceeded max iterations (${maxTaskIterations})`);
@@ -24253,85 +25386,115 @@ async function executeRoutine(options) {
24253
25386
  return { shouldPause: false };
24254
25387
  };
24255
25388
  agent.registerHook("pause:check", iterationLimiter);
24256
- const getTask = () => execution.plan.tasks[taskIndex];
24257
- await injectRoutineContext(agent, execution, definition, getTask());
24258
- while (!taskCompleted) {
24259
- try {
24260
- const taskPrompt = buildTaskPrompt(getTask());
24261
- const response = await agent.run(taskPrompt);
24262
- const responseText = response.output_text ?? "";
24263
- const validationResult = await validateTaskCompletion(
24264
- agent,
24265
- getTask(),
24266
- responseText,
24267
- buildValidationPrompt
24268
- );
24269
- onTaskValidation?.(getTask(), validationResult, execution);
24270
- if (validationResult.isComplete) {
24271
- execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "completed");
24272
- execution.plan.tasks[taskIndex].result = {
24273
- success: true,
24274
- output: responseText,
24275
- validationScore: validationResult.completionScore,
24276
- validationExplanation: validationResult.explanation
24277
- };
24278
- taskCompleted = true;
24279
- log.info(
24280
- { taskName: getTask().name, score: validationResult.completionScore },
24281
- "Task completed"
24282
- );
24283
- execution.progress = getRoutineProgress(execution);
24284
- execution.lastUpdatedAt = Date.now();
24285
- onTaskComplete?.(execution.plan.tasks[taskIndex], execution);
24286
- } else {
24287
- log.warn(
24288
- {
24289
- taskName: getTask().name,
24290
- score: validationResult.completionScore,
24291
- attempt: getTask().attempts,
24292
- maxAttempts: getTask().maxAttempts
24293
- },
24294
- "Task validation failed"
24295
- );
24296
- 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 {
24297
25404
  execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
24298
- execution.plan.tasks[taskIndex].result = {
24299
- success: false,
24300
- error: validationResult.explanation,
24301
- validationScore: validationResult.completionScore,
24302
- validationExplanation: validationResult.explanation
24303
- };
24304
- break;
25405
+ execution.plan.tasks[taskIndex].result = { success: false, error: cfResult.error };
24305
25406
  }
24306
- execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
24307
- }
24308
- } catch (error) {
24309
- const errorMessage = error.message;
24310
- log.error({ taskName: getTask().name, error: errorMessage }, "Task execution error");
24311
- if (getTask().attempts >= getTask().maxAttempts) {
25407
+ } catch (error) {
25408
+ const errorMessage = error.message;
25409
+ log.error({ taskName: getTask().name, error: errorMessage }, "Control flow error");
24312
25410
  execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "failed");
24313
- execution.plan.tasks[taskIndex].result = {
24314
- success: false,
24315
- error: errorMessage
24316
- };
24317
- 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
+ }
24318
25478
  }
24319
- execution.plan.tasks[taskIndex] = updateTaskStatus(getTask(), "in_progress");
24320
25479
  }
24321
- }
24322
- if (!taskCompleted) {
24323
- execution.progress = getRoutineProgress(execution);
24324
- execution.lastUpdatedAt = Date.now();
24325
- onTaskFailed?.(execution.plan.tasks[taskIndex], execution);
24326
- if (failureMode === "fail-fast") {
24327
- execution.status = "failed";
24328
- execution.error = `Task "${getTask().name}" failed after ${getTask().attempts} attempt(s)`;
24329
- execution.completedAt = Date.now();
25480
+ if (!taskCompleted) {
25481
+ execution.progress = getRoutineProgress(execution);
24330
25482
  execution.lastUpdatedAt = Date.now();
24331
- 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 {
24332
25496
  }
24333
25497
  }
24334
- agent.unregisterHook("pause:check", iterationLimiter);
24335
25498
  agent.clearConversation("task-boundary");
24336
25499
  nextTasks = getNextExecutableTasks(execution.plan);
24337
25500
  }
@@ -24359,16 +25522,22 @@ async function executeRoutine(options) {
24359
25522
  } finally {
24360
25523
  try {
24361
25524
  await cleanupRoutineContext(agent);
24362
- } catch {
25525
+ } catch (e) {
25526
+ log.debug({ error: e.message }, "Failed to clean up routine context");
24363
25527
  }
24364
25528
  for (const { name, hook } of registeredHooks) {
24365
25529
  try {
24366
25530
  agent.unregisterHook(name, hook);
24367
- } catch {
25531
+ } catch (e) {
25532
+ log.debug({ hookName: name, error: e.message }, "Failed to unregister hook");
24368
25533
  }
24369
25534
  }
24370
25535
  if (ownsAgent) {
24371
- agent.destroy();
25536
+ try {
25537
+ agent.destroy();
25538
+ } catch (e) {
25539
+ log.debug({ error: e.message }, "Failed to destroy agent");
25540
+ }
24372
25541
  }
24373
25542
  }
24374
25543
  }
@@ -31175,7 +32344,7 @@ var TextToSpeech = class _TextToSpeech {
31175
32344
  */
31176
32345
  async toFile(text, filePath, options) {
31177
32346
  const response = await this.synthesize(text, options);
31178
- await fs18.writeFile(filePath, response.audio);
32347
+ await fs17.writeFile(filePath, response.audio);
31179
32348
  }
31180
32349
  // ======================== Introspection Methods ========================
31181
32350
  /**
@@ -31523,7 +32692,7 @@ var SpeechToText = class _SpeechToText {
31523
32692
  * @param options - Optional transcription parameters
31524
32693
  */
31525
32694
  async transcribeFile(filePath, options) {
31526
- const audio = await fs18.readFile(filePath);
32695
+ const audio = await fs17.readFile(filePath);
31527
32696
  return this.transcribe(audio, options);
31528
32697
  }
31529
32698
  /**
@@ -38266,10 +39435,10 @@ var FileMediaStorage = class {
38266
39435
  }
38267
39436
  async save(data, metadata) {
38268
39437
  const dir = metadata.userId ? path2.join(this.outputDir, metadata.userId) : this.outputDir;
38269
- await fs18.mkdir(dir, { recursive: true });
39438
+ await fs17.mkdir(dir, { recursive: true });
38270
39439
  const filename = metadata.suggestedFilename ?? this.generateFilename(metadata);
38271
39440
  const filePath = path2.join(dir, filename);
38272
- await fs18.writeFile(filePath, data);
39441
+ await fs17.writeFile(filePath, data);
38273
39442
  const format = metadata.format.toLowerCase();
38274
39443
  const mimeType = MIME_TYPES2[format] ?? "application/octet-stream";
38275
39444
  return {
@@ -38280,7 +39449,7 @@ var FileMediaStorage = class {
38280
39449
  }
38281
39450
  async read(location) {
38282
39451
  try {
38283
- return await fs18.readFile(location);
39452
+ return await fs17.readFile(location);
38284
39453
  } catch (err) {
38285
39454
  if (err.code === "ENOENT") {
38286
39455
  return null;
@@ -38290,7 +39459,7 @@ var FileMediaStorage = class {
38290
39459
  }
38291
39460
  async delete(location) {
38292
39461
  try {
38293
- await fs18.unlink(location);
39462
+ await fs17.unlink(location);
38294
39463
  } catch (err) {
38295
39464
  if (err.code === "ENOENT") {
38296
39465
  return;
@@ -38300,7 +39469,7 @@ var FileMediaStorage = class {
38300
39469
  }
38301
39470
  async exists(location) {
38302
39471
  try {
38303
- await fs18.access(location);
39472
+ await fs17.access(location);
38304
39473
  return true;
38305
39474
  } catch {
38306
39475
  return false;
@@ -38309,11 +39478,11 @@ var FileMediaStorage = class {
38309
39478
  async list(options) {
38310
39479
  await this.ensureDir();
38311
39480
  let entries = [];
38312
- const files = await fs18.readdir(this.outputDir);
39481
+ const files = await fs17.readdir(this.outputDir);
38313
39482
  for (const file of files) {
38314
39483
  const filePath = path2.join(this.outputDir, file);
38315
39484
  try {
38316
- const stat6 = await fs18.stat(filePath);
39485
+ const stat6 = await fs17.stat(filePath);
38317
39486
  if (!stat6.isFile()) continue;
38318
39487
  const ext = path2.extname(file).slice(1).toLowerCase();
38319
39488
  const mimeType = MIME_TYPES2[ext] ?? "application/octet-stream";
@@ -38353,7 +39522,7 @@ var FileMediaStorage = class {
38353
39522
  }
38354
39523
  async ensureDir() {
38355
39524
  if (!this.initialized) {
38356
- await fs18.mkdir(this.outputDir, { recursive: true });
39525
+ await fs17.mkdir(this.outputDir, { recursive: true });
38357
39526
  this.initialized = true;
38358
39527
  }
38359
39528
  }
@@ -38888,6 +40057,42 @@ var StreamHelpers = class {
38888
40057
  }
38889
40058
  return chunks.join("");
38890
40059
  }
40060
+ /**
40061
+ * Get only reasoning/thinking deltas from stream
40062
+ * Filters out all other event types
40063
+ */
40064
+ static async *thinkingOnly(stream) {
40065
+ for await (const event of stream) {
40066
+ if (isReasoningDelta(event)) {
40067
+ yield event.delta;
40068
+ }
40069
+ }
40070
+ }
40071
+ /**
40072
+ * Get both text and thinking deltas from stream
40073
+ * Yields tagged objects so consumers can distinguish them
40074
+ */
40075
+ static async *textAndThinking(stream) {
40076
+ for await (const event of stream) {
40077
+ if (isOutputTextDelta(event)) {
40078
+ yield { type: "text", delta: event.delta };
40079
+ } else if (isReasoningDelta(event)) {
40080
+ yield { type: "thinking", delta: event.delta };
40081
+ }
40082
+ }
40083
+ }
40084
+ /**
40085
+ * Accumulate all thinking/reasoning content from stream into a single string
40086
+ */
40087
+ static async accumulateThinking(stream) {
40088
+ const chunks = [];
40089
+ for await (const event of stream) {
40090
+ if (isReasoningDelta(event)) {
40091
+ chunks.push(event.delta);
40092
+ }
40093
+ }
40094
+ return chunks.join("");
40095
+ }
38891
40096
  /**
38892
40097
  * Buffer stream events into batches
38893
40098
  */
@@ -38947,6 +40152,11 @@ var StreamHelpers = class {
38947
40152
  case "response.output_text.delta" /* OUTPUT_TEXT_DELTA */:
38948
40153
  state.accumulateTextDelta(event.item_id, event.delta);
38949
40154
  break;
40155
+ case "response.reasoning.delta" /* REASONING_DELTA */:
40156
+ state.accumulateReasoningDelta(event.item_id, event.delta);
40157
+ break;
40158
+ case "response.reasoning.done" /* REASONING_DONE */:
40159
+ break;
38950
40160
  case "response.tool_call.start" /* TOOL_CALL_START */:
38951
40161
  state.startToolCall(event.tool_call_id, event.tool_name);
38952
40162
  break;
@@ -38977,21 +40187,36 @@ var StreamHelpers = class {
38977
40187
  */
38978
40188
  static reconstructLLMResponse(state) {
38979
40189
  const output = [];
40190
+ const contentParts = [];
40191
+ let thinkingText;
40192
+ if (state.hasReasoning()) {
40193
+ const reasoning = state.getAllReasoning();
40194
+ if (reasoning) {
40195
+ thinkingText = reasoning;
40196
+ contentParts.push({
40197
+ type: "thinking" /* THINKING */,
40198
+ thinking: reasoning,
40199
+ persistInHistory: false
40200
+ // Vendor-agnostic default; caller can adjust
40201
+ });
40202
+ }
40203
+ }
38980
40204
  if (state.hasText()) {
38981
40205
  const textContent = state.getAllText();
38982
40206
  if (textContent) {
38983
- output.push({
38984
- type: "message",
38985
- role: "assistant" /* ASSISTANT */,
38986
- content: [
38987
- {
38988
- type: "output_text" /* OUTPUT_TEXT */,
38989
- text: textContent
38990
- }
38991
- ]
40207
+ contentParts.push({
40208
+ type: "output_text" /* OUTPUT_TEXT */,
40209
+ text: textContent
38992
40210
  });
38993
40211
  }
38994
40212
  }
40213
+ if (contentParts.length > 0) {
40214
+ output.push({
40215
+ type: "message",
40216
+ role: "assistant" /* ASSISTANT */,
40217
+ content: contentParts
40218
+ });
40219
+ }
38995
40220
  const toolCalls = state.getCompletedToolCalls();
38996
40221
  if (toolCalls.length > 0) {
38997
40222
  const toolUseContent = toolCalls.map((tc) => ({
@@ -39020,6 +40245,7 @@ var StreamHelpers = class {
39020
40245
  model: state.model,
39021
40246
  output,
39022
40247
  output_text: outputText,
40248
+ thinking: thinkingText,
39023
40249
  usage: state.usage
39024
40250
  };
39025
40251
  }
@@ -39148,6 +40374,15 @@ var SERVICE_DEFINITIONS = [
39148
40374
  baseURL: "https://api.telegram.org",
39149
40375
  docsURL: "https://core.telegram.org/bots/api"
39150
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
+ },
39151
40386
  // ============ Development & Project Management ============
39152
40387
  {
39153
40388
  id: "github",
@@ -39635,19 +40870,30 @@ var ConnectorTools = class {
39635
40870
  */
39636
40871
  static for(connectorOrName, userId, options) {
39637
40872
  const connector = this.resolveConnector(connectorOrName, options?.registry);
40873
+ const accountId = options?.accountId;
39638
40874
  const tools = [];
40875
+ const namePrefix = accountId ? `${sanitizeToolName(connector.name)}_${sanitizeToolName(accountId)}` : sanitizeToolName(connector.name);
39639
40876
  if (connector.baseURL) {
39640
- 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
+ }));
39641
40884
  }
39642
40885
  const serviceType = this.detectService(connector);
39643
40886
  if (serviceType && this.factories.has(serviceType)) {
39644
40887
  const factory = this.factories.get(serviceType);
39645
40888
  const serviceTools = factory(connector, userId);
39646
40889
  for (const tool of serviceTools) {
39647
- tool.definition.function.name = `${sanitizeToolName(connector.name)}_${tool.definition.function.name}`;
40890
+ tool.definition.function.name = `${namePrefix}_${tool.definition.function.name}`;
39648
40891
  }
39649
40892
  tools.push(...serviceTools);
39650
40893
  }
40894
+ if (accountId) {
40895
+ return tools.map((tool) => this.bindAccountId(tool, accountId));
40896
+ }
39651
40897
  return tools;
39652
40898
  }
39653
40899
  /**
@@ -39797,6 +41043,56 @@ var ConnectorTools = class {
39797
41043
  }
39798
41044
  return connectorOrName;
39799
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
+ }
39800
41096
  static createGenericAPITool(connector, options) {
39801
41097
  const toolName = options?.toolName ?? `${sanitizeToolName(connector.name)}_api`;
39802
41098
  const userId = options?.userId;
@@ -39838,6 +41134,7 @@ var ConnectorTools = class {
39838
41134
  },
39839
41135
  execute: async (args, context) => {
39840
41136
  const effectiveUserId = context?.userId ?? userId;
41137
+ const effectiveAccountId = context?.accountId;
39841
41138
  let url2 = args.endpoint;
39842
41139
  if (args.queryParams && Object.keys(args.queryParams).length > 0) {
39843
41140
  const params = new URLSearchParams();
@@ -39870,7 +41167,8 @@ var ConnectorTools = class {
39870
41167
  },
39871
41168
  body: bodyStr
39872
41169
  },
39873
- effectiveUserId
41170
+ effectiveUserId,
41171
+ effectiveAccountId
39874
41172
  );
39875
41173
  const text = await response.text();
39876
41174
  let data;
@@ -39931,8 +41229,8 @@ var FileStorage = class {
39931
41229
  }
39932
41230
  async ensureDirectory() {
39933
41231
  try {
39934
- await fs18.mkdir(this.directory, { recursive: true });
39935
- await fs18.chmod(this.directory, 448);
41232
+ await fs17.mkdir(this.directory, { recursive: true });
41233
+ await fs17.chmod(this.directory, 448);
39936
41234
  } catch (error) {
39937
41235
  }
39938
41236
  }
@@ -39946,24 +41244,27 @@ var FileStorage = class {
39946
41244
  async storeToken(key, token) {
39947
41245
  await this.ensureDirectory();
39948
41246
  const filePath = this.getFilePath(key);
39949
- const plaintext = JSON.stringify(token);
41247
+ const tokenWithKey = { ...token, _storageKey: key };
41248
+ const plaintext = JSON.stringify(tokenWithKey);
39950
41249
  const encrypted = encrypt(plaintext, this.encryptionKey);
39951
- await fs18.writeFile(filePath, encrypted, "utf8");
39952
- await fs18.chmod(filePath, 384);
41250
+ await fs17.writeFile(filePath, encrypted, "utf8");
41251
+ await fs17.chmod(filePath, 384);
39953
41252
  }
39954
41253
  async getToken(key) {
39955
41254
  const filePath = this.getFilePath(key);
39956
41255
  try {
39957
- const encrypted = await fs18.readFile(filePath, "utf8");
41256
+ const encrypted = await fs17.readFile(filePath, "utf8");
39958
41257
  const decrypted = decrypt(encrypted, this.encryptionKey);
39959
- return JSON.parse(decrypted);
41258
+ const parsed = JSON.parse(decrypted);
41259
+ const { _storageKey, ...token } = parsed;
41260
+ return token;
39960
41261
  } catch (error) {
39961
41262
  if (error.code === "ENOENT") {
39962
41263
  return null;
39963
41264
  }
39964
41265
  console.error("Failed to read/decrypt token file:", error);
39965
41266
  try {
39966
- await fs18.unlink(filePath);
41267
+ await fs17.unlink(filePath);
39967
41268
  } catch {
39968
41269
  }
39969
41270
  return null;
@@ -39972,7 +41273,7 @@ var FileStorage = class {
39972
41273
  async deleteToken(key) {
39973
41274
  const filePath = this.getFilePath(key);
39974
41275
  try {
39975
- await fs18.unlink(filePath);
41276
+ await fs17.unlink(filePath);
39976
41277
  } catch (error) {
39977
41278
  if (error.code !== "ENOENT") {
39978
41279
  throw error;
@@ -39982,18 +41283,44 @@ var FileStorage = class {
39982
41283
  async hasToken(key) {
39983
41284
  const filePath = this.getFilePath(key);
39984
41285
  try {
39985
- await fs18.access(filePath);
41286
+ await fs17.access(filePath);
39986
41287
  return true;
39987
41288
  } catch {
39988
41289
  return false;
39989
41290
  }
39990
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
+ }
39991
41318
  /**
39992
41319
  * List all token keys (for debugging)
39993
41320
  */
39994
41321
  async listTokens() {
39995
41322
  try {
39996
- const files = await fs18.readdir(this.directory);
41323
+ const files = await fs17.readdir(this.directory);
39997
41324
  return files.filter((f) => f.endsWith(".token")).map((f) => f.replace(".token", ""));
39998
41325
  } catch {
39999
41326
  return [];
@@ -40004,10 +41331,10 @@ var FileStorage = class {
40004
41331
  */
40005
41332
  async clearAll() {
40006
41333
  try {
40007
- const files = await fs18.readdir(this.directory);
41334
+ const files = await fs17.readdir(this.directory);
40008
41335
  const tokenFiles = files.filter((f) => f.endsWith(".token"));
40009
41336
  await Promise.all(
40010
- tokenFiles.map((f) => fs18.unlink(path2.join(this.directory, f)).catch(() => {
41337
+ tokenFiles.map((f) => fs17.unlink(path2.join(this.directory, f)).catch(() => {
40011
41338
  }))
40012
41339
  );
40013
41340
  } catch {
@@ -40017,14 +41344,14 @@ var FileStorage = class {
40017
41344
 
40018
41345
  // src/connectors/authenticatedFetch.ts
40019
41346
  init_Connector();
40020
- async function authenticatedFetch(url2, options, authProvider, userId) {
41347
+ async function authenticatedFetch(url2, options, authProvider, userId, accountId) {
40021
41348
  const connector = Connector.get(authProvider);
40022
- return connector.fetch(url2.toString(), options, userId);
41349
+ return connector.fetch(url2.toString(), options, userId, accountId);
40023
41350
  }
40024
- function createAuthenticatedFetch(authProvider, userId) {
41351
+ function createAuthenticatedFetch(authProvider, userId, accountId) {
40025
41352
  const connector = Connector.get(authProvider);
40026
41353
  return async (url2, options) => {
40027
- return connector.fetch(url2.toString(), options, userId);
41354
+ return connector.fetch(url2.toString(), options, userId, accountId);
40028
41355
  };
40029
41356
  }
40030
41357
 
@@ -40455,14 +41782,14 @@ var FileConnectorStorage = class {
40455
41782
  await this.ensureDirectory();
40456
41783
  const filePath = this.getFilePath(name);
40457
41784
  const json = JSON.stringify(stored, null, 2);
40458
- await fs18.writeFile(filePath, json, "utf8");
40459
- await fs18.chmod(filePath, 384);
41785
+ await fs17.writeFile(filePath, json, "utf8");
41786
+ await fs17.chmod(filePath, 384);
40460
41787
  await this.updateIndex(name, "add");
40461
41788
  }
40462
41789
  async get(name) {
40463
41790
  const filePath = this.getFilePath(name);
40464
41791
  try {
40465
- const json = await fs18.readFile(filePath, "utf8");
41792
+ const json = await fs17.readFile(filePath, "utf8");
40466
41793
  return JSON.parse(json);
40467
41794
  } catch (error) {
40468
41795
  const err = error;
@@ -40475,7 +41802,7 @@ var FileConnectorStorage = class {
40475
41802
  async delete(name) {
40476
41803
  const filePath = this.getFilePath(name);
40477
41804
  try {
40478
- await fs18.unlink(filePath);
41805
+ await fs17.unlink(filePath);
40479
41806
  await this.updateIndex(name, "remove");
40480
41807
  return true;
40481
41808
  } catch (error) {
@@ -40489,7 +41816,7 @@ var FileConnectorStorage = class {
40489
41816
  async has(name) {
40490
41817
  const filePath = this.getFilePath(name);
40491
41818
  try {
40492
- await fs18.access(filePath);
41819
+ await fs17.access(filePath);
40493
41820
  return true;
40494
41821
  } catch {
40495
41822
  return false;
@@ -40515,13 +41842,13 @@ var FileConnectorStorage = class {
40515
41842
  */
40516
41843
  async clear() {
40517
41844
  try {
40518
- const files = await fs18.readdir(this.directory);
41845
+ const files = await fs17.readdir(this.directory);
40519
41846
  const connectorFiles = files.filter(
40520
41847
  (f) => f.endsWith(".connector.json") || f === "_index.json"
40521
41848
  );
40522
41849
  await Promise.all(
40523
41850
  connectorFiles.map(
40524
- (f) => fs18.unlink(path2.join(this.directory, f)).catch(() => {
41851
+ (f) => fs17.unlink(path2.join(this.directory, f)).catch(() => {
40525
41852
  })
40526
41853
  )
40527
41854
  );
@@ -40548,8 +41875,8 @@ var FileConnectorStorage = class {
40548
41875
  async ensureDirectory() {
40549
41876
  if (this.initialized) return;
40550
41877
  try {
40551
- await fs18.mkdir(this.directory, { recursive: true });
40552
- await fs18.chmod(this.directory, 448);
41878
+ await fs17.mkdir(this.directory, { recursive: true });
41879
+ await fs17.chmod(this.directory, 448);
40553
41880
  this.initialized = true;
40554
41881
  } catch {
40555
41882
  this.initialized = true;
@@ -40560,7 +41887,7 @@ var FileConnectorStorage = class {
40560
41887
  */
40561
41888
  async loadIndex() {
40562
41889
  try {
40563
- const json = await fs18.readFile(this.indexPath, "utf8");
41890
+ const json = await fs17.readFile(this.indexPath, "utf8");
40564
41891
  return JSON.parse(json);
40565
41892
  } catch {
40566
41893
  return { connectors: {} };
@@ -40578,8 +41905,8 @@ var FileConnectorStorage = class {
40578
41905
  delete index.connectors[hash];
40579
41906
  }
40580
41907
  const json = JSON.stringify(index, null, 2);
40581
- await fs18.writeFile(this.indexPath, json, "utf8");
40582
- await fs18.chmod(this.indexPath, 384);
41908
+ await fs17.writeFile(this.indexPath, json, "utf8");
41909
+ await fs17.chmod(this.indexPath, 384);
40583
41910
  }
40584
41911
  };
40585
41912
 
@@ -40802,14 +42129,15 @@ var microsoftTemplate = {
40802
42129
  name: "OAuth (Delegated Permissions)",
40803
42130
  type: "oauth",
40804
42131
  flow: "authorization_code",
40805
- description: "User signs in with Microsoft account. Best for accessing user data (mail, calendar, files)",
40806
- requiredFields: ["clientId", "clientSecret", "redirectUri", "tenantId"],
40807
- 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"],
40808
42135
  defaults: {
40809
42136
  type: "oauth",
40810
42137
  flow: "authorization_code",
40811
42138
  authorizationUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize",
40812
- tokenUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token"
42139
+ tokenUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token",
42140
+ usePKCE: true
40813
42141
  },
40814
42142
  scopes: [
40815
42143
  "User.Read",
@@ -40895,14 +42223,15 @@ var googleTemplate = {
40895
42223
  name: "OAuth (User Consent)",
40896
42224
  type: "oauth",
40897
42225
  flow: "authorization_code",
40898
- description: "User logs in with Google account. Best for accessing user data (Drive, Gmail, Calendar)",
40899
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
40900
- 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"],
40901
42229
  defaults: {
40902
42230
  type: "oauth",
40903
42231
  flow: "authorization_code",
40904
42232
  authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",
40905
- tokenUrl: "https://oauth2.googleapis.com/token"
42233
+ tokenUrl: "https://oauth2.googleapis.com/token",
42234
+ usePKCE: true
40906
42235
  },
40907
42236
  scopes: [
40908
42237
  "https://www.googleapis.com/auth/drive",
@@ -40981,14 +42310,15 @@ var slackTemplate = {
40981
42310
  name: "OAuth (User Token)",
40982
42311
  type: "oauth",
40983
42312
  flow: "authorization_code",
40984
- description: "Distributed app - users authorize via Slack OAuth",
40985
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
40986
- 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"],
40987
42316
  defaults: {
40988
42317
  type: "oauth",
40989
42318
  flow: "authorization_code",
40990
42319
  authorizationUrl: "https://slack.com/oauth/v2/authorize",
40991
- tokenUrl: "https://slack.com/api/oauth.v2.access"
42320
+ tokenUrl: "https://slack.com/api/oauth.v2.access",
42321
+ usePKCE: true
40992
42322
  },
40993
42323
  scopes: ["chat:write", "channels:read", "users:read", "im:write", "groups:read", "files:read", "files:write", "reactions:read", "reactions:write", "team:read"],
40994
42324
  scopeDescriptions: {
@@ -41034,14 +42364,15 @@ var discordTemplate = {
41034
42364
  name: "OAuth (User Token)",
41035
42365
  type: "oauth",
41036
42366
  flow: "authorization_code",
41037
- description: "OAuth2 for user authorization - users grant permissions to your app",
41038
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41039
- 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"],
41040
42370
  defaults: {
41041
42371
  type: "oauth",
41042
42372
  flow: "authorization_code",
41043
42373
  authorizationUrl: "https://discord.com/api/oauth2/authorize",
41044
- tokenUrl: "https://discord.com/api/oauth2/token"
42374
+ tokenUrl: "https://discord.com/api/oauth2/token",
42375
+ usePKCE: true
41045
42376
  },
41046
42377
  scopes: ["identify", "email", "guilds", "guilds.members.read", "messages.read", "bot", "connections"],
41047
42378
  scopeDescriptions: {
@@ -41083,6 +42414,92 @@ var telegramTemplate = {
41083
42414
  ]
41084
42415
  };
41085
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
+
41086
42503
  // src/connectors/vendors/templates/github.ts
41087
42504
  var githubTemplate = {
41088
42505
  id: "github",
@@ -41110,14 +42527,15 @@ var githubTemplate = {
41110
42527
  name: "OAuth App (User Authorization)",
41111
42528
  type: "oauth",
41112
42529
  flow: "authorization_code",
41113
- description: "User logs in via GitHub and grants permissions to your app",
41114
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41115
- 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"],
41116
42533
  defaults: {
41117
42534
  type: "oauth",
41118
42535
  flow: "authorization_code",
41119
42536
  authorizationUrl: "https://github.com/login/oauth/authorize",
41120
- tokenUrl: "https://github.com/login/oauth/access_token"
42537
+ tokenUrl: "https://github.com/login/oauth/access_token",
42538
+ usePKCE: true
41121
42539
  },
41122
42540
  scopes: ["repo", "read:user", "user:email", "read:org", "workflow", "gist", "notifications", "delete_repo", "admin:org"],
41123
42541
  scopeDescriptions: {
@@ -41176,14 +42594,15 @@ var gitlabTemplate = {
41176
42594
  name: "OAuth (User Authorization)",
41177
42595
  type: "oauth",
41178
42596
  flow: "authorization_code",
41179
- description: "OAuth2 application for user authorization",
41180
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41181
- 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"],
41182
42600
  defaults: {
41183
42601
  type: "oauth",
41184
42602
  flow: "authorization_code",
41185
42603
  authorizationUrl: "https://gitlab.com/oauth/authorize",
41186
- tokenUrl: "https://gitlab.com/oauth/token"
42604
+ tokenUrl: "https://gitlab.com/oauth/token",
42605
+ usePKCE: true
41187
42606
  },
41188
42607
  scopes: ["api", "read_user", "read_repository", "write_repository"],
41189
42608
  scopeDescriptions: {
@@ -41224,14 +42643,15 @@ var jiraTemplate = {
41224
42643
  name: "OAuth 2.0 (3LO)",
41225
42644
  type: "oauth",
41226
42645
  flow: "authorization_code",
41227
- description: "Three-legged OAuth for user authorization. Create app at developer.atlassian.com",
41228
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41229
- 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"],
41230
42649
  defaults: {
41231
42650
  type: "oauth",
41232
42651
  flow: "authorization_code",
41233
42652
  authorizationUrl: "https://auth.atlassian.com/authorize",
41234
- tokenUrl: "https://auth.atlassian.com/oauth/token"
42653
+ tokenUrl: "https://auth.atlassian.com/oauth/token",
42654
+ usePKCE: true
41235
42655
  },
41236
42656
  scopes: ["read:jira-work", "write:jira-work", "read:jira-user", "manage:jira-project", "manage:jira-configuration"],
41237
42657
  scopeDescriptions: {
@@ -41271,14 +42691,15 @@ var confluenceTemplate = {
41271
42691
  name: "OAuth 2.0 (3LO)",
41272
42692
  type: "oauth",
41273
42693
  flow: "authorization_code",
41274
- description: "Three-legged OAuth for user authorization",
41275
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41276
- 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"],
41277
42697
  defaults: {
41278
42698
  type: "oauth",
41279
42699
  flow: "authorization_code",
41280
42700
  authorizationUrl: "https://auth.atlassian.com/authorize",
41281
- tokenUrl: "https://auth.atlassian.com/oauth/token"
42701
+ tokenUrl: "https://auth.atlassian.com/oauth/token",
42702
+ usePKCE: true
41282
42703
  },
41283
42704
  scopes: ["read:confluence-content.all", "write:confluence-content", "read:confluence-space.summary", "write:confluence-space", "read:confluence-user"],
41284
42705
  scopeDescriptions: {
@@ -41317,14 +42738,15 @@ var bitbucketTemplate = {
41317
42738
  name: "OAuth Consumer",
41318
42739
  type: "oauth",
41319
42740
  flow: "authorization_code",
41320
- description: "OAuth consumer for user authorization. Create at Workspace Settings > OAuth consumers",
41321
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41322
- 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"],
41323
42744
  defaults: {
41324
42745
  type: "oauth",
41325
42746
  flow: "authorization_code",
41326
42747
  authorizationUrl: "https://bitbucket.org/site/oauth2/authorize",
41327
- tokenUrl: "https://bitbucket.org/site/oauth2/access_token"
42748
+ tokenUrl: "https://bitbucket.org/site/oauth2/access_token",
42749
+ usePKCE: true
41328
42750
  },
41329
42751
  scopes: ["repository", "repository:write", "pullrequest", "pullrequest:write", "account", "pipeline", "wiki"],
41330
42752
  scopeDescriptions: {
@@ -41366,14 +42788,15 @@ var trelloTemplate = {
41366
42788
  name: "OAuth 1.0a",
41367
42789
  type: "oauth",
41368
42790
  flow: "authorization_code",
41369
- description: "OAuth 1.0a for user authorization (legacy)",
41370
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41371
- 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"],
41372
42794
  defaults: {
41373
42795
  type: "oauth",
41374
42796
  flow: "authorization_code",
41375
42797
  authorizationUrl: "https://trello.com/1/authorize",
41376
- tokenUrl: "https://trello.com/1/OAuthGetAccessToken"
42798
+ tokenUrl: "https://trello.com/1/OAuthGetAccessToken",
42799
+ usePKCE: true
41377
42800
  },
41378
42801
  scopes: ["read", "write", "account"],
41379
42802
  scopeDescriptions: {
@@ -41413,14 +42836,15 @@ var linearTemplate = {
41413
42836
  name: "OAuth (User Authorization)",
41414
42837
  type: "oauth",
41415
42838
  flow: "authorization_code",
41416
- description: "OAuth application for user authorization. Create at Settings > API > OAuth applications",
41417
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41418
- 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"],
41419
42842
  defaults: {
41420
42843
  type: "oauth",
41421
42844
  flow: "authorization_code",
41422
42845
  authorizationUrl: "https://linear.app/oauth/authorize",
41423
- tokenUrl: "https://api.linear.app/oauth/token"
42846
+ tokenUrl: "https://api.linear.app/oauth/token",
42847
+ usePKCE: true
41424
42848
  },
41425
42849
  scopes: ["read", "write", "issues:create", "comments:create"]
41426
42850
  }
@@ -41454,14 +42878,15 @@ var asanaTemplate = {
41454
42878
  name: "OAuth (User Authorization)",
41455
42879
  type: "oauth",
41456
42880
  flow: "authorization_code",
41457
- description: "OAuth application for user authorization. Create at developer console",
41458
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41459
- 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"],
41460
42884
  defaults: {
41461
42885
  type: "oauth",
41462
42886
  flow: "authorization_code",
41463
42887
  authorizationUrl: "https://app.asana.com/-/oauth_authorize",
41464
- tokenUrl: "https://app.asana.com/-/oauth_token"
42888
+ tokenUrl: "https://app.asana.com/-/oauth_token",
42889
+ usePKCE: true
41465
42890
  },
41466
42891
  scopes: ["default"]
41467
42892
  }
@@ -41495,14 +42920,15 @@ var notionTemplate = {
41495
42920
  name: "Public Integration (OAuth)",
41496
42921
  type: "oauth",
41497
42922
  flow: "authorization_code",
41498
- description: "Public integration for multi-workspace access",
41499
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41500
- 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"],
41501
42926
  defaults: {
41502
42927
  type: "oauth",
41503
42928
  flow: "authorization_code",
41504
42929
  authorizationUrl: "https://api.notion.com/v1/oauth/authorize",
41505
- tokenUrl: "https://api.notion.com/v1/oauth/token"
42930
+ tokenUrl: "https://api.notion.com/v1/oauth/token",
42931
+ usePKCE: true
41506
42932
  }
41507
42933
  }
41508
42934
  ]
@@ -41535,9 +42961,9 @@ var airtableTemplate = {
41535
42961
  name: "OAuth (User Authorization)",
41536
42962
  type: "oauth",
41537
42963
  flow: "authorization_code",
41538
- description: "OAuth integration for multi-user access. Register at airtable.com/create/oauth",
41539
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41540
- 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"],
41541
42967
  defaults: {
41542
42968
  type: "oauth",
41543
42969
  flow: "authorization_code",
@@ -41566,14 +42992,15 @@ var salesforceTemplate = {
41566
42992
  name: "OAuth (User Authorization)",
41567
42993
  type: "oauth",
41568
42994
  flow: "authorization_code",
41569
- description: "User logs in via Salesforce. Create Connected App in Setup",
41570
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41571
- 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"],
41572
42998
  defaults: {
41573
42999
  type: "oauth",
41574
43000
  flow: "authorization_code",
41575
43001
  authorizationUrl: "https://login.salesforce.com/services/oauth2/authorize",
41576
- tokenUrl: "https://login.salesforce.com/services/oauth2/token"
43002
+ tokenUrl: "https://login.salesforce.com/services/oauth2/token",
43003
+ usePKCE: true
41577
43004
  },
41578
43005
  scopes: ["api", "refresh_token", "offline_access", "chatter_api", "wave_api", "full"],
41579
43006
  scopeDescriptions: {
@@ -41629,14 +43056,15 @@ var hubspotTemplate = {
41629
43056
  name: "OAuth (User Authorization)",
41630
43057
  type: "oauth",
41631
43058
  flow: "authorization_code",
41632
- description: "Public app OAuth for multi-portal access. Create app at developers.hubspot.com",
41633
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41634
- 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"],
41635
43062
  defaults: {
41636
43063
  type: "oauth",
41637
43064
  flow: "authorization_code",
41638
43065
  authorizationUrl: "https://app.hubspot.com/oauth/authorize",
41639
- tokenUrl: "https://api.hubapi.com/oauth/v1/token"
43066
+ tokenUrl: "https://api.hubapi.com/oauth/v1/token",
43067
+ usePKCE: true
41640
43068
  },
41641
43069
  scopes: [
41642
43070
  "crm.objects.contacts.read",
@@ -41658,6 +43086,22 @@ var hubspotTemplate = {
41658
43086
  "tickets": "Read and write support tickets",
41659
43087
  "e-commerce": "Access e-commerce data (products, line items)"
41660
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
+ }
41661
43105
  }
41662
43106
  ]
41663
43107
  };
@@ -41689,14 +43133,15 @@ var pipedriveTemplate = {
41689
43133
  name: "OAuth (App Authorization)",
41690
43134
  type: "oauth",
41691
43135
  flow: "authorization_code",
41692
- description: "OAuth app for marketplace distribution. Create at developers.pipedrive.com",
41693
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41694
- 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"],
41695
43139
  defaults: {
41696
43140
  type: "oauth",
41697
43141
  flow: "authorization_code",
41698
43142
  authorizationUrl: "https://oauth.pipedrive.com/oauth/authorize",
41699
- tokenUrl: "https://oauth.pipedrive.com/oauth/token"
43143
+ tokenUrl: "https://oauth.pipedrive.com/oauth/token",
43144
+ usePKCE: true
41700
43145
  }
41701
43146
  }
41702
43147
  ]
@@ -41729,14 +43174,15 @@ var stripeTemplate = {
41729
43174
  name: "OAuth (Stripe Connect)",
41730
43175
  type: "oauth",
41731
43176
  flow: "authorization_code",
41732
- description: "Stripe Connect for marketplace platforms. Requires Connect setup in dashboard",
41733
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41734
- 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"],
41735
43180
  defaults: {
41736
43181
  type: "oauth",
41737
43182
  flow: "authorization_code",
41738
43183
  authorizationUrl: "https://connect.stripe.com/oauth/authorize",
41739
- tokenUrl: "https://connect.stripe.com/oauth/token"
43184
+ tokenUrl: "https://connect.stripe.com/oauth/token",
43185
+ usePKCE: true
41740
43186
  },
41741
43187
  scopes: ["read_write"]
41742
43188
  }
@@ -41786,14 +43232,15 @@ var quickbooksTemplate = {
41786
43232
  name: "OAuth (User Authorization)",
41787
43233
  type: "oauth",
41788
43234
  flow: "authorization_code",
41789
- description: "Standard OAuth 2.0 flow for accessing QuickBooks on behalf of a user. Create an app at developer.intuit.com",
41790
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41791
- 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"],
41792
43238
  defaults: {
41793
43239
  type: "oauth",
41794
43240
  flow: "authorization_code",
41795
43241
  authorizationUrl: "https://appcenter.intuit.com/connect/oauth2",
41796
- tokenUrl: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"
43242
+ tokenUrl: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
43243
+ usePKCE: true
41797
43244
  },
41798
43245
  scopes: ["com.intuit.quickbooks.accounting", "com.intuit.quickbooks.payment"]
41799
43246
  }
@@ -41828,14 +43275,15 @@ var rampTemplate = {
41828
43275
  name: "OAuth (User Authorization)",
41829
43276
  type: "oauth",
41830
43277
  flow: "authorization_code",
41831
- description: "OAuth 2.0 authorization code flow for accessing Ramp on behalf of a user",
41832
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41833
- 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"],
41834
43281
  defaults: {
41835
43282
  type: "oauth",
41836
43283
  flow: "authorization_code",
41837
43284
  authorizationUrl: "https://app.ramp.com/v1/authorize",
41838
- tokenUrl: "https://api.ramp.com/developer/v1/token"
43285
+ tokenUrl: "https://api.ramp.com/developer/v1/token",
43286
+ usePKCE: true
41839
43287
  },
41840
43288
  scopes: [
41841
43289
  "transactions:read",
@@ -41892,9 +43340,9 @@ var dropboxTemplate = {
41892
43340
  name: "OAuth (User Authorization)",
41893
43341
  type: "oauth",
41894
43342
  flow: "authorization_code",
41895
- description: "OAuth app for user authorization. Create app at dropbox.com/developers/apps",
41896
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41897
- 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"],
41898
43346
  defaults: {
41899
43347
  type: "oauth",
41900
43348
  flow: "authorization_code",
@@ -41931,14 +43379,15 @@ var boxTemplate = {
41931
43379
  name: "OAuth (User Authorization)",
41932
43380
  type: "oauth",
41933
43381
  flow: "authorization_code",
41934
- description: "OAuth 2.0 for user authorization. Create app at developer.box.com/console",
41935
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
41936
- 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"],
41937
43385
  defaults: {
41938
43386
  type: "oauth",
41939
43387
  flow: "authorization_code",
41940
43388
  authorizationUrl: "https://account.box.com/api/oauth2/authorize",
41941
- tokenUrl: "https://api.box.com/oauth2/token"
43389
+ tokenUrl: "https://api.box.com/oauth2/token",
43390
+ usePKCE: true
41942
43391
  },
41943
43392
  scopes: ["root_readwrite", "manage_users", "manage_groups", "manage_enterprise"],
41944
43393
  scopeDescriptions: {
@@ -42016,13 +43465,15 @@ var mailchimpTemplate = {
42016
43465
  name: "OAuth (User Authorization)",
42017
43466
  type: "oauth",
42018
43467
  flow: "authorization_code",
42019
- description: "OAuth for multi-account access. Register app at mailchimp.com/developer",
42020
- 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"],
42021
43471
  defaults: {
42022
43472
  type: "oauth",
42023
43473
  flow: "authorization_code",
42024
43474
  authorizationUrl: "https://login.mailchimp.com/oauth2/authorize",
42025
- tokenUrl: "https://login.mailchimp.com/oauth2/token"
43475
+ tokenUrl: "https://login.mailchimp.com/oauth2/token",
43476
+ usePKCE: true
42026
43477
  }
42027
43478
  }
42028
43479
  ]
@@ -42114,14 +43565,15 @@ var pagerdutyTemplate = {
42114
43565
  name: "OAuth (App Authorization)",
42115
43566
  type: "oauth",
42116
43567
  flow: "authorization_code",
42117
- description: "OAuth app for multi-account access. Register at developer.pagerduty.com",
42118
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42119
- 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"],
42120
43571
  defaults: {
42121
43572
  type: "oauth",
42122
43573
  flow: "authorization_code",
42123
43574
  authorizationUrl: "https://app.pagerduty.com/oauth/authorize",
42124
- tokenUrl: "https://app.pagerduty.com/oauth/token"
43575
+ tokenUrl: "https://app.pagerduty.com/oauth/token",
43576
+ usePKCE: true
42125
43577
  },
42126
43578
  scopes: ["read", "write"],
42127
43579
  scopeDescriptions: {
@@ -42157,14 +43609,15 @@ var sentryTemplate = {
42157
43609
  name: "OAuth (Integration)",
42158
43610
  type: "oauth",
42159
43611
  flow: "authorization_code",
42160
- description: "OAuth integration. Create at Organization Settings > Integrations",
42161
- requiredFields: ["clientId", "clientSecret", "redirectUri"],
42162
- 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"],
42163
43615
  defaults: {
42164
43616
  type: "oauth",
42165
43617
  flow: "authorization_code",
42166
43618
  authorizationUrl: "https://sentry.io/oauth/authorize/",
42167
- tokenUrl: "https://sentry.io/oauth/token/"
43619
+ tokenUrl: "https://sentry.io/oauth/token/",
43620
+ usePKCE: true
42168
43621
  },
42169
43622
  scopes: ["project:read", "project:write", "event:read", "org:read", "member:read"],
42170
43623
  scopeDescriptions: {
@@ -42361,14 +43814,15 @@ var zendeskTemplate = {
42361
43814
  name: "OAuth (User Authorization)",
42362
43815
  type: "oauth",
42363
43816
  flow: "authorization_code",
42364
- description: "OAuth client for user authorization. Create at Admin > Channels > API > OAuth Clients",
42365
- requiredFields: ["clientId", "clientSecret", "redirectUri", "subdomain"],
42366
- 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"],
42367
43820
  defaults: {
42368
43821
  type: "oauth",
42369
43822
  flow: "authorization_code",
42370
43823
  authorizationUrl: "https://{subdomain}.zendesk.com/oauth/authorizations/new",
42371
- tokenUrl: "https://{subdomain}.zendesk.com/oauth/tokens"
43824
+ tokenUrl: "https://{subdomain}.zendesk.com/oauth/tokens",
43825
+ usePKCE: true
42372
43826
  },
42373
43827
  scopes: ["read", "write", "tickets:read", "tickets:write"],
42374
43828
  scopeDescriptions: {
@@ -42406,13 +43860,15 @@ var intercomTemplate = {
42406
43860
  name: "OAuth (App Installation)",
42407
43861
  type: "oauth",
42408
43862
  flow: "authorization_code",
42409
- description: "OAuth for Intercom app marketplace distribution",
42410
- 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"],
42411
43866
  defaults: {
42412
43867
  type: "oauth",
42413
43868
  flow: "authorization_code",
42414
43869
  authorizationUrl: "https://app.intercom.com/oauth",
42415
- tokenUrl: "https://api.intercom.io/auth/eagle/token"
43870
+ tokenUrl: "https://api.intercom.io/auth/eagle/token",
43871
+ usePKCE: true
42416
43872
  }
42417
43873
  }
42418
43874
  ]
@@ -42445,14 +43901,15 @@ var shopifyTemplate = {
42445
43901
  name: "OAuth (Public/Custom App)",
42446
43902
  type: "oauth",
42447
43903
  flow: "authorization_code",
42448
- description: "OAuth for public apps or per-store custom apps. Create at partners.shopify.com",
42449
- requiredFields: ["clientId", "clientSecret", "redirectUri", "subdomain"],
42450
- 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"],
42451
43907
  defaults: {
42452
43908
  type: "oauth",
42453
43909
  flow: "authorization_code",
42454
43910
  authorizationUrl: "https://{subdomain}.myshopify.com/admin/oauth/authorize",
42455
- tokenUrl: "https://{subdomain}.myshopify.com/admin/oauth/access_token"
43911
+ tokenUrl: "https://{subdomain}.myshopify.com/admin/oauth/access_token",
43912
+ usePKCE: true
42456
43913
  },
42457
43914
  scopes: ["read_products", "write_products", "read_orders", "write_orders", "read_customers", "write_customers", "read_inventory", "write_inventory", "read_fulfillments", "write_fulfillments"],
42458
43915
  scopeDescriptions: {
@@ -42480,6 +43937,7 @@ var allVendorTemplates = [
42480
43937
  slackTemplate,
42481
43938
  discordTemplate,
42482
43939
  telegramTemplate,
43940
+ twitterTemplate,
42483
43941
  // Development
42484
43942
  githubTemplate,
42485
43943
  gitlabTemplate,
@@ -42539,6 +43997,7 @@ var VENDOR_ICON_MAP = {
42539
43997
  discord: "discord",
42540
43998
  slack: "slack",
42541
43999
  telegram: "telegram",
44000
+ twitter: "x",
42542
44001
  "microsoft-teams": "microsoftteams",
42543
44002
  // CRM
42544
44003
  salesforce: "salesforce",
@@ -42603,6 +44062,7 @@ var FALLBACK_PLACEHOLDERS = {
42603
44062
  // Communication (trademark removed)
42604
44063
  slack: { color: "#4A154B", letter: "S" },
42605
44064
  "microsoft-teams": { color: "#6264A7", letter: "T" },
44065
+ twitter: { color: "#000000", letter: "X" },
42606
44066
  // CRM (trademark removed)
42607
44067
  salesforce: { color: "#00A1E0", letter: "S" },
42608
44068
  pipedrive: { color: "#1A1F26", letter: "P" },
@@ -45772,21 +47232,53 @@ registerWebTools();
45772
47232
  init_Connector();
45773
47233
  var DEFAULT_TIMEOUT = 1e4;
45774
47234
  var DEFAULT_MAX_TIMEOUT = 3e4;
45775
- function formatConnectorEntry(c) {
47235
+ function formatConnectorEntry(c, accountId) {
45776
47236
  const parts = [];
45777
47237
  const serviceOrVendor = c.serviceType ?? c.vendor ?? void 0;
45778
47238
  if (serviceOrVendor) parts.push(`Service: ${serviceOrVendor}`);
47239
+ if (accountId) parts.push(`Account: "${accountId}"`);
45779
47240
  if (c.config.description) parts.push(c.config.description);
45780
47241
  if (c.baseURL) parts.push(`URL: ${c.baseURL}`);
47242
+ const label = accountId ? `"${c.name}" account "${accountId}"` : `"${c.name}"`;
45781
47243
  const details = parts.map((p) => ` ${p}`).join("\n");
45782
- return ` \u2022 "${c.name}" (${c.displayName})
47244
+ return ` \u2022 ${label} (${c.displayName})
45783
47245
  ${details}`;
45784
47246
  }
45785
- function generateDescription(context, maxTimeout) {
47247
+ function buildIdentityList(context) {
47248
+ const identities = context?.identities;
45786
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
+ }
45787
47262
  const connectors = registry.listAll();
45788
- 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);
45789
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
+ ` : "";
45790
47282
  return `Execute JavaScript code in a secure sandbox with authenticated API access to external services.
45791
47283
 
45792
47284
  Use this tool when you need to:
@@ -45797,7 +47289,7 @@ Use this tool when you need to:
45797
47289
 
45798
47290
  SANDBOX API:
45799
47291
 
45800
- 1. authenticatedFetch(url, options, connectorName)
47292
+ 1. authenticatedFetch(url, options, connectorName${showAccountId ? ", accountId?" : ""})
45801
47293
  Makes authenticated HTTP requests using the connector's credentials.
45802
47294
  The current user's identity (userId) is automatically included \u2014 no need to pass it.
45803
47295
  Auth headers are added automatically \u2014 DO NOT set Authorization header manually.
@@ -45808,7 +47300,7 @@ SANDBOX API:
45808
47300
  - Relative: "/user/repos" (resolved against connector's base URL)
45809
47301
  \u2022 options: Standard fetch options { method, headers, body }
45810
47302
  - For POST/PUT: set body to JSON.stringify(data) and headers to { 'Content-Type': 'application/json' }
45811
- \u2022 connectorName: Name of a registered connector (see list below)
47303
+ \u2022 connectorName: Name of a registered connector (see list below)${accountIdParam}
45812
47304
 
45813
47305
  Returns: Promise<Response>
45814
47306
  \u2022 response.ok \u2014 true if status 200-299
@@ -45844,7 +47336,7 @@ const resp = await authenticatedFetch('/chat.postMessage', {
45844
47336
  body: JSON.stringify({ channel: '#general', text: 'Hello!' })
45845
47337
  }, 'slack');
45846
47338
  output = await resp.json();
45847
-
47339
+ ${accountIdExamples}
45848
47340
  // Data processing (no API needed)
45849
47341
  const items = input.data;
45850
47342
  output = items.filter(i => i.score > 0.8).sort((a, b) => b.score - a.score);
@@ -45932,9 +47424,10 @@ async function executeInVM(code, input, timeout, logs, userId, registry) {
45932
47424
  },
45933
47425
  // Authenticated fetch — userId auto-injected from ToolContext.
45934
47426
  // Only connectors visible in the scoped registry are accessible.
45935
- authenticatedFetch: (url2, options, connectorName) => {
47427
+ // Optional 4th param accountId for multi-account OAuth identities.
47428
+ authenticatedFetch: (url2, options, connectorName, accountId) => {
45936
47429
  registry.get(connectorName);
45937
- return authenticatedFetch(url2, options, connectorName, userId);
47430
+ return authenticatedFetch(url2, options, connectorName, userId, accountId);
45938
47431
  },
45939
47432
  // Standard fetch (no auth)
45940
47433
  fetch: globalThis.fetch,
@@ -46622,7 +48115,8 @@ async function githubFetch(connector, endpoint, options) {
46622
48115
  headers,
46623
48116
  body: options?.body ? JSON.stringify(options.body) : void 0
46624
48117
  },
46625
- options?.userId
48118
+ options?.userId,
48119
+ options?.accountId
46626
48120
  );
46627
48121
  const text = await response.text();
46628
48122
  let data;
@@ -46704,6 +48198,7 @@ EXAMPLES:
46704
48198
  },
46705
48199
  execute: async (args, context) => {
46706
48200
  const effectiveUserId = context?.userId ?? userId;
48201
+ const effectiveAccountId = context?.accountId;
46707
48202
  const resolved = resolveRepository(args.repository, connector);
46708
48203
  if (!resolved.success) {
46709
48204
  return { success: false, error: resolved.error };
@@ -46715,7 +48210,7 @@ EXAMPLES:
46715
48210
  const repoInfo = await githubFetch(
46716
48211
  connector,
46717
48212
  `/repos/${owner}/${repo}`,
46718
- { userId: effectiveUserId }
48213
+ { userId: effectiveUserId, accountId: effectiveAccountId }
46719
48214
  );
46720
48215
  ref = repoInfo.default_branch;
46721
48216
  }
@@ -46815,6 +48310,7 @@ EXAMPLES:
46815
48310
  },
46816
48311
  execute: async (args, context) => {
46817
48312
  const effectiveUserId = context?.userId ?? userId;
48313
+ const effectiveAccountId = context?.accountId;
46818
48314
  const resolved = resolveRepository(args.repository, connector);
46819
48315
  if (!resolved.success) {
46820
48316
  return { success: false, error: resolved.error };
@@ -46832,6 +48328,7 @@ EXAMPLES:
46832
48328
  `/search/code`,
46833
48329
  {
46834
48330
  userId: effectiveUserId,
48331
+ accountId: effectiveAccountId,
46835
48332
  // Request text-match fragments
46836
48333
  accept: "application/vnd.github.text-match+json",
46837
48334
  queryParams: { q, per_page: perPage }
@@ -46920,6 +48417,7 @@ NOTE: Files larger than 1MB are fetched via the Git Blob API. Very large files (
46920
48417
  },
46921
48418
  execute: async (args, context) => {
46922
48419
  const effectiveUserId = context?.userId ?? userId;
48420
+ const effectiveAccountId = context?.accountId;
46923
48421
  const resolved = resolveRepository(args.repository, connector);
46924
48422
  if (!resolved.success) {
46925
48423
  return { success: false, error: resolved.error };
@@ -46933,7 +48431,7 @@ NOTE: Files larger than 1MB are fetched via the Git Blob API. Very large files (
46933
48431
  const contentResp = await githubFetch(
46934
48432
  connector,
46935
48433
  `/repos/${owner}/${repo}/contents/${args.path}${refParam}`,
46936
- { userId: effectiveUserId }
48434
+ { userId: effectiveUserId, accountId: effectiveAccountId }
46937
48435
  );
46938
48436
  if (contentResp.type !== "file") {
46939
48437
  return {
@@ -46950,7 +48448,7 @@ NOTE: Files larger than 1MB are fetched via the Git Blob API. Very large files (
46950
48448
  const blob = await githubFetch(
46951
48449
  connector,
46952
48450
  contentResp.git_url,
46953
- { userId: effectiveUserId }
48451
+ { userId: effectiveUserId, accountId: effectiveAccountId }
46954
48452
  );
46955
48453
  fileContent = Buffer.from(blob.content, "base64").toString("utf-8");
46956
48454
  fileSize = blob.size;
@@ -47039,6 +48537,7 @@ EXAMPLES:
47039
48537
  },
47040
48538
  execute: async (args, context) => {
47041
48539
  const effectiveUserId = context?.userId ?? userId;
48540
+ const effectiveAccountId = context?.accountId;
47042
48541
  const resolved = resolveRepository(args.repository, connector);
47043
48542
  if (!resolved.success) {
47044
48543
  return { success: false, error: resolved.error };
@@ -47048,7 +48547,7 @@ EXAMPLES:
47048
48547
  const pr = await githubFetch(
47049
48548
  connector,
47050
48549
  `/repos/${owner}/${repo}/pulls/${args.pull_number}`,
47051
- { userId: effectiveUserId }
48550
+ { userId: effectiveUserId, accountId: effectiveAccountId }
47052
48551
  );
47053
48552
  return {
47054
48553
  success: true,
@@ -47126,6 +48625,7 @@ NOTE: Very large diffs may be truncated by GitHub. Patch content may be absent f
47126
48625
  },
47127
48626
  execute: async (args, context) => {
47128
48627
  const effectiveUserId = context?.userId ?? userId;
48628
+ const effectiveAccountId = context?.accountId;
47129
48629
  const resolved = resolveRepository(args.repository, connector);
47130
48630
  if (!resolved.success) {
47131
48631
  return { success: false, error: resolved.error };
@@ -47137,6 +48637,7 @@ NOTE: Very large diffs may be truncated by GitHub. Patch content may be absent f
47137
48637
  `/repos/${owner}/${repo}/pulls/${args.pull_number}/files`,
47138
48638
  {
47139
48639
  userId: effectiveUserId,
48640
+ accountId: effectiveAccountId,
47140
48641
  queryParams: { per_page: 100 }
47141
48642
  }
47142
48643
  );
@@ -47209,6 +48710,7 @@ EXAMPLES:
47209
48710
  },
47210
48711
  execute: async (args, context) => {
47211
48712
  const effectiveUserId = context?.userId ?? userId;
48713
+ const effectiveAccountId = context?.accountId;
47212
48714
  const resolved = resolveRepository(args.repository, connector);
47213
48715
  if (!resolved.success) {
47214
48716
  return { success: false, error: resolved.error };
@@ -47216,7 +48718,7 @@ EXAMPLES:
47216
48718
  const { owner, repo } = resolved.repo;
47217
48719
  try {
47218
48720
  const basePath = `/repos/${owner}/${repo}`;
47219
- const queryOpts = { userId: effectiveUserId, queryParams: { per_page: 100 } };
48721
+ const queryOpts = { userId: effectiveUserId, accountId: effectiveAccountId, queryParams: { per_page: 100 } };
47220
48722
  const [reviewComments, reviews, issueComments] = await Promise.all([
47221
48723
  githubFetch(
47222
48724
  connector,
@@ -47345,6 +48847,7 @@ EXAMPLES:
47345
48847
  },
47346
48848
  execute: async (args, context) => {
47347
48849
  const effectiveUserId = context?.userId ?? userId;
48850
+ const effectiveAccountId = context?.accountId;
47348
48851
  const resolved = resolveRepository(args.repository, connector);
47349
48852
  if (!resolved.success) {
47350
48853
  return { success: false, error: resolved.error };
@@ -47357,6 +48860,7 @@ EXAMPLES:
47357
48860
  {
47358
48861
  method: "POST",
47359
48862
  userId: effectiveUserId,
48863
+ accountId: effectiveAccountId,
47360
48864
  body: {
47361
48865
  title: args.title,
47362
48866
  body: args.body,
@@ -47448,7 +48952,8 @@ async function microsoftFetch(connector, endpoint, options) {
47448
48952
  headers,
47449
48953
  body: options?.body ? JSON.stringify(options.body) : void 0
47450
48954
  },
47451
- options?.userId
48955
+ options?.userId,
48956
+ options?.accountId
47452
48957
  );
47453
48958
  const text = await response.text();
47454
48959
  if (!response.ok) {
@@ -47501,7 +49006,7 @@ function isTeamsMeetingUrl(input) {
47501
49006
  return false;
47502
49007
  }
47503
49008
  }
47504
- async function resolveMeetingId(connector, input, prefix, effectiveUserId) {
49009
+ async function resolveMeetingId(connector, input, prefix, effectiveUserId, effectiveAccountId) {
47505
49010
  if (!input || input.trim().length === 0) {
47506
49011
  throw new Error("Meeting ID cannot be empty");
47507
49012
  }
@@ -47514,6 +49019,7 @@ async function resolveMeetingId(connector, input, prefix, effectiveUserId) {
47514
49019
  `${prefix}/onlineMeetings`,
47515
49020
  {
47516
49021
  userId: effectiveUserId,
49022
+ accountId: effectiveAccountId,
47517
49023
  queryParams: { "$filter": `JoinWebUrl eq '${trimmed}'` }
47518
49024
  }
47519
49025
  );
@@ -47592,13 +49098,14 @@ EXAMPLES:
47592
49098
  },
47593
49099
  execute: async (args, context) => {
47594
49100
  const effectiveUserId = context?.userId ?? userId;
49101
+ const effectiveAccountId = context?.accountId;
47595
49102
  try {
47596
49103
  const prefix = getUserPathPrefix(connector, args.targetUser);
47597
49104
  if (args.replyToMessageId) {
47598
49105
  const replyDraft = await microsoftFetch(
47599
49106
  connector,
47600
49107
  `${prefix}/messages/${args.replyToMessageId}/createReply`,
47601
- { method: "POST", userId: effectiveUserId, body: {} }
49108
+ { method: "POST", userId: effectiveUserId, accountId: effectiveAccountId, body: {} }
47602
49109
  );
47603
49110
  const updated = await microsoftFetch(
47604
49111
  connector,
@@ -47606,6 +49113,7 @@ EXAMPLES:
47606
49113
  {
47607
49114
  method: "PATCH",
47608
49115
  userId: effectiveUserId,
49116
+ accountId: effectiveAccountId,
47609
49117
  body: {
47610
49118
  subject: args.subject,
47611
49119
  body: { contentType: "HTML", content: args.body },
@@ -47626,6 +49134,7 @@ EXAMPLES:
47626
49134
  {
47627
49135
  method: "POST",
47628
49136
  userId: effectiveUserId,
49137
+ accountId: effectiveAccountId,
47629
49138
  body: {
47630
49139
  isDraft: true,
47631
49140
  subject: args.subject,
@@ -47714,6 +49223,7 @@ EXAMPLES:
47714
49223
  },
47715
49224
  execute: async (args, context) => {
47716
49225
  const effectiveUserId = context?.userId ?? userId;
49226
+ const effectiveAccountId = context?.accountId;
47717
49227
  try {
47718
49228
  const prefix = getUserPathPrefix(connector, args.targetUser);
47719
49229
  if (args.replyToMessageId) {
@@ -47723,6 +49233,7 @@ EXAMPLES:
47723
49233
  {
47724
49234
  method: "POST",
47725
49235
  userId: effectiveUserId,
49236
+ accountId: effectiveAccountId,
47726
49237
  body: {
47727
49238
  message: {
47728
49239
  toRecipients: formatRecipients(args.to),
@@ -47739,6 +49250,7 @@ EXAMPLES:
47739
49250
  {
47740
49251
  method: "POST",
47741
49252
  userId: effectiveUserId,
49253
+ accountId: effectiveAccountId,
47742
49254
  body: {
47743
49255
  message: {
47744
49256
  subject: args.subject,
@@ -47838,6 +49350,7 @@ EXAMPLES:
47838
49350
  },
47839
49351
  execute: async (args, context) => {
47840
49352
  const effectiveUserId = context?.userId ?? userId;
49353
+ const effectiveAccountId = context?.accountId;
47841
49354
  try {
47842
49355
  const prefix = getUserPathPrefix(connector, args.targetUser);
47843
49356
  const tz = args.timeZone ?? "UTC";
@@ -47860,7 +49373,7 @@ EXAMPLES:
47860
49373
  const event = await microsoftFetch(
47861
49374
  connector,
47862
49375
  `${prefix}/events`,
47863
- { method: "POST", userId: effectiveUserId, body: eventBody }
49376
+ { method: "POST", userId: effectiveUserId, accountId: effectiveAccountId, body: eventBody }
47864
49377
  );
47865
49378
  return {
47866
49379
  success: true,
@@ -47964,6 +49477,7 @@ EXAMPLES:
47964
49477
  },
47965
49478
  execute: async (args, context) => {
47966
49479
  const effectiveUserId = context?.userId ?? userId;
49480
+ const effectiveAccountId = context?.accountId;
47967
49481
  try {
47968
49482
  const prefix = getUserPathPrefix(connector, args.targetUser);
47969
49483
  const tz = args.timeZone ?? "UTC";
@@ -47987,7 +49501,7 @@ EXAMPLES:
47987
49501
  const event = await microsoftFetch(
47988
49502
  connector,
47989
49503
  `${prefix}/events/${args.eventId}`,
47990
- { method: "PATCH", userId: effectiveUserId, body: patchBody }
49504
+ { method: "PATCH", userId: effectiveUserId, accountId: effectiveAccountId, body: patchBody }
47991
49505
  );
47992
49506
  return {
47993
49507
  success: true,
@@ -48060,14 +49574,15 @@ EXAMPLES:
48060
49574
  },
48061
49575
  execute: async (args, context) => {
48062
49576
  const effectiveUserId = context?.userId ?? userId;
49577
+ const effectiveAccountId = context?.accountId;
48063
49578
  try {
48064
49579
  const prefix = getUserPathPrefix(connector, args.targetUser);
48065
- const resolved = await resolveMeetingId(connector, args.meetingId, prefix, effectiveUserId);
49580
+ const resolved = await resolveMeetingId(connector, args.meetingId, prefix, effectiveUserId, effectiveAccountId);
48066
49581
  const meetingId = resolved.meetingId;
48067
49582
  const transcriptList = await microsoftFetch(
48068
49583
  connector,
48069
49584
  `${prefix}/onlineMeetings/${meetingId}/transcripts`,
48070
- { userId: effectiveUserId }
49585
+ { userId: effectiveUserId, accountId: effectiveAccountId }
48071
49586
  );
48072
49587
  if (!transcriptList.value || transcriptList.value.length === 0) {
48073
49588
  return {
@@ -48080,7 +49595,8 @@ EXAMPLES:
48080
49595
  const response = await connector.fetch(
48081
49596
  contentUrl + "?$format=text/vtt",
48082
49597
  { method: "GET", headers: { "Accept": "text/vtt" } },
48083
- effectiveUserId
49598
+ effectiveUserId,
49599
+ effectiveAccountId
48084
49600
  );
48085
49601
  if (!response.ok) {
48086
49602
  const errorText = await response.text();
@@ -48172,6 +49688,7 @@ EXAMPLES:
48172
49688
  },
48173
49689
  execute: async (args, context) => {
48174
49690
  const effectiveUserId = context?.userId ?? userId;
49691
+ const effectiveAccountId = context?.accountId;
48175
49692
  try {
48176
49693
  const prefix = getUserPathPrefix(connector, args.targetUser);
48177
49694
  const tz = args.timeZone ?? "UTC";
@@ -48181,6 +49698,7 @@ EXAMPLES:
48181
49698
  {
48182
49699
  method: "POST",
48183
49700
  userId: effectiveUserId,
49701
+ accountId: effectiveAccountId,
48184
49702
  body: {
48185
49703
  attendees: formatAttendees(args.attendees),
48186
49704
  timeConstraint: {
@@ -49109,27 +50627,42 @@ var customToolDelete = createCustomToolDelete();
49109
50627
 
49110
50628
  // src/tools/custom-tools/sandboxDescription.ts
49111
50629
  init_Connector();
49112
- function formatConnectorEntry2(c) {
50630
+ function formatConnectorEntry2(c, accountId) {
49113
50631
  const parts = [];
49114
50632
  const serviceOrVendor = c.serviceType ?? c.vendor ?? void 0;
49115
50633
  if (serviceOrVendor) parts.push(`Service: ${serviceOrVendor}`);
50634
+ if (accountId) parts.push(`Account: "${accountId}"`);
49116
50635
  if (c.config.description) parts.push(c.config.description);
49117
50636
  if (c.baseURL) parts.push(`URL: ${c.baseURL}`);
50637
+ const label = accountId ? `"${c.name}" account "${accountId}"` : `"${c.name}"`;
49118
50638
  const details = parts.map((p) => ` ${p}`).join("\n");
49119
- return ` \u2022 "${c.name}" (${c.displayName})
50639
+ return ` \u2022 ${label} (${c.displayName})
49120
50640
  ${details}`;
49121
50641
  }
49122
50642
  function buildConnectorList(context) {
50643
+ const identities = context?.identities;
49123
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
+ }
49124
50657
  const connectors = registry.listAll();
49125
50658
  if (connectors.length === 0) {
49126
50659
  return " No connectors registered.";
49127
50660
  }
49128
- return connectors.map(formatConnectorEntry2).join("\n\n");
50661
+ return connectors.map((c) => formatConnectorEntry2(c)).join("\n\n");
49129
50662
  }
49130
50663
  var SANDBOX_API_REFERENCE = `SANDBOX API (available inside custom tool code):
49131
50664
 
49132
- 1. authenticatedFetch(url, options, connectorName)
50665
+ 1. authenticatedFetch(url, options, connectorName, accountId?)
49133
50666
  Makes authenticated HTTP requests using the connector's credentials.
49134
50667
  Auth headers are added automatically \u2014 DO NOT set Authorization header manually.
49135
50668
 
@@ -49140,6 +50673,7 @@ var SANDBOX_API_REFERENCE = `SANDBOX API (available inside custom tool code):
49140
50673
  \u2022 options: Standard fetch options { method, headers, body }
49141
50674
  - For POST/PUT: set body to JSON.stringify(data) and headers to { 'Content-Type': 'application/json' }
49142
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')
49143
50677
 
49144
50678
  Returns: Promise<Response>
49145
50679
  \u2022 response.ok \u2014 true if status 200-299
@@ -50223,6 +51757,6 @@ REMEMBER: Keep it conversational, ask one question at a time, and only output th
50223
51757
  }
50224
51758
  };
50225
51759
 
50226
- 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, 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, 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 };
50227
51761
  //# sourceMappingURL=index.js.map
50228
51762
  //# sourceMappingURL=index.js.map