Files
EvoScientist-Multi/EvoScientist/cli/widgets/loading_widget.py
T
X-iZhang 03f4134190 feat: add UserMessage widget and UI backend selection during onboarding
- Introduced UserMessage widget for displaying user input with a styled prompt.
- Updated onboarding steps to include UI backend selection (Rich CLI or Textual TUI).
- Modified EvoScientistConfig to store selected UI backend.
- Enhanced configuration handling to support UI backend environment variable.
- Updated README with new UI backend options and commands.
- Added tests for new UI backend functionality and UserMessage widget.
- Removed obsolete test files and ensured existing tests are updated accordingly.
2026-02-21 01:18:33 +00:00

51 lines
1.4 KiB
Python

"""Loading spinner widget shown while waiting for the first token."""
from __future__ import annotations
from textual.widgets import Static
_SPINNER_FRAMES = "\u280b\u2819\u2839\u2838\u283c\u2834\u2826\u2827\u2807\u280f"
class LoadingWidget(Static):
"""Spinner + 'Thinking...' with elapsed time counter.
Mount when a turn starts; call ``remove()`` when the first
thinking/text/tool_call event arrives.
"""
DEFAULT_CSS = """
LoadingWidget {
height: auto;
color: #22d3ee;
padding: 0 0;
}
"""
def __init__(self) -> None:
super().__init__("")
self._frame = 0
self._elapsed = 0.0
self._timer_handle = None
def on_mount(self) -> None:
self._timer_handle = self.set_interval(0.1, self._tick)
self._refresh_display()
def _tick(self) -> None:
self._frame = (self._frame + 1) % len(_SPINNER_FRAMES)
self._elapsed += 0.1
self._refresh_display()
def _refresh_display(self) -> None:
char = _SPINNER_FRAMES[self._frame]
secs = int(self._elapsed)
self.update(f"{char} Thinking... ({secs}s)")
async def cleanup(self) -> None:
"""Stop timer and remove from DOM."""
if self._timer_handle is not None:
self._timer_handle.stop()
self._timer_handle = None
await self.remove()