@probelabs/probe 0.6.0-rc265 → 0.6.0-rc267

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 (37) hide show
  1. package/bin/binaries/probe-v0.6.0-rc267-aarch64-apple-darwin.tar.gz +0 -0
  2. package/bin/binaries/probe-v0.6.0-rc267-aarch64-unknown-linux-musl.tar.gz +0 -0
  3. package/bin/binaries/probe-v0.6.0-rc267-x86_64-apple-darwin.tar.gz +0 -0
  4. package/bin/binaries/probe-v0.6.0-rc267-x86_64-pc-windows-msvc.zip +0 -0
  5. package/bin/binaries/probe-v0.6.0-rc267-x86_64-unknown-linux-musl.tar.gz +0 -0
  6. package/build/agent/ProbeAgent.js +644 -1442
  7. package/build/agent/engines/enhanced-vercel.js +0 -7
  8. package/build/agent/index.js +3941 -5940
  9. package/build/agent/mcp/index.js +6 -15
  10. package/build/agent/mcp/xmlBridge.js +24 -324
  11. package/build/agent/tasks/index.js +0 -1
  12. package/build/agent/tools.js +11 -181
  13. package/build/index.js +13 -35
  14. package/build/tools/common.js +15 -707
  15. package/build/tools/executePlan.js +2 -2
  16. package/build/tools/index.js +8 -11
  17. package/cjs/agent/ProbeAgent.cjs +3734 -5831
  18. package/cjs/index.cjs +4797 -6869
  19. package/package.json +1 -1
  20. package/src/agent/ProbeAgent.js +644 -1442
  21. package/src/agent/engines/enhanced-vercel.js +0 -7
  22. package/src/agent/index.js +10 -2
  23. package/src/agent/mcp/index.js +6 -15
  24. package/src/agent/mcp/xmlBridge.js +24 -324
  25. package/src/agent/tasks/index.js +0 -1
  26. package/src/agent/tools.js +11 -181
  27. package/src/index.js +13 -35
  28. package/src/tools/common.js +15 -707
  29. package/src/tools/executePlan.js +2 -2
  30. package/src/tools/index.js +8 -11
  31. package/bin/binaries/probe-v0.6.0-rc265-aarch64-apple-darwin.tar.gz +0 -0
  32. package/bin/binaries/probe-v0.6.0-rc265-aarch64-unknown-linux-musl.tar.gz +0 -0
  33. package/bin/binaries/probe-v0.6.0-rc265-x86_64-apple-darwin.tar.gz +0 -0
  34. package/bin/binaries/probe-v0.6.0-rc265-x86_64-pc-windows-msvc.zip +0 -0
  35. package/bin/binaries/probe-v0.6.0-rc265-x86_64-unknown-linux-musl.tar.gz +0 -0
  36. package/build/agent/xmlParsingUtils.js +0 -221
  37. package/src/agent/xmlParsingUtils.js +0 -221
