@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.
@@ -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
  }
@@ -3767,11 +3767,14 @@ async function delegate({
3767
3767
  enableTasks = false,
3768
3768
  enableMcp = false,
3769
3769
  mcpConfig = null,
3770
- mcpConfigPath = null
3770
+ mcpConfigPath = null,
3771
+ delegationManager = null
3772
+ // Optional per-instance manager, falls back to default singleton
3771
3773
  }) {
3772
3774
  if (!task || typeof task !== "string") {
3773
3775
  throw new Error("Task parameter is required and must be a string");
3774
3776
  }
3777
+ const manager = delegationManager || defaultDelegationManager;
3775
3778
  const sessionId = randomUUID();
3776
3779
  const startTime = Date.now();
3777
3780
  const remainingIterations = Math.max(1, maxIterations - currentIteration);
@@ -3779,17 +3782,17 @@ async function delegate({
3779
3782
  let timeoutId = null;
3780
3783
  let acquired = false;
3781
3784
  try {
3782
- delegationManager.tryAcquire(parentSessionId);
3785
+ await manager.acquire(parentSessionId, debug);
3783
3786
  acquired = true;
3784
3787
  if (debug) {
3785
- const stats = delegationManager.getStats();
3788
+ const stats = manager.getStats();
3786
3789
  console.error(`[DELEGATE] Starting delegation session ${sessionId}`);
3787
3790
  console.error(`[DELEGATE] Parent session: ${parentSessionId || "none"}`);
3788
3791
  console.error(`[DELEGATE] Task: ${task}`);
3789
3792
  console.error(`[DELEGATE] Current iteration: ${currentIteration}/${maxIterations}`);
3790
3793
  console.error(`[DELEGATE] Remaining iterations for subagent: ${remainingIterations}`);
3791
3794
  console.error(`[DELEGATE] Timeout configured: ${timeout} seconds`);
3792
- console.error(`[DELEGATE] Global active delegations: ${stats.globalActive}/${stats.maxConcurrent}`);
3795
+ console.error(`[DELEGATE] Global active delegations: ${stats.globalActive}/${stats.maxConcurrent}, queue: ${stats.queueSize}`);
3793
3796
  console.error(`[DELEGATE] Using ProbeAgent SDK with ${promptType} prompt`);
3794
3797
  }
3795
3798
  const subagent = new ProbeAgent({
@@ -3883,7 +3886,7 @@ async function delegate({
3883
3886
  }
3884
3887
  }
3885
3888
  if (acquired) {
3886
- delegationManager.release(parentSessionId, debug);
3889
+ manager.release(parentSessionId, debug);
3887
3890
  }
3888
3891
  return response;
3889
3892
  } catch (error) {
@@ -3893,7 +3896,7 @@ async function delegate({
3893
3896
  }
3894
3897
  const duration = Date.now() - startTime;
3895
3898
  if (acquired) {
3896
- delegationManager.release(parentSessionId, debug);
3899
+ manager.release(parentSessionId, debug);
3897
3900
  }
3898
3901
  if (debug) {
3899
3902
  console.error(`[DELEGATE] Task failed for session ${sessionId} after ${duration}ms`);
@@ -3921,7 +3924,7 @@ async function delegate({
3921
3924
  throw new Error(`Delegation failed: ${error.message}`);
3922
3925
  }
3923
3926
  }
3924
- var DelegationManager, delegationManager;
3927
+ var DelegationManager, defaultDelegationManager;
3925
3928
  var init_delegate = __esm({
3926
3929
  "src/delegate.js"() {
3927
3930
  "use strict";
@@ -3930,8 +3933,10 @@ var init_delegate = __esm({
3930
3933
  constructor() {
3931
3934
  this.maxConcurrent = parseInt(process.env.MAX_CONCURRENT_DELEGATIONS || "3", 10);
3932
3935
  this.maxPerSession = parseInt(process.env.MAX_DELEGATIONS_PER_SESSION || "10", 10);
3936
+ this.defaultQueueTimeout = parseInt(process.env.DELEGATION_QUEUE_TIMEOUT || "60000", 10);
3933
3937
  this.sessionDelegations = /* @__PURE__ */ new Map();
3934
3938
  this.globalActive = 0;
3939
+ this.waitQueue = [];
3935
3940
  this.cleanupInterval = setInterval(() => {
3936
3941
  try {
3937
3942
  this.cleanupStaleSessions();
@@ -3946,13 +3951,14 @@ var init_delegate = __esm({
3946
3951
  /**
3947
3952
  * Check limits and increment counters (synchronous, atomic in Node.js event loop)
3948
3953
  * @param {string|null|undefined} parentSessionId - Parent session ID for tracking
3954
+ * @returns {boolean} true if acquired, false if would need to wait
3949
3955
  */
3950
3956
  tryAcquire(parentSessionId) {
3951
3957
  if (parentSessionId !== null && parentSessionId !== void 0 && typeof parentSessionId !== "string") {
3952
3958
  throw new TypeError("parentSessionId must be a string, null, or undefined");
3953
3959
  }
3954
3960
  if (this.globalActive >= this.maxConcurrent) {
3955
- throw new Error(`Maximum concurrent delegations (${this.maxConcurrent}) reached. Please wait for some delegations to complete.`);
3961
+ return false;
3956
3962
  }
3957
3963
  if (parentSessionId) {
3958
3964
  const sessionData = this.sessionDelegations.get(parentSessionId);
@@ -3961,6 +3967,14 @@ var init_delegate = __esm({
3961
3967
  throw new Error(`Maximum delegations per session (${this.maxPerSession}) reached for session ${parentSessionId}`);
3962
3968
  }
3963
3969
  }
3970
+ this._incrementCounters(parentSessionId);
3971
+ return true;
3972
+ }
3973
+ /**
3974
+ * Internal helper to increment counters
3975
+ * @private
3976
+ */
3977
+ _incrementCounters(parentSessionId) {
3964
3978
  this.globalActive++;
3965
3979
  if (parentSessionId) {
3966
3980
  const sessionData = this.sessionDelegations.get(parentSessionId);
@@ -3974,10 +3988,60 @@ var init_delegate = __esm({
3974
3988
  });
3975
3989
  }
3976
3990
  }
3977
- return true;
3978
3991
  }
3979
3992
  /**
3980
- * Decrement counters (synchronous, atomic in Node.js event loop)
3993
+ * Acquire a delegation slot, waiting in queue if necessary
3994
+ * @param {string|null|undefined} parentSessionId - Parent session ID for tracking
3995
+ * @param {boolean} debug - Enable debug logging
3996
+ * @param {number|null} queueTimeout - Max time to wait in queue (ms). Defaults to this.defaultQueueTimeout. Set to 0 to disable.
3997
+ * @returns {Promise<boolean>} Resolves when slot is acquired, rejects on timeout or session limit error
3998
+ */
3999
+ async acquire(parentSessionId, debug = false, queueTimeout = null) {
4000
+ const effectiveTimeout = queueTimeout !== null ? queueTimeout : this.defaultQueueTimeout;
4001
+ if (this.tryAcquire(parentSessionId)) {
4002
+ return true;
4003
+ }
4004
+ if (debug) {
4005
+ console.error(`[DelegationManager] Slot unavailable (${this.globalActive}/${this.maxConcurrent}), queuing... (queue size: ${this.waitQueue.length}, timeout: ${effectiveTimeout}ms)`);
4006
+ }
4007
+ return new Promise((resolve8, reject2) => {
4008
+ const entry = {
4009
+ resolve: null,
4010
+ // Will be wrapped below
4011
+ reject: null,
4012
+ // Will be wrapped below
4013
+ parentSessionId,
4014
+ debug,
4015
+ queuedAt: Date.now(),
4016
+ timeoutId: null
4017
+ };
4018
+ let settled = false;
4019
+ entry.resolve = (value) => {
4020
+ if (settled) return;
4021
+ settled = true;
4022
+ if (entry.timeoutId) clearTimeout(entry.timeoutId);
4023
+ resolve8(value);
4024
+ };
4025
+ entry.reject = (error) => {
4026
+ if (settled) return;
4027
+ settled = true;
4028
+ if (entry.timeoutId) clearTimeout(entry.timeoutId);
4029
+ reject2(error);
4030
+ };
4031
+ if (effectiveTimeout > 0) {
4032
+ entry.timeoutId = setTimeout(() => {
4033
+ const index = this.waitQueue.indexOf(entry);
4034
+ if (index !== -1) {
4035
+ this.waitQueue.splice(index, 1);
4036
+ }
4037
+ entry.reject(new Error(`Delegation queue timeout: waited ${effectiveTimeout}ms for an available slot`));
4038
+ }, effectiveTimeout);
4039
+ }
4040
+ this.waitQueue.push(entry);
4041
+ });
4042
+ }
4043
+ /**
4044
+ * Decrement counters and process queue (synchronous, atomic in Node.js event loop)
3981
4045
  */
3982
4046
  release(parentSessionId, debug = false) {
3983
4047
  this.globalActive = Math.max(0, this.globalActive - 1);
@@ -3991,7 +4055,36 @@ var init_delegate = __esm({
3991
4055
  }
3992
4056
  }
3993
4057
  if (debug) {
3994
- console.error(`[DELEGATE] Released. Global active: ${this.globalActive}`);
4058
+ console.error(`[DELEGATE] Released. Global active: ${this.globalActive}, queue size: ${this.waitQueue.length}`);
4059
+ }
4060
+ this._processQueue(debug);
4061
+ }
4062
+ /**
4063
+ * Process the wait queue - grant slot to next waiting delegation
4064
+ * @private
4065
+ */
4066
+ _processQueue(debug = false) {
4067
+ while (this.waitQueue.length > 0 && this.globalActive < this.maxConcurrent) {
4068
+ const next = this.waitQueue.shift();
4069
+ if (!next) break;
4070
+ const { resolve: resolve8, reject: reject2, parentSessionId, queuedAt } = next;
4071
+ if (parentSessionId) {
4072
+ const sessionData = this.sessionDelegations.get(parentSessionId);
4073
+ const sessionCount = sessionData?.count || 0;
4074
+ if (sessionCount >= this.maxPerSession) {
4075
+ if (debug) {
4076
+ console.error(`[DelegationManager] Session limit (${this.maxPerSession}) reached for queued item, rejecting`);
4077
+ }
4078
+ reject2(new Error(`Maximum delegations per session (${this.maxPerSession}) reached for session ${parentSessionId}`));
4079
+ continue;
4080
+ }
4081
+ }
4082
+ this._incrementCounters(parentSessionId);
4083
+ if (debug) {
4084
+ const waitTime = Date.now() - queuedAt;
4085
+ console.error(`[DelegationManager] Granted slot from queue (waited ${waitTime}ms). Active: ${this.globalActive}/${this.maxConcurrent}`);
4086
+ }
4087
+ resolve8(true);
3995
4088
  }
3996
4089
  }
3997
4090
  /**
@@ -4002,7 +4095,9 @@ var init_delegate = __esm({
4002
4095
  globalActive: this.globalActive,
4003
4096
  maxConcurrent: this.maxConcurrent,
4004
4097
  maxPerSession: this.maxPerSession,
4005
- sessionCount: this.sessionDelegations.size
4098
+ defaultQueueTimeout: this.defaultQueueTimeout,
4099
+ sessionCount: this.sessionDelegations.size,
4100
+ queueSize: this.waitQueue.length
4006
4101
  };
4007
4102
  }
4008
4103
  /**
@@ -4024,11 +4119,20 @@ var init_delegate = __esm({
4024
4119
  clearInterval(this.cleanupInterval);
4025
4120
  this.cleanupInterval = null;
4026
4121
  }
4122
+ for (const entry of this.waitQueue) {
4123
+ if (entry.timeoutId) {
4124
+ clearTimeout(entry.timeoutId);
4125
+ }
4126
+ if (entry.reject) {
4127
+ entry.reject(new Error("DelegationManager was cleaned up"));
4128
+ }
4129
+ }
4130
+ this.waitQueue = [];
4027
4131
  this.sessionDelegations.clear();
4028
4132
  this.globalActive = 0;
4029
4133
  }
4030
4134
  };
4031
- delegationManager = new DelegationManager();
4135
+ defaultDelegationManager = new DelegationManager();
4032
4136
  }
4033
4137
  });
4034
4138
 
@@ -4140,7 +4244,9 @@ Instructions:
4140
4244
  enableBash: false,
4141
4245
  promptType: "code-researcher",
4142
4246
  allowedTools: ["extract"],
4143
- maxIterations: 5
4247
+ maxIterations: 5,
4248
+ delegationManager: options.delegationManager
4249
+ // Per-instance delegation limits
4144
4250
  // timeout removed - inherit default from delegate (300s)
4145
4251
  });
4146
4252
  return { chunk, result };
@@ -4238,7 +4344,9 @@ Organize all findings into clear categories with items listed under each.${compl
4238
4344
  enableBash: false,
4239
4345
  promptType: "code-researcher",
4240
4346
  allowedTools: [],
4241
- maxIterations: 5
4347
+ maxIterations: 5,
4348
+ delegationManager: options.delegationManager
4349
+ // Per-instance delegation limits
4242
4350
  // timeout removed - inherit default from delegate (300s)
4243
4351
  });
4244
4352
  return result;
@@ -4301,7 +4409,9 @@ CRITICAL: Do NOT guess keywords. Actually run searches and see what returns resu
4301
4409
  enableBash: false,
4302
4410
  promptType: "code-researcher",
4303
4411
  // Full tool access for exploration and experimentation
4304
- maxIterations: 15
4412
+ maxIterations: 15,
4413
+ delegationManager: options.delegationManager
4414
+ // Per-instance delegation limits
4305
4415
  // timeout removed - inherit default from delegate (300s)
4306
4416
  });
4307
4417
  const plan = parsePlanningResult(stripResultTags(result));
@@ -4357,7 +4467,9 @@ IMPORTANT: When completing, use the FULL format: <attempt_completion><result>YOU
4357
4467
  enableBash: false,
4358
4468
  promptType: "code-researcher",
4359
4469
  allowedTools: [],
4360
- maxIterations: 5
4470
+ maxIterations: 5,
4471
+ delegationManager: options.delegationManager
4472
+ // Per-instance delegation limits
4361
4473
  // timeout removed - inherit default from delegate (300s)
4362
4474
  });
4363
4475
  return stripResultTags(result);
@@ -4379,7 +4491,9 @@ async function analyzeAll(options) {
4379
4491
  model,
4380
4492
  tracer,
4381
4493
  chunkSizeTokens = DEFAULT_CHUNK_SIZE_TOKENS,
4382
- maxChunks = MAX_CHUNKS
4494
+ maxChunks = MAX_CHUNKS,
4495
+ delegationManager = null
4496
+ // Per-instance delegation limits
4383
4497
  } = options;
4384
4498
  if (!question) {
4385
4499
  throw new Error('The "question" parameter is required.');
@@ -4391,7 +4505,9 @@ async function analyzeAll(options) {
4391
4505
  allowedFolders,
4392
4506
  provider,
4393
4507
  model,
4394
- tracer
4508
+ tracer,
4509
+ delegationManager
4510
+ // Per-instance delegation limits
4395
4511
  };
4396
4512
  if (debug) {
4397
4513
  console.error(`[analyze_all] Starting analysis`);
@@ -10318,7 +10434,7 @@ var init_vercel = __esm({
10318
10434
  });
10319
10435
  };
10320
10436
  delegateTool = (options = {}) => {
10321
- const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName, enableMcp = false, mcpConfig = null, mcpConfigPath = null } = options;
10437
+ const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName, enableMcp = false, mcpConfig = null, mcpConfigPath = null, delegationManager = null } = options;
10322
10438
  return tool2({
10323
10439
  name: "delegate",
10324
10440
  description: delegateDescription,
@@ -10380,14 +10496,16 @@ var init_vercel = __esm({
10380
10496
  searchDelegate,
10381
10497
  enableMcp,
10382
10498
  mcpConfig,
10383
- mcpConfigPath
10499
+ mcpConfigPath,
10500
+ delegationManager
10501
+ // Per-instance delegation limits
10384
10502
  });
10385
10503
  return result;
10386
10504
  }
10387
10505
  });
10388
10506
  };
10389
10507
  analyzeAllTool = (options = {}) => {
10390
- const { sessionId, debug = false } = options;
10508
+ const { sessionId, debug = false, delegationManager = null } = options;
10391
10509
  return tool2({
10392
10510
  name: "analyze_all",
10393
10511
  description: analyzeAllDescription,
@@ -10415,7 +10533,9 @@ var init_vercel = __esm({
10415
10533
  allowedFolders: options.allowedFolders,
10416
10534
  provider: options.provider,
10417
10535
  model: options.model,
10418
- tracer: options.tracer
10536
+ tracer: options.tracer,
10537
+ delegationManager
10538
+ // Per-instance delegation limits
10419
10539
  });
10420
10540
  return result;
10421
10541
  } catch (error) {
@@ -69835,6 +69955,7 @@ var init_ProbeAgent = __esm({
69835
69955
  init_contextCompactor();
69836
69956
  init_error_types();
69837
69957
  init_outputTruncator();
69958
+ init_delegate();
69838
69959
  init_tasks();
69839
69960
  dotenv2.config();
69840
69961
  MAX_TOOL_ITERATIONS = (() => {
@@ -69976,6 +70097,7 @@ var init_ProbeAgent = __esm({
69976
70097
  this._mcpInitialized = false;
69977
70098
  this.enableTasks = !!options.enableTasks;
69978
70099
  this.taskManager = null;
70100
+ this.delegationManager = new DelegationManager();
69979
70101
  this.retryConfig = options.retry || {};
69980
70102
  this.retryManager = null;
69981
70103
  this.fallbackConfig = options.fallback || null;
@@ -70147,6 +70269,8 @@ var init_ProbeAgent = __esm({
70147
70269
  architectureFileName: this.architectureFileName,
70148
70270
  provider: this.clientApiProvider,
70149
70271
  model: this.clientApiModel,
70272
+ delegationManager: this.delegationManager,
70273
+ // Per-instance delegation limits
70150
70274
  isToolAllowed
70151
70275
  };
70152
70276
  const baseTools = createTools(configOptions);
@@ -73165,6 +73289,16 @@ Convert your previous response content into actual JSON data that follows this s
73165
73289
  console.error("Error cleaning up MCP bridge:", error);
73166
73290
  }
73167
73291
  }
73292
+ if (this.delegationManager) {
73293
+ try {
73294
+ this.delegationManager.cleanup();
73295
+ if (this.debug) {
73296
+ console.log("[DEBUG] Delegation manager cleaned up");
73297
+ }
73298
+ } catch (error) {
73299
+ console.error("Error cleaning up delegation manager:", error);
73300
+ }
73301
+ }
73168
73302
  this.clearHistory();
73169
73303
  }
73170
73304
  /**