"""Small JSON object extraction helpers for model output.""" from __future__ import annotations import json from typing import Any def parse_json_object(raw: str) -> dict[str, Any]: value = json.loads(_extract_json_object(raw)) if not isinstance(value, dict): raise ValueError("Expected a JSON object.") return value def _extract_json_object(raw: str) -> str: clean = _strip_markdown_fence(raw.strip()) candidate = _scan_json_object(clean) if candidate is None: raise ValueError("No JSON object found.") return candidate def _strip_markdown_fence(clean: str) -> str: if not clean.startswith("```"): return clean lines = clean.splitlines() if not lines: return clean if lines[0].strip().startswith("```"): lines = lines[1:] if lines and lines[-1].strip().startswith("```"): lines = lines[:-1] return "\n".join(lines).strip() def _scan_json_object(clean: str) -> str | None: start = clean.find("{") if start == -1: return None stack: list[str] = [] in_string = False escaped = False for index, char in enumerate(clean[start:], start=start): if in_string: if escaped: escaped = False elif char == "\\": escaped = True elif char == '"': in_string = False continue if char == '"': in_string = True elif char == "{": stack.append("}") elif char == "[": stack.append("]") elif char in {"}", "]"}: if not stack or stack[-1] != char: return None stack.pop() if not stack: return clean[start : index + 1] if in_string or not stack: return None return clean[start:] + "".join(reversed(stack))