diff --git a/studio/frontend/src/features/api-monitor/use-api-monitor.ts b/studio/frontend/src/features/api-monitor/use-api-monitor.ts index 3a40990120..0b613eb8c6 100644 --- a/studio/frontend/src/features/api-monitor/use-api-monitor.ts +++ b/studio/frontend/src/features/api-monitor/use-api-monitor.ts @@ -77,7 +77,19 @@ export function computeStats(entries: ApiMonitorEntry[]): MonitorStats { let generatedTokens = 0; let generatedDurationMs = 0; + let requests = 0; + for (const entry of entries) { + // A model load, unload or download is not an HTTP call. It shows as + // "running" for as long as the load takes, so counting it would report an + // in-flight request with no client waiting and fold a multi-minute download + // into "Avg latency". The backend already leaves these out of + // active_count for the same reason, so counting them here would also make + // the page disagree with the number the API itself reports. + if (entry.kind === "lifecycle") { + continue; + } + requests += 1; totalTokens += entryTokens(entry); if (entry.status === "running") { active += 1; @@ -106,7 +118,7 @@ export function computeStats(entries: ApiMonitorEntry[]): MonitorStats { const finished = completed + errors + cancelled; return { active, - total: entries.length, + total: requests, completed, errors, cancelled, diff --git a/studio/frontend/src/features/hub/catalog/hub-model-settings-view.tsx b/studio/frontend/src/features/hub/catalog/hub-model-settings-view.tsx index a293a0071a..30176a7d90 100644 --- a/studio/frontend/src/features/hub/catalog/hub-model-settings-view.tsx +++ b/studio/frontend/src/features/hub/catalog/hub-model-settings-view.tsx @@ -109,8 +109,13 @@ export function HubModelSettingsView({ />

- Saved settings apply everywhere this model loads, including when an - OpenAI-compatible API request asks for it. Turn on{" "} + {/* Only a GGUF is mirrored to the server, because API auto-switch + indexes GGUFs only, so promising the API case for anything + else describes a load that cannot happen. */} + {target.isGguf + ? "Saved settings apply everywhere this model loads, including when an OpenAI-compatible API request asks for it." + : "Saved settings apply everywhere Studio loads this model."}{" "} + Turn on{" "} Remember for this model {" "} diff --git a/tests/studio/test_model_picker_contracts.py b/tests/studio/test_model_picker_contracts.py index 71a3c7d659..f3dbd9c545 100644 --- a/tests/studio/test_model_picker_contracts.py +++ b/tests/studio/test_model_picker_contracts.py @@ -702,3 +702,34 @@ def test_backfill_compares_server_keys_by_normalized_identity(): assert 'key.lastIndexOf(":")' in src # Repo ids fold and POSIX paths do not, which is exactly what these do. assert "normalizeModelIdentity(" in src and "normalizeGgufVariantIdentity(" in src + + +def test_monitor_stats_exclude_model_lifecycle_rows(): + """A load, unload or download is recorded as a monitor entry but is not an + HTTP call. It reads as "running" for as long as the load takes, so counting + it reports an in-flight request with no client waiting and folds a + multi-minute download into "Avg latency". The backend already leaves these + out of active_count, so counting them here also makes the page disagree with + the number the API itself reports. + """ + src = " ".join(_read("features/api-monitor/use-api-monitor.ts").split()) + assert 'if (entry.kind === "lifecycle") { continue; }' in src + # "Requests" is a request count too, so it cannot stay entries.length. + assert "total: requests," in src + assert "total: entries.length" not in src + + backend = ( + WORKDIR / "studio" / "backend" / "core" / "inference" / "api_monitor.py" + ).read_text(encoding = "utf-8") + assert 'entry.kind != "lifecycle"' in backend, "the rule this mirrors" + + +def test_api_reach_copy_is_limited_to_gguf_models(): + """The Hub opens this page for every downloaded model, but ModelConfigPage + mirrors settings to the server only when target.isGguf, because API + auto-switch indexes GGUFs only. Telling a safetensors user the settings + apply to an API request describes a load that cannot happen. + """ + src = " ".join(_read("features/hub/catalog/hub-model-settings-view.tsx").split()) + assert "{target.isGguf ?" in src + assert "Saved settings apply everywhere Studio loads this model." in src