@probelabs/probe 0.6.0-rc239 → 0.6.0-rc241

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 (31) hide show
  1. package/bin/binaries/probe-v0.6.0-rc241-aarch64-apple-darwin.tar.gz +0 -0
  2. package/bin/binaries/{probe-v0.6.0-rc239-aarch64-unknown-linux-musl.tar.gz → probe-v0.6.0-rc241-aarch64-unknown-linux-musl.tar.gz} +0 -0
  3. package/bin/binaries/probe-v0.6.0-rc241-x86_64-apple-darwin.tar.gz +0 -0
  4. package/bin/binaries/probe-v0.6.0-rc241-x86_64-pc-windows-msvc.zip +0 -0
  5. package/bin/binaries/probe-v0.6.0-rc241-x86_64-unknown-linux-musl.tar.gz +0 -0
  6. package/build/agent/ProbeAgent.js +20 -2
  7. package/build/agent/dsl/validator.js +99 -8
  8. package/build/agent/index.js +213 -22
  9. package/build/agent/probeTool.js +9 -0
  10. package/build/agent/schemaUtils.js +34 -10
  11. package/build/agent/tools.js +9 -0
  12. package/build/index.js +5 -1
  13. package/build/tools/common.js +6 -0
  14. package/build/tools/executePlan.js +136 -2
  15. package/build/tools/index.js +3 -2
  16. package/cjs/agent/ProbeAgent.cjs +213 -22
  17. package/cjs/index.cjs +219 -19
  18. package/package.json +1 -1
  19. package/src/agent/ProbeAgent.js +20 -2
  20. package/src/agent/dsl/validator.js +99 -8
  21. package/src/agent/probeTool.js +9 -0
  22. package/src/agent/schemaUtils.js +34 -10
  23. package/src/agent/tools.js +9 -0
  24. package/src/index.js +5 -1
  25. package/src/tools/common.js +6 -0
  26. package/src/tools/executePlan.js +136 -2
  27. package/src/tools/index.js +3 -2
  28. package/bin/binaries/probe-v0.6.0-rc239-aarch64-apple-darwin.tar.gz +0 -0
  29. package/bin/binaries/probe-v0.6.0-rc239-x86_64-apple-darwin.tar.gz +0 -0
  30. package/bin/binaries/probe-v0.6.0-rc239-x86_64-pc-windows-msvc.zip +0 -0
  31. package/bin/binaries/probe-v0.6.0-rc239-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
  }
@@ -9,6 +9,81 @@
9
9
  import * as acorn from 'acorn';
10
10
  import * as walk from 'acorn-walk';
11
11
 
