Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 45 additions & 1 deletion src/agents/planner-executor/plan-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,36 @@ function stripThinkingTags(content: string): string {
return cleaned;
}

/**
* Repair common JSON issues from LLM output.
*
* Handles:
* - Unquoted object keys (valid JS but not valid JSON): `reasoning:"..."` → `"reasoning":"..."`
* - Single-quoted strings: `'text'` → `"text"`
* - Trailing commas before `}` or `]`
*
* @param text - Raw text that looks like JSON but may have syntax issues
* @returns Repaired JSON string
*/
function repairJson(text: string): string {
let repaired = text;

// Add double quotes around unquoted object keys
// Matches: word-characters followed by colon (not already inside a string)
// Pattern: start of object `{` or comma `,`, optional whitespace, then unquoted key, then `:`
repaired = repaired.replace(/([{,]\s*)([\w$]+)\s*:/g, '$1"$2":');

// Replace single-quoted strings with double-quoted strings
// This is a simple heuristic — it won't handle escaped single quotes inside strings,
// but it handles the common case of LLMs outputting `'text'` instead of `"text"`
repaired = repaired.replace(/'([^']*)'/g, '"$1"');

// Remove trailing commas before } or ]
repaired = repaired.replace(/,\s*([}\]])/g, '$1');

return repaired;
}

/**
* Extract JSON from LLM response that may contain markdown or prose.
*
Expand Down Expand Up @@ -178,10 +208,24 @@ export function extractJson(content: string): Record<string, unknown> {
try {
return JSON.parse(jsonMatch[0]);
} catch {
// Continue to last resort
// Try to repair common JSON issues: unquoted keys (valid JS but not valid JSON)
try {
const repaired = repairJson(jsonMatch[0]);
return JSON.parse(repaired);
} catch {
// Continue to last resort
}
}
}

// Last resort: try to repair the entire cleaned content as a JS object literal
try {
const repaired = repairJson(cleaned);
return JSON.parse(repaired);
} catch {
// Give up
}

throw new Error(`Failed to extract JSON from response: ${cleaned.slice(0, 200)}`);
}

Expand Down
2 changes: 1 addition & 1 deletion src/agents/planner-executor/planner-executor-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@ export class PlannerExecutorAgent {
const startTime = Date.now();

// Initialize run state
this.runId = `run-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
this.runId = crypto.randomUUID();
this.actionHistory = [];
this.currentStepIndex = 0;
this.tokenCollector.reset();
Expand Down
Loading