fix: stop terminal border flashing with steady cursor and TUI spinner widget
Cherry-picked and improved from PR #470 (fixes #464). Problem: On Ubuntu 24.04 with ghostty + tmux, the prompt input box border lines flash due to cursor blink and raw spinner terminal writes conflicting with prompt_toolkit's rendering. Changes: - cli.py: Add CursorShape.BLOCK to Application() to disable cursor blink - cli.py: Add thinking_callback + spinner_widget in TUI layout so thinking status displays as a proper prompt_toolkit widget instead of raw terminal writes that conflict with the TUI renderer - run_agent.py: Add thinking_callback parameter to AIAgent; when set, uses the callback instead of KawaiiSpinner for thinking display What was NOT changed (preserving existing behavior): - agent/display.py: Untouched. KawaiiSpinner _write() stdout capture, _animate() logic, and 0.12s frame interval all preserved. This protects subagent stdout redirection and keeps smooth animations for non-CLI contexts (gateway, batch runner). - Original emoji spinner types (brain/sparkle/pulse/moon/star) preserved for all non-CLI contexts. Fixes from original PR #470: - CursorShape.STEADY_BLOCK -> CursorShape.BLOCK (STEADY_BLOCK doesn't exist in prompt_toolkit 3.0.52) - Removed duplicate self._spinner_text = '' line - Removed redundant nested if-checks Tested: 2706 tests pass, interactive CLI verified via tmux.
This commit is contained in:
parent
88f8bcde38
commit
ee4008431a
2 changed files with 46 additions and 3 deletions
20
run_agent.py
20
run_agent.py
|
|
@ -172,6 +172,7 @@ class AIAgent:
|
|||
provider_data_collection: str = None,
|
||||
session_id: str = None,
|
||||
tool_progress_callback: callable = None,
|
||||
thinking_callback: callable = None,
|
||||
clarify_callback: callable = None,
|
||||
step_callback: callable = None,
|
||||
max_tokens: int = None,
|
||||
|
|
@ -256,6 +257,7 @@ class AIAgent:
|
|||
self.api_mode = "chat_completions"
|
||||
|
||||
self.tool_progress_callback = tool_progress_callback
|
||||
self.thinking_callback = thinking_callback
|
||||
self.clarify_callback = clarify_callback
|
||||
self.step_callback = step_callback
|
||||
self._last_reported_tool = None # Track for "new tool" mode
|
||||
|
|
@ -3325,9 +3327,13 @@ class AIAgent:
|
|||
# Animated thinking spinner in quiet mode
|
||||
face = random.choice(KawaiiSpinner.KAWAII_THINKING)
|
||||
verb = random.choice(KawaiiSpinner.THINKING_VERBS)
|
||||
spinner_type = random.choice(['brain', 'sparkle', 'pulse', 'moon', 'star'])
|
||||
thinking_spinner = KawaiiSpinner(f"{face} {verb}...", spinner_type=spinner_type)
|
||||
thinking_spinner.start()
|
||||
if self.thinking_callback:
|
||||
# CLI TUI mode: use prompt_toolkit widget instead of raw spinner
|
||||
self.thinking_callback(f"{face} {verb}...")
|
||||
else:
|
||||
spinner_type = random.choice(['brain', 'sparkle', 'pulse', 'moon', 'star'])
|
||||
thinking_spinner = KawaiiSpinner(f"{face} {verb}...", spinner_type=spinner_type)
|
||||
thinking_spinner.start()
|
||||
|
||||
# Log request details if verbose
|
||||
if self.verbose_logging:
|
||||
|
|
@ -3364,6 +3370,8 @@ class AIAgent:
|
|||
if thinking_spinner:
|
||||
thinking_spinner.stop("")
|
||||
thinking_spinner = None
|
||||
if self.thinking_callback:
|
||||
self.thinking_callback("")
|
||||
|
||||
if not self.quiet_mode:
|
||||
print(f"{self.log_prefix}⏱️ API call completed in {api_duration:.2f}s")
|
||||
|
|
@ -3404,6 +3412,8 @@ class AIAgent:
|
|||
if thinking_spinner:
|
||||
thinking_spinner.stop(f"(´;ω;`) oops, retrying...")
|
||||
thinking_spinner = None
|
||||
if self.thinking_callback:
|
||||
self.thinking_callback("")
|
||||
|
||||
# This is often rate limiting or provider returning malformed response
|
||||
retry_count += 1
|
||||
|
|
@ -3573,6 +3583,8 @@ class AIAgent:
|
|||
if thinking_spinner:
|
||||
thinking_spinner.stop("")
|
||||
thinking_spinner = None
|
||||
if self.thinking_callback:
|
||||
self.thinking_callback("")
|
||||
api_elapsed = time.time() - api_start_time
|
||||
print(f"{self.log_prefix}⚡ Interrupted during API call.")
|
||||
self._persist_session(messages, conversation_history)
|
||||
|
|
@ -3585,6 +3597,8 @@ class AIAgent:
|
|||
if thinking_spinner:
|
||||
thinking_spinner.stop(f"(╥_╥) error, retrying...")
|
||||
thinking_spinner = None
|
||||
if self.thinking_callback:
|
||||
self.thinking_callback("")
|
||||
|
||||
status_code = getattr(api_error, "status_code", None)
|
||||
if (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue