@ducci/jarvis 1.0.52 → 1.0.54
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/package.json +1 -1
- package/src/server/agent.js +12 -6
- package/src/server/tools.js +3 -3
package/package.json
CHANGED
package/src/server/agent.js
CHANGED
|
@@ -9,6 +9,12 @@ import chalk from 'chalk';
|
|
|
9
9
|
|
|
10
10
|
const FORMAT_NUDGE = 'Your previous response was not valid JSON. Respond only with the required JSON object: {"response": "...", "logSummary": "..."}';
|
|
11
11
|
const LOOP_DETECTION_THRESHOLD = 3;
|
|
12
|
+
|
|
13
|
+
// Strip markdown code fences (```json...``` or ```...```) that models sometimes
|
|
14
|
+
// wrap around JSON responses, which would otherwise cause JSON.parse to throw.
|
|
15
|
+
function stripCodeFence(text) {
|
|
16
|
+
return text.replace(/^```(?:json)?\s*\n([\s\S]*?)\n?```\s*$/, '$1').trim();
|
|
17
|
+
}
|
|
12
18
|
const CONSECUTIVE_FAILURE_THRESHOLD = 3;
|
|
13
19
|
const MAX_TOOL_RESULT = 4000;
|
|
14
20
|
|
|
@@ -396,20 +402,20 @@ export async function runAgentLoop(client, config, session, prepareMessages, usa
|
|
|
396
402
|
if (nudgeContent.trim()) {
|
|
397
403
|
content = nudgeContent;
|
|
398
404
|
}
|
|
399
|
-
parsed = JSON.parse(nudgeContent);
|
|
405
|
+
parsed = JSON.parse(stripCodeFence(nudgeContent));
|
|
400
406
|
} catch {
|
|
401
407
|
// Fall through to !parsed handler; content may now carry the nudge text
|
|
402
408
|
}
|
|
403
409
|
} else {
|
|
404
410
|
try {
|
|
405
|
-
parsed = JSON.parse(content);
|
|
411
|
+
parsed = JSON.parse(stripCodeFence(content));
|
|
406
412
|
} catch {
|
|
407
413
|
// Step 1: retry with fallback model
|
|
408
414
|
try {
|
|
409
415
|
const fallbackResult = await callModel(client, config.fallbackModel, preparedMessages, toolDefs);
|
|
410
416
|
accumulateUsage(usageAccum, fallbackResult);
|
|
411
417
|
const fallbackContent = fallbackResult.choices[0]?.message?.content || '';
|
|
412
|
-
parsed = JSON.parse(fallbackContent);
|
|
418
|
+
parsed = JSON.parse(stripCodeFence(fallbackContent));
|
|
413
419
|
content = fallbackContent;
|
|
414
420
|
} catch {
|
|
415
421
|
// Step 2: nudge retry via both models
|
|
@@ -418,7 +424,7 @@ export async function runAgentLoop(client, config, session, prepareMessages, usa
|
|
|
418
424
|
const nudgeResult = await callModelWithFallback(client, config, nudgeMessages, toolDefs);
|
|
419
425
|
accumulateUsage(usageAccum, nudgeResult);
|
|
420
426
|
const nudgeContent = nudgeResult.choices[0]?.message?.content || '';
|
|
421
|
-
parsed = JSON.parse(nudgeContent);
|
|
427
|
+
parsed = JSON.parse(stripCodeFence(nudgeContent));
|
|
422
428
|
content = nudgeContent;
|
|
423
429
|
} catch {
|
|
424
430
|
// Give up
|
|
@@ -489,14 +495,14 @@ export async function runAgentLoop(client, config, session, prepareMessages, usa
|
|
|
489
495
|
|
|
490
496
|
// Try JSON parse; if it fails, nudge retry (Layer 2)
|
|
491
497
|
try {
|
|
492
|
-
parsedWrapUp = JSON.parse(wrapUpContent);
|
|
498
|
+
parsedWrapUp = JSON.parse(stripCodeFence(wrapUpContent));
|
|
493
499
|
} catch {
|
|
494
500
|
try {
|
|
495
501
|
const nudgeMessages = [...wrapUpMessages, { role: 'user', content: FORMAT_NUDGE }];
|
|
496
502
|
const nudgeResult = await callModelWithFallback(client, config, nudgeMessages, []);
|
|
497
503
|
accumulateUsage(usageAccum, nudgeResult);
|
|
498
504
|
const nudgeContent = nudgeResult.choices[0]?.message?.content || '';
|
|
499
|
-
parsedWrapUp = JSON.parse(nudgeContent);
|
|
505
|
+
parsedWrapUp = JSON.parse(stripCodeFence(nudgeContent));
|
|
500
506
|
wrapUpContent = nudgeContent;
|
|
501
507
|
} catch {
|
|
502
508
|
// Layer 3: use raw text as best-effort response below
|
package/src/server/tools.js
CHANGED
|
@@ -38,7 +38,7 @@ const SEED_TOOLS = {
|
|
|
38
38
|
},
|
|
39
39
|
},
|
|
40
40
|
code: `
|
|
41
|
-
const targetPath = path.resolve(args.path);
|
|
41
|
+
const targetPath = path.resolve(args.path.replace(/^~(?=\/|$)/, require('os').homedir()));
|
|
42
42
|
const raw = await fs.promises.readFile(targetPath, 'utf8');
|
|
43
43
|
const lines = raw.split('\\n');
|
|
44
44
|
const offset = args.offset ? args.offset - 1 : 0;
|
|
@@ -308,7 +308,7 @@ const SEED_TOOLS = {
|
|
|
308
308
|
},
|
|
309
309
|
},
|
|
310
310
|
code: `
|
|
311
|
-
const targetPath = path.resolve(args.path);
|
|
311
|
+
const targetPath = path.resolve(args.path.replace(/^~(?=\/|$)/, require('os').homedir()));
|
|
312
312
|
await fs.promises.mkdir(path.dirname(targetPath), { recursive: true });
|
|
313
313
|
await fs.promises.writeFile(targetPath, args.content, 'utf8');
|
|
314
314
|
if (args.mode) {
|
|
@@ -345,7 +345,7 @@ const SEED_TOOLS = {
|
|
|
345
345
|
},
|
|
346
346
|
},
|
|
347
347
|
code: `
|
|
348
|
-
const targetPath = path.resolve(args.path);
|
|
348
|
+
const targetPath = path.resolve(args.path.replace(/^~(?=\/|$)/, require('os').homedir()));
|
|
349
349
|
const content = await fs.promises.readFile(targetPath, 'utf8');
|
|
350
350
|
const count = content.split(args.old_string).length - 1;
|
|
351
351
|
if (count === 0) {
|