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,30 +1,32 @@
from datetime import datetime
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple
import json
import time
import traceback
import random
import re
from typing import Dict, Optional, Tuple, List, TYPE_CHECKING
from rich.traceback import install
from datetime import datetime
from json_repair import repair_json
import time
import traceback
from json_repair import repair_json
from rich.traceback import install
from src.llm_models.utils_model import LLMRequest
from src.config.config import global_config, model_config
from src.common.logger import get_logger
from src.chat.logger.plan_reply_logger import PlanReplyLogger
from src.chat.message_receive.chat_manager import chat_manager as _chat_manager
from src.chat.planner_actions.action_manager import ActionManager
from src.chat.utils.utils import get_chat_type_and_target_info
from src.common.data_models.info_data_model import ActionPlannerInfo
from src.common.logger import get_logger
from src.common.utils.utils_action import ActionUtils
from src.config.config import global_config, model_config
from src.core.types import ActionActivationType, ActionInfo, ComponentType
from src.llm_models.utils_model import LLMRequest
from src.plugin_runtime.component_query import component_query_service
from src.prompt.prompt_manager import prompt_manager
from src.services.message_service import (
build_readable_messages_with_id,
get_actions_by_timestamp_with_chat,
get_messages_before_time_in_chat,
)
from src.chat.utils.utils import get_chat_type_and_target_info
from src.chat.planner_actions.action_manager import ActionManager
from src.chat.message_receive.chat_manager import chat_manager as _chat_manager
from src.core.types import ActionActivationType, ActionInfo, ComponentType
from src.core.component_registry import component_registry
if TYPE_CHECKING:
from src.common.data_models.info_data_model import TargetPersonInfo
@@ -320,7 +322,7 @@ class BrainPlanner:
current_available_actions_dict = self.action_manager.get_using_actions()
# 获取完整的动作信息
all_registered_actions: Dict[str, ActionInfo] = component_registry.get_components_by_type( # type: ignore
all_registered_actions: Dict[str, ActionInfo] = component_query_service.get_components_by_type( # type: ignore
ComponentType.ACTION
)
current_available_actions = {}

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(

View File

@@ -3,8 +3,8 @@ from typing import Dict, Optional, Tuple
from src.chat.message_receive.chat_manager import BotChatSession
from src.chat.message_receive.message import SessionMessage
from src.common.logger import get_logger
from src.core.component_registry import component_registry, ActionExecutor
from src.core.types import ActionInfo
from src.plugin_runtime.component_query import ActionExecutor, component_query_service
logger = get_logger("action_manager")
@@ -28,7 +28,7 @@ class ActionManager:
"""
动作管理器,用于管理各种类型的动作
使用核心组件注册表的 executor-based 模式。
使用插件运行时统一查询服务的 executor-based 模式。
"""
def __init__(self):
@@ -38,7 +38,7 @@ class ActionManager:
self._using_actions: Dict[str, ActionInfo] = {}
# 初始化时将默认动作加载到使用中的动作
self._using_actions = component_registry.get_default_actions()
self._using_actions = component_query_service.get_default_actions()
# === 执行Action方法 ===
@@ -72,17 +72,17 @@ class ActionManager:
Optional[ActionHandle]: 执行句柄,如果动作未注册则返回 None
"""
try:
executor = component_registry.get_action_executor(action_name)
executor = component_query_service.get_action_executor(action_name)
if not executor:
logger.warning(f"{log_prefix} 未找到Action组件: {action_name}")
return None
info = component_registry.get_action_info(action_name)
info = component_query_service.get_action_info(action_name)
if not info:
logger.warning(f"{log_prefix} 未找到Action组件信息: {action_name}")
return None
plugin_config = component_registry.get_plugin_config(info.plugin_name) or {}
plugin_config = component_query_service.get_plugin_config(info.plugin_name) or {}
handle = ActionHandle(
executor,
@@ -133,5 +133,5 @@ class ActionManager:
def restore_actions(self) -> None:
"""恢复到默认动作集"""
actions_to_restore = list(self._using_actions.keys())
self._using_actions = component_registry.get_default_actions()
self._using_actions = component_query_service.get_default_actions()
logger.debug(f"恢复动作集: 从 {actions_to_restore} 恢复到默认动作集 {list(self._using_actions.keys())}")

View File

@@ -1,33 +1,36 @@
from collections import OrderedDict
from datetime import datetime
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Union
import contextlib
import json
import time
import traceback
import random
import re
import contextlib
from typing import Dict, Optional, Tuple, List, TYPE_CHECKING, Union
from collections import OrderedDict
from rich.traceback import install
from datetime import datetime
import time
import traceback
from json_repair import repair_json
from src.llm_models.utils_model import LLMRequest
from src.config.config import global_config, model_config
from src.common.logger import get_logger
from rich.traceback import install
from src.chat.logger.plan_reply_logger import PlanReplyLogger
from src.chat.message_receive.chat_manager import chat_manager as _chat_manager
from src.chat.message_receive.message import SessionMessage
from src.chat.planner_actions.action_manager import ActionManager
from src.chat.utils.utils import get_chat_type_and_target_info, is_bot_self
from src.common.data_models.info_data_model import ActionPlannerInfo
from src.common.logger import get_logger
from src.config.config import global_config, model_config
from src.core.types import ActionActivationType, ActionInfo, ComponentType
from src.llm_models.utils_model import LLMRequest
from src.person_info.person_info import Person
from src.plugin_runtime.component_query import component_query_service
from src.prompt.prompt_manager import prompt_manager
from src.services.message_service import (
build_readable_messages_with_id,
replace_user_references,
get_messages_before_time_in_chat,
replace_user_references,
translate_pid_to_description,
)
from src.chat.utils.utils import get_chat_type_and_target_info, is_bot_self
from src.chat.planner_actions.action_manager import ActionManager
from src.chat.message_receive.chat_manager import chat_manager as _chat_manager
from src.chat.message_receive.message import SessionMessage
from src.core.types import ActionActivationType, ActionInfo, ComponentType
from src.core.component_registry import component_registry
from src.person_info.person_info import Person
if TYPE_CHECKING:
from src.common.data_models.info_data_model import TargetPersonInfo
@@ -634,7 +637,7 @@ class ActionPlanner:
current_available_actions_dict = self.action_manager.get_using_actions()
# 获取完整的动作信息
all_registered_actions: Dict[str, ActionInfo] = component_registry.get_components_by_type( # type: ignore
all_registered_actions: Dict[str, ActionInfo] = component_query_service.get_components_by_type( # type: ignore
ComponentType.ACTION
)
current_available_actions = {}

View File

@@ -1,22 +1,20 @@
"""
工具执行器
"""工具执行器。
独立的工具执行组件,可以直接输入聊天消息内容,
自动判断并执行相应的工具,返回结构化的工具执行结果。
从 src.plugin_system.core.tool_use 迁移,使用新的核心组件注册表。
"""
from typing import Any, Dict, List, Optional, Tuple
import hashlib
import time
from typing import Any, Dict, List, Optional, Tuple
from src.common.logger import get_logger
from src.config.config import global_config, model_config
from src.core.announcement_manager import global_announcement_manager
from src.core.component_registry import component_registry
from src.llm_models.payload_content import ToolCall
from src.llm_models.utils_model import LLMRequest
from src.plugin_runtime.component_query import component_query_service
from src.prompt.prompt_manager import prompt_manager
logger = get_logger("tool_use")
@@ -89,7 +87,7 @@ class ToolExecutor:
def _get_tool_definitions(self) -> List[Dict[str, Any]]:
"""获取 LLM 可用的工具定义列表"""
all_tools = component_registry.get_llm_available_tools()
all_tools = component_query_service.get_llm_available_tools()
user_disabled_tools = global_announcement_manager.get_disabled_chat_tools(self.chat_id)
return [info.get_llm_definition() for name, info in all_tools.items() if name not in user_disabled_tools]
@@ -152,7 +150,7 @@ class ToolExecutor:
function_args = tool_call.args or {}
function_args["llm_called"] = True
executor = component_registry.get_tool_executor(function_name)
executor = component_query_service.get_tool_executor(function_name)
if not executor:
logger.warning(f"未知工具名称: {function_name}")
return None