Builds a complete task context for the given query. Pipeline: 1. Extract symbol names from the query 2. Search for matching nodes via FTS and exact name lookup 3. Expand graph around entry points using BFS traversal 4. Extract code blocks by reading source files 5. Build and return `TaskContext`
(
&self,
query: &str,
options: &BuildContextOptions,
)
| 30 | /// 4. Extract code blocks by reading source files |
| 31 | /// 5. Build and return `TaskContext` |
| 32 | pub async fn build_context( |
| 33 | &self, |
| 34 | query: &str, |
| 35 | options: &BuildContextOptions, |
| 36 | ) -> Result<TaskContext> { |
| 37 | debug_assert!(!query.is_empty(), "build_context called with empty query"); |
| 38 | debug_assert!(options.max_nodes > 0, "max_nodes must be positive"); |
| 39 | // Step 1-3: find relevant subgraph and entry points |
| 40 | let symbols = extract_symbols_from_query(query); |
| 41 | let entry_points = self.find_entry_points(query, &symbols, options).await?; |
| 42 | let subgraph = self.expand_subgraph(&entry_points, options).await?; |
| 43 | |
| 44 | // Step 4: extract code blocks from source files |
| 45 | let code_blocks = if options.include_code { |
| 46 | // Share one file-content cache across extract + merge so each |
| 47 | // source file is read at most once for this request. |
| 48 | let mut file_cache: HashMap<String, Option<String>> = HashMap::new(); |
| 49 | let blocks = self.extract_code_blocks(&entry_points, options, &mut file_cache); |
| 50 | if options.merge_adjacent { |
| 51 | self.merge_adjacent_blocks(blocks, &mut file_cache) |
| 52 | } else { |
| 53 | blocks |
| 54 | } |
| 55 | } else { |
| 56 | Vec::new() |
| 57 | }; |
| 58 | |
| 59 | // Collect unique related files |
| 60 | let related_files = Self::collect_related_files(&subgraph); |
| 61 | |
| 62 | // Build summary |
| 63 | let summary = Self::build_summary(query, &entry_points, &subgraph); |
| 64 | |
| 65 | let seen_node_ids: Vec<String> = entry_points.iter().map(|n| n.id.clone()).collect(); |
| 66 | |
| 67 | Ok(TaskContext { |
| 68 | query: query.to_string(), |
| 69 | summary, |
| 70 | subgraph, |
| 71 | entry_points, |
| 72 | code_blocks, |
| 73 | related_files, |
| 74 | seen_node_ids, |
| 75 | }) |
| 76 | } |
| 77 | |
| 78 | /// Finds the relevant subgraph for a query without extracting code blocks. |
| 79 | /// |