Files
Mofox-Core/src/plugin_system/base/base_plugin.py
minecraft1024a fe9d99e7fa refactor(plugin_system): 将依赖检查逻辑从插件基类移至插件管理器
将插件的Python包依赖和插件间依赖的检查逻辑,从各个插件实例的初始化阶段 (`PluginBase`),统一前置到插件模块加载阶段 (`PluginManager`)。

这一重构有以下好处:
- **提前失败 (Fail-fast)**:在加载插件模块时立即检查依赖,如果依赖不满足,则直接跳过该插件的加载和实例化,避免了不必要的资源消耗和后续的运行时错误。
- **职责单一**: `PluginManager` 负责插件的发现、加载和依赖管理,而 `PluginBase` 更专注于插件自身的业务逻辑和生命周期,使得代码结构更清晰。
- **配置中心化**: 依赖关系现在统一在 `__plugin_meta__` 中声明,而不是分散在插件类的属性中,提高了可维护性。
- **简化插件实现**: 插件开发者不再需要在插件类中定义 `dependencies` 和 `python_dependencies` 属性,只需在 `__init__.py` 中声明元数据即可。
2025-10-25 21:56:27 +08:00

157 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from abc import abstractmethod
from src.common.logger import get_logger
from src.plugin_system.base.component_types import (
ActionInfo,
CommandInfo,
ComponentType,
EventHandlerInfo,
InterestCalculatorInfo,
PlusCommandInfo,
PromptInfo,
ToolInfo,
)
from .base_action import BaseAction
from .base_command import BaseCommand
from .base_events_handler import BaseEventHandler
from .base_interest_calculator import BaseInterestCalculator
from .base_prompt import BasePrompt
from .base_tool import BaseTool
from .plugin_base import PluginBase
from .plus_command import PlusCommand
logger = get_logger("base_plugin")
class BasePlugin(PluginBase):
"""基于Action和Command的插件基类
所有上述类型的插件都应该继承这个基类,一个插件可以包含多种组件:
- Action组件处理聊天中的动作
- Command组件处理命令请求
- 未来可扩展Scheduler、Listener等
"""
@classmethod
def _get_component_info_from_class(cls, component_class: type, component_type: ComponentType):
"""从组件类自动生成组件信息
Args:
component_class: 组件类
component_type: 组件类型
Returns:
对应类型的ComponentInfo对象
"""
if component_type == ComponentType.COMMAND:
if hasattr(component_class, "get_command_info"):
return component_class.get_command_info()
else:
logger.warning(f"Command类 {component_class.__name__} 缺少 get_command_info 方法")
return None
elif component_type == ComponentType.ACTION:
if hasattr(component_class, "get_action_info"):
return component_class.get_action_info()
else:
logger.warning(f"Action类 {component_class.__name__} 缺少 get_action_info 方法")
return None
elif component_type == ComponentType.INTEREST_CALCULATOR:
if hasattr(component_class, "get_interest_calculator_info"):
return component_class.get_interest_calculator_info()
else:
logger.warning(
f"InterestCalculator类 {component_class.__name__} 缺少 get_interest_calculator_info 方法"
)
return None
elif component_type == ComponentType.PLUS_COMMAND:
# PlusCommand的get_info逻辑可以在这里实现
logger.warning("PlusCommand的get_info逻辑尚未实现")
return None
elif component_type == ComponentType.TOOL:
# Tool的get_info逻辑可以在这里实现
logger.warning("Tool的get_info逻辑尚未实现")
return None
elif component_type == ComponentType.EVENT_HANDLER:
# EventHandler的get_info逻辑可以在这里实现
logger.warning("EventHandler的get_info逻辑尚未实现")
return None
elif component_type == ComponentType.PROMPT:
if hasattr(component_class, "get_prompt_info"):
return component_class.get_prompt_info()
else:
logger.warning(f"Prompt类 {component_class.__name__} 缺少 get_prompt_info 方法")
return None
else:
logger.error(f"不支持的组件类型: {component_type}")
return None
@classmethod
def get_component_info(cls, component_class: type, component_type: ComponentType):
"""获取组件信息的通用方法
这是一个便捷方法内部调用_get_component_info_from_class
Args:
component_class: 组件类
component_type: 组件类型
Returns:
对应类型的ComponentInfo对象
"""
return cls._get_component_info_from_class(component_class, component_type)
@abstractmethod
def get_plugin_components(
self,
) -> list[
tuple[ActionInfo, type[BaseAction]]
| tuple[CommandInfo, type[BaseCommand]]
| tuple[PlusCommandInfo, type[PlusCommand]]
| tuple[EventHandlerInfo, type[BaseEventHandler]]
| tuple[ToolInfo, type[BaseTool]]
| tuple[InterestCalculatorInfo, type[BaseInterestCalculator]]
| tuple[PromptInfo, type[BasePrompt]]
]:
"""获取插件包含的组件列表
子类必须实现此方法,返回组件信息和组件类的列表
Returns:
List[tuple[ComponentInfo, Type]]: [(组件信息, 组件类), ...]
"""
...
def register_plugin(self) -> bool:
"""注册插件及其所有组件"""
from src.plugin_system.core.component_registry import component_registry
components = self.get_plugin_components()
# 注册所有组件
registered_components = []
for component_info, component_class in components:
component_info.plugin_name = self.plugin_name
if component_registry.register_component(component_info, component_class):
registered_components.append(component_info)
else:
logger.warning(f"{self.log_prefix} 组件 {component_info.name} 注册失败")
# 更新插件信息中的组件列表
self.plugin_info.components = registered_components
# 注册插件
if component_registry.register_plugin(self.plugin_info):
logger.debug(f"{self.log_prefix} 插件注册成功,包含 {len(registered_components)} 个组件")
return True
else:
logger.error(f"{self.log_prefix} 插件注册失败")
return False