diff --git a/cauldron/sterilizer.py b/cauldron/sterilizer.py index f1554eb..1a9cc0e 100644 --- a/cauldron/sterilizer.py +++ b/cauldron/sterilizer.py @@ -533,12 +533,28 @@ class Sterilizer: prompt=prompt, model=self.model, system=self._system_prompt(), - timeout_secs=180, + timeout_secs=300, ) except ForgeError as e: raise RuntimeError(f"clawdforge failed: {e}") from e result = resp.get("result") + # Sonnet sometimes returns the JSON as a string rather than a parsed + # dict (depends on output size + clawdforge's parsing). Defensively + # parse if so, mirroring forge._extract_food_info's pattern. + if isinstance(result, str): + try: + stripped = result.strip() + # Strip optional code fences + if stripped.startswith("```"): + import re as _re + stripped = _re.sub(r"^```(?:json)?\s*", "", stripped) + stripped = _re.sub(r"\s*```$", "", stripped) + result = json.loads(stripped) + except Exception: + # Fall through to the shape-check below; will raise with + # the (truncated) original string for debugging + pass if not isinstance(result, dict) or "parses" not in result: raise RuntimeError(f"unexpected response shape: {str(result)[:200]}")