@probelabs/probe 0.6.0-rc215 → 0.6.0-rc217

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/cjs/index.cjs CHANGED
@@ -95799,6 +95799,7 @@ var init_ProbeAgent = __esm({
95799
95799
  init_contextCompactor();
95800
95800
  init_error_types();
95801
95801
  init_outputTruncator();
95802
+ init_delegate();
95802
95803
  init_tasks();
95803
95804
  import_dotenv.default.config();
95804
95805
  MAX_TOOL_ITERATIONS = (() => {
@@ -95940,6 +95941,7 @@ var init_ProbeAgent = __esm({
95940
95941
  this._mcpInitialized = false;
95941
95942
  this.enableTasks = !!options.enableTasks;
95942
95943
  this.taskManager = null;
95944
+ this.delegationManager = new DelegationManager();
95943
95945
  this.retryConfig = options.retry || {};
95944
95946
  this.retryManager = null;
95945
95947
  this.fallbackConfig = options.fallback || null;
@@ -96111,6 +96113,8 @@ var init_ProbeAgent = __esm({
96111
96113
  architectureFileName: this.architectureFileName,
96112
96114
  provider: this.clientApiProvider,
96113
96115
  model: this.clientApiModel,
96116
+ delegationManager: this.delegationManager,
96117
+ // Per-instance delegation limits
96114
96118
  isToolAllowed
96115
96119
  };
96116
96120
  const baseTools = createTools(configOptions);
@@ -99129,6 +99133,16 @@ Convert your previous response content into actual JSON data that follows this s
99129
99133
  console.error("Error cleaning up MCP bridge:", error2);
99130
99134
  }
99131
99135
  }
99136
+ if (this.delegationManager) {
99137
+ try {
99138
+ this.delegationManager.cleanup();
99139
+ if (this.debug) {
99140
+ console.log("[DEBUG] Delegation manager cleaned up");
99141
+ }
99142
+ } catch (error2) {
99143
+ console.error("Error cleaning up delegation manager:", error2);
99144
+ }
99145
+ }
99132
99146
  this.clearHistory();
99133
99147
  }
99134
99148
  /**
@@ -99168,11 +99182,14 @@ async function delegate({
99168
99182
  enableTasks = false,
99169
99183
  enableMcp = false,
99170
99184
  mcpConfig = null,
99171
- mcpConfigPath = null
99185
+ mcpConfigPath = null,
99186
+ delegationManager = null
99187
+ // Optional per-instance manager, falls back to default singleton
99172
99188
  }) {
99173
99189
  if (!task || typeof task !== "string") {
99174
99190
  throw new Error("Task parameter is required and must be a string");
99175
99191
  }
99192
+ const manager = delegationManager || defaultDelegationManager;
99176
99193
  const sessionId = (0, import_crypto9.randomUUID)();
99177
99194
  const startTime = Date.now();
99178
99195
  const remainingIterations = Math.max(1, maxIterations - currentIteration);
@@ -99180,17 +99197,17 @@ async function delegate({
99180
99197
  let timeoutId = null;
99181
99198
  let acquired = false;
99182
99199
  try {
99183
- delegationManager.tryAcquire(parentSessionId);
99200
+ await manager.acquire(parentSessionId, debug);
99184
99201
  acquired = true;
99185
99202
  if (debug) {
99186
- const stats = delegationManager.getStats();
99203
+ const stats = manager.getStats();
99187
99204
  console.error(`[DELEGATE] Starting delegation session ${sessionId}`);
99188
99205
  console.error(`[DELEGATE] Parent session: ${parentSessionId || "none"}`);
99189
99206
  console.error(`[DELEGATE] Task: ${task}`);
99190
99207
  console.error(`[DELEGATE] Current iteration: ${currentIteration}/${maxIterations}`);
99191
99208
  console.error(`[DELEGATE] Remaining iterations for subagent: ${remainingIterations}`);
99192
99209
  console.error(`[DELEGATE] Timeout configured: ${timeout} seconds`);
99193
- console.error(`[DELEGATE] Global active delegations: ${stats.globalActive}/${stats.maxConcurrent}`);
99210
+ console.error(`[DELEGATE] Global active delegations: ${stats.globalActive}/${stats.maxConcurrent}, queue: ${stats.queueSize}`);
99194
99211
  console.error(`[DELEGATE] Using ProbeAgent SDK with ${promptType} prompt`);
99195
99212
  }
99196
99213
  const subagent = new ProbeAgent({
@@ -99284,7 +99301,7 @@ async function delegate({
99284
99301
  }
99285
99302
  }
99286
99303
  if (acquired) {
99287
- delegationManager.release(parentSessionId, debug);
99304
+ manager.release(parentSessionId, debug);
99288
99305
  }
99289
99306
  return response;
99290
99307
  } catch (error2) {
@@ -99294,7 +99311,7 @@ async function delegate({
99294
99311
  }
99295
99312
  const duration = Date.now() - startTime;
99296
99313
  if (acquired) {
99297
- delegationManager.release(parentSessionId, debug);
99314
+ manager.release(parentSessionId, debug);
99298
99315
  }
99299
99316
  if (debug) {
99300
99317
  console.error(`[DELEGATE] Task failed for session ${sessionId} after ${duration}ms`);
@@ -99322,7 +99339,7 @@ async function delegate({
99322
99339
  throw new Error(`Delegation failed: ${error2.message}`);
99323
99340
  }
99324
99341
  }
99325
- var import_crypto9, DelegationManager, delegationManager;
99342
+ var import_crypto9, DelegationManager, defaultDelegationManager;
99326
99343
  var init_delegate = __esm({
99327
99344
  "src/delegate.js"() {
99328
99345
  "use strict";
@@ -99332,8 +99349,10 @@ var init_delegate = __esm({
99332
99349
  constructor() {
99333
99350
  this.maxConcurrent = parseInt(process.env.MAX_CONCURRENT_DELEGATIONS || "3", 10);
99334
99351
  this.maxPerSession = parseInt(process.env.MAX_DELEGATIONS_PER_SESSION || "10", 10);
99352
+ this.defaultQueueTimeout = parseInt(process.env.DELEGATION_QUEUE_TIMEOUT || "60000", 10);
99335
99353
  this.sessionDelegations = /* @__PURE__ */ new Map();
99336
99354
  this.globalActive = 0;
99355
+ this.waitQueue = [];
99337
99356
  this.cleanupInterval = setInterval(() => {
99338
99357
  try {
99339
99358
  this.cleanupStaleSessions();
@@ -99348,13 +99367,14 @@ var init_delegate = __esm({
99348
99367
  /**
99349
99368
  * Check limits and increment counters (synchronous, atomic in Node.js event loop)
99350
99369
  * @param {string|null|undefined} parentSessionId - Parent session ID for tracking
99370
+ * @returns {boolean} true if acquired, false if would need to wait
99351
99371
  */
99352
99372
  tryAcquire(parentSessionId) {
99353
99373
  if (parentSessionId !== null && parentSessionId !== void 0 && typeof parentSessionId !== "string") {
99354
99374
  throw new TypeError("parentSessionId must be a string, null, or undefined");
99355
99375
  }
99356
99376
  if (this.globalActive >= this.maxConcurrent) {
99357
- throw new Error(`Maximum concurrent delegations (${this.maxConcurrent}) reached. Please wait for some delegations to complete.`);
99377
+ return false;
99358
99378
  }
99359
99379
  if (parentSessionId) {
99360
99380
  const sessionData = this.sessionDelegations.get(parentSessionId);
@@ -99363,6 +99383,14 @@ var init_delegate = __esm({
99363
99383
  throw new Error(`Maximum delegations per session (${this.maxPerSession}) reached for session ${parentSessionId}`);
99364
99384
  }
99365
99385
  }
99386
+ this._incrementCounters(parentSessionId);
99387
+ return true;
99388
+ }
99389
+ /**
99390
+ * Internal helper to increment counters
99391
+ * @private
99392
+ */
99393
+ _incrementCounters(parentSessionId) {
99366
99394
  this.globalActive++;
99367
99395
  if (parentSessionId) {
99368
99396
  const sessionData = this.sessionDelegations.get(parentSessionId);
@@ -99376,10 +99404,60 @@ var init_delegate = __esm({
99376
99404
  });
99377
99405
  }
99378
99406
  }
99379
- return true;
99380
99407
  }
99381
99408
  /**
99382
- * Decrement counters (synchronous, atomic in Node.js event loop)
99409
+ * Acquire a delegation slot, waiting in queue if necessary
99410
+ * @param {string|null|undefined} parentSessionId - Parent session ID for tracking
99411
+ * @param {boolean} debug - Enable debug logging
99412
+ * @param {number|null} queueTimeout - Max time to wait in queue (ms). Defaults to this.defaultQueueTimeout. Set to 0 to disable.
99413
+ * @returns {Promise<boolean>} Resolves when slot is acquired, rejects on timeout or session limit error
99414
+ */
99415
+ async acquire(parentSessionId, debug = false, queueTimeout = null) {
99416
+ const effectiveTimeout = queueTimeout !== null ? queueTimeout : this.defaultQueueTimeout;
99417
+ if (this.tryAcquire(parentSessionId)) {
99418
+ return true;
99419
+ }
99420
+ if (debug) {
99421
+ console.error(`[DelegationManager] Slot unavailable (${this.globalActive}/${this.maxConcurrent}), queuing... (queue size: ${this.waitQueue.length}, timeout: ${effectiveTimeout}ms)`);
99422
+ }
99423
+ return new Promise((resolve7, reject2) => {
99424
+ const entry = {
99425
+ resolve: null,
99426
+ // Will be wrapped below
99427
+ reject: null,
99428
+ // Will be wrapped below
99429
+ parentSessionId,
99430
+ debug,
99431
+ queuedAt: Date.now(),
99432
+ timeoutId: null
99433
+ };
99434
+ let settled = false;
99435
+ entry.resolve = (value) => {
99436
+ if (settled) return;
99437
+ settled = true;
99438
+ if (entry.timeoutId) clearTimeout(entry.timeoutId);
99439
+ resolve7(value);
99440
+ };
99441
+ entry.reject = (error2) => {
99442
+ if (settled) return;
99443
+ settled = true;
99444
+ if (entry.timeoutId) clearTimeout(entry.timeoutId);
99445
+ reject2(error2);
99446
+ };
99447
+ if (effectiveTimeout > 0) {
99448
+ entry.timeoutId = setTimeout(() => {
99449
+ const index = this.waitQueue.indexOf(entry);
99450
+ if (index !== -1) {
99451
+ this.waitQueue.splice(index, 1);
99452
+ }
99453
+ entry.reject(new Error(`Delegation queue timeout: waited ${effectiveTimeout}ms for an available slot`));
99454
+ }, effectiveTimeout);
99455
+ }
99456
+ this.waitQueue.push(entry);
99457
+ });
99458
+ }
99459
+ /**
99460
+ * Decrement counters and process queue (synchronous, atomic in Node.js event loop)
99383
99461
  */
99384
99462
  release(parentSessionId, debug = false) {
99385
99463
  this.globalActive = Math.max(0, this.globalActive - 1);
@@ -99393,7 +99471,36 @@ var init_delegate = __esm({
99393
99471
  }
99394
99472
  }
99395
99473
  if (debug) {
99396
- console.error(`[DELEGATE] Released. Global active: ${this.globalActive}`);
99474
+ console.error(`[DELEGATE] Released. Global active: ${this.globalActive}, queue size: ${this.waitQueue.length}`);
99475
+ }
99476
+ this._processQueue(debug);
99477
+ }
99478
+ /**
99479
+ * Process the wait queue - grant slot to next waiting delegation
99480
+ * @private
99481
+ */
99482
+ _processQueue(debug = false) {
99483
+ while (this.waitQueue.length > 0 && this.globalActive < this.maxConcurrent) {
99484
+ const next = this.waitQueue.shift();
99485
+ if (!next) break;
99486
+ const { resolve: resolve7, reject: reject2, parentSessionId, queuedAt } = next;
99487
+ if (parentSessionId) {
99488
+ const sessionData = this.sessionDelegations.get(parentSessionId);
99489
+ const sessionCount = sessionData?.count || 0;
99490
+ if (sessionCount >= this.maxPerSession) {
99491
+ if (debug) {
99492
+ console.error(`[DelegationManager] Session limit (${this.maxPerSession}) reached for queued item, rejecting`);
99493
+ }
99494
+ reject2(new Error(`Maximum delegations per session (${this.maxPerSession}) reached for session ${parentSessionId}`));
99495
+ continue;
99496
+ }
99497
+ }
99498
+ this._incrementCounters(parentSessionId);
99499
+ if (debug) {
99500
+ const waitTime = Date.now() - queuedAt;
99501
+ console.error(`[DelegationManager] Granted slot from queue (waited ${waitTime}ms). Active: ${this.globalActive}/${this.maxConcurrent}`);
99502
+ }
99503
+ resolve7(true);
99397
99504
  }
99398
99505
  }
99399
99506
  /**
@@ -99404,7 +99511,9 @@ var init_delegate = __esm({
99404
99511
  globalActive: this.globalActive,
99405
99512
  maxConcurrent: this.maxConcurrent,
99406
99513
  maxPerSession: this.maxPerSession,
99407
- sessionCount: this.sessionDelegations.size
99514
+ defaultQueueTimeout: this.defaultQueueTimeout,
99515
+ sessionCount: this.sessionDelegations.size,
99516
+ queueSize: this.waitQueue.length
99408
99517
  };
99409
99518
  }
99410
99519
  /**
@@ -99426,11 +99535,20 @@ var init_delegate = __esm({
99426
99535
  clearInterval(this.cleanupInterval);
99427
99536
  this.cleanupInterval = null;
99428
99537
  }
99538
+ for (const entry of this.waitQueue) {
99539
+ if (entry.timeoutId) {
99540
+ clearTimeout(entry.timeoutId);
99541
+ }
99542
+ if (entry.reject) {
99543
+ entry.reject(new Error("DelegationManager was cleaned up"));
99544
+ }
99545
+ }
99546
+ this.waitQueue = [];
99429
99547
  this.sessionDelegations.clear();
99430
99548
  this.globalActive = 0;
99431
99549
  }
99432
99550
  };
99433
- delegationManager = new DelegationManager();
99551
+ defaultDelegationManager = new DelegationManager();
99434
99552
  }
99435
99553
  });
99436
99554
 
@@ -99542,7 +99660,9 @@ Instructions:
99542
99660
  enableBash: false,
99543
99661
  promptType: "code-researcher",
99544
99662
  allowedTools: ["extract"],
99545
- maxIterations: 5
99663
+ maxIterations: 5,
99664
+ delegationManager: options.delegationManager
99665
+ // Per-instance delegation limits
99546
99666
  // timeout removed - inherit default from delegate (300s)
99547
99667
  });
99548
99668
  return { chunk, result };
@@ -99640,7 +99760,9 @@ Organize all findings into clear categories with items listed under each.${compl
99640
99760
  enableBash: false,
99641
99761
  promptType: "code-researcher",
99642
99762
  allowedTools: [],
99643
- maxIterations: 5
99763
+ maxIterations: 5,
99764
+ delegationManager: options.delegationManager
99765
+ // Per-instance delegation limits
99644
99766
  // timeout removed - inherit default from delegate (300s)
99645
99767
  });
99646
99768
  return result;
@@ -99703,7 +99825,9 @@ CRITICAL: Do NOT guess keywords. Actually run searches and see what returns resu
99703
99825
  enableBash: false,
99704
99826
  promptType: "code-researcher",
99705
99827
  // Full tool access for exploration and experimentation
99706
- maxIterations: 15
99828
+ maxIterations: 15,
99829
+ delegationManager: options.delegationManager
99830
+ // Per-instance delegation limits
99707
99831
  // timeout removed - inherit default from delegate (300s)
99708
99832
  });
99709
99833
  const plan = parsePlanningResult(stripResultTags(result));
@@ -99759,7 +99883,9 @@ IMPORTANT: When completing, use the FULL format: <attempt_completion><result>YOU
99759
99883
  enableBash: false,
99760
99884
  promptType: "code-researcher",
99761
99885
  allowedTools: [],
99762
- maxIterations: 5
99886
+ maxIterations: 5,
99887
+ delegationManager: options.delegationManager
99888
+ // Per-instance delegation limits
99763
99889
  // timeout removed - inherit default from delegate (300s)
99764
99890
  });
99765
99891
  return stripResultTags(result);
@@ -99781,7 +99907,9 @@ async function analyzeAll(options) {
99781
99907
  model,
99782
99908
  tracer,
99783
99909
  chunkSizeTokens = DEFAULT_CHUNK_SIZE_TOKENS,
99784
- maxChunks = MAX_CHUNKS
99910
+ maxChunks = MAX_CHUNKS,
99911
+ delegationManager = null
99912
+ // Per-instance delegation limits
99785
99913
  } = options;
99786
99914
  if (!question) {
99787
99915
  throw new Error('The "question" parameter is required.');
@@ -99793,7 +99921,9 @@ async function analyzeAll(options) {
99793
99921
  allowedFolders,
99794
99922
  provider,
99795
99923
  model,
99796
- tracer
99924
+ tracer,
99925
+ delegationManager
99926
+ // Per-instance delegation limits
99797
99927
  };
99798
99928
  if (debug) {
99799
99929
  console.error(`[analyze_all] Starting analysis`);
@@ -100247,7 +100377,7 @@ var init_vercel = __esm({
100247
100377
  });
100248
100378
  };
100249
100379
  delegateTool = (options = {}) => {
100250
- const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName, enableMcp = false, mcpConfig = null, mcpConfigPath = null } = options;
100380
+ const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName, enableMcp = false, mcpConfig = null, mcpConfigPath = null, delegationManager = null } = options;
100251
100381
  return (0, import_ai4.tool)({
100252
100382
  name: "delegate",
100253
100383
  description: delegateDescription,
@@ -100309,14 +100439,16 @@ var init_vercel = __esm({
100309
100439
  searchDelegate,
100310
100440
  enableMcp,
100311
100441
  mcpConfig,
100312
- mcpConfigPath
100442
+ mcpConfigPath,
100443
+ delegationManager
100444
+ // Per-instance delegation limits
100313
100445
  });
100314
100446
  return result;
100315
100447
  }
100316
100448
  });
100317
100449
  };
100318
100450
  analyzeAllTool = (options = {}) => {
100319
- const { sessionId, debug = false } = options;
100451
+ const { sessionId, debug = false, delegationManager = null } = options;
100320
100452
  return (0, import_ai4.tool)({
100321
100453
  name: "analyze_all",
100322
100454
  description: analyzeAllDescription,
@@ -100344,7 +100476,9 @@ var init_vercel = __esm({
100344
100476
  allowedFolders: options.allowedFolders,
100345
100477
  provider: options.provider,
100346
100478
  model: options.model,
100347
- tracer: options.tracer
100479
+ tracer: options.tracer,
100480
+ delegationManager
100481
+ // Per-instance delegation limits
100348
100482
  });
100349
100483
  return result;
100350
100484
  } catch (error2) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@probelabs/probe",
3
- "version": "0.6.0-rc215",
3
+ "version": "0.6.0-rc217",
4
4
  "description": "Node.js wrapper for the probe code search tool",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
@@ -72,6 +72,7 @@ import { FallbackManager, createFallbackManagerFromEnv, buildFallbackProvidersFr
72
72
  import { handleContextLimitError } from './contextCompactor.js';
73
73
  import { formatErrorForAI, ParameterError } from '../utils/error-types.js';
74
74
  import { truncateIfNeeded, getMaxOutputTokens } from './outputTruncator.js';
75
+ import { DelegationManager } from '../delegate.js';
75
76
  import {
76
77
  TaskManager,
77
78
  createTaskTool,
@@ -315,6 +316,10 @@ export class ProbeAgent {
315
316
  this.enableTasks = !!options.enableTasks;
316
317
  this.taskManager = null; // Initialized per-request in answer()
317
318
 
319
+ // Per-instance delegation manager for concurrent delegation limits
320
+ // Each ProbeAgent instance has its own limits, not shared globally
321
+ this.delegationManager = new DelegationManager();
322
+
318
323
  // Retry configuration
319
324
  this.retryConfig = options.retry || {};
320
325
  this.retryManager = null; // Will be initialized lazily when needed
@@ -538,6 +543,7 @@ export class ProbeAgent {
538
543
  architectureFileName: this.architectureFileName,
539
544
  provider: this.clientApiProvider,
540
545
  model: this.clientApiModel,
546
+ delegationManager: this.delegationManager, // Per-instance delegation limits
541
547
  isToolAllowed
542
548
  };
543
549
 
@@ -4371,6 +4377,18 @@ Convert your previous response content into actual JSON data that follows this s
4371
4377
  }
4372
4378
  }
4373
4379
 
4380
+ // Clean up delegation manager
4381
+ if (this.delegationManager) {
4382
+ try {
4383
+ this.delegationManager.cleanup();
4384
+ if (this.debug) {
4385
+ console.log('[DEBUG] Delegation manager cleaned up');
4386
+ }
4387
+ } catch (error) {
4388
+ console.error('Error cleaning up delegation manager:', error);
4389
+ }
4390
+ }
4391
+
4374
4392
  // Clear history and other resources
4375
4393
  this.clearHistory();
4376
4394
  }