Repository navigation
perf(models): open the launcher's model pickers from the disk cache - #249
Conversation
The launcher warms the catalog and benchmark scores on a background thread when it opens, so Switch model and Models show the picker without waiting on the network. Every interactive picker reads the same disk cache that launches use. The cache now keeps prices and dates so the picker columns survive it. HUD Models opens the picker instead of printing a list the launcher redraws over. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Duyet Le <me@duyet.net> Co-authored-by: duyetbot <bot@duyet.net>
|
Verdict: APPROVE (head 7ed4e29). Tests: 33 passed (picker, launch_cache). Checked and fine:
Findings (none blocking):
🤖 Generated with Claude Code |
…og cannot load Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Duyet Le <me@duyet.net> Co-authored-by: duyetbot <bot@duyet.net>
|
Review triage (author):
|
|
APPROVE (delta 7ed4e29..949051d). bind_agent_model returns an error again when the catalog is empty and lookups are on. The check sits after models_for_picker, so the warm thread is joined first, and a lookup-disabled env is skipped. The lib builds. No new tests for it (nit). 🤖 Generated with Claude Code |
anyr size and startupStartup is wall time for a cold Size budget:
Budget check: ok raw timings[
{
"asset": "anyr-darwin-arm64",
"kind": "native",
"path": "/Users/runner/work/cli/cli/anyr-darwin-arm64",
"bytes": 2570616,
"size": "2.5 MiB",
"version": "0.1.37 (built 2026-10-29 16:21:00)",
"target": "aarch64-apple-darwin",
"os": "macos-latest",
"startup_version": {
"n": 21,
"min_ms": 4.92,
"median_ms": 6.9,
"p95_ms": 10.73,
"mean_ms": 7.66
},
"startup_help": {
"n": 21,
"min_ms": 4.07,
"median_ms": 7.15,
"p95_ms": 9.32,
"mean_ms": 7.23
}
},
{
"asset": "anyr-darwin-x86_64",
"kind": "native",
"path": "/Users/runner/work/cli/cli/anyr-darwin-x86_64",
"bytes": 3078792,
"size": "2.9 MiB",
"version": "0.1.37 (built 2026-10-29 16:16:03)",
"target": "x86_64-apple-darwin",
"os": "macos-latest",
"startup_version": {
"n": 21,
"min_ms": 38.29,
"median_ms": 47.4,
"p95_ms": 56.22,
"mean_ms": 49.17
},
"startup_help": {
"n": 21,
"min_ms": 38.17,
"median_ms": 45.78,
"p95_ms": 55.5,
"mean_ms": 46.58
}
},
{
"asset": "anyr-linux-arm64",
"kind": "native",
"path": "/home/runner/work/cli/cli/anyr-linux-arm64",
"bytes": 3020048,
"size": "2.9 MiB",
"version": "0.1.37 (built 2026-10-29 16:16:09)",
"target": "aarch64-unknown-linux-gnu",
"os": "ubuntu-24.04-arm",
"startup_version": {
"n": 21,
"min_ms": 0.84,
"median_ms": 0.95,
"p95_ms": 1.05,
"mean_ms": 0.95
},
"startup_help": {
"n": 21,
"min_ms": 0.86,
"median_ms": 0.95,
"p95_ms": 1.01,
"mean_ms": 0.95
}
},
{
"asset": "anyr-linux-x86_64",
"kind": "native",
"path": "/home/runner/work/cli/cli/anyr-linux-x86_64",
"bytes": 3568472,
"size": "3.4 MiB",
"version": "0.1.37 (built 2026-10-29 16:15:06)",
"target": "x86_64-unknown-linux-gnu",
"os": "ubuntu-latest",
"startup_version": {
"n": 21,
"min_ms": 0.75,
"median_ms": 0.77,
"p95_ms": 0.86,
"mean_ms": 0.79
},
"startup_help": {
"n": 21,
"min_ms": 0.74,
"median_ms": 0.75,
"p95_ms": 0.84,
"mean_ms": 0.77
}
},
{
"asset": "anyr-windows-x86_64.exe",
"kind": "native",
"path": "D:\\a\\cli\\cli\\anyr-windows-x86_64.exe",
"bytes": 3040768,
"size": "2.9 MiB",
"version": "0.1.37 (built 2026-10-29T16:16:44Z)",
"target": "x86_64-pc-windows-msvc",
"os": "windows-latest",
"startup_version": {
"n": 21,
"min_ms": 9.03,
"median_ms": 9.59,
"p95_ms": 10.63,
"mean_ms": 9.65
},
"startup_help": {
"n": 21,
"min_ms": 9.18,
"median_ms": 9.42,
"p95_ms": 9.68,
"mean_ms": 9.45
}
},
{
"asset": "anyr.wasm",
"kind": "wasm",
"path": "/home/runner/work/cli/cli/target/wasm-pkg/anyr_cli_bg.wasm",
"bytes": 258392,
"size": "252.3 KiB",
"version": "wasm",
"target": "wasm32-unknown-unknown",
"os": ""
}
] |
Summary
Picking
model…in the launcher used to tear down the palette and leave a blank screen while two uncached requests ran (GET /v1/models, 235 KB, then the benchmarks feed). The picker then drew roughly half a second later, and over a second on a slow network.With this change, the picker opens in 32 ms instead of 576 ms (median of 7 interleaved runs per side, warm cache).
Loading models…line, so it never shows an empty screen.launch_cache):models --pick,models use --agent, Switch model, bind agent model, the config TUI and status. A fresh copy is used as is. A stale copy (under a day old) is shown while it refreshes in the background. With no copy, the full catalog is fetched without the launch path's 1.5 s cap.created, so the price,freeandnewcolumns survive it. Rows from older cache versions are ignored. Benchmark scores get their own cached row (model-scores.json) with the same freshness rules.Models(ANYR_TUI=0) now opens the picker. It used to print a list into scrollback, and the launcher then drew over it.anyr modelsfrom a shell is unchanged. The list, TSV,--jsonanduse <id>validation still fetch live.Measurement
The time is from pressing Enter on
model…until the picker table is on screen. A Python pty harness drove release builds oforigin/main(adaae15) and this branch, alternating A, B, A, B. Each run was checked for at least 10 model ids and 10 prices on screen.The before number is network bound. curl puts the catalog at ~0.37 s and the benchmarks feed at ~0.22 s, run one after the other. In the cold Enter-at-once case, the picker waits on the in-flight warm instead of starting a second fetch, so it still matches the network time. It shows
Loading models…instead of a blank screen. One baseline cold run never drew the picker within 15 s, because the uncached fetch stalled behind a blank screen.Tests
a_warm_picker_reads_catalog_and_scores_from_disk_onlyuses injected fetchers that panic if they are called.the_launcher_pickers_read_the_disk_cachetestsmodels_for_pickeragainst an unroutable base. It fails if the picker bypasses the cache (mutation checked).a_saved_catalog_reads_back_with_every_launch_fieldnow covers pricing andcreated.a_row_from_an_older_cache_version_is_ignoredis new.cargo fmt --check,cargo clippy --locked --all-targets(0 warnings) andcargo test --locked --all-targets(1047 passed) all pass. The wasm--no-default-featurescheck builds with no new warnings.🤖 Generated with Claude Code