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
@@ -872,25 +872,46 @@ mod tui {
872
Style::default().fg(Color::DarkGray),
873
)));
874
} else if app.switching_model {
875
- let frame_str = app.switching_frame();
876
- let progress_str = if let Some((downloaded, expected)) = app.download_progress {
877
- if expected > 0 {
878
- let pct = (downloaded as f64 / expected as f64 * 100.0).min(100.0) as u8;
879
- let dl_str = format_size_human(downloaded);
880
- let ex_str = format_size_human(expected);
881
- format!(" — {dl_str} / {ex_str} ({pct}%)")
882
- } else if downloaded > 0 {
883
- format!(" — {} downloaded", format_size_human(downloaded))
875
+ // Once the weights have fully landed on disk, swap the spinner for a
876
+ // checkmark so it's clear the download finished and we're now loading
877
+ // the model into memory (which can still take a while).
878
+ let download_complete = matches!(
879
+ app.download_progress,
880
+ Some((downloaded, expected)) if expected > 0 && downloaded >= expected
881
+ );
882
+
883
+ if download_complete {
884
+ let size_str = app
885
+ .download_progress
886
+ .map(|(_, expected)| format!(" ({})", format_size_human(expected)))
887
+ .unwrap_or_default();
888
+ lines.push(Line::from(vec![
889
+ Span::styled(" ✓ ", Style::default().fg(Color::Green)),
890
+ Span::styled(
891
+ format!("model downloaded{size_str} — loading into memory…"),
892
+ Style::default().fg(Color::DarkGray),
893
+ ),
894
+ ]));
895
+ } else {
896
+ let progress_str = if let Some((downloaded, expected)) = app.download_progress {
897
+ if expected > 0 {
898
+ let pct = (downloaded as f64 / expected as f64 * 100.0).min(100.0) as u8;
899
+ let dl_str = format_size_human(downloaded.min(expected));
900
+ let ex_str = format_size_human(expected);
901
+ format!(" — {dl_str} / {ex_str} ({pct}%)")
902
+ } else if downloaded > 0 {
903
+ format!(" — {} downloaded", format_size_human(downloaded))
904
+ } else {
905
+ String::new()
906
+ }
907
} else {
908
String::new()
886
- }
887
- } else {
888
- String::new()
889
- };
890
- lines.push(Line::from(Span::styled(
891
- format!(" {frame_str} switching model{progress_str}…"),
892
- Style::default().fg(Color::DarkGray),
893
- )));
909
+ };
910
+ lines.push(Line::from(Span::styled(
911
+ format!(" {} switching model{progress_str}…", app.switching_frame()),
912
+ Style::default().fg(Color::DarkGray),
913
+ )));
914
+ }
915
}
916
917
let total_lines = lines.len() as u16;