diff --git a/agent/display.py b/agent/display.py index 301af5f9d3..7320cb7ea6 100644 --- a/agent/display.py +++ b/agent/display.py @@ -7,7 +7,6 @@ Used by AIAgent._execute_tool_calls for CLI feedback. import json import os import random -import sys import threading import time @@ -16,22 +15,6 @@ _RED = "\033[31m" _RESET = "\033[0m" -def _raw_write(text: str): - """Write directly to the real stdout, bypassing prompt_toolkit's patch_stdout proxy. - - prompt_toolkit's StdoutProxy intercepts sys.stdout and can swallow or - mishandle \\r carriage returns and inline ANSI escapes that the spinner - relies on. sys.__stdout__ is the original file object before any monkey - patching, so writes go straight to the terminal. - """ - out = sys.__stdout__ - try: - out.write(text) - out.flush() - except (ValueError, OSError): - pass - - # ========================================================================= # Tool preview (one-line summary of a tool call's primary argument) # ========================================================================= @@ -186,10 +169,8 @@ class KawaiiSpinner: frame = self.spinner_frames[self.frame_idx % len(self.spinner_frames)] elapsed = time.time() - self.start_time line = f" {frame} {self.message} ({elapsed:.1f}s)" - # \033[2K erases the entire current line, \r moves cursor to col 0. - # Using _raw_write bypasses patch_stdout so the animation renders - # even when prompt_toolkit owns the terminal. - _raw_write(f"\033[2K\r{line}") + clear = '\r' + ' ' * self.last_line_len + '\r' + print(clear + line, end='', flush=True) self.last_line_len = len(line) self.frame_idx += 1 time.sleep(0.12) @@ -209,9 +190,9 @@ class KawaiiSpinner: self.running = False if self.thread: self.thread.join(timeout=0.5) - _raw_write(f"\033[2K\r") + print('\r' + ' ' * (self.last_line_len + 5) + '\r', end='', flush=True) if final_message: - _raw_write(f" {final_message}\n") + print(f" {final_message}", flush=True) def __enter__(self): self.start()