Skip to content

Commit 9e6a1fc

Browse files
committed
Fix: Restore reasoning display with visual improvements (v0.2.8)
1 parent 0f50da9 commit 9e6a1fc

1 file changed

Lines changed: 98 additions & 44 deletions

File tree

supercoder/repl.py

Lines changed: 98 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)