Refactor plugin runtime components and enhance message handling

- Removed unused core action mirror functionality from PluginRunnerSupervisor.
- Simplified action and command execution logic in send_service.py.
- Introduced ComponentQueryService for unified component querying in plugin runtime.
- Enhanced message component handling with new binary component support.
- Improved message sequence construction and detection of outbound message flags.
- Updated methods for sending messages to streamline the process and improve readability.
This commit is contained in:
DrSmoothl
2026-03-23 16:14:13 +08:00
parent d07915eea0
commit 18a0e7664a
15 changed files with 1255 additions and 853 deletions

View File

@@ -1,19 +1,19 @@
from contextlib import suppress
import traceback
import os
from maim_message import MessageBase
from typing import Any, Dict, Optional
import os
import traceback
from maim_message import MessageBase
from src.chat.heart_flow.heartflow_message_processor import HeartFCMessageReceiver
from src.common.logger import get_logger
from src.common.utils.utils_message import MessageUtils
from src.common.utils.utils_session import SessionUtils
from src.chat.heart_flow.heartflow_message_processor import HeartFCMessageReceiver
# from src.chat.brain_chat.PFC.pfc_manager import PFCManager
from src.core.announcement_manager import global_announcement_manager
from src.core.component_registry import component_registry
from src.plugin_runtime.component_query import component_query_service
from .message import SessionMessage
from .chat_manager import chat_manager
@@ -58,16 +58,22 @@ class ChatBot:
logger.error(f"创建PFC聊天失败: {e}")
logger.error(traceback.format_exc())
async def _process_commands(self, message: SessionMessage):
# sourcery skip: use-named-expression
"""使用新插件系统处理命令"""
async def _process_commands(self, message: SessionMessage) -> tuple[bool, Optional[str], bool]:
"""使用统一组件注册表处理命令。
Args:
message: 当前待处理的会话消息。
Returns:
tuple[bool, Optional[str], bool]: ``(是否命中命令, 命令响应文本, 是否继续后续处理)``。
"""
if not message.processed_plain_text:
return False, None, True # 没有文本内容,继续处理消息
try:
text = message.processed_plain_text
# 使用核心组件注册表查找命令
command_result = component_registry.find_command_by_text(text)
# 使用插件运行时统一查询服务查找命令
command_result = component_query_service.find_command_by_text(text)
if command_result:
command_executor, matched_groups, command_info = command_result
plugin_name = command_info.plugin_name
@@ -81,7 +87,7 @@ class ChatBot:
message.is_command = True
# 获取插件配置
plugin_config = component_registry.get_plugin_config(plugin_name)
plugin_config = component_query_service.get_plugin_config(plugin_name)
try:
# 调用命令执行器
@@ -112,88 +118,32 @@ class ChatBot:
# 命令出错时,根据命令的拦截设置决定是否继续处理消息
return True, str(e), False # 出错时继续处理消息
# 没有找到旧系统命令,尝试新版本插件运行时
new_cmd_result = await self._process_new_runtime_command(message)
return new_cmd_result if new_cmd_result is not None else (False, None, True)
return False, None, True
except Exception as e:
logger.error(f"处理命令时出错: {e}")
return False, None, True # 出错时继续处理消息
async def _process_new_runtime_command(self, message: SessionMessage):
"""尝试在新版本插件运行时中查找并执行命令
Returns:
(found, response, continue_processing) 三元组,
或 None 表示新运行时中也未找到匹配命令。
"""
from src.plugin_runtime.integration import get_plugin_runtime_manager
prm = get_plugin_runtime_manager()
if not prm.is_running:
return None
matched = prm.find_command_by_text(message.processed_plain_text)
if matched is None:
return None
command_name = matched["name"]
if message.session_id and command_name in global_announcement_manager.get_disabled_chat_commands(
message.session_id
):
logger.info(f"[新运行时] 用户禁用的命令,跳过处理: {matched['full_name']}")
return False, None, True
message.is_command = True
logger.info(f"[新运行时] 匹配命令: {matched['full_name']}")
try:
resp = await prm.invoke_plugin(
method="plugin.invoke_command",
plugin_id=matched["plugin_id"],
component_name=matched["name"],
args={
"text": message.processed_plain_text,
"stream_id": message.session_id or "",
"matched_groups": matched.get("matched_groups") or {},
},
timeout_ms=30000,
)
payload = resp.payload
success = payload.get("success", False)
cmd_result = payload.get("result")
# 拦截位优先从命令返回值中获取(支持运行时动态决定),
# 回退到组件 metadata 中的静态声明
if isinstance(cmd_result, (list, tuple)) and len(cmd_result) >= 3:
# 命令返回 (found, response_text, intercept_bool) 三元组
response_text = cmd_result[1] if cmd_result[1] is not None else ""
intercept = bool(cmd_result[2])
else:
response_text = cmd_result if cmd_result is not None else ""
intercept = bool(matched["metadata"].get("intercept_message_level", 0))
self._mark_command_message(message, int(intercept))
if success:
logger.info(f"[新运行时] 命令执行成功: {matched['full_name']}")
else:
logger.warning(f"[新运行时] 命令执行失败: {matched['full_name']} - {response_text}")
return True, response_text, not intercept
except Exception as e:
logger.error(f"[新运行时] 执行命令 {matched['full_name']} 异常: {e}", exc_info=True)
return True, str(e), True
@staticmethod
def _mark_command_message(message: SessionMessage, intercept_message_level: int) -> None:
"""标记消息已经被命令链消费。
Args:
message: 待标记的会话消息。
intercept_message_level: 命令设置的拦截级别。
"""
message.is_command = True
message.message_info.additional_config["intercept_message_level"] = intercept_message_level
@staticmethod
def _store_intercepted_command_message(message: SessionMessage) -> None:
"""将被命令链拦截的消息写入数据库。
Args:
message: 已完成命令处理的会话消息。
"""
MessageUtils.store_message_to_db(message)
async def _handle_command_processing_result(