Merge branch 'dev' of https://github.com/MaiM-with-u/MaiBot into dev
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
- `config_api.py`中的`get_global_config`和`get_plugin_config`方法现在支持嵌套访问的配置键名。
|
||||
- `database_api.py`中的`db_query`方法调整了参数顺序以增强参数限制的同时,保证了typing正确;`db_get`方法增加了`single_result`参数,与`db_query`保持一致。
|
||||
5. 增加了`logging_api`,可以用`get_logger`来获取日志记录器。
|
||||
6. 增加了插件和组件管理的API。
|
||||
|
||||
# 插件系统修改
|
||||
1. 现在所有的匹配模式不再是关键字了,而是枚举类。**(可能有遗漏)**
|
||||
@@ -53,11 +54,13 @@
|
||||
- 通过`disable_specific_chat_action`,`enable_specific_chat_action`,`disable_specific_chat_command`,`enable_specific_chat_command`,`disable_specific_chat_event_handler`,`enable_specific_chat_event_handler`来操作
|
||||
- 同样不保存到配置文件~
|
||||
|
||||
# 官方插件修改
|
||||
1. `HelloWorld`插件现在有一个样例的`EventHandler`。
|
||||
2. 内置插件增加了一个通过`Command`来管理插件的功能。
|
||||
|
||||
### TODO
|
||||
把这个看起来就很别扭的config获取方式改一下
|
||||
|
||||
来个API管理这些启用禁用!
|
||||
|
||||
|
||||
# 吐槽
|
||||
```python
|
||||
|
||||
@@ -118,17 +118,17 @@ class HelloWorldPlugin(BasePlugin):
|
||||
"""Hello World插件 - 你的第一个MaiCore插件"""
|
||||
|
||||
# 插件基本信息
|
||||
plugin_name = "hello_world_plugin" # 内部标识符
|
||||
enable_plugin = True
|
||||
dependencies = [] # 插件依赖列表
|
||||
python_dependencies = [] # Python包依赖列表
|
||||
config_file_name = "config.toml" # 配置文件名
|
||||
plugin_name: str = "hello_world_plugin" # 内部标识符
|
||||
enable_plugin: bool = True
|
||||
dependencies: List[str] = [] # 插件依赖列表
|
||||
python_dependencies: List[str] = [] # Python包依赖列表
|
||||
config_file_name: str = "config.toml" # 配置文件名
|
||||
|
||||
# 配置节描述
|
||||
config_section_descriptions = {"plugin": "插件基本信息", "greeting": "问候功能配置", "time": "时间查询配置"}
|
||||
|
||||
# 配置Schema定义
|
||||
config_schema = {
|
||||
config_schema: dict = {
|
||||
"plugin": {
|
||||
"name": ConfigField(type=str, default="hello_world_plugin", description="插件名称"),
|
||||
"version": ConfigField(type=str, default="1.0.0", description="插件版本"),
|
||||
|
||||
@@ -51,8 +51,6 @@ NO_ACTION = {
|
||||
"action_prompt": "",
|
||||
}
|
||||
|
||||
IS_MAI4U = False
|
||||
|
||||
install(extra_lines=3)
|
||||
|
||||
# 注释:原来的动作修改超时常量已移除,因为改为顺序执行
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import json
|
||||
import time
|
||||
import traceback
|
||||
from typing import Dict, Any, Optional, Tuple, List
|
||||
from typing import Dict, Any, Optional, Tuple
|
||||
from rich.traceback import install
|
||||
from datetime import datetime
|
||||
from json_repair import repair_json
|
||||
@@ -119,8 +119,8 @@ class ActionPlanner:
|
||||
current_available_actions_dict = self.action_manager.get_using_actions()
|
||||
|
||||
# 获取完整的动作信息
|
||||
all_registered_actions: List[ActionInfo] = list(
|
||||
component_registry.get_components_by_type(ComponentType.ACTION).values() # type: ignore
|
||||
all_registered_actions: Dict[str, ActionInfo] = component_registry.get_components_by_type( # type: ignore
|
||||
ComponentType.ACTION
|
||||
)
|
||||
current_available_actions = {}
|
||||
for action_name in current_available_actions_dict:
|
||||
|
||||
@@ -48,7 +48,7 @@ TEMPLATE_DIR = os.path.join(PROJECT_ROOT, "template")
|
||||
|
||||
# 考虑到,实际上配置文件中的mai_version是不会自动更新的,所以采用硬编码
|
||||
# 对该字段的更新,请严格参照语义化版本规范:https://semver.org/lang/zh-CN/
|
||||
MMC_VERSION = "0.9.0-snapshot.2"
|
||||
MMC_VERSION = "0.9.0-snapshot.3"
|
||||
|
||||
|
||||
def get_key_comment(toml_table, key):
|
||||
|
||||
@@ -23,13 +23,6 @@ from .base import (
|
||||
EventType,
|
||||
MaiMessages,
|
||||
)
|
||||
from .core import (
|
||||
plugin_manager,
|
||||
component_registry,
|
||||
dependency_manager,
|
||||
events_manager,
|
||||
global_announcement_manager,
|
||||
)
|
||||
|
||||
# 导入工具模块
|
||||
from .utils import (
|
||||
@@ -39,12 +32,42 @@ from .utils import (
|
||||
# generate_plugin_manifest,
|
||||
)
|
||||
|
||||
from .apis import register_plugin, get_logger
|
||||
from .apis import (
|
||||
chat_api,
|
||||
component_manage_api,
|
||||
config_api,
|
||||
database_api,
|
||||
emoji_api,
|
||||
generator_api,
|
||||
llm_api,
|
||||
message_api,
|
||||
person_api,
|
||||
plugin_manage_api,
|
||||
send_api,
|
||||
utils_api,
|
||||
register_plugin,
|
||||
get_logger,
|
||||
)
|
||||
|
||||
|
||||
__version__ = "1.0.0"
|
||||
|
||||
__all__ = [
|
||||
# API 模块
|
||||
"chat_api",
|
||||
"component_manage_api",
|
||||
"config_api",
|
||||
"database_api",
|
||||
"emoji_api",
|
||||
"generator_api",
|
||||
"llm_api",
|
||||
"message_api",
|
||||
"person_api",
|
||||
"plugin_manage_api",
|
||||
"send_api",
|
||||
"utils_api",
|
||||
"register_plugin",
|
||||
"get_logger",
|
||||
# 基础类
|
||||
"BasePlugin",
|
||||
"BaseAction",
|
||||
@@ -63,12 +86,6 @@ __all__ = [
|
||||
"EventType",
|
||||
# 消息
|
||||
"MaiMessages",
|
||||
# 管理器
|
||||
"plugin_manager",
|
||||
"component_registry",
|
||||
"dependency_manager",
|
||||
"events_manager",
|
||||
"global_announcement_manager",
|
||||
# 装饰器
|
||||
"register_plugin",
|
||||
"ConfigField",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
# 导入所有API模块
|
||||
from src.plugin_system.apis import (
|
||||
chat_api,
|
||||
component_manage_api,
|
||||
config_api,
|
||||
database_api,
|
||||
emoji_api,
|
||||
@@ -14,15 +15,17 @@ from src.plugin_system.apis import (
|
||||
llm_api,
|
||||
message_api,
|
||||
person_api,
|
||||
plugin_manage_api,
|
||||
send_api,
|
||||
utils_api,
|
||||
plugin_register_api,
|
||||
)
|
||||
from .logging_api import get_logger
|
||||
from .plugin_register_api import register_plugin
|
||||
|
||||
# 导出所有API模块,使它们可以通过 apis.xxx 方式访问
|
||||
__all__ = [
|
||||
"chat_api",
|
||||
"component_manage_api",
|
||||
"config_api",
|
||||
"database_api",
|
||||
"emoji_api",
|
||||
@@ -30,9 +33,9 @@ __all__ = [
|
||||
"llm_api",
|
||||
"message_api",
|
||||
"person_api",
|
||||
"plugin_manage_api",
|
||||
"send_api",
|
||||
"utils_api",
|
||||
"plugin_register_api",
|
||||
"get_logger",
|
||||
"register_plugin",
|
||||
]
|
||||
|
||||
245
src/plugin_system/apis/component_manage_api.py
Normal file
245
src/plugin_system/apis/component_manage_api.py
Normal file
@@ -0,0 +1,245 @@
|
||||
from typing import Optional, Union, Dict
|
||||
from src.plugin_system.base.component_types import (
|
||||
CommandInfo,
|
||||
ActionInfo,
|
||||
EventHandlerInfo,
|
||||
PluginInfo,
|
||||
ComponentType,
|
||||
)
|
||||
|
||||
|
||||
# === 插件信息查询 ===
|
||||
def get_all_plugin_info() -> Dict[str, PluginInfo]:
|
||||
"""
|
||||
获取所有插件的信息。
|
||||
|
||||
Returns:
|
||||
dict: 包含所有插件信息的字典,键为插件名称,值为 PluginInfo 对象。
|
||||
"""
|
||||
from src.plugin_system.core.component_registry import component_registry
|
||||
|
||||
return component_registry.get_all_plugins()
|
||||
|
||||
|
||||
def get_plugin_info(plugin_name: str) -> Optional[PluginInfo]:
|
||||
"""
|
||||
获取指定插件的信息。
|
||||
|
||||
Args:
|
||||
plugin_name (str): 插件名称。
|
||||
|
||||
Returns:
|
||||
PluginInfo: 插件信息对象,如果插件不存在则返回 None。
|
||||
"""
|
||||
from src.plugin_system.core.component_registry import component_registry
|
||||
|
||||
return component_registry.get_plugin_info(plugin_name)
|
||||
|
||||
|
||||
# === 组件查询方法 ===
|
||||
def get_component_info(
|
||||
component_name: str, component_type: ComponentType
|
||||
) -> Optional[Union[CommandInfo, ActionInfo, EventHandlerInfo]]:
|
||||
"""
|
||||
获取指定组件的信息。
|
||||
|
||||
Args:
|
||||
component_name (str): 组件名称。
|
||||
component_type (ComponentType): 组件类型。
|
||||
Returns:
|
||||
Union[CommandInfo, ActionInfo, EventHandlerInfo]: 组件信息对象,如果组件不存在则返回 None。
|
||||
"""
|
||||
from src.plugin_system.core.component_registry import component_registry
|
||||
|
||||
return component_registry.get_component_info(component_name, component_type) # type: ignore
|
||||
|
||||
|
||||
def get_components_info_by_type(
|
||||
component_type: ComponentType,
|
||||
) -> Dict[str, Union[CommandInfo, ActionInfo, EventHandlerInfo]]:
|
||||
"""
|
||||
获取指定类型的所有组件信息。
|
||||
|
||||
Args:
|
||||
component_type (ComponentType): 组件类型。
|
||||
|
||||
Returns:
|
||||
dict: 包含指定类型组件信息的字典,键为组件名称,值为对应的组件信息对象。
|
||||
"""
|
||||
from src.plugin_system.core.component_registry import component_registry
|
||||
|
||||
return component_registry.get_components_by_type(component_type) # type: ignore
|
||||
|
||||
|
||||
def get_enabled_components_info_by_type(
|
||||
component_type: ComponentType,
|
||||
) -> Dict[str, Union[CommandInfo, ActionInfo, EventHandlerInfo]]:
|
||||
"""
|
||||
获取指定类型的所有启用的组件信息。
|
||||
|
||||
Args:
|
||||
component_type (ComponentType): 组件类型。
|
||||
|
||||
Returns:
|
||||
dict: 包含指定类型启用组件信息的字典,键为组件名称,值为对应的组件信息对象。
|
||||
"""
|
||||
from src.plugin_system.core.component_registry import component_registry
|
||||
|
||||
return component_registry.get_enabled_components_by_type(component_type) # type: ignore
|
||||
|
||||
|
||||
# === Action 查询方法 ===
|
||||
def get_registered_action_info(action_name: str) -> Optional[ActionInfo]:
|
||||
"""
|
||||
获取指定 Action 的注册信息。
|
||||
|
||||
Args:
|
||||
action_name (str): Action 名称。
|
||||
|
||||
Returns:
|
||||
ActionInfo: Action 信息对象,如果 Action 不存在则返回 None。
|
||||
"""
|
||||
from src.plugin_system.core.component_registry import component_registry
|
||||
|
||||
return component_registry.get_registered_action_info(action_name)
|
||||
|
||||
|
||||
def get_registered_command_info(command_name: str) -> Optional[CommandInfo]:
|
||||
"""
|
||||
获取指定 Command 的注册信息。
|
||||
|
||||
Args:
|
||||
command_name (str): Command 名称。
|
||||
|
||||
Returns:
|
||||
CommandInfo: Command 信息对象,如果 Command 不存在则返回 None。
|
||||
"""
|
||||
from src.plugin_system.core.component_registry import component_registry
|
||||
|
||||
return component_registry.get_registered_command_info(command_name)
|
||||
|
||||
|
||||
# === EventHandler 特定查询方法 ===
|
||||
def get_registered_event_handler_info(
|
||||
event_handler_name: str,
|
||||
) -> Optional[EventHandlerInfo]:
|
||||
"""
|
||||
获取指定 EventHandler 的注册信息。
|
||||
|
||||
Args:
|
||||
event_handler_name (str): EventHandler 名称。
|
||||
|
||||
Returns:
|
||||
EventHandlerInfo: EventHandler 信息对象,如果 EventHandler 不存在则返回 None。
|
||||
"""
|
||||
from src.plugin_system.core.component_registry import component_registry
|
||||
|
||||
return component_registry.get_registered_event_handler_info(event_handler_name)
|
||||
|
||||
|
||||
# === 组件管理方法 ===
|
||||
def globally_enable_component(component_name: str, component_type: ComponentType) -> bool:
|
||||
"""
|
||||
全局启用指定组件。
|
||||
|
||||
Args:
|
||||
component_name (str): 组件名称。
|
||||
component_type (ComponentType): 组件类型。
|
||||
|
||||
Returns:
|
||||
bool: 启用成功返回 True,否则返回 False。
|
||||
"""
|
||||
from src.plugin_system.core.component_registry import component_registry
|
||||
|
||||
return component_registry.enable_component(component_name, component_type)
|
||||
|
||||
|
||||
async def globally_disable_component(component_name: str, component_type: ComponentType) -> bool:
|
||||
"""
|
||||
全局禁用指定组件。
|
||||
|
||||
**此函数是异步的,确保在异步环境中调用。**
|
||||
|
||||
Args:
|
||||
component_name (str): 组件名称。
|
||||
component_type (ComponentType): 组件类型。
|
||||
|
||||
Returns:
|
||||
bool: 禁用成功返回 True,否则返回 False。
|
||||
"""
|
||||
from src.plugin_system.core.component_registry import component_registry
|
||||
|
||||
return await component_registry.disable_component(component_name, component_type)
|
||||
|
||||
|
||||
def locally_enable_component(component_name: str, component_type: ComponentType, stream_id: str) -> bool:
|
||||
"""
|
||||
局部启用指定组件。
|
||||
|
||||
Args:
|
||||
component_name (str): 组件名称。
|
||||
component_type (ComponentType): 组件类型。
|
||||
stream_id (str): 消息流 ID。
|
||||
|
||||
Returns:
|
||||
bool: 启用成功返回 True,否则返回 False。
|
||||
"""
|
||||
from src.plugin_system.core.global_announcement_manager import global_announcement_manager
|
||||
|
||||
match component_type:
|
||||
case ComponentType.ACTION:
|
||||
return global_announcement_manager.enable_specific_chat_action(stream_id, component_name)
|
||||
case ComponentType.COMMAND:
|
||||
return global_announcement_manager.enable_specific_chat_command(stream_id, component_name)
|
||||
case ComponentType.EVENT_HANDLER:
|
||||
return global_announcement_manager.enable_specific_chat_event_handler(stream_id, component_name)
|
||||
case _:
|
||||
raise ValueError(f"未知 component type: {component_type}")
|
||||
|
||||
|
||||
def locally_disable_component(component_name: str, component_type: ComponentType, stream_id: str) -> bool:
|
||||
"""
|
||||
局部禁用指定组件。
|
||||
|
||||
Args:
|
||||
component_name (str): 组件名称。
|
||||
component_type (ComponentType): 组件类型。
|
||||
stream_id (str): 消息流 ID。
|
||||
|
||||
Returns:
|
||||
bool: 禁用成功返回 True,否则返回 False。
|
||||
"""
|
||||
from src.plugin_system.core.global_announcement_manager import global_announcement_manager
|
||||
|
||||
match component_type:
|
||||
case ComponentType.ACTION:
|
||||
return global_announcement_manager.disable_specific_chat_action(stream_id, component_name)
|
||||
case ComponentType.COMMAND:
|
||||
return global_announcement_manager.disable_specific_chat_command(stream_id, component_name)
|
||||
case ComponentType.EVENT_HANDLER:
|
||||
return global_announcement_manager.disable_specific_chat_event_handler(stream_id, component_name)
|
||||
case _:
|
||||
raise ValueError(f"未知 component type: {component_type}")
|
||||
|
||||
def get_locally_disabled_components(stream_id: str, component_type: ComponentType) -> list[str]:
|
||||
"""
|
||||
获取指定消息流中禁用的组件列表。
|
||||
|
||||
Args:
|
||||
stream_id (str): 消息流 ID。
|
||||
component_type (ComponentType): 组件类型。
|
||||
|
||||
Returns:
|
||||
list[str]: 禁用的组件名称列表。
|
||||
"""
|
||||
from src.plugin_system.core.global_announcement_manager import global_announcement_manager
|
||||
|
||||
match component_type:
|
||||
case ComponentType.ACTION:
|
||||
return global_announcement_manager.get_disabled_chat_actions(stream_id)
|
||||
case ComponentType.COMMAND:
|
||||
return global_announcement_manager.get_disabled_chat_commands(stream_id)
|
||||
case ComponentType.EVENT_HANDLER:
|
||||
return global_announcement_manager.get_disabled_chat_event_handlers(stream_id)
|
||||
case _:
|
||||
raise ValueError(f"未知 component type: {component_type}")
|
||||
95
src/plugin_system/apis/plugin_manage_api.py
Normal file
95
src/plugin_system/apis/plugin_manage_api.py
Normal file
@@ -0,0 +1,95 @@
|
||||
from typing import Tuple, List
|
||||
def list_loaded_plugins() -> List[str]:
|
||||
"""
|
||||
列出所有当前加载的插件。
|
||||
|
||||
Returns:
|
||||
list: 当前加载的插件名称列表。
|
||||
"""
|
||||
from src.plugin_system.core.plugin_manager import plugin_manager
|
||||
|
||||
return plugin_manager.list_loaded_plugins()
|
||||
|
||||
|
||||
def list_registered_plugins() -> List[str]:
|
||||
"""
|
||||
列出所有已注册的插件。
|
||||
|
||||
Returns:
|
||||
list: 已注册的插件名称列表。
|
||||
"""
|
||||
from src.plugin_system.core.plugin_manager import plugin_manager
|
||||
|
||||
return plugin_manager.list_registered_plugins()
|
||||
|
||||
|
||||
async def remove_plugin(plugin_name: str) -> bool:
|
||||
"""
|
||||
卸载指定的插件。
|
||||
|
||||
**此函数是异步的,确保在异步环境中调用。**
|
||||
|
||||
Args:
|
||||
plugin_name (str): 要卸载的插件名称。
|
||||
|
||||
Returns:
|
||||
bool: 卸载是否成功。
|
||||
"""
|
||||
from src.plugin_system.core.plugin_manager import plugin_manager
|
||||
|
||||
return await plugin_manager.remove_registered_plugin(plugin_name)
|
||||
|
||||
|
||||
async def reload_plugin(plugin_name: str) -> bool:
|
||||
"""
|
||||
重新加载指定的插件。
|
||||
|
||||
**此函数是异步的,确保在异步环境中调用。**
|
||||
|
||||
Args:
|
||||
plugin_name (str): 要重新加载的插件名称。
|
||||
|
||||
Returns:
|
||||
bool: 重新加载是否成功。
|
||||
"""
|
||||
from src.plugin_system.core.plugin_manager import plugin_manager
|
||||
|
||||
return await plugin_manager.reload_registered_plugin(plugin_name)
|
||||
|
||||
|
||||
def load_plugin(plugin_name: str) -> Tuple[bool, int]:
|
||||
"""
|
||||
加载指定的插件。
|
||||
|
||||
Args:
|
||||
plugin_name (str): 要加载的插件名称。
|
||||
|
||||
Returns:
|
||||
Tuple[bool, int]: 加载是否成功,成功或失败个数。
|
||||
"""
|
||||
from src.plugin_system.core.plugin_manager import plugin_manager
|
||||
|
||||
return plugin_manager.load_registered_plugin_classes(plugin_name)
|
||||
|
||||
def add_plugin_directory(plugin_directory: str) -> bool:
|
||||
"""
|
||||
添加插件目录。
|
||||
|
||||
Args:
|
||||
plugin_directory (str): 要添加的插件目录路径。
|
||||
Returns:
|
||||
bool: 添加是否成功。
|
||||
"""
|
||||
from src.plugin_system.core.plugin_manager import plugin_manager
|
||||
|
||||
return plugin_manager.add_plugin_directory(plugin_directory)
|
||||
|
||||
def rescan_plugin_directory() -> Tuple[int, int]:
|
||||
"""
|
||||
重新扫描插件目录,加载新插件。
|
||||
Returns:
|
||||
Tuple[int, int]: 成功加载的插件数量和失败的插件数量。
|
||||
"""
|
||||
from src.plugin_system.core.plugin_manager import plugin_manager
|
||||
|
||||
return plugin_manager.rescan_plugin_directory()
|
||||
@@ -24,9 +24,8 @@ class BaseCommand(ABC):
|
||||
"""Command组件的名称"""
|
||||
command_description: str = ""
|
||||
"""Command组件的描述"""
|
||||
|
||||
# 默认命令设置(子类可以覆盖)
|
||||
command_pattern: str = ""
|
||||
# 默认命令设置
|
||||
command_pattern: str = r""
|
||||
"""命令匹配的正则表达式"""
|
||||
command_help: str = ""
|
||||
"""命令帮助信息"""
|
||||
|
||||
@@ -442,7 +442,7 @@ class ComponentRegistry:
|
||||
command_info,
|
||||
)
|
||||
|
||||
# === 事件处理器特定查询方法 ===
|
||||
# === EventHandler 特定查询方法 ===
|
||||
|
||||
def get_event_handler_registry(self) -> Dict[str, Type[BaseEventHandler]]:
|
||||
"""获取事件处理器注册表"""
|
||||
@@ -467,9 +467,9 @@ class ComponentRegistry:
|
||||
"""获取所有插件"""
|
||||
return self._plugins.copy()
|
||||
|
||||
def get_enabled_plugins(self) -> Dict[str, PluginInfo]:
|
||||
"""获取所有启用的插件"""
|
||||
return {name: info for name, info in self._plugins.items() if info.enabled}
|
||||
# def get_enabled_plugins(self) -> Dict[str, PluginInfo]:
|
||||
# """获取所有启用的插件"""
|
||||
# return {name: info for name, info in self._plugins.items() if info.enabled}
|
||||
|
||||
def get_plugin_components(self, plugin_name: str) -> List[ComponentInfo]:
|
||||
"""获取插件的所有组件"""
|
||||
|
||||
@@ -31,6 +31,7 @@ class GlobalAnnouncementManager:
|
||||
self._user_disabled_actions[chat_id].remove(action_name)
|
||||
return True
|
||||
except ValueError:
|
||||
logger.warning(f"动作 {action_name} 不在禁用列表中")
|
||||
return False
|
||||
return False
|
||||
|
||||
@@ -51,6 +52,7 @@ class GlobalAnnouncementManager:
|
||||
self._user_disabled_commands[chat_id].remove(command_name)
|
||||
return True
|
||||
except ValueError:
|
||||
logger.warning(f"命令 {command_name} 不在禁用列表中")
|
||||
return False
|
||||
return False
|
||||
|
||||
@@ -71,6 +73,7 @@ class GlobalAnnouncementManager:
|
||||
self._user_disabled_event_handlers[chat_id].remove(handler_name)
|
||||
return True
|
||||
except ValueError:
|
||||
logger.warning(f"事件处理器 {handler_name} 不在禁用列表中")
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ from pathlib import Path
|
||||
|
||||
from src.common.logger import get_logger
|
||||
from src.plugin_system.base.plugin_base import PluginBase
|
||||
from src.plugin_system.base.component_types import ComponentType, PluginInfo, PythonDependency
|
||||
from src.plugin_system.base.component_types import ComponentType, PythonDependency
|
||||
from src.plugin_system.utils.manifest_utils import VersionComparator
|
||||
from .component_registry import component_registry
|
||||
from .dependency_manager import dependency_manager
|
||||
@@ -75,7 +75,7 @@ class PluginManager:
|
||||
total_failed_registration = 0
|
||||
|
||||
for plugin_name in self.plugin_classes.keys():
|
||||
load_status, count = self._load_registered_plugin_classes(plugin_name)
|
||||
load_status, count = self.load_registered_plugin_classes(plugin_name)
|
||||
if load_status:
|
||||
total_registered += 1
|
||||
else:
|
||||
@@ -85,7 +85,73 @@ class PluginManager:
|
||||
|
||||
return total_registered, total_failed_registration
|
||||
|
||||
async def remove_registered_plugin(self, plugin_name: str) -> None:
|
||||
def load_registered_plugin_classes(self, plugin_name: str) -> Tuple[bool, int]:
|
||||
# sourcery skip: extract-duplicate-method, extract-method
|
||||
"""
|
||||
加载已经注册的插件类
|
||||
"""
|
||||
plugin_class = self.plugin_classes.get(plugin_name)
|
||||
if not plugin_class:
|
||||
logger.error(f"插件 {plugin_name} 的插件类未注册或不存在")
|
||||
return False, 1
|
||||
try:
|
||||
# 使用记录的插件目录路径
|
||||
plugin_dir = self.plugin_paths.get(plugin_name)
|
||||
|
||||
# 如果没有记录,直接返回失败
|
||||
if not plugin_dir:
|
||||
return False, 1
|
||||
|
||||
plugin_instance = plugin_class(plugin_dir=plugin_dir) # 实例化插件(可能因为缺少manifest而失败)
|
||||
if not plugin_instance:
|
||||
logger.error(f"插件 {plugin_name} 实例化失败")
|
||||
return False, 1
|
||||
# 检查插件是否启用
|
||||
if not plugin_instance.enable_plugin:
|
||||
logger.info(f"插件 {plugin_name} 已禁用,跳过加载")
|
||||
return False, 0
|
||||
|
||||
# 检查版本兼容性
|
||||
is_compatible, compatibility_error = self._check_plugin_version_compatibility(
|
||||
plugin_name, plugin_instance.manifest_data
|
||||
)
|
||||
if not is_compatible:
|
||||
self.failed_plugins[plugin_name] = compatibility_error
|
||||
logger.error(f"❌ 插件加载失败: {plugin_name} - {compatibility_error}")
|
||||
return False, 1
|
||||
if plugin_instance.register_plugin():
|
||||
self.loaded_plugins[plugin_name] = plugin_instance
|
||||
self._show_plugin_components(plugin_name)
|
||||
return True, 1
|
||||
else:
|
||||
self.failed_plugins[plugin_name] = "插件注册失败"
|
||||
logger.error(f"❌ 插件注册失败: {plugin_name}")
|
||||
return False, 1
|
||||
|
||||
except FileNotFoundError as e:
|
||||
# manifest文件缺失
|
||||
error_msg = f"缺少manifest文件: {str(e)}"
|
||||
self.failed_plugins[plugin_name] = error_msg
|
||||
logger.error(f"❌ 插件加载失败: {plugin_name} - {error_msg}")
|
||||
return False, 1
|
||||
|
||||
except ValueError as e:
|
||||
# manifest文件格式错误或验证失败
|
||||
traceback.print_exc()
|
||||
error_msg = f"manifest验证失败: {str(e)}"
|
||||
self.failed_plugins[plugin_name] = error_msg
|
||||
logger.error(f"❌ 插件加载失败: {plugin_name} - {error_msg}")
|
||||
return False, 1
|
||||
|
||||
except Exception as e:
|
||||
# 其他错误
|
||||
error_msg = f"未知错误: {str(e)}"
|
||||
self.failed_plugins[plugin_name] = error_msg
|
||||
logger.error(f"❌ 插件加载失败: {plugin_name} - {error_msg}")
|
||||
logger.debug("详细错误信息: ", exc_info=True)
|
||||
return False, 1
|
||||
|
||||
async def remove_registered_plugin(self, plugin_name: str) -> bool:
|
||||
"""
|
||||
禁用插件模块
|
||||
"""
|
||||
@@ -93,38 +159,40 @@ class PluginManager:
|
||||
raise ValueError("插件名称不能为空")
|
||||
if plugin_name not in self.loaded_plugins:
|
||||
logger.warning(f"插件 {plugin_name} 未加载")
|
||||
return
|
||||
return False
|
||||
plugin_instance = self.loaded_plugins[plugin_name]
|
||||
plugin_info = plugin_instance.plugin_info
|
||||
for component in plugin_info.components:
|
||||
await component_registry.remove_component(component.name, component.component_type)
|
||||
del self.loaded_plugins[plugin_name]
|
||||
return True
|
||||
|
||||
async def reload_registered_plugin_module(self, plugin_name: str) -> None:
|
||||
async def reload_registered_plugin(self, plugin_name: str) -> bool:
|
||||
"""
|
||||
重载插件模块
|
||||
"""
|
||||
await self.remove_registered_plugin(plugin_name)
|
||||
self._load_registered_plugin_classes(plugin_name)
|
||||
if not await self.remove_registered_plugin(plugin_name):
|
||||
return False
|
||||
if not self.load_registered_plugin_classes(plugin_name)[0]:
|
||||
return False
|
||||
logger.debug(f"插件 {plugin_name} 重载成功")
|
||||
return True
|
||||
|
||||
def rescan_plugin_directory(self) -> None:
|
||||
def rescan_plugin_directory(self) -> Tuple[int, int]:
|
||||
"""
|
||||
重新扫描插件根目录
|
||||
"""
|
||||
total_success = 0
|
||||
total_fail = 0
|
||||
for directory in self.plugin_directories:
|
||||
if os.path.exists(directory):
|
||||
logger.debug(f"重新扫描插件根目录: {directory}")
|
||||
self._load_plugin_modules_from_directory(directory)
|
||||
success, fail = self._load_plugin_modules_from_directory(directory)
|
||||
total_success += success
|
||||
total_fail += fail
|
||||
else:
|
||||
logger.warning(f"插件根目录不存在: {directory}")
|
||||
|
||||
def get_loaded_plugins(self) -> List[PluginInfo]:
|
||||
"""获取所有已加载的插件信息"""
|
||||
return list(component_registry.get_all_plugins().values())
|
||||
|
||||
def get_enabled_plugins(self) -> List[PluginInfo]:
|
||||
"""获取所有启用的插件信息"""
|
||||
return list(component_registry.get_enabled_plugins().values())
|
||||
return total_success, total_fail
|
||||
|
||||
def get_plugin_instance(self, plugin_name: str) -> Optional["PluginBase"]:
|
||||
"""获取插件实例
|
||||
@@ -235,6 +303,25 @@ class PluginManager:
|
||||
|
||||
return dependency_manager.generate_requirements_file(all_dependencies, output_path)
|
||||
|
||||
# === 查询方法 ===
|
||||
def list_loaded_plugins(self) -> List[str]:
|
||||
"""
|
||||
列出所有当前加载的插件。
|
||||
|
||||
Returns:
|
||||
list: 当前加载的插件名称列表。
|
||||
"""
|
||||
return list(self.loaded_plugins.keys())
|
||||
|
||||
def list_registered_plugins(self) -> List[str]:
|
||||
"""
|
||||
列出所有已注册的插件类。
|
||||
|
||||
Returns:
|
||||
list: 已注册的插件类名称列表。
|
||||
"""
|
||||
return list(self.plugin_classes.keys())
|
||||
|
||||
# === 私有方法 ===
|
||||
# == 目录管理 ==
|
||||
def _ensure_plugin_directories(self) -> None:
|
||||
@@ -310,72 +397,6 @@ class PluginManager:
|
||||
self.failed_plugins[module_name] = error_msg
|
||||
return False
|
||||
|
||||
def _load_registered_plugin_classes(self, plugin_name: str) -> Tuple[bool, int]:
|
||||
# sourcery skip: extract-duplicate-method, extract-method
|
||||
"""
|
||||
加载已经注册的插件类
|
||||
"""
|
||||
plugin_class = self.plugin_classes.get(plugin_name)
|
||||
if not plugin_class:
|
||||
logger.error(f"插件 {plugin_name} 的插件类未注册或不存在")
|
||||
return False, 1
|
||||
try:
|
||||
# 使用记录的插件目录路径
|
||||
plugin_dir = self.plugin_paths.get(plugin_name)
|
||||
|
||||
# 如果没有记录,直接返回失败
|
||||
if not plugin_dir:
|
||||
return False, 1
|
||||
|
||||
plugin_instance = plugin_class(plugin_dir=plugin_dir) # 实例化插件(可能因为缺少manifest而失败)
|
||||
if not plugin_instance:
|
||||
logger.error(f"插件 {plugin_name} 实例化失败")
|
||||
return False, 1
|
||||
# 检查插件是否启用
|
||||
if not plugin_instance.enable_plugin:
|
||||
logger.info(f"插件 {plugin_name} 已禁用,跳过加载")
|
||||
return False, 0
|
||||
|
||||
# 检查版本兼容性
|
||||
is_compatible, compatibility_error = self._check_plugin_version_compatibility(
|
||||
plugin_name, plugin_instance.manifest_data
|
||||
)
|
||||
if not is_compatible:
|
||||
self.failed_plugins[plugin_name] = compatibility_error
|
||||
logger.error(f"❌ 插件加载失败: {plugin_name} - {compatibility_error}")
|
||||
return False, 1
|
||||
if plugin_instance.register_plugin():
|
||||
self.loaded_plugins[plugin_name] = plugin_instance
|
||||
self._show_plugin_components(plugin_name)
|
||||
return True, 1
|
||||
else:
|
||||
self.failed_plugins[plugin_name] = "插件注册失败"
|
||||
logger.error(f"❌ 插件注册失败: {plugin_name}")
|
||||
return False, 1
|
||||
|
||||
except FileNotFoundError as e:
|
||||
# manifest文件缺失
|
||||
error_msg = f"缺少manifest文件: {str(e)}"
|
||||
self.failed_plugins[plugin_name] = error_msg
|
||||
logger.error(f"❌ 插件加载失败: {plugin_name} - {error_msg}")
|
||||
return False, 1
|
||||
|
||||
except ValueError as e:
|
||||
# manifest文件格式错误或验证失败
|
||||
traceback.print_exc()
|
||||
error_msg = f"manifest验证失败: {str(e)}"
|
||||
self.failed_plugins[plugin_name] = error_msg
|
||||
logger.error(f"❌ 插件加载失败: {plugin_name} - {error_msg}")
|
||||
return False, 1
|
||||
|
||||
except Exception as e:
|
||||
# 其他错误
|
||||
error_msg = f"未知错误: {str(e)}"
|
||||
self.failed_plugins[plugin_name] = error_msg
|
||||
logger.error(f"❌ 插件加载失败: {plugin_name} - {error_msg}")
|
||||
logger.debug("详细错误信息: ", exc_info=True)
|
||||
return False, 1
|
||||
|
||||
# == 兼容性检查 ==
|
||||
|
||||
def _check_plugin_version_compatibility(self, plugin_name: str, manifest_data: Dict[str, Any]) -> Tuple[bool, str]:
|
||||
|
||||
@@ -22,6 +22,7 @@ from src.plugins.built_in.core_actions.reply import ReplyAction
|
||||
|
||||
logger = get_logger("core_actions")
|
||||
|
||||
|
||||
@register_plugin
|
||||
class CoreActionsPlugin(BasePlugin):
|
||||
"""核心动作插件
|
||||
@@ -35,11 +36,11 @@ class CoreActionsPlugin(BasePlugin):
|
||||
"""
|
||||
|
||||
# 插件基本信息
|
||||
plugin_name = "core_actions" # 内部标识符
|
||||
enable_plugin = True
|
||||
dependencies = [] # 插件依赖列表
|
||||
python_dependencies = [] # Python包依赖列表
|
||||
config_file_name = "config.toml"
|
||||
plugin_name: str = "core_actions" # 内部标识符
|
||||
enable_plugin: bool = True
|
||||
dependencies: list[str] = [] # 插件依赖列表
|
||||
python_dependencies: list[str] = [] # Python包依赖列表
|
||||
config_file_name: str = "config.toml"
|
||||
|
||||
# 配置节描述
|
||||
config_section_descriptions = {
|
||||
@@ -48,7 +49,7 @@ class CoreActionsPlugin(BasePlugin):
|
||||
}
|
||||
|
||||
# 配置Schema定义
|
||||
config_schema = {
|
||||
config_schema: dict = {
|
||||
"plugin": {
|
||||
"enabled": ConfigField(type=bool, default=True, description="是否启用插件"),
|
||||
"config_version": ConfigField(type=str, default="0.4.0", description="配置文件版本"),
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# 导入新插件系统
|
||||
from src.plugin_system import BaseAction, ActionActivationType, ChatMode
|
||||
from src.config.config import global_config
|
||||
@@ -8,6 +7,7 @@ from typing import Tuple
|
||||
import asyncio
|
||||
import re
|
||||
import traceback
|
||||
|
||||
# 导入依赖的系统组件
|
||||
from src.common.logger import get_logger
|
||||
|
||||
@@ -20,6 +20,7 @@ from src.mais4u.constant_s4u import ENABLE_S4U
|
||||
|
||||
logger = get_logger("reply_action")
|
||||
|
||||
|
||||
class ReplyAction(BaseAction):
|
||||
"""回复动作 - 参与聊天回复"""
|
||||
|
||||
@@ -61,10 +62,10 @@ class ReplyAction(BaseAction):
|
||||
user_id = self.user_id
|
||||
platform = self.platform
|
||||
# logger.info(f"{self.log_prefix} 用户ID: {user_id}, 平台: {platform}")
|
||||
person_id = get_person_info_manager().get_person_id(platform, user_id)
|
||||
person_id = get_person_info_manager().get_person_id(platform, user_id) # type: ignore
|
||||
# logger.info(f"{self.log_prefix} 人物ID: {person_id}")
|
||||
person_name = get_person_info_manager().get_value_sync(person_id, "person_name")
|
||||
reply_to = f"{person_name}:{self.action_message.get('processed_plain_text', '')}"
|
||||
reply_to = f"{person_name}:{self.action_message.get('processed_plain_text', '')}" # type: ignore
|
||||
logger.info(f"{self.log_prefix} 回复目标: {reply_to}")
|
||||
|
||||
try:
|
||||
@@ -118,11 +119,9 @@ class ReplyAction(BaseAction):
|
||||
|
||||
# 存储动作记录
|
||||
reply_text = f"你对{person_name}进行了回复:{reply_text}"
|
||||
|
||||
|
||||
|
||||
if ENABLE_S4U:
|
||||
await mai_thinking_manager.get_mai_think(self.chat_id).do_think_after_response(reply_text)
|
||||
|
||||
|
||||
await self.store_action_info(
|
||||
action_build_into_prompt=False,
|
||||
@@ -138,4 +137,4 @@ class ReplyAction(BaseAction):
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 回复动作执行失败: {e}")
|
||||
traceback.print_exc()
|
||||
return False, f"回复失败: {str(e)}"
|
||||
return False, f"回复失败: {str(e)}"
|
||||
|
||||
39
src/plugins/built_in/plugin_management/_manifest.json
Normal file
39
src/plugins/built_in/plugin_management/_manifest.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"name": "插件和组件管理 (Plugin and Component Management)",
|
||||
"version": "1.0.0",
|
||||
"description": "通过系统API管理插件和组件的生命周期,包括加载、卸载、启用和禁用等操作。",
|
||||
"author": {
|
||||
"name": "MaiBot团队",
|
||||
"url": "https://github.com/MaiM-with-u"
|
||||
},
|
||||
"license": "GPL-v3.0-or-later",
|
||||
"host_application": {
|
||||
"min_version": "0.9.0"
|
||||
},
|
||||
"homepage_url": "https://github.com/MaiM-with-u/maibot",
|
||||
"repository_url": "https://github.com/MaiM-with-u/maibot",
|
||||
"keywords": [
|
||||
"plugins",
|
||||
"components",
|
||||
"management",
|
||||
"built-in"
|
||||
],
|
||||
"categories": [
|
||||
"Core System",
|
||||
"Plugin Management"
|
||||
],
|
||||
"default_locale": "zh-CN",
|
||||
"locales_path": "_locales",
|
||||
"plugin_info": {
|
||||
"is_built_in": true,
|
||||
"plugin_type": "plugin_management",
|
||||
"components": [
|
||||
{
|
||||
"type": "command",
|
||||
"name": "plugin_management",
|
||||
"description": "管理插件和组件的生命周期,包括加载、卸载、启用和禁用等操作。"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
246
src/plugins/built_in/plugin_management/plugin.py
Normal file
246
src/plugins/built_in/plugin_management/plugin.py
Normal file
@@ -0,0 +1,246 @@
|
||||
from typing import List, Tuple, Type
|
||||
from src.plugin_system import (
|
||||
BasePlugin,
|
||||
BaseCommand,
|
||||
CommandInfo,
|
||||
ConfigField,
|
||||
register_plugin,
|
||||
plugin_manage_api,
|
||||
component_manage_api,
|
||||
ComponentInfo,
|
||||
ComponentType,
|
||||
)
|
||||
from src.plugin_system.base.base_action import BaseAction
|
||||
from src.plugin_system.base.base_events_handler import BaseEventHandler
|
||||
from src.plugin_system.base.component_types import ActionInfo, EventHandlerInfo
|
||||
|
||||
|
||||
class ManagementCommand(BaseCommand):
|
||||
command_name: str = "management"
|
||||
description: str = "管理命令"
|
||||
command_pattern: str = r"(?P<manage_command>^/p_m(\s[a-zA-Z0-9_]+)*\s*$)"
|
||||
intercept_message: bool = True
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
command_list = self.matched_groups["manage_command"].strip().split(" ")
|
||||
if len(command_list) == 1:
|
||||
await self.show_help("all")
|
||||
return True, "帮助已发送"
|
||||
if len(command_list) == 2:
|
||||
match command_list[1]:
|
||||
case "plugin":
|
||||
await self.show_help("plugin")
|
||||
case "component":
|
||||
await self.show_help("component")
|
||||
case "help":
|
||||
await self.show_help("all")
|
||||
case _:
|
||||
return False, "命令不合法"
|
||||
if len(command_list) == 3:
|
||||
if command_list[1] == "plugin":
|
||||
match command_list[2]:
|
||||
case "help":
|
||||
await self.show_help("plugin")
|
||||
case "list":
|
||||
await self._list_registered_plugins()
|
||||
case "list_enabled":
|
||||
await self._list_loaded_plugins()
|
||||
case "rescan":
|
||||
await self._rescan_plugin_dirs()
|
||||
case _:
|
||||
return False, "命令不合法"
|
||||
elif command_list[1] == "component":
|
||||
match command_list[2]:
|
||||
case "help":
|
||||
await self.show_help("component")
|
||||
return True, "帮助已发送"
|
||||
case "list":
|
||||
pass
|
||||
case _:
|
||||
return False, "命令不合法"
|
||||
else:
|
||||
return False, "命令不合法"
|
||||
if len(command_list) == 4:
|
||||
if command_list[1] == "plugin":
|
||||
match command_list[2]:
|
||||
case "load":
|
||||
await self._load_plugin(command_list[3])
|
||||
case "unload":
|
||||
await self._unload_plugin(command_list[3])
|
||||
case "reload":
|
||||
await self._reload_plugin(command_list[3])
|
||||
case "add_dir":
|
||||
await self._add_dir(command_list[3])
|
||||
case _:
|
||||
return False, "命令不合法"
|
||||
elif command_list[1] == "component":
|
||||
pass
|
||||
else:
|
||||
return False, "命令不合法"
|
||||
if len(command_list) == 5:
|
||||
pass
|
||||
if len(command_list) == 6:
|
||||
pass
|
||||
|
||||
return True, "命令执行完成"
|
||||
|
||||
async def show_help(self, target: str):
|
||||
help_msg = ""
|
||||
match target:
|
||||
case "all":
|
||||
help_msg = (
|
||||
"管理命令帮助\n"
|
||||
"/p_m help 管理命令提示\n"
|
||||
"/p_m plugin 插件管理命令\n"
|
||||
"/p_m component 组件管理命令\n"
|
||||
"使用 /p_m plugin help 或 /p_m component help 获取具体帮助"
|
||||
)
|
||||
case "plugin":
|
||||
help_msg = (
|
||||
"插件管理命令帮助\n"
|
||||
"/p_m plugin help 插件管理命令提示\n"
|
||||
"/p_m plugin list 列出所有注册的插件\n"
|
||||
"/p_m plugin list_enabled 列出所有加载(启用)的插件\n"
|
||||
"/p_m plugin rescan 重新扫描所有目录\n"
|
||||
"/p_m plugin load <plugin_name> 加载指定插件\n"
|
||||
"/p_m plugin unload <plugin_name> 卸载指定插件\n"
|
||||
"/p_m plugin reload <plugin_name> 重新加载指定插件\n"
|
||||
"/p_m plugin add_dir <directory_path> 添加插件目录\n"
|
||||
)
|
||||
case "component":
|
||||
help_msg = (
|
||||
"组件管理命令帮助\n"
|
||||
"/p_m component help 组件管理命令提示\n"
|
||||
"/p_m component list 列出所有注册的组件\n"
|
||||
"/p_m component list enabled <可选: type> 列出所有启用的组件\n"
|
||||
"/p_m component list disabled <可选: type> 列出所有禁用的组件\n"
|
||||
" - <type> 可选项: local,代表当前聊天中的;global,代表全局的\n"
|
||||
" - <type> 不填时为 global\n"
|
||||
"/p_m component list type <component_type> 列出指定类型的组件\n"
|
||||
"/p_m component global enable <component_name> <可选: component_type> 全局启用组件\n"
|
||||
"/p_m component global disable <component_name> <可选: component_type> 全局禁用组件\n"
|
||||
"/p_m component local enable <component_name> <可选: component_type> 本聊天启用组件\n"
|
||||
"/p_m component local disable <component_name> <可选: component_type> 本聊天禁用组件\n"
|
||||
" - <component_type> 可选项: action, command, event_handler\n"
|
||||
)
|
||||
case _:
|
||||
return
|
||||
await self.send_text(help_msg)
|
||||
|
||||
async def _list_loaded_plugins(self):
|
||||
plugins = plugin_manage_api.list_loaded_plugins()
|
||||
await self.send_text(f"已加载的插件: {', '.join(plugins)}")
|
||||
|
||||
async def _list_registered_plugins(self):
|
||||
plugins = plugin_manage_api.list_registered_plugins()
|
||||
await self.send_text(f"已注册的插件: {', '.join(plugins)}")
|
||||
|
||||
async def _rescan_plugin_dirs(self):
|
||||
plugin_manage_api.rescan_plugin_directory()
|
||||
await self.send_text("插件目录重新扫描执行中")
|
||||
|
||||
async def _load_plugin(self, plugin_name: str):
|
||||
await self.send_text(f"正在加载插件: {plugin_name}")
|
||||
success, count = plugin_manage_api.load_plugin(plugin_name)
|
||||
if success:
|
||||
await self.send_text(f"插件加载成功: {plugin_name}")
|
||||
else:
|
||||
if count == 0:
|
||||
await self.send_text(f"插件{plugin_name}为禁用状态")
|
||||
await self.send_text(f"插件加载失败: {plugin_name}")
|
||||
|
||||
async def _unload_plugin(self, plugin_name: str):
|
||||
await self.send_text(f"正在卸载插件: {plugin_name}")
|
||||
success = plugin_manage_api.remove_plugin(plugin_name)
|
||||
if success:
|
||||
await self.send_text(f"插件卸载成功: {plugin_name}")
|
||||
else:
|
||||
await self.send_text(f"插件卸载失败: {plugin_name}")
|
||||
|
||||
async def _reload_plugin(self, plugin_name: str):
|
||||
await self.send_text(f"正在重新加载插件: {plugin_name}")
|
||||
success = plugin_manage_api.reload_plugin(plugin_name)
|
||||
if success:
|
||||
await self.send_text(f"插件重新加载成功: {plugin_name}")
|
||||
else:
|
||||
await self.send_text(f"插件重新加载失败: {plugin_name}")
|
||||
|
||||
async def _add_dir(self, dir_path: str):
|
||||
await self.send_text(f"正在添加插件目录: {dir_path}")
|
||||
success = plugin_manage_api.add_plugin_directory(dir_path)
|
||||
if success:
|
||||
await self.send_text(f"插件目录添加成功: {dir_path}")
|
||||
else:
|
||||
await self.send_text(f"插件目录添加失败: {dir_path}")
|
||||
|
||||
def _fetch_all_registered_components(self) -> List[ComponentInfo]:
|
||||
all_plugin_info = component_manage_api.get_all_plugin_info()
|
||||
if not all_plugin_info:
|
||||
return []
|
||||
|
||||
components_info: List[ComponentInfo] = []
|
||||
for plugin_info in all_plugin_info.values():
|
||||
components_info.extend(plugin_info.components)
|
||||
return components_info
|
||||
|
||||
def _fetch_locally_disabled_components(self) -> List[str]:
|
||||
locally_disabled_components_actions = component_manage_api.get_locally_disabled_components(
|
||||
self.message.chat_stream.stream_id, ComponentType.ACTION
|
||||
)
|
||||
locally_disabled_components_commands = component_manage_api.get_locally_disabled_components(
|
||||
self.message.chat_stream.stream_id, ComponentType.COMMAND
|
||||
)
|
||||
locally_disabled_components_event_handlers = component_manage_api.get_locally_disabled_components(
|
||||
self.message.chat_stream.stream_id, ComponentType.EVENT_HANDLER
|
||||
)
|
||||
return (
|
||||
locally_disabled_components_actions
|
||||
+ locally_disabled_components_commands
|
||||
+ locally_disabled_components_event_handlers
|
||||
)
|
||||
|
||||
async def _list_all_registered_components(self):
|
||||
components_info = self._fetch_all_registered_components()
|
||||
if not components_info:
|
||||
await self.send_text("没有注册的组件")
|
||||
return
|
||||
|
||||
all_components_str = ", ".join(
|
||||
f"{component.name} ({component.component_type})" for component in components_info
|
||||
)
|
||||
await self.send_text(f"已注册的组件: {all_components_str}")
|
||||
|
||||
async def _list_enabled_components(self, target_type: str = "global"):
|
||||
components_info = self._fetch_all_registered_components()
|
||||
if not components_info:
|
||||
await self.send_text("没有注册的组件")
|
||||
return
|
||||
|
||||
if target_type == "global":
|
||||
enabled_components = [component for component in components_info if component.enabled]
|
||||
if not enabled_components:
|
||||
await self.send_text("没有启用的全局组件")
|
||||
return
|
||||
enabled_components_str = ", ".join(
|
||||
f"{component.name} ({component.component_type})" for component in enabled_components
|
||||
)
|
||||
await self.send_text(f"启用的全局组件: {enabled_components_str}")
|
||||
elif target_type == "local":
|
||||
locally_disabled_components = self._fetch_locally_disabled_components()
|
||||
|
||||
|
||||
|
||||
@register_plugin
|
||||
class PluginManagementPlugin(BasePlugin):
|
||||
plugin_name: str = "plugin_management_plugin"
|
||||
enable_plugin: bool = True
|
||||
dependencies: list[str] = []
|
||||
python_dependencies: list[str] = []
|
||||
config_file_name: str = "config.toml"
|
||||
config_schema: dict = {"plugin": {"enable": ConfigField(bool, default=True, description="是否启用插件")}}
|
||||
|
||||
def get_plugin_components(self) -> List[Tuple[CommandInfo, Type[BaseCommand]]]:
|
||||
components = []
|
||||
if self.get_config("plugin.enable", True):
|
||||
components.append((ManagementCommand.get_command_info(), ManagementCommand))
|
||||
return components
|
||||
@@ -92,7 +92,7 @@ class TTSAction(BaseAction):
|
||||
|
||||
# 确保句子结尾有合适的标点
|
||||
if not any(processed_text.endswith(end) for end in [".", "?", "!", "。", "!", "?"]):
|
||||
processed_text = processed_text + "。"
|
||||
processed_text = f"{processed_text}。"
|
||||
|
||||
return processed_text
|
||||
|
||||
@@ -107,11 +107,11 @@ class TTSPlugin(BasePlugin):
|
||||
"""
|
||||
|
||||
# 插件基本信息
|
||||
plugin_name = "tts_plugin" # 内部标识符
|
||||
enable_plugin = True
|
||||
dependencies = [] # 插件依赖列表
|
||||
python_dependencies = [] # Python包依赖列表
|
||||
config_file_name = "config.toml"
|
||||
plugin_name: str = "tts_plugin" # 内部标识符
|
||||
enable_plugin: bool = True
|
||||
dependencies: list[str] = [] # 插件依赖列表
|
||||
python_dependencies: list[str] = [] # Python包依赖列表
|
||||
config_file_name: str = "config.toml"
|
||||
|
||||
# 配置节描述
|
||||
config_section_descriptions = {
|
||||
@@ -121,7 +121,7 @@ class TTSPlugin(BasePlugin):
|
||||
}
|
||||
|
||||
# 配置Schema定义
|
||||
config_schema = {
|
||||
config_schema: dict = {
|
||||
"plugin": {
|
||||
"name": ConfigField(type=str, default="tts_plugin", description="插件名称", required=True),
|
||||
"version": ConfigField(type=str, default="0.1.0", description="插件版本号"),
|
||||
|
||||
Reference in New Issue
Block a user