feat: Phase 3 插件与工具系统 — Plugin SDK + Plugin Manager + 13内置插件 (40文件, 3293行)

- 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>
This commit is contained in:
2026-05-23 15:50:19 +08:00
parent 87214b9441
commit 717ad65b05
42 changed files with 3797 additions and 0 deletions
@@ -0,0 +1,128 @@
package tools
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"time"
)
// PluginManagerClient calls the plugin-manager service.
type PluginManagerClient struct {
baseURL string
httpClient *http.Client
}
// PMToolDefinition matches the plugin-manager tool definition format.
type PMToolDefinition struct {
ID string `json:"id"`
Name string `json:"name"`
DisplayName string `json:"displayName"`
Description string `json:"description"`
Category string `json:"category"`
Complexity string `json:"complexity"`
Parameters map[string]interface{} `json:"parameters"`
DangerLevel string `json:"danger_level,omitempty"`
}
// PMToolResult matches the plugin-manager execution result.
type PMToolResult struct {
ToolName string `json:"tool_name"`
Success bool `json:"success"`
Output string `json:"output,omitempty"`
Error string `json:"error,omitempty"`
}
// PMPluginInfo matches plugin-manager plugin info.
type PMPluginInfo struct {
Name string `json:"name"`
Version string `json:"version"`
Status string `json:"status"`
Enabled bool `json:"enabled"`
Tools []string `json:"tools"`
}
func NewPluginManagerClient(baseURL string) *PluginManagerClient {
return &PluginManagerClient{
baseURL: baseURL,
httpClient: &http.Client{Timeout: 10 * time.Second},
}
}
// GetToolDefinitions fetches all tool definitions from plugin-manager.
func (c *PluginManagerClient) GetToolDefinitions(ctx context.Context) ([]PMToolDefinition, error) {
req, _ := http.NewRequestWithContext(ctx, "GET", c.baseURL+"/api/v1/tools", nil)
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("plugin-manager GetToolDefinitions: %w", err)
}
defer resp.Body.Close()
var body struct {
Tools []PMToolDefinition `json:"tools"`
}
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
return nil, fmt.Errorf("plugin-manager decode tools: %w", err)
}
return body.Tools, nil
}
// ExecuteTool calls a tool on plugin-manager by ID.
func (c *PluginManagerClient) ExecuteTool(ctx context.Context, toolID string, args map[string]interface{}) (*PMToolResult, error) {
body, _ := json.Marshal(map[string]interface{}{"arguments": args})
url := fmt.Sprintf("%s/api/v1/tools/%s/execute", c.baseURL, toolID)
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(body))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("plugin-manager ExecuteTool: %w", err)
}
defer resp.Body.Close()
var result PMToolResult
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, fmt.Errorf("plugin-manager decode result: %w", err)
}
return &result, nil
}
// ListPlugins fetches all installed plugins from plugin-manager.
func (c *PluginManagerClient) ListPlugins(ctx context.Context) ([]PMPluginInfo, error) {
req, _ := http.NewRequestWithContext(ctx, "GET", c.baseURL+"/api/v1/plugins", nil)
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var body struct {
Plugins []PMPluginInfo `json:"plugins"`
}
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
return nil, err
}
return body.Plugins, nil
}
// AdaptDefinitions converts PM tool definitions to ai-core ToolDefinition format.
func (c *PluginManagerClient) AdaptDefinitions(ctx context.Context) ([]ToolDefinition, error) {
pmDefs, err := c.GetToolDefinitions(ctx)
if err != nil {
return nil, err
}
defs := make([]ToolDefinition, 0, len(pmDefs))
for _, d := range pmDefs {
defs = append(defs, ToolDefinition{
Name: d.Name,
Description: d.Description,
Parameters: d.Parameters,
})
}
return defs, nil
}