114 lines
4.9 KiB
Go
114 lines
4.9 KiB
Go
package plugins
|
|
|
|
import (
|
|
"context"
|
|
"plugin"
|
|
|
|
"github.com/maximhq/bifrost/core/schemas"
|
|
)
|
|
|
|
// DynamicPlugin is a generic dynamic plugin that can implement any combination of plugin interfaces
|
|
// It uses optional function pointers - nil pointers indicate the interface is not implemented
|
|
type DynamicPlugin struct {
|
|
Enabled bool
|
|
Path string
|
|
Config any
|
|
|
|
filename string
|
|
plugin *plugin.Plugin
|
|
|
|
// BasePlugin (required)
|
|
getName func() string
|
|
cleanup func() error
|
|
|
|
// HTTPTransportPlugin (optional)
|
|
httpTransportPreHook func(ctx *schemas.BifrostContext, req *schemas.HTTPRequest) (*schemas.HTTPResponse, error)
|
|
httpTransportPostHook func(ctx *schemas.BifrostContext, req *schemas.HTTPRequest, resp *schemas.HTTPResponse) error
|
|
httpTransportStreamChunkHook func(ctx *schemas.BifrostContext, req *schemas.HTTPRequest, stream *schemas.BifrostStreamChunk) (*schemas.BifrostStreamChunk, error)
|
|
|
|
// LLMPlugin (optional)
|
|
preLLMHook func(ctx *schemas.BifrostContext, req *schemas.BifrostRequest) (*schemas.BifrostRequest, *schemas.LLMPluginShortCircuit, error)
|
|
postLLMHook func(ctx *schemas.BifrostContext, resp *schemas.BifrostResponse, bifrostErr *schemas.BifrostError) (*schemas.BifrostResponse, *schemas.BifrostError, error)
|
|
|
|
// MCPPlugin (optional)
|
|
preMCPHook func(ctx *schemas.BifrostContext, req *schemas.BifrostMCPRequest) (*schemas.BifrostMCPRequest, *schemas.MCPPluginShortCircuit, error)
|
|
postMCPHook func(ctx *schemas.BifrostContext, resp *schemas.BifrostMCPResponse, bifrostErr *schemas.BifrostError) (*schemas.BifrostMCPResponse, *schemas.BifrostError, error)
|
|
|
|
// ObservabilityPlugin (optional)
|
|
inject func(ctx context.Context, trace *schemas.Trace) error
|
|
}
|
|
|
|
// GetName returns the name of the plugin (BasePlugin interface)
|
|
func (dp *DynamicPlugin) GetName() string {
|
|
return dp.getName()
|
|
}
|
|
|
|
// Cleanup is invoked by core/bifrost.go during plugin unload, reload, and shutdown (BasePlugin interface)
|
|
func (dp *DynamicPlugin) Cleanup() error {
|
|
return dp.cleanup()
|
|
}
|
|
|
|
// HTTPTransportPreHook intercepts HTTP requests at the transport layer before entering Bifrost core (HTTPTransportPlugin interface)
|
|
func (dp *DynamicPlugin) HTTPTransportPreHook(ctx *schemas.BifrostContext, req *schemas.HTTPRequest) (*schemas.HTTPResponse, error) {
|
|
if dp.httpTransportPreHook == nil {
|
|
return nil, nil // No-op if not implemented
|
|
}
|
|
return dp.httpTransportPreHook(ctx, req)
|
|
}
|
|
|
|
// HTTPTransportPostHook intercepts HTTP responses at the transport layer after exiting Bifrost core (HTTPTransportPlugin interface)
|
|
func (dp *DynamicPlugin) HTTPTransportPostHook(ctx *schemas.BifrostContext, req *schemas.HTTPRequest, resp *schemas.HTTPResponse) error {
|
|
if dp.httpTransportPostHook == nil {
|
|
return nil // No-op if not implemented
|
|
}
|
|
return dp.httpTransportPostHook(ctx, req, resp)
|
|
}
|
|
|
|
// HTTPTransportStreamChunkHook intercepts streaming chunks before they are written to the client
|
|
func (dp *DynamicPlugin) HTTPTransportStreamChunkHook(ctx *schemas.BifrostContext, req *schemas.HTTPRequest, stream *schemas.BifrostStreamChunk) (*schemas.BifrostStreamChunk, error) {
|
|
if dp.httpTransportStreamChunkHook == nil {
|
|
return stream, nil // No-op if not implemented
|
|
}
|
|
return dp.httpTransportStreamChunkHook(ctx, req, stream)
|
|
}
|
|
|
|
// PreLLMHook is invoked before LLM provider calls (LLMPlugin interface)
|
|
func (dp *DynamicPlugin) PreLLMHook(ctx *schemas.BifrostContext, req *schemas.BifrostRequest) (*schemas.BifrostRequest, *schemas.LLMPluginShortCircuit, error) {
|
|
if dp.preLLMHook == nil {
|
|
return req, nil, nil // No-op if not implemented
|
|
}
|
|
return dp.preLLMHook(ctx, req)
|
|
}
|
|
|
|
// PostLLMHook is invoked after LLM provider calls (LLMPlugin interface)
|
|
func (dp *DynamicPlugin) PostLLMHook(ctx *schemas.BifrostContext, resp *schemas.BifrostResponse, bifrostErr *schemas.BifrostError) (*schemas.BifrostResponse, *schemas.BifrostError, error) {
|
|
if dp.postLLMHook == nil {
|
|
return resp, bifrostErr, nil // No-op if not implemented
|
|
}
|
|
return dp.postLLMHook(ctx, resp, bifrostErr)
|
|
}
|
|
|
|
// PreMCPHook is invoked before MCP calls (MCPPlugin interface)
|
|
func (dp *DynamicPlugin) PreMCPHook(ctx *schemas.BifrostContext, req *schemas.BifrostMCPRequest) (*schemas.BifrostMCPRequest, *schemas.MCPPluginShortCircuit, error) {
|
|
if dp.preMCPHook == nil {
|
|
return req, nil, nil // No-op if not implemented
|
|
}
|
|
return dp.preMCPHook(ctx, req)
|
|
}
|
|
|
|
// PostMCPHook is invoked after MCP calls (MCPPlugin interface)
|
|
func (dp *DynamicPlugin) PostMCPHook(ctx *schemas.BifrostContext, resp *schemas.BifrostMCPResponse, bifrostErr *schemas.BifrostError) (*schemas.BifrostMCPResponse, *schemas.BifrostError, error) {
|
|
if dp.postMCPHook == nil {
|
|
return resp, bifrostErr, nil // No-op if not implemented
|
|
}
|
|
return dp.postMCPHook(ctx, resp, bifrostErr)
|
|
}
|
|
|
|
// Inject receives completed traces for observability backends (ObservabilityPlugin interface)
|
|
func (dp *DynamicPlugin) Inject(ctx context.Context, trace *schemas.Trace) error {
|
|
if dp.inject == nil {
|
|
return nil // No-op if not implemented
|
|
}
|
|
return dp.inject(ctx, trace)
|
|
}
|