fix(tui): make model download progress feel alive and stop offering a running download - #137
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two problems while a local model is downloading: the numbers barely move, and the list keeps
offering a download that is already running.
1. The byte counter freezes
downloadFileemitted progress only when the whole-number percentage changed(
src/local-llm/download-file.ts,if (percent !== lastReportedPercent)). Sincetransferredwas sampled only at those moments, the KB/MB figure sat still in between: onepercent of a 4 GB GGUF is ~41 MB, so at 5–20 MB/s the number moved once every 2–8 seconds and
the download looked stalled.
Worse, with no
content-lengththe total is 0, which pinspercentat 0 — after the firstchunk the guard never opened again and the counter was frozen for the entire download.
Progress is now emitted on a 200 ms time base, with a forced final emit at the end so the
terminal 100% is never lost. Nothing downstream throttles (the orchestrator forwards each
callback, and Ink's default
maxFps: 30is far faster than this), so the UI now updatesabout five times a second.
2. The list still says
Enter: downloadThe row builders only looked at
model.downloaded; they never consultedstate.localModelsPanel.pull/.embeddingPull, which is the live per-model download statethe Models tab already renders. A model being pulled right now therefore advertised
Enter: download, which reads as if the keypress did nothing and invites a second press —and pressing Enter really did re-fire the pull.
Enter: downloadDownloading… 42%Enter: use local-llama/<id>Enter: select modelEnter: downloadEnter: download(unchanged)Enter: downloadEnter: download(unchanged)primaryActiongains a"downloading"variant on both the chat and embedding row unions, andtriggerLocalChatModel/triggerLocalEmbeddingModelnow no-op while that model's pull is inflight instead of starting it again. The Models-tab detail pane got the same treatment — it
was showing
Enter — downloadmid-pull too.Testing
npm run lint(tsc --noEmit) cleandownload-file.test.ts, both verified to fail against the oldimplementation (1 progress callback where the test requires 5+) and pass against the new
one: chunks smaller than one percent, and a response with no
content-lengthmodel (which must not mark this row as downloading)
llm-panel-selectors.test.tspinned"Enter: use local-llama/qwen-3.5-4b", now"Enter: select model"src/tui+src/local-llmsuites, serial: 111 files passed, 4 failed — the samefour that fail on unmodified
main(tui-app×2 stale snapshots,splash-banner,chat-log,persist-embedding-hybrid-recall)The 200 ms interval is a deliberate choice over exactly 1 s: it is frequent enough that the
counter reads as live, and still ~6× cheaper than the render throttle above it.