@@ -1057,6 +1057,9 @@ async def _run_patched(self, with_message=None, preproc=True):
10571057 self .show_announcements ()
10581058 self .suppress_announcements_for_next_prompt = False
10591059
1060+ # Stop spinner before showing announcements or getting input
1061+ self .io .stop_spinner ()
1062+
10601063 self .copy_context ()
10611064 self .input_task = asyncio .create_task (self .get_input ())
10621065 input_task = self .input_task
@@ -1080,6 +1083,7 @@ async def _run_patched(self, with_message=None, preproc=True):
10801083 await processing_task
10811084 except asyncio .CancelledError :
10821085 pass
1086+ self .io .stop_spinner ()
10831087 processing_task = None
10841088
10851089 try :
@@ -1097,16 +1101,22 @@ async def _run_patched(self, with_message=None, preproc=True):
10971101 except (asyncio .CancelledError , KeyboardInterrupt ):
10981102 pass
10991103 processing_task = None
1104+ # Stop spinner when processing task completes
1105+ self .io .stop_spinner ()
11001106
11011107 if user_message and self .run_one_completed and self .compact_context_completed :
11021108 processing_task = asyncio .create_task (
11031109 self ._processing_logic (user_message , preproc )
11041110 )
1111+ # Start spinner for processing task
1112+ self .io .start_spinner ("Processing..." )
11051113 user_message = None # Clear message after starting task
11061114 except KeyboardInterrupt :
11071115 if processing_task :
11081116 processing_task .cancel ()
11091117 processing_task = None
1118+ # Stop spinner when processing task is cancelled
1119+ self .io .stop_spinner ()
11101120 if input_task :
11111121 self .io .set_placeholder ("" )
11121122 input_task .cancel ()
@@ -1176,6 +1186,9 @@ async def run_one(self, user_message, preproc):
11761186 else :
11771187 message = user_message
11781188
1189+ if self .commands .is_command (user_message ):
1190+ return
1191+
11791192 while True :
11801193 self .reflected_message = None
11811194 self .tool_reflection = False
@@ -1881,7 +1894,7 @@ async def send_message(self, inp):
18811894 ]
18821895 return
18831896
1884- edited = self .apply_updates ()
1897+ edited = await self .apply_updates ()
18851898
18861899 if edited :
18871900 self .aider_edited_files .update (edited )
@@ -2496,6 +2509,48 @@ async def check_for_file_mentions(self, content):
24962509 return prompts .added_files .format (fnames = ", " .join (added_fnames ))
24972510
24982511 async def send (self , messages , model = None , functions = None , tools = None ):
2512+ # Add tool usage context if this is a navigator coder with tool history
2513+ if hasattr (self , "tool_usage_history" ) and self .tool_usage_history :
2514+ # Get the last user message
2515+ last_user_message = messages [- 1 ]
2516+ repetitive_tools = (
2517+ self ._get_repetitive_tools () if hasattr (self , "_get_repetitive_tools" ) else set ()
2518+ )
2519+
2520+ if repetitive_tools :
2521+ tool_context = (
2522+ self ._generate_tool_context (repetitive_tools )
2523+ if hasattr (self , "_generate_tool_context" )
2524+ else ""
2525+ )
2526+
2527+ if tool_context and "content" in last_user_message :
2528+ # Add tool context to the user message
2529+ if messages [- 1 ].get ("role" ) == "user" :
2530+ messages [- 1 ][
2531+ "content"
2532+ ] = f"{ tool_context } \n \n { last_user_message ['content' ]} "
2533+
2534+ # Filter out repetitive tools from the context
2535+ if tools :
2536+ tools = [
2537+ tool
2538+ for tool in tools
2539+ if tool .get ("function" , {}).get ("name" , "" ) not in repetitive_tools
2540+ ]
2541+ if functions :
2542+ functions = [
2543+ func
2544+ for func in functions
2545+ if func .get ("function" , {}).get ("name" , "" ) not in repetitive_tools
2546+ ]
2547+
2548+ if self .verbose :
2549+ self .io .tool_output (
2550+ "Temporarily hiding repetitive tool(s) to encourage progress:"
2551+ f" { ', ' .join (sorted (repetitive_tools ))} "
2552+ )
2553+
24992554 self .got_reasoning_content = False
25002555 self .ended_reasoning_content = False
25012556
@@ -2996,7 +3051,7 @@ def check_for_dirty_commit(self, path):
29963051 self .io .tool_output (f"Committing { path } before applying edits." )
29973052 self .need_commit_before_edits .add (path )
29983053
2999- def allowed_to_edit (self , path ):
3054+ async def allowed_to_edit (self , path ):
30003055 full_path = self .abs_root_path (path )
30013056 if self .repo :
30023057 need_to_add = not self .repo .path_in_repo (path )
@@ -3031,7 +3086,7 @@ def allowed_to_edit(self, path):
30313086 self .check_added_files ()
30323087 return True
30333088
3034- if not self .io .confirm_ask (
3089+ if not await self .io .confirm_ask (
30353090 "Allow edits to file that has not been added to the chat?" ,
30363091 subject = path ,
30373092 ):
@@ -3074,7 +3129,7 @@ def check_added_files(self):
30743129 self .io .tool_warning (urls .edit_errors )
30753130 self .warning_given = True
30763131
3077- def prepare_to_edit (self , edits ):
3132+ async def prepare_to_edit (self , edits ):
30783133 res = []
30793134 seen = dict ()
30803135
@@ -3090,7 +3145,7 @@ def prepare_to_edit(self, edits):
30903145 if path in seen :
30913146 allowed = seen [path ]
30923147 else :
3093- allowed = self .allowed_to_edit (path )
3148+ allowed = await self .allowed_to_edit (path )
30943149 seen [path ] = allowed
30953150
30963151 if allowed :
@@ -3101,12 +3156,12 @@ def prepare_to_edit(self, edits):
31013156
31023157 return res
31033158
3104- def apply_updates (self ):
3159+ async def apply_updates (self ):
31053160 edited = set ()
31063161 try :
31073162 edits = self .get_edits ()
31083163 edits = self .apply_edits_dry_run (edits )
3109- edits = self .prepare_to_edit (edits )
3164+ edits = await self .prepare_to_edit (edits )
31103165 edited = set (edit [0 ] for edit in edits )
31113166
31123167 self .apply_edits (edits )
0 commit comments