fix(tui): show checkmark once model download completes
The in-chat model-switch line kept spinning at "switching model … (100%)" while the weights loaded into memory, which looked stuck. Once the download has fully landed on disk, swap the spinner for a green checkmark and switch the label to "model downloaded — loading into memory…". Also cap the displayed downloaded size at the expected size so it no longer reads e.g. "9.36 GB / 4.78 GB". Fixes #4 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
keypair34 committed
Jun 24, 2026 at 15:45 UTC
172a214c7a7a5217509951c6af7f3b457581dec4
1 file changed
+38
-17
src/chat.rs
+38
-17
index d2807d9..df35406 100644
--- a/src/chat.rs
+++ b/src/chat.rs
@@ -872,25 +872,46 @@ mod tui {
Style::default().fg(Color::DarkGray),
)));
} else if app.switching_model {
- let frame_str = app.switching_frame();
- let progress_str = if let Some((downloaded, expected)) = app.download_progress {
- if expected > 0 {
- let pct = (downloaded as f64 / expected as f64 * 100.0).min(100.0) as u8;
- let dl_str = format_size_human(downloaded);
- let ex_str = format_size_human(expected);
- format!(" — {dl_str} / {ex_str} ({pct}%)")
- } else if downloaded > 0 {
- format!(" — {} downloaded", format_size_human(downloaded))
+ // Once the weights have fully landed on disk, swap the spinner for a
+ // checkmark so it's clear the download finished and we're now loading
+ // the model into memory (which can still take a while).
+ let download_complete = matches!(
+ app.download_progress,
+ Some((downloaded, expected)) if expected > 0 && downloaded >= expected
+ );
+
+ if download_complete {
+ let size_str = app
+ .download_progress
+ .map(|(_, expected)| format!(" ({})", format_size_human(expected)))
+ .unwrap_or_default();
+ lines.push(Line::from(vec![
+ Span::styled(" ✓ ", Style::default().fg(Color::Green)),
+ Span::styled(
+ format!("model downloaded{size_str} — loading into memory…"),
+ Style::default().fg(Color::DarkGray),
+ ),
+ ]));
+ } else {
+ let progress_str = if let Some((downloaded, expected)) = app.download_progress {
+ if expected > 0 {
+ let pct = (downloaded as f64 / expected as f64 * 100.0).min(100.0) as u8;
+ let dl_str = format_size_human(downloaded.min(expected));
+ let ex_str = format_size_human(expected);
+ format!(" — {dl_str} / {ex_str} ({pct}%)")
+ } else if downloaded > 0 {
+ format!(" — {} downloaded", format_size_human(downloaded))
+ } else {
+ String::new()
+ }
} else {
String::new()
- }
- } else {
- String::new()
- };
- lines.push(Line::from(Span::styled(
- format!(" {frame_str} switching model{progress_str}…"),
- Style::default().fg(Color::DarkGray),
- )));
+ };
+ lines.push(Line::from(Span::styled(
+ format!(" {} switching model{progress_str}…", app.switching_frame()),
+ Style::default().fg(Color::DarkGray),
+ )));
+ }
}
let total_lines = lines.len() as u16;