@@ -153,21 +153,56 @@ def run(self):
153153 self .console .print ("[green]Goodbye![/]" )
154154
155155 def _handle_chat (self , message ):
156- """Handle chat interaction with clean output (no streaming) ."""
156+ """Handle chat interaction with clean, incremental output ."""
157157 # User message is already displayed by the main loop with styling
158158
159- # Collect full response first, then display
160- response_text = ""
161- tool_calls = []
162- tool_results = []
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+
163168 errors = []
164169 was_aborted = False
165170 rollback_info = None
166171
167172 # Track active files (files touched by tools)
168173 touched_files = set ()
169174
170- # Show spinner while processing
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+
171206 # Show spinner while processing
172207 with self .console .status ("[bold blue]SuperCoder is thinking...[/]" , spinner = "dots" ) as status :
173208 # Start keyboard listener for abort
@@ -179,27 +214,66 @@ def _handle_chat(self, message):
179214 event_type = event .get ("type" )
180215 content = event .get ("content" )
181216
182- if event_type == "token" :
183- response_text += content
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+
184234 elif event_type == "tool_call" :
185- tool_calls .append (content )
186- # Track files from tool args
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
187246 self ._track_files (content , touched_files )
247+
188248 elif event_type == "tool_result" :
189- tool_results .append (content )
249+ # Tool result interrupts
250+ flush_buffer ()
251+ self ._display_tool_result (content )
252+
190253 elif event_type == "error" :
254+ flush_buffer ()
191255 errors .append (content )
256+ self .console .print (Panel (f"[red]{ content } [/]" , title = "[bold red]Error[/]" , border_style = "red" ))
257+
192258 elif event_type == "aborted" :
259+ flush_buffer ()
193260 was_aborted = True
194261 status .stop ()
262+
195263 elif event_type == "rollback" :
196264 rollback_info = content
265+
197266 elif event_type == "command_waiting" :
198- # Process is waiting - need user interaction
199- status .stop () # Stop spinner to allow interaction
267+ # Need user interaction
268+ flush_buffer ()
269+ status .stop ()
200270 self ._handle_command_waiting (event )
201- # Continue iteration - the process has been handled
271+ # Process handled, maybe loops back
272+
202273 finally :
274+ # Ensure pending buffer is printed
275+ flush_buffer ()
276+
203277 # Stop keyboard listener
204278 if hasattr (self , 'keyboard_listener' ):
205279 self .keyboard_listener .stop ()
@@ -224,30 +298,7 @@ def _handle_chat(self, message):
224298 border_style = "cyan" ,
225299 box = self ._get_box_style ()
226300 ))
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-
301+
251302 # 4. Display Status Footer (Tokens & Files)
252303 self ._display_status_footer (touched_files )
253304
@@ -407,10 +458,11 @@ def _display_tool_call(self, tool_call):
407458 args_str = json .dumps (args , indent = 2 )
408459
409460 self .console .print (Panel (
410- Syntax (args_str , "json" , theme = "monokai" , word_wrap = True ),
461+ Syntax (args_str . strip () , "json" , theme = "monokai" , word_wrap = True , padding = 0 ),
411462 title = f"[bold yellow]🔧 Tool Call: { name } [/]" ,
412463 border_style = "yellow" ,
413- box = self ._get_box_style ()
464+ box = self ._get_box_style (),
465+ padding = (0 , 1 )
414466 ))
415467
416468 def _display_tool_result (self , result_data ):
@@ -427,10 +479,11 @@ def _display_tool_result(self, result_data):
427479 display_result = result [:500 ] + "..." if len (result ) > 500 else result
428480
429481 self .console .print (Panel (
430- f"[dim]{ display_result } [/]" ,
482+ f"[dim]{ display_result . strip () } [/]" ,
431483 title = f"[bold green]✔ Result: { name } [/]" ,
432484 border_style = "green" ,
433- box = self ._get_box_style ()
485+ box = self ._get_box_style (),
486+ padding = (0 , 1 )
434487 ))
435488
436489 def _is_diff_result (self , result : str ) -> bool :
@@ -471,12 +524,13 @@ def _display_diff_result(self, name: str, result: str):
471524 # Display diff with syntax highlighting
472525 if diff_lines :
473526 diff_text = "\n " .join (diff_lines )
474- syntax = Syntax (diff_text , "diff" , theme = "monokai" , line_numbers = False )
527+ syntax = Syntax (diff_text , "diff" , theme = "monokai" , line_numbers = False , padding = 0 )
475528 self .console .print (Panel (
476529 syntax ,
477530 title = "[bold cyan]Changes[/]" ,
478531 border_style = "cyan" ,
479- box = self ._get_box_style ()
532+ box = self ._get_box_style (),
533+ padding = (0 , 1 )
480534 ))
481535
482536
0 commit comments