Summary
PR #10947 fixed capability filtering on the backend discovery endpoints so GPU-only backends are no longer hidden behind a GPU-less controller's own capability. But those same endpoints still filter on b.Installed, which on a distributed controller is derived from the controller's own filesystem — where worker-installed backends do not exist.
Affected endpoints
GET /api/fine-tuning/backends (core/http/endpoints/localai/finetune.go)
GET /api/quantization/backends (core/http/endpoints/localai/quantization.go)
GET /backends/available (to the extent it reports installed state)
Symptom
In distributed mode, an admin with a fine-tuning-capable GPU worker can see a backend listed as available (post-#10947) but still get a short or empty list where installed-state is the filter, because the controller has nothing on disk.
Why it is separate from #10947
#10947 addressed compatibility filtering — "can anything in this cluster run this backend" — by unioning capabilities over healthy backend-type worker nodes. Installed-state is a different question: "does any node in this cluster actually have it installed", and it needs the same cluster-aware treatment.
The aggregate view already exists elsewhere: GET /backends reports per-backend nodes[] with node_name/node_status, so the registry knows. These list endpoints simply do not consult it.
Suggested direction
Aggregate installed-state across healthy backend-type nodes the same way #10947 aggregates capability, so a backend installed on any worker reports as installed. Consider whether the response should distinguish "installed somewhere" from "installed on N of M nodes" — the per-node install path (POST /api/nodes/:id/backends/install) already gives admins node-level control, so the summary view may be sufficient.
Noted as a known remaining gap in #10947 rather than expanded into it, to keep that change reviewable.
Summary
PR #10947 fixed capability filtering on the backend discovery endpoints so GPU-only backends are no longer hidden behind a GPU-less controller's own capability. But those same endpoints still filter on
b.Installed, which on a distributed controller is derived from the controller's own filesystem — where worker-installed backends do not exist.Affected endpoints
GET /api/fine-tuning/backends(core/http/endpoints/localai/finetune.go)GET /api/quantization/backends(core/http/endpoints/localai/quantization.go)GET /backends/available(to the extent it reports installed state)Symptom
In distributed mode, an admin with a fine-tuning-capable GPU worker can see a backend listed as available (post-#10947) but still get a short or empty list where installed-state is the filter, because the controller has nothing on disk.
Why it is separate from #10947
#10947 addressed compatibility filtering — "can anything in this cluster run this backend" — by unioning capabilities over healthy backend-type worker nodes. Installed-state is a different question: "does any node in this cluster actually have it installed", and it needs the same cluster-aware treatment.
The aggregate view already exists elsewhere:
GET /backendsreports per-backendnodes[]withnode_name/node_status, so the registry knows. These list endpoints simply do not consult it.Suggested direction
Aggregate installed-state across healthy backend-type nodes the same way #10947 aggregates capability, so a backend installed on any worker reports as installed. Consider whether the response should distinguish "installed somewhere" from "installed on N of M nodes" — the per-node install path (
POST /api/nodes/:id/backends/install) already gives admins node-level control, so the summary view may be sufficient.Noted as a known remaining gap in #10947 rather than expanded into it, to keep that change reviewable.