Something went wrong. Try again.
sloproxy
Something went wrong. Try again.
11 kB · 352 lines
Go
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353package pluginhost
import ( "context"
internalconfig "github.com/router-for-me/CLIProxyAPI/v7/internal/config" internalpluginhost "github.com/router-for-me/CLIProxyAPI/v7/internal/pluginhost" internalregistry "github.com/router-for-me/CLIProxyAPI/v7/internal/registry" coreauth "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/auth" "github.com/router-for-me/CLIProxyAPI/v7/sdk/pluginapi" "gopkg.in/yaml.v3")
// ModelInfo describes a plugin-provided model using public plugin SDK types.type ModelInfo = pluginapi.ModelInfo
// ThinkingSupport describes plugin-provided thinking controls.type ThinkingSupport = pluginapi.ThinkingSupport
// OAuthModelAlias defines a model ID alias for OAuth/file-backed auth channels.type OAuthModelAlias struct { Name string Alias string Fork bool}
// RuntimeConfig is the public plugin host configuration used by embedders.type RuntimeConfig struct { Enabled bool Dir string AuthDir string ProxyURL string ForceModelPrefix bool OAuthModelAlias map[string][]OAuthModelAlias OAuthExcludedModels map[string][]string Configs map[string]PluginInstanceConfig}
// PluginInstanceConfig stores host-owned plugin settings and the original plugin YAML subtree.type PluginInstanceConfig struct { Enabled *bool Priority int Raw yaml.Node}
// AuthModelResult is the public result for per-auth model discovery.type AuthModelResult struct { Provider string Models []ModelInfo Auth *coreauth.Auth Handled bool Err error}
// RegisteredPluginInfo describes a plugin active in the current host snapshot.type RegisteredPluginInfo = internalpluginhost.RegisteredPluginInfo
// RegisteredPluginMenu describes a plugin-owned resource menu entry.type RegisteredPluginMenu = internalpluginhost.RegisteredPluginMenu
// Host wraps the internal plugin host behind a public SDK surface.type Host struct { inner *internalpluginhost.Host}
// New creates a plugin host.func New() *Host { return &Host{inner: internalpluginhost.New()}}
// ApplyConfig applies plugin runtime configuration.func (h *Host) ApplyConfig(ctx context.Context, cfg RuntimeConfig) { if h == nil || h.inner == nil { return } internalCfg := runtimeConfigToInternalConfig(cfg) h.inner.ApplyConfig(ctx, internalCfg)}
// ShutdownAll unloads every active plugin.func (h *Host) ShutdownAll() { h.ShutdownAllContext(context.Background())}
// ShutdownAllContext detaches every active plugin and bounds waiting for active calls by ctx.func (h *Host) ShutdownAllContext(ctx context.Context) { if h == nil || h.inner == nil { return } h.inner.ShutdownAllContext(ctx)}
// PluginBusy reports whether a plugin dynamic library is loaded or being loaded.func (h *Host) PluginBusy(id string) bool { return h != nil && h.inner != nil && h.inner.PluginBusy(id)}
// UnloadPlugin removes one plugin from the active runtime and closes its dynamic library.func (h *Host) UnloadPlugin(id string) bool { return h.UnloadPluginContext(context.Background(), id)}
// UnloadPluginContext detaches one plugin and bounds waiting for active calls by ctx.func (h *Host) UnloadPluginContext(ctx context.Context, id string) bool { if h == nil || h.inner == nil { return false } return h.inner.UnloadPluginContext(ctx, id)}
// ParseAuth lets plugin auth providers parse a credential payload.func (h *Host) ParseAuth(ctx context.Context, req pluginapi.AuthParseRequest) (*coreauth.Auth, bool, error) { if h == nil || h.inner == nil { return nil, false, nil } return h.inner.ParseAuth(ctx, req)}
// ParseAuths lets plugin auth providers expand one credential payload into multiple auth records.func (h *Host) ParseAuths(ctx context.Context, req pluginapi.AuthParseRequest) ([]*coreauth.Auth, bool, error) { if h == nil || h.inner == nil { return nil, false, nil } return h.inner.ParseAuths(ctx, req)}
// ModelsForAuth lets plugin model providers discover auth-bound models.func (h *Host) ModelsForAuth(ctx context.Context, auth *coreauth.Auth) AuthModelResult { if h == nil || h.inner == nil { return AuthModelResult{} } result := h.inner.ModelsForAuth(ctx, auth) return AuthModelResult{ Provider: result.Provider, Models: registryModelsToPluginModels(result.Models), Auth: result.Auth, Handled: result.Handled, Err: result.Err, }}
// ModelsForProvider returns static models registered for a provider by plugins.func (h *Host) ModelsForProvider(provider string) []ModelInfo { if h == nil || h.inner == nil { return nil } return registryModelsToPluginModels(h.inner.ModelsForProvider(provider))}
// RefreshAuth lets plugin auth providers refresh a credential.func (h *Host) RefreshAuth(ctx context.Context, auth *coreauth.Auth) (*coreauth.Auth, bool, error) { if h == nil || h.inner == nil { return nil, false, nil } return h.inner.RefreshAuth(ctx, auth)}
// HasAuthProvider reports whether an active plugin handles provider auth for provider.func (h *Host) HasAuthProvider(provider string) bool { return h != nil && h.inner != nil && h.inner.HasAuthProvider(provider)}
// StartLogin starts a provider login flow through an active auth-provider plugin.func (h *Host) StartLogin(ctx context.Context, provider string, baseURL string) (pluginapi.AuthLoginStartResponse, bool, error) { if h == nil || h.inner == nil { return pluginapi.AuthLoginStartResponse{}, false, nil } return h.inner.StartLogin(ctx, provider, baseURL)}
// PollLogin polls a provider login flow through an active auth-provider plugin.func (h *Host) PollLogin(ctx context.Context, provider, state string, metadata ...map[string]any) (pluginapi.AuthLoginPollResponse, bool, error) { if h == nil || h.inner == nil { return pluginapi.AuthLoginPollResponse{}, false, nil } return h.inner.PollLogin(ctx, provider, state, metadata...)}
// AuthDataToCoreAuth converts plugin auth data into a host auth record.func (h *Host) AuthDataToCoreAuth(data pluginapi.AuthData, path, fileName string) *coreauth.Auth { if h == nil || h.inner == nil { return nil } return h.inner.AuthDataToCoreAuth(data, path, fileName)}
// PickAuth lets a scheduler plugin choose an auth candidate.func (h *Host) PickAuth(ctx context.Context, req pluginapi.SchedulerPickRequest) (pluginapi.SchedulerPickResponse, bool, error) { if h == nil || h.inner == nil { return pluginapi.SchedulerPickResponse{}, false, nil } return h.inner.PickAuth(ctx, req)}
// HasScheduler reports whether any active plugin provides a scheduler.func (h *Host) HasScheduler() bool { return h != nil && h.inner != nil && h.inner.HasScheduler()}
// RegisteredPlugins returns active plugin metadata from the current runtime snapshot.func (h *Host) RegisteredPlugins() []RegisteredPluginInfo { if h == nil || h.inner == nil { return nil } return h.inner.RegisteredPlugins()}
func runtimeConfigToInternalConfig(cfg RuntimeConfig) *internalconfig.Config { out := &internalconfig.Config{ SDKConfig: internalconfig.SDKConfig{ ProxyURL: cfg.ProxyURL, ForceModelPrefix: cfg.ForceModelPrefix, }, AuthDir: cfg.AuthDir, OAuthExcludedModels: cloneStringSliceMap(cfg.OAuthExcludedModels), OAuthModelAlias: oauthModelAliasToInternal(cfg.OAuthModelAlias), Plugins: internalconfig.PluginsConfig{ Enabled: cfg.Enabled, Dir: cfg.Dir, Configs: pluginConfigsToInternal(cfg.Configs), }, } out.NormalizePluginsConfig() out.SanitizeOAuthModelAlias() return out}
func pluginConfigsToInternal(in map[string]PluginInstanceConfig) map[string]internalconfig.PluginInstanceConfig { if len(in) == 0 { return nil } out := make(map[string]internalconfig.PluginInstanceConfig, len(in)) for id, item := range in { out[id] = internalconfig.PluginInstanceConfig{ Enabled: item.Enabled, Priority: item.Priority, Raw: *deepCopyYAMLNode(&item.Raw), } } return out}
func oauthModelAliasToInternal(in map[string][]OAuthModelAlias) map[string][]internalconfig.OAuthModelAlias { if len(in) == 0 { return nil } out := make(map[string][]internalconfig.OAuthModelAlias, len(in)) for provider, aliases := range in { if len(aliases) == 0 { continue } items := make([]internalconfig.OAuthModelAlias, 0, len(aliases)) for _, alias := range aliases { items = append(items, internalconfig.OAuthModelAlias{ Name: alias.Name, Alias: alias.Alias, Fork: alias.Fork, }) } out[provider] = items } if len(out) == 0 { return nil } return out}
func registryModelsToPluginModels(models []*internalregistry.ModelInfo) []ModelInfo { if len(models) == 0 { return nil } out := make([]ModelInfo, 0, len(models)) for _, model := range models { if model == nil { continue } out = append(out, registryModelToPluginModel(model)) } return out}
func registryModelToPluginModel(model *internalregistry.ModelInfo) ModelInfo { if model == nil { return ModelInfo{} } return ModelInfo{ ID: model.ID, Object: model.Object, Created: model.Created, OwnedBy: model.OwnedBy, Type: model.Type, DisplayName: model.DisplayName, Name: model.Name, Version: model.Version, Description: model.Description, InputTokenLimit: int64(model.InputTokenLimit), OutputTokenLimit: int64(model.OutputTokenLimit), SupportedGenerationMethods: cloneStringSlice(model.SupportedGenerationMethods), ContextLength: int64(model.ContextLength), MaxCompletionTokens: int64(model.MaxCompletionTokens), SupportedParameters: cloneStringSlice(model.SupportedParameters), SupportedInputModalities: cloneStringSlice(model.SupportedInputModalities), SupportedOutputModalities: cloneStringSlice(model.SupportedOutputModalities), Thinking: thinkingSupportToPlugin(model.Thinking), UserDefined: model.UserDefined, }}
func thinkingSupportToPlugin(thinking *internalregistry.ThinkingSupport) *ThinkingSupport { if thinking == nil { return nil } return &ThinkingSupport{ Min: thinking.Min, Max: thinking.Max, ZeroAllowed: thinking.ZeroAllowed, DynamicAllowed: thinking.DynamicAllowed, Levels: cloneStringSlice(thinking.Levels), }}
func cloneStringSlice(in []string) []string { if len(in) == 0 { return nil } return append([]string(nil), in...)}
func cloneStringSliceMap(in map[string][]string) map[string][]string { if len(in) == 0 { return nil } out := make(map[string][]string, len(in)) for key, values := range in { out[key] = cloneStringSlice(values) } return out}
func deepCopyYAMLNode(node *yaml.Node) *yaml.Node { if node == nil { return &yaml.Node{} } copyNode := *node if len(node.Content) > 0 { copyNode.Content = make([]*yaml.Node, 0, len(node.Content)) for _, child := range node.Content { copyNode.Content = append(copyNode.Content, deepCopyYAMLNode(child)) } } return ©Node}