sterilize hot-fixes: 300s timeout + defensive string→dict parsing
Two failures surfaced by job 6 with the bigger prompt (full Mealie food
catalog ~50KB + recipe context with steps + spell-cleanup rules):
1. quinoa-chili-with-sweet-potatoes: 180s timeout. The bigger prompt
means Sonnet has more to chew through per call. Bumped _parse_batch
timeout 180s → 300s. Recipes with many ingredients now get more
slack before clawdforge gives up.
2. salmon-sushi-bake: "unexpected response shape" — Sonnet returned
the JSON as a STRING rather than a parsed dict (depends on size +
how clawdforge unwraps the response). _parse_batch was strictly
requiring isinstance(result, dict) and rejecting strings outright,
leaving the recipe in error state with valid JSON visible in the
error message. Added defensive string→dict parsing (with optional
code-fence stripping) mirroring the pattern already used by
forge._extract_food_info.
Both errored recipes from job 6 can now be re-run cleanly. Apply path
unchanged — defensive food.id preservation from 6bcf79e still in
effect.
This commit is contained in:
parent
6bcf79e5dc
commit
d97fdbc407
1 changed files with 17 additions and 1 deletions
|
|
@ -533,12 +533,28 @@ class Sterilizer:
|
||||||
prompt=prompt,
|
prompt=prompt,
|
||||||
model=self.model,
|
model=self.model,
|
||||||
system=self._system_prompt(),
|
system=self._system_prompt(),
|
||||||
timeout_secs=180,
|
timeout_secs=300,
|
||||||
)
|
)
|
||||||
except ForgeError as e:
|
except ForgeError as e:
|
||||||
raise RuntimeError(f"clawdforge failed: {e}") from e
|
raise RuntimeError(f"clawdforge failed: {e}") from e
|
||||||
|
|
||||||
result = resp.get("result")
|
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:
|
if not isinstance(result, dict) or "parses" not in result:
|
||||||
raise RuntimeError(f"unexpected response shape: {str(result)[:200]}")
|
raise RuntimeError(f"unexpected response shape: {str(result)[:200]}")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue