11from dataclasses import dataclass
22from itertools import islice
3- from pathlib import Path
3+ import shutil
44import subprocess
55from typing import Any , Optional
66from agents import RunContextWrapper , function_tool
77from llm_utils import number_group_of_lines
88from perfparser import LineLoc
99
1010from accelerant .chat_interface import CodeSuggestion
11- from accelerant .fs_sandbox import FsSandbox
1211from accelerant .lsp import TOP_LEVEL_SYMBOL_KINDS , uri_to_relpath
1312from accelerant .patch import apply_simultaneous_suggestions
1413from accelerant .util import find_symbol , truncate_for_llm
1817@dataclass
1918class AgentContext :
2019 project : Project
21- active_fs : FsSandbox
22- initial_perf_data_path : Optional [Path ]
2320
2421
2522@function_tool
@@ -32,7 +29,9 @@ def edit_code(
3229 Args:
3330 suggs: A list of code suggestions that should be applied.
3431 """
35- apply_simultaneous_suggestions (ctx .context .project , ctx .context .active_fs , suggs )
32+ apply_simultaneous_suggestions (
33+ ctx .context .project , ctx .context .project .fs_sandbox (), suggs
34+ )
3635
3736
3837@function_tool
@@ -43,26 +42,34 @@ def check_codebase_for_errors(
4342 assert ctx .context .project ._lang == "rust" , (
4443 "Only Rust is supported for code checking"
4544 )
45+
46+ cargo_path = shutil .which ("cargo" )
47+ assert cargo_path is not None , "cargo not found in PATH"
4648 try :
4749 subprocess .run (
48- ["cargo" , "check" , "--all" ], check = True , cwd = str (ctx .context .project ._root )
50+ [cargo_path , "check" , "--all-targets" ],
51+ check = True ,
52+ cwd = str (ctx .context .project ._root ),
4953 )
5054 except subprocess .CalledProcessError as e :
5155 return f"ERROR: Codebase has errors:\n \n { e } "
5256 return "OK: Codebase has no errors!"
5357
5458
5559@function_tool
56- def get_profiler_data (
60+ def run_perf_profiler (
5761 ctx : RunContextWrapper [AgentContext ],
5862) -> list [dict [str , Any ]]:
59- """Get a summary of the objective performance data gathered by a profiler ."""
63+ """Run a performance profiler on the target binary and return the top hotspots ."""
6064 try :
61- perf_data_path = ctx .context .initial_perf_data_path
62- if perf_data_path is None :
63- raise ValueError ("No initial performance data path provided" )
6465 project = ctx .context .project
65- perf_data = project .perf_data (perf_data_path )
66+ version = project .fs_sandbox ().version ()
67+ perf_data = project .perf_data (version )
68+ if perf_data is None :
69+ project .build_for_profiling ()
70+ project .run_profiler ()
71+ perf_data = project .perf_data (version )
72+ assert perf_data is not None , "perf data should be available after profiling"
6673 perf_tabulated = perf_data .tabulate ()
6774 NUM_HOTSPOTS = 5
6875
@@ -76,18 +83,20 @@ def get_parent_region(loc: LineLoc) -> Optional[str]:
7683 return None
7784 return parent_sym ["name" ]
7885
79- hotspots = islice (
80- map (
81- lambda x : {
82- "parent_region" : get_parent_region (x [0 ]) or "<unknown>" ,
83- "loc" : x [0 ],
84- "pct_time" : x [1 ] * 100 ,
85- },
86- filter (lambda x : x [0 ].line > 0 , perf_tabulated ),
87- ),
88- NUM_HOTSPOTS ,
86+ hotspots = list (
87+ islice (
88+ map (
89+ lambda x : {
90+ "parent_region" : get_parent_region (x [0 ]) or "<unknown>" ,
91+ "loc" : x [0 ],
92+ "pct_time" : x [1 ] * 100 ,
93+ },
94+ filter (lambda x : x [0 ].line > 0 , perf_tabulated ),
95+ ),
96+ NUM_HOTSPOTS ,
97+ )
8998 )
90- return list ( hotspots )
99+ return hotspots
91100 except Exception as e :
92101 print ("ERROR" , e )
93102 raise e
@@ -240,8 +249,8 @@ def get_surrounding_code(
240249 filename , line - 1 , TOP_LEVEL_SYMBOL_KINDS
241250 ),
242251 )
243- # FIXME: avoid crashing
244- assert parent_sym is not None
252+ if parent_sym is None :
253+ raise ValueError ( f"no surrounding top-level symbol found at { filename } : { line } " )
245254 sline = parent_sym ["range" ]["start" ]["line" ] + 1
246255 lines = project .get_range (filename , parent_sym ["range" ])
247256 return {
0 commit comments