12
+ /**
13
+ * Convert a character offset to line and column numbers.
14
+ * @param {string} code - The source code
15
+ * @param {number} offset - Character offset
16
+ * @returns {{ line: number, column: number }}
17
+ */
18
+ function offsetToLineColumn(code, offset) {
19
+ const lines = code.split('\n');
20
+ let pos = 0;
21
+ for (let i = 0; i < lines.length; i++) {
22
+ const lineLength = lines[i].length + 1; // +1 for newline
23
+ if (pos + lineLength > offset) {
24
+ return { line: i + 1, column: offset - pos + 1 };
25
+ }
26
+ pos += lineLength;
27
+ }
28
+ return { line: lines.length, column: 1 };
29
+ }
30
+
31
+ /**
32
+ * Generate a code snippet with an arrow pointing to the error location.
33
+ * @param {string} code - The source code
34
+ * @param {number} line - Line number (1-based)
35
+ * @param {number} column - Column number (1-based)
36
+ * @param {number} contextLines - Number of lines to show before/after (default: 2)
37
+ * @returns {string}
38
+ */
39
+ function generateErrorSnippet(code, line, column, contextLines = 2) {
40
+ const lines = code.split('\n');
41
+ const startLine = Math.max(0, line - 1 - contextLines);
42
+ const endLine = Math.min(lines.length, line + contextLines);
43
+
44
+ const snippetLines = [];
45
+ const lineNumWidth = String(endLine).length;
46
+
47
+ for (let i = startLine; i < endLine; i++) {
48
+ const lineNum = String(i + 1).padStart(lineNumWidth, ' ');
49
+ const marker = (i + 1 === line) ? '>' : ' ';
50
+ snippetLines.push(`${marker} ${lineNum} | ${lines[i]}`);
51
+
52
+ // Add arrow line for the error line
53
+ if (i + 1 === line) {
54
+ const padding = ' '.repeat(lineNumWidth + 4); // " 123 | " prefix
55
+ const arrow = ' '.repeat(Math.max(0, column - 1)) + '^';
56
+ snippetLines.push(`${padding}${arrow}`);
57
+ }
58
+ }
59
+
60
+ return snippetLines.join('\n');
61
+ }
62
+
63
+ /**
64
+ * Format an error message with code snippet.
65
+ * @param {string} message - The error message
66
+ * @param {string} code - The source code
67
+ * @param {number} offset - Character offset (optional, use -1 if line/column provided)
68
+ * @param {number} line - Line number (optional)
69
+ * @param {number} column - Column number (optional)
70
+ * @returns {string}
71
+ */
72
+ function formatErrorWithSnippet(message, code, offset = -1, line = 0, column = 0) {
73
+ if (offset >= 0) {
74
+ const loc = offsetToLineColumn(code, offset);
75
+ line = loc.line;
76
+ column = loc.column;
77
+ }
78
+
79
+ if (line <= 0) {
80
+ return message;
81
+ }
82
+
83
+ const snippet = generateErrorSnippet(code, line, column);
84
+ return `${message}\n\n${snippet}`;
85
+ }
86
+
12
87
  // Node types the LLM is allowed to generate
13
88
  const ALLOWED_NODE_TYPES = new Set([
14
89
  'Program',
@@ -102,16 +177,32 @@ export function validateDSL(code) {
102
177
  ecmaVersion: 2022,
103
178
  sourceType: 'script',
104
179
  allowReturnOutsideFunction: true,
180
+ locations: true, // Enable location tracking for better error messages
105
181
  });
106
182
  } catch (e) {
107
- return { valid: false, errors: [`Syntax error: ${e.message}`] };
183
+ // Acorn errors have loc property with line/column
184
+ const line = e.loc?.line || 0;
185
+ const column = e.loc?.column ? e.loc.column + 1 : 0; // Acorn column is 0-based
186
+ const formattedError = formatErrorWithSnippet(
187
+ `Syntax error: ${e.message}`,
188
+ code,
189
+ -1,
190
+ line,
191
+ column
192
+ );
193
+ return { valid: false, errors: [formattedError] };
108
194
  }
109
195
 
196
+ // Helper to add error with code snippet
197
+ const addError = (message, position) => {
198
+ errors.push(formatErrorWithSnippet(message, code, position));
199
+ };
200
+
110
201
  // Step 2: Walk every node and validate
