refactor: name the proxy backends with constants

Review asked for constants instead of the "cloud-proxy" and
"localai-proxy" literals. Add CloudProxyBackend and LocalAIProxyBackend next
to the other backend-name constants in pkg/model (WhisperBackend,
TransformersBackend, ...), which core/config already imports, and use them
in every production check: the proxy options builder, IsRemoteProxy,
IsCloudProxyBackendPassthrough, the PII defaults, the localai-proxy backend
hook and loader warning, and the PII middleware metadata in the routes and
the in-process MCP client.

The proxy options builder now calls IsRemoteProxy() instead of repeating
the two-backend check, so the set of proxy backends is defined once.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
Ettore Di Giacinto committed 2026-09-27 07:42:21 +00:00
1 parent 53ce024efc
commit 8db6c15fe0
8 files changed
+25 -12

No files matched your search

+2 -2
View File
@@ -542,7 +542,7 @@ func grpcModelOpts(c config.ModelConfig, modelPath string) *pb.ModelOptions {
Tokenizer: c.Tokenizer,
}
if c.Backend == "cloud-proxy" || c.Backend == "localai-proxy" {
if c.IsRemoteProxy() {
opts.Proxy = &pb.ProxyOptions{
UpstreamUrl: c.Proxy.UpstreamURL,
Mode: c.Proxy.Mode,
@@ -558,7 +558,7 @@ func grpcModelOpts(c config.ModelConfig, modelPath string) *pb.ModelOptions {
// failover.UpstreamModel uses. Not for cloud-proxy: its translate mode
// falls back to parameters.model and passthrough keeps the client's
// model when upstream_model is empty.
if c.Backend == "localai-proxy" && opts.Proxy.UpstreamModel == "" {
if c.Backend == model.LocalAIProxyBackend && opts.Proxy.UpstreamModel == "" {
opts.Proxy.UpstreamModel = c.Name
}
}
+3 -1
View File
@@ -1,7 +1,9 @@
package config
import "github.com/mudler/LocalAI/pkg/model"
func init() {
RegisterBackendHook("localai-proxy", localAIProxyDefaults)
RegisterBackendHook(model.LocalAIProxyBackend, localAIProxyDefaults)
}
// localAIProxyDefaults makes chat requests reach the upstream as structured
+4 -3
View File
@@ -17,6 +17,7 @@ import (
"github.com/mudler/LocalAI/core/services/routing/piipattern"
"github.com/mudler/LocalAI/pkg/downloader"
"github.com/mudler/LocalAI/pkg/functions"
"github.com/mudler/LocalAI/pkg/model"
"github.com/mudler/LocalAI/pkg/modelartifacts"
"github.com/mudler/LocalAI/pkg/reasoning"
"github.com/mudler/cogito"
@@ -332,7 +333,7 @@ func (p ProxyConfig) ResolveAPIKey(envLookup func(string) string) (string, error
// passthrough (SetDefaults normalises it, but Validate accepts empty
// too — handlers should not rely on a particular call order).
func (c *ModelConfig) IsCloudProxyBackendPassthrough() bool {
if c.Backend != "cloud-proxy" {
if c.Backend != model.CloudProxyBackend {
return false
}
return c.Proxy.Mode == "" || c.Proxy.Mode == ProxyModePassthrough
@@ -670,7 +671,7 @@ func (c *ModelConfig) PIIIsEnabled() bool {
if c.PII.Enabled != nil {
return *c.PII.Enabled
}
return c.Backend == "cloud-proxy"
return c.Backend == model.CloudProxyBackend
}
// PIIDetectors returns the names of the token-classification models that
@@ -701,7 +702,7 @@ var piiCoverableUsecases = []ModelConfigUsecase{FLAG_CHAT, FLAG_COMPLETION, FLAG
// false naturally: HasUsecases short-circuits to false for any usecase a
// declared score/token_classify model did not itself declare.
func (c *ModelConfig) PIIFilterApplies() bool {
if c.Backend == "cloud-proxy" {
if c.Backend == model.CloudProxyBackend {
return true
}
return slices.ContainsFunc(piiCoverableUsecases, c.HasUsecases)
+3 -1
View File
@@ -3,6 +3,8 @@ package config
import (
"fmt"
"time"
"github.com/mudler/LocalAI/pkg/model"
)
// FailoverConfig turns a model config into a failover chain: requests for the
@@ -54,7 +56,7 @@ func (c ModelConfig) IsFailover() bool { return c.Failover != nil }
// `warm` has no effect on it.
func (c ModelConfig) IsRemoteProxy() bool {
switch c.Backend {
case "cloud-proxy", "localai-proxy":
case model.CloudProxyBackend, model.LocalAIProxyBackend:
return true
}
return false
+2 -1
View File
@@ -17,6 +17,7 @@ import (
"github.com/charmbracelet/glamour"
"github.com/mudler/LocalAI/core/schema"
"github.com/mudler/LocalAI/pkg/downloader"
"github.com/mudler/LocalAI/pkg/model"
"github.com/mudler/LocalAI/pkg/modelartifacts"
"github.com/mudler/LocalAI/pkg/safefile"
"github.com/mudler/LocalAI/pkg/utils"
@@ -963,7 +964,7 @@ func (bcl *ModelConfigLoader) loadModelConfigsFromPath(path string, strict bool,
// when a config carries settings that only make sense there, or lacks
// the usecases failover's own usecase-sharing check depends on.
for name, cfg := range bcl.configs {
if cfg.Backend != "localai-proxy" {
if cfg.Backend != model.LocalAIProxyBackend {
continue
}
if cfg.Proxy.Mode == ProxyModeTranslate || cfg.Proxy.Provider != "" {
+3 -2
View File
@@ -12,6 +12,7 @@ import (
"github.com/mudler/LocalAI/core/http/endpoints/localai"
"github.com/mudler/LocalAI/core/http/middleware"
"github.com/mudler/LocalAI/core/services/routing/router"
"github.com/mudler/LocalAI/pkg/model"
)
// RegisterMiddlewareRoutes wires the routing-module admin surface that
@@ -348,7 +349,7 @@ func buildPIIStatus(app *application.Application) map[string]any {
// Why is this on? backend default (cloud-proxy) vs an explicit YAML
// toggle. Helps admins understand the resolved state without
// reading source.
"default_for_backend": !explicit && cfg.Backend == "cloud-proxy",
"default_for_backend": !explicit && cfg.Backend == model.CloudProxyBackend,
// The detectors came from the global default, not this model's YAML.
"detectors_from_default": enabled && len(ownDetectors) == 0 && len(detectors) > 0,
}
@@ -403,7 +404,7 @@ func buildPIIStatus(app *application.Application) map[string]any {
return map[string]any{
"enabled_globally": true,
"default_enabled_for_backends": []string{"cloud-proxy"},
"default_enabled_for_backends": []string{model.CloudProxyBackend},
"models": models,
"detector_models": detectorModels,
"recent_event_count": recentCount,
+2 -2
View File
@@ -1008,7 +1008,7 @@ func (c *Client) GetMiddlewareStatus(ctx context.Context) (*localaitools.Middlew
EnabledGlobally: c.PIIEvents != nil,
Models: []localaitools.MiddlewarePIIModel{},
}
piiSection.DefaultEnabledForBackends = []string{"cloud-proxy"}
piiSection.DefaultEnabledForBackends = []string{model.CloudProxyBackend}
if c.ConfigLoader != nil {
for _, cfg := range c.ConfigLoader.GetAllModelsConfigs() {
cfg := cfg
@@ -1017,7 +1017,7 @@ func (c *Client) GetMiddlewareStatus(ctx context.Context) (*localaitools.Middlew
Backend: cfg.Backend,
Enabled: cfg.PIIIsEnabled(),
Explicit: cfg.PII.Enabled != nil,
DefaultForBackend: cfg.Backend == "cloud-proxy",
DefaultForBackend: cfg.Backend == model.CloudProxyBackend,
Detectors: cfg.PIIDetectors(),
})
}
+6
View File
@@ -51,6 +51,12 @@ const (
TransformersBackend = "transformers"
LocalStoreBackend = "local-store"
ValkeyStoreBackend = "valkey-store"
// Proxy backends serve a model by forwarding to another server instead
// of loading weights. Core special-cases both (credentials, failover
// kind, PII defaults), so every check goes through these names.
CloudProxyBackend = "cloud-proxy"
LocalAIProxyBackend = "localai-proxy"
)
// starts the grpcModelProcess for the backend, and returns a grpc client