11use anyhow:: Result ;
22
3+ #[ path = "file_context/base.rs" ]
4+ mod base;
5+ #[ path = "file_context/finalize.rs" ]
6+ mod finalize;
7+ #[ path = "file_context/sources.rs" ]
8+ mod sources;
9+
310use crate :: config;
411use crate :: core;
512
6- use super :: context:: { extract_symbols_from_diff, gather_related_file_context} ;
713use super :: services:: PipelineServices ;
814use super :: session:: ReviewSession ;
915
@@ -21,191 +27,21 @@ pub(super) async fn assemble_file_context(
2127 pre_analysis_context : Vec < core:: LLMContextChunk > ,
2228 deterministic_comments : Vec < core:: Comment > ,
2329) -> Result < PreparedFileContext > {
24- let mut builder =
25- FileContextBuilder :: new ( services, session, diff, pre_analysis_context) . await ?;
26- builder. add_symbol_context ( ) . await ?;
27- builder. add_related_file_context ( ) ;
28- builder. add_semantic_context ( ) . await ;
29- builder. add_path_context ( ) . await ?;
30- builder. inject_repository_context ( ) . await ?;
31- Ok ( builder. finalize ( deterministic_comments) )
32- }
33-
34- struct FileContextBuilder < ' a > {
35- services : & ' a PipelineServices ,
36- session : & ' a ReviewSession ,
37- diff : & ' a core:: UnifiedDiff ,
38- context_chunks : Vec < core:: LLMContextChunk > ,
39- path_config : Option < config:: PathConfig > ,
40- }
41-
42- impl < ' a > FileContextBuilder < ' a > {
43- async fn new (
44- services : & ' a PipelineServices ,
45- session : & ' a ReviewSession ,
46- diff : & ' a core:: UnifiedDiff ,
47- pre_analysis_context : Vec < core:: LLMContextChunk > ,
48- ) -> Result < Self > {
49- let mut context_chunks = services
50- . context_fetcher
51- . fetch_context_for_file ( & diff. file_path , & changed_line_ranges ( diff) )
52- . await ?;
53- context_chunks. extend ( pre_analysis_context) ;
54-
55- Ok ( Self {
56- services,
57- session,
58- diff,
59- context_chunks,
60- path_config : services. config . get_path_config ( & diff. file_path ) . cloned ( ) ,
61- } )
62- }
63-
64- async fn add_symbol_context ( & mut self ) -> Result < ( ) > {
65- let symbols = extract_symbols_from_diff ( self . diff ) ;
66- if symbols. is_empty ( ) {
67- return Ok ( ( ) ) ;
68- }
69-
70- let definition_chunks = self
71- . services
72- . context_fetcher
73- . fetch_related_definitions ( & self . diff . file_path , & symbols)
74- . await ?;
75- self . context_chunks . extend ( definition_chunks) ;
76-
77- if let Some ( index) = self . session . symbol_index . as_ref ( ) {
78- let index_chunks = self
79- . services
80- . context_fetcher
81- . fetch_related_definitions_with_index (
82- & self . diff . file_path ,
83- & symbols,
84- index,
85- self . services . config . symbol_index_max_locations ,
86- self . services . config . symbol_index_graph_hops ,
87- self . services . config . symbol_index_graph_max_files ,
88- )
89- . await ?;
90- self . context_chunks . extend ( index_chunks) ;
91- }
92-
93- Ok ( ( ) )
94- }
95-
96- fn add_related_file_context ( & mut self ) {
97- if let Some ( index) = self . session . symbol_index . as_ref ( ) {
98- let caller_chunks =
99- gather_related_file_context ( index, & self . diff . file_path , & self . services . repo_path ) ;
100- self . context_chunks . extend ( caller_chunks) ;
101- }
102- }
103-
104- async fn add_semantic_context ( & mut self ) {
105- let Some ( index) = self . session . semantic_index . as_ref ( ) else {
106- return ;
107- } ;
108-
109- let semantic_chunks = core:: semantic_context_for_diff (
110- index,
111- self . diff ,
112- self . session
113- . source_files
114- . get ( & self . diff . file_path )
115- . map ( |content| content. as_str ( ) ) ,
116- self . services . embedding_adapter . as_deref ( ) ,
117- self . services . config . semantic_rag_top_k ,
118- self . services . config . semantic_rag_min_similarity ,
119- )
120- . await ;
121- self . context_chunks . extend ( semantic_chunks) ;
122- }
123-
124- async fn add_path_context ( & mut self ) -> Result < ( ) > {
125- let Some ( path_config) = self . path_config . as_ref ( ) else {
126- return Ok ( ( ) ) ;
127- } ;
128-
129- if !path_config. focus . is_empty ( ) {
130- self . context_chunks . push (
131- core:: LLMContextChunk :: documentation (
132- self . diff . file_path . clone ( ) ,
133- format ! (
134- "Focus areas for this file: {}" ,
135- path_config. focus. join( ", " )
136- ) ,
137- )
138- . with_provenance ( core:: ContextProvenance :: PathSpecificFocusAreas ) ,
139- ) ;
140- }
141-
142- if !path_config. extra_context . is_empty ( ) {
143- let extra_chunks = self
144- . services
145- . context_fetcher
146- . fetch_additional_context ( & path_config. extra_context )
147- . await ?;
148- self . context_chunks . extend ( extra_chunks) ;
149- }
150-
151- Ok ( ( ) )
152- }
153-
154- async fn inject_repository_context ( & mut self ) -> Result < ( ) > {
155- super :: super :: context_helpers:: inject_custom_context (
156- & self . services . config ,
157- & self . services . context_fetcher ,
158- self . diff ,
159- & mut self . context_chunks ,
160- )
161- . await ?;
162- super :: super :: context_helpers:: inject_pattern_repository_context (
163- & self . services . config ,
164- & self . services . pattern_repositories ,
165- & self . services . context_fetcher ,
166- self . diff ,
167- & mut self . context_chunks ,
168- )
169- . await ?;
170-
171- Ok ( ( ) )
172- }
173-
174- fn finalize ( mut self , deterministic_comments : Vec < core:: Comment > ) -> PreparedFileContext {
175- let active_rules = core:: active_rules_for_file (
176- & self . services . review_rules ,
177- & self . diff . file_path ,
178- self . services . config . max_active_rules ,
179- ) ;
180- super :: super :: rule_helpers:: inject_rule_context (
181- self . diff ,
182- & active_rules,
183- & mut self . context_chunks ,
184- ) ;
185- self . context_chunks = super :: super :: context_helpers:: rank_and_trim_context_chunks (
186- self . diff ,
187- self . context_chunks ,
188- self . services . config . context_max_chunks ,
189- self . services . config . context_budget_chars ,
190- ) ;
191-
192- PreparedFileContext {
193- active_rules,
194- path_config : self . path_config ,
195- deterministic_comments,
196- context_chunks : self . context_chunks ,
197- }
198- }
199- }
200-
201- fn changed_line_ranges ( diff : & core:: UnifiedDiff ) -> Vec < ( usize , usize ) > {
202- diff. hunks
203- . iter ( )
204- . map ( |hunk| {
205- (
206- hunk. new_start ,
207- hunk. new_start + hunk. new_lines . saturating_sub ( 1 ) ,
208- )
209- } )
210- . collect ( )
30+ let path_config = services. config . get_path_config ( & diff. file_path ) . cloned ( ) ;
31+ let mut context_chunks =
32+ base:: initial_context_chunks ( services, diff, pre_analysis_context) . await ?;
33+
34+ sources:: add_symbol_context ( services, session, diff, & mut context_chunks) . await ?;
35+ sources:: add_related_file_context ( services, session, diff, & mut context_chunks) ;
36+ sources:: add_semantic_context ( services, session, diff, & mut context_chunks) . await ;
37+ sources:: add_path_context ( services, diff, path_config. as_ref ( ) , & mut context_chunks) . await ?;
38+ sources:: inject_repository_context ( services, diff, & mut context_chunks) . await ?;
39+
40+ Ok ( finalize:: finalize_file_context (
41+ services,
42+ diff,
43+ path_config,
44+ deterministic_comments,
45+ context_chunks,
46+ ) )
21147}
0 commit comments