111
202
  walk.full(ast, (node) => {
112
203
  // Check node type against whitelist
113
204
  if (!ALLOWED_NODE_TYPES.has(node.type)) {
114
- errors.push(`Blocked node type: ${node.type} at position ${node.start}`);
205
+ addError(`Blocked node type: ${node.type}`, node.start);
115
206
  return;
116
207
  }
117
208
 
@@ -121,7 +212,7 @@ export function validateDSL(code) {
121
212
  node.type === 'FunctionExpression') &&
122
213
  node.async
123
214
  ) {
124
- errors.push(`Async functions are not allowed at position ${node.start}. Write synchronous code — the runtime handles async.`);
215
+ addError(`Async functions are not allowed. Write synchronous code — the runtime handles async.`, node.start);
125
216
  }
126
217
 
127
218
  // Block generator functions
@@ -129,19 +220,19 @@ export function validateDSL(code) {
129
220
  (node.type === 'FunctionExpression') &&
130
221
  node.generator
131
222
  ) {
132
- errors.push(`Generator functions are not allowed at position ${node.start}`);
223
+ addError(`Generator functions are not allowed`, node.start);
133
224
  }
134
225
 
135
226
 
136
227
  // Check identifiers against blocklist
137
228
  if (node.type === 'Identifier' && BLOCKED_IDENTIFIERS.has(node.name)) {
138
- errors.push(`Blocked identifier: '${node.name}' at position ${node.start}`);
229
+ addError(`Blocked identifier: '${node.name}'`, node.start);
139
230
  }
140
231
 
141
232
  // Check member expressions for blocked properties
142
233
  if (node.type === 'MemberExpression' && !node.computed) {
143
234
  if (node.property.type === 'Identifier' && BLOCKED_PROPERTIES.has(node.property.name)) {
144
- errors.push(`Blocked property access: '.${node.property.name}' at position ${node.property.start}`);
235
+ addError(`Blocked property access: '.${node.property.name}'`, node.property.start);
145
236
  }
146
237
  }
147
238
 
@@ -149,7 +240,7 @@ export function validateDSL(code) {
149
240
  if (node.type === 'MemberExpression' && node.computed) {
150
241
  if (node.property.type === 'Literal' && typeof node.property.value === 'string') {
151
242
  if (BLOCKED_PROPERTIES.has(node.property.value) || BLOCKED_IDENTIFIERS.has(node.property.value)) {
152
- errors.push(`Blocked computed property access: '["${node.property.value}"]' at position ${node.property.start}`);
243
+ addError(`Blocked computed property access: '["${node.property.value}"]'`, node.property.start);
153
244
  }
154
245
  }
155
246
  }
@@ -157,7 +248,7 @@ export function validateDSL(code) {
157
248
  // Block variable declarations named with blocked identifiers
158
249
  if (node.type === 'VariableDeclarator' && node.id.type === 'Identifier') {
159
250
  if (BLOCKED_IDENTIFIERS.has(node.id.name)) {
160
- errors.push(`Cannot declare variable with blocked name: '${node.id.name}' at position ${node.id.start}`);
251
+ addError(`Cannot declare variable with blocked name: '${node.id.name}'`, node.id.start);
161
252
  }
162
253
  }
163
254
  });
@@ -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",
@@ -21476,6 +21481,50 @@ var init_walk = __esm({
21476
21481
  });
21477
21482
 
21478
21483
  // src/agent/dsl/validator.js
21484
+ function offsetToLineColumn(code, offset2) {
21485
+ const lines = code.split("\n");
21486
+ let pos = 0;
21487
+ for (let i = 0; i < lines.length; i++) {
21488
+ const lineLength = lines[i].length + 1;
21489
+ if (pos + lineLength > offset2) {
21490
+ return { line: i + 1, column: offset2 - pos + 1 };
21491
+ }
21492
+ pos += lineLength;
21493
+ }
21494
+ return { line: lines.length, column: 1 };
21495
+ }
21496
+ function generateErrorSnippet(code, line, column, contextLines = 2) {
21497
+ const lines = code.split("\n");
21498
+ const startLine = Math.max(0, line - 1 - contextLines);
21499
+ const endLine = Math.min(lines.length, line + contextLines);
21500
+ const snippetLines = [];
21501
+ const lineNumWidth = String(endLine).length;
21502
+ for (let i = startLine; i < endLine; i++) {
21503
+ const lineNum = String(i + 1).padStart(lineNumWidth, " ");
21504
+ const marker = i + 1 === line ? ">" : " ";
21505
+ snippetLines.push(`${marker} ${lineNum} | ${lines[i]}`);
21506
+ if (i + 1 === line) {
21507
+ const padding = " ".repeat(lineNumWidth + 4);
21508
+ const arrow = " ".repeat(Math.max(0, column - 1)) + "^";
21509
+ snippetLines.push(`${padding}${arrow}`);
21510
+ }
21511
+ }
21512
+ return snippetLines.join("\n");
21513
+ }
21514
+ function formatErrorWithSnippet(message, code, offset2 = -1, line = 0, column = 0) {
21515
+ if (offset2 >= 0) {
21516
+ const loc = offsetToLineColumn(code, offset2);
21517
+ line = loc.line;
21518
+ column = loc.column;
21519
+ }
21520
+ if (line <= 0) {
21521
+ return message;
21522
+ }
21523
+ const snippet = generateErrorSnippet(code, line, column);
21524
+ return `${message}
21525
+
21526
+ ${snippet}`;
21527
+ }
21479
21528
  function validateDSL(code) {
21480
21529
  const errors = [];
21481
21530
  let ast;
@@ -21483,40 +21532,54 @@ function validateDSL(code) {
21483
21532
  ast = parse3(code, {
21484
21533
  ecmaVersion: 2022,
21485
21534
  sourceType: "script",
21486
- allowReturnOutsideFunction: true
21535
+ allowReturnOutsideFunction: true,
21536
+ locations: true
21537
+ // Enable location tracking for better error messages
21487
21538
  });
21488
21539
  } catch (e) {
21489
- return { valid: false, errors: [`Syntax error: ${e.message}`] };
21540
+ const line = e.loc?.line || 0;
21541
+ const column = e.loc?.column ? e.loc.column + 1 : 0;
21542
+ const formattedError = formatErrorWithSnippet(
21543
+ `Syntax error: ${e.message}`,
21544
+ code,
21545
+ -1,
21546
+ line,
21547
+ column
21548
+ );
21549
+ return { valid: false, errors: [formattedError] };
21490
21550
  }
21551
+ const addError = (message, position) => {
21552
+ errors.push(formatErrorWithSnippet(message, code, position));
21553
+ };
21491
21554
  full(ast, (node) => {
21492
21555
  if (!ALLOWED_NODE_TYPES.has(node.type)) {
21493
- errors.push(`Blocked node type: ${node.type} at position ${node.start}`);
21556
+ addError(`Blocked node type: ${node.type}`, node.start);
21494
21557
  return;
21495
21558
  }
21496
21559
  if ((node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression") && node.async) {
21497
- errors.push(`Async functions are not allowed at position ${node.start}. Write synchronous code \u2014 the runtime handles async.`);
21560
+ addError(`Async functions are not allowed. Write synchronous code \u2014 the runtime handles async.`, node.start);
21498
21561
  }
21499
21562
  if (node.type === "FunctionExpression" && node.generator) {
21500
- errors.push(`Generator functions are not allowed at position ${node.start}`);
21563
+ addError(`Generator functions are not allowed`, node.start);
21501
21564
  }
21502
21565
  if (node.type === "Identifier" && BLOCKED_IDENTIFIERS.has(node.name)) {
21503
- errors.push(`Blocked identifier: '${node.name}' at position ${node.start}`);
21566
+ addError(`Blocked identifier: '${node.name}'`, node.start);
21504
21567
  }
21505
21568
  if (node.type === "MemberExpression" && !node.computed) {
21506
21569
  if (node.property.type === "Identifier" && BLOCKED_PROPERTIES.has(node.property.name)) {
21507
- errors.push(`Blocked property access: '.${node.property.name}' at position ${node.property.start}`);
21570
+ addError(`Blocked property access: '.${node.property.name}'`, node.property.start);
21508
21571
  }
21509
21572
  }
21510
21573
  if (node.type === "MemberExpression" && node.computed) {
21511
21574
  if (node.property.type === "Literal" && typeof node.property.value === "string") {
21512
21575
  if (BLOCKED_PROPERTIES.has(node.property.value) || BLOCKED_IDENTIFIERS.has(node.property.value)) {
21513
- errors.push(`Blocked computed property access: '["${node.property.value}"]' at position ${node.property.start}`);
21576
+ addError(`Blocked computed property access: '["${node.property.value}"]'`, node.property.start);
21514
21577
  }
21515
21578
  }
21516
21579
  }
21517
21580
  if (node.type === "VariableDeclarator" && node.id.type === "Identifier") {
21518
21581
  if (BLOCKED_IDENTIFIERS.has(node.id.name)) {
21519
- errors.push(`Cannot declare variable with blocked name: '${node.id.name}' at position ${node.id.start}`);
21582
+ addError(`Cannot declare variable with blocked name: '${node.id.name}'`, node.id.start);
21520
21583
  }
21521
21584
  }
21522
21585
  });
@@ -28831,10 +28894,32 @@ var init_esm5 = __esm({
28831
28894
 
28832
28895
  // src/tools/executePlan.js
28833
28896
  import { tool as tool4 } from "ai";
28897
+ function decodeHtmlEntities(str) {
28898
+ const entities = {
28899
+ "&amp;": "&",
28900
+ "&lt;": "<",
28901
+ "&gt;": ">",
28902
+ "&quot;": '"',
28903
+ "&apos;": "'",
28904
+ "&#39;": "'",
28905
+ "&#x27;": "'"
28906
+ };
28907
+ let result = str.replace(/&(?:amp|lt|gt|quot|apos|#39|#x27);/gi, (match2) => {
28908
+ return entities[match2.toLowerCase()] || match2;
28909
+ });
28910
+ result = result.replace(/&#(\d+);/g, (match2, dec) => {
28911
+ return String.fromCharCode(parseInt(dec, 10));
28912
+ });
28913
+ result = result.replace(/&#x([0-9a-f]+);/gi, (match2, hex) => {
28914
+ return String.fromCharCode(parseInt(hex, 16));
28915
+ });
28916
+ return result;
28917
+ }
28834
28918
  function stripCodeWrapping(code) {
28835
28919
  let s = String(code || "");
28836
28920
  s = s.replace(/^```(?:javascript|js)?\n?/gm, "").replace(/```$/gm, "");
28837
28921
  s = s.replace(/<\/?(?:execute_plan|code)>/g, "");
28922
+ s = decodeHtmlEntities(s);
28838
28923
  return s.trim();
28839
28924
  }
28840
28925
  function buildToolImplementations(configOptions) {
@@ -29086,6 +29171,14 @@ Logs: ${result.logs.join(" | ")}` : "";
29086
29171
  "dsl.error": lastError.substring(0, 1e3)
29087
29172
  });
29088
29173
  }
29174
+ if (outputBuffer && outputBuffer.items && outputBuffer.items.length > 0) {
29175
+ const clearedChars = outputBuffer.items.reduce((sum, item) => sum + item.length, 0);
29176
+ outputBuffer.items = [];
29177
+ planSpan?.addEvent?.("dsl.auto_cleanup", {
29178
+ "cleanup.chars_cleared": clearedChars,
29179
+ "cleanup.reason": "all_retries_exhausted"
29180
+ });
29181
+ }
29089
29182
  finalOutput = `Plan execution failed after ${maxRetries} retries.
29090
29183
 
29091
29184
  Last error: ${lastError}`;
@@ -29098,6 +29191,9 @@ Last error: ${lastError}`;
29098
29191
  planSpan?.end?.();
29099
29192
  return finalOutput;
29100
29193
  } catch (e) {
29194
+ if (outputBuffer && outputBuffer.items && outputBuffer.items.length > 0) {
29195
+ outputBuffer.items = [];
29196
+ }
29101
29197
  planSpan?.setStatus?.("ERROR");
29102
29198
  planSpan?.addEvent?.("exception", {
29103
29199
  "exception.message": e.message,
@@ -29541,6 +29637,62 @@ output(table);
29541
29637
  return "Generated table with " + results.length + " items.";
29542
29638
  \`\`\``;
29543
29639
  }
29640
+ function createCleanupExecutePlanTool(options) {
29641
+ const { outputBuffer, sessionStore, tracer } = options;
29642
+ return tool4({
29643
+ 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.",
29644
+ parameters: cleanupExecutePlanSchema,
29645
+ execute: async ({ clearOutputBuffer = true, clearSessionStore = false }) => {
29646
+ const span = tracer?.createToolSpan?.("cleanup_execute_plan", {
29647
+ "cleanup.clear_output_buffer": clearOutputBuffer,
29648
+ "cleanup.clear_session_store": clearSessionStore
29649
+ }) || null;
29650
+ const results = [];
29651
+ try {
29652
+ if (clearOutputBuffer && outputBuffer) {
29653
+ const itemCount = outputBuffer.items?.length || 0;
29654
+ const charCount = outputBuffer.items?.reduce((sum, item) => sum + item.length, 0) || 0;
29655
+ outputBuffer.items = [];
29656
+ results.push(`Output buffer cleared (${itemCount} items, ${charCount} chars)`);
29657
+ }
29658
+ if (clearSessionStore && sessionStore) {
29659
+ const keyCount = Object.keys(sessionStore).length;
29660
+ for (const key of Object.keys(sessionStore)) {
29661
+ delete sessionStore[key];
29662
+ }
29663
+ results.push(`Session store cleared (${keyCount} keys)`);
29664
+ }
29665
+ const output = results.length > 0 ? `Cleanup complete:
29666
+ - ${results.join("\n- ")}` : "Nothing to clean up";
29667
+ span?.setAttributes?.({
29668
+ "cleanup.result": output,
29669
+ "cleanup.success": true
29670
+ });
29671
+ span?.setStatus?.("OK");
29672
+ span?.end?.();
29673
+ return output;
29674
+ } catch (e) {
29675
+ span?.setStatus?.("ERROR");
29676
+ span?.addEvent?.("exception", { "exception.message": e.message });
29677
+ span?.end?.();
29678
+ return `Cleanup failed: ${e.message}`;
29679
+ }
29680
+ }
29681
+ });
29682
+ }
29683
+ function getCleanupExecutePlanToolDefinition() {
29684
+ return `## cleanup_execute_plan
29685
+ 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.
29686
+
29687
+ Parameters:
29688
+ - clearOutputBuffer: (optional, default: true) Clear the output buffer from previous execute_plan calls
29689
+ - clearSessionStore: (optional, default: false) Clear the session store (persisted data across execute_plan calls)
29690
+
29691
+ Example:
29692
+ <cleanup_execute_plan>
29693
+ <clearOutputBuffer>true</clearOutputBuffer>
29694
+ </cleanup_execute_plan>`;
29695
+ }
29544
29696
  var init_executePlan = __esm({
29545
29697
  "src/tools/executePlan.js"() {
29546
29698
  "use strict";
@@ -30336,6 +30488,13 @@ function createWrappedTools(baseTools) {
30336
30488
  baseTools.executePlanTool.execute
30337
30489
  );
30338
30490
  }
30491
+ if (baseTools.cleanupExecutePlanTool) {
30492
+ wrappedTools.cleanupExecutePlanToolInstance = wrapToolWithEmitter(
30493
+ baseTools.cleanupExecutePlanTool,
30494
+ "cleanup_execute_plan",
30495
+ baseTools.cleanupExecutePlanTool.execute
30496
+ );
30497
+ }
30339
30498
  if (baseTools.bashTool) {
30340
30499
  wrappedTools.bashToolInstance = wrapToolWithEmitter(
30341
30500
  baseTools.bashTool,
@@ -31245,6 +31404,9 @@ function createTools(configOptions) {
31245
31404
  }
31246
31405
  if (configOptions.enableExecutePlan && isToolAllowed("execute_plan")) {
31247
31406
  tools2.executePlanTool = createExecutePlanTool(configOptions);
31407
+ if (isToolAllowed("cleanup_execute_plan")) {
31408
+ tools2.cleanupExecutePlanTool = createCleanupExecutePlanTool(configOptions);
31409
+ }
31248
31410
  } else if (isToolAllowed("analyze_all")) {
31249
31411
  tools2.analyzeAllTool = analyzeAllTool(configOptions);
31250
31412
  }
@@ -68122,7 +68284,7 @@ __export(schemaUtils_exports, {
68122
68284
  createJsonCorrectionPrompt: () => createJsonCorrectionPrompt,
68123
68285
  createMermaidCorrectionPrompt: () => createMermaidCorrectionPrompt,
68124
68286
  createSchemaDefinitionCorrectionPrompt: () => createSchemaDefinitionCorrectionPrompt,
68125
- decodeHtmlEntities: () => decodeHtmlEntities,
68287
+ decodeHtmlEntities: () => decodeHtmlEntities2,
68126
68288
  extractMermaidFromJson: () => extractMermaidFromJson,
68127
68289
  extractMermaidFromMarkdown: () => extractMermaidFromMarkdown,
68128
68290
  generateExampleFromSchema: () => generateExampleFromSchema,
@@ -68227,7 +68389,7 @@ function enforceNoAdditionalProperties(schema) {
68227
68389
  applyRecursively(cloned);
68228
68390
  return cloned;
68229
68391
  }
68230
- function decodeHtmlEntities(text) {
68392
+ function decodeHtmlEntities2(text) {
68231
68393
  if (!text || typeof text !== "string") {
68232
68394
  return text;
68233
68395
  }
@@ -68657,15 +68819,31 @@ function isSimpleTextWrapperSchema(schema) {
68657
68819
  return null;
68658
68820
  }
68659
68821
  const trimmed = schema.trim();
68660
- const simplePatterns = [
68661
- /^\{\s*["']?(\w+)["']?\s*:\s*["']?string["']?\s*\}$/i,
68662
- /^\{\s*["']?type["']?\s*:\s*["']?object["']?\s*,\s*["']?properties["']?\s*:\s*\{\s*["']?(\w+)["']?\s*:\s*\{\s*["']?type["']?\s*:\s*["']?string["']?\s*\}\s*\}\s*\}$/i
68663
- ];
68664
- for (const pattern of simplePatterns) {
68665
- const match2 = trimmed.match(pattern);
68666
- if (match2) {
68667
- return { fieldName: match2[1] };
68822
+ try {
68823
+ const parsed = JSON.parse(trimmed);
68824
+ if (typeof parsed !== "object" || parsed === null) {
68825
+ } else {
68826
+ const keys2 = Object.keys(parsed);
68827
+ if (keys2.length === 1 && parsed[keys2[0]] === "string") {
68828
+ return { fieldName: keys2[0] };
68829
+ }
68830
+ if (parsed.type === "object" && parsed.properties) {
68831
+ const propKeys = Object.keys(parsed.properties);
68832
+ if (propKeys.length === 1) {
68833
+ const prop = parsed.properties[propKeys[0]];
68834
+ if (prop && prop.type === "string") {
68835
+ return { fieldName: propKeys[0] };
68836
+ }
68837
+ }
68838
+ }
68839
+ return null;
68668
68840
  }
68841
+ } catch {
68842
+ }
68843
+ const simplePattern = /^\{\s*["']?(\w+)["']?\s*:\s*["']?string["']?\s*\}$/i;
68844
+ const match2 = trimmed.match(simplePattern);
68845
+ if (match2) {
68846
+ return { fieldName: match2[1] };
68669
68847
  }
68670
68848
  return null;
68671
68849
  }
@@ -69654,7 +69832,7 @@ When presented with a broken Mermaid diagram, analyze it thoroughly and provide
69654
69832
  * @returns {Promise<string>} - The corrected Mermaid diagram
69655
69833
  */
69656
69834
  async fixMermaidDiagram(diagramContent, originalErrors = [], diagramInfo = {}) {
69657
- const decodedContent = decodeHtmlEntities(diagramContent);
69835
+ const decodedContent = decodeHtmlEntities2(diagramContent);
69658
69836
  if (decodedContent !== diagramContent) {
69659
69837
  try {
69660
69838
  const quickValidation = await validateMermaidDiagram(decodedContent);
@@ -81528,6 +81706,9 @@ var init_ProbeAgent = __esm({
81528
81706
  }
81529
81707
  if (this.enableExecutePlan && wrappedTools.executePlanToolInstance && isToolAllowed("execute_plan")) {
81530
81708
  this.toolImplementations.execute_plan = wrappedTools.executePlanToolInstance;
81709
+ if (wrappedTools.cleanupExecutePlanToolInstance && isToolAllowed("cleanup_execute_plan")) {
81710
+ this.toolImplementations.cleanup_execute_plan = wrappedTools.cleanupExecutePlanToolInstance;
81711
+ }
81531
81712
  } else if (wrappedTools.analyzeAllToolInstance && isToolAllowed("analyze_all")) {
81532
81713
  this.toolImplementations.analyze_all = wrappedTools.analyzeAllToolInstance;
81533
81714
  }
@@ -82901,6 +83082,10 @@ Workspace: ${this.allowedFolders.join(", ")}`;
82901
83082
  if (this.enableBash && isToolAllowed("bash")) dslFunctions.push("bash");
82902
83083
  toolDefinitions += `${getExecutePlanToolDefinition(dslFunctions)}
82903
83084
  `;
83085
+ if (isToolAllowed("cleanup_execute_plan")) {
83086
+ toolDefinitions += `${getCleanupExecutePlanToolDefinition()}
83087
+ `;
83088
+ }
82904
83089
  } else if (isToolAllowed("analyze_all")) {
82905
83090
  toolDefinitions += `${analyzeAllToolDefinition}
82906
83091
  `;
@@ -82976,6 +83161,9 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
82976
83161
  }
82977
83162
  if (this.enableExecutePlan && isToolAllowed("execute_plan")) {
82978
83163
  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';
83164
+ if (isToolAllowed("cleanup_execute_plan")) {
83165
+ availableToolsList += "- cleanup_execute_plan: Clean up output buffer and session store from previous execute_plan calls.\n";
83166
+ }
82979
83167
  } else if (isToolAllowed("analyze_all")) {
82980
83168
  availableToolsList += "- analyze_all: Process ALL data matching a query using map-reduce (for aggregate questions needing 100% coverage).\n";
82981
83169
  }
@@ -83202,7 +83390,7 @@ You are working with a workspace. Available paths: ${workspaceDesc}
83202
83390
  }
83203
83391
  try {
83204
83392
  const oldHistoryLength = this.history.length;
83205
- if (this._outputBuffer) {
83393
+ if (this._outputBuffer && !options?._schemaFormatted) {
83206
83394
  this._outputBuffer.items = [];
83207
83395
  }
83208
83396
  if (this.enableTasks) {
@@ -83562,6 +83750,9 @@ You are working with a workspace. Available paths: ${workspaceDesc}
83562
83750
  }
83563
83751
  if (this.enableExecutePlan && this.allowedTools.isEnabled("execute_plan")) {
83564
83752
  validTools.push("execute_plan");
83753
+ if (this.allowedTools.isEnabled("cleanup_execute_plan")) {
83754
+ validTools.push("cleanup_execute_plan");
83755
+ }
83565
83756
  } else if (this.allowedTools.isEnabled("analyze_all")) {
83566
83757
  validTools.push("analyze_all");
83567
83758
  }
@@ -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(