@probelabs/probe 0.6.0-rc234 → 0.6.0-rc236

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.
@@ -839,7 +839,12 @@ export class ProbeAgent {
839
839
  delegationManager: this.delegationManager, // Per-instance delegation limits
840
840
  outputBuffer: this._outputBuffer,
841
841
  concurrencyLimiter: this.concurrencyLimiter, // Global AI concurrency limiter
842
- isToolAllowed
842
+ isToolAllowed,
843
+ // Lazy MCP getters — MCP is initialized after tools are created, so we use
844
+ // getter functions that resolve at call-time to get the current MCP state
845
+ getMcpBridge: () => this.mcpBridge,
846
+ getMcpTools: () => this.mcpBridge?.mcpTools || {},
847
+ isMcpToolAllowed: (toolName) => this._isMcpToolAllowed(toolName),
843
848
  };
844
849
 
845
850
  // Create base tools
@@ -3680,6 +3685,17 @@ Follow these instructions carefully:
3680
3685
  const executeToolCall = async () => {
3681
3686
  // For delegate tool, pass current iteration, max iterations, session ID, and config
3682
3687
  if (toolName === 'delegate') {
3688
+ // Reconstruct allowedTools array preserving all modes (same logic as clone())
3689
+ let allowedToolsForDelegate = null;
3690
+ if (this.allowedTools.mode === 'whitelist') {
3691
+ allowedToolsForDelegate = [...this.allowedTools.allowed];
3692
+ } else if (this.allowedTools.mode === 'none') {
3693
+ allowedToolsForDelegate = [];
3694
+ } else if (this.allowedTools.mode === 'all' && this.allowedTools.exclusions?.length > 0) {
3695
+ allowedToolsForDelegate = ['*', ...this.allowedTools.exclusions.map(t => '!' + t)];
3696
+ }
3697
+ // If mode is 'all' with no exclusions, leave as null (default)
3698
+
3683
3699
  const enhancedParams = {
3684
3700
  ...toolParams,
3685
3701
  currentIteration,
@@ -3690,6 +3706,12 @@ Follow these instructions carefully:
3690
3706
  model: this.model, // Inherit model
3691
3707
  searchDelegate: this.searchDelegate,
3692
3708
  enableTasks: this.enableTasks, // Inherit task management (subagent gets isolated TaskManager)
3709
+ enableMcp: !!this.mcpBridge, // Inherit MCP enablement
3710
+ mcpConfig: this.mcpConfig, // Inherit MCP configuration
3711
+ mcpConfigPath: this.mcpConfigPath, // Inherit MCP config path
3712
+ enableBash: this.enableBash, // Inherit bash enablement
3713
+ bashConfig: this.bashConfig, // Inherit bash configuration
3714
+ allowedTools: allowedToolsForDelegate, // Inherit allowed tools from parent
3693
3715
  debug: this.debug,
3694
3716
  tracer: this.tracer
3695
3717
  };
@@ -10508,7 +10508,12 @@ var init_vercel = __esm({
10508
10508
  if (outline) {
10509
10509
  extractOptions.format = "xml";
10510
10510
  }
10511
- return await extract(extractOptions);
10511
+ const extractResult = await extract(extractOptions);
10512
+ if (resolutionBase && typeof extractResult === "string") {
10513
+ const wsPrefix = resolutionBase.endsWith("/") ? resolutionBase : resolutionBase + "/";
10514
+ return extractResult.split(wsPrefix).join("");
10515
+ }
10516
+ return extractResult;
10512
10517
  } catch (error) {
10513
10518
  console.error("Delegated search failed, falling back to raw search:", error);
10514
10519
  try {
@@ -28898,25 +28903,56 @@ function createExecutePlanTool(options) {
28898
28903
  const tracer = options.tracer || null;
28899
28904
  const sessionStore = options.sessionStore || {};
28900
28905
  const outputBuffer = options.outputBuffer || null;
28901
- if (options.toolImplementations) {
28902
- runtimeOptions = { ...options, tracer, sessionStore, outputBuffer };
28903
- llmCallFn = options.llmCall;
28904
- } else {
28905
- llmCallFn = buildLLMCall(options);
28906
- runtimeOptions = {
28907
- toolImplementations: buildToolImplementations(options),
28908
- llmCall: llmCallFn,
28909
- mcpBridge: options.mcpBridge || null,
28910
- mcpTools: options.mcpTools || {},
28911
- mapConcurrency: options.mapConcurrency || 5,
28912
- timeoutMs: options.timeoutMs || 3e5,
28913
- maxLoopIterations: options.maxLoopIterations || 5e3,
28914
- tracer,
28915
- sessionStore,
28916
- outputBuffer
28917
- };
28906
+ const getMcpBridge = options.getMcpBridge || (() => options.mcpBridge || null);
28907
+ const getMcpTools = options.getMcpTools || (() => options.mcpTools || {});
28908
+ const isMcpToolAllowed = options.isMcpToolAllowed || (() => true);
28909
+ let cachedMcpBridge = null;
28910
+ let runtime = null;
28911
+ function buildRuntime() {
28912
+ const currentMcpBridge = getMcpBridge();
28913
+ const currentMcpTools = getMcpTools();
28914
+ const filteredMcpTools = {};
28915
+ for (const [name, tool5] of Object.entries(currentMcpTools)) {
28916
+ if (isMcpToolAllowed(name)) {
28917
+ filteredMcpTools[name] = tool5;
28918
+ }
28919
+ }
28920
+ if (options.toolImplementations) {
28921
+ runtimeOptions = {
28922
+ ...options,
28923
+ tracer,
28924
+ sessionStore,
28925
+ outputBuffer,
28926
+ mcpBridge: currentMcpBridge,
28927
+ mcpTools: filteredMcpTools
28928
+ };
28929
+ llmCallFn = options.llmCall;
28930
+ } else {
28931
+ llmCallFn = llmCallFn || buildLLMCall(options);
28932
+ runtimeOptions = {
28933
+ toolImplementations: buildToolImplementations(options),
28934
+ llmCall: llmCallFn,
28935
+ mcpBridge: currentMcpBridge,
28936
+ mcpTools: filteredMcpTools,
28937
+ mapConcurrency: options.mapConcurrency || 5,
28938
+ timeoutMs: options.timeoutMs || 3e5,
28939
+ maxLoopIterations: options.maxLoopIterations || 5e3,
28940
+ tracer,
28941
+ sessionStore,
28942
+ outputBuffer
28943
+ };
28944
+ }
28945
+ cachedMcpBridge = currentMcpBridge;
28946
+ runtime = createDSLRuntime(runtimeOptions);
28947
+ return runtime;
28948
+ }
28949
+ function getRuntime() {
28950
+ const currentMcpBridge = getMcpBridge();
28951
+ if (!runtime || cachedMcpBridge !== currentMcpBridge) {
28952
+ buildRuntime();
28953
+ }
28954
+ return runtime;
28918
28955
  }
28919
- const runtime = createDSLRuntime(runtimeOptions);
28920
28956
  const maxRetries = options.maxRetries ?? 2;
28921
28957
  return tool4({
28922
28958
  description: "Execute a JavaScript DSL program to orchestrate tool calls. Use for batch processing, paginated APIs, multi-step workflows where intermediate data is large. Write simple synchronous-looking code \u2014 do NOT use async/await.",
@@ -28982,7 +29018,7 @@ Original error: ${lastError}`;
28982
29018
  return finalOutput;
28983
29019
  }
28984
29020
  }
28985
- const result = await runtime.execute(currentCode, description);
29021
+ const result = await getRuntime().execute(currentCode, description);
28986
29022
  if (result.status === "success") {
28987
29023
  finalOutput = formatSuccess(result, description, attempt, outputBuffer);
28988
29024
  planSpan?.setAttributes?.({
@@ -81422,7 +81458,12 @@ var init_ProbeAgent = __esm({
81422
81458
  outputBuffer: this._outputBuffer,
81423
81459
  concurrencyLimiter: this.concurrencyLimiter,
81424
81460
  // Global AI concurrency limiter
81425
- isToolAllowed
81461
+ isToolAllowed,
81462
+ // Lazy MCP getters — MCP is initialized after tools are created, so we use
81463
+ // getter functions that resolve at call-time to get the current MCP state
81464
+ getMcpBridge: () => this.mcpBridge,
81465
+ getMcpTools: () => this.mcpBridge?.mcpTools || {},
81466
+ isMcpToolAllowed: (toolName) => this._isMcpToolAllowed(toolName)
81426
81467
  };
81427
81468
  const baseTools = createTools(configOptions);
81428
81469
  const wrappedTools = createWrappedTools(baseTools);
@@ -83679,6 +83720,14 @@ ${errorXml}
83679
83720
  });
83680
83721
  const executeToolCall = async () => {
83681
83722
  if (toolName === "delegate") {
83723
+ let allowedToolsForDelegate = null;
83724
+ if (this.allowedTools.mode === "whitelist") {
83725
+ allowedToolsForDelegate = [...this.allowedTools.allowed];
83726
+ } else if (this.allowedTools.mode === "none") {
83727
+ allowedToolsForDelegate = [];
83728
+ } else if (this.allowedTools.mode === "all" && this.allowedTools.exclusions?.length > 0) {
83729
+ allowedToolsForDelegate = ["*", ...this.allowedTools.exclusions.map((t) => "!" + t)];
83730
+ }
83682
83731
  const enhancedParams = {
83683
83732
  ...toolParams,
83684
83733
  currentIteration,
@@ -83694,6 +83743,18 @@ ${errorXml}
83694
83743
  searchDelegate: this.searchDelegate,
83695
83744
  enableTasks: this.enableTasks,
83696
83745
  // Inherit task management (subagent gets isolated TaskManager)
83746
+ enableMcp: !!this.mcpBridge,
83747
+ // Inherit MCP enablement
83748
+ mcpConfig: this.mcpConfig,
83749
+ // Inherit MCP configuration
83750
+ mcpConfigPath: this.mcpConfigPath,
83751
+ // Inherit MCP config path
83752
+ enableBash: this.enableBash,
83753
+ // Inherit bash enablement
83754
+ bashConfig: this.bashConfig,
83755
+ // Inherit bash configuration
83756
+ allowedTools: allowedToolsForDelegate,
83757
+ // Inherit allowed tools from parent
83697
83758
  debug: this.debug,
83698
83759
  tracer: this.tracer
83699
83760
  };
@@ -175,28 +175,77 @@ export function createExecutePlanTool(options) {
175
175
  // Output buffer for direct-to-user content (bypasses LLM context window)
176
176
  const outputBuffer = options.outputBuffer || null;
177
177
 
178
- if (options.toolImplementations) {
179
- // Direct DSL options used by tests and manual scripts
180
- runtimeOptions = { ...options, tracer, sessionStore, outputBuffer };
181
- llmCallFn = options.llmCall;
182
- } else {
183
- // Agent configOptions — build everything from the agent's config
184
- llmCallFn = buildLLMCall(options);
185
- runtimeOptions = {
186
- toolImplementations: buildToolImplementations(options),
187
- llmCall: llmCallFn,
188
- mcpBridge: options.mcpBridge || null,
189
- mcpTools: options.mcpTools || {},
190
- mapConcurrency: options.mapConcurrency || 5,
191
- timeoutMs: options.timeoutMs || 300000,
192
- maxLoopIterations: options.maxLoopIterations || 5000,
193
- tracer,
194
- sessionStore,
195
- outputBuffer,
196
- };
178
+ // Lazy MCP getters — when using agent configOptions, MCP may be initialized after
179
+ // this tool is created. We use getters to resolve MCP state at execution time.
180
+ const getMcpBridge = options.getMcpBridge || (() => options.mcpBridge || null);
181
+ const getMcpTools = options.getMcpTools || (() => options.mcpTools || {});
182
+ const isMcpToolAllowed = options.isMcpToolAllowed || (() => true);
183
+
184
+ // Track which MCP bridge the current runtime was built with
185
+ let cachedMcpBridge = null;
186
+ let runtime = null;
187
+
188
+ /**
189
+ * Build or rebuild the DSL runtime.
190
+ * Called lazily on first execute() and when MCP bridge changes.
191
+ */
192
+ function buildRuntime() {
193
+ const currentMcpBridge = getMcpBridge();
194
+ const currentMcpTools = getMcpTools();
195
+
196
+ // Filter MCP tools through allowedTools
197
+ const filteredMcpTools = {};
198
+ for (const [name, tool] of Object.entries(currentMcpTools)) {
199
+ if (isMcpToolAllowed(name)) {
200
+ filteredMcpTools[name] = tool;
201
+ }
202
+ }
203
+
204
+ if (options.toolImplementations) {
205
+ // Direct DSL options — used by tests and manual scripts
206
+ runtimeOptions = {
207
+ ...options,
208
+ tracer,
209
+ sessionStore,
210
+ outputBuffer,
211
+ mcpBridge: currentMcpBridge,
212
+ mcpTools: filteredMcpTools,
213
+ };
214
+ llmCallFn = options.llmCall;
215
+ } else {
216
+ // Agent configOptions — build everything from the agent's config
217
+ llmCallFn = llmCallFn || buildLLMCall(options);
218
+ runtimeOptions = {
219
+ toolImplementations: buildToolImplementations(options),
220
+ llmCall: llmCallFn,
221
+ mcpBridge: currentMcpBridge,
222
+ mcpTools: filteredMcpTools,
223
+ mapConcurrency: options.mapConcurrency || 5,
224
+ timeoutMs: options.timeoutMs || 300000,
225
+ maxLoopIterations: options.maxLoopIterations || 5000,
226
+ tracer,
227
+ sessionStore,
228
+ outputBuffer,
229
+ };
230
+ }
231
+
232
+ cachedMcpBridge = currentMcpBridge;
233
+ runtime = createDSLRuntime(runtimeOptions);
234
+ return runtime;
235
+ }
236
+
237
+ /**
238
+ * Get or rebuild the runtime if MCP state has changed.
239
+ */
240
+ function getRuntime() {
241
+ const currentMcpBridge = getMcpBridge();
242
+ // Rebuild runtime if MCP bridge changed (null -> bridge, or different bridge)
243
+ if (!runtime || cachedMcpBridge !== currentMcpBridge) {
244
+ buildRuntime();
245
+ }
246
+ return runtime;
197
247
  }
198
248
 
199
- const runtime = createDSLRuntime(runtimeOptions);
200
249
  const maxRetries = options.maxRetries ?? 2;
201
250
 
202
251
  return tool({
@@ -272,7 +321,7 @@ RULES REMINDER:
272
321
  }
273
322
  }
274
323
 
275
- const result = await runtime.execute(currentCode, description);
324
+ const result = await getRuntime().execute(currentCode, description);
276
325
 
277
326
  if (result.status === 'success') {
278
327
  finalOutput = formatSuccess(result, description, attempt, outputBuffer);
@@ -283,7 +283,15 @@ export const searchTool = (options = {}) => {
283
283
  extractOptions.format = 'xml';
284
284
  }
285
285
 
286
- return await extract(extractOptions);
286
+ const extractResult = await extract(extractOptions);
287
+
288
+ // Strip workspace root prefix from extract output so paths are relative
289
+ if (resolutionBase && typeof extractResult === 'string') {
290
+ const wsPrefix = resolutionBase.endsWith('/') ? resolutionBase : resolutionBase + '/';
291
+ return extractResult.split(wsPrefix).join('');
292
+ }
293
+
294
+ return extractResult;
287
295
  } catch (error) {
288
296
  console.error('Delegated search failed, falling back to raw search:', error);
289
297
  try {
@@ -37619,7 +37619,12 @@ var init_vercel = __esm({
37619
37619
  if (outline) {
37620
37620
  extractOptions.format = "xml";
37621
37621
  }
37622
- return await extract(extractOptions);
37622
+ const extractResult = await extract(extractOptions);
37623
+ if (resolutionBase && typeof extractResult === "string") {
37624
+ const wsPrefix = resolutionBase.endsWith("/") ? resolutionBase : resolutionBase + "/";
37625
+ return extractResult.split(wsPrefix).join("");
37626
+ }
37627
+ return extractResult;
37623
37628
  } catch (error2) {
37624
37629
  console.error("Delegated search failed, falling back to raw search:", error2);
37625
37630
  try {
@@ -56009,25 +56014,56 @@ function createExecutePlanTool(options) {
56009
56014
  const tracer = options.tracer || null;
56010
56015
  const sessionStore = options.sessionStore || {};
56011
56016
  const outputBuffer = options.outputBuffer || null;
56012
- if (options.toolImplementations) {
56013
- runtimeOptions = { ...options, tracer, sessionStore, outputBuffer };
56014
- llmCallFn = options.llmCall;
56015
- } else {
56016
- llmCallFn = buildLLMCall(options);
56017
- runtimeOptions = {
56018
- toolImplementations: buildToolImplementations(options),
56019
- llmCall: llmCallFn,
56020
- mcpBridge: options.mcpBridge || null,
56021
- mcpTools: options.mcpTools || {},
56022
- mapConcurrency: options.mapConcurrency || 5,
56023
- timeoutMs: options.timeoutMs || 3e5,
56024
- maxLoopIterations: options.maxLoopIterations || 5e3,
56025
- tracer,
56026
- sessionStore,
56027
- outputBuffer
56028
- };
56017
+ const getMcpBridge = options.getMcpBridge || (() => options.mcpBridge || null);
56018
+ const getMcpTools = options.getMcpTools || (() => options.mcpTools || {});
56019
+ const isMcpToolAllowed = options.isMcpToolAllowed || (() => true);
56020
+ let cachedMcpBridge = null;
56021
+ let runtime = null;
56022
+ function buildRuntime() {
56023
+ const currentMcpBridge = getMcpBridge();
56024
+ const currentMcpTools = getMcpTools();
56025
+ const filteredMcpTools = {};
56026
+ for (const [name14, tool5] of Object.entries(currentMcpTools)) {
56027
+ if (isMcpToolAllowed(name14)) {
56028
+ filteredMcpTools[name14] = tool5;
56029
+ }
56030
+ }
56031
+ if (options.toolImplementations) {
56032
+ runtimeOptions = {
56033
+ ...options,
56034
+ tracer,
56035
+ sessionStore,
56036
+ outputBuffer,
56037
+ mcpBridge: currentMcpBridge,
56038
+ mcpTools: filteredMcpTools
56039
+ };
56040
+ llmCallFn = options.llmCall;
56041
+ } else {
56042
+ llmCallFn = llmCallFn || buildLLMCall(options);
56043
+ runtimeOptions = {
56044
+ toolImplementations: buildToolImplementations(options),
56045
+ llmCall: llmCallFn,
56046
+ mcpBridge: currentMcpBridge,
56047
+ mcpTools: filteredMcpTools,
56048
+ mapConcurrency: options.mapConcurrency || 5,
56049
+ timeoutMs: options.timeoutMs || 3e5,
56050
+ maxLoopIterations: options.maxLoopIterations || 5e3,
56051
+ tracer,
56052
+ sessionStore,
56053
+ outputBuffer
56054
+ };
56055
+ }
56056
+ cachedMcpBridge = currentMcpBridge;
56057
+ runtime = createDSLRuntime(runtimeOptions);
56058
+ return runtime;
56059
+ }
56060
+ function getRuntime() {
56061
+ const currentMcpBridge = getMcpBridge();
56062
+ if (!runtime || cachedMcpBridge !== currentMcpBridge) {
56063
+ buildRuntime();
56064
+ }
56065
+ return runtime;
56029
56066
  }
56030
- const runtime = createDSLRuntime(runtimeOptions);
56031
56067
  const maxRetries = options.maxRetries ?? 2;
56032
56068
  return (0, import_ai4.tool)({
56033
56069
  description: "Execute a JavaScript DSL program to orchestrate tool calls. Use for batch processing, paginated APIs, multi-step workflows where intermediate data is large. Write simple synchronous-looking code \u2014 do NOT use async/await.",
@@ -56093,7 +56129,7 @@ Original error: ${lastError}`;
56093
56129
  return finalOutput;
56094
56130
  }
56095
56131
  }
56096
- const result = await runtime.execute(currentCode, description);
56132
+ const result = await getRuntime().execute(currentCode, description);
56097
56133
  if (result.status === "success") {
56098
56134
  finalOutput = formatSuccess(result, description, attempt, outputBuffer);
56099
56135
  planSpan?.setAttributes?.({
@@ -108100,7 +108136,12 @@ var init_ProbeAgent = __esm({
108100
108136
  outputBuffer: this._outputBuffer,
108101
108137
  concurrencyLimiter: this.concurrencyLimiter,
108102
108138
  // Global AI concurrency limiter
108103
- isToolAllowed
108139
+ isToolAllowed,
108140
+ // Lazy MCP getters — MCP is initialized after tools are created, so we use
108141
+ // getter functions that resolve at call-time to get the current MCP state
108142
+ getMcpBridge: () => this.mcpBridge,
108143
+ getMcpTools: () => this.mcpBridge?.mcpTools || {},
108144
+ isMcpToolAllowed: (toolName) => this._isMcpToolAllowed(toolName)
108104
108145
  };
108105
108146
  const baseTools = createTools(configOptions);
108106
108147
  const wrappedTools = createWrappedTools(baseTools);
@@ -110357,6 +110398,14 @@ ${errorXml}
110357
110398
  });
110358
110399
  const executeToolCall = async () => {
110359
110400
  if (toolName === "delegate") {
110401
+ let allowedToolsForDelegate = null;
110402
+ if (this.allowedTools.mode === "whitelist") {
110403
+ allowedToolsForDelegate = [...this.allowedTools.allowed];
110404
+ } else if (this.allowedTools.mode === "none") {
110405
+ allowedToolsForDelegate = [];
110406
+ } else if (this.allowedTools.mode === "all" && this.allowedTools.exclusions?.length > 0) {
110407
+ allowedToolsForDelegate = ["*", ...this.allowedTools.exclusions.map((t4) => "!" + t4)];
110408
+ }
110360
110409
  const enhancedParams = {
110361
110410
  ...toolParams,
110362
110411
  currentIteration,
@@ -110372,6 +110421,18 @@ ${errorXml}
110372
110421
  searchDelegate: this.searchDelegate,
110373
110422
  enableTasks: this.enableTasks,
110374
110423
  // Inherit task management (subagent gets isolated TaskManager)
110424
+ enableMcp: !!this.mcpBridge,
110425
+ // Inherit MCP enablement
110426
+ mcpConfig: this.mcpConfig,
110427
+ // Inherit MCP configuration
110428
+ mcpConfigPath: this.mcpConfigPath,
110429
+ // Inherit MCP config path
110430
+ enableBash: this.enableBash,
110431
+ // Inherit bash enablement
110432
+ bashConfig: this.bashConfig,
110433
+ // Inherit bash configuration
110434
+ allowedTools: allowedToolsForDelegate,
110435
+ // Inherit allowed tools from parent
110375
110436
  debug: this.debug,
110376
110437
  tracer: this.tracer
110377
110438
  };
package/cjs/index.cjs CHANGED
@@ -94428,7 +94428,12 @@ var init_ProbeAgent = __esm({
94428
94428
  outputBuffer: this._outputBuffer,
94429
94429
  concurrencyLimiter: this.concurrencyLimiter,
94430
94430
  // Global AI concurrency limiter
94431
- isToolAllowed
94431
+ isToolAllowed,
94432
+ // Lazy MCP getters — MCP is initialized after tools are created, so we use
94433
+ // getter functions that resolve at call-time to get the current MCP state
94434
+ getMcpBridge: () => this.mcpBridge,
94435
+ getMcpTools: () => this.mcpBridge?.mcpTools || {},
94436
+ isMcpToolAllowed: (toolName) => this._isMcpToolAllowed(toolName)
94432
94437
  };
94433
94438
  const baseTools = createTools(configOptions);
94434
94439
  const wrappedTools = createWrappedTools(baseTools);
@@ -96685,6 +96690,14 @@ ${errorXml}
96685
96690
  });
96686
96691
  const executeToolCall = async () => {
96687
96692
  if (toolName === "delegate") {
96693
+ let allowedToolsForDelegate = null;
96694
+ if (this.allowedTools.mode === "whitelist") {
96695
+ allowedToolsForDelegate = [...this.allowedTools.allowed];
96696
+ } else if (this.allowedTools.mode === "none") {
96697
+ allowedToolsForDelegate = [];
96698
+ } else if (this.allowedTools.mode === "all" && this.allowedTools.exclusions?.length > 0) {
96699
+ allowedToolsForDelegate = ["*", ...this.allowedTools.exclusions.map((t4) => "!" + t4)];
96700
+ }
96688
96701
  const enhancedParams = {
96689
96702
  ...toolParams,
96690
96703
  currentIteration,
@@ -96700,6 +96713,18 @@ ${errorXml}
96700
96713
  searchDelegate: this.searchDelegate,
96701
96714
  enableTasks: this.enableTasks,
96702
96715
  // Inherit task management (subagent gets isolated TaskManager)
96716
+ enableMcp: !!this.mcpBridge,
96717
+ // Inherit MCP enablement
96718
+ mcpConfig: this.mcpConfig,
96719
+ // Inherit MCP configuration
96720
+ mcpConfigPath: this.mcpConfigPath,
96721
+ // Inherit MCP config path
96722
+ enableBash: this.enableBash,
96723
+ // Inherit bash enablement
96724
+ bashConfig: this.bashConfig,
96725
+ // Inherit bash configuration
96726
+ allowedTools: allowedToolsForDelegate,
96727
+ // Inherit allowed tools from parent
96703
96728
  debug: this.debug,
96704
96729
  tracer: this.tracer
96705
96730
  };
@@ -98889,7 +98914,12 @@ var init_vercel = __esm({
98889
98914
  if (outline) {
98890
98915
  extractOptions.format = "xml";
98891
98916
  }
98892
- return await extract(extractOptions);
98917
+ const extractResult = await extract(extractOptions);
98918
+ if (resolutionBase && typeof extractResult === "string") {
98919
+ const wsPrefix = resolutionBase.endsWith("/") ? resolutionBase : resolutionBase + "/";
98920
+ return extractResult.split(wsPrefix).join("");
98921
+ }
98922
+ return extractResult;
98893
98923
  } catch (error2) {
98894
98924
  console.error("Delegated search failed, falling back to raw search:", error2);
98895
98925
  try {
@@ -110676,25 +110706,56 @@ function createExecutePlanTool(options) {
110676
110706
  const tracer = options.tracer || null;
110677
110707
  const sessionStore = options.sessionStore || {};
110678
110708
  const outputBuffer = options.outputBuffer || null;
110679
- if (options.toolImplementations) {
110680
- runtimeOptions = { ...options, tracer, sessionStore, outputBuffer };
110681
- llmCallFn = options.llmCall;
110682
- } else {
110683
- llmCallFn = buildLLMCall(options);
110684
- runtimeOptions = {
110685
- toolImplementations: buildToolImplementations(options),
110686
- llmCall: llmCallFn,
110687
- mcpBridge: options.mcpBridge || null,
110688
- mcpTools: options.mcpTools || {},
110689
- mapConcurrency: options.mapConcurrency || 5,
110690
- timeoutMs: options.timeoutMs || 3e5,
110691
- maxLoopIterations: options.maxLoopIterations || 5e3,
110692
- tracer,
110693
- sessionStore,
110694
- outputBuffer
110695
- };
110709
+ const getMcpBridge = options.getMcpBridge || (() => options.mcpBridge || null);
110710
+ const getMcpTools = options.getMcpTools || (() => options.mcpTools || {});
110711
+ const isMcpToolAllowed = options.isMcpToolAllowed || (() => true);
110712
+ let cachedMcpBridge = null;
110713
+ let runtime = null;
110714
+ function buildRuntime() {
110715
+ const currentMcpBridge = getMcpBridge();
110716
+ const currentMcpTools = getMcpTools();
110717
+ const filteredMcpTools = {};
110718
+ for (const [name14, tool5] of Object.entries(currentMcpTools)) {
110719
+ if (isMcpToolAllowed(name14)) {
110720
+ filteredMcpTools[name14] = tool5;
110721
+ }
110722
+ }
110723
+ if (options.toolImplementations) {
110724
+ runtimeOptions = {
110725
+ ...options,
110726
+ tracer,
110727
+ sessionStore,
110728
+ outputBuffer,
110729
+ mcpBridge: currentMcpBridge,
110730
+ mcpTools: filteredMcpTools
110731
+ };
110732
+ llmCallFn = options.llmCall;
110733
+ } else {
110734
+ llmCallFn = llmCallFn || buildLLMCall(options);
110735
+ runtimeOptions = {
110736
+ toolImplementations: buildToolImplementations(options),
110737
+ llmCall: llmCallFn,
110738
+ mcpBridge: currentMcpBridge,
110739
+ mcpTools: filteredMcpTools,
110740
+ mapConcurrency: options.mapConcurrency || 5,
110741
+ timeoutMs: options.timeoutMs || 3e5,
110742
+ maxLoopIterations: options.maxLoopIterations || 5e3,
110743
+ tracer,
110744
+ sessionStore,
110745
+ outputBuffer
110746
+ };
110747
+ }
110748
+ cachedMcpBridge = currentMcpBridge;
110749
+ runtime = createDSLRuntime(runtimeOptions);
110750
+ return runtime;
110751
+ }
110752
+ function getRuntime() {
110753
+ const currentMcpBridge = getMcpBridge();
110754
+ if (!runtime || cachedMcpBridge !== currentMcpBridge) {
110755
+ buildRuntime();
110756
+ }
110757
+ return runtime;
110696
110758
  }
110697
- const runtime = createDSLRuntime(runtimeOptions);
110698
110759
  const maxRetries = options.maxRetries ?? 2;
110699
110760
  return (0, import_ai6.tool)({
110700
110761
  description: "Execute a JavaScript DSL program to orchestrate tool calls. Use for batch processing, paginated APIs, multi-step workflows where intermediate data is large. Write simple synchronous-looking code \u2014 do NOT use async/await.",
@@ -110760,7 +110821,7 @@ Original error: ${lastError}`;
110760
110821
  return finalOutput;
110761
110822
  }
110762
110823
  }
110763
- const result = await runtime.execute(currentCode, description);
110824
+ const result = await getRuntime().execute(currentCode, description);
110764
110825
  if (result.status === "success") {
110765
110826
  finalOutput = formatSuccess(result, description, attempt, outputBuffer);
110766
110827
  planSpan?.setAttributes?.({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@probelabs/probe",
3
- "version": "0.6.0-rc234",
3
+ "version": "0.6.0-rc236",
4
4
  "description": "Node.js wrapper for the probe code search tool",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
@@ -839,7 +839,12 @@ export class ProbeAgent {
839
839
  delegationManager: this.delegationManager, // Per-instance delegation limits
840
840
  outputBuffer: this._outputBuffer,
841
841
  concurrencyLimiter: this.concurrencyLimiter, // Global AI concurrency limiter
842
- isToolAllowed
842
+ isToolAllowed,
843
+ // Lazy MCP getters — MCP is initialized after tools are created, so we use
844
+ // getter functions that resolve at call-time to get the current MCP state
845
+ getMcpBridge: () => this.mcpBridge,
846
+ getMcpTools: () => this.mcpBridge?.mcpTools || {},
847
+ isMcpToolAllowed: (toolName) => this._isMcpToolAllowed(toolName),
843
848
  };
844
849
 
845
850
  // Create base tools
@@ -3680,6 +3685,17 @@ Follow these instructions carefully:
3680
3685
  const executeToolCall = async () => {
3681
3686
  // For delegate tool, pass current iteration, max iterations, session ID, and config
3682
3687
  if (toolName === 'delegate') {
3688
+ // Reconstruct allowedTools array preserving all modes (same logic as clone())
3689
+ let allowedToolsForDelegate = null;
3690
+ if (this.allowedTools.mode === 'whitelist') {
3691
+ allowedToolsForDelegate = [...this.allowedTools.allowed];
3692
+ } else if (this.allowedTools.mode === 'none') {
3693
+ allowedToolsForDelegate = [];
3694
+ } else if (this.allowedTools.mode === 'all' && this.allowedTools.exclusions?.length > 0) {
3695
+ allowedToolsForDelegate = ['*', ...this.allowedTools.exclusions.map(t => '!' + t)];
3696
+ }
3697
+ // If mode is 'all' with no exclusions, leave as null (default)
3698
+
3683
3699
  const enhancedParams = {
3684
3700
  ...toolParams,
3685
3701
  currentIteration,
@@ -3690,6 +3706,12 @@ Follow these instructions carefully:
3690
3706
  model: this.model, // Inherit model
3691
3707
  searchDelegate: this.searchDelegate,
3692
3708
  enableTasks: this.enableTasks, // Inherit task management (subagent gets isolated TaskManager)
3709
+ enableMcp: !!this.mcpBridge, // Inherit MCP enablement
3710
+ mcpConfig: this.mcpConfig, // Inherit MCP configuration
3711
+ mcpConfigPath: this.mcpConfigPath, // Inherit MCP config path
3712
+ enableBash: this.enableBash, // Inherit bash enablement
3713
+ bashConfig: this.bashConfig, // Inherit bash configuration
3714
+ allowedTools: allowedToolsForDelegate, // Inherit allowed tools from parent
3693
3715
  debug: this.debug,
3694
3716
  tracer: this.tracer
3695
3717
  };
@@ -175,28 +175,77 @@ export function createExecutePlanTool(options) {
175
175
  // Output buffer for direct-to-user content (bypasses LLM context window)
176
176
  const outputBuffer = options.outputBuffer || null;
177
177
 
178
- if (options.toolImplementations) {
179
- // Direct DSL options used by tests and manual scripts
180
- runtimeOptions = { ...options, tracer, sessionStore, outputBuffer };
181
- llmCallFn = options.llmCall;
182
- } else {
183
- // Agent configOptions — build everything from the agent's config
184
- llmCallFn = buildLLMCall(options);
185
- runtimeOptions = {
186
- toolImplementations: buildToolImplementations(options),
187
- llmCall: llmCallFn,
188
- mcpBridge: options.mcpBridge || null,
189
- mcpTools: options.mcpTools || {},
190
- mapConcurrency: options.mapConcurrency || 5,
191
- timeoutMs: options.timeoutMs || 300000,
192
- maxLoopIterations: options.maxLoopIterations || 5000,
193
- tracer,
194
- sessionStore,
195
- outputBuffer,
196
- };
178
+ // Lazy MCP getters — when using agent configOptions, MCP may be initialized after
179
+ // this tool is created. We use getters to resolve MCP state at execution time.
180
+ const getMcpBridge = options.getMcpBridge || (() => options.mcpBridge || null);
181
+ const getMcpTools = options.getMcpTools || (() => options.mcpTools || {});
182
+ const isMcpToolAllowed = options.isMcpToolAllowed || (() => true);
183
+
184
+ // Track which MCP bridge the current runtime was built with
185
+ let cachedMcpBridge = null;
186
+ let runtime = null;
187
+
188
+ /**
189
+ * Build or rebuild the DSL runtime.
190
+ * Called lazily on first execute() and when MCP bridge changes.
191
+ */
192
+ function buildRuntime() {
193
+ const currentMcpBridge = getMcpBridge();
194
+ const currentMcpTools = getMcpTools();
195
+
196
+ // Filter MCP tools through allowedTools
197
+ const filteredMcpTools = {};
198
+ for (const [name, tool] of Object.entries(currentMcpTools)) {
199
+ if (isMcpToolAllowed(name)) {
200
+ filteredMcpTools[name] = tool;
201
+ }
202
+ }
203
+
204
+ if (options.toolImplementations) {
205
+ // Direct DSL options — used by tests and manual scripts
206
+ runtimeOptions = {
207
+ ...options,
208
+ tracer,
209
+ sessionStore,
210
+ outputBuffer,
211
+ mcpBridge: currentMcpBridge,
212
+ mcpTools: filteredMcpTools,
213
+ };
214
+ llmCallFn = options.llmCall;
215
+ } else {
216
+ // Agent configOptions — build everything from the agent's config
217
+ llmCallFn = llmCallFn || buildLLMCall(options);
218
+ runtimeOptions = {
219
+ toolImplementations: buildToolImplementations(options),
220
+ llmCall: llmCallFn,
221
+ mcpBridge: currentMcpBridge,
222
+ mcpTools: filteredMcpTools,
223
+ mapConcurrency: options.mapConcurrency || 5,
224
+ timeoutMs: options.timeoutMs || 300000,
225
+ maxLoopIterations: options.maxLoopIterations || 5000,
226
+ tracer,
227
+ sessionStore,
228
+ outputBuffer,
229
+ };
230
+ }
231
+
232
+ cachedMcpBridge = currentMcpBridge;
233
+ runtime = createDSLRuntime(runtimeOptions);
234
+ return runtime;
235
+ }
236
+
237
+ /**
238
+ * Get or rebuild the runtime if MCP state has changed.
239
+ */
240
+ function getRuntime() {
241
+ const currentMcpBridge = getMcpBridge();
242
+ // Rebuild runtime if MCP bridge changed (null -> bridge, or different bridge)
243
+ if (!runtime || cachedMcpBridge !== currentMcpBridge) {
244
+ buildRuntime();
245
+ }
246
+ return runtime;
197
247
  }
198
248
 
199
- const runtime = createDSLRuntime(runtimeOptions);
200
249
  const maxRetries = options.maxRetries ?? 2;
201
250
 
202
251
  return tool({
@@ -272,7 +321,7 @@ RULES REMINDER:
272
321
  }
273
322
  }
274
323
 
275
- const result = await runtime.execute(currentCode, description);
324
+ const result = await getRuntime().execute(currentCode, description);
276
325
 
277
326
  if (result.status === 'success') {
278
327
  finalOutput = formatSuccess(result, description, attempt, outputBuffer);
@@ -283,7 +283,15 @@ export const searchTool = (options = {}) => {
283
283
  extractOptions.format = 'xml';
284
284
  }
285
285
 
286
- return await extract(extractOptions);
286
+ const extractResult = await extract(extractOptions);
287
+
288
+ // Strip workspace root prefix from extract output so paths are relative
289
+ if (resolutionBase && typeof extractResult === 'string') {
290
+ const wsPrefix = resolutionBase.endsWith('/') ? resolutionBase : resolutionBase + '/';
291
+ return extractResult.split(wsPrefix).join('');
292
+ }
293
+
294
+ return extractResult;
287
295
  } catch (error) {
288
296
  console.error('Delegated search failed, falling back to raw search:', error);
289
297
  try {