AI SDK

Plugins

Dynamic plugin system for extending SDK functionality

Plugin System

Dynamically load and execute plugins to extend SDK functionality.

Basic Plugin

type MyPlugin struct{}

func (p *MyPlugin) Name() string {
    return "my-plugin"
}

func (p *MyPlugin) Version() string {
    return "1.0.0"
}

func (p *MyPlugin) Execute(ctx context.Context, input interface{}) (interface{}, error) {
    // Plugin logic here
    return fmt.Sprintf("Processed: %v", input), nil
}

// Register
pluginSystem := sdk.NewPluginSystem(logger, metrics)
pluginSystem.RegisterPlugin(&MyPlugin{})

// Execute
result, err := pluginSystem.ExecutePlugin(ctx, "my-plugin", "input data")

Plugin Interface

type Plugin interface {
    // Plugin metadata
    Name() string
    Version() string
    Description() string
    
    // Lifecycle
    Init(ctx context.Context, config map[string]interface{}) error
    Execute(ctx context.Context, input interface{}) (interface{}, error)
    Cleanup(ctx context.Context) error
    
    // Health check
    HealthCheck(ctx context.Context) error
}

Complete Plugin Example

type TranslationPlugin struct {
    apiKey string
    logger forge.Logger
}

func (p *TranslationPlugin) Name() string {
    return "translator"
}

func (p *TranslationPlugin) Version() string {
    return "1.0.0"
}

func (p *TranslationPlugin) Description() string {
    return "Translates text between languages"
}

func (p *TranslationPlugin) Init(ctx context.Context, config map[string]interface{}) error {
    apiKey, ok := config["api_key"].(string)
    if !ok {
        return fmt.Errorf("api_key required")
    }
    
    p.apiKey = apiKey
    p.logger = config["logger"].(forge.Logger)
    
    return nil
}

func (p *TranslationPlugin) Execute(ctx context.Context, input interface{}) (interface{}, error) {
    req := input.(map[string]interface{})
    text := req["text"].(string)
    targetLang := req["target_lang"].(string)
    
    // Translation logic
    translated, err := p.translate(ctx, text, targetLang)
    if err != nil {
        return nil, err
    }
    
    return map[string]interface{}{
        "original":   text,
        "translated": translated,
        "language":   targetLang,
    }, nil
}

func (p *TranslationPlugin) Cleanup(ctx context.Context) error {
    // Cleanup resources
    return nil
}

func (p *TranslationPlugin) HealthCheck(ctx context.Context) error {
    // Check if service is available
    return nil
}

Plugin Registration

Manual Registration

plugin := &TranslationPlugin{}
pluginSystem.RegisterPlugin(plugin)

With Configuration

err := pluginSystem.RegisterPlugin(&TranslationPlugin{}, map[string]interface{}{
    "api_key": os.Getenv("TRANSLATION_API_KEY"),
    "logger":  logger,
})

Dynamic Loading

// Load plugin from file (Go plugin system)
pluginSystem.LoadPlugin("./plugins/translator.so")

// Or from URL
pluginSystem.LoadPluginFromURL("https://plugins.example.com/translator.so")

Plugin Execution

Simple Execution

result, err := pluginSystem.ExecutePlugin(ctx, "translator", map[string]interface{}{
    "text":        "Hello, world!",
    "target_lang": "es",
})

translation := result.(map[string]interface{})
fmt.Println(translation["translated"])  // "¡Hola, mundo!"

With Timeout

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

result, err := pluginSystem.ExecutePlugin(ctx, "translator", input)

Concurrent Execution

var wg sync.WaitGroup
results := make([]interface{}, len(inputs))

for i, input := range inputs {
    wg.Add(1)
    go func(i int, input interface{}) {
        defer wg.Done()
        result, _ := pluginSystem.ExecutePlugin(ctx, "plugin-name", input)
        results[i] = result
    }(i, input)
}

wg.Wait()

Plugin Discovery

// List all plugins
plugins := pluginSystem.ListPlugins()
for _, plugin := range plugins {
    fmt.Printf("%s v%s: %s\n", 
        plugin.Name(), plugin.Version(), plugin.Description())
}

// Get specific plugin
plugin, err := pluginSystem.GetPlugin("translator")

// Check if plugin exists
if pluginSystem.HasPlugin("translator") {
    // Use plugin
}

Plugin Lifecycle

// Initialize plugin
err := pluginSystem.InitPlugin(ctx, "translator", config)

// Execute plugin
result, err := pluginSystem.ExecutePlugin(ctx, "translator", input)

// Health check
err = pluginSystem.HealthCheckPlugin(ctx, "translator")

// Unload plugin
err = pluginSystem.UnregisterPlugin("translator")

Real-World Examples

Content Moderation Plugin

type ModerationPlugin struct {
    threshold float64
}

func (p *ModerationPlugin) Name() string {
    return "content-moderator"
}

