""" 核心组件注册表 面向最终架构的组件管理: - Action:注册 ActionInfo + 执行器(本地 callable 或 IPC 路由) - Command:注册正则模式 + 执行器 - Tool:注册工具定义 + 执行器 不依赖任何插件基类,组件执行器是纯 async callable。 """ import re from typing import Any, Awaitable, Callable, Dict, Optional, Pattern, Tuple from src.common.logger import get_logger from src.core.types import ( ActionInfo, CommandInfo, ComponentInfo, ComponentType, ToolInfo, ) logger = get_logger("component_registry") # 执行器类型 ActionExecutor = Callable[..., Awaitable[Any]] CommandExecutor = Callable[..., Awaitable[Tuple[bool, Optional[str], bool]]] ToolExecutor = Callable[..., Awaitable[Any]] class ComponentRegistry: """核心组件注册表 管理 action、command、tool 三类组件。 每个组件由「元信息 + 执行器」构成,执行器是 async callable, 不需要继承任何基类。 """ def __init__(self): # Action 注册 self._actions: Dict[str, ActionInfo] = {} self._action_executors: Dict[str, ActionExecutor] = {} self._default_actions: Dict[str, ActionInfo] = {} # Command 注册 self._commands: Dict[str, CommandInfo] = {} self._command_executors: Dict[str, CommandExecutor] = {} self._command_patterns: Dict[Pattern, str] = {} # Tool 注册 self._tools: Dict[str, ToolInfo] = {} self._tool_executors: Dict[str, ToolExecutor] = {} self._llm_available_tools: Dict[str, ToolInfo] = {} # 插件配置(plugin_name -> config dict) self._plugin_configs: Dict[str, dict] = {} logger.info("核心组件注册表初始化完成") # ========== Action ========== def register_action( self, info: ActionInfo, executor: ActionExecutor, ) -> bool: """注册 action Args: info: action 元信息 executor: 执行器,async callable """ name = info.name if name in self._actions: logger.warning(f"Action {name} 已存在,跳过注册") return False self._actions[name] = info self._action_executors[name] = executor if info.enabled: self._default_actions[name] = info logger.debug(f"注册 Action: {name}") return True def get_action_info(self, name: str) -> Optional[ActionInfo]: return self._actions.get(name) def get_action_executor(self, name: str) -> Optional[ActionExecutor]: return self._action_executors.get(name) def get_default_actions(self) -> Dict[str, ActionInfo]: return self._default_actions.copy() def get_all_actions(self) -> Dict[str, ActionInfo]: return self._actions.copy() def remove_action(self, name: str) -> bool: if name not in self._actions: return False del self._actions[name] self._action_executors.pop(name, None) self._default_actions.pop(name, None) logger.debug(f"移除 Action: {name}") return True # ========== Command ========== def register_command( self, info: CommandInfo, executor: CommandExecutor, ) -> bool: """注册 command""" name = info.name if name in self._commands: logger.warning(f"Command {name} 已存在,跳过注册") return False self._commands[name] = info self._command_executors[name] = executor if info.enabled and info.command_pattern: pattern = re.compile(info.command_pattern, re.IGNORECASE | re.DOTALL) self._command_patterns[pattern] = name logger.debug(f"注册 Command: {name}") return True def find_command_by_text(self, text: str) -> Optional[Tuple[CommandExecutor, dict, CommandInfo]]: """根据文本查找匹配的命令 Returns: (executor, matched_groups, command_info) 或 None """ candidates = [p for p in self._command_patterns if p.match(text)] if not candidates: return None if len(candidates) > 1: logger.warning(f"文本 '{text[:50]}' 匹配到多个命令模式,使用第一个") pattern = candidates[0] name = self._command_patterns[pattern] return ( self._command_executors[name], pattern.match(text).groupdict(), # type: ignore self._commands[name], ) def remove_command(self, name: str) -> bool: if name not in self._commands: return False del self._commands[name] self._command_executors.pop(name, None) self._command_patterns = {k: v for k, v in self._command_patterns.items() if v != name} logger.debug(f"移除 Command: {name}") return True # ========== Tool ========== def register_tool( self, info: ToolInfo, executor: ToolExecutor, ) -> bool: """注册 tool""" name = info.name if name in self._tools: logger.warning(f"Tool {name} 已存在,跳过注册") return False self._tools[name] = info self._tool_executors[name] = executor if info.enabled: self._llm_available_tools[name] = info logger.debug(f"注册 Tool: {name}") return True def get_tool_info(self, name: str) -> Optional[ToolInfo]: return self._tools.get(name) def get_tool_executor(self, name: str) -> Optional[ToolExecutor]: return self._tool_executors.get(name) def get_llm_available_tools(self) -> Dict[str, ToolInfo]: return self._llm_available_tools.copy() def get_all_tools(self) -> Dict[str, ToolInfo]: return self._tools.copy() def remove_tool(self, name: str) -> bool: if name not in self._tools: return False del self._tools[name] self._tool_executors.pop(name, None) self._llm_available_tools.pop(name, None) logger.debug(f"移除 Tool: {name}") return True # ========== 通用查询 ========== def get_component_info(self, name: str, component_type: ComponentType) -> Optional[ComponentInfo]: """获取组件元信息""" match component_type: case ComponentType.ACTION: return self._actions.get(name) case ComponentType.COMMAND: return self._commands.get(name) case ComponentType.TOOL: return self._tools.get(name) case _: return None def get_components_by_type(self, component_type: ComponentType) -> Dict[str, ComponentInfo]: """获取某类型的所有组件""" match component_type: case ComponentType.ACTION: return dict(self._actions) case ComponentType.COMMAND: return dict(self._commands) case ComponentType.TOOL: return dict(self._tools) case _: return {} # ========== 插件配置 ========== def set_plugin_config(self, plugin_name: str, config: dict) -> None: self._plugin_configs[plugin_name] = config def get_plugin_config(self, plugin_name: str) -> Optional[dict]: return self._plugin_configs.get(plugin_name) # 全局单例 component_registry = ComponentRegistry()