@@ -393,7 +393,7 @@ export function createExecutePlanTool(options) {
393
393
  description: 'Execute a JavaScript DSL program to orchestrate tool calls. ' +
394
394
  'Use for batch processing, paginated APIs, multi-step workflows where intermediate data is large. ' +
395
395
  'Write simple synchronous-looking code — do NOT use async/await.',
396
- parameters: executePlanSchema,
396
+ inputSchema: executePlanSchema,
397
397
  execute: async ({ code, description }) => {
398
398
  // Generate a unique session ID for this execute_plan invocation
399
399
  // This ensures search pagination is isolated per execute_plan call
@@ -1051,7 +1051,7 @@ export function createCleanupExecutePlanTool(options) {
1051
1051
  return tool({
1052
1052
  description: 'Clean up output buffer and session store from previous execute_plan calls. ' +
1053
1053
  'Use this when a previous execute_plan failed and left stale data, or before starting a fresh analysis.',
1054
- parameters: cleanupExecutePlanSchema,
1054
+ inputSchema: cleanupExecutePlanSchema,
1055
1055
  execute: async ({ clearOutputBuffer = true, clearSessionStore = false }) => {
1056
1056
  const span = tracer?.createToolSpan?.('cleanup_execute_plan', {
1057
1057
  'cleanup.clear_output_buffer': clearOutputBuffer,
@@ -12,7 +12,7 @@ export { editTool, createTool, multiEditTool } from './edit.js';
12
12
  export { createSearchTool, createQueryTool, createExtractTool } from './langchain.js';
13
13
 
14
14
  // Export execute_plan and cleanup_execute_plan tools
15
- export { createExecutePlanTool, getExecutePlanToolDefinition, createCleanupExecutePlanTool, getCleanupExecutePlanToolDefinition } from './executePlan.js';
15
+ export { createExecutePlanTool, createCleanupExecutePlanTool } from './executePlan.js';
16
16
 
17
17
  // Export common schemas and utilities
18
18
  export {
@@ -24,15 +24,15 @@ export {
24
24
  executePlanSchema,
25
25
  cleanupExecutePlanSchema,
26
26
  delegateDescription,
27
- delegateToolDefinition,
28
27
  bashDescription,
29
- bashToolDefinition,
30
28
  attemptCompletionSchema,
31
- attemptCompletionToolDefinition,
32
29
  parseAndResolvePaths,
33
30
  resolveTargetPath,
34
- DEFAULT_VALID_TOOLS,
35
- buildToolTagPattern
31
+ listFilesSchema,
32
+ searchFilesSchema,
33
+ readImageSchema,
34
+ listSkillsSchema,
35
+ useSkillSchema
36
36
  } from './common.js';
37
37
 
38
38
  // Export edit and create schemas
@@ -42,10 +42,7 @@ export {
42
42
  multiEditSchema,
43
43
  editDescription,
44
44
  createDescription,
45
- multiEditDescription,
46
- editToolDefinition,
47
- createToolDefinition,
48
- multiEditToolDefinition
45
+ multiEditDescription
49
46
  } from './edit.js';
50
47
 
51
48
  // Export system message
@@ -66,4 +63,4 @@ const tools = {
66
63
  DEFAULT_SYSTEM_MESSAGE
67
64
  };
68
65
 
69
- export { tools };
66
+ export { tools };
@@ -1,221 +0,0 @@
1
- /**
2
- * Shared XML parsing utilities used by both CLI/SDK and MCP modes
3
- * This module contains the core logic for thinking tag removal and attempt_complete recovery
4
- */
5
-
6
- import { DEFAULT_VALID_TOOLS, buildToolTagPattern } from '../tools/common.js';
7
-
8
- /**
9
- * Remove thinking tags and their content from XML string
10
- * Handles both closed and unclosed thinking tags
11
- * @param {string} xmlString - The XML string to clean
12
- * @returns {string} - Cleaned XML string without thinking tags
13
- */
14
- export function removeThinkingTags(xmlString, validTools = DEFAULT_VALID_TOOLS) {
15
- let result = xmlString;
16
-
17
- // Remove all properly closed thinking tags first
18
- result = result.replace(/<thinking>[\s\S]*?<\/thinking>/g, '');
19
-
20
- // Handle unclosed thinking tags
21
- // Find any remaining <thinking> tag (which means it's unclosed)
22
- const thinkingIndex = result.indexOf('<thinking>');
23
- if (thinkingIndex !== -1) {
24
- // Check if there's a tool tag after the thinking tag
25
- // We want to preserve tool tags even if they're after unclosed thinking
26
- const afterThinking = result.substring(thinkingIndex + '<thinking>'.length);
27
-
28
- // Look for any tool tags in the remaining content
29
- // Use the provided valid tools list to build the pattern dynamically
30
- const toolPattern = buildToolTagPattern(validTools);
31
- const toolMatch = afterThinking.match(toolPattern);
32
-
33
- if (toolMatch) {
34
- // Found a tool tag - remove thinking tag and its content up to the tool tag
35
- const toolStart = thinkingIndex + '<thinking>'.length + toolMatch.index;
36
- result = result.substring(0, thinkingIndex) + result.substring(toolStart);
37
- } else {
38
- // No tool tag found - remove everything from <thinking> onwards
39
- result = result.substring(0, thinkingIndex);
40
- }
41
- }
42
-
43
- return result.trim();
44
- }
45
-
46
- /**
47
- * Extract thinking content for potential logging
48
- * Handles nested thinking tags by recursively stripping inner tags.
49
- * @param {string} xmlString - The XML string to extract from
50
- * @returns {string|null} - Thinking content (cleaned of nested tags) or null if not found
51
- */
52
- export function extractThinkingContent(xmlString) {
53
- const thinkingMatch = xmlString.match(/<thinking>([\s\S]*?)<\/thinking>/);
54
- if (!thinkingMatch) {
55
- return null;
56
- }
57
-
58
- let content = thinkingMatch[1].trim();
59
-
60
- // Handle nested thinking tags: if the extracted content itself starts with <thinking>,
61
- // recursively extract from it until we get clean content.
62
- // This handles: <thinking><thinking>content</thinking></thinking>
63
- // where non-greedy match captures "<thinking>content" (issue #439)
64
- while (content.startsWith('<thinking>')) {
65
- const innerMatch = content.match(/<thinking>([\s\S]*?)<\/thinking>/);
66
- if (innerMatch) {
67
- content = innerMatch[1].trim();
68
- } else {
69
- // Unclosed inner <thinking> tag - strip the opening tag and use remaining content
70
- // e.g., "<thinking>content" becomes "content"
71
- content = content.substring('<thinking>'.length).trim();
72
- break;
73
- }
74
- }
75
-
76
- // Also strip any remaining thinking tags that might be embedded in the content
77
- content = content.replace(/<\/?thinking>/g, '').trim();
78
-
79
- return content || null;
80
- }
81
-
82
- /**
83
- * Check for attempt_complete recovery patterns and return standardized result
84
- * @param {string} cleanedXmlString - XML string with thinking tags already removed
85
- * @param {Array<string>} validTools - List of valid tool names
86
- * @returns {Object|null} - Standardized attempt_completion result or null
87
- */
88
- export function checkAttemptCompleteRecovery(cleanedXmlString, validTools = []) {
89
- // Check for <attempt_completion> with content (with or without closing tag)
90
- // This handles: "<attempt_completion>content" or "<attempt_completion>content</attempt_completion>"
91
-
92
- // IMPORTANT: Use greedy match ([\s\S]*) instead of non-greedy ([\s\S]*?) to handle cases
93
- // where the content contains the string "</attempt_completion>" (e.g., in regex patterns or code examples).
94
- // We want to find the LAST occurrence of </attempt_completion>, not the first one.
95
- const openTagIndex = cleanedXmlString.indexOf('<attempt_completion>');
96
- if (openTagIndex !== -1) {
97
- const afterOpenTag = cleanedXmlString.substring(openTagIndex + '<attempt_completion>'.length);
98
- const closeTagIndex = cleanedXmlString.lastIndexOf('</attempt_completion>');
99
-
100
- let content;
101
- let hasClosingTag = false;
102
-
103
- if (closeTagIndex !== -1 && closeTagIndex >= openTagIndex + '<attempt_completion>'.length) {
104
- // Found a closing tag at or after the opening tag - extract content between them
105
- content = cleanedXmlString.substring(
106
- openTagIndex + '<attempt_completion>'.length,
107
- closeTagIndex
108
- ).trim();
109
- hasClosingTag = true;
110
- } else {
111
- // No closing tag - use content from opening tag to end of string
112
- content = afterOpenTag.trim();
113
- hasClosingTag = false;
114
- }
115
-
116
- if (content) {
117
- // If there's content after the tag, use it as the result
118
- return {
119
- toolName: 'attempt_completion',
120
- params: { result: content }
121
- };
122
- }
123
-
124
- // If the tag exists but is empty:
125
- // - With closing tag (e.g., "<attempt_completion></attempt_completion>"): use empty string
126
- // - Without closing tag (e.g., "<attempt_completion>"): use previous response
127
- return {
128
- toolName: 'attempt_completion',
129
- params: { result: hasClosingTag ? '' : '__PREVIOUS_RESPONSE__' }
130
- };
131
- }
132
-
133
- // Enhanced recovery logic for attempt_complete shorthand
134
- const attemptCompletePatterns = [
135
- // Standard shorthand with optional whitespace
136
- /^<attempt_complete>\s*$/,
137
- // Empty with proper closing tag (common case from the logs)
138
- /^<attempt_complete>\s*<\/attempt_complete>\s*$/,
139
- // Self-closing variant
140
- /^<attempt_complete\s*\/>\s*$/,
141
- // Incomplete opening tag (missing closing bracket)
142
- /^<attempt_complete\s*$/,
143
- // With trailing content (extract just the tag part) - must come after empty tag pattern
144
- /^<attempt_complete>(.*)$/s,
145
- // Self-closing with trailing content
146
- /^<attempt_complete\s*\/>(.*)$/s
147
- ];
148
-
149
- for (const pattern of attemptCompletePatterns) {
150
- const match = cleanedXmlString.match(pattern);
151
- if (match) {
152
- // Convert any form of attempt_complete to the standard format
153
- return {
154
- toolName: 'attempt_completion',
155
- params: { result: '__PREVIOUS_RESPONSE__' }
156
- };
157
- }
158
- }
159
-
160
- // Additional recovery: check if the string contains attempt_complete anywhere
161
- // and treat the entire response as a completion signal if no other tool tags are found
162
- if (cleanedXmlString.includes('<attempt_complete') && !hasOtherToolTags(cleanedXmlString, validTools)) {
163
- // This handles malformed cases where attempt_complete appears but is broken
164
- return {
165
- toolName: 'attempt_completion',
166
- params: { result: '__PREVIOUS_RESPONSE__' }
167
- };
168
- }
169
-
170
- return null;
171
- }
172
-
173
- /**
174
- * Helper function to check if the XML string contains other tool tags
175
- * @param {string} xmlString - The XML string to check
176
- * @param {string[]} validTools - List of valid tool names
177
- * @returns {boolean} - True if other tool tags are found
178
- */
179
- function hasOtherToolTags(xmlString, validTools = []) {
180
- // Use the shared canonical tool list as default
181
- const toolsToCheck = validTools.length > 0 ? validTools : DEFAULT_VALID_TOOLS;
182
-
183
- // Check for any tool tags other than attempt_complete variants
184
- for (const tool of toolsToCheck) {
185
- if (tool !== 'attempt_completion' && xmlString.includes(`<${tool}`)) {
186
- return true;
187
- }
188
- }
189
- return false;
190
- }
191
-
192
- /**
193
- * Apply the full thinking tag removal and attempt_complete recovery logic
194
- * This replicates the core logic from parseXmlToolCallWithThinking
195
- * @param {string} xmlString - The XML string to process
196
- * @param {Array<string>} validTools - List of valid tool names
197
- * @returns {Object} - Processing result with cleanedXml and potentialRecovery
198
- */
199
- export function processXmlWithThinkingAndRecovery(xmlString, validTools = []) {
200
- // Extract thinking content if present (for potential logging or analysis)
201
- const thinkingContent = extractThinkingContent(xmlString);
202
-
203
- // Remove thinking tags and their content from the XML string
204
- // Forward validTools so that tool tags (e.g. edit, create) inside unclosed
205
- // thinking blocks are preserved when they are in the valid tools list
206
- const cleanedXmlString = removeThinkingTags(xmlString, validTools.length > 0 ? validTools : undefined);
207
-
208
- // Check for attempt_complete recovery patterns
209
- const recoveryResult = checkAttemptCompleteRecovery(cleanedXmlString, validTools);
210
-
211
- // If debugging is enabled, log the thinking content
212
- if (process.env.DEBUG === '1' && thinkingContent) {
213
- console.log(`[DEBUG] AI Thinking Process:\n${thinkingContent}`);
214
- }
215
-
216
- return {
217
- cleanedXmlString,
218
- thinkingContent,
219
- recoveryResult
220
- };
221
- }
@@ -1,221 +0,0 @@
1
- /**
2
- * Shared XML parsing utilities used by both CLI/SDK and MCP modes
3
- * This module contains the core logic for thinking tag removal and attempt_complete recovery
4
- */
5
-
6
- import { DEFAULT_VALID_TOOLS, buildToolTagPattern } from '../tools/common.js';
7
-
8
- /**
9
- * Remove thinking tags and their content from XML string
10
- * Handles both closed and unclosed thinking tags
11
- * @param {string} xmlString - The XML string to clean
12
- * @returns {string} - Cleaned XML string without thinking tags
13
- */
14
- export function removeThinkingTags(xmlString, validTools = DEFAULT_VALID_TOOLS) {
15
- let result = xmlString;
16
-
17
- // Remove all properly closed thinking tags first
18
- result = result.replace(/<thinking>[\s\S]*?<\/thinking>/g, '');
19
-
20
- // Handle unclosed thinking tags
21
- // Find any remaining <thinking> tag (which means it's unclosed)
22
- const thinkingIndex = result.indexOf('<thinking>');
23
- if (thinkingIndex !== -1) {
24
- // Check if there's a tool tag after the thinking tag
25
- // We want to preserve tool tags even if they're after unclosed thinking
26
- const afterThinking = result.substring(thinkingIndex + '<thinking>'.length);
27
-
28
- // Look for any tool tags in the remaining content
29
- // Use the provided valid tools list to build the pattern dynamically
30
- const toolPattern = buildToolTagPattern(validTools);
31
- const toolMatch = afterThinking.match(toolPattern);
32
-
33
- if (toolMatch) {
34
- // Found a tool tag - remove thinking tag and its content up to the tool tag
35
- const toolStart = thinkingIndex + '<thinking>'.length + toolMatch.index;
36
- result = result.substring(0, thinkingIndex) + result.substring(toolStart);
37
- } else {
38
- // No tool tag found - remove everything from <thinking> onwards
39
- result = result.substring(0, thinkingIndex);
40
- }
41
- }
42
-
43
- return result.trim();
44
- }
45
-
46
- /**
47
- * Extract thinking content for potential logging
48
- * Handles nested thinking tags by recursively stripping inner tags.
49
- * @param {string} xmlString - The XML string to extract from
50
- * @returns {string|null} - Thinking content (cleaned of nested tags) or null if not found
51
- */
52
- export function extractThinkingContent(xmlString) {
53
- const thinkingMatch = xmlString.match(/<thinking>([\s\S]*?)<\/thinking>/);
54
- if (!thinkingMatch) {
55
- return null;
56
- }
57
-
58
- let content = thinkingMatch[1].trim();
59
-
60
- // Handle nested thinking tags: if the extracted content itself starts with <thinking>,
61
- // recursively extract from it until we get clean content.
62
- // This handles: <thinking><thinking>content</thinking></thinking>
63
- // where non-greedy match captures "<thinking>content" (issue #439)
64
- while (content.startsWith('<thinking>')) {
65
- const innerMatch = content.match(/<thinking>([\s\S]*?)<\/thinking>/);
66
- if (innerMatch) {
67
- content = innerMatch[1].trim();
68
- } else {
69
- // Unclosed inner <thinking> tag - strip the opening tag and use remaining content
70
- // e.g., "<thinking>content" becomes "content"
71
- content = content.substring('<thinking>'.length).trim();
72
- break;
73
- }
74
- }
75
-
76
- // Also strip any remaining thinking tags that might be embedded in the content
77
- content = content.replace(/<\/?thinking>/g, '').trim();
78
-
79
- return content || null;
80
- }
81
-
82
- /**
83
- * Check for attempt_complete recovery patterns and return standardized result
84
- * @param {string} cleanedXmlString - XML string with thinking tags already removed
85
- * @param {Array<string>} validTools - List of valid tool names
86
- * @returns {Object|null} - Standardized attempt_completion result or null
87
- */
88
- export function checkAttemptCompleteRecovery(cleanedXmlString, validTools = []) {
89
- // Check for <attempt_completion> with content (with or without closing tag)
90
- // This handles: "<attempt_completion>content" or "<attempt_completion>content</attempt_completion>"
91
-
92
- // IMPORTANT: Use greedy match ([\s\S]*) instead of non-greedy ([\s\S]*?) to handle cases
93
- // where the content contains the string "</attempt_completion>" (e.g., in regex patterns or code examples).
94
- // We want to find the LAST occurrence of </attempt_completion>, not the first one.
95
- const openTagIndex = cleanedXmlString.indexOf('<attempt_completion>');
96
- if (openTagIndex !== -1) {
97
- const afterOpenTag = cleanedXmlString.substring(openTagIndex + '<attempt_completion>'.length);
98
- const closeTagIndex = cleanedXmlString.lastIndexOf('</attempt_completion>');
99
-
100
- let content;
101
- let hasClosingTag = false;
102
-
103
- if (closeTagIndex !== -1 && closeTagIndex >= openTagIndex + '<attempt_completion>'.length) {
104
- // Found a closing tag at or after the opening tag - extract content between them
105
- content = cleanedXmlString.substring(
106
- openTagIndex + '<attempt_completion>'.length,
107
- closeTagIndex
108
- ).trim();
109
- hasClosingTag = true;
110
- } else {
111
- // No closing tag - use content from opening tag to end of string
112
- content = afterOpenTag.trim();
113
- hasClosingTag = false;
114
- }
115
-
116
- if (content) {
117
- // If there's content after the tag, use it as the result
118
- return {
119
- toolName: 'attempt_completion',
120
- params: { result: content }
121
- };
122
- }
123
-
124
- // If the tag exists but is empty:
125
- // - With closing tag (e.g., "<attempt_completion></attempt_completion>"): use empty string
126
- // - Without closing tag (e.g., "<attempt_completion>"): use previous response
127
- return {
128
- toolName: 'attempt_completion',
129
- params: { result: hasClosingTag ? '' : '__PREVIOUS_RESPONSE__' }
130
- };
131
- }
132
-
133
- // Enhanced recovery logic for attempt_complete shorthand
134
- const attemptCompletePatterns = [
135
- // Standard shorthand with optional whitespace
136
- /^<attempt_complete>\s*$/,
137
- // Empty with proper closing tag (common case from the logs)
138
- /^<attempt_complete>\s*<\/attempt_complete>\s*$/,
139
- // Self-closing variant
140
- /^<attempt_complete\s*\/>\s*$/,
141
- // Incomplete opening tag (missing closing bracket)
142
- /^<attempt_complete\s*$/,
143
- // With trailing content (extract just the tag part) - must come after empty tag pattern
144
- /^<attempt_complete>(.*)$/s,
145
- // Self-closing with trailing content
146
- /^<attempt_complete\s*\/>(.*)$/s
147
- ];
148
-
149
- for (const pattern of attemptCompletePatterns) {
150
- const match = cleanedXmlString.match(pattern);
151
- if (match) {
152
- // Convert any form of attempt_complete to the standard format
153
- return {
154
- toolName: 'attempt_completion',
155
- params: { result: '__PREVIOUS_RESPONSE__' }
156
- };
157
- }
158
- }
159
-
160
- // Additional recovery: check if the string contains attempt_complete anywhere
161
- // and treat the entire response as a completion signal if no other tool tags are found
162
- if (cleanedXmlString.includes('<attempt_complete') && !hasOtherToolTags(cleanedXmlString, validTools)) {
163
- // This handles malformed cases where attempt_complete appears but is broken
164
- return {
165
- toolName: 'attempt_completion',
166
- params: { result: '__PREVIOUS_RESPONSE__' }
167
- };
168
- }
169
-
170
- return null;
171
- }
172
-
173
- /**
174
- * Helper function to check if the XML string contains other tool tags
175
- * @param {string} xmlString - The XML string to check
176
- * @param {string[]} validTools - List of valid tool names
177
- * @returns {boolean} - True if other tool tags are found
178
- */
179
- function hasOtherToolTags(xmlString, validTools = []) {
180
- // Use the shared canonical tool list as default
181
- const toolsToCheck = validTools.length > 0 ? validTools : DEFAULT_VALID_TOOLS;
182
-
183
- // Check for any tool tags other than attempt_complete variants
184
- for (const tool of toolsToCheck) {
185
- if (tool !== 'attempt_completion' && xmlString.includes(`<${tool}`)) {
186
- return true;
187
- }
188
- }
189
- return false;
190
- }
191
-
192
- /**
193
- * Apply the full thinking tag removal and attempt_complete recovery logic
194
- * This replicates the core logic from parseXmlToolCallWithThinking
195
- * @param {string} xmlString - The XML string to process
196
- * @param {Array<string>} validTools - List of valid tool names
197
- * @returns {Object} - Processing result with cleanedXml and potentialRecovery
198
- */
199
- export function processXmlWithThinkingAndRecovery(xmlString, validTools = []) {
200
- // Extract thinking content if present (for potential logging or analysis)
201
- const thinkingContent = extractThinkingContent(xmlString);
202
-
203
- // Remove thinking tags and their content from the XML string
204
- // Forward validTools so that tool tags (e.g. edit, create) inside unclosed
205
- // thinking blocks are preserved when they are in the valid tools list
206
- const cleanedXmlString = removeThinkingTags(xmlString, validTools.length > 0 ? validTools : undefined);
207
-
208
- // Check for attempt_complete recovery patterns
209
- const recoveryResult = checkAttemptCompleteRecovery(cleanedXmlString, validTools);
210
-
211
- // If debugging is enabled, log the thinking content
212
- if (process.env.DEBUG === '1' && thinkingContent) {
213
- console.log(`[DEBUG] AI Thinking Process:\n${thinkingContent}`);
214
- }
215
-
216
- return {
217
- cleanedXmlString,
218
- thinkingContent,
219
- recoveryResult
220
- };
221
- }