fix(dashboard): resolve model-switch spinner + persist benchmark on switchboard hosts - #289
Merged
azilber merged 1 commit intoAug 11, 2026
Conversation
…witchboard hosts On switchboard-mode hosts the host agent records model-activation completion in data/model-state.json (record_verified_route) and never writes the legacy data/model-activation-receipt.json. The dashboard-api's activationReadyModel signal was gated solely on that receipt, so it stayed null forever and the Models page "Working" spinner ran to its 610s timeout on every switch even though the switch had actually succeeded. - dashboard-api: add _read_model_state() + _switchboard_activation_complete() and OR it into the activationReadyModel gate (legacy receipt path preserved, so non-switchboard installs are unaffected). Reuses _model_name_tokens(). - dashboard UI: capture the benchmark tokensPerSecond into a client-side benchmarkResults map so the freshly measured value survives the next /api/models poll (which re-derives Speed server-side); getSpeedDisplay now prefers that override, threaded through the model rows and the current-model panel. Poll acceleration also covers a running benchmark. Adds backend unit tests for switchboard completion (positive + negative cases) and a UI test that the benchmarked tok/s survives a subsequent poll. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
azilber
deleted the
fix/switchboard-activation-ready-and-benchmark-persist
branch
August 11, 2026 14:26
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.
Problem
On switchboard-mode hosts (e.g. CPU installs after PR #288), the Models dashboard misbehaves:
data/model-state.json(record_verified_route) and never writes the legacydata/model-activation-receipt.json. The dashboard-api'sactivationReadyModelsignal was gated solely on that receipt, so it stayednullforever and the UI (activationMatchesinuseModels.js) spun to its 610s timeout on every switch — even though the switch had actually succeeded (llama-server +model-state.jsonconfirm it).Fix
routers/models.py): add_read_model_state()+_switchboard_activation_complete()and OR it into theactivationReadyModelgate. The legacy receipt path is preserved, so non-switchboard installs are unaffected. Reuses_model_name_tokens().useModels.js,Models.jsx): capture the benchmarktokensPerSecondinto a client-sidebenchmarkResultsmap so the value survives the next/api/modelspoll;getSpeedDisplay(model, benchmarkOverride)prefers it, threaded through the rows and the current-model panel. Poll acceleration also covers a running benchmark.Not changed (working as designed)
not_agent_viable.Tests
test_models.py; fulltest_models.py(114),test_model_state.py/test_config.py(99) pass.useModelstest that benchmarked tok/s survives a later poll; ESLint clean;useModels(35) +Models(36) tests pass;vite buildsucceeds.Verified live
Rebuilt/recreated
ods-dashboard-api+ods-dashboard; with no receipt on disk,GET /api/modelsnow returnsactivationReadyModel: "qwen3.5-9b-q4"(wasnull), sourced from the switchboard state.Two pre-existing large files (
models.py,tests/test_models.py, already >2000 lines) carry a# FILE-SIZE-OKmarker; splitting is a separate follow-up.🤖 Generated with Claude Code