package tool import ( "context" "fmt" "sort" "sync" ) // Manager is a thread-safe registry that manages tool registration and execution. // // Tools are registered by name (case-sensitive) and can be discovered, // listed, and invoked through the Manager. Duplicate registration returns // an error. type Manager struct { mu sync.RWMutex tools map[string]Tool } // NewManager creates a new empty tool manager. func NewManager() *Manager { return &Manager{ tools: make(map[string]Tool), } } // Register adds a tool to the manager. Returns an error if a tool with the // same name is already registered. func (m *Manager) Register(tool Tool) error { m.mu.Lock() defer m.mu.Unlock() name := tool.Name() if _, exists := m.tools[name]; exists { return fmt.Errorf("tool %q is already registered", name) } m.tools[name] = tool return nil } // Unregister removes a tool from the manager by name. func (m *Manager) Unregister(name string) error { m.mu.Lock() defer m.mu.Unlock() if _, exists := m.tools[name]; !exists { return fmt.Errorf("tool %q is not registered", name) } delete(m.tools, name) return nil } // Get retrieves a tool by name. Returns false if not found. func (m *Manager) Get(name string) (Tool, bool) { m.mu.RLock() defer m.mu.RUnlock() t, ok := m.tools[name] return t, ok } // List returns all registered tools sorted by name. func (m *Manager) List() []Tool { m.mu.RLock() defer m.mu.RUnlock() result := make([]Tool, 0, len(m.tools)) for _, t := range m.tools { result = append(result, t) } sort.Slice(result, func(i, j int) bool { return result[i].Name() < result[j].Name() }) return result } // Execute looks up a tool by name and invokes it with the given arguments. // Returns an error if the tool is not found. func (m *Manager) Execute(name string, ctx context.Context, args map[string]interface{}) (*Result, error) { tool, ok := m.Get(name) if !ok { return nil, fmt.Errorf("tool %q not found", name) } return tool.Execute(ctx, args) } // Count returns the number of registered tools. func (m *Manager) Count() int { m.mu.RLock() defer m.mu.RUnlock() return len(m.tools) } // Names returns the names of all registered tools sorted alphabetically. func (m *Manager) Names() []string { m.mu.RLock() defer m.mu.RUnlock() names := make([]string, 0, len(m.tools)) for name := range m.tools { names = append(names, name) } sort.Strings(names) return names }