@@ -13,6 +13,8 @@ pub struct LLMContextChunk {
1313 pub content : String ,
1414 pub context_type : ContextType ,
1515 pub line_range : Option < ( usize , usize ) > ,
16+ #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
17+ pub provenance : Option < String > ,
1618}
1719
1820#[ derive( Debug , Clone , PartialEq , Serialize , Deserialize ) ]
@@ -74,6 +76,7 @@ impl ContextFetcher {
7476 content : chunk_content,
7577 context_type : ContextType :: FileContent ,
7678 line_range : Some ( ( expanded_start, expanded_end) ) ,
79+ provenance : None ,
7780 } ) ;
7881 }
7982 }
@@ -137,6 +140,7 @@ impl ContextFetcher {
137140 content : snippet,
138141 context_type : ContextType :: Reference ,
139142 line_range : None ,
143+ provenance : None ,
140144 } ) ;
141145 }
142146
@@ -185,6 +189,7 @@ impl ContextFetcher {
185189 content : definition_content,
186190 context_type : ContextType :: Definition ,
187191 line_range : Some ( ( start_line + 1 , end_line) ) ,
192+ provenance : None ,
188193 } ) ;
189194 }
190195 }
@@ -222,11 +227,32 @@ impl ContextFetcher {
222227 content : snippet,
223228 context_type : ContextType :: Definition ,
224229 line_range : Some ( location. line_range ) ,
230+ provenance : location. provenance . clone ( ) ,
225231 } ) ;
226232 }
227233 }
228234 }
229235
236+ for location in index. graph_related_locations (
237+ file_path,
238+ symbols,
239+ graph_hops,
240+ max_locations,
241+ graph_max_files,
242+ ) {
243+ if & location. file_path == file_path {
244+ continue ;
245+ }
246+ let snippet = truncate_with_notice ( location. snippet , MAX_CONTEXT_CHARS ) ;
247+ chunks. push ( LLMContextChunk {
248+ file_path : location. file_path ,
249+ content : snippet,
250+ context_type : ContextType :: Definition ,
251+ line_range : Some ( location. line_range ) ,
252+ provenance : location. provenance ,
253+ } ) ;
254+ }
255+
230256 for location in index. multi_hop_locations (
231257 file_path,
232258 symbols,
@@ -243,6 +269,7 @@ impl ContextFetcher {
243269 content : snippet,
244270 context_type : ContextType :: Reference ,
245271 line_range : Some ( location. line_range ) ,
272+ provenance : location. provenance ,
246273 } ) ;
247274 }
248275
@@ -373,4 +400,55 @@ mod tests {
373400 let chunk = & chunks[ 0 ] ;
374401 assert ! ( chunk. content. contains( "pub fn process" ) ) ;
375402 }
403+
404+ #[ tokio:: test]
405+ async fn test_fetch_related_definitions_with_index_uses_symbol_graph_neighbors ( ) {
406+ let dir = tempfile:: tempdir ( ) . unwrap ( ) ;
407+ let src_dir = dir. path ( ) . join ( "src" ) ;
408+ std:: fs:: create_dir_all ( & src_dir) . unwrap ( ) ;
409+
410+ std:: fs:: write (
411+ src_dir. join ( "auth.rs" ) ,
412+ "pub fn validate_token(token: &str) -> bool {\n token.len() > 10\n }\n " ,
413+ )
414+ . unwrap ( ) ;
415+ std:: fs:: write (
416+ src_dir. join ( "handler.rs" ) ,
417+ "use crate::auth::validate_token;\n \n pub fn handle_request(token: &str) -> bool {\n validate_token(token)\n }\n " ,
418+ )
419+ . unwrap ( ) ;
420+
421+ let index = SymbolIndex :: build ( dir. path ( ) , 20 , 200_000 , 10 , |_| false ) . unwrap ( ) ;
422+ let fetcher = ContextFetcher :: new ( dir. path ( ) . to_path_buf ( ) ) ;
423+
424+ let chunks = fetcher
425+ . fetch_related_definitions_with_index (
426+ & PathBuf :: from ( "src/handler.rs" ) ,
427+ & [ "handle_request" . to_string ( ) ] ,
428+ & index,
429+ 10 ,
430+ 2 ,
431+ 5 ,
432+ )
433+ . await
434+ . unwrap ( ) ;
435+
436+ let graph_chunk = chunks
437+ . iter ( )
438+ . find ( |chunk| chunk. file_path == std:: path:: Path :: new ( "src/auth.rs" ) )
439+ . expect ( "expected graph-related auth context" ) ;
440+
441+ assert_eq ! ( graph_chunk. context_type, ContextType :: Definition ) ;
442+ assert ! ( graph_chunk. content. contains( "validate_token" ) ) ;
443+ assert ! ( graph_chunk
444+ . provenance
445+ . as_deref( )
446+ . unwrap_or_default( )
447+ . contains( "symbol graph" ) ) ;
448+ assert ! ( graph_chunk
449+ . provenance
450+ . as_deref( )
451+ . unwrap_or_default( )
452+ . contains( "calls" ) ) ;
453+ }
376454}
0 commit comments