Skip to content

fix(engine): review JSON output truncation — max_tokens 4096 caps every review call, no per-call override #232

Description

@djdembeck

Bug Description

Mira's review pipeline silently truncates findings when a chunk produces more output than llm.max_tokens (default 4096) allows. The LLM stops mid-JSON (finish_reason: length), and the response parser's repair logic silently re-balances braces so json.loads succeeds with a shorter comments array — tail findings are dropped without error.

Steps to Reproduce

  1. Configure mira with default llm.max_tokens=4096 (or leave unset).
  2. Submit a PR with a chunk dense enough to generate >10 review findings (e.g., multiple medium-severity issues in a single file).
  3. Observe that only the first several findings appear in the review; the remainder are silently absent.

Expected

All findings generated by the review LLM call are preserved. If output exceeds the token budget, mira either uses a larger budget for review calls or surfaces a visible warning.

Actual

The review path is engine._review_chunkself.llm.review()complete_with_tools()_call_llm_with_tools(). Every hop hardcodes self.config.max_tokens (default 4096), and complete_with_tools does not accept a max_tokens override at all. When the LLM exhausts its budget, the tool-call JSON ends mid-array. response_parser's _repair_json/_balance_json close dangling braces so parsing succeeds, and LLMReviewResponse.model_validate accepts the truncated comments array. No finish_reason inspection occurs.

Affected Code

  • src/mira/config.py:50LLMConfig.max_tokens default 4096, no per-purpose override
  • src/mira/llm/provider.py:214_call_llm_with_tools hardcodes max_tokens: self.config.max_tokens
  • src/mira/llm/provider.py:341_call_llm_agentic hardcodes the same
  • src/mira/llm/provider.py:403-421complete_with_tools() signature accepts no max_tokens (unlike complete() at 270-285)
  • src/mira/core/engine.py:1270-1286_review_chunk and ensemble calls pass no max_tokens
  • src/mira/core/passes.py:383-386self_critique uses complete_with_tools with no override
  • src/mira/llm/response_parser.py:51-133_repair_json/_balance_json silently re-balance truncated JSON without surfacing the truncation

Root Cause Analysis

The cause chain is: review calls cannot override max_tokens → default 4096 is too small for large finding batches (each comment is ~200-500 tokens in tool_schemas.py:12-108) → finish_reason: length fires mid-JSON → repair path produces valid-but-incomplete JSON → no error is raised, tail comments disappear. The indexing path already encountered this and added a ~16k cap (indexer.py:385-390) with the explicit comment: "4096 — large batches were getting truncated mid-JSON (finish_reason: length)". The review path lacks the same protection.

Possible Fix

  1. Thread a max_tokens parameter through complete_with_tools/_call_llm_with_tools/_call_llm_agentic, mirroring complete() (provider.py:270).
  2. Have review callers (engine._review_chunk, agentic loop, self_critique, security/dependency passes) pass a capped override — model max_output_tokens, default ~16384 like the indexer.
  3. Inspect finish_reason in _call_llm_with_tools; if it is "length", log a visible warning or raise so truncation is surfaced rather than silently absorbed.

Related Issues

None.

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions