Merge branch 'main' of https://gitea.functen.cn/shihao/WechatHookBot
This commit is contained in:
@@ -2,7 +2,6 @@ import importlib
|
||||
import inspect
|
||||
import os
|
||||
import sys
|
||||
import tomllib
|
||||
import traceback
|
||||
from typing import Dict, Type, List, Union
|
||||
|
||||
@@ -10,6 +9,8 @@ from loguru import logger
|
||||
|
||||
# from WechatAPI import WechatAPIClient # 注释掉,WechatHookBot 不需要这个导入
|
||||
from utils.singleton import Singleton
|
||||
from utils.config_manager import get_bot_config
|
||||
from utils.llm_tooling import register_plugin_tools, unregister_plugin_tools
|
||||
from .event_manager import EventManager
|
||||
from .plugin_base import PluginBase
|
||||
|
||||
@@ -22,10 +23,9 @@ class PluginManager(metaclass=Singleton):
|
||||
|
||||
self.bot = None
|
||||
|
||||
with open("main_config.toml", "rb") as f:
|
||||
main_config = tomllib.load(f)
|
||||
|
||||
self.excluded_plugins = main_config.get("Bot", {}).get("disabled-plugins", [])
|
||||
# 使用统一配置管理器
|
||||
bot_config = get_bot_config()
|
||||
self.excluded_plugins = bot_config.get("disabled-plugins", [])
|
||||
|
||||
def set_bot(self, bot):
|
||||
"""设置 bot 客户端(WechatHookClient)"""
|
||||
@@ -74,13 +74,34 @@ class PluginManager(metaclass=Singleton):
|
||||
if is_disabled:
|
||||
return False
|
||||
|
||||
# 创建插件实例
|
||||
plugin = plugin_class()
|
||||
EventManager.bind_instance(plugin)
|
||||
await plugin.on_enable(self.bot)
|
||||
|
||||
# 生命周期: on_load(可访问其他插件)
|
||||
await plugin.on_load(self)
|
||||
|
||||
# 生命周期: async_init(加载配置、资源)
|
||||
await plugin.async_init()
|
||||
|
||||
# 绑定事件处理器
|
||||
EventManager.bind_instance(plugin)
|
||||
|
||||
# 生命周期: on_enable(注册定时任务)
|
||||
await plugin.on_enable(self.bot)
|
||||
|
||||
# 注册到插件管理器
|
||||
self.plugins[plugin_name] = plugin
|
||||
self.plugin_classes[plugin_name] = plugin_class
|
||||
self.plugin_info[plugin_name]["enabled"] = True
|
||||
|
||||
# 注册插件的 LLM 工具到全局注册中心
|
||||
try:
|
||||
tools_config = self._get_tools_config()
|
||||
timeout_config = self._get_timeout_config()
|
||||
register_plugin_tools(plugin_name, plugin, tools_config, timeout_config)
|
||||
except Exception as e:
|
||||
logger.warning(f"注册插件 {plugin_name} 的工具时出错: {e}")
|
||||
|
||||
logger.success(f"加载插件 {plugin_name} 成功")
|
||||
return True
|
||||
except:
|
||||
@@ -232,8 +253,22 @@ class PluginManager(metaclass=Singleton):
|
||||
|
||||
try:
|
||||
plugin = self.plugins[plugin_name]
|
||||
|
||||
# 生命周期: on_disable(清理定时任务)
|
||||
await plugin.on_disable()
|
||||
|
||||
# 解绑事件处理器
|
||||
EventManager.unbind_instance(plugin)
|
||||
|
||||
# 从全局注册中心注销插件的工具
|
||||
try:
|
||||
unregister_plugin_tools(plugin_name)
|
||||
except Exception as e:
|
||||
logger.warning(f"注销插件 {plugin_name} 的工具时出错: {e}")
|
||||
|
||||
# 生命周期: on_unload(释放资源)
|
||||
await plugin.on_unload()
|
||||
|
||||
del self.plugins[plugin_name]
|
||||
del self.plugin_classes[plugin_name]
|
||||
if plugin_name in self.plugin_info.keys():
|
||||
@@ -256,7 +291,7 @@ class PluginManager(metaclass=Singleton):
|
||||
return unloaded_plugins, failed_unloads
|
||||
|
||||
async def reload_plugin(self, plugin_name: str) -> bool:
|
||||
"""重载单个插件"""
|
||||
"""重载单个插件(支持状态保存和恢复)"""
|
||||
if plugin_name not in self.plugin_classes:
|
||||
return False
|
||||
|
||||
@@ -270,7 +305,15 @@ class PluginManager(metaclass=Singleton):
|
||||
plugin_class = self.plugin_classes[plugin_name]
|
||||
module_name = plugin_class.__module__
|
||||
|
||||
# 先卸载插件
|
||||
# 生命周期: on_reload(保存状态)
|
||||
saved_state = {}
|
||||
if plugin_name in self.plugins:
|
||||
try:
|
||||
saved_state = await self.plugins[plugin_name].on_reload()
|
||||
except Exception as e:
|
||||
logger.warning(f"保存插件 {plugin_name} 状态失败: {e}")
|
||||
|
||||
# 卸载插件
|
||||
if not await self.unload_plugin(plugin_name):
|
||||
return False
|
||||
|
||||
@@ -284,8 +327,15 @@ class PluginManager(metaclass=Singleton):
|
||||
issubclass(obj, PluginBase) and
|
||||
obj != PluginBase and
|
||||
obj.__name__ == plugin_name):
|
||||
# 使用新的插件类而不是旧的
|
||||
return await self.load_plugin(obj)
|
||||
# 加载新插件
|
||||
if await self.load_plugin(obj):
|
||||
# 恢复状态
|
||||
if saved_state and plugin_name in self.plugins:
|
||||
try:
|
||||
await self.plugins[plugin_name].restore_state(saved_state)
|
||||
except Exception as e:
|
||||
logger.warning(f"恢复插件 {plugin_name} 状态失败: {e}")
|
||||
return True
|
||||
|
||||
return False
|
||||
except Exception as e:
|
||||
@@ -349,13 +399,42 @@ class PluginManager(metaclass=Singleton):
|
||||
|
||||
def get_plugin_info(self, plugin_name: str = None) -> Union[dict, List[dict]]:
|
||||
"""获取插件信息
|
||||
|
||||
|
||||
Args:
|
||||
plugin_name: 插件名称,如果为None则返回所有插件信息
|
||||
|
||||
|
||||
Returns:
|
||||
如果指定插件名,返回单个插件信息字典;否则返回所有插件信息列表
|
||||
"""
|
||||
if plugin_name:
|
||||
return self.plugin_info.get(plugin_name)
|
||||
return list(self.plugin_info.values())
|
||||
|
||||
def _get_tools_config(self) -> dict:
|
||||
"""获取工具配置(用于工具注册)"""
|
||||
try:
|
||||
# 尝试从 AIChat 插件配置读取
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
aichat_config_path = Path("plugins/AIChat/config.toml")
|
||||
if aichat_config_path.exists():
|
||||
with open(aichat_config_path, "rb") as f:
|
||||
aichat_config = tomllib.load(f)
|
||||
return aichat_config.get("tools", {})
|
||||
except Exception:
|
||||
pass
|
||||
return {"mode": "all", "whitelist": [], "blacklist": []}
|
||||
|
||||
def _get_timeout_config(self) -> dict:
|
||||
"""获取工具超时配置"""
|
||||
try:
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
aichat_config_path = Path("plugins/AIChat/config.toml")
|
||||
if aichat_config_path.exists():
|
||||
with open(aichat_config_path, "rb") as f:
|
||||
aichat_config = tomllib.load(f)
|
||||
return aichat_config.get("tools", {}).get("timeout", {})
|
||||
except Exception:
|
||||
pass
|
||||
return {"default": 60}
|
||||
|
||||
Reference in New Issue
Block a user