mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-09-20 08:57:57 +00:00
feat(auto): AUTO-only priority chain with tiered slots + live source probing; CSV export w/ key names; audit persistence; fix prompt token accounting & deepseek thinking
This commit is contained in:
@ -121,9 +121,11 @@ func (c *Config) ApplyDefaults() error {
|
||||
|
||||
// RuntimeConfig is the persisted web-UI editable slice (sources added/edited).
|
||||
type RuntimeConfig struct {
|
||||
Sources []Source `json:"sources"`
|
||||
Keys []GWKey `json:"keys,omitempty"`
|
||||
Auto []ModelScope `json:"auto,omitempty"`
|
||||
Sources []Source `json:"sources"`
|
||||
DeletedSources []string `json:"deleted_sources,omitempty"`
|
||||
DeletedAdapters []string `json:"deleted_adapters,omitempty"`
|
||||
Keys []GWKey `json:"keys,omitempty"`
|
||||
Auto []ModelScope `json:"auto,omitempty"`
|
||||
}
|
||||
|
||||
// GWKey is a gateway API key persisted in the runtime store. Role is "admin"
|
||||
@ -144,6 +146,8 @@ type GWKey struct {
|
||||
// uses Hours as the window length in hours.
|
||||
type ModelScope struct {
|
||||
Model string `json:"model"`
|
||||
Source string `json:"source,omitempty"` // optional: pin to one upstream source; "" = any source
|
||||
Tier int `json:"tier,omitempty"`
|
||||
TokenQuota int64 `json:"token_quota"`
|
||||
Period string `json:"period,omitempty"`
|
||||
Hours int64 `json:"hours,omitempty"`
|
||||
@ -160,6 +164,8 @@ func (m *ModelScope) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
var o struct {
|
||||
Model string `json:"model"`
|
||||
Source string `json:"source"`
|
||||
Tier int `json:"tier"`
|
||||
TokenQuota int64 `json:"token_quota"`
|
||||
Period string `json:"period"`
|
||||
Hours int64 `json:"hours"`
|
||||
@ -168,6 +174,8 @@ func (m *ModelScope) UnmarshalJSON(b []byte) error {
|
||||
return err
|
||||
}
|
||||
m.Model = o.Model
|
||||
m.Source = o.Source
|
||||
m.Tier = o.Tier
|
||||
m.TokenQuota = o.TokenQuota
|
||||
m.Period = o.Period
|
||||
m.Hours = o.Hours
|
||||
|
||||
@ -49,14 +49,16 @@ func (s *Store) Upsert(src Source) error {
|
||||
for i := range s.data.Sources {
|
||||
if s.data.Sources[i].Name == src.Name {
|
||||
s.data.Sources[i] = src
|
||||
s.data.DeletedSources = removeString(s.data.DeletedSources, src.Name)
|
||||
return s.persistLocked()
|
||||
}
|
||||
}
|
||||
s.data.Sources = append(s.data.Sources, src)
|
||||
s.data.DeletedSources = removeString(s.data.DeletedSources, src.Name)
|
||||
return s.persistLocked()
|
||||
}
|
||||
|
||||
// Remove deletes a runtime source and persists.
|
||||
// Remove deletes a runtime source or hides a base YAML source and persists.
|
||||
func (s *Store) Remove(name string) (bool, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
@ -69,11 +71,47 @@ func (s *Store) Remove(name string) (bool, error) {
|
||||
}
|
||||
kept = append(kept, src)
|
||||
}
|
||||
if !removed {
|
||||
return false, nil
|
||||
}
|
||||
s.data.Sources = kept
|
||||
return true, s.persistLocked()
|
||||
if !containsString(s.data.DeletedSources, name) {
|
||||
s.data.DeletedSources = append(s.data.DeletedSources, name)
|
||||
}
|
||||
return removed || containsString(s.data.DeletedSources, name), s.persistLocked()
|
||||
}
|
||||
|
||||
func (s *Store) DeletedSources() map[string]bool {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
out := map[string]bool{}
|
||||
for _, name := range s.data.DeletedSources {
|
||||
out[name] = true
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (s *Store) DeleteAdapter(name string) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if !containsString(s.data.DeletedAdapters, name) {
|
||||
s.data.DeletedAdapters = append(s.data.DeletedAdapters, name)
|
||||
}
|
||||
return s.persistLocked()
|
||||
}
|
||||
|
||||
func (s *Store) RestoreAdapter(name string) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.data.DeletedAdapters = removeString(s.data.DeletedAdapters, name)
|
||||
return s.persistLocked()
|
||||
}
|
||||
|
||||
func (s *Store) DeletedAdapters() map[string]bool {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
out := map[string]bool{}
|
||||
for _, name := range s.data.DeletedAdapters {
|
||||
out[name] = true
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (s *Store) persistLocked() error {
|
||||
@ -84,6 +122,25 @@ func (s *Store) persistLocked() error {
|
||||
return os.WriteFile(s.path, b, 0644)
|
||||
}
|
||||
|
||||
func containsString(list []string, s string) bool {
|
||||
for _, x := range list {
|
||||
if x == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func removeString(list []string, s string) []string {
|
||||
out := list[:0]
|
||||
for _, x := range list {
|
||||
if x != s {
|
||||
out = append(out, x)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// ListKeys returns the persisted gateway keys.
|
||||
func (s *Store) ListKeys() []GWKey {
|
||||
s.mu.Lock()
|
||||
|
||||
Reference in New Issue
Block a user