Repository navigation
refactor(llm): unify parse/repair/retry policy behind a Transport seam - #582
Merged
Merged
Conversation
Review, streaming review and scan now share one findings step (llm::findings) that owns empty-response recovery, parse, repair, partial salvage and the single stricter-prompt retry. llm.rs is split into transport / prompts / findings / repair modules; the LLM layer no longer prints (LlmEvents sink), so tests drive the policy with a fake transport. Closes #570 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: ajianaz <ajianaz@users.noreply.github.com>
This was referenced Oct 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Replace the 2.4k-line
engine/llm.rswithengine/llm/{mod,transport,prompts,findings,repair}.rs, built around ONE "structured findings from a model response" step (findings::request_findings) that owns empty-response recovery, parse, repair, partial salvage and the retry policy. Review, streaming review and scan all go through it.Why
Closes #570.
parse_review_response/parse_scan_responsehad diverged,review_diffretried with a stricter prompt butreview_diff_streamdid not, prompt assembly was duplicated, and llm.rs printed to stdout.How
trait Transport { async fn complete(&self, &Turn) -> Result<Completion> }(static dispatch).HttpTransportdoes non-stream and SSE; tests use scripted fakes (and an SSE replay that runs the realSseAccumulator) with no network.findings.rs):complete_with_recovery(review/scan: reasoning models can return empty content — misleading 'EOF while parsing' error #536: empty +finish_reason=lengthdoubles the budget up to the ceiling, else salvage fromreasoning_content, else explicit error),parse_findings(strict -> truncation repair -> salvage of complete objects, one function for both flows), then one stricter-prompt retry. Used by review, stream and scan, andcomplete_with_recoveryalso by the raw commit-message calls.LlmEvents(status/delta/retry, all no-op by default). Spinner is anLlmEventsimpl inllm/mod.rs;progress::StdoutStreamprints deltas forreview --stream/commit --stream.build_scan_prompt+ sharedpush_focus_and_rulesreplace the inline assembly inscan_files; fix(llm): harden response parsing, prompt injection and stream limits #573 hardening (untrusted-data clause, diff fence, SSE caps) kept and now tested on the retry path too.chat_request_*tests now exercise the realbuild_request_body.Behavior changes (user-visible)
StdoutStream::retryprints a one-line notice to stderr before the second stream; the discarded first output has already been written to stdout (can't be unprinted).finish_reasonandreasoning_contentdeltas.provider returned an EMPTY response ... LLM response is not valid JSON (length=0) ...so both old assertions hold; scan's non-JSON message now also applies to review.review.rs) on success, as before.Testing
cargo test --features tree-sitterpasses (1036 unit + integration)cargo fmt --all -- --checkpassescargo clippy --all-targets --features tree-sitter -- -D warningspasses]and|||inside a finding body (fix(llm): harden response parsing, prompt injection and stream limits #573); empty +lengthdoubles the budget (plain and SSE); ceiling -> explicit error; reasoning salvage; retry starts from escalated budget; review/scan share the retry; hardening present on retry; SSE decoding across split chunks, line cap, total cap; request body max-token param naming.Related Issues
Closes #570
Checklist
develop🤖 Generated with Claude Code