Skip to content

fix(gemini): recover JSON review when model emits prose before the envelope - #22

Open
AlgizPure wants to merge 1 commit into
abiswas97:mainfrom
AlgizPure:fix/parse-review-prose-before-json
Open

fix(gemini): recover JSON review when model emits prose before the envelope#22
AlgizPure wants to merge 1 commit into
abiswas97:mainfrom
AlgizPure:fix/parse-review-prose-before-json

Conversation

@AlgizPure

Copy link
Copy Markdown

Problem

parseReviewOutput (plugins/gemini/scripts/lib/gemini.mjs) strips a markdown code-fence only when it sits at offset 0:

.replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/i, "")

When Gemini streams narration before the JSON envelope — e.g.

I've checked .gitignore. Now let's check reindex_cases.py.
```json
{ "verdict": "...", "findings": [...] }

— the fence is no longer at offset 0, so `JSON.parse` runs on the prose and throws `REVIEW_PARSE_ERROR`. The entire review (a perfectly valid envelope sitting later in the output) is discarded and the lane reports a failure. This shows up often on research-heavy reviews where the model narrates its checks before converging to JSON.

## Repro

Feed `"some prose\n\`\`\`json\n{...valid review...}\n\`\`\`"` to `parseReviewOutput` → it throws instead of parsing the review that is right there.

## Fix

Additive `extractJsonCandidate` fallback in the `catch`: on parse failure, recover the JSON before giving up — take the **last** fenced ```` ```json ```` block (else the first-`{`..last-`}` run) and parse that; only throw `REVIEW_PARSE_ERROR` if that also fails.

- **Happy path unchanged** — clean output parses on the first `JSON.parse` and never reaches the fallback.
- **Genuinely non-JSON output still throws** `REVIEW_PARSE_ERROR`.

## Test

clean output : OK
fenced-only output : OK
prose + fenced (the bug): OK ← now recovered
prose + bare braces : OK
non-JSON garbage : throws REVIEW_PARSE_ERROR (unchanged)

…velope

parseReviewOutput strips a markdown code-fence only when it sits at offset 0:

    .replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/i, "")

When Gemini streams narration first (e.g. "I've checked .gitignore. Now let's
check reindex_cases.py") and only then the ```json block, the fence is no longer
at offset 0, so JSON.parse runs on the prose and throws REVIEW_PARSE_ERROR — the
entire review (a valid envelope sitting later in the output) is discarded. This
happens often on research-heavy reviews where the model narrates before
converging to JSON.

Fix: add an additive extractJsonCandidate fallback in the catch — on parse
failure, recover the JSON (last fenced ```json block, else the first-{..last-}
run) and parse that; only throw if that also fails. The happy path is unchanged
(clean output parses on the first try and never reaches the fallback); genuinely
non-JSON output still throws REVIEW_PARSE_ERROR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant