Class: Aireview::ReviewPipeline

Inherits:
Object
  • Object
show all
Defined in:
lib/aireview/review_pipeline.rb

Overview

A review run: context → Generate → anchoring check against the diff → Critique (an LLM, or Jev with llm.critique.engine: jev) → report. Invalid JSON is repaired once by the same model; when the repair is invalid too, the stage restarts on another model with the original request.

Constant Summary collapse

SchemaError =
ResultParser::SchemaError
REPAIR_SYSTEM_PROMPT =
<<~PROMPT.strip.freeze
  You fix invalid JSON produced by another LLM call.
  Return only valid JSON matching the requested schema.
  Do not use markdown, code fences, comments, or text outside JSON.
  Do not add new review findings.
PROMPT
CUT_OFF_REASONS =

Finish reasons after which an unparsable answer gets no repair.

{
  max_tokens: 'cut off at the output limit (max_tokens)',
  content_filter: 'blocked by the provider (content_filter)'
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(config:, reviewer: nil, context_builder: nil, logger: Logger.new($stderr), **jev) ⇒ ReviewPipeline

jev — jev_shadow: and jev_stage: for tests; by default they are built from the config, the stage only when Jev is the engine.



38
39
40
41
42
43
44
45
46
47
# File 'lib/aireview/review_pipeline.rb', line 38

def initialize(config:, reviewer: nil, context_builder: nil, logger: Logger.new($stderr), **jev)
  @config = config
  @parser = ResultParser.new
  @reviewer = reviewer || Reviewer.new(config: config, logger: logger)
  @context_builder = context_builder || ContextBuilder.new(config: config, logger: logger)
  @jev_shadow = jev[:jev_shadow] ||
                JevShadow.new(config: config, scrub: @context_builder.method(:scrub_text), logger: logger)
  @jev_stage = jev[:jev_stage]
  @logger = logger
end

Instance Method Details

#dry_run_prompts(merge_request:, changes:, jira_issue: nil, critique: true) ⇒ Object

The prompts of the run and everything --dry-run shows; see DryRunPrompts.



91
92
93
94
# File 'lib/aireview/review_pipeline.rb', line 91

def dry_run_prompts(merge_request:, changes:, jira_issue: nil, critique: true)
  DryRunPrompts.new(config: @config, context_builder: @context_builder, logger: @logger)
    .build(merge_request: merge_request, changes: changes, jira_issue: jira_issue, critique: critique)
end

#run(merge_request:, changes:, jira_issue: nil, critique: true) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/aireview/review_pipeline.rb', line 49

def run(merge_request:, changes:, jira_issue: nil, critique: true)
  context = @context_builder.prepare(
    merge_request: merge_request,
    changes: changes,
    jira_issue: jira_issue,
    critique: critique
  )
  generate_prompt = @context_builder.build_generate_prompt(context)
  @logger.info("Pipeline generate pass started (model=#{@config.generate_model})")
  generate_result = run_stage('generate') do
    parse_with_repair(
      raw: @reviewer.generate(**generate_prompt),
      kind: 'generate result',
      expected: 'generate',
      repair_stage: 'generate'
    )
  end
  summary = generate_result['summary']
  candidates = Array(generate_result['candidates'])
  @logger.info("Pipeline generate pass completed with #{candidates.size} candidate(s) " \
               "(model=#{@reviewer.answered_model('generate')})")
  candidates = check_candidates(context: context, changes: changes, candidates: candidates)

  accepted, jev_note = if critique
                         maybe_critique(context: context, candidates: candidates)
                       else
                         skip_critique(candidates)
                       end

  @logger.info("Pipeline finished with #{accepted.size} accepted finding(s)")

  ReviewRenderer.new(language: @config.review_language).render(
    accepted,
    summary: summary,
    coverage: context.coverage,
    fallback_models: @reviewer.fallback_models,
    critique_weaker: critique && @reviewer.critique_weaker?,
    jev_note: jev_note
  )
end