@probelabs/probe 0.6.0-rc238 → 0.6.0-rc240

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.
Files changed (33) hide show
  1. package/bin/binaries/probe-v0.6.0-rc240-aarch64-apple-darwin.tar.gz +0 -0
  2. package/bin/binaries/probe-v0.6.0-rc240-aarch64-unknown-linux-musl.tar.gz +0 -0
  3. package/bin/binaries/probe-v0.6.0-rc240-x86_64-apple-darwin.tar.gz +0 -0
  4. package/bin/binaries/{probe-v0.6.0-rc238-x86_64-pc-windows-msvc.zip → probe-v0.6.0-rc240-x86_64-pc-windows-msvc.zip} +0 -0
  5. package/bin/binaries/probe-v0.6.0-rc240-x86_64-unknown-linux-musl.tar.gz +0 -0
  6. package/build/agent/ProbeAgent.js +20 -2
  7. package/build/agent/dsl/runtime.js +3 -16
  8. package/build/agent/dsl/validator.js +5 -4
  9. package/build/agent/index.js +127 -24
  10. package/build/agent/probeTool.js +9 -0
  11. package/build/agent/schemaUtils.js +34 -10
  12. package/build/agent/tools.js +9 -0
  13. package/build/index.js +5 -1
  14. package/build/tools/common.js +6 -0
  15. package/build/tools/executePlan.js +100 -2
  16. package/build/tools/index.js +3 -2
  17. package/cjs/agent/ProbeAgent.cjs +127 -24
  18. package/cjs/index.cjs +136 -24
  19. package/package.json +1 -1
  20. package/src/agent/ProbeAgent.js +20 -2
  21. package/src/agent/dsl/runtime.js +3 -16
  22. package/src/agent/dsl/validator.js +5 -4
  23. package/src/agent/probeTool.js +9 -0
  24. package/src/agent/schemaUtils.js +34 -10
  25. package/src/agent/tools.js +9 -0
  26. package/src/index.js +5 -1
  27. package/src/tools/common.js +6 -0
  28. package/src/tools/executePlan.js +100 -2
  29. package/src/tools/index.js +3 -2
  30. package/bin/binaries/probe-v0.6.0-rc238-aarch64-apple-darwin.tar.gz +0 -0
  31. package/bin/binaries/probe-v0.6.0-rc238-aarch64-unknown-linux-musl.tar.gz +0 -0
  32. package/bin/binaries/probe-v0.6.0-rc238-x86_64-apple-darwin.tar.gz +0 -0
  33. package/bin/binaries/probe-v0.6.0-rc238-x86_64-unknown-linux-musl.tar.gz +0 -0
