feat(model_registry): enhance model registration and refresh mechanisms
This commit is contained in:
@@ -434,6 +434,17 @@ func (s *Service) ensureExecutorsForAuthWithMode(a *coreauth.Auth, forceReplace
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) registerResolvedModelsForAuth(a *coreauth.Auth, providerKey string, models []*ModelInfo) {
|
||||
if a == nil || a.ID == "" {
|
||||
return
|
||||
}
|
||||
if len(models) == 0 {
|
||||
GlobalModelRegistry().UnregisterClient(a.ID)
|
||||
return
|
||||
}
|
||||
GlobalModelRegistry().RegisterClient(a.ID, providerKey, models)
|
||||
}
|
||||
|
||||
// rebindExecutors refreshes provider executors so they observe the latest configuration.
|
||||
func (s *Service) rebindExecutors() {
|
||||
if s == nil || s.coreManager == nil {
|
||||
@@ -541,6 +552,44 @@ func (s *Service) Run(ctx context.Context) error {
|
||||
s.hooks.OnBeforeStart(s.cfg)
|
||||
}
|
||||
|
||||
// Register callback for startup and periodic model catalog refresh.
|
||||
// When remote model definitions change, re-register models for affected providers.
|
||||
// This intentionally rebuilds per-auth model availability from the latest catalog
|
||||
// snapshot instead of preserving prior registry suppression state.
|
||||
registry.SetModelRefreshCallback(func(changedProviders []string) {
|
||||
if s == nil || s.coreManager == nil || len(changedProviders) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
providerSet := make(map[string]bool, len(changedProviders))
|
||||
for _, p := range changedProviders {
|
||||
providerSet[strings.ToLower(strings.TrimSpace(p))] = true
|
||||
}
|
||||
|
||||
auths := s.coreManager.List()
|
||||
refreshed := 0
|
||||
for _, item := range auths {
|
||||
if item == nil || item.ID == "" {
|
||||
continue
|
||||
}
|
||||
auth, ok := s.coreManager.GetByID(item.ID)
|
||||
if !ok || auth == nil || auth.Disabled {
|
||||
continue
|
||||
}
|
||||
provider := strings.ToLower(strings.TrimSpace(auth.Provider))
|
||||
if !providerSet[provider] {
|
||||
continue
|
||||
}
|
||||
if s.refreshModelRegistrationForAuth(auth) {
|
||||
refreshed++
|
||||
}
|
||||
}
|
||||
|
||||
if refreshed > 0 {
|
||||
log.Infof("re-registered models for %d auth(s) due to model catalog changes: %v", refreshed, changedProviders)
|
||||
}
|
||||
})
|
||||
|
||||
s.serverErr = make(chan error, 1)
|
||||
go func() {
|
||||
if errStart := s.server.Start(); errStart != nil {
|
||||
@@ -926,7 +975,7 @@ func (s *Service) registerModelsForAuth(a *coreauth.Auth) {
|
||||
if providerKey == "" {
|
||||
providerKey = "openai-compatibility"
|
||||
}
|
||||
GlobalModelRegistry().RegisterClient(a.ID, providerKey, applyModelPrefixes(ms, a.Prefix, s.cfg.ForceModelPrefix))
|
||||
s.registerResolvedModelsForAuth(a, providerKey, applyModelPrefixes(ms, a.Prefix, s.cfg.ForceModelPrefix))
|
||||
} else {
|
||||
// Ensure stale registrations are cleared when model list becomes empty.
|
||||
GlobalModelRegistry().UnregisterClient(a.ID)
|
||||
@@ -947,13 +996,60 @@ func (s *Service) registerModelsForAuth(a *coreauth.Auth) {
|
||||
if key == "" {
|
||||
key = strings.ToLower(strings.TrimSpace(a.Provider))
|
||||
}
|
||||
GlobalModelRegistry().RegisterClient(a.ID, key, applyModelPrefixes(models, a.Prefix, s.cfg != nil && s.cfg.ForceModelPrefix))
|
||||
s.registerResolvedModelsForAuth(a, key, applyModelPrefixes(models, a.Prefix, s.cfg != nil && s.cfg.ForceModelPrefix))
|
||||
return
|
||||
}
|
||||
|
||||
GlobalModelRegistry().UnregisterClient(a.ID)
|
||||
}
|
||||
|
||||
// refreshModelRegistrationForAuth re-applies the latest model registration for
|
||||
// one auth and reconciles any concurrent auth changes that race with the
|
||||
// refresh. Callers are expected to pre-filter provider membership.
|
||||
//
|
||||
// Re-registration is deliberate: registry cooldown/suspension state is treated
|
||||
// as part of the previous registration snapshot and is cleared when the auth is
|
||||
// rebound to the refreshed model catalog.
|
||||
func (s *Service) refreshModelRegistrationForAuth(current *coreauth.Auth) bool {
|
||||
if s == nil || s.coreManager == nil || current == nil || current.ID == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if !current.Disabled {
|
||||
s.ensureExecutorsForAuth(current)
|
||||
}
|
||||
s.registerModelsForAuth(current)
|
||||
|
||||
latest, ok := s.latestAuthForModelRegistration(current.ID)
|
||||
if !ok || latest.Disabled {
|
||||
GlobalModelRegistry().UnregisterClient(current.ID)
|
||||
s.coreManager.RefreshSchedulerEntry(current.ID)
|
||||
return false
|
||||
}
|
||||
|
||||
// Re-apply the latest auth snapshot so concurrent auth updates cannot leave
|
||||
// stale model registrations behind. This may duplicate registration work when
|
||||
// no auth fields changed, but keeps the refresh path simple and correct.
|
||||
s.ensureExecutorsForAuth(latest)
|
||||
s.registerModelsForAuth(latest)
|
||||
s.coreManager.RefreshSchedulerEntry(current.ID)
|
||||
return true
|
||||
}
|
||||
|
||||
// latestAuthForModelRegistration returns the latest auth snapshot regardless of
|
||||
// provider membership. Callers use this after a registration attempt to restore
|
||||
// whichever state currently owns the client ID in the global registry.
|
||||
func (s *Service) latestAuthForModelRegistration(authID string) (*coreauth.Auth, bool) {
|
||||
if s == nil || s.coreManager == nil || authID == "" {
|
||||
return nil, false
|
||||
}
|
||||
auth, ok := s.coreManager.GetByID(authID)
|
||||
if !ok || auth == nil || auth.ID == "" {
|
||||
return nil, false
|
||||
}
|
||||
return auth, true
|
||||
}
|
||||
|
||||
func (s *Service) resolveConfigClaudeKey(auth *coreauth.Auth) *config.ClaudeKey {
|
||||
if auth == nil || s.cfg == nil {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user