mirror of
https://github.com/mudler/LocalAI.git
synced 2026-11-06 12:33:16 -05:00
An add-on can declare userSettings in its manifest: a key, the allowed
values and a default. The host keeps each person's answer in the account
database every frontend shares (one file when accounts are off), checks
every write against the declaration, and never asks the add-on.
GET and PUT /api/addons/{id}/user-settings read and write them. A write
needs the person's own browser session, so no API key, model or tool can
change one. A setting may carry a role that the host reads for its own
rules; the host fixes the values and the default of a role so a manifest
cannot loosen it. Pages reach their settings through sdk.userSettings,
which is bound to the add-on that calls it.
Assisted-by: Claude:claude-sonnet-5-5 go node
64 lines
2.0 KiB
Go
64 lines
2.0 KiB
Go
// SPDX-License-Identifier: MIT
|
|
package application
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"path/filepath"
|
|
|
|
"github.com/mudler/LocalAI/core/http/auth"
|
|
"github.com/mudler/LocalAI/core/services/addons/usersettings"
|
|
"github.com/mudler/xlog"
|
|
)
|
|
|
|
// AddonUserSettingsStore returns the store of the per-person add-on settings,
|
|
// created once so the routes and the chats share it. An error is cached: a
|
|
// store that cannot be opened stays unavailable, and startup stops rather than
|
|
// fall back to a copy that another frontend would not see.
|
|
func (a *Application) AddonUserSettingsStore() (usersettings.Store, error) {
|
|
a.addonUserSettingsOnce.Do(func() {
|
|
if db := a.authDB; db != nil {
|
|
s, err := usersettings.NewGormStore(db)
|
|
if err != nil {
|
|
a.addonUserSettingsErr = fmt.Errorf("open the add-on user settings table: %w", err)
|
|
return
|
|
}
|
|
a.addonUserSettings = s
|
|
return
|
|
}
|
|
path := ""
|
|
if dp := a.applicationConfig.DataPath; dp != "" {
|
|
path = filepath.Join(dp, "addon-user-settings.json")
|
|
} else {
|
|
xlog.Warn("No data path and no account database: add-on user settings are kept in memory only and do not survive a restart")
|
|
}
|
|
s, err := usersettings.NewFileStore(path)
|
|
if err != nil {
|
|
a.addonUserSettingsErr = fmt.Errorf("open the add-on user settings file %q: %w", path, err)
|
|
return
|
|
}
|
|
a.addonUserSettings = s
|
|
})
|
|
return a.addonUserSettings, a.addonUserSettingsErr
|
|
}
|
|
|
|
// studioUserSetting reads one stored answer for a chat owner. Without an
|
|
// account database there is one local owner, whichever name the chat carries;
|
|
// the routes write under the same key. A store that cannot answer is an error:
|
|
// the caller treats it as the default, never as a looser choice.
|
|
func (a *Application) studioUserSetting(ctx context.Context, user, addonID, key string) (string, bool, error) {
|
|
store, err := a.AddonUserSettingsStore()
|
|
if err != nil {
|
|
return "", false, err
|
|
}
|
|
if a.authDB == nil {
|
|
user = auth.AddonLocalOwnerID
|
|
}
|
|
m, err := store.Get(ctx, user, addonID)
|
|
if err != nil {
|
|
return "", false, err
|
|
}
|
|
v, ok := m[key]
|
|
return v, ok, nil
|
|
}
|