717ad65b05
- Plugin SDK: Plugin/Tool/ComplexTool/HostAPI 标准化接口 - Plugin Manager: 插件生命周期管理 (Install/Enable/Disable/Uninstall/Reload) - Tool Registry: 聚合工具注册表 (Register/Execute/Dispatch) - 13 个内置插件: 将原有硬编码工具迁移为标准插件格式 - REST API: 11 个端点 (net/http, 零外部依赖) - ai-core 集成: PluginManagerClient 替代本地工具调用 - plugin.json 元数据: 每个插件含完整 author/version/category/permissions Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
86 lines
1.9 KiB
Go
86 lines
1.9 KiB
Go
package manager
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/yourname/cyrene-ai/plugin-manager/internal/sdk"
|
|
)
|
|
|
|
// ToolRegistry aggregates tool definitions from all running plugins and dispatches execution.
|
|
type ToolRegistry struct {
|
|
mu sync.RWMutex
|
|
tools map[string]sdk.Tool // tool ID -> Tool
|
|
}
|
|
|
|
func NewToolRegistry() *ToolRegistry {
|
|
return &ToolRegistry{tools: make(map[string]sdk.Tool)}
|
|
}
|
|
|
|
func (r *ToolRegistry) Register(tool sdk.Tool) error {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
id := tool.Definition().ID
|
|
if _, exists := r.tools[id]; exists {
|
|
return fmt.Errorf("tool %q already registered", id)
|
|
}
|
|
r.tools[id] = tool
|
|
return nil
|
|
}
|
|
|
|
func (r *ToolRegistry) Unregister(toolID string) {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
delete(r.tools, toolID)
|
|
}
|
|
|
|
func (r *ToolRegistry) Get(toolID string) (sdk.Tool, bool) {
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
t, ok := r.tools[toolID]
|
|
return t, ok
|
|
}
|
|
|
|
func (r *ToolRegistry) List() []sdk.Tool {
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
result := make([]sdk.Tool, 0, len(r.tools))
|
|
for _, t := range r.tools {
|
|
result = append(result, t)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (r *ToolRegistry) Definitions() []sdk.ToolDefinition {
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
defs := make([]sdk.ToolDefinition, 0, len(r.tools))
|
|
for _, t := range r.tools {
|
|
defs = append(defs, t.Definition())
|
|
}
|
|
return defs
|
|
}
|
|
|
|
func (r *ToolRegistry) Execute(ctx context.Context, toolID string, args map[string]interface{}) (*sdk.ToolResult, error) {
|
|
r.mu.RLock()
|
|
tool, ok := r.tools[toolID]
|
|
r.mu.RUnlock()
|
|
if !ok {
|
|
return nil, fmt.Errorf("tool %q not found", toolID)
|
|
}
|
|
if err := tool.Validate(args); err != nil {
|
|
return &sdk.ToolResult{Success: false, Error: err.Error()}, nil
|
|
}
|
|
return tool.Execute(ctx, args)
|
|
}
|
|
|
|
// UnregisterAll removes all tools matching a prefix (plugin's tools).
|
|
func (r *ToolRegistry) UnregisterAll(toolIDs []string) {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
for _, id := range toolIDs {
|
|
delete(r.tools, id)
|
|
}
|
|
}
|