export function parseJsonObject(rawText: string): unknown { const trimmed = stripCodeFence(rawText.trim()); try { return JSON.parse(trimmed); } catch { const extracted = extractFirstJsonValue(trimmed); if (extracted === undefined) { throw new SyntaxError("No JSON value found in model response."); } return JSON.parse(extracted); } } function stripCodeFence(value: string): string { const match = value.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i); return match?.[1]?.trim() ?? value; } function extractFirstJsonValue(value: string): string | undefined { const start = findFirstJsonStart(value); if (start === -1) { return undefined; } const opener = value[start]; const closer = opener === "{" ? "}" : "]"; let depth = 0; let inString = false; let escaping = false; for (let index = start; index < value.length; index += 1) { const char = value[index]; if (inString) { if (escaping) { escaping = false; } else if (char === "\\") { escaping = true; } else if (char === "\"") { inString = false; } continue; } if (char === "\"") { inString = true; } else if (char === opener) { depth += 1; } else if (char === closer) { depth -= 1; if (depth === 0) { return value.slice(start, index + 1); } } } return undefined; } function findFirstJsonStart(value: string): number { const objectStart = value.indexOf("{"); const arrayStart = value.indexOf("["); if (objectStart === -1) { return arrayStart; } if (arrayStart === -1) { return objectStart; } return Math.min(objectStart, arrayStart); }