Skip to content

Commit e45c9e9

Browse files
committed
refactor: split review response processing helpers
Made-with: Cursor
1 parent 87d550b commit e45c9e9

File tree

7 files changed

+203
-138
lines changed

7 files changed

+203
-138
lines changed

TODO.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595

9696
### Review pipeline backlog
9797

98-
- [ ] `src/review/pipeline/execution/responses/processing.rs`: split raw response normalization, comment extraction, and merge logic.
98+
- [x] `src/review/pipeline/execution/responses/processing.rs`: split raw response normalization, comment extraction, and merge logic.
9999
- [ ] `src/review/pipeline/execution/responses/validation.rs`: separate schema validation from per-comment sanitization.
100100
- [ ] `src/review/pipeline/prepare/runner.rs`: split per-diff orchestration, pre-analysis/triage decisions, and progress updates.
101101
- [ ] `src/review/pipeline/context/symbols.rs`: split symbol search, snippet selection, and fallback behavior.
Lines changed: 13 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
use anyhow::Result;
1+
#[path = "processing/comments.rs"]
2+
mod comments;
3+
#[path = "processing/fallback.rs"]
4+
mod fallback;
5+
#[path = "processing/merge.rs"]
6+
mod merge;
7+
#[path = "processing/run.rs"]
8+
mod run;
9+
#[path = "processing/usage.rs"]
10+
mod usage;
11+
212
use std::path::PathBuf;
3-
use tracing::warn;
413

5-
use crate::adapters::llm::LLMResponse;
614
use crate::core;
7-
use crate::parsing::parse_llm_response;
8-
use crate::review::{apply_rule_overrides, filter_comments_for_diff, AgentActivity};
9-
10-
use super::super::dispatcher::DispatchedJobResult;
11-
use super::overrides::{apply_path_severity_overrides, apply_specialized_pass_tags};
12-
use super::validation::validate_llm_response;
15+
use crate::review::AgentActivity;
1316

