Skip to content

fix(judge): retry unusable json mode responses - #220

Merged
jithin23-kv merged 5 commits into
KeyValueSoftwareSystems:masterfrom
adity982:fix/json-mode-empty-verdict
Aug 4, 2026
Merged

fix(judge): retry unusable json mode responses#220
jithin23-kv merged 5 commits into
KeyValueSoftwareSystems:masterfrom
adity982:fix/json-mode-empty-verdict

Conversation

@adity982

@adity982 adity982 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

  • let the OpenAI-compatible completion helper validate extracted JSON for its caller
  • when JSON mode returns an unusable judge payload such as {}, retry exactly once without response_format
  • keep the second response as the terminal result and add regression coverage proving the fallback request omits JSON mode

Validation

  • full core suite: 167 tests, 164 passed, 3 expected skips
  • repository pre-commit hook: typecheck, lint, repo-wide Prettier, catalog generation, skill validation, and gitleaks

Closes #165

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of invalid, malformed, empty, or unacceptable JSON responses from compatible AI providers.
    • Automatically retries once without JSON mode when a response cannot be accepted.
    • Improved judge response handling to reject error verdicts while preserving valid results.
    • Added clearer guidance for malformed responses and empty content.
    • Improved token usage tracking and recovery during rate-limited requests.
    • Added stronger validation of provider responses for greater reliability.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4ad0d567-e48a-4ff1-a8de-a0c48e6d4272

📥 Commits

Reviewing files that changed from the base of the PR and between 5ad7a85 and 2182958.

📒 Files selected for processing (1)
  • core/tests/openaiCompatible.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • core/tests/openaiCompatible.test.ts

Walkthrough

The OpenAI-compatible completion path validates response structure and JSON acceptability. It retries once without JSON mode when validation fails. The judge rejects ERROR results, and tests cover retry, usage, rate-limit, and malformed-response handling.

Changes

JSON retry flow

Layer / File(s) Summary
Completion response contract
core/src/llm/openaiCompatible.ts
A Zod schema validates completion choices, message content, and optional token usage. chatCompletionJsonContent accepts an optional JSON predicate.
Completion parsing and fallback
core/src/llm/openaiCompatible.ts
The client drains discarded response bodies, records usage only from validated responses, reports structured provider errors, rejects empty content, and retries without response_format when the predicate rejects the JSON.
Judge integration and regression coverage
core/src/run/judge.ts, core/tests/openaiCompatible.test.ts
judgeToolResponse rejects ERROR results. Tests verify retry limits, request bodies, token accounting, rate-limit recovery, missing telemetry, null content, malformed responses, and state restoration.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Judge
  participant OpenAICompatibleClient
  participant Provider
  Judge->>OpenAICompatibleClient: Request JSON with validator
  OpenAICompatibleClient->>Provider: Send request with JSON mode
  Provider-->>OpenAICompatibleClient: Return completion response
  OpenAICompatibleClient->>OpenAICompatibleClient: Validate response and JSON
  OpenAICompatibleClient->>Provider: Retry without JSON mode
  Provider-->>OpenAICompatibleClient: Return fallback response
  OpenAICompatibleClient-->>Judge: Return extracted JSON
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the primary change: retrying unusable JSON-mode responses for judge calls.
Description check ✅ Passed The description explains the solution, affected behavior, issue reference, and validation results, although it does not use the repository template headings.
Linked Issues check ✅ Passed The implementation satisfies issue #165 by detecting unusable JSON, retrying once without JSON mode, and using the fallback response.
Out of Scope Changes check ✅ Passed The additional validation, retry recovery, telemetry handling, and regression tests support the linked issue and stated pull request objectives.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jithin23-kv

Copy link
Copy Markdown
Collaborator

Hi @adity982, appreciate you contributing to Agent Opfor.
I noticed this PR is still marked as a draft. Are you still working on more changes, or is it ready to be marked as ready for review?

@adity982
adity982 marked this pull request as ready for review July 31, 2026 07:23
@adity982

Copy link
Copy Markdown
Contributor Author

