@probelabs/probe 0.6.0-rc235 → 0.6.0-rc237

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.
@@ -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 {