@@ -121,6 +121,20 @@ type modelRegistrationTask struct {
121121 run func ()
122122}
123123
124+ type executorRegistrationOptions struct {
125+ includeBaseline bool
126+ includePlugins bool
127+ forceReplaceAuths bool
128+ auths []* coreauth.Auth
129+ }
130+
131+ var registerPluginExecutors = func (host * pluginhost.Host , manager * coreauth.Manager ) {
132+ if host == nil || manager == nil {
133+ return
134+ }
135+ host .RegisterExecutors (manager , registry .GetGlobalRegistry ())
136+ }
137+
124138// RegisterUsagePlugin registers a usage plugin on the global usage manager.
125139// This allows external code to monitor API usage and token consumption.
126140//
@@ -191,8 +205,12 @@ func (s *Service) syncPluginModelRuntime(ctx context.Context) {
191205 ctx = context .Background ()
192206 }
193207 s .pluginHost .RegisterModels (ctx , registry .GetGlobalRegistry ())
194- s .rebindExecutors ()
195- s .pluginHost .RegisterExecutors (s .coreManager , registry .GetGlobalRegistry ())
208+ s .registerAvailableExecutors (ctx , executorRegistrationOptions {
209+ includeBaseline : s .cfg != nil && s .cfg .Home .Enabled ,
210+ includePlugins : true ,
211+ forceReplaceAuths : true ,
212+ auths : s .coreManager .List (),
213+ })
196214 s .refreshPluginModelRegistrations (ctx )
197215 s .coreManager .RefreshSchedulerAll ()
198216}
@@ -809,6 +827,76 @@ func (s *Service) ensureExecutorsForAuth(a *coreauth.Auth) {
809827}
810828
811829func (s * Service ) ensureExecutorsForAuthWithMode (a * coreauth.Auth , forceReplace bool ) {
830+ if a == nil {
831+ return
832+ }
833+ s .registerAvailableExecutors (context .Background (), executorRegistrationOptions {
834+ auths : []* coreauth.Auth {a },
835+ forceReplaceAuths : forceReplace ,
836+ })
837+ }
838+
839+ func (s * Service ) registerAvailableExecutors (ctx context.Context , opts executorRegistrationOptions ) {
840+ if s == nil || s .coreManager == nil {
841+ return
842+ }
843+ if ctx == nil {
844+ ctx = context .Background ()
845+ }
846+ // Keep all Service-owned executor registration paths here so native, Home,
847+ // auth-derived, and plugin executors stay in the same binding order.
848+ if opts .includeBaseline {
849+ s .registerExecutorsForAuths (baselineExecutorAuths (), true )
850+ }
851+ if len (opts .auths ) > 0 {
852+ s .registerExecutorsForAuths (opts .auths , opts .forceReplaceAuths )
853+ }
854+ if opts .includePlugins && s .pluginHost != nil {
855+ registerPluginExecutors (s .pluginHost , s .coreManager )
856+ }
857+ }
858+
859+ func baselineExecutorAuths () []* coreauth.Auth {
860+ providers := []string {
861+ "codex" ,
862+ "claude" ,
863+ "gemini" ,
864+ "vertex" ,
865+ "gemini-cli" ,
866+ "aistudio" ,
867+ "antigravity" ,
868+ "kimi" ,
869+ "xai" ,
870+ "openai-compatibility" ,
871+ }
872+ auths := make ([]* coreauth.Auth , 0 , len (providers ))
873+ for _ , provider := range providers {
874+ auth := & coreauth.Auth {
875+ ID : provider ,
876+ Provider : provider ,
877+ }
878+ if provider == "openai-compatibility" {
879+ auth .Attributes = map [string ]string {"compat_name" : "openai-compatibility" }
880+ }
881+ auths = append (auths , auth )
882+ }
883+ return auths
884+ }
885+
886+ func (s * Service ) registerExecutorsForAuths (auths []* coreauth.Auth , forceReplace bool ) {
887+ reboundCodex := false
888+ for _ , auth := range auths {
889+ if auth != nil && strings .EqualFold (strings .TrimSpace (auth .Provider ), "codex" ) {
890+ if reboundCodex && forceReplace {
891+ continue
892+ }
893+ reboundCodex = true
894+ }
895+ s .registerExecutorForAuth (auth , forceReplace )
896+ }
897+ }
898+
899+ func (s * Service ) registerExecutorForAuth (a * coreauth.Auth , forceReplace bool ) {
812900 if s == nil || s .coreManager == nil || a == nil {
813901 return
814902 }
@@ -1015,24 +1103,6 @@ func (s *Service) tryRegisterPluginModelsForAuth(ctx context.Context, a *coreaut
10151103 return true
10161104}
10171105
1018- // rebindExecutors refreshes provider executors so they observe the latest configuration.
1019- func (s * Service ) rebindExecutors () {
1020- if s == nil || s .coreManager == nil {
1021- return
1022- }
1023- auths := s .coreManager .List ()
1024- reboundCodex := false
1025- for _ , auth := range auths {
1026- if auth != nil && strings .EqualFold (strings .TrimSpace (auth .Provider ), "codex" ) {
1027- if reboundCodex {
1028- continue
1029- }
1030- reboundCodex = true
1031- }
1032- s .ensureExecutorsForAuthWithMode (auth , true )
1033- }
1034- }
1035-
10361106func (s * Service ) applyConfigUpdate (newCfg * config.Config ) {
10371107 if s == nil {
10381108 return
@@ -1117,10 +1187,15 @@ func (s *Service) applyConfigUpdate(newCfg *config.Config) {
11171187 s .coreManager .SetConfig (newCfg )
11181188 s .coreManager .SetOAuthModelAlias (newCfg .OAuthModelAlias )
11191189 }
1120- if newCfg .Home .Enabled {
1121- s .registerHomeExecutors ()
1190+ var auths []* coreauth.Auth
1191+ if s .coreManager != nil {
1192+ auths = s .coreManager .List ()
11221193 }
1123- s .rebindExecutors ()
1194+ s .registerAvailableExecutors (context .Background (), executorRegistrationOptions {
1195+ includeBaseline : newCfg .Home .Enabled ,
1196+ forceReplaceAuths : true ,
1197+ auths : auths ,
1198+ })
11241199 ctx := context .Background ()
11251200 s .registerConfigAPIKeyAuths (ctx , newCfg )
11261201 s .syncPluginRuntime (ctx )
@@ -1178,24 +1253,6 @@ func forceHomeRuntimeConfig(cfg *config.Config) {
11781253 cfg .RemoteManagement .DisableControlPanel = true
11791254}
11801255
1181- func (s * Service ) registerHomeExecutors () {
1182- if s == nil || s .coreManager == nil || s .cfg == nil {
1183- return
1184- }
1185-
1186- // Register baseline executors so home-dispatched auth entries can execute without
1187- // requiring any local auth-dir credentials.
1188- s .coreManager .RegisterExecutor (executor .NewCodexAutoExecutor (s .cfg ))
1189- s .coreManager .RegisterExecutor (executor .NewClaudeExecutor (s .cfg ))
1190- s .coreManager .RegisterExecutor (executor .NewGeminiExecutor (s .cfg ))
1191- s .coreManager .RegisterExecutor (executor .NewGeminiVertexExecutor (s .cfg ))
1192- s .coreManager .RegisterExecutor (executor .NewGeminiCLIExecutor (s .cfg ))
1193- s .coreManager .RegisterExecutor (executor .NewAIStudioExecutor (s .cfg , "" , s .wsGateway ))
1194- s .coreManager .RegisterExecutor (executor .NewAntigravityExecutor (s .cfg ))
1195- s .coreManager .RegisterExecutor (executor .NewKimiExecutor (s .cfg ))
1196- s .coreManager .RegisterExecutor (executor .NewOpenAICompatExecutor ("openai-compatibility" , s .cfg ))
1197- }
1198-
11991256func (s * Service ) applyHomeOverlay (remoteCfg * config.Config ) {
12001257 if s == nil || remoteCfg == nil {
12011258 return
@@ -1416,7 +1473,9 @@ func (s *Service) Run(ctx context.Context) error {
14161473
14171474 s .ensureWebsocketGateway ()
14181475 if homeEnabled {
1419- s .registerHomeExecutors ()
1476+ s .registerAvailableExecutors (ctx , executorRegistrationOptions {
1477+ includeBaseline : true ,
1478+ })
14201479 // Home mode does not expose in-process Redis RESP usage output; usage is forwarded to home instead.
14211480 redisqueue .SetEnabled (true )
14221481 }
@@ -1609,9 +1668,9 @@ func (s *Service) Shutdown(ctx context.Context) error {
16091668 }
16101669 s .pluginHost .ApplyConfig (ctx , & config.Config {})
16111670 s .pluginHost .RegisterModels (ctx , registry .GetGlobalRegistry ())
1612- if s . coreManager != nil {
1613- s . pluginHost . RegisterExecutors ( s . coreManager , registry . GetGlobalRegistry ())
1614- }
1671+ s . registerAvailableExecutors ( ctx , executorRegistrationOptions {
1672+ includePlugins : true ,
1673+ })
16151674 s .pluginHost .RegisterFrontendAuthProviders ()
16161675 s .pluginHost .ShutdownAll ()
16171676 if s .accessManager != nil {
0 commit comments