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:
root
2026-08-10 00:10:19 +08:00
parent 859d310ad3
commit d48b993010
10 changed files with 663 additions and 210 deletions

View File

@ -152,6 +152,7 @@ func (c *Core) FindKey(key string) (config.GWKey, bool) { return c.store.KeyByVa
// CreateKey builds a new random gateway key and persists it.
func (c *Core) CreateKey(name, role string, models []config.ModelScope, note string) (config.GWKey, error) {
models = cleanScopes(models)
key := make([]byte, 16)
if _, err := rand.Read(key); err != nil {
return config.GWKey{}, err
@ -185,7 +186,7 @@ func (c *Core) UpdateKey(key, name, role string, models []config.ModelScope, not
if role == "admin" || role == "user" {
rec.Role = role
}
rec.Models = models
rec.Models = cleanScopes(models)
rec.Note = note
if err := c.store.SaveKey(rec); err != nil {
return config.GWKey{}, err
@ -202,16 +203,23 @@ func (c *Core) DeleteKey(key string) (bool, error) { return c.store.DeleteKey(ke
// highest priority).
func (c *Core) AutoRules() []config.ModelScope { return c.store.AutoRules() }
// SaveAutoRules persists the AUTO scheduling slots.
func (c *Core) SaveAutoRules(entries []config.ModelScope) error {
func cleanScopes(entries []config.ModelScope) []config.ModelScope {
clean := make([]config.ModelScope, 0, len(entries))
for _, e := range entries {
if e.Model == "" {
continue
}
if e.Source == "undefined" || e.Source == "null" {
e.Source = ""
}
clean = append(clean, e)
}
return c.store.SaveAutoRules(clean)
return clean
}
// SaveAutoRules persists the AUTO scheduling slots.
func (c *Core) SaveAutoRules(entries []config.ModelScope) error {
return c.store.SaveAutoRules(cleanScopes(entries))
}
// Registry resolves model -> owning provider.
@ -219,14 +227,24 @@ func (c *Core) ProviderForModel(model string) *provider.Provider {
return c.registry.ProviderForModel(model)
}
// ProviderForSlot resolves a (model, source) scheduling slot to a provider;
// source "" falls back to ProviderForModel.
func (c *Core) ProviderForSlot(model, source string) *provider.Provider {
return c.registry.ProviderForSlot(model, source)
}
// Config exposes the underlying configuration (read-only usage).
func (c *Core) Config() *config.Config { return c.cfg }
// mergedSources = base YAML sources + runtime sources (runtime wins by name).
func (c *Core) mergedSources() []config.Source {
deleted := c.store.DeletedSources()
byName := map[string]config.Source{}
order := []string{}
for _, s := range c.cfg.Sources {
if deleted[s.Name] {
continue
}
byName[s.Name] = s
order = append(order, s.Name)
}
@ -278,7 +296,17 @@ func (c *Core) Reload() error {
// ---- adapter management (web UI) ----
func (c *Core) ListAdapters() []lua.APIAdapter { return c.vm.ListAdapters() }
func (c *Core) ListAdapters() []lua.APIAdapter {
deleted := c.store.DeletedAdapters()
list := c.vm.ListAdapters()
out := make([]lua.APIAdapter, 0, len(list))
for _, a := range list {
if !deleted[a.Name] {
out = append(out, a)
}
}
return out
}
// UploadAdapter saves a new Lua adapter script to the adapter dir and loads it.
func (c *Core) UploadAdapter(name, code string) error {
@ -295,7 +323,7 @@ func (c *Core) UploadAdapter(name, code string) error {
if err := c.vm.LoadAdapter(path); err != nil {
return fmt.Errorf("load adapter: %w", err)
}
return nil
return c.store.RestoreAdapter(name)
}
// RemoveAdapter deletes an adapter script and evicts it from the VM.
@ -303,7 +331,7 @@ func (c *Core) RemoveAdapter(name string) error {
path := filepath.Join(c.cfg.AdapterDir, name+".lua")
_ = os.Remove(path)
c.vm.RemoveAdapter(name)
return nil
return c.store.DeleteAdapter(name)
}
// ---- source management (web UI) ----