From c07e4397aaba3d6c83ab5413b4b86b98c694aadf Mon Sep 17 00:00:00 2001 From: Adam Moussa Date: Wed, 1 Jul 2026 19:11:09 -0400 Subject: [PATCH] Harden review JSON parsing against reasoning models Some Fireworks models emit chain-of-thought before the JSON review, and that preamble can contain stray "{". The old first-"{"-to-last-"}" span then grabbed reasoning braces and failed to parse (seen live on a real PR). Scan each "{" and return the first substring that actually decodes to an object instead, so a preamble or trailing prose no longer breaks the review. --- app/reviewer.py | 19 +++++++++++++++---- tests/test_reviewer.py | 6 ++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/app/reviewer.py b/app/reviewer.py index 6e5acd9..e1cc35e 100644 --- a/app/reviewer.py +++ b/app/reviewer.py @@ -173,7 +173,18 @@ def _safe_json(text: str) -> dict[str, Any]: try: return json.loads(text) except json.JSONDecodeError: - start, end = text.find("{"), text.rfind("}") - if start != -1 and end != -1: - return json.loads(text[start : end + 1]) - raise + pass + # Reasoning models often emit chain-of-thought (which may contain stray "{") + # before the JSON object. Scan every "{" and return the first that decodes to + # an object, rather than assuming the span from the first "{" to the last "}". + decoder = json.JSONDecoder() + for i, ch in enumerate(text): + if ch != "{": + continue + try: + obj, _ = decoder.raw_decode(text[i:]) + except json.JSONDecodeError: + continue + if isinstance(obj, dict): + return obj + raise json.JSONDecodeError("no JSON object found", text, 0) diff --git a/tests/test_reviewer.py b/tests/test_reviewer.py index 726b14d..0eb1a19 100644 --- a/tests/test_reviewer.py +++ b/tests/test_reviewer.py @@ -36,6 +36,12 @@ def test_safe_json_prose_wrapped() -> None: assert _safe_json(text) == {"summary": "ok"} +def test_safe_json_skips_reasoning_braces() -> None: + # A reasoning preamble containing stray "{" must not confuse extraction. + text = 'We should return {the result}. Final: {"summary": "ok", "block": []} done.' + assert _safe_json(text) == {"summary": "ok", "block": []} + + def test_safe_json_malformed_raises() -> None: with pytest.raises(json.JSONDecodeError): _safe_json("this is not json at all")