@probelabs/probe 0.6.0-rc65 → 0.6.0-rc67
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/build/agent/ProbeAgent.js +31 -10
- package/build/agent/index.js +84 -21
- package/build/agent/schemaUtils.js +77 -16
- package/cjs/agent/ProbeAgent.cjs +84 -21
- package/cjs/index.cjs +84 -21
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +31 -10
- package/src/agent/schemaUtils.js +77 -16
|
@@ -729,7 +729,19 @@ When troubleshooting:
|
|
|
729
729
|
|
|
730
730
|
try {
|
|
731
731
|
// Step 1: Make a follow-up call to format according to schema
|
|
732
|
-
const schemaPrompt = `
|
|
732
|
+
const schemaPrompt = `CRITICAL: You MUST respond with ONLY valid JSON that matches this schema. Ignore any previous response format or instructions.
|
|
733
|
+
|
|
734
|
+
Schema:
|
|
735
|
+
${options.schema}
|
|
736
|
+
|
|
737
|
+
REQUIREMENTS:
|
|
738
|
+
- Return ONLY the JSON object/array
|
|
739
|
+
- NO additional text, explanations, or markdown
|
|
740
|
+
- NO code blocks or formatting
|
|
741
|
+
- The JSON must be parseable by JSON.parse()
|
|
742
|
+
- DO NOT include any conversational text like "Hello" or explanations
|
|
743
|
+
|
|
744
|
+
Convert your previous response content into this JSON format now. Return nothing but valid JSON.`;
|
|
733
745
|
|
|
734
746
|
// Call answer recursively with _schemaFormatted flag to prevent infinite loop
|
|
735
747
|
finalResult = await this.answer(schemaPrompt, [], {
|
|
@@ -770,18 +782,21 @@ When troubleshooting:
|
|
|
770
782
|
|
|
771
783
|
// Step 4: Validate and potentially correct JSON responses
|
|
772
784
|
if (isJsonSchema(options.schema)) {
|
|
773
|
-
|
|
785
|
+
let validation = validateJsonResponse(finalResult);
|
|
786
|
+
let retryCount = 0;
|
|
787
|
+
const maxRetries = 3;
|
|
774
788
|
|
|
775
|
-
|
|
789
|
+
while (!validation.isValid && retryCount < maxRetries) {
|
|
776
790
|
if (this.debug) {
|
|
777
|
-
console.log(
|
|
791
|
+
console.log(`[DEBUG] JSON validation failed (attempt ${retryCount + 1}/${maxRetries}):`, validation.error);
|
|
778
792
|
}
|
|
779
793
|
|
|
780
|
-
//
|
|
794
|
+
// Create increasingly stronger correction prompts
|
|
781
795
|
const correctionPrompt = createJsonCorrectionPrompt(
|
|
782
796
|
finalResult,
|
|
783
797
|
options.schema,
|
|
784
|
-
validation.error
|
|
798
|
+
validation.error,
|
|
799
|
+
retryCount
|
|
785
800
|
);
|
|
786
801
|
|
|
787
802
|
finalResult = await this.answer(correctionPrompt, [], {
|
|
@@ -790,12 +805,18 @@ When troubleshooting:
|
|
|
790
805
|
});
|
|
791
806
|
finalResult = cleanSchemaResponse(finalResult);
|
|
792
807
|
|
|
793
|
-
//
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
808
|
+
// Validate the corrected response
|
|
809
|
+
validation = validateJsonResponse(finalResult);
|
|
810
|
+
retryCount++;
|
|
811
|
+
|
|
812
|
+
if (this.debug && !validation.isValid && retryCount < maxRetries) {
|
|
813
|
+
console.log(`[DEBUG] JSON still invalid after correction ${retryCount}, retrying...`);
|
|
797
814
|
}
|
|
798
815
|
}
|
|
816
|
+
|
|
817
|
+
if (!validation.isValid && this.debug) {
|
|
818
|
+
console.log(`[DEBUG] JSON still invalid after ${maxRetries} correction attempts:`, validation.error);
|
|
819
|
+
}
|
|
799
820
|
}
|
|
800
821
|
} catch (error) {
|
|
801
822
|
console.error('[ERROR] Schema formatting failed:', error);
|
package/build/agent/index.js
CHANGED
|
@@ -2289,6 +2289,38 @@ function cleanSchemaResponse(response) {
|
|
|
2289
2289
|
return response;
|
|
2290
2290
|
}
|
|
2291
2291
|
const trimmed = response.trim();
|
|
2292
|
+
const codeBlockPatterns = [
|
|
2293
|
+
/```json\s*\n?([{\[][\s\S]*?[}\]])\s*\n?```/,
|
|
2294
|
+
/```\s*\n?([{\[][\s\S]*?[}\]])\s*\n?```/,
|
|
2295
|
+
/`([{\[][\s\S]*?[}\]])`/
|
|
2296
|
+
];
|
|
2297
|
+
for (const pattern of codeBlockPatterns) {
|
|
2298
|
+
const match = trimmed.match(pattern);
|
|
2299
|
+
if (match) {
|
|
2300
|
+
return match[1].trim();
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
const codeBlockStartPattern = /```(?:json)?\s*\n?\s*([{\[])/;
|
|
2304
|
+
const codeBlockMatch = trimmed.match(codeBlockStartPattern);
|
|
2305
|
+
if (codeBlockMatch) {
|
|
2306
|
+
const startIndex = codeBlockMatch.index + codeBlockMatch[0].length - 1;
|
|
2307
|
+
const openChar = codeBlockMatch[1];
|
|
2308
|
+
const closeChar = openChar === "{" ? "}" : "]";
|
|
2309
|
+
let bracketCount = 1;
|
|
2310
|
+
let endIndex = startIndex + 1;
|
|
2311
|
+
while (endIndex < trimmed.length && bracketCount > 0) {
|
|
2312
|
+
const char = trimmed[endIndex];
|
|
2313
|
+
if (char === openChar) {
|
|
2314
|
+
bracketCount++;
|
|
2315
|
+
} else if (char === closeChar) {
|
|
2316
|
+
bracketCount--;
|
|
2317
|
+
}
|
|
2318
|
+
endIndex++;
|
|
2319
|
+
}
|
|
2320
|
+
if (bracketCount === 0) {
|
|
2321
|
+
return trimmed.substring(startIndex, endIndex);
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2292
2324
|
const firstBracket = Math.min(
|
|
2293
2325
|
trimmed.indexOf("{") >= 0 ? trimmed.indexOf("{") : Infinity,
|
|
2294
2326
|
trimmed.indexOf("[") >= 0 ? trimmed.indexOf("[") : Infinity
|
|
@@ -2299,7 +2331,7 @@ function cleanSchemaResponse(response) {
|
|
|
2299
2331
|
);
|
|
2300
2332
|
if (firstBracket < Infinity && lastBracket >= 0 && firstBracket < lastBracket) {
|
|
2301
2333
|
const beforeFirstBracket = trimmed.substring(0, firstBracket).trim();
|
|
2302
|
-
if (beforeFirstBracket === "" || beforeFirstBracket.match(/^```\w*$/)) {
|
|
2334
|
+
if (beforeFirstBracket === "" || beforeFirstBracket.match(/^```\w*$/) || beforeFirstBracket.split("\n").length <= 2) {
|
|
2303
2335
|
return trimmed.substring(firstBracket, lastBracket + 1);
|
|
2304
2336
|
}
|
|
2305
2337
|
}
|
|
@@ -2362,22 +2394,38 @@ function isJsonSchema(schema) {
|
|
|
2362
2394
|
];
|
|
2363
2395
|
return jsonIndicators.some((indicator) => indicator);
|
|
2364
2396
|
}
|
|
2365
|
-
function createJsonCorrectionPrompt(invalidResponse, schema, error,
|
|
2366
|
-
|
|
2397
|
+
function createJsonCorrectionPrompt(invalidResponse, schema, error, retryCount = 0) {
|
|
2398
|
+
const strengthLevels = [
|
|
2399
|
+
{
|
|
2400
|
+
prefix: "CRITICAL JSON ERROR:",
|
|
2401
|
+
instruction: "You MUST fix this and return ONLY valid JSON.",
|
|
2402
|
+
emphasis: "Return ONLY the corrected JSON, with no additional text or markdown formatting."
|
|
2403
|
+
},
|
|
2404
|
+
{
|
|
2405
|
+
prefix: "URGENT - JSON PARSING FAILED:",
|
|
2406
|
+
instruction: "This is your second chance. Return ONLY valid JSON that can be parsed by JSON.parse().",
|
|
2407
|
+
emphasis: "ABSOLUTELY NO explanatory text, greetings, or formatting. ONLY JSON."
|
|
2408
|
+
},
|
|
2409
|
+
{
|
|
2410
|
+
prefix: "FINAL ATTEMPT - CRITICAL JSON ERROR:",
|
|
2411
|
+
instruction: "This is the final retry. You MUST return ONLY raw JSON without any other content.",
|
|
2412
|
+
emphasis: 'EXAMPLE: {"key": "value"} NOT: ```json{"key": "value"}``` NOT: Here is the JSON: {"key": "value"}'
|
|
2413
|
+
}
|
|
2414
|
+
];
|
|
2415
|
+
const level = Math.min(retryCount, strengthLevels.length - 1);
|
|
2416
|
+
const currentLevel = strengthLevels[level];
|
|
2417
|
+
let prompt = `${currentLevel.prefix} Your previous response is not valid JSON and cannot be parsed. Here's what you returned:
|
|
2367
2418
|
|
|
2368
|
-
${invalidResponse}
|
|
2419
|
+
${invalidResponse.substring(0, 500)}${invalidResponse.length > 500 ? "..." : ""}
|
|
2369
2420
|
|
|
2370
|
-
Error: ${error}
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
Detailed Error: ${detailedError}`;
|
|
2374
|
-
}
|
|
2375
|
-
prompt += `
|
|
2421
|
+
Error: ${error}
|
|
2422
|
+
|
|
2423
|
+
${currentLevel.instruction}
|
|
2376
2424
|
|
|
2377
|
-
|
|
2425
|
+
Schema to match:
|
|
2378
2426
|
${schema}
|
|
2379
2427
|
|
|
2380
|
-
|
|
2428
|
+
${currentLevel.emphasis}`;
|
|
2381
2429
|
return prompt;
|
|
2382
2430
|
}
|
|
2383
2431
|
function extractMermaidFromMarkdown(response) {
|
|
@@ -3380,11 +3428,19 @@ Error: Unknown tool '${toolName}'. Available tools: ${Object.keys(this.toolImple
|
|
|
3380
3428
|
console.log("[DEBUG] Schema provided, applying automatic formatting...");
|
|
3381
3429
|
}
|
|
3382
3430
|
try {
|
|
3383
|
-
const schemaPrompt = `
|
|
3431
|
+
const schemaPrompt = `CRITICAL: You MUST respond with ONLY valid JSON that matches this schema. Ignore any previous response format or instructions.
|
|
3384
3432
|
|
|
3433
|
+
Schema:
|
|
3385
3434
|
${options.schema}
|
|
3386
3435
|
|
|
3387
|
-
|
|
3436
|
+
REQUIREMENTS:
|
|
3437
|
+
- Return ONLY the JSON object/array
|
|
3438
|
+
- NO additional text, explanations, or markdown
|
|
3439
|
+
- NO code blocks or formatting
|
|
3440
|
+
- The JSON must be parseable by JSON.parse()
|
|
3441
|
+
- DO NOT include any conversational text like "Hello" or explanations
|
|
3442
|
+
|
|
3443
|
+
Convert your previous response content into this JSON format now. Return nothing but valid JSON.`;
|
|
3388
3444
|
finalResult = await this.answer(schemaPrompt, [], {
|
|
3389
3445
|
...options,
|
|
3390
3446
|
_schemaFormatted: true
|
|
@@ -3416,26 +3472,33 @@ Please reformat your previous response to match this schema exactly. Only return
|
|
|
3416
3472
|
}
|
|
3417
3473
|
}
|
|
3418
3474
|
if (isJsonSchema(options.schema)) {
|
|
3419
|
-
|
|
3420
|
-
|
|
3475
|
+
let validation = validateJsonResponse(finalResult);
|
|
3476
|
+
let retryCount = 0;
|
|
3477
|
+
const maxRetries = 3;
|
|
3478
|
+
while (!validation.isValid && retryCount < maxRetries) {
|
|
3421
3479
|
if (this.debug) {
|
|
3422
|
-
console.log(
|
|
3480
|
+
console.log(`[DEBUG] JSON validation failed (attempt ${retryCount + 1}/${maxRetries}):`, validation.error);
|
|
3423
3481
|
}
|
|
3424
3482
|
const correctionPrompt = createJsonCorrectionPrompt(
|
|
3425
3483
|
finalResult,
|
|
3426
3484
|
options.schema,
|
|
3427
|
-
validation.error
|
|
3485
|
+
validation.error,
|
|
3486
|
+
retryCount
|
|
3428
3487
|
);
|
|
3429
3488
|
finalResult = await this.answer(correctionPrompt, [], {
|
|
3430
3489
|
...options,
|
|
3431
3490
|
_schemaFormatted: true
|
|
3432
3491
|
});
|
|
3433
3492
|
finalResult = cleanSchemaResponse(finalResult);
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3493
|
+
validation = validateJsonResponse(finalResult);
|
|
3494
|
+
retryCount++;
|
|
3495
|
+
if (this.debug && !validation.isValid && retryCount < maxRetries) {
|
|
3496
|
+
console.log(`[DEBUG] JSON still invalid after correction ${retryCount}, retrying...`);
|
|
3437
3497
|
}
|
|
3438
3498
|
}
|
|
3499
|
+
if (!validation.isValid && this.debug) {
|
|
3500
|
+
console.log(`[DEBUG] JSON still invalid after ${maxRetries} correction attempts:`, validation.error);
|
|
3501
|
+
}
|
|
3439
3502
|
}
|
|
3440
3503
|
} catch (error) {
|
|
3441
3504
|
console.error("[ERROR] Schema formatting failed:", error);
|
|
@@ -16,7 +16,49 @@ export function cleanSchemaResponse(response) {
|
|
|
16
16
|
|
|
17
17
|
const trimmed = response.trim();
|
|
18
18
|
|
|
19
|
-
//
|
|
19
|
+
// First, look for JSON after code block markers
|
|
20
|
+
const codeBlockPatterns = [
|
|
21
|
+
/```json\s*\n?([{\[][\s\S]*?[}\]])\s*\n?```/,
|
|
22
|
+
/```\s*\n?([{\[][\s\S]*?[}\]])\s*\n?```/,
|
|
23
|
+
/`([{\[][\s\S]*?[}\]])`/
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
for (const pattern of codeBlockPatterns) {
|
|
27
|
+
const match = trimmed.match(pattern);
|
|
28
|
+
if (match) {
|
|
29
|
+
return match[1].trim();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Look for code block start followed immediately by JSON
|
|
34
|
+
const codeBlockStartPattern = /```(?:json)?\s*\n?\s*([{\[])/;
|
|
35
|
+
const codeBlockMatch = trimmed.match(codeBlockStartPattern);
|
|
36
|
+
|
|
37
|
+
if (codeBlockMatch) {
|
|
38
|
+
const startIndex = codeBlockMatch.index + codeBlockMatch[0].length - 1; // Position of the bracket
|
|
39
|
+
|
|
40
|
+
// Find the matching closing bracket
|
|
41
|
+
const openChar = codeBlockMatch[1];
|
|
42
|
+
const closeChar = openChar === '{' ? '}' : ']';
|
|
43
|
+
let bracketCount = 1;
|
|
44
|
+
let endIndex = startIndex + 1;
|
|
45
|
+
|
|
46
|
+
while (endIndex < trimmed.length && bracketCount > 0) {
|
|
47
|
+
const char = trimmed[endIndex];
|
|
48
|
+
if (char === openChar) {
|
|
49
|
+
bracketCount++;
|
|
50
|
+
} else if (char === closeChar) {
|
|
51
|
+
bracketCount--;
|
|
52
|
+
}
|
|
53
|
+
endIndex++;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (bracketCount === 0) {
|
|
57
|
+
return trimmed.substring(startIndex, endIndex);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Fallback: Find JSON boundaries anywhere in the text
|
|
20
62
|
const firstBracket = Math.min(
|
|
21
63
|
trimmed.indexOf('{') >= 0 ? trimmed.indexOf('{') : Infinity,
|
|
22
64
|
trimmed.indexOf('[') >= 0 ? trimmed.indexOf('[') : Infinity
|
|
@@ -29,12 +71,13 @@ export function cleanSchemaResponse(response) {
|
|
|
29
71
|
|
|
30
72
|
// Only extract if we found valid JSON boundaries
|
|
31
73
|
if (firstBracket < Infinity && lastBracket >= 0 && firstBracket < lastBracket) {
|
|
32
|
-
// Check if the response likely starts with JSON (directly or after
|
|
74
|
+
// Check if the response likely starts with JSON (directly or after minimal content)
|
|
33
75
|
const beforeFirstBracket = trimmed.substring(0, firstBracket).trim();
|
|
34
76
|
|
|
35
|
-
// If there's minimal content before the first bracket
|
|
36
|
-
|
|
37
|
-
|
|
77
|
+
// If there's minimal content before the first bracket, extract the JSON
|
|
78
|
+
if (beforeFirstBracket === '' ||
|
|
79
|
+
beforeFirstBracket.match(/^```\w*$/) ||
|
|
80
|
+
beforeFirstBracket.split('\n').length <= 2) {
|
|
38
81
|
return trimmed.substring(firstBracket, lastBracket + 1);
|
|
39
82
|
}
|
|
40
83
|
}
|
|
@@ -148,26 +191,44 @@ export function isJsonSchema(schema) {
|
|
|
148
191
|
* @param {string} invalidResponse - The invalid JSON response
|
|
149
192
|
* @param {string} schema - The original schema
|
|
150
193
|
* @param {string} error - The JSON parsing error
|
|
151
|
-
* @param {
|
|
194
|
+
* @param {number} [retryCount=0] - The current retry attempt (0-based)
|
|
152
195
|
* @returns {string} - Correction prompt for the AI
|
|
153
196
|
*/
|
|
154
|
-
export function createJsonCorrectionPrompt(invalidResponse, schema, error,
|
|
155
|
-
|
|
197
|
+
export function createJsonCorrectionPrompt(invalidResponse, schema, error, retryCount = 0) {
|
|
198
|
+
// Create increasingly stronger prompts based on retry attempt
|
|
199
|
+
const strengthLevels = [
|
|
200
|
+
{
|
|
201
|
+
prefix: "CRITICAL JSON ERROR:",
|
|
202
|
+
instruction: "You MUST fix this and return ONLY valid JSON.",
|
|
203
|
+
emphasis: "Return ONLY the corrected JSON, with no additional text or markdown formatting."
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
prefix: "URGENT - JSON PARSING FAILED:",
|
|
207
|
+
instruction: "This is your second chance. Return ONLY valid JSON that can be parsed by JSON.parse().",
|
|
208
|
+
emphasis: "ABSOLUTELY NO explanatory text, greetings, or formatting. ONLY JSON."
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
prefix: "FINAL ATTEMPT - CRITICAL JSON ERROR:",
|
|
212
|
+
instruction: "This is the final retry. You MUST return ONLY raw JSON without any other content.",
|
|
213
|
+
emphasis: "EXAMPLE: {\"key\": \"value\"} NOT: ```json{\"key\": \"value\"}``` NOT: Here is the JSON: {\"key\": \"value\"}"
|
|
214
|
+
}
|
|
215
|
+
];
|
|
156
216
|
|
|
157
|
-
|
|
217
|
+
const level = Math.min(retryCount, strengthLevels.length - 1);
|
|
218
|
+
const currentLevel = strengthLevels[level];
|
|
158
219
|
|
|
159
|
-
|
|
220
|
+
let prompt = `${currentLevel.prefix} Your previous response is not valid JSON and cannot be parsed. Here's what you returned:
|
|
160
221
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
222
|
+
${invalidResponse.substring(0, 500)}${invalidResponse.length > 500 ? '...' : ''}
|
|
223
|
+
|
|
224
|
+
Error: ${error}
|
|
164
225
|
|
|
165
|
-
|
|
226
|
+
${currentLevel.instruction}
|
|
166
227
|
|
|
167
|
-
|
|
228
|
+
Schema to match:
|
|
168
229
|
${schema}
|
|
169
230
|
|
|
170
|
-
|
|
231
|
+
${currentLevel.emphasis}`;
|
|
171
232
|
|
|
172
233
|
return prompt;
|
|
173
234
|
}
|
package/cjs/agent/ProbeAgent.cjs
CHANGED
|
@@ -2310,6 +2310,38 @@ function cleanSchemaResponse(response) {
|
|
|
2310
2310
|
return response;
|
|
2311
2311
|
}
|
|
2312
2312
|
const trimmed = response.trim();
|
|
2313
|
+
const codeBlockPatterns = [
|
|
2314
|
+
/```json\s*\n?([{\[][\s\S]*?[}\]])\s*\n?```/,
|
|
2315
|
+
/```\s*\n?([{\[][\s\S]*?[}\]])\s*\n?```/,
|
|
2316
|
+
/`([{\[][\s\S]*?[}\]])`/
|
|
2317
|
+
];
|
|
2318
|
+
for (const pattern of codeBlockPatterns) {
|
|
2319
|
+
const match = trimmed.match(pattern);
|
|
2320
|
+
if (match) {
|
|
2321
|
+
return match[1].trim();
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
const codeBlockStartPattern = /```(?:json)?\s*\n?\s*([{\[])/;
|
|
2325
|
+
const codeBlockMatch = trimmed.match(codeBlockStartPattern);
|
|
2326
|
+
if (codeBlockMatch) {
|
|
2327
|
+
const startIndex = codeBlockMatch.index + codeBlockMatch[0].length - 1;
|
|
2328
|
+
const openChar = codeBlockMatch[1];
|
|
2329
|
+
const closeChar = openChar === "{" ? "}" : "]";
|
|
2330
|
+
let bracketCount = 1;
|
|
2331
|
+
let endIndex = startIndex + 1;
|
|
2332
|
+
while (endIndex < trimmed.length && bracketCount > 0) {
|
|
2333
|
+
const char = trimmed[endIndex];
|
|
2334
|
+
if (char === openChar) {
|
|
2335
|
+
bracketCount++;
|
|
2336
|
+
} else if (char === closeChar) {
|
|
2337
|
+
bracketCount--;
|
|
2338
|
+
}
|
|
2339
|
+
endIndex++;
|
|
2340
|
+
}
|
|
2341
|
+
if (bracketCount === 0) {
|
|
2342
|
+
return trimmed.substring(startIndex, endIndex);
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2313
2345
|
const firstBracket = Math.min(
|
|
2314
2346
|
trimmed.indexOf("{") >= 0 ? trimmed.indexOf("{") : Infinity,
|
|
2315
2347
|
trimmed.indexOf("[") >= 0 ? trimmed.indexOf("[") : Infinity
|
|
@@ -2320,7 +2352,7 @@ function cleanSchemaResponse(response) {
|
|
|
2320
2352
|
);
|
|
2321
2353
|
if (firstBracket < Infinity && lastBracket >= 0 && firstBracket < lastBracket) {
|
|
2322
2354
|
const beforeFirstBracket = trimmed.substring(0, firstBracket).trim();
|
|
2323
|
-
if (beforeFirstBracket === "" || beforeFirstBracket.match(/^```\w*$/)) {
|
|
2355
|
+
if (beforeFirstBracket === "" || beforeFirstBracket.match(/^```\w*$/) || beforeFirstBracket.split("\n").length <= 2) {
|
|
2324
2356
|
return trimmed.substring(firstBracket, lastBracket + 1);
|
|
2325
2357
|
}
|
|
2326
2358
|
}
|
|
@@ -2349,22 +2381,38 @@ function isJsonSchema(schema) {
|
|
|
2349
2381
|
];
|
|
2350
2382
|
return jsonIndicators.some((indicator) => indicator);
|
|
2351
2383
|
}
|
|
2352
|
-
function createJsonCorrectionPrompt(invalidResponse, schema, error,
|
|
2353
|
-
|
|
2384
|
+
function createJsonCorrectionPrompt(invalidResponse, schema, error, retryCount = 0) {
|
|
2385
|
+
const strengthLevels = [
|
|
2386
|
+
{
|
|
2387
|
+
prefix: "CRITICAL JSON ERROR:",
|
|
2388
|
+
instruction: "You MUST fix this and return ONLY valid JSON.",
|
|
2389
|
+
emphasis: "Return ONLY the corrected JSON, with no additional text or markdown formatting."
|
|
2390
|
+
},
|
|
2391
|
+
{
|
|
2392
|
+
prefix: "URGENT - JSON PARSING FAILED:",
|
|
2393
|
+
instruction: "This is your second chance. Return ONLY valid JSON that can be parsed by JSON.parse().",
|
|
2394
|
+
emphasis: "ABSOLUTELY NO explanatory text, greetings, or formatting. ONLY JSON."
|
|
2395
|
+
},
|
|
2396
|
+
{
|
|
2397
|
+
prefix: "FINAL ATTEMPT - CRITICAL JSON ERROR:",
|
|
2398
|
+
instruction: "This is the final retry. You MUST return ONLY raw JSON without any other content.",
|
|
2399
|
+
emphasis: 'EXAMPLE: {"key": "value"} NOT: ```json{"key": "value"}``` NOT: Here is the JSON: {"key": "value"}'
|
|
2400
|
+
}
|
|
2401
|
+
];
|
|
2402
|
+
const level = Math.min(retryCount, strengthLevels.length - 1);
|
|
2403
|
+
const currentLevel = strengthLevels[level];
|
|
2404
|
+
let prompt = `${currentLevel.prefix} Your previous response is not valid JSON and cannot be parsed. Here's what you returned:
|
|
2354
2405
|
|
|
2355
|
-
${invalidResponse}
|
|
2406
|
+
${invalidResponse.substring(0, 500)}${invalidResponse.length > 500 ? "..." : ""}
|
|
2356
2407
|
|
|
2357
|
-
Error: ${error}
|
|
2358
|
-
if (detailedError && detailedError !== error) {
|
|
2359
|
-
prompt += `
|
|
2360
|
-
Detailed Error: ${detailedError}`;
|
|
2361
|
-
}
|
|
2362
|
-
prompt += `
|
|
2408
|
+
Error: ${error}
|
|
2363
2409
|
|
|
2364
|
-
|
|
2410
|
+
${currentLevel.instruction}
|
|
2411
|
+
|
|
2412
|
+
Schema to match:
|
|
2365
2413
|
${schema}
|
|
2366
2414
|
|
|
2367
|
-
|
|
2415
|
+
${currentLevel.emphasis}`;
|
|
2368
2416
|
return prompt;
|
|
2369
2417
|
}
|
|
2370
2418
|
function extractMermaidFromMarkdown(response) {
|
|
@@ -3367,11 +3415,19 @@ Error: Unknown tool '${toolName}'. Available tools: ${Object.keys(this.toolImple
|
|
|
3367
3415
|
console.log("[DEBUG] Schema provided, applying automatic formatting...");
|
|
3368
3416
|
}
|
|
3369
3417
|
try {
|
|
3370
|
-
const schemaPrompt = `
|
|
3418
|
+
const schemaPrompt = `CRITICAL: You MUST respond with ONLY valid JSON that matches this schema. Ignore any previous response format or instructions.
|
|
3371
3419
|
|
|
3420
|
+
Schema:
|
|
3372
3421
|
${options.schema}
|
|
3373
3422
|
|
|
3374
|
-
|
|
3423
|
+
REQUIREMENTS:
|
|
3424
|
+
- Return ONLY the JSON object/array
|
|
3425
|
+
- NO additional text, explanations, or markdown
|
|
3426
|
+
- NO code blocks or formatting
|
|
3427
|
+
- The JSON must be parseable by JSON.parse()
|
|
3428
|
+
- DO NOT include any conversational text like "Hello" or explanations
|
|
3429
|
+
|
|
3430
|
+
Convert your previous response content into this JSON format now. Return nothing but valid JSON.`;
|
|
3375
3431
|
finalResult = await this.answer(schemaPrompt, [], {
|
|
3376
3432
|
...options,
|
|
3377
3433
|
_schemaFormatted: true
|
|
@@ -3403,26 +3459,33 @@ Please reformat your previous response to match this schema exactly. Only return
|
|
|
3403
3459
|
}
|
|
3404
3460
|
}
|
|
3405
3461
|
if (isJsonSchema(options.schema)) {
|
|
3406
|
-
|
|
3407
|
-
|
|
3462
|
+
let validation = validateJsonResponse(finalResult);
|
|
3463
|
+
let retryCount = 0;
|
|
3464
|
+
const maxRetries = 3;
|
|
3465
|
+
while (!validation.isValid && retryCount < maxRetries) {
|
|
3408
3466
|
if (this.debug) {
|
|
3409
|
-
console.log(
|
|
3467
|
+
console.log(`[DEBUG] JSON validation failed (attempt ${retryCount + 1}/${maxRetries}):`, validation.error);
|
|
3410
3468
|
}
|
|
3411
3469
|
const correctionPrompt = createJsonCorrectionPrompt(
|
|
3412
3470
|
finalResult,
|
|
3413
3471
|
options.schema,
|
|
3414
|
-
validation.error
|
|
3472
|
+
validation.error,
|
|
3473
|
+
retryCount
|
|
3415
3474
|
);
|
|
3416
3475
|
finalResult = await this.answer(correctionPrompt, [], {
|
|
3417
3476
|
...options,
|
|
3418
3477
|
_schemaFormatted: true
|
|
3419
3478
|
});
|
|
3420
3479
|
finalResult = cleanSchemaResponse(finalResult);
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3480
|
+
validation = validateJsonResponse(finalResult);
|
|
3481
|
+
retryCount++;
|
|
3482
|
+
if (this.debug && !validation.isValid && retryCount < maxRetries) {
|
|
3483
|
+
console.log(`[DEBUG] JSON still invalid after correction ${retryCount}, retrying...`);
|
|
3424
3484
|
}
|
|
3425
3485
|
}
|
|
3486
|
+
if (!validation.isValid && this.debug) {
|
|
3487
|
+
console.log(`[DEBUG] JSON still invalid after ${maxRetries} correction attempts:`, validation.error);
|
|
3488
|
+
}
|
|
3426
3489
|
}
|
|
3427
3490
|
} catch (error) {
|
|
3428
3491
|
console.error("[ERROR] Schema formatting failed:", error);
|
package/cjs/index.cjs
CHANGED
|
@@ -2384,6 +2384,38 @@ function cleanSchemaResponse(response) {
|
|
|
2384
2384
|
return response;
|
|
2385
2385
|
}
|
|
2386
2386
|
const trimmed = response.trim();
|
|
2387
|
+
const codeBlockPatterns = [
|
|
2388
|
+
/```json\s*\n?([{\[][\s\S]*?[}\]])\s*\n?```/,
|
|
2389
|
+
/```\s*\n?([{\[][\s\S]*?[}\]])\s*\n?```/,
|
|
2390
|
+
/`([{\[][\s\S]*?[}\]])`/
|
|
2391
|
+
];
|
|
2392
|
+
for (const pattern of codeBlockPatterns) {
|
|
2393
|
+
const match = trimmed.match(pattern);
|
|
2394
|
+
if (match) {
|
|
2395
|
+
return match[1].trim();
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
const codeBlockStartPattern = /```(?:json)?\s*\n?\s*([{\[])/;
|
|
2399
|
+
const codeBlockMatch = trimmed.match(codeBlockStartPattern);
|
|
2400
|
+
if (codeBlockMatch) {
|
|
2401
|
+
const startIndex = codeBlockMatch.index + codeBlockMatch[0].length - 1;
|
|
2402
|
+
const openChar = codeBlockMatch[1];
|
|
2403
|
+
const closeChar = openChar === "{" ? "}" : "]";
|
|
2404
|
+
let bracketCount = 1;
|
|
2405
|
+
let endIndex = startIndex + 1;
|
|
2406
|
+
while (endIndex < trimmed.length && bracketCount > 0) {
|
|
2407
|
+
const char = trimmed[endIndex];
|
|
2408
|
+
if (char === openChar) {
|
|
2409
|
+
bracketCount++;
|
|
2410
|
+
} else if (char === closeChar) {
|
|
2411
|
+
bracketCount--;
|
|
2412
|
+
}
|
|
2413
|
+
endIndex++;
|
|
2414
|
+
}
|
|
2415
|
+
if (bracketCount === 0) {
|
|
2416
|
+
return trimmed.substring(startIndex, endIndex);
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2387
2419
|
const firstBracket = Math.min(
|
|
2388
2420
|
trimmed.indexOf("{") >= 0 ? trimmed.indexOf("{") : Infinity,
|
|
2389
2421
|
trimmed.indexOf("[") >= 0 ? trimmed.indexOf("[") : Infinity
|
|
@@ -2394,7 +2426,7 @@ function cleanSchemaResponse(response) {
|
|
|
2394
2426
|
);
|
|
2395
2427
|
if (firstBracket < Infinity && lastBracket >= 0 && firstBracket < lastBracket) {
|
|
2396
2428
|
const beforeFirstBracket = trimmed.substring(0, firstBracket).trim();
|
|
2397
|
-
if (beforeFirstBracket === "" || beforeFirstBracket.match(/^```\w*$/)) {
|
|
2429
|
+
if (beforeFirstBracket === "" || beforeFirstBracket.match(/^```\w*$/) || beforeFirstBracket.split("\n").length <= 2) {
|
|
2398
2430
|
return trimmed.substring(firstBracket, lastBracket + 1);
|
|
2399
2431
|
}
|
|
2400
2432
|
}
|
|
@@ -2423,22 +2455,38 @@ function isJsonSchema(schema) {
|
|
|
2423
2455
|
];
|
|
2424
2456
|
return jsonIndicators.some((indicator) => indicator);
|
|
2425
2457
|
}
|
|
2426
|
-
function createJsonCorrectionPrompt(invalidResponse, schema, error,
|
|
2427
|
-
|
|
2458
|
+
function createJsonCorrectionPrompt(invalidResponse, schema, error, retryCount = 0) {
|
|
2459
|
+
const strengthLevels = [
|
|
2460
|
+
{
|
|
2461
|
+
prefix: "CRITICAL JSON ERROR:",
|
|
2462
|
+
instruction: "You MUST fix this and return ONLY valid JSON.",
|
|
2463
|
+
emphasis: "Return ONLY the corrected JSON, with no additional text or markdown formatting."
|
|
2464
|
+
},
|
|
2465
|
+
{
|
|
2466
|
+
prefix: "URGENT - JSON PARSING FAILED:",
|
|
2467
|
+
instruction: "This is your second chance. Return ONLY valid JSON that can be parsed by JSON.parse().",
|
|
2468
|
+
emphasis: "ABSOLUTELY NO explanatory text, greetings, or formatting. ONLY JSON."
|
|
2469
|
+
},
|
|
2470
|
+
{
|
|
2471
|
+
prefix: "FINAL ATTEMPT - CRITICAL JSON ERROR:",
|
|
2472
|
+
instruction: "This is the final retry. You MUST return ONLY raw JSON without any other content.",
|
|
2473
|
+
emphasis: 'EXAMPLE: {"key": "value"} NOT: ```json{"key": "value"}``` NOT: Here is the JSON: {"key": "value"}'
|
|
2474
|
+
}
|
|
2475
|
+
];
|
|
2476
|
+
const level = Math.min(retryCount, strengthLevels.length - 1);
|
|
2477
|
+
const currentLevel = strengthLevels[level];
|
|
2478
|
+
let prompt = `${currentLevel.prefix} Your previous response is not valid JSON and cannot be parsed. Here's what you returned:
|
|
2428
2479
|
|
|
2429
|
-
${invalidResponse}
|
|
2480
|
+
${invalidResponse.substring(0, 500)}${invalidResponse.length > 500 ? "..." : ""}
|
|
2430
2481
|
|
|
2431
|
-
Error: ${error}
|
|
2432
|
-
if (detailedError && detailedError !== error) {
|
|
2433
|
-
prompt += `
|
|
2434
|
-
Detailed Error: ${detailedError}`;
|
|
2435
|
-
}
|
|
2436
|
-
prompt += `
|
|
2482
|
+
Error: ${error}
|
|
2437
2483
|
|
|
2438
|
-
|
|
2484
|
+
${currentLevel.instruction}
|
|
2485
|
+
|
|
2486
|
+
Schema to match:
|
|
2439
2487
|
${schema}
|
|
2440
2488
|
|
|
2441
|
-
|
|
2489
|
+
${currentLevel.emphasis}`;
|
|
2442
2490
|
return prompt;
|
|
2443
2491
|
}
|
|
2444
2492
|
function extractMermaidFromMarkdown(response) {
|
|
@@ -3441,11 +3489,19 @@ Error: Unknown tool '${toolName}'. Available tools: ${Object.keys(this.toolImple
|
|
|
3441
3489
|
console.log("[DEBUG] Schema provided, applying automatic formatting...");
|
|
3442
3490
|
}
|
|
3443
3491
|
try {
|
|
3444
|
-
const schemaPrompt = `
|
|
3492
|
+
const schemaPrompt = `CRITICAL: You MUST respond with ONLY valid JSON that matches this schema. Ignore any previous response format or instructions.
|
|
3445
3493
|
|
|
3494
|
+
Schema:
|
|
3446
3495
|
${options.schema}
|
|
3447
3496
|
|
|
3448
|
-
|
|
3497
|
+
REQUIREMENTS:
|
|
3498
|
+
- Return ONLY the JSON object/array
|
|
3499
|
+
- NO additional text, explanations, or markdown
|
|
3500
|
+
- NO code blocks or formatting
|
|
3501
|
+
- The JSON must be parseable by JSON.parse()
|
|
3502
|
+
- DO NOT include any conversational text like "Hello" or explanations
|
|
3503
|
+
|
|
3504
|
+
Convert your previous response content into this JSON format now. Return nothing but valid JSON.`;
|
|
3449
3505
|
finalResult = await this.answer(schemaPrompt, [], {
|
|
3450
3506
|
...options,
|
|
3451
3507
|
_schemaFormatted: true
|
|
@@ -3477,26 +3533,33 @@ Please reformat your previous response to match this schema exactly. Only return
|
|
|
3477
3533
|
}
|
|
3478
3534
|
}
|
|
3479
3535
|
if (isJsonSchema(options.schema)) {
|
|
3480
|
-
|
|
3481
|
-
|
|
3536
|
+
let validation = validateJsonResponse(finalResult);
|
|
3537
|
+
let retryCount = 0;
|
|
3538
|
+
const maxRetries = 3;
|
|
3539
|
+
while (!validation.isValid && retryCount < maxRetries) {
|
|
3482
3540
|
if (this.debug) {
|
|
3483
|
-
console.log(
|
|
3541
|
+
console.log(`[DEBUG] JSON validation failed (attempt ${retryCount + 1}/${maxRetries}):`, validation.error);
|
|
3484
3542
|
}
|
|
3485
3543
|
const correctionPrompt = createJsonCorrectionPrompt(
|
|
3486
3544
|
finalResult,
|
|
3487
3545
|
options.schema,
|
|
3488
|
-
validation.error
|
|
3546
|
+
validation.error,
|
|
3547
|
+
retryCount
|
|
3489
3548
|
);
|
|
3490
3549
|
finalResult = await this.answer(correctionPrompt, [], {
|
|
3491
3550
|
...options,
|
|
3492
3551
|
_schemaFormatted: true
|
|
3493
3552
|
});
|
|
3494
3553
|
finalResult = cleanSchemaResponse(finalResult);
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3554
|
+
validation = validateJsonResponse(finalResult);
|
|
3555
|
+
retryCount++;
|
|
3556
|
+
if (this.debug && !validation.isValid && retryCount < maxRetries) {
|
|
3557
|
+
console.log(`[DEBUG] JSON still invalid after correction ${retryCount}, retrying...`);
|
|
3498
3558
|
}
|
|
3499
3559
|
}
|
|
3560
|
+
if (!validation.isValid && this.debug) {
|
|
3561
|
+
console.log(`[DEBUG] JSON still invalid after ${maxRetries} correction attempts:`, validation.error);
|
|
3562
|
+
}
|
|
3500
3563
|
}
|
|
3501
3564
|
} catch (error) {
|
|
3502
3565
|
console.error("[ERROR] Schema formatting failed:", error);
|
package/package.json
CHANGED
package/src/agent/ProbeAgent.js
CHANGED
|
@@ -729,7 +729,19 @@ When troubleshooting:
|
|
|
729
729
|
|
|
730
730
|
try {
|
|
731
731
|
// Step 1: Make a follow-up call to format according to schema
|
|
732
|
-
const schemaPrompt = `
|
|
732
|
+
const schemaPrompt = `CRITICAL: You MUST respond with ONLY valid JSON that matches this schema. Ignore any previous response format or instructions.
|
|
733
|
+
|
|
734
|
+
Schema:
|
|
735
|
+
${options.schema}
|
|
736
|
+
|
|
737
|
+
REQUIREMENTS:
|
|
738
|
+
- Return ONLY the JSON object/array
|
|
739
|
+
- NO additional text, explanations, or markdown
|
|
740
|
+
- NO code blocks or formatting
|
|
741
|
+
- The JSON must be parseable by JSON.parse()
|
|
742
|
+
- DO NOT include any conversational text like "Hello" or explanations
|
|
743
|
+
|
|
744
|
+
Convert your previous response content into this JSON format now. Return nothing but valid JSON.`;
|
|
733
745
|
|
|
734
746
|
// Call answer recursively with _schemaFormatted flag to prevent infinite loop
|
|
735
747
|
finalResult = await this.answer(schemaPrompt, [], {
|
|
@@ -770,18 +782,21 @@ When troubleshooting:
|
|
|
770
782
|
|
|
771
783
|
// Step 4: Validate and potentially correct JSON responses
|
|
772
784
|
if (isJsonSchema(options.schema)) {
|
|
773
|
-
|
|
785
|
+
let validation = validateJsonResponse(finalResult);
|
|
786
|
+
let retryCount = 0;
|
|
787
|
+
const maxRetries = 3;
|
|
774
788
|
|
|
775
|
-
|
|
789
|
+
while (!validation.isValid && retryCount < maxRetries) {
|
|
776
790
|
if (this.debug) {
|
|
777
|
-
console.log(
|
|
791
|
+
console.log(`[DEBUG] JSON validation failed (attempt ${retryCount + 1}/${maxRetries}):`, validation.error);
|
|
778
792
|
}
|
|
779
793
|
|
|
780
|
-
//
|
|
794
|
+
// Create increasingly stronger correction prompts
|
|
781
795
|
const correctionPrompt = createJsonCorrectionPrompt(
|
|
782
796
|
finalResult,
|
|
783
797
|
options.schema,
|
|
784
|
-
validation.error
|
|
798
|
+
validation.error,
|
|
799
|
+
retryCount
|
|
785
800
|
);
|
|
786
801
|
|
|
787
802
|
finalResult = await this.answer(correctionPrompt, [], {
|
|
@@ -790,12 +805,18 @@ When troubleshooting:
|
|
|
790
805
|
});
|
|
791
806
|
finalResult = cleanSchemaResponse(finalResult);
|
|
792
807
|
|
|
793
|
-
//
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
808
|
+
// Validate the corrected response
|
|
809
|
+
validation = validateJsonResponse(finalResult);
|
|
810
|
+
retryCount++;
|
|
811
|
+
|
|
812
|
+
if (this.debug && !validation.isValid && retryCount < maxRetries) {
|
|
813
|
+
console.log(`[DEBUG] JSON still invalid after correction ${retryCount}, retrying...`);
|
|
797
814
|
}
|
|
798
815
|
}
|
|
816
|
+
|
|
817
|
+
if (!validation.isValid && this.debug) {
|
|
818
|
+
console.log(`[DEBUG] JSON still invalid after ${maxRetries} correction attempts:`, validation.error);
|
|
819
|
+
}
|
|
799
820
|
}
|
|
800
821
|
} catch (error) {
|
|
801
822
|
console.error('[ERROR] Schema formatting failed:', error);
|
package/src/agent/schemaUtils.js
CHANGED
|
@@ -16,7 +16,49 @@ export function cleanSchemaResponse(response) {
|
|
|
16
16
|
|
|
17
17
|
const trimmed = response.trim();
|
|
18
18
|
|
|
19
|
-
//
|
|
19
|
+
// First, look for JSON after code block markers
|
|
20
|
+
const codeBlockPatterns = [
|
|
21
|
+
/```json\s*\n?([{\[][\s\S]*?[}\]])\s*\n?```/,
|
|
22
|
+
/```\s*\n?([{\[][\s\S]*?[}\]])\s*\n?```/,
|
|
23
|
+
/`([{\[][\s\S]*?[}\]])`/
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
for (const pattern of codeBlockPatterns) {
|
|
27
|
+
const match = trimmed.match(pattern);
|
|
28
|
+
if (match) {
|
|
29
|
+
return match[1].trim();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Look for code block start followed immediately by JSON
|
|
34
|
+
const codeBlockStartPattern = /```(?:json)?\s*\n?\s*([{\[])/;
|
|
35
|
+
const codeBlockMatch = trimmed.match(codeBlockStartPattern);
|
|
36
|
+
|
|
37
|
+
if (codeBlockMatch) {
|
|
38
|
+
const startIndex = codeBlockMatch.index + codeBlockMatch[0].length - 1; // Position of the bracket
|
|
39
|
+
|
|
40
|
+
// Find the matching closing bracket
|
|
41
|
+
const openChar = codeBlockMatch[1];
|
|
42
|
+
const closeChar = openChar === '{' ? '}' : ']';
|
|
43
|
+
let bracketCount = 1;
|
|
44
|
+
let endIndex = startIndex + 1;
|
|
45
|
+
|
|
46
|
+
while (endIndex < trimmed.length && bracketCount > 0) {
|
|
47
|
+
const char = trimmed[endIndex];
|
|
48
|
+
if (char === openChar) {
|
|
49
|
+
bracketCount++;
|
|
50
|
+
} else if (char === closeChar) {
|
|
51
|
+
bracketCount--;
|
|
52
|
+
}
|
|
53
|
+
endIndex++;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (bracketCount === 0) {
|
|
57
|
+
return trimmed.substring(startIndex, endIndex);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Fallback: Find JSON boundaries anywhere in the text
|
|
20
62
|
const firstBracket = Math.min(
|
|
21
63
|
trimmed.indexOf('{') >= 0 ? trimmed.indexOf('{') : Infinity,
|
|
22
64
|
trimmed.indexOf('[') >= 0 ? trimmed.indexOf('[') : Infinity
|
|
@@ -29,12 +71,13 @@ export function cleanSchemaResponse(response) {
|
|
|
29
71
|
|
|
30
72
|
// Only extract if we found valid JSON boundaries
|
|
31
73
|
if (firstBracket < Infinity && lastBracket >= 0 && firstBracket < lastBracket) {
|
|
32
|
-
// Check if the response likely starts with JSON (directly or after
|
|
74
|
+
// Check if the response likely starts with JSON (directly or after minimal content)
|
|
33
75
|
const beforeFirstBracket = trimmed.substring(0, firstBracket).trim();
|
|
34
76
|
|
|
35
|
-
// If there's minimal content before the first bracket
|
|
36
|
-
|
|
37
|
-
|
|
77
|
+
// If there's minimal content before the first bracket, extract the JSON
|
|
78
|
+
if (beforeFirstBracket === '' ||
|
|
79
|
+
beforeFirstBracket.match(/^```\w*$/) ||
|
|
80
|
+
beforeFirstBracket.split('\n').length <= 2) {
|
|
38
81
|
return trimmed.substring(firstBracket, lastBracket + 1);
|
|
39
82
|
}
|
|
40
83
|
}
|
|
@@ -148,26 +191,44 @@ export function isJsonSchema(schema) {
|
|
|
148
191
|
* @param {string} invalidResponse - The invalid JSON response
|
|
149
192
|
* @param {string} schema - The original schema
|
|
150
193
|
* @param {string} error - The JSON parsing error
|
|
151
|
-
* @param {
|
|
194
|
+
* @param {number} [retryCount=0] - The current retry attempt (0-based)
|
|
152
195
|
* @returns {string} - Correction prompt for the AI
|
|
153
196
|
*/
|
|
154
|
-
export function createJsonCorrectionPrompt(invalidResponse, schema, error,
|
|
155
|
-
|
|
197
|
+
export function createJsonCorrectionPrompt(invalidResponse, schema, error, retryCount = 0) {
|
|
198
|
+
// Create increasingly stronger prompts based on retry attempt
|
|
199
|
+
const strengthLevels = [
|
|
200
|
+
{
|
|
201
|
+
prefix: "CRITICAL JSON ERROR:",
|
|
202
|
+
instruction: "You MUST fix this and return ONLY valid JSON.",
|
|
203
|
+
emphasis: "Return ONLY the corrected JSON, with no additional text or markdown formatting."
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
prefix: "URGENT - JSON PARSING FAILED:",
|
|
207
|
+
instruction: "This is your second chance. Return ONLY valid JSON that can be parsed by JSON.parse().",
|
|
208
|
+
emphasis: "ABSOLUTELY NO explanatory text, greetings, or formatting. ONLY JSON."
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
prefix: "FINAL ATTEMPT - CRITICAL JSON ERROR:",
|
|
212
|
+
instruction: "This is the final retry. You MUST return ONLY raw JSON without any other content.",
|
|
213
|
+
emphasis: "EXAMPLE: {\"key\": \"value\"} NOT: ```json{\"key\": \"value\"}``` NOT: Here is the JSON: {\"key\": \"value\"}"
|
|
214
|
+
}
|
|
215
|
+
];
|
|
156
216
|
|
|
157
|
-
|
|
217
|
+
const level = Math.min(retryCount, strengthLevels.length - 1);
|
|
218
|
+
const currentLevel = strengthLevels[level];
|
|
158
219
|
|
|
159
|
-
|
|
220
|
+
let prompt = `${currentLevel.prefix} Your previous response is not valid JSON and cannot be parsed. Here's what you returned:
|
|
160
221
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
222
|
+
${invalidResponse.substring(0, 500)}${invalidResponse.length > 500 ? '...' : ''}
|
|
223
|
+
|
|
224
|
+
Error: ${error}
|
|
164
225
|
|
|
165
|
-
|
|
226
|
+
${currentLevel.instruction}
|
|
166
227
|
|
|
167
|
-
|
|
228
|
+
Schema to match:
|
|
168
229
|
${schema}
|
|
169
230
|
|
|
170
|
-
|
|
231
|
+
${currentLevel.emphasis}`;
|
|
171
232
|
|
|
172
233
|
return prompt;
|
|
173
234
|
}
|