func (p *ModerationPlugin) Execute(ctx context.Context, input interface{}) (interface{}, error) {
    text := input.(string)
    
    // Check for inappropriate content
    score := p.moderateContent(text)
    
    return map[string]interface{}{
        "safe":    score < p.threshold,
        "score":   score,
        "flagged": score >= p.threshold,
    }, nil
}

Data Enrichment Plugin

type EnrichmentPlugin struct {
    database Database
}

func (p *EnrichmentPlugin) Execute(ctx context.Context, input interface{}) (interface{}, error) {
    userID := input.(string)
    
    // Fetch additional data
    profile, _ := p.database.GetUserProfile(ctx, userID)
    preferences, _ := p.database.GetPreferences(ctx, userID)
    history, _ := p.database.GetHistory(ctx, userID)
    
    return map[string]interface{}{
        "profile":     profile,
        "preferences": preferences,
        "history":     history,
    }, nil
}

Custom Formatter Plugin

type FormatterPlugin struct{}

func (p *FormatterPlugin) Execute(ctx context.Context, input interface{}) (interface{}, error) {
    data := input.(map[string]interface{})
    format := data["format"].(string)
    content := data["content"].(string)
    
    switch format {
    case "markdown":
        return p.toMarkdown(content), nil
    case "html":
        return p.toHTML(content), nil
    case "json":
        return p.toJSON(content), nil
    default:
        return content, nil
    }
}

Plugin Chains

Execute multiple plugins in sequence:

chain := pluginSystem.CreateChain(
    "moderator",
    "enricher",
    "formatter",
)

result, err := chain.Execute(ctx, input)

Plugin Versioning

// Register multiple versions
pluginSystem.RegisterPlugin(&TranslatorV1{})
pluginSystem.RegisterPlugin(&TranslatorV2{})

// Execute specific version
result, _ := pluginSystem.ExecutePlugin(ctx, "translator@1.0.0", input)

// Execute latest
result, _ := pluginSystem.ExecutePlugin(ctx, "translator", input)

Plugin Marketplace

marketplace := sdk.NewPluginMarketplace(
    "https://plugins.example.com",
    logger,
    metrics,
)

// Browse plugins
plugins, _ := marketplace.ListAvailable()

// Install plugin
err := marketplace.Install("translator", "1.0.0")

// Update plugin
err = marketplace.Update("translator", "2.0.0")

// Uninstall plugin
err = marketplace.Uninstall("translator")

Plugin Security

Sandboxing

pluginSystem := sdk.NewPluginSystem(logger, metrics, sdk.PluginConfig{
    EnableSandbox:  true,
    MaxMemory:      100 * 1024 * 1024,  // 100MB
    MaxCPU:         0.5,                 // 50% of one core
    Timeout:        30 * time.Second,
    NetworkAccess:  false,               // No network
})

Permission System

plugin := &MyPlugin{}
pluginSystem.RegisterPlugin(plugin, sdk.PluginPermissions{
    FileAccess:     sdk.ReadOnly,
    NetworkAccess:  sdk.AllowHTTPS,
    DatabaseAccess: sdk.NoAccess,
})

Monitoring

// Plugin metrics
stats := pluginSystem.GetStats("translator")
fmt.Printf("Executions: %d\n", stats.TotalExecutions)
fmt.Printf("Failures: %d\n", stats.Failures)
fmt.Printf("Avg duration: %v\n", stats.AvgDuration)

// Health monitoring
go func() {
    ticker := time.NewTicker(1 * time.Minute)
    for range ticker.C {
        for _, name := range pluginSystem.ListPluginNames() {
            if err := pluginSystem.HealthCheckPlugin(ctx, name); err != nil {
                logger.Error("plugin unhealthy", "plugin", name, "error", err)
            }
        }
    }
}()

Best Practices

Error Handling

func (p *MyPlugin) Execute(ctx context.Context, input interface{}) (interface{}, error) {
    // Validate input
    if input == nil {
        return nil, fmt.Errorf("input cannot be nil")
    }
    
    // Type assertion with check
    data, ok := input.(map[string]interface{})
    if !ok {
        return nil, fmt.Errorf("input must be map[string]interface{}")
    }
    
    // Execute with error handling
    result, err := p.process(data)
    if err != nil {
        return nil, fmt.Errorf("processing failed: %w", err)
    }
    
    return result, nil
}

Resource Cleanup

func (p *MyPlugin) Cleanup(ctx context.Context) error {
    // Close connections
    if p.conn != nil {
        p.conn.Close()
    }
    
    // Release resources
    if p.cache != nil {
        p.cache.Clear()
    }
    
    return nil
}

Graceful Degradation

func (p *MyPlugin) Execute(ctx context.Context, input interface{}) (interface{}, error) {
    result, err := p.tryExecute(ctx, input)
    if err != nil {
        // Log error but return partial result
        p.logger.Error("plugin failed, returning partial result", "error", err)
        return p.getPartialResult(input), nil
    }
    
    return result, nil
}

Next Steps

How is this guide?

Last updated on