mirror of
https://github.com/mudler/LocalAI.git
synced 2026-05-16 20:52:08 -04:00
In distributed mode the Backends gallery used to fan every install out to every worker — fine for auto-resolving (meta) backends like llama-cpp where each node picks its own variant, but wrong for hardware-specific builds like cpu-llama-cpp that would silently land on every GPU node. Adds a node-targeted install path through the existing POST /api/nodes/:id/backends/install plumbing, with two entry points: - Backends gallery row gets a split-button in distributed mode. Auto- resolving keeps "Install on all nodes" as the primary; chevron menu opens the picker. Hardware-specific routes the primary directly to the picker — no fan-out path on the row. - Nodes-page drawer gets a "+ Add backend" button that navigates to /app/backends?target=<node-id>; the gallery scopes itself to that node (banner, single per-row install button, Reinstall/Remove for already- installed). One gallery, two scopes — no second UI to maintain. The picker (new NodeInstallPicker) shows a 3-state suitability column (Compatible / Override / Installed), an auto-expanding variant override disclosure that fires when selected nodes have no working GPU, parallel per-node installs with inline status and Retry-failed-nodes, and a mismatch confirm that names the consequence on the button itself. A 409 fan-out guard on /api/backends/apply protects CLI/Terraform/script users from the same footgun: hardware-specific installs in distributed mode now return code "concrete_backend_requires_target" with a human- readable error and a meta_alternative pointer. The gallery list payload now surfaces capabilities, metaBackendFor and per-row nodes (NodeBackendRef) so the picker and the new Nodes column have everything they need without re-walking the gallery client-side. GODEBUG=netdns=go is set on the compose services because the cgo DNS resolver follows the container's nsswitch.conf to host systemd-resolved (127.0.0.53), unreachable from inside the container; the pure-Go resolver reads /etc/resolv.conf directly and uses Docker's embedded DNS. Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Assisted-by: Claude Code:claude-opus-4-7[1m] [Edit] [Bash] [Read] [Write]
31 lines
1.3 KiB
Go
31 lines
1.3 KiB
Go
package galleryop
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/mudler/LocalAI/core/gallery"
|
|
)
|
|
|
|
// ProgressCallback reports download progress for model/backend installations.
|
|
type ProgressCallback func(fileName, current, total string, percentage float64)
|
|
|
|
// ModelManager handles model install and delete lifecycle.
|
|
type ModelManager interface {
|
|
InstallModel(ctx context.Context, op *ManagementOp[gallery.GalleryModel, gallery.ModelConfig], progressCb ProgressCallback) error
|
|
DeleteModel(name string) error
|
|
}
|
|
|
|
// BackendManager handles backend install, delete, upgrade, and listing lifecycle.
|
|
type BackendManager interface {
|
|
InstallBackend(ctx context.Context, op *ManagementOp[gallery.GalleryBackend, any], progressCb ProgressCallback) error
|
|
DeleteBackend(name string) error
|
|
ListBackends() (gallery.SystemBackends, error)
|
|
UpgradeBackend(ctx context.Context, name string, progressCb ProgressCallback) error
|
|
CheckUpgrades(ctx context.Context) (map[string]gallery.UpgradeInfo, error)
|
|
// IsDistributed reports whether installs fan out across worker nodes.
|
|
// The HTTP layer uses this to refuse hardware-specific (non-meta) installs
|
|
// on /api/backends/apply in distributed mode — a CPU build silently
|
|
// landing on every GPU node is the footgun this guards against.
|
|
IsDistributed() bool
|
|
}
|