feat: a GPU agent on the CPU shows as degraded, in the System view and on its own page (4410)
CI and images / lint (push) Successful in 3s
CI and images / extension-version (push) Successful in 3s
CI and images / frontend-build (push) Successful in 27s
CI and images / backend-lint-and-test (push) Successful in 34s
CI and images / integration (push) Successful in 2m22s
CI and images / sign-extension (push) Successful in 4s
CI and images / build-web (push) Successful in 2m46s
CI and images / smoke-web (push) Successful in 50s
CI and images / build-agent (push) Successful in 6m35s
CI and images / promote (push) Successful in 2s

torch and onnxruntime both fall back to the CPU without raising, so the agent
that ran CPU-bound for weeks after a driver update leased and checked in like
a healthy one.

- The agent sends its startup accel report on every lease and heartbeat.
- The server keeps a bounded copy on the roster row. A running agent with a
  runtime off the GPU becomes `degraded`, with a sentence naming the runtime
  and the reason.
- The top nav shows it amber.
- The agent page carries a banner, and its pill reads "CPU only".

Also: the bandwidth field gets the page's − / + stepper, and both number
fields drop the browser's spin arrows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVjrnpQjRgHdvq95rASoiR
This commit is contained in:
2026-09-24 19:09:07 -04:00
co-authored by Claude Opus 5.5
parent e39ec1c550
commit cc53d8db7b
10 changed files with 210 additions and 10 deletions
+17
View File
@@ -103,3 +103,20 @@ def test_a_missing_runtime_is_reported_not_raised():
assert accel.torch_status(imp)["device"] == "unavailable"
assert accel.onnx_status(imp)["device"] == "unavailable"
def test_summary_is_what_the_server_stores(monkeypatch):
"""Device plus a bounded reason, per runtime — sent on every lease."""
monkeypatch.setattr(accel, "LAST", {
"torch": {"version": "2.14.0", "device": "cuda", "gpu": "RTX"},
"onnx": {"version": "1.30.0", "device": "cpu", "error": "e" * 500},
})
assert accel.summary() == {
"torch": {"device": "cuda"},
"onnx": {"device": "cpu", "error": "e" * 200},
}
def test_summary_before_the_report_is_none(monkeypatch):
monkeypatch.setattr(accel, "LAST", {})
assert accel.summary() is None