1417
pub(in super::super) struct ProcessedJobResult {
1518
pub file_path: PathBuf,
@@ -31,131 +34,4 @@ struct ResponseUsage {
3134
total_tokens: usize,
3235
}
3336

34-
pub(in super::super) fn process_job_result(
35-
result: DispatchedJobResult,
36-
diff: &core::UnifiedDiff,
37-
is_local: bool,
38-
) -> Result<ProcessedJobResult> {
39-
let DispatchedJobResult {
40-
active_rules,
41-
path_config,
42-
file_path,
43-
deterministic_comments,
44-
pass_kind,
45-
mark_file_complete,
46-
response,
47-
latency_ms,
48-
agent_data,
49-
..
50-
} = result;
51-
52-
match response {
53-
Err(error) => {
54-
warn!("LLM request failed for {}: {}", file_path.display(), error);
55-
Ok(fallback_result(
56-
file_path,
57-
deterministic_comments,
58-
mark_file_complete,
59-
latency_ms,
60-
ResponseUsage::default(),
61-
agent_data,
62-
))
63-
}
64-
Ok(response) => {
65-
let usage = response_usage(&response);
66-
67-
if let Err(validation_error) = validate_llm_response(&response.content) {
68-
eprintln!(
69-
"Warning: LLM response validation failed for {}: {}",
70-
file_path.display(),
71-
validation_error
72-
);
73-
if is_local {
74-
eprintln!(
75-
"Hint: Try a larger model or reduce diff size for better results with local models."
76-
);
77-
}
78-
return Ok(fallback_result(
79-
file_path,
80-
deterministic_comments,
81-
mark_file_complete,
82-
latency_ms,
83-
usage,
84-
agent_data,
85-
));
86-
}
87-
88-
let Ok(raw_comments) = parse_llm_response(&response.content, &diff.file_path) else {
89-
return Ok(fallback_result(
90-
file_path,
91-
deterministic_comments,
92-
mark_file_complete,
93-
latency_ms,
94-
usage,
95-
agent_data,
96-
));
97-
};
98-
99-
let mut comments = core::CommentSynthesizer::synthesize(raw_comments)?;
100-
apply_specialized_pass_tags(&mut comments, pass_kind);
101-
apply_path_severity_overrides(&mut comments, path_config.as_ref());
102-
103-
let comments = apply_rule_overrides(comments, &active_rules);
104-
105-
let mut comments = filter_comments_for_diff(diff, comments);
106-
comments.extend(deterministic_comments);
107-
108-
Ok(ProcessedJobResult {
109-
file_path,
110-
comment_count: comments.len(),
111-
comments,
112-
latency_ms,
113-
prompt_tokens: usage.prompt_tokens,
114-
completion_tokens: usage.completion_tokens,
115-
total_tokens: usage.total_tokens,
116-
pass_tag: Some(
117-
pass_kind
118-
.map(|kind| kind.tag().to_string())
119-
.unwrap_or_else(|| "default".to_string()),
120-
),
121-
mark_file_complete,
122-
agent_data,
123-
})
124-
}
125-
}
126-
}
127-
128-
fn fallback_result(
129-
file_path: PathBuf,
130-
comments: Vec<core::Comment>,
131-
mark_file_complete: bool,
132-
latency_ms: u64,
133-
usage: ResponseUsage,
134-
agent_data: Option<AgentActivity>,
135-
) -> ProcessedJobResult {
136-
let comment_count = comments.len();
137-
ProcessedJobResult {
138-
file_path,
139-
comments,
140-
latency_ms,
141-
prompt_tokens: usage.prompt_tokens,
142-
completion_tokens: usage.completion_tokens,
143-
total_tokens: usage.total_tokens,
144-
comment_count,
145-
pass_tag: None,
146-
mark_file_complete,
147-
agent_data,
148-
}
149-
}
150-
151-
fn response_usage(response: &LLMResponse) -> ResponseUsage {
152-
response
153-
.usage
154-
.as_ref()
155-
.map(|usage| ResponseUsage {
156-
prompt_tokens: usage.prompt_tokens,
157-
completion_tokens: usage.completion_tokens,
158-
total_tokens: usage.total_tokens,
159-
})
160-
.unwrap_or_default()
161-
}
37+
pub(in super::super) use run::process_job_result;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use anyhow::Result;
2+
3+
use crate::config;
4+
use crate::core;
5+
use crate::parsing::parse_llm_response;
6+
use crate::review::apply_rule_overrides;
7+
8+
use super::super::overrides::{apply_path_severity_overrides, apply_specialized_pass_tags};
9+
10+
pub(super) fn extract_processed_comments(
11+
response_content: &str,
12+
diff: &core::UnifiedDiff,
13+
active_rules: &[core::ReviewRule],
14+
path_config: Option<&config::PathConfig>,
15+
pass_kind: Option<core::SpecializedPassKind>,
16+
) -> Result<Option<Vec<core::Comment>>> {
17+
let Ok(raw_comments) = parse_llm_response(response_content, &diff.file_path) else {
18+
return Ok(None);
19+
};
20+
21+
let mut comments = core::CommentSynthesizer::synthesize(raw_comments)?;
22+
apply_specialized_pass_tags(&mut comments, pass_kind);
23+
apply_path_severity_overrides(&mut comments, path_config);
24+
25+
let comments = apply_rule_overrides(comments, active_rules);
26+
Ok(Some(comments))
27+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use std::path::PathBuf;
2+
3+
use crate::core;
4+
use crate::review::AgentActivity;
5+
6+
use super::{ProcessedJobResult, ResponseUsage};
7+
8+
pub(super) fn fallback_result(
9+
file_path: PathBuf,
10+
comments: Vec<core::Comment>,
11+
mark_file_complete: bool,
12+
latency_ms: u64,
13+
usage: ResponseUsage,
14+
agent_data: Option<AgentActivity>,
15+
) -> ProcessedJobResult {
16+
let comment_count = comments.len();
17+
ProcessedJobResult {
18+
file_path,
19+
comments,
20+
latency_ms,
21+
prompt_tokens: usage.prompt_tokens,
22+
completion_tokens: usage.completion_tokens,
23+
total_tokens: usage.total_tokens,
24+
comment_count,
25+
pass_tag: None,
26+
mark_file_complete,
27+
agent_data,
28+
}
29+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use crate::core;
2+
use crate::review::filter_comments_for_diff;
3+
4+
pub(super) fn merge_processed_comments(
5+
diff: &core::UnifiedDiff,
6+
comments: Vec<core::Comment>,
7+
deterministic_comments: Vec<core::Comment>,
8+
) -> Vec<core::Comment> {
9+
let mut comments = filter_comments_for_diff(diff, comments);
10+
comments.extend(deterministic_comments);
11+
comments
12+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
use anyhow::Result;
2+
use tracing::warn;
3+
4+
use crate::core;
5+
6+
use super::super::super::dispatcher::DispatchedJobResult;
7+
use super::super::validation::validate_llm_response;
8+
use super::comments::extract_processed_comments;
9+
use super::fallback::fallback_result;
10+
use super::merge::merge_processed_comments;
11+
use super::usage::response_usage;
12+
use super::{ProcessedJobResult, ResponseUsage};
13+
14+
pub(in super::super::super) fn process_job_result(
15+
result: DispatchedJobResult,
16+
diff: &core::UnifiedDiff,
17+
is_local: bool,
18+
) -> Result<ProcessedJobResult> {
19+
let DispatchedJobResult {
20+
active_rules,
21+
path_config,
22+
file_path,
23+
deterministic_comments,
24+
pass_kind,
25+
mark_file_complete,
26+
response,
27+
latency_ms,
28+
agent_data,
29+
..
30+
} = result;
31+
32+
match response {
33+
Err(error) => {
34+
warn!("LLM request failed for {}: {}", file_path.display(), error);
35+
Ok(fallback_result(
36+
file_path,
37+
deterministic_comments,
38+
mark_file_complete,
39+
latency_ms,
40+
ResponseUsage::default(),
41+
agent_data,
42+
))
43+
}
44+
Ok(response) => {
45+
let usage = response_usage(&response);
46+
47+
if let Err(validation_error) = validate_llm_response(&response.content) {
48+
eprintln!(
49+
"Warning: LLM response validation failed for {}: {}",
50+
file_path.display(),
51+
validation_error
52+
);
53+
if is_local {
54+
eprintln!(
55+
"Hint: Try a larger model or reduce diff size for better results with local models."
56+
);
57+
}
58+
return Ok(fallback_result(
59+
file_path,
60+
deterministic_comments,
61+
mark_file_complete,
62+
latency_ms,
63+
usage,
64+
agent_data,
65+
));
66+
}
67+
68+
let Some(comments) = extract_processed_comments(
69+
&response.content,
70+
diff,
71+
&active_rules,
72+
path_config.as_ref(),
73+
pass_kind,
74+
)?
75+
else {
76+
return Ok(fallback_result(
77+
file_path,
78+
deterministic_comments,
79+
mark_file_complete,
80+
latency_ms,
81+
usage,
82+
agent_data,
83+
));
84+
};
85+
86+
let comments = merge_processed_comments(diff, comments, deterministic_comments);
87+
88+
Ok(ProcessedJobResult {
89+
file_path,
90+
comment_count: comments.len(),
91+
comments,
92+
latency_ms,
93+
prompt_tokens: usage.prompt_tokens,
94+
completion_tokens: usage.completion_tokens,
95+
total_tokens: usage.total_tokens,
96+
pass_tag: Some(
97+
pass_kind
98+
.map(|kind| kind.tag().to_string())
99+
.unwrap_or_else(|| "default".to_string()),
100+
),
101+
mark_file_complete,
102+
agent_data,
103+
})
104+
}
105+
}
106+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use crate::adapters::llm::LLMResponse;
2+
3+
use super::ResponseUsage;
4+
5+
pub(super) fn response_usage(response: &LLMResponse) -> ResponseUsage {
6+
response
7+
.usage
8+
.as_ref()
9+
.map(|usage| ResponseUsage {
10+
prompt_tokens: usage.prompt_tokens,
11+
completion_tokens: usage.completion_tokens,
12+
total_tokens: usage.total_tokens,
13+
})
14+
.unwrap_or_default()
15+
}

0 commit comments

Comments
 (0)