@@ -153,56 +153,21 @@ def run(self):
153153 self .console .print ("[green]Goodbye![/]" )
154154
155155 def _handle_chat (self , message ):
156- """Handle chat interaction with clean, incremental output."""
156+ """Handle chat interaction with clean output (no streaming) ."""
157157 # User message is already displayed by the main loop with styling
158158
159- # State tracking
160- current_block_type = None # 'reasoning', 'response', or None
161- current_buffer = ""
162-
163- # Accumulators for logging/final processing, NOT for display (display is immediate)
164- full_response_text = ""
165- full_reasoning_text = "" # Just for internal consistency if needed
166- # We still collect tool calls/results for logging logic if needed, but display them immediately
167-
159+ # Collect full response first, then display
160+ response_text = ""
161+ tool_calls = []
162+ tool_results = []
168163 errors = []
169164 was_aborted = False
170165 rollback_info = None
171166
172167 # Track active files (files touched by tools)
173168 touched_files = set ()
174169
175- # Helper to flush current text buffer to display
176- def flush_buffer ():
177- nonlocal current_block_type , current_buffer
178- if not current_buffer or not current_buffer .strip ():
179- return
180-
181- content_to_print = current_buffer .strip ()
182-
183- if current_block_type == 'reasoning' :
184- self .console .print (Panel (
185- Markdown (content_to_print ),
186- title = "[bold magenta]💭 Reasoning[/]" ,
187- border_style = "magenta" ,
188- box = self ._get_box_style (),
189- padding = (0 , 1 )
190- ))
191- elif current_block_type == 'response' :
192- clean_text = self ._filter_special_tokens (content_to_print )
193- if clean_text :
194- self .console .print (Panel (
195- Markdown (clean_text ),
196- title = "[bold blue]SuperCoder[/]" ,
197- border_style = "blue" ,
198- box = self ._get_box_style (),
199- padding = (0 , 1 )
200- ))
201-
202- # Reset buffer
203- current_buffer = ""
204- current_block_type = None
205-
170+ # Show spinner while processing
206171 # Show spinner while processing
207172 with self .console .status ("[bold blue]SuperCoder is thinking...[/]" , spinner = "dots" ) as status :
208173 # Start keyboard listener for abort
@@ -214,66 +179,27 @@ def flush_buffer():
214179 event_type = event .get ("type" )
215180 content = event .get ("content" )
216181
217- # Handle state transitions
218- if event_type == "reasoning" :
219- # If we were doing something else (e.g. response), flush it
220- if current_block_type != 'reasoning' :
221- flush_buffer ()
222- current_block_type = 'reasoning'
223- current_buffer += content
224- full_reasoning_text += content
225-
226- elif event_type == "token" :
227- # If we were doing reasoning, flush it
228- if current_block_type != 'response' :
229- flush_buffer ()
230- current_block_type = 'response'
231- current_buffer += content
232- full_response_text += content
233-
182+ if event_type == "token" :
183+ response_text += content
234184 elif event_type == "tool_call" :
235- # Tool call interrupts any text generation
236- flush_buffer ()
237-
238- # Display tool call immediately
239- # We might want to clear spinner, print, resume spinner -
240- # but Rich handles prints during active spinner gracefully usually.
241- status .stop ()
242- self ._display_tool_call (content )
243- status .start ()
244-
245- # Track files
185+ tool_calls .append (content )
186+ # Track files from tool args
246187 self ._track_files (content , touched_files )
247-
248188 elif event_type == "tool_result" :
249- # Tool result interrupts
250- flush_buffer ()
251- self ._display_tool_result (content )
252-
189+ tool_results .append (content )
253190 elif event_type == "error" :
254- flush_buffer ()
255191 errors .append (content )
256- self .console .print (Panel (f"[red]{ content } [/]" , title = "[bold red]Error[/]" , border_style = "red" ))
257-
258192 elif event_type == "aborted" :
259- flush_buffer ()
260193 was_aborted = True
261194 status .stop ()
262-
263195 elif event_type == "rollback" :
264196 rollback_info = content
265-
266197 elif event_type == "command_waiting" :
267- # Need user interaction
268- flush_buffer ()
269- status .stop ()
198+ # Process is waiting - need user interaction
199+ status .stop () # Stop spinner to allow interaction
270200 self ._handle_command_waiting (event )
271- # Process handled, maybe loops back
272-
201+ # Continue iteration - the process has been handled
273202 finally :
274- # Ensure pending buffer is printed
275- flush_buffer ()
276-
277203 # Stop keyboard listener
278204 if hasattr (self , 'keyboard_listener' ):
279205 self .keyboard_listener .stop ()
@@ -298,7 +224,30 @@ def flush_buffer():
298224 border_style = "cyan" ,
299225 box = self ._get_box_style ()
300226 ))
301-
227+
228+ # 1. Display Tool Calls & Results first (Implementation Detail)
229+ if tool_calls :
230+ self .console .print () # Spacer
231+ for i , tc in enumerate (tool_calls ):
232+ self ._display_tool_call (tc )
233+ if i < len (tool_results ):
234+ self ._display_tool_result (tool_results [i ])
235+ self .console .print () # Spacer
236+
237+ # 2. Display Errors
238+ for error in errors :
239+ self .console .print (Panel (f"[red]{ error } [/]" , title = "[bold red]Error[/]" , border_style = "red" ))
240+
241+ # 3. Display Assistant Response
242+ clean_text = self ._filter_special_tokens (response_text )
243+ if clean_text :
244+ self .console .print (Panel (
245+ Markdown (clean_text ),
246+ title = "[bold blue]SuperCoder[/]" ,
247+ border_style = "blue" ,
248+ box = self ._get_box_style ()
249+ ))
250+
302251 # 4. Display Status Footer (Tokens & Files)
303252 self ._display_status_footer (touched_files )
304253
@@ -348,6 +297,11 @@ def _display_status_footer(self, touched_files):
348297 files_str = ", " .join (sorted (touched_files ))
349298 parts .append (f"[dim]Active Files: { files_str } [/]" )
350299
300+ # Cost estimate (rough approximation)
301+ # Assuming generic pricing, just to show we can
302+ # cost = (stats.used_tokens / 1000) * 0.002 # Example
303+ # parts.append(f"[dim]Est. Cost: ${cost:.4f}[/]")
304+
351305 self .console .print (" | " .join (parts ), justify = "right" )
352306
353307 def _get_box_style (self ):
@@ -359,13 +313,15 @@ def _handle_command_waiting(self, event):
359313 """Handle a command that appears to be waiting for input."""
360314 content = event .get ("content" , "" )
361315 process = event .get ("process" )
316+ tool_name = event .get ("tool_name" , "command-exec" )
362317
363318 # Display warning
364319 self .console .print (Panel (
365320 f"[yellow]{ content } [/]" ,
366321 title = "[bold yellow]⚠️ Process Stalled[/]" ,
367322 border_style = "yellow" ,
368323 box = self ._get_box_style ()
324+
369325 ))
370326
371327 # Simple stdin-based menu (most reliable across terminals)
@@ -403,6 +359,10 @@ def _handle_command_waiting(self, event):
403359 except Exception :
404360 pass
405361 return "killed"
362+
363+
364+
365+
406366
407367 def _filter_special_tokens (self , text : str ) -> str :
408368 """Remove special tokens from display text while preserving normal content."""
@@ -447,11 +407,10 @@ def _display_tool_call(self, tool_call):
447407 args_str = json .dumps (args , indent = 2 )
448408
449409 self .console .print (Panel (
450- Syntax (args_str . strip () , "json" , theme = "monokai" , word_wrap = True , padding = 0 ),
410+ Syntax (args_str , "json" , theme = "monokai" , word_wrap = True ),
451411 title = f"[bold yellow]🔧 Tool Call: { name } [/]" ,
452412 border_style = "yellow" ,
453- box = self ._get_box_style (),
454- padding = (0 , 1 )
413+ box = self ._get_box_style ()
455414 ))
456415
457416 def _display_tool_result (self , result_data ):
@@ -468,11 +427,10 @@ def _display_tool_result(self, result_data):
468427 display_result = result [:500 ] + "..." if len (result ) > 500 else result
469428
470429 self .console .print (Panel (
471- f"[dim]{ display_result . strip () } [/]" ,
430+ f"[dim]{ display_result } [/]" ,
472431 title = f"[bold green]✔ Result: { name } [/]" ,
473432 border_style = "green" ,
474- box = self ._get_box_style (),
475- padding = (0 , 1 )
433+ box = self ._get_box_style ()
476434 ))
477435
478436 def _is_diff_result (self , result : str ) -> bool :
@@ -493,28 +451,32 @@ def _display_diff_result(self, name: str, result: str):
493451 in_diff = False
494452
495453 for line in lines :
454+ # Check for unified diff markers to start capturing diff
455+ # --- file header, +++ file header, @@ hunk header
496456 if line .startswith ("--- " ) or line .startswith ("+++ " ) or line .startswith ("@@" ):
497457 in_diff = True
498458
499459 if in_diff :
460+ # Once in diff mode, capture all lines (including +/- content lines)
500461 diff_lines .append (line )
501462 else :
502463 message_lines .append (line )
503464
465+ # Display message part (success message)
504466 if message_lines :
505467 message = "\n " .join (message_lines ).strip ()
506468 if message :
507469 self .console .print (f"[bold green]✔ { name } [/]: { message } " )
508470
471+ # Display diff with syntax highlighting
509472 if diff_lines :
510473 diff_text = "\n " .join (diff_lines )
511- syntax = Syntax (diff_text , "diff" , theme = "monokai" , line_numbers = False , padding = 0 )
474+ syntax = Syntax (diff_text , "diff" , theme = "monokai" , line_numbers = False )
512475 self .console .print (Panel (
513476 syntax ,
514477 title = "[bold cyan]Changes[/]" ,
515478 border_style = "cyan" ,
516- box = self ._get_box_style (),
517- padding = (0 , 1 )
479+ box = self ._get_box_style ()
518480 ))
519481
520482
0 commit comments