@@ -49,6 +49,7 @@ import {
49
49
  delegateToolDefinition,
50
50
  analyzeAllToolDefinition,
51
51
  getExecutePlanToolDefinition,
52
+ getCleanupExecutePlanToolDefinition,
52
53
  bashToolDefinition,
53
54
  listFilesToolDefinition,
54
55
  searchFilesToolDefinition,
@@ -870,6 +871,10 @@ export class ProbeAgent {
870
871
  }
871
872
  if (this.enableExecutePlan && wrappedTools.executePlanToolInstance && isToolAllowed('execute_plan')) {
872
873
  this.toolImplementations.execute_plan = wrappedTools.executePlanToolInstance;
874
+ // cleanup_execute_plan is enabled together with execute_plan
875
+ if (wrappedTools.cleanupExecutePlanToolInstance && isToolAllowed('cleanup_execute_plan')) {
876
+ this.toolImplementations.cleanup_execute_plan = wrappedTools.cleanupExecutePlanToolInstance;
877
+ }
873
878
  } else if (wrappedTools.analyzeAllToolInstance && isToolAllowed('analyze_all')) {
874
879
  // analyze_all is fallback when execute_plan is not enabled
875
880
  this.toolImplementations.analyze_all = wrappedTools.analyzeAllToolInstance;
@@ -2582,6 +2587,10 @@ ${extractGuidance}
2582
2587
  if (isToolAllowed('listFiles')) dslFunctions.push('listFiles');
2583
2588
  if (this.enableBash && isToolAllowed('bash')) dslFunctions.push('bash');
2584
2589
  toolDefinitions += `${getExecutePlanToolDefinition(dslFunctions)}\n`;
2590
+ // cleanup_execute_plan is enabled together with execute_plan
2591
+ if (isToolAllowed('cleanup_execute_plan')) {
2592
+ toolDefinitions += `${getCleanupExecutePlanToolDefinition()}\n`;
2593
+ }
2585
2594
  } else if (isToolAllowed('analyze_all')) {
2586
2595
  // Fallback: only register analyze_all if execute_plan is not available
2587
2596
  toolDefinitions += `${analyzeAllToolDefinition}\n`;
@@ -2661,6 +2670,9 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
2661
2670
  }
2662
2671
  if (this.enableExecutePlan && isToolAllowed('execute_plan')) {
2663
2672
  availableToolsList += '- execute_plan: Execute a DSL program to orchestrate tool calls. ALWAYS use this for: questions containing "all"/"every"/"comprehensive"/"complete inventory", multi-topic analysis, open-ended discovery questions, or any task requiring full codebase coverage.\n';
2673
+ if (isToolAllowed('cleanup_execute_plan')) {
2674
+ availableToolsList += '- cleanup_execute_plan: Clean up output buffer and session store from previous execute_plan calls.\n';
2675
+ }
2664
2676
  } else if (isToolAllowed('analyze_all')) {
2665
2677
  availableToolsList += '- analyze_all: Process ALL data matching a query using map-reduce (for aggregate questions needing 100% coverage).\n';
2666
2678
  }
@@ -2891,8 +2903,10 @@ Follow these instructions carefully:
2891
2903
  // Track initial history length for storage
2892
2904
  const oldHistoryLength = this.history.length;
2893
2905
 
2894
- // Reset output buffer for this answer() call
2895
- if (this._outputBuffer) {
2906
+ // Reset output buffer for this answer() call — but NOT during schema correction recursion
2907
+ // When _schemaFormatted is true, this is a recursive call to fix JSON formatting,
2908
+ // and we must preserve the output buffer so the parent call can append it
2909
+ if (this._outputBuffer && !options?._schemaFormatted) {
2896
2910
  this._outputBuffer.items = [];
2897
2911
  }
2898
2912
 
@@ -3411,6 +3425,10 @@ Follow these instructions carefully:
3411
3425
  // Execute Plan tool (requires enableExecutePlan flag, supersedes analyze_all)
3412
3426
  if (this.enableExecutePlan && this.allowedTools.isEnabled('execute_plan')) {
3413
3427
  validTools.push('execute_plan');
3428
+ // cleanup_execute_plan is enabled together with execute_plan
3429
+ if (this.allowedTools.isEnabled('cleanup_execute_plan')) {
3430
+ validTools.push('cleanup_execute_plan');
3431
+ }
3414
3432
  } else if (this.allowedTools.isEnabled('analyze_all')) {
3415
3433
  validTools.push('analyze_all');
3416
3434
  }
@@ -4,7 +4,7 @@
4
4
  * Orchestrates the full pipeline:
5
5
  * 1. Validate (AST whitelist)
6
6
  * 2. Transform (inject await, wrap in async IIFE)
7
- * 3. Execute in SandboxJS with tool globals + timeout
7
+ * 3. Execute in SandboxJS with tool globals
8
8
  *
9
9
  * Returns the result or a structured error.
10
10
  */
@@ -25,7 +25,6 @@ const Sandbox = SandboxModule.default || SandboxModule;
25
25
  * @param {Object} [options.mcpTools={}] - MCP tool metadata
26
26
  * @param {Function} options.llmCall - Function for LLM() calls: (instruction, data, options?) => Promise<any>
27
27
  * @param {number} [options.mapConcurrency=3] - Concurrency limit for map()
28
- * @param {number} [options.timeoutMs=120000] - Execution timeout in milliseconds (default 2 min)
29
28
  * @param {number} [options.maxLoopIterations=5000] - Max iterations for while/for loops
30
29
  * @param {Object} [options.tracer=null] - SimpleAppTracer instance for OTEL telemetry
31
30
  * @returns {Object} Runtime with execute() method
@@ -37,7 +36,6 @@ export function createDSLRuntime(options) {
37
36
  mcpTools = {},
38
37
  llmCall,
39
38
  mapConcurrency = 3,
40
- timeoutMs = 120000,
41
39
  maxLoopIterations = 5000,
42
40
  tracer = null,
43
41
  sessionStore = {},
@@ -108,9 +106,8 @@ export function createDSLRuntime(options) {
108
106
  };
109
107
  }
110
108
 
111
- // Step 3: Execute in SandboxJS with timeout
109
+ // Step 3: Execute in SandboxJS
112
110
  tracer?.addEvent?.('dsl.phase.execute_start', {
113
- 'dsl.timeout_ms': timeoutMs,
114
111
  'dsl.max_loop_iterations': maxLoopIterations,
115
112
  });
116
113
 
@@ -147,20 +144,10 @@ export function createDSLRuntime(options) {
147
144
  };
148
145
  process.on('unhandledRejection', rejectionHandler);
149
146
 
150
- // Race execution against timeout
151
- let timeoutHandle;
152
- const executionPromise = exec().run();
153
- const timeoutPromise = new Promise((_, reject) => {
154
- timeoutHandle = setTimeout(() => {
155
- reject(new Error(`Execution timed out after ${Math.round(timeoutMs / 1000)}s. Script took too long — reduce the amount of work (fewer items, smaller data) or increase timeout.`));
156
- }, timeoutMs);
157
- });
158
-
159
147
  let result;
160
148
  try {
161
- result = await Promise.race([executionPromise, timeoutPromise]);
149
+ result = await exec().run();
162
150
  } finally {
163
- clearTimeout(timeoutHandle);
164
151
  // Delay handler removal — SandboxJS can throw async errors after execution completes
165
152
  setTimeout(() => {
166
153
  process.removeListener('unhandledRejection', rejectionHandler);
@@ -16,18 +16,23 @@ const ALLOWED_NODE_TYPES = new Set([
16
16
  'BlockStatement',
17
17
  'VariableDeclaration',
18
18
  'VariableDeclarator',
19
+ 'FunctionDeclaration',
19
20
  'ArrowFunctionExpression',
20
21
  'FunctionExpression',
21
22
  'CallExpression',
23
+ 'NewExpression',
22
24
  'MemberExpression',
23
25
  'Identifier',
24
26
  'Literal',
25
27
  'TemplateLiteral',
26
28
  'TemplateElement',
29
+ 'TaggedTemplateExpression',
27
30
  'ArrayExpression',
28
31
  'ObjectExpression',
29
32
  'SpreadElement',
30
33
  'IfStatement',
34
+ 'SwitchStatement',
35
+ 'SwitchCase',
31
36
  'ConditionalExpression',
32
37
  'ForOfStatement',
33
38
  'ForInStatement',
@@ -127,10 +132,6 @@ export function validateDSL(code) {
127
132
  errors.push(`Generator functions are not allowed at position ${node.start}`);
128
133
  }
129
134
 
130
- // Block regex literals — SandboxJS doesn't support them
131
- if (node.type === 'Literal' && node.regex) {
132
- errors.push(`Regex literals are not supported at position ${node.start}. Use String methods like indexOf(), includes(), startsWith() instead.`);
133
- }
134
135
 
135
136
  // Check identifiers against blocklist
136
137
  if (node.type === 'Identifier' && BLOCKED_IDENTIFIERS.has(node.name)) {
@@ -9905,7 +9905,7 @@ function resolveTargetPath(target, cwd) {
9905
9905
  }
9906
9906
  return filePart + suffix;
9907
9907
  }
9908
- var searchSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, bashSchema, analyzeAllSchema, executePlanSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, analyzeAllToolDefinition, bashToolDefinition, googleSearchToolDefinition, urlContextToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, analyzeAllDescription, DEFAULT_VALID_TOOLS;
9908
+ var searchSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, bashSchema, analyzeAllSchema, executePlanSchema, cleanupExecutePlanSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, analyzeAllToolDefinition, bashToolDefinition, googleSearchToolDefinition, urlContextToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, analyzeAllDescription, DEFAULT_VALID_TOOLS;
9909
9909
  var init_common = __esm({
9910
9910
  "src/tools/common.js"() {
9911
9911
  "use strict";
@@ -9953,6 +9953,10 @@ var init_common = __esm({
9953
9953
  code: external_exports.string().min(1).describe("JavaScript DSL code to execute. All function calls look synchronous \u2014 do NOT use async/await. Use map(items, fn) for batch operations. Use LLM(instruction, data) for AI processing."),
9954
9954
  description: external_exports.string().optional().describe("Human-readable description of what this plan does, for logging.")
9955
9955
  });
9956
+ cleanupExecutePlanSchema = external_exports.object({
9957
+ clearOutputBuffer: external_exports.boolean().optional().default(true).describe("Clear the output buffer from previous execute_plan calls"),
9958
+ clearSessionStore: external_exports.boolean().optional().default(false).describe("Clear the session store (persisted data across execute_plan calls)")
9959
+ });
9956
9960
  attemptCompletionSchema = {
9957
9961
  // Custom validation that requires result parameter but allows direct XML response
9958
9962
  safeParse: (params) => {
@@ -10300,6 +10304,7 @@ Capabilities:
10300
10304
  "delegate",
10301
10305
  "analyze_all",
10302
10306
  "execute_plan",
10307
+ "cleanup_execute_plan",
10303
10308
  "listSkills",
10304
10309
  "useSkill",
10305
10310
  "listFiles",
@@ -21499,9 +21504,6 @@ function validateDSL(code) {
21499
21504
  if (node.type === "FunctionExpression" && node.generator) {
21500
21505
  errors.push(`Generator functions are not allowed at position ${node.start}`);
21501
21506
  }
21502
- if (node.type === "Literal" && node.regex) {
21503
- errors.push(`Regex literals are not supported at position ${node.start}. Use String methods like indexOf(), includes(), startsWith() instead.`);
21504
- }
21505
21507
  if (node.type === "Identifier" && BLOCKED_IDENTIFIERS.has(node.name)) {
21506
21508
  errors.push(`Blocked identifier: '${node.name}' at position ${node.start}`);
21507
21509
  }
@@ -21540,18 +21542,23 @@ var init_validator = __esm({
21540
21542
  "BlockStatement",
21541
21543
  "VariableDeclaration",
21542
21544
  "VariableDeclarator",
21545
+ "FunctionDeclaration",
21543
21546
  "ArrowFunctionExpression",
21544
21547
  "FunctionExpression",
21545
21548
  "CallExpression",
21549
+ "NewExpression",
21546
21550
  "MemberExpression",
21547
21551
  "Identifier",
21548
21552
  "Literal",
21549
21553
  "TemplateLiteral",
21550
21554
  "TemplateElement",
21555
+ "TaggedTemplateExpression",
21551
21556
  "ArrayExpression",
21552
21557
  "ObjectExpression",
21553
21558
  "SpreadElement",
21554
21559
  "IfStatement",
21560
+ "SwitchStatement",
21561
+ "SwitchCase",
21555
21562
  "ConditionalExpression",
21556
21563
  "ForOfStatement",
21557
21564
  "ForInStatement",
@@ -22013,7 +22020,6 @@ function createDSLRuntime(options) {
22013
22020
  mcpTools = {},
22014
22021
  llmCall,
22015
22022
  mapConcurrency = 3,
22016
- timeoutMs = 12e4,
22017
22023
  maxLoopIterations = 5e3,
22018
22024
  tracer = null,
22019
22025
  sessionStore = {},
@@ -22068,7 +22074,6 @@ ${validation.errors.join("\n")}`,
22068
22074
  };
22069
22075
  }
22070
22076
  tracer?.addEvent?.("dsl.phase.execute_start", {
22071
- "dsl.timeout_ms": timeoutMs,
22072
22077
  "dsl.max_loop_iterations": maxLoopIterations
22073
22078
  });
22074
22079
  try {
@@ -22096,18 +22101,10 @@ ${validation.errors.join("\n")}`,
22096
22101
  escapedError = reason;
22097
22102
  };
22098
22103
  process.on("unhandledRejection", rejectionHandler);
22099
- let timeoutHandle;
22100
- const executionPromise = exec6().run();
22101
- const timeoutPromise = new Promise((_, reject2) => {
22102
- timeoutHandle = setTimeout(() => {
22103
- reject2(new Error(`Execution timed out after ${Math.round(timeoutMs / 1e3)}s. Script took too long \u2014 reduce the amount of work (fewer items, smaller data) or increase timeout.`));
22104
- }, timeoutMs);
22105
- });
22106
22104
  let result;
22107
22105
  try {
22108
- result = await Promise.race([executionPromise, timeoutPromise]);
22106
+ result = await exec6().run();
22109
22107
  } finally {
22110
- clearTimeout(timeoutHandle);
22111
22108
  setTimeout(() => {
22112
22109
  process.removeListener("unhandledRejection", rejectionHandler);
22113
22110
  }, 500);
@@ -29094,6 +29091,14 @@ Logs: ${result.logs.join(" | ")}` : "";
29094
29091
  "dsl.error": lastError.substring(0, 1e3)
29095
29092
  });
29096
29093
  }
29094
+ if (outputBuffer && outputBuffer.items && outputBuffer.items.length > 0) {
29095
+ const clearedChars = outputBuffer.items.reduce((sum, item) => sum + item.length, 0);
29096
+ outputBuffer.items = [];
29097
+ planSpan?.addEvent?.("dsl.auto_cleanup", {
29098
+ "cleanup.chars_cleared": clearedChars,
29099
+ "cleanup.reason": "all_retries_exhausted"
29100
+ });
29101
+ }
29097
29102
  finalOutput = `Plan execution failed after ${maxRetries} retries.
29098
29103
 
29099
29104
  Last error: ${lastError}`;
@@ -29106,6 +29111,9 @@ Last error: ${lastError}`;
29106
29111
  planSpan?.end?.();
29107
29112
  return finalOutput;
29108
29113
  } catch (e) {
29114
+ if (outputBuffer && outputBuffer.items && outputBuffer.items.length > 0) {
29115
+ outputBuffer.items = [];
29116
+ }
29109
29117
  planSpan?.setStatus?.("ERROR");
29110
29118
  planSpan?.addEvent?.("exception", {
29111
29119
  "exception.message": e.message,
@@ -29549,6 +29557,62 @@ output(table);
29549
29557
  return "Generated table with " + results.length + " items.";
29550
29558
  \`\`\``;
29551
29559
  }
29560
+ function createCleanupExecutePlanTool(options) {
29561
+ const { outputBuffer, sessionStore, tracer } = options;
29562
+ return tool4({
29563
+ description: "Clean up output buffer and session store from previous execute_plan calls. Use this when a previous execute_plan failed and left stale data, or before starting a fresh analysis.",
29564
+ parameters: cleanupExecutePlanSchema,
29565
+ execute: async ({ clearOutputBuffer = true, clearSessionStore = false }) => {
29566
+ const span = tracer?.createToolSpan?.("cleanup_execute_plan", {
29567
+ "cleanup.clear_output_buffer": clearOutputBuffer,
29568
+ "cleanup.clear_session_store": clearSessionStore
29569
+ }) || null;
29570
+ const results = [];
29571
+ try {
29572
+ if (clearOutputBuffer && outputBuffer) {
29573
+ const itemCount = outputBuffer.items?.length || 0;
29574
+ const charCount = outputBuffer.items?.reduce((sum, item) => sum + item.length, 0) || 0;
29575
+ outputBuffer.items = [];
29576
+ results.push(`Output buffer cleared (${itemCount} items, ${charCount} chars)`);
29577
+ }
29578
+ if (clearSessionStore && sessionStore) {
29579
+ const keyCount = Object.keys(sessionStore).length;
29580
+ for (const key of Object.keys(sessionStore)) {
29581
+ delete sessionStore[key];
29582
+ }
29583
+ results.push(`Session store cleared (${keyCount} keys)`);
29584
+ }
29585
+ const output = results.length > 0 ? `Cleanup complete:
29586
+ - ${results.join("\n- ")}` : "Nothing to clean up";
29587
+ span?.setAttributes?.({
29588
+ "cleanup.result": output,
29589
+ "cleanup.success": true
29590
+ });
29591
+ span?.setStatus?.("OK");
29592
+ span?.end?.();
29593
+ return output;
29594
+ } catch (e) {
29595
+ span?.setStatus?.("ERROR");
29596
+ span?.addEvent?.("exception", { "exception.message": e.message });
29597
+ span?.end?.();
29598
+ return `Cleanup failed: ${e.message}`;
29599
+ }
29600
+ }
29601
+ });
29602
+ }
29603
+ function getCleanupExecutePlanToolDefinition() {
29604
+ return `## cleanup_execute_plan
29605
+ Description: Clean up output buffer and session store from previous execute_plan calls. Use when a previous execute_plan failed and left stale data, or before starting a fresh analysis.
29606
+
29607
+ Parameters:
29608
+ - clearOutputBuffer: (optional, default: true) Clear the output buffer from previous execute_plan calls
29609
+ - clearSessionStore: (optional, default: false) Clear the session store (persisted data across execute_plan calls)
29610
+
29611
+ Example:
29612
+ <cleanup_execute_plan>
29613
+ <clearOutputBuffer>true</clearOutputBuffer>
29614
+ </cleanup_execute_plan>`;
29615
+ }
29552
29616
  var init_executePlan = __esm({
29553
29617
  "src/tools/executePlan.js"() {
29554
29618
  "use strict";
@@ -30344,6 +30408,13 @@ function createWrappedTools(baseTools) {
30344
30408
  baseTools.executePlanTool.execute
30345
30409
  );
30346
30410
  }
30411
+ if (baseTools.cleanupExecutePlanTool) {
30412
+ wrappedTools.cleanupExecutePlanToolInstance = wrapToolWithEmitter(
30413
+ baseTools.cleanupExecutePlanTool,
30414
+ "cleanup_execute_plan",
30415
+ baseTools.cleanupExecutePlanTool.execute
30416
+ );
30417
+ }
30347
30418
  if (baseTools.bashTool) {
30348
30419
  wrappedTools.bashToolInstance = wrapToolWithEmitter(
30349
30420
  baseTools.bashTool,
@@ -31253,6 +31324,9 @@ function createTools(configOptions) {
31253
31324
  }
31254
31325
  if (configOptions.enableExecutePlan && isToolAllowed("execute_plan")) {
31255
31326
  tools2.executePlanTool = createExecutePlanTool(configOptions);
31327
+ if (isToolAllowed("cleanup_execute_plan")) {
31328
+ tools2.cleanupExecutePlanTool = createCleanupExecutePlanTool(configOptions);
31329
+ }
31256
31330
  } else if (isToolAllowed("analyze_all")) {
31257
31331
  tools2.analyzeAllTool = analyzeAllTool(configOptions);
31258
31332
  }
@@ -68665,15 +68739,31 @@ function isSimpleTextWrapperSchema(schema) {
68665
68739
  return null;
68666
68740
  }
68667
68741
  const trimmed = schema.trim();
68668
- const simplePatterns = [
68669
- /^\{\s*["']?(\w+)["']?\s*:\s*["']?string["']?\s*\}$/i,
68670
- /^\{\s*["']?type["']?\s*:\s*["']?object["']?\s*,\s*["']?properties["']?\s*:\s*\{\s*["']?(\w+)["']?\s*:\s*\{\s*["']?type["']?\s*:\s*["']?string["']?\s*\}\s*\}\s*\}$/i
68671
- ];
68672
- for (const pattern of simplePatterns) {
68673
- const match2 = trimmed.match(pattern);
68674
- if (match2) {
68675
- return { fieldName: match2[1] };
68742
+ try {
68743
+ const parsed = JSON.parse(trimmed);
68744
+ if (typeof parsed !== "object" || parsed === null) {
68745
+ } else {
68746
+ const keys2 = Object.keys(parsed);
68747
+ if (keys2.length === 1 && parsed[keys2[0]] === "string") {
68748
+ return { fieldName: keys2[0] };
68749
+ }
68750
+ if (parsed.type === "object" && parsed.properties) {
68751
+ const propKeys = Object.keys(parsed.properties);
68752
+ if (propKeys.length === 1) {
68753
+ const prop = parsed.properties[propKeys[0]];
68754
+ if (prop && prop.type === "string") {
68755
+ return { fieldName: propKeys[0] };
68756
+ }
68757
+ }
68758
+ }
68759
+ return null;
68676
68760
  }
68761
+ } catch {
68762
+ }
68763
+ const simplePattern = /^\{\s*["']?(\w+)["']?\s*:\s*["']?string["']?\s*\}$/i;
68764
+ const match2 = trimmed.match(simplePattern);
68765
+ if (match2) {
68766
+ return { fieldName: match2[1] };
68677
68767
  }
68678
68768
  return null;
68679
68769
  }
@@ -81536,6 +81626,9 @@ var init_ProbeAgent = __esm({
81536
81626
  }
81537
81627
  if (this.enableExecutePlan && wrappedTools.executePlanToolInstance && isToolAllowed("execute_plan")) {
81538
81628
  this.toolImplementations.execute_plan = wrappedTools.executePlanToolInstance;
81629
+ if (wrappedTools.cleanupExecutePlanToolInstance && isToolAllowed("cleanup_execute_plan")) {
81630
+ this.toolImplementations.cleanup_execute_plan = wrappedTools.cleanupExecutePlanToolInstance;
81631
+ }
81539
81632
  } else if (wrappedTools.analyzeAllToolInstance && isToolAllowed("analyze_all")) {
81540
81633
  this.toolImplementations.analyze_all = wrappedTools.analyzeAllToolInstance;
81541
81634
  }
@@ -82909,6 +83002,10 @@ Workspace: ${this.allowedFolders.join(", ")}`;
82909
83002
  if (this.enableBash && isToolAllowed("bash")) dslFunctions.push("bash");
82910
83003
  toolDefinitions += `${getExecutePlanToolDefinition(dslFunctions)}
82911
83004
  `;
83005
+ if (isToolAllowed("cleanup_execute_plan")) {
83006
+ toolDefinitions += `${getCleanupExecutePlanToolDefinition()}
83007
+ `;
83008
+ }
82912
83009
  } else if (isToolAllowed("analyze_all")) {
82913
83010
  toolDefinitions += `${analyzeAllToolDefinition}
82914
83011
  `;
@@ -82984,6 +83081,9 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
82984
83081
  }
82985
83082
  if (this.enableExecutePlan && isToolAllowed("execute_plan")) {
82986
83083
  availableToolsList += '- execute_plan: Execute a DSL program to orchestrate tool calls. ALWAYS use this for: questions containing "all"/"every"/"comprehensive"/"complete inventory", multi-topic analysis, open-ended discovery questions, or any task requiring full codebase coverage.\n';
83084
+ if (isToolAllowed("cleanup_execute_plan")) {
83085
+ availableToolsList += "- cleanup_execute_plan: Clean up output buffer and session store from previous execute_plan calls.\n";
83086
+ }
82987
83087
  } else if (isToolAllowed("analyze_all")) {
82988
83088
  availableToolsList += "- analyze_all: Process ALL data matching a query using map-reduce (for aggregate questions needing 100% coverage).\n";
82989
83089
  }
@@ -83210,7 +83310,7 @@ You are working with a workspace. Available paths: ${workspaceDesc}
83210
83310
  }
83211
83311
  try {
83212
83312
  const oldHistoryLength = this.history.length;
83213
- if (this._outputBuffer) {
83313
+ if (this._outputBuffer && !options?._schemaFormatted) {
83214
83314
  this._outputBuffer.items = [];
83215
83315
  }
83216
83316
  if (this.enableTasks) {
@@ -83570,6 +83670,9 @@ You are working with a workspace. Available paths: ${workspaceDesc}
83570
83670
  }
83571
83671
  if (this.enableExecutePlan && this.allowedTools.isEnabled("execute_plan")) {
83572
83672
  validTools.push("execute_plan");
83673
+ if (this.allowedTools.isEnabled("cleanup_execute_plan")) {
83674
+ validTools.push("cleanup_execute_plan");
83675
+ }
83573
83676
  } else if (this.allowedTools.isEnabled("analyze_all")) {
83574
83677
  validTools.push("analyze_all");
83575
83678
  }
@@ -220,6 +220,15 @@ export function createWrappedTools(baseTools) {
220
220
  );
221
221
  }
222
222
 
223
+ // Wrap cleanup_execute_plan tool
224
+ if (baseTools.cleanupExecutePlanTool) {
225
+ wrappedTools.cleanupExecutePlanToolInstance = wrapToolWithEmitter(
226
+ baseTools.cleanupExecutePlanTool,
227
+ 'cleanup_execute_plan',
228
+ baseTools.cleanupExecutePlanTool.execute
229
+ );
230
+ }
231
+
223
232
  // Wrap bash tool
224
233
  if (baseTools.bashTool) {
225
234
  wrappedTools.bashToolInstance = wrapToolWithEmitter(
@@ -784,18 +784,42 @@ export function isSimpleTextWrapperSchema(schema) {
784
784
 
785
785
  const trimmed = schema.trim();
786
786
 
787
- // Match patterns like: {text: string}, {"text": "string"}, {response: string}, etc.
788
- // These are simple wrappers that just need a single text field
789
- const simplePatterns = [
790
- /^\{\s*["']?(\w+)["']?\s*:\s*["']?string["']?\s*\}$/i,
791
- /^\{\s*["']?type["']?\s*:\s*["']?object["']?\s*,\s*["']?properties["']?\s*:\s*\{\s*["']?(\w+)["']?\s*:\s*\{\s*["']?type["']?\s*:\s*["']?string["']?\s*\}\s*\}\s*\}$/i
792
- ];
787
+ // First, try parsing as JSON for full JSON Schema format
788
+ try {
789
+ const parsed = JSON.parse(trimmed);
790
+ if (typeof parsed !== 'object' || parsed === null) {
791
+ // Fall through to regex matching
792
+ } else {
793
+ // Shorthand JSON format: {"text": "string"} or {"fieldName": "string"}
794
+ const keys = Object.keys(parsed);
795
+ if (keys.length === 1 && parsed[keys[0]] === 'string') {
796
+ return { fieldName: keys[0] };
797
+ }
793
798
 
794
- for (const pattern of simplePatterns) {
795
- const match = trimmed.match(pattern);
796
- if (match) {
797
- return { fieldName: match[1] };
799
+ // Full JSON Schema format: {"type":"object","properties":{"text":{"type":"string",...}}}
800
+ // Handles schemas with "required", "description", and other extra fields
801
+ if (parsed.type === 'object' && parsed.properties) {
802
+ const propKeys = Object.keys(parsed.properties);
803
+ if (propKeys.length === 1) {
804
+ const prop = parsed.properties[propKeys[0]];
805
+ if (prop && prop.type === 'string') {
806
+ return { fieldName: propKeys[0] };
807
+ }
808
+ }
809
+ }
810
+
811
+ // Valid JSON but not a simple wrapper
812
+ return null;
798
813
  }
814
+ } catch {
815
+ // Not valid JSON, fall through to regex matching
816
+ }
817
+
818
+ // Fallback: regex matching for shorthand formats like {text: string}, {'text': 'string'}
819
+ const simplePattern = /^\{\s*["']?(\w+)["']?\s*:\s*["']?string["']?\s*\}$/i;
820
+ const match = trimmed.match(simplePattern);
821
+ if (match) {
822
+ return { fieldName: match[1] };
799
823
  }
800
824
 
801
825
  return null;
@@ -6,6 +6,7 @@ import {
6
6
  delegateTool,
7
7
  analyzeAllTool,
8
8
  createExecutePlanTool,
9
+ createCleanupExecutePlanTool,
9
10
  bashTool,
10
11
  editTool,
11
12
  createTool,
@@ -18,6 +19,7 @@ import {
18
19
  delegateSchema,
19
20
  analyzeAllSchema,
20
21
  executePlanSchema,
22
+ cleanupExecutePlanSchema,
21
23
  bashSchema,
22
24
  editSchema,
23
25
  createSchema,
@@ -27,6 +29,7 @@ import {
27
29
  delegateToolDefinition,
28
30
  analyzeAllToolDefinition,
29
31
  getExecutePlanToolDefinition,
32
+ getCleanupExecutePlanToolDefinition,
30
33
  bashToolDefinition,
31
34
  editToolDefinition,
32
35
  createToolDefinition,
@@ -63,6 +66,10 @@ export function createTools(configOptions) {
63
66
  }
64
67
  if (configOptions.enableExecutePlan && isToolAllowed('execute_plan')) {
65
68
  tools.executePlanTool = createExecutePlanTool(configOptions);
69
+ // cleanup_execute_plan is enabled together with execute_plan
70
+ if (isToolAllowed('cleanup_execute_plan')) {
71
+ tools.cleanupExecutePlanTool = createCleanupExecutePlanTool(configOptions);
72
+ }
66
73
  } else if (isToolAllowed('analyze_all')) {
67
74
  // analyze_all is fallback when execute_plan is not enabled
68
75
  tools.analyzeAllTool = analyzeAllTool(configOptions);
@@ -104,6 +111,7 @@ export {
104
111
  delegateSchema,
105
112
  analyzeAllSchema,
106
113
  executePlanSchema,
114
+ cleanupExecutePlanSchema,
107
115
  bashSchema,
108
116
  editSchema,
109
117
  createSchema,
@@ -114,6 +122,7 @@ export {
114
122
  delegateToolDefinition,
115
123
  analyzeAllToolDefinition,
116
124
  getExecutePlanToolDefinition,
125
+ getCleanupExecutePlanToolDefinition,
117
126
  bashToolDefinition,
118
127
  editToolDefinition,
119
128
  createToolDefinition,
package/build/index.js CHANGED
@@ -27,6 +27,7 @@ import {
27
27
  delegateSchema,
28
28
  analyzeAllSchema,
29
29
  executePlanSchema,
30
+ cleanupExecutePlanSchema,
30
31
  attemptCompletionSchema,
31
32
  bashSchema,
32
33
  searchToolDefinition,
@@ -47,7 +48,7 @@ import {
47
48
  createToolDefinition
48
49
  } from './tools/edit.js';
49
50
  import { searchTool, queryTool, extractTool, delegateTool, analyzeAllTool } from './tools/vercel.js';
50
- import { createExecutePlanTool, getExecutePlanToolDefinition } from './tools/executePlan.js';
51
+ import { createExecutePlanTool, getExecutePlanToolDefinition, createCleanupExecutePlanTool, getCleanupExecutePlanToolDefinition } from './tools/executePlan.js';
51
52
  import { bashTool } from './tools/bash.js';
52
53
  import { editTool, createTool } from './tools/edit.js';
53
54
  import { ProbeAgent } from './agent/ProbeAgent.js';
@@ -93,6 +94,7 @@ export {
93
94
  delegateTool,
94
95
  analyzeAllTool,
95
96
  createExecutePlanTool,
97
+ createCleanupExecutePlanTool,
96
98
  bashTool,
97
99
  editTool,
98
100
  createTool,
@@ -106,6 +108,7 @@ export {
106
108
  delegateSchema,
107
109
  analyzeAllSchema,
108
110
  executePlanSchema,
111
+ cleanupExecutePlanSchema,
109
112
  attemptCompletionSchema,
110
113
  bashSchema,
111
114
  editSchema,
@@ -117,6 +120,7 @@ export {
117
120
  delegateToolDefinition,
118
121
  analyzeAllToolDefinition,
119
122
  getExecutePlanToolDefinition,
123
+ getCleanupExecutePlanToolDefinition,
120
124
  attemptCompletionToolDefinition,
121
125
  bashToolDefinition,
122
126
  editToolDefinition,
@@ -59,6 +59,11 @@ export const executePlanSchema = z.object({
59
59
  description: z.string().optional().describe('Human-readable description of what this plan does, for logging.')
60
60
  });
61
61
 
62
+ export const cleanupExecutePlanSchema = z.object({
63
+ clearOutputBuffer: z.boolean().optional().default(true).describe('Clear the output buffer from previous execute_plan calls'),
64
+ clearSessionStore: z.boolean().optional().default(false).describe('Clear the session store (persisted data across execute_plan calls)')
65
+ });
66
+
62
67
  // Schema for the attempt_completion tool - flexible validation for direct XML response
63
68
  export const attemptCompletionSchema = {
64
69
  // Custom validation that requires result parameter but allows direct XML response
@@ -431,6 +436,7 @@ export const DEFAULT_VALID_TOOLS = [
431
436
  'delegate',
432
437
  'analyze_all',
433
438
  'execute_plan',
439
+ 'cleanup_execute_plan',
434
440
  'listSkills',
435
441
  'useSkill',
436
442
  'listFiles',