package tools import ( "fmt" "sync" "git.flytoex.net/yuanwei/flyto-agent/pkg/permission" ) // Registry 是工具注册表. // 对应原项目中 assembleToolPool() 和 tools 数组的功能, // 但作为独立的,线程安全的数据结构存在. // // 原项目的工具池在每次 getCommands() 时重新组装(带 memoize 缓存), // 且内置工具和 MCP 工具的合并逻辑散落在多处. // Go 版本统一用 Registry 管理,支持运行时动态注册/注销. type Registry struct { mu sync.RWMutex tools map[string]Tool // name -> tool aliases map[string]string // alias -> canonical name order []string // 注册顺序(保持稳定性) } // NewRegistry 创建一个空的工具注册表. func NewRegistry() *Registry { return &Registry{ tools: make(map[string]Tool), aliases: make(map[string]string), order: make([]string, 0), } } // Register 注册一个工具. // 如果同名工具已存在,返回错误. func (r *Registry) Register(t Tool) error { r.mu.Lock() defer r.mu.Unlock() name := t.Name() if _, exists := r.tools[name]; exists { return fmt.Errorf("tool %q already registered", name) } r.tools[name] = t r.order = append(r.order, name) // 注册别名 + 权限类型 meta := GetMetadata(t) for _, alias := range meta.Aliases { r.aliases[alias] = name } // 升华改进(ELEVATED): P0-2 修复--工具注册时自动同步权限类型到 permission 包. // 第三方工具只需在 Metadata.PermissionClass 声明一次,权限系统自动感知. // 不修改权限检查核心代码,扩展零侵入. if meta.PermissionClass != "" { permission.RegisterToolClass(name, meta.PermissionClass) } return nil } // MetadataFor 按名称查询工具的 Metadata (支持别名). // 返回 (Metadata, true) 表示工具存在; (Metadata{}, false) 表示未注册. // // 工具未实现 MetadataProvider 时 GetMetadata 返回零值 Metadata, // 调用方据此判断"已注册但未声明元数据". // // 升华改进(ELEVATED): 与 Get() 对称, 但只暴露元数据不暴露 Tool 实例. // 用于跨切面关注 (audit / permission / policy) 查询语义标签 - // AuditObserver 据此决定 operationFromTool, 不再硬编码 switch. func (r *Registry) MetadataFor(name string) (Metadata, bool) { t, ok := r.Get(name) if !ok { return Metadata{}, false } return GetMetadata(t), true } // Get 按名称获取工具(支持别名查找). func (r *Registry) Get(name string) (Tool, bool) { r.mu.RLock() defer r.mu.RUnlock() // 先查原名 if t, ok := r.tools[name]; ok { return t, true } // 再查别名 if canonical, ok := r.aliases[name]; ok { if t, ok := r.tools[canonical]; ok { return t, true } } return nil, false } // All 返回所有已注册工具(按注册顺序). func (r *Registry) All() []Tool { r.mu.RLock() defer r.mu.RUnlock() result := make([]Tool, 0, len(r.order)) for _, name := range r.order { if t, ok := r.tools[name]; ok { result = append(result, t) } } return result } // Names 返回所有已注册工具的名称(按注册顺序). func (r *Registry) Names() []string { r.mu.RLock() defer r.mu.RUnlock() out := make([]string, len(r.order)) copy(out, r.order) return out } // Unregister 注销一个工具. func (r *Registry) Unregister(name string) bool { r.mu.Lock() defer r.mu.Unlock() if _, exists := r.tools[name]; !exists { return false } // 清理别名 for alias, canonical := range r.aliases { if canonical == name { delete(r.aliases, alias) } } delete(r.tools, name) // 从有序列表中移除 for i, n := range r.order { if n == name { r.order = append(r.order[:i], r.order[i+1:]...) break } } return true } // Filter 返回符合条件的工具子集. // 用于 Agent 子进程的工具过滤. func (r *Registry) Filter(names []string) []Tool { r.mu.RLock() defer r.mu.RUnlock() nameSet := make(map[string]bool, len(names)) for _, n := range names { nameSet[n] = true } result := make([]Tool, 0) for _, name := range r.order { if nameSet[name] { if t, ok := r.tools[name]; ok { result = append(result, t) } } } return result } // Count 返回已注册工具数量. func (r *Registry) Count() int { r.mu.RLock() defer r.mu.RUnlock() return len(r.tools) }