@probelabs/probe 0.6.0-rc259 → 0.6.0-rc261
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.
- package/bin/binaries/probe-v0.6.0-rc261-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc261-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc261-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc261-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc261-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/bashCommandUtils.js +3 -0
- package/build/agent/bashPermissions.js +23 -0
- package/build/agent/index.js +263 -240
- package/build/agent/schemaUtils.js +40 -4
- package/build/agent/xmlParsingUtils.js +6 -4
- package/cjs/agent/ProbeAgent.cjs +403 -342
- package/cjs/index.cjs +403 -342
- package/package.json +1 -1
- package/src/agent/bashCommandUtils.js +3 -0
- package/src/agent/bashPermissions.js +23 -0
- package/src/agent/schemaUtils.js +40 -4
- package/src/agent/xmlParsingUtils.js +6 -4
- package/bin/binaries/probe-v0.6.0-rc259-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc259-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc259-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc259-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc259-x86_64-unknown-linux-musl.tar.gz +0 -0
package/package.json
CHANGED
|
@@ -127,6 +127,8 @@ export function parseSimpleCommand(command) {
|
|
|
127
127
|
/&&/, // Logical AND
|
|
128
128
|
/\|\|/, // Logical OR
|
|
129
129
|
/(?<!\\);/, // Command separator (but not escaped \;)
|
|
130
|
+
/\n/, // Newline command separator (multi-line commands)
|
|
131
|
+
/\r/, // Carriage return (CRLF line endings)
|
|
130
132
|
/&$/, // Background execution
|
|
131
133
|
/\$\(/, // Command substitution $()
|
|
132
134
|
/`/, // Command substitution ``
|
|
@@ -260,6 +262,7 @@ export function isComplexPattern(pattern) {
|
|
|
260
262
|
/&&/, // Logical AND
|
|
261
263
|
/\|\|/, // Logical OR
|
|
262
264
|
/;/, // Command separator
|
|
265
|
+
/\n/, // Newline command separator
|
|
263
266
|
/&$/, // Background execution
|
|
264
267
|
/\$\(/, // Command substitution $()
|
|
265
268
|
/`/, // Command substitution ``
|
|
@@ -402,6 +402,29 @@ export class BashPermissionChecker {
|
|
|
402
402
|
i++;
|
|
403
403
|
continue;
|
|
404
404
|
}
|
|
405
|
+
// Check for newline (command separator in multi-line scripts)
|
|
406
|
+
// Also handle \r\n (CRLF) line endings
|
|
407
|
+
if (char === '\n' || (char === '\r' && nextChar === '\n')) {
|
|
408
|
+
if (current.trim()) {
|
|
409
|
+
components.push(current.trim());
|
|
410
|
+
}
|
|
411
|
+
current = '';
|
|
412
|
+
if (char === '\r') {
|
|
413
|
+
i += 2; // Skip \r\n
|
|
414
|
+
} else {
|
|
415
|
+
i++;
|
|
416
|
+
}
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
if (char === '\r') {
|
|
420
|
+
// Bare \r without \n
|
|
421
|
+
if (current.trim()) {
|
|
422
|
+
components.push(current.trim());
|
|
423
|
+
}
|
|
424
|
+
current = '';
|
|
425
|
+
i++;
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
405
428
|
}
|
|
406
429
|
|
|
407
430
|
current += char;
|
package/src/agent/schemaUtils.js
CHANGED
|
@@ -266,6 +266,36 @@ function normalizeJsonQuotes(str) {
|
|
|
266
266
|
return result;
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
+
/**
|
|
270
|
+
* Check if a code block is embedded within a structured markdown document.
|
|
271
|
+
* Used to avoid extracting embedded JSON examples from markdown text.
|
|
272
|
+
* Issue #456: attempt_completion results containing markdown with JSON code block
|
|
273
|
+
* documentation examples were having the examples extracted as structured output.
|
|
274
|
+
*
|
|
275
|
+
* Normal AI behavior: AI wraps JSON answer in a code block with brief explanation text.
|
|
276
|
+
* Issue #456: AI returns a markdown document that contains JSON code blocks as examples.
|
|
277
|
+
*
|
|
278
|
+
* We distinguish these by checking if the surrounding text contains markdown structural
|
|
279
|
+
* elements (headings) which indicate a document rather than a brief explanation.
|
|
280
|
+
*
|
|
281
|
+
* @param {string} text - The full trimmed text
|
|
282
|
+
* @param {RegExpMatchArray} match - The regex match for the code block
|
|
283
|
+
* @returns {boolean} - true if the code block is embedded in a markdown document
|
|
284
|
+
*/
|
|
285
|
+
function isCodeBlockEmbeddedInDocument(text, match) {
|
|
286
|
+
const beforeBlock = text.substring(0, match.index).trim();
|
|
287
|
+
const afterBlock = text.substring(match.index + match[0].length).trim();
|
|
288
|
+
|
|
289
|
+
// Check if surrounding text contains markdown headings (lines starting with #)
|
|
290
|
+
// This is a strong signal that the content is a structured document, not just explanation text
|
|
291
|
+
const hasMarkdownHeadings = /^#{1,6}\s/m.test(beforeBlock) || /^#{1,6}\s/m.test(afterBlock);
|
|
292
|
+
if (hasMarkdownHeadings) {
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
|
|
269
299
|
/**
|
|
270
300
|
* Clean AI response by extracting JSON content when response contains JSON
|
|
271
301
|
* Only processes responses that contain JSON structures { or [
|
|
@@ -311,15 +341,20 @@ export function cleanSchemaResponse(response) {
|
|
|
311
341
|
}
|
|
312
342
|
|
|
313
343
|
// First, look for JSON after code block markers - similar to mermaid extraction
|
|
344
|
+
// Only extract from code blocks when they are the primary content (not embedded examples in markdown).
|
|
345
|
+
// Issue #456: When attempt_completion result contains markdown with embedded JSON code blocks
|
|
346
|
+
// as documentation examples, extracting those blocks produces wrong structured output.
|
|
347
|
+
// We check that there's no significant text content outside the code block.
|
|
348
|
+
|
|
314
349
|
// Try with json language specifier
|
|
315
350
|
const jsonBlockMatch = trimmed.match(/```json\s*\n([\s\S]*?)\n```/);
|
|
316
|
-
if (jsonBlockMatch) {
|
|
351
|
+
if (jsonBlockMatch && !isCodeBlockEmbeddedInDocument(trimmed, jsonBlockMatch)) {
|
|
317
352
|
return normalizeJsonQuotes(jsonBlockMatch[1].trim());
|
|
318
353
|
}
|
|
319
354
|
|
|
320
355
|
// Try any code block with JSON content
|
|
321
356
|
const anyBlockMatch = trimmed.match(/```\s*\n([{\[][\s\S]*?[}\]])\s*```/);
|
|
322
|
-
if (anyBlockMatch) {
|
|
357
|
+
if (anyBlockMatch && !isCodeBlockEmbeddedInDocument(trimmed, anyBlockMatch)) {
|
|
323
358
|
return normalizeJsonQuotes(anyBlockMatch[1].trim());
|
|
324
359
|
}
|
|
325
360
|
|
|
@@ -331,7 +366,7 @@ export function cleanSchemaResponse(response) {
|
|
|
331
366
|
|
|
332
367
|
for (const pattern of codeBlockPatterns) {
|
|
333
368
|
const match = trimmed.match(pattern);
|
|
334
|
-
if (match) {
|
|
369
|
+
if (match && !isCodeBlockEmbeddedInDocument(trimmed, match)) {
|
|
335
370
|
return normalizeJsonQuotes(match[1].trim());
|
|
336
371
|
}
|
|
337
372
|
}
|
|
@@ -345,10 +380,11 @@ export function cleanSchemaResponse(response) {
|
|
|
345
380
|
}
|
|
346
381
|
|
|
347
382
|
// Look for code block start followed immediately by JSON
|
|
383
|
+
// Only extract if the code block is not embedded in a structured markdown document
|
|
348
384
|
const codeBlockStartPattern = /```(?:json)?\s*\n?\s*([{\[])/;
|
|
349
385
|
const codeBlockMatch = trimmed.match(codeBlockStartPattern);
|
|
350
386
|
|
|
351
|
-
if (codeBlockMatch) {
|
|
387
|
+
if (codeBlockMatch && !isCodeBlockEmbeddedInDocument(trimmed, codeBlockMatch)) {
|
|
352
388
|
const startIndex = codeBlockMatch.index + codeBlockMatch[0].length - 1; // Position of the bracket
|
|
353
389
|
|
|
354
390
|
// Find the matching closing bracket
|
|
@@ -11,7 +11,7 @@ import { DEFAULT_VALID_TOOLS, buildToolTagPattern } from '../tools/common.js';
|
|
|
11
11
|
* @param {string} xmlString - The XML string to clean
|
|
12
12
|
* @returns {string} - Cleaned XML string without thinking tags
|
|
13
13
|
*/
|
|
14
|
-
export function removeThinkingTags(xmlString) {
|
|
14
|
+
export function removeThinkingTags(xmlString, validTools = DEFAULT_VALID_TOOLS) {
|
|
15
15
|
let result = xmlString;
|
|
16
16
|
|
|
17
17
|
// Remove all properly closed thinking tags first
|
|
@@ -26,8 +26,8 @@ export function removeThinkingTags(xmlString) {
|
|
|
26
26
|
const afterThinking = result.substring(thinkingIndex + '<thinking>'.length);
|
|
27
27
|
|
|
28
28
|
// Look for any tool tags in the remaining content
|
|
29
|
-
// Use the
|
|
30
|
-
const toolPattern = buildToolTagPattern(
|
|
29
|
+
// Use the provided valid tools list to build the pattern dynamically
|
|
30
|
+
const toolPattern = buildToolTagPattern(validTools);
|
|
31
31
|
const toolMatch = afterThinking.match(toolPattern);
|
|
32
32
|
|
|
33
33
|
if (toolMatch) {
|
|
@@ -201,7 +201,9 @@ export function processXmlWithThinkingAndRecovery(xmlString, validTools = []) {
|
|
|
201
201
|
const thinkingContent = extractThinkingContent(xmlString);
|
|
202
202
|
|
|
203
203
|
// Remove thinking tags and their content from the XML string
|
|
204
|
-
|
|
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);
|
|
205
207
|
|
|
206
208
|
// Check for attempt_complete recovery patterns
|
|
207
209
|
const recoveryResult = checkAttemptCompleteRecovery(cleanedXmlString, validTools);
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|