mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
b88ca96064
* refactor: move client_type to provider, replace model fields with config JSONB - Move `client_type` from `models` to `llm_providers` table - Add `icon` field to `llm_providers` - Replace `dimensions`, `input_modalities`, `supports_reasoning` on `models` with a single `config` JSONB column containing `dimensions`, `compatibilities` (vision, tool-call, image-output, reasoning), and `context_window` - Auto-imported models default to vision + tool-call + reasoning - Update all backend consumers (agent, flow resolver, handlers, memory) - Regenerate sqlc, swagger, and TypeScript SDK - Update frontend forms, display, and i18n for new schema * ui: show provider icon avatar in sidebar and detail header, remove icon input * feat: add built-in provider registry with YAML definitions and enable toggle - Add `enable` column to llm_providers (default true, backward-compatible) - Create internal/registry package to load YAML provider/model definitions on startup and upsert into database (new providers disabled by default) - Add conf/providers/ with OpenAI, Anthropic, Google YAML definitions - Add RegistryConfig to TOML config (providers_dir, default conf/providers) - Model listing APIs and conversation flow now filter by enabled providers - Frontend: enable switch in provider form, green status dot in sidebar, enabled providers sorted to top * fix: make 0041 migration idempotent for fresh databases Guard data migration steps with column-existence checks so the migration succeeds on databases created from the updated init schema.
252 lines
6.3 KiB
Go
252 lines
6.3 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/BurntSushi/toml"
|
|
)
|
|
|
|
const (
|
|
DefaultConfigPath = "config.toml"
|
|
DefaultHTTPAddr = ":8080"
|
|
DefaultNamespace = "default"
|
|
DefaultSocketPath = "/run/containerd/containerd.sock"
|
|
DefaultDataRoot = "data"
|
|
DefaultDataMount = "/data"
|
|
DefaultCNIBinaryDir = "/opt/cni/bin"
|
|
DefaultCNIConfigDir = "/etc/cni/net.d"
|
|
DefaultJWTExpiresIn = "24h"
|
|
DefaultPGHost = "127.0.0.1"
|
|
DefaultPGPort = 5432
|
|
DefaultPGUser = "postgres"
|
|
DefaultPGDatabase = "memoh"
|
|
DefaultPGSSLMode = "disable"
|
|
DefaultQdrantURL = "http://127.0.0.1:6334"
|
|
DefaultQdrantCollection = "memory"
|
|
DefaultRuntimeDir = "/opt/memoh/runtime"
|
|
DefaultBaseImage = "debian:bookworm-slim"
|
|
)
|
|
|
|
type Config struct {
|
|
Log LogConfig `toml:"log"`
|
|
Server ServerConfig `toml:"server"`
|
|
Admin AdminConfig `toml:"admin"`
|
|
Auth AuthConfig `toml:"auth"`
|
|
Containerd ContainerdConfig `toml:"containerd"`
|
|
Workspace WorkspaceConfig `toml:"workspace"`
|
|
Postgres PostgresConfig `toml:"postgres"`
|
|
Qdrant QdrantConfig `toml:"qdrant"`
|
|
Sparse SparseConfig `toml:"sparse"`
|
|
BrowserGateway BrowserGatewayConfig `toml:"browser_gateway"`
|
|
Registry RegistryConfig `toml:"registry"`
|
|
}
|
|
|
|
type LogConfig struct {
|
|
Level string `toml:"level"`
|
|
Format string `toml:"format"`
|
|
}
|
|
|
|
type ServerConfig struct {
|
|
Addr string `toml:"addr"`
|
|
}
|
|
|
|
type AdminConfig struct {
|
|
Username string `toml:"username"`
|
|
Password string `toml:"password" json:"-"`
|
|
Email string `toml:"email"`
|
|
}
|
|
|
|
type AuthConfig struct {
|
|
JWTSecret string `toml:"jwt_secret" json:"-"`
|
|
JWTExpiresIn string `toml:"jwt_expires_in"`
|
|
}
|
|
|
|
type ContainerdConfig struct {
|
|
SocketPath string `toml:"socket_path"`
|
|
Namespace string `toml:"namespace"`
|
|
Socktainer SocktainerConfig `toml:"socktainer"`
|
|
}
|
|
|
|
type SocktainerConfig struct {
|
|
SocketPath string `toml:"socket_path"`
|
|
BinaryPath string `toml:"binary_path"`
|
|
}
|
|
|
|
type WorkspaceConfig struct {
|
|
Registry string `toml:"registry"`
|
|
DefaultImage string `toml:"default_image"`
|
|
Snapshotter string `toml:"snapshotter"`
|
|
DataRoot string `toml:"data_root"`
|
|
CNIBinaryDir string `toml:"cni_bin_dir"`
|
|
CNIConfigDir string `toml:"cni_conf_dir"`
|
|
RuntimeDir string `toml:"runtime_dir"`
|
|
}
|
|
|
|
// ImageRef returns the fully qualified image reference for the base image,
|
|
// prepending the registry mirror when configured and normalizing for containerd
|
|
// compatibility.
|
|
func (c WorkspaceConfig) ImageRef() string {
|
|
img := c.DefaultImage
|
|
if img == "" {
|
|
img = DefaultBaseImage
|
|
}
|
|
if c.Registry != "" {
|
|
return c.Registry + "/" + img
|
|
}
|
|
return NormalizeImageRef(img)
|
|
}
|
|
|
|
// RuntimePath returns the path to the workspace runtime directory.
|
|
func (c WorkspaceConfig) RuntimePath() string {
|
|
if c.RuntimeDir != "" {
|
|
return c.RuntimeDir
|
|
}
|
|
return DefaultRuntimeDir
|
|
}
|
|
|
|
// NormalizeImageRef ensures an image reference is fully qualified for containerd.
|
|
func NormalizeImageRef(ref string) string {
|
|
firstSlash := strings.Index(ref, "/")
|
|
if firstSlash == -1 {
|
|
return "docker.io/library/" + ref
|
|
}
|
|
firstSegment := ref[:firstSlash]
|
|
if strings.Contains(firstSegment, ".") || strings.Contains(firstSegment, ":") || firstSegment == "localhost" {
|
|
return ref
|
|
}
|
|
return "docker.io/" + ref
|
|
}
|
|
|
|
type PostgresConfig struct {
|
|
Host string `toml:"host"`
|
|
Port int `toml:"port"`
|
|
User string `toml:"user"`
|
|
Password string `toml:"password" json:"-"`
|
|
Database string `toml:"database"`
|
|
SSLMode string `toml:"sslmode"`
|
|
}
|
|
|
|
type QdrantConfig struct {
|
|
BaseURL string `toml:"base_url"`
|
|
APIKey string `toml:"api_key" json:"-"`
|
|
TimeoutSeconds int `toml:"timeout_seconds"`
|
|
}
|
|
|
|
type SparseConfig struct {
|
|
BaseURL string `toml:"base_url"`
|
|
}
|
|
|
|
const DefaultProvidersDir = "conf/providers"
|
|
|
|
type RegistryConfig struct {
|
|
ProvidersDir string `toml:"providers_dir"`
|
|
}
|
|
|
|
// ProvidersPath returns the configured providers directory or the default.
|
|
func (c RegistryConfig) ProvidersPath() string {
|
|
if c.ProvidersDir != "" {
|
|
return c.ProvidersDir
|
|
}
|
|
return DefaultProvidersDir
|
|
}
|
|
|
|
type BrowserGatewayConfig struct {
|
|
Host string `toml:"host"`
|
|
Port int `toml:"port"`
|
|
}
|
|
|
|
func (c BrowserGatewayConfig) BaseURL() string {
|
|
host := c.Host
|
|
if host == "" {
|
|
host = "127.0.0.1"
|
|
}
|
|
port := c.Port
|
|
if port == 0 {
|
|
port = 8083
|
|
}
|
|
return "http://" + host + ":" + strconv.Itoa(port)
|
|
}
|
|
|
|
func Load(path string) (Config, error) {
|
|
cfg := Config{
|
|
Log: LogConfig{
|
|
Level: "info",
|
|
Format: "text",
|
|
},
|
|
Server: ServerConfig{
|
|
Addr: DefaultHTTPAddr,
|
|
},
|
|
Admin: AdminConfig{
|
|
Username: "admin",
|
|
Password: "change-your-password-here",
|
|
Email: "you@example.com",
|
|
},
|
|
Auth: AuthConfig{
|
|
JWTExpiresIn: DefaultJWTExpiresIn,
|
|
},
|
|
Containerd: ContainerdConfig{
|
|
SocketPath: DefaultSocketPath,
|
|
Namespace: DefaultNamespace,
|
|
},
|
|
Workspace: WorkspaceConfig{
|
|
DefaultImage: DefaultBaseImage,
|
|
DataRoot: DefaultDataRoot,
|
|
CNIBinaryDir: DefaultCNIBinaryDir,
|
|
CNIConfigDir: DefaultCNIConfigDir,
|
|
},
|
|
Postgres: PostgresConfig{
|
|
Host: DefaultPGHost,
|
|
Port: DefaultPGPort,
|
|
User: DefaultPGUser,
|
|
Database: DefaultPGDatabase,
|
|
SSLMode: DefaultPGSSLMode,
|
|
},
|
|
BrowserGateway: BrowserGatewayConfig{
|
|
Host: "127.0.0.1",
|
|
Port: 8083,
|
|
},
|
|
}
|
|
|
|
if path == "" {
|
|
path = DefaultConfigPath
|
|
}
|
|
path = filepath.Clean(path)
|
|
|
|
if _, err := os.Stat(path); err != nil {
|
|
if os.IsNotExist(err) {
|
|
return cfg, nil
|
|
}
|
|
return cfg, err
|
|
}
|
|
|
|
//nolint:gosec // config path is intentionally user-configurable
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return cfg, err
|
|
}
|
|
|
|
var raw struct {
|
|
Workspace map[string]any `toml:"workspace"`
|
|
MCP map[string]any `toml:"mcp"`
|
|
}
|
|
if _, err := toml.Decode(string(data), &raw); err != nil {
|
|
return cfg, err
|
|
}
|
|
if raw.MCP != nil {
|
|
if raw.Workspace != nil {
|
|
return cfg, errors.New("config uses both [mcp] and [workspace]; remove [mcp] and keep only [workspace]")
|
|
}
|
|
return cfg, errors.New("config section [mcp] has been renamed to [workspace]; update your config.toml and restart")
|
|
}
|
|
|
|
if _, err := toml.Decode(string(data), &cfg); err != nil {
|
|
return cfg, err
|
|
}
|
|
|
|
return cfg, nil
|
|
}
|