Thanks for checking in. The implementation and full local/CI validation are complete, so I have marked the PR ready for review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/src/llm/openaiCompatible.ts`:
- Around line 157-159: The empty-content error thrown in the OpenAI-compatible
response handling must tell users how to resolve the issue. Update the error
message in the content validation block to instruct them to configure the
provider or prompt to return a non-empty JSON completion.
- Around line 153-156: In core/src/llm/openaiCompatible.ts at lines 153-156,
replace the unsafe type assertion on response.json() with proper Zod validation
by first parsing the response as unknown, defining a Zod schema that describes
the expected structure with choices array containing message objects with
content, validating the parsed data against the schema, and throwing an
actionable error that includes details when validation fails. In
core/tests/openaiCompatible.test.ts at line 26, ensure the mocked request body
is similarly parsed as unknown and validated with the same Zod schema to
maintain consistency between test data and production validation logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dc1ccdf7-b552-40db-9464-d52069af0c43

📥 Commits

Reviewing files that changed from the base of the PR and between e45a62c and bb5fbd9.

📒 Files selected for processing (3)
  • core/src/llm/openaiCompatible.ts
  • core/src/run/judge.ts
  • core/tests/openaiCompatible.test.ts

Comment thread core/src/llm/openaiCompatible.ts Outdated
Comment thread core/src/llm/openaiCompatible.ts
@jithin23-kv

Copy link
Copy Markdown
Collaborator

Can you resolve the conflicts and address Coderabbit's review comments @adity982

@adity982

Copy link
Copy Markdown
Contributor Author

Refreshed this branch against current upstream master and resolved the overlap with the new token-accounting work. The JSON-mode retry behavior is preserved while TokenTracker/parseUsage are now wired through the same OpenAI-compatible and judge paths.\n\nValidation after resolution:\n- core test suite: 185 passed, 3 skipped, 0 failed\n- core TypeScript typecheck passed\n- full pre-commit checks passed: workspace typechecks, ESLint, Prettier, catalog builds, skill validation, and gitleaks\n\nUpdated head:

@adity982

Copy link
Copy Markdown
Contributor Author

Addressed both new CodeRabbit findings in 8783b2e: OpenAI-compatible provider responses are now Zod-validated with an actionable malformed-response error, and empty content now includes remediation guidance. Validation: core suite 186 passed / 3 skipped / 0 failed, core typecheck and Prettier passed, and the repository pre-commit gate passed. Both threads are resolved.

- Loosen the response schema so provider-supplied usage:null and
  content:null (both legal on the wire) can't fail an otherwise
  usable completion; the existing emptiness check already handles
  null content correctly.
- Route the JSON-mode fallback request through the same 400/429
  recovery path as the first attempt, so a rate-limited retry no
  longer throws away the fix this PR is making.
- Retry once when JSON-mode content fails to parse as JSON, not
  just when it round-trips to {}.
- Log the fallback so double LLM spend is diagnosable.
- Add regression coverage for each of the above.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/tests/openaiCompatible.test.ts`:
- Line 150: Update the test cases in the usage loop of textCompletion to include
undefined, covering the absent usage field alongside null and the partial usage
object.
- Line 45: Update the assertion message in the response-queue check to state the
corrective action: queue one response for every expected fetch call, while
retaining the existing context about excess fetches.
- Line 43: In the line where bodies.push() is called with JSON.parse, refactor
to parse the init?.body to unknown first instead of directly casting. Then
validate the parsed unknown value using a Zod schema such as z.record to ensure
it conforms to the expected structure. Only push the validated result to the
bodies array after the Zod validation succeeds. This separates the parsing step
from the type validation and ensures type safety without unvalidated casts.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b8ccdd76-bba3-4d2b-80f1-4eff2062c110

📥 Commits

Reviewing files that changed from the base of the PR and between 8783b2e and 5ad7a85.

📒 Files selected for processing (3)
  • core/src/llm/openaiCompatible.ts
  • core/src/run/judge.ts
  • core/tests/openaiCompatible.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • core/src/run/judge.ts
  • core/src/llm/openaiCompatible.ts

Comment thread core/tests/openaiCompatible.test.ts Outdated
Comment thread core/tests/openaiCompatible.test.ts Outdated
Comment thread core/tests/openaiCompatible.test.ts Outdated
Address CodeRabbit nits on the openaiCompatible fetch stub: parse the
captured request body through a Zod schema instead of an unvalidated
cast, make the queue-exhaustion assertion state the fix, and add the
undefined case so "omits usage telemetry" actually exercises a body
with no usage key.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@jithin23-kv
jithin23-kv merged commit 4dda117 into KeyValueSoftwareSystems:master Aug 4, 2026
8 checks passed
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.

bug: judge reports terminal ERROR on openai-compatible providers that return valid-but-empty JSON in json_object mode

2 participants