163 lines
5.4 KiB
Go
163 lines
5.4 KiB
Go
// Package plugins provides a framework for dynamically loading and managing plugins
|
|
package plugins
|
|
|
|
import (
|
|
"github.com/maximhq/bifrost/core/schemas"
|
|
)
|
|
|
|
// PluginConfig is the generic configuration for any plugin type
|
|
// Plugin types are automatically detected based on implemented interfaces
|
|
type PluginConfig struct {
|
|
Path string `json:"path"`
|
|
Name string `json:"name"`
|
|
Enabled bool `json:"enabled"`
|
|
Config any `json:"config,omitempty"`
|
|
}
|
|
|
|
// Config is the configuration for the plugins framework
|
|
type Config struct {
|
|
// Plugins is the unified configuration for all plugin types
|
|
Plugins []PluginConfig `json:"plugins"`
|
|
}
|
|
|
|
// AsLLMPlugin checks if a base plugin implements LLMPlugin and actually has LLM hooks.
|
|
// For DynamicPlugin, it checks if the hook function pointers are not nil.
|
|
// Returns nil if the plugin does not implement the interface or has no LLM hooks.
|
|
func AsLLMPlugin(plugin schemas.BasePlugin) schemas.LLMPlugin {
|
|
// Check if it's a DynamicPlugin first
|
|
if dp, ok := plugin.(*DynamicPlugin); ok {
|
|
// Only return as LLMPlugin if it actually has LLM hooks
|
|
if dp.preLLMHook != nil || dp.postLLMHook != nil {
|
|
return dp
|
|
}
|
|
return nil
|
|
}
|
|
// For non-DynamicPlugin types, use normal type assertion
|
|
if llmPlugin, ok := plugin.(schemas.LLMPlugin); ok {
|
|
return llmPlugin
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AsMCPPlugin checks if a base plugin implements MCPPlugin and actually has MCP hooks.
|
|
// For DynamicPlugin, it checks if the hook function pointers are not nil.
|
|
// Returns nil if the plugin does not implement the interface or has no MCP hooks.
|
|
func AsMCPPlugin(plugin schemas.BasePlugin) schemas.MCPPlugin {
|
|
// Check if it's a DynamicPlugin first
|
|
if dp, ok := plugin.(*DynamicPlugin); ok {
|
|
// Only return as MCPPlugin if it actually has MCP hooks
|
|
if dp.preMCPHook != nil || dp.postMCPHook != nil {
|
|
return dp
|
|
}
|
|
return nil
|
|
}
|
|
// For non-DynamicPlugin types, use normal type assertion
|
|
if mcpPlugin, ok := plugin.(schemas.MCPPlugin); ok {
|
|
return mcpPlugin
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AsHTTPTransportPlugin checks if a base plugin implements HTTPTransportPlugin and actually has HTTP transport hooks.
|
|
// For DynamicPlugin, it checks if the hook function pointers are not nil.
|
|
// Returns nil if the plugin does not implement the interface or has no HTTP transport hooks.
|
|
func AsHTTPTransportPlugin(plugin schemas.BasePlugin) schemas.HTTPTransportPlugin {
|
|
// Check if it's a DynamicPlugin first
|
|
if dp, ok := plugin.(*DynamicPlugin); ok {
|
|
// Only return as HTTPTransportPlugin if it actually has HTTP transport hooks
|
|
if dp.httpTransportPreHook != nil || dp.httpTransportPostHook != nil {
|
|
return dp
|
|
}
|
|
return nil
|
|
}
|
|
// For non-DynamicPlugin types, use normal type assertion
|
|
if httpPlugin, ok := plugin.(schemas.HTTPTransportPlugin); ok {
|
|
return httpPlugin
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AsObservabilityPlugin checks if a base plugin implements ObservabilityPlugin and actually has observability hooks.
|
|
// For DynamicPlugin, it checks if the hook function pointer is not nil.
|
|
// Returns nil if the plugin does not implement the interface or has no observability hooks.
|
|
func AsObservabilityPlugin(plugin schemas.BasePlugin) schemas.ObservabilityPlugin {
|
|
// Check if it's a DynamicPlugin first
|
|
if dp, ok := plugin.(*DynamicPlugin); ok {
|
|
// Only return as ObservabilityPlugin if it actually has the Inject hook
|
|
if dp.inject != nil {
|
|
return dp
|
|
}
|
|
return nil
|
|
}
|
|
// For non-DynamicPlugin types, use normal type assertion
|
|
if obsPlugin, ok := plugin.(schemas.ObservabilityPlugin); ok {
|
|
return obsPlugin
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// LoadPlugins loads all plugins from the config
|
|
func LoadPlugins(loader PluginLoader, config *Config) ([]schemas.BasePlugin, error) {
|
|
plugins := []schemas.BasePlugin{}
|
|
if config == nil {
|
|
return plugins, nil
|
|
}
|
|
|
|
for _, pc := range config.Plugins {
|
|
if !pc.Enabled {
|
|
continue
|
|
}
|
|
plugin, err := loader.LoadPlugin(pc.Path, pc.Config)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
plugins = append(plugins, plugin)
|
|
}
|
|
|
|
return plugins, nil
|
|
}
|
|
|
|
// FilterLLMPlugins filters a list of BasePlugins to only include those implementing LLMPlugin
|
|
func FilterLLMPlugins(plugins []schemas.BasePlugin) []schemas.LLMPlugin {
|
|
result := []schemas.LLMPlugin{}
|
|
for _, p := range plugins {
|
|
if llmPlugin := AsLLMPlugin(p); llmPlugin != nil {
|
|
result = append(result, llmPlugin)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// FilterMCPPlugins filters a list of BasePlugins to only include those implementing MCPPlugin
|
|
func FilterMCPPlugins(plugins []schemas.BasePlugin) []schemas.MCPPlugin {
|
|
result := []schemas.MCPPlugin{}
|
|
for _, p := range plugins {
|
|
if mcpPlugin := AsMCPPlugin(p); mcpPlugin != nil {
|
|
result = append(result, mcpPlugin)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// FilterHTTPTransportPlugins filters a list of BasePlugins to only include those implementing HTTPTransportPlugin
|
|
func FilterHTTPTransportPlugins(plugins []schemas.BasePlugin) []schemas.HTTPTransportPlugin {
|
|
result := []schemas.HTTPTransportPlugin{}
|
|
for _, p := range plugins {
|
|
if httpPlugin := AsHTTPTransportPlugin(p); httpPlugin != nil {
|
|
result = append(result, httpPlugin)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// FilterObservabilityPlugins filters a list of BasePlugins to only include those implementing ObservabilityPlugin
|
|
func FilterObservabilityPlugins(plugins []schemas.BasePlugin) []schemas.ObservabilityPlugin {
|
|
result := []schemas.ObservabilityPlugin{}
|
|
for _, p := range plugins {
|
|
if obsPlugin := AsObservabilityPlugin(p); obsPlugin != nil {
|
|
result = append(result, obsPlugin)
|
|
}
|
|
}
|
|
return result
|
|
}
|