@probelabs/probe 0.6.0-rc161 → 0.6.0-rc162

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.
@@ -100,6 +100,13 @@ export function decodeHtmlEntities(text) {
100
100
  /**
101
101
  * Clean AI response by extracting JSON content when response contains JSON
102
102
  * Only processes responses that contain JSON structures { or [
103
+ *
104
+ * NOTE: This function handles both JSON extraction AND content stripping.
105
+ * Future improvement: Consider splitting into separate functions for better separation of concerns:
106
+ * - extractJsonContent() - Find and extract JSON from response
107
+ * - stripNonJsonContent() - Remove explanatory text while preserving validation-relevant content
108
+ * This would allow validation to run on full responses before content is discarded.
109
+ *
103
110
  * @param {string} response - Raw AI response
104
111
  * @returns {string} - Cleaned response with JSON boundaries extracted if applicable
105
112
  */
@@ -59,10 +59,30 @@ export function extractThinkingContent(xmlString) {
59
59
  export function checkAttemptCompleteRecovery(cleanedXmlString, validTools = []) {
60
60
  // Check for <attempt_completion> with content (with or without closing tag)
61
61
  // This handles: "<attempt_completion>content" or "<attempt_completion>content</attempt_completion>"
62
- const attemptCompletionMatch = cleanedXmlString.match(/<attempt_completion>([\s\S]*?)(?:<\/attempt_completion>|$)/);
63
- if (attemptCompletionMatch) {
64
- const content = attemptCompletionMatch[1].trim();
65
- const hasClosingTag = cleanedXmlString.includes('</attempt_completion>');
62
+
63
+ // IMPORTANT: Use greedy match ([\s\S]*) instead of non-greedy ([\s\S]*?) to handle cases
64
+ // where the content contains the string "</attempt_completion>" (e.g., in regex patterns or code examples).
65
+ // We want to find the LAST occurrence of </attempt_completion>, not the first one.
66
+ const openTagIndex = cleanedXmlString.indexOf('<attempt_completion>');
67
+ if (openTagIndex !== -1) {
68
+ const afterOpenTag = cleanedXmlString.substring(openTagIndex + '<attempt_completion>'.length);
69
+ const closeTagIndex = cleanedXmlString.lastIndexOf('</attempt_completion>');
70
+
71
+ let content;
72
+ let hasClosingTag = false;
73
+
74
+ if (closeTagIndex !== -1 && closeTagIndex >= openTagIndex + '<attempt_completion>'.length) {
75
+ // Found a closing tag at or after the opening tag - extract content between them
76
+ content = cleanedXmlString.substring(
77
+ openTagIndex + '<attempt_completion>'.length,
78
+ closeTagIndex
79
+ ).trim();
80
+ hasClosingTag = true;
81
+ } else {
82
+ // No closing tag - use content from opening tag to end of string
83
+ content = afterOpenTag.trim();
84
+ hasClosingTag = false;
85
+ }
66
86
 
67
87
  if (content) {
68
88
  // If there's content after the tag, use it as the result
@@ -384,7 +384,22 @@ export function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
384
384
  continue; // Tool not found, try next tool
385
385
  }
386
386
 
387
- let closeIndex = xmlString.indexOf(closeTag, openIndex + openTag.length);
387
+ // For attempt_completion, use lastIndexOf to find the LAST occurrence of closing tag
388
+ // This prevents issues where the content contains the closing tag string (e.g., in regex patterns)
389
+ // For other tools, use indexOf from the opening tag position
390
+ let closeIndex;
391
+ if (toolName === 'attempt_completion') {
392
+ // Find the last occurrence of the closing tag in the entire string
393
+ // This assumes attempt_completion doesn't have nested tags of the same name
394
+ closeIndex = xmlString.lastIndexOf(closeTag);
395
+ // Make sure the closing tag is after the opening tag
396
+ if (closeIndex !== -1 && closeIndex <= openIndex + openTag.length) {
397
+ closeIndex = -1; // Invalid, treat as no closing tag
398
+ }
399
+ } else {
400
+ closeIndex = xmlString.indexOf(closeTag, openIndex + openTag.length);
401
+ }
402
+
388
403
  let hasClosingTag = closeIndex !== -1;
389
404
 
390
405
  // If no closing tag found, use content until end of string