* proxy/config: add model level macros Add macros to model configuration. Model macros override macros that are defined at the global configuration level. They follow the same naming and value rules as the global macros. * proxy/config: fix bug with macro reserved name checking The PORT reserved name was not properly checked * proxy/config: add tests around model.filters.stripParams - add check that model.filters.stripParams has no invalid macros - renamed strip_params to stripParams for camel case consistency - add legacy code compatibility so model.filters.strip_params continues to work * proxy/config: add duplicate removal to model.filters.stripParams * clean up some doc nits
122 lines
2.9 KiB
Go
122 lines
2.9 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"runtime"
|
|
"slices"
|
|
"strings"
|
|
)
|
|
|
|
type ModelConfig struct {
|
|
Cmd string `yaml:"cmd"`
|
|
CmdStop string `yaml:"cmdStop"`
|
|
Proxy string `yaml:"proxy"`
|
|
Aliases []string `yaml:"aliases"`
|
|
Env []string `yaml:"env"`
|
|
CheckEndpoint string `yaml:"checkEndpoint"`
|
|
UnloadAfter int `yaml:"ttl"`
|
|
Unlisted bool `yaml:"unlisted"`
|
|
UseModelName string `yaml:"useModelName"`
|
|
|
|
// #179 for /v1/models
|
|
Name string `yaml:"name"`
|
|
Description string `yaml:"description"`
|
|
|
|
// Limit concurrency of HTTP requests to process
|
|
ConcurrencyLimit int `yaml:"concurrencyLimit"`
|
|
|
|
// Model filters see issue #174
|
|
Filters ModelFilters `yaml:"filters"`
|
|
|
|
// Macros: see #264
|
|
// Model level macros take precedence over the global macros
|
|
Macros MacroList `yaml:"macros"`
|
|
}
|
|
|
|
func (m *ModelConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
type rawModelConfig ModelConfig
|
|
defaults := rawModelConfig{
|
|
Cmd: "",
|
|
CmdStop: "",
|
|
Proxy: "http://localhost:${PORT}",
|
|
Aliases: []string{},
|
|
Env: []string{},
|
|
CheckEndpoint: "/health",
|
|
UnloadAfter: 0,
|
|
Unlisted: false,
|
|
UseModelName: "",
|
|
ConcurrencyLimit: 0,
|
|
Name: "",
|
|
Description: "",
|
|
}
|
|
|
|
// the default cmdStop to taskkill /f /t /pid ${PID}
|
|
if runtime.GOOS == "windows" {
|
|
defaults.CmdStop = "taskkill /f /t /pid ${PID}"
|
|
}
|
|
|
|
if err := unmarshal(&defaults); err != nil {
|
|
return err
|
|
}
|
|
|
|
*m = ModelConfig(defaults)
|
|
return nil
|
|
}
|
|
|
|
func (m *ModelConfig) SanitizedCommand() ([]string, error) {
|
|
return SanitizeCommand(m.Cmd)
|
|
}
|
|
|
|
// ModelFilters see issue #174
|
|
type ModelFilters struct {
|
|
StripParams string `yaml:"stripParams"`
|
|
}
|
|
|
|
func (m *ModelFilters) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
type rawModelFilters ModelFilters
|
|
defaults := rawModelFilters{
|
|
StripParams: "",
|
|
}
|
|
|
|
if err := unmarshal(&defaults); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Try to unmarshal with the old field name for backwards compatibility
|
|
if defaults.StripParams == "" {
|
|
var legacy struct {
|
|
StripParams string `yaml:"strip_params"`
|
|
}
|
|
if legacyErr := unmarshal(&legacy); legacyErr != nil {
|
|
return errors.New("failed to unmarshal legacy filters.strip_params: " + legacyErr.Error())
|
|
}
|
|
defaults.StripParams = legacy.StripParams
|
|
}
|
|
|
|
*m = ModelFilters(defaults)
|
|
return nil
|
|
}
|
|
|
|
func (f ModelFilters) SanitizedStripParams() ([]string, error) {
|
|
if f.StripParams == "" {
|
|
return nil, nil
|
|
}
|
|
|
|
params := strings.Split(f.StripParams, ",")
|
|
cleaned := make([]string, 0, len(params))
|
|
seen := make(map[string]bool)
|
|
|
|
for _, param := range params {
|
|
trimmed := strings.TrimSpace(param)
|
|
if trimmed == "model" || trimmed == "" || seen[trimmed] {
|
|
continue
|
|
}
|
|
seen[trimmed] = true
|
|
cleaned = append(cleaned, trimmed)
|
|
}
|
|
|
|
// sort cleaned
|
|
slices.Sort(cleaned)
|
|
return cleaned, nil
|
|
}
|