Files
mai-bot/src/plugin_runtime/capabilities/data.py
DawnARC bd84e500e1 feat:新增记忆测试、检索工具与服务
新增完整的长期记忆支持及测试:引入中文记忆检索提示词、query_long_term_memory 检索工具、记忆服务与记忆流程服务,以及 WebUI 的记忆路由。新增大规模测试套件(包括单元测试与基准/在线测试),覆盖聊天历史摘要、知识获取器、事件(episode)生成、写回机制以及用户画像检索等功能。

更新多个模块以集成记忆检索能力(包括 knowledge fetcher、chat summarizer、memory_retrieval、person_info、config/legacy 迁移以及 WebUI 路由),并移除遗留的 lpmm 知识模块。这些变更完成了记忆运行时的接入,同时为基准测试提供嵌入适配器的 mock,并支持新测试与工具所需的导入与 episode 处理流程。
2026-03-18 21:35:17 +08:00

684 lines
31 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 pathlib import Path
from typing import Any, Dict, List, Optional
import random
import time
from src.chat.message_receive.chat_manager import BotChatSession, chat_manager
from src.common.data_models.image_data_model import MaiEmoji
from src.common.logger import get_logger
from src.common.utils.utils_image import ImageUtils
logger = get_logger("plugin_runtime.integration")
class RuntimeDataCapabilityMixin:
@staticmethod
def _serialize_emoji_payload(emoji: MaiEmoji) -> Optional[Dict[str, str]]:
emoji_base64 = ImageUtils.image_path_to_base64(str(emoji.full_path))
if not emoji_base64:
return None
matched_emotion = emoji.emotion[0] if emoji.emotion else ""
return {
"base64": emoji_base64,
"description": emoji.description,
"emotion": matched_emotion,
}
@staticmethod
def _build_emoji_temp_path() -> Path:
from src.chat.emoji_system.emoji_manager import EMOJI_DIR
EMOJI_DIR.mkdir(parents=True, exist_ok=True)
return EMOJI_DIR / f"emoji_cap_{int(time.time() * 1000000)}.png"
async def _cap_database_query(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.services import database_service
model_name: str = args.get("model_name", "")
if not model_name:
return {"success": False, "error": "缺少必要参数 model_name"}
try:
import src.common.database.database_model as db_models
model_class = getattr(db_models, model_name, None)
if model_class is None:
return {"success": False, "error": f"未找到数据模型: {model_name}"}
query_type = args.get("query_type", "get")
if query_type == "get":
result = await database_service.db_get(
model_class=model_class,
filters=args.get("filters"),
limit=args.get("limit"),
order_by=args.get("order_by"),
single_result=args.get("single_result", False),
)
elif query_type == "create":
if not (data := args.get("data")):
return {"success": False, "error": "create 需要 data"}
result = await database_service.db_save(model_class=model_class, data=data)
elif query_type == "update":
if not (data := args.get("data")):
return {"success": False, "error": "update 需要 data"}
result = await database_service.db_update(
model_class=model_class,
data=data,
filters=args.get("filters"),
)
elif query_type == "delete":
result = await database_service.db_delete(model_class=model_class, filters=args.get("filters"))
elif query_type == "count":
result = await database_service.db_count(model_class=model_class, filters=args.get("filters"))
else:
return {"success": False, "error": f"不支持的 query_type: {query_type}"}
return {"success": True, "result": result}
except Exception as e:
logger.error(f"[cap.database.query] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_database_save(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.services import database_service
model_name: str = args.get("model_name", "")
data: Optional[Dict[str, Any]] = args.get("data")
if not model_name or not data:
return {"success": False, "error": "缺少必要参数 model_name 或 data"}
try:
import src.common.database.database_model as db_models
model_class = getattr(db_models, model_name, None)
if model_class is None:
return {"success": False, "error": f"未找到数据模型: {model_name}"}
result = await database_service.db_save(
model_class=model_class,
data=data,
key_field=args.get("key_field"),
key_value=args.get("key_value"),
)
return {"success": True, "result": result}
except Exception as e:
logger.error(f"[cap.database.save] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_database_get(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.services import database_service
model_name: str = args.get("model_name", "")
if not model_name:
return {"success": False, "error": "缺少必要参数 model_name"}
try:
import src.common.database.database_model as db_models
model_class = getattr(db_models, model_name, None)
if model_class is None:
return {"success": False, "error": f"未找到数据模型: {model_name}"}
result = await database_service.db_get(
model_class=model_class,
filters=args.get("filters"),
limit=args.get("limit"),
order_by=args.get("order_by"),
single_result=args.get("single_result", False),
)
return {"success": True, "result": result}
except Exception as e:
logger.error(f"[cap.database.get] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_database_delete(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.services import database_service
model_name: str = args.get("model_name", "")
filters = args.get("filters", {})
if not model_name:
return {"success": False, "error": "缺少必要参数 model_name"}
if not filters:
return {"success": False, "error": "缺少必要参数 filters不允许无条件删除"}
try:
import src.common.database.database_model as db_models
model_class = getattr(db_models, model_name, None)
if model_class is None:
return {"success": False, "error": f"未找到数据模型: {model_name}"}
result = await database_service.db_delete(model_class=model_class, filters=filters)
return {"success": True, "result": result}
except Exception as e:
logger.error(f"[cap.database.delete] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_database_count(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.services import database_service
model_name: str = args.get("model_name", "")
if not model_name:
return {"success": False, "error": "缺少必要参数 model_name"}
try:
import src.common.database.database_model as db_models
model_class = getattr(db_models, model_name, None)
if model_class is None:
return {"success": False, "error": f"未找到数据模型: {model_name}"}
result = await database_service.db_count(model_class=model_class, filters=args.get("filters"))
return {"success": True, "count": result}
except Exception as e:
logger.error(f"[cap.database.count] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
def _list_sessions(self, platform: str, is_group_session: Optional[bool] = None) -> List[BotChatSession]:
return [
session
for session in chat_manager.sessions.values()
if (platform == "all_platforms" or session.platform == platform)
and (is_group_session is None or session.is_group_session == is_group_session)
]
@staticmethod
def _serialize_stream(stream: BotChatSession) -> Dict[str, Any]:
return {
"session_id": stream.session_id,
"platform": stream.platform,
"user_id": stream.user_id,
"group_id": stream.group_id,
"is_group_session": stream.is_group_session,
}
async def _cap_chat_get_all_streams(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
platform: str = args.get("platform", "qq")
try:
streams = self._list_sessions(platform=platform)
return {"success": True, "streams": [self._serialize_stream(item) for item in streams]}
except Exception as e:
logger.error(f"[cap.chat.get_all_streams] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_chat_get_group_streams(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
platform: str = args.get("platform", "qq")
try:
streams = self._list_sessions(platform=platform, is_group_session=True)
return {"success": True, "streams": [self._serialize_stream(item) for item in streams]}
except Exception as e:
logger.error(f"[cap.chat.get_group_streams] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_chat_get_private_streams(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
platform: str = args.get("platform", "qq")
try:
streams = self._list_sessions(platform=platform, is_group_session=False)
return {"success": True, "streams": [self._serialize_stream(item) for item in streams]}
except Exception as e:
logger.error(f"[cap.chat.get_private_streams] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_chat_get_stream_by_group_id(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
group_id: str = args.get("group_id", "")
if not group_id:
return {"success": False, "error": "缺少必要参数 group_id"}
platform: str = args.get("platform", "qq")
try:
stream = next(
(
item
for item in self._list_sessions(platform=platform, is_group_session=True)
if str(item.group_id) == str(group_id)
),
None,
)
return {"success": True, "stream": None if stream is None else self._serialize_stream(stream)}
except Exception as e:
logger.error(f"[cap.chat.get_stream_by_group_id] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_chat_get_stream_by_user_id(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
user_id: str = args.get("user_id", "")
if not user_id:
return {"success": False, "error": "缺少必要参数 user_id"}
platform: str = args.get("platform", "qq")
try:
stream = next(
(
item
for item in self._list_sessions(platform=platform, is_group_session=False)
if str(item.user_id) == str(user_id)
),
None,
)
return {"success": True, "stream": None if stream is None else self._serialize_stream(stream)}
except Exception as e:
logger.error(f"[cap.chat.get_stream_by_user_id] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
@staticmethod
def _serialize_messages(messages: list) -> List[Any]:
result: List[Any] = []
for msg in messages:
if hasattr(msg, "model_dump"):
result.append(msg.model_dump())
elif hasattr(msg, "__dict__"):
result.append(dict(msg.__dict__))
else:
result.append(str(msg))
return result
async def _cap_message_get_by_time(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.services import message_service
try:
messages = message_service.get_messages_by_time(
start_time=float(args.get("start_time", 0.0)),
end_time=float(args.get("end_time", 0.0)),
limit=args.get("limit", 0),
limit_mode=args.get("limit_mode", "latest"),
filter_mai=args.get("filter_mai", False),
)
return {"success": True, "messages": self._serialize_messages(messages)}
except Exception as e:
logger.error(f"[cap.message.get_by_time] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_message_get_by_time_in_chat(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.services import message_service
chat_id: str = args.get("chat_id", "")
if not chat_id:
return {"success": False, "error": "缺少必要参数 chat_id"}
try:
messages = message_service.get_messages_by_time_in_chat(
chat_id=chat_id,
start_time=float(args.get("start_time", 0.0)),
end_time=float(args.get("end_time", 0.0)),
limit=args.get("limit", 0),
limit_mode=args.get("limit_mode", "latest"),
filter_mai=args.get("filter_mai", False),
filter_command=args.get("filter_command", False),
)
return {"success": True, "messages": self._serialize_messages(messages)}
except Exception as e:
logger.error(f"[cap.message.get_by_time_in_chat] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_message_get_recent(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.services import message_service
chat_id: str = args.get("chat_id", "")
if not chat_id:
return {"success": False, "error": "缺少必要参数 chat_id"}
try:
hours = float(args.get("hours", 24.0))
if hours < 0:
return {"success": False, "error": "hours 不能是负数"}
current_time = time.time()
messages = message_service.get_messages_by_time_in_chat(
chat_id=chat_id,
start_time=current_time - hours * 3600,
end_time=current_time,
limit=args.get("limit", 100),
limit_mode=args.get("limit_mode", "latest"),
filter_mai=args.get("filter_mai", False),
)
return {"success": True, "messages": self._serialize_messages(messages)}
except Exception as e:
logger.error(f"[cap.message.get_recent] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_message_count_new(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.services import message_service
chat_id: str = args.get("chat_id", "")
if not chat_id:
return {"success": False, "error": "缺少必要参数 chat_id"}
try:
since = args.get("since")
start_time = float(since) if since is not None else float(args.get("start_time", 0.0))
count = message_service.count_new_messages(
chat_id=chat_id,
start_time=start_time,
end_time=args.get("end_time"),
)
return {"success": True, "count": count}
except Exception as e:
logger.error(f"[cap.message.count_new] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_message_build_readable(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.services import message_service
try:
messages = args.get("messages")
if messages is None:
if not (chat_id := args.get("chat_id", "")):
return {"success": False, "error": "缺少必要参数: messages 或 chat_id"}
messages = message_service.get_messages_by_time_in_chat(
chat_id=chat_id,
start_time=float(args.get("start_time", 0.0)),
end_time=float(args.get("end_time", 0.0)),
limit=args.get("limit", 0),
)
readable = message_service.build_readable_messages(
messages=messages,
replace_bot_name=args.get("replace_bot_name", True),
timestamp_mode=args.get("timestamp_mode", "relative"),
truncate=args.get("truncate", False),
)
return {"success": True, "text": readable}
except Exception as e:
logger.error(f"[cap.message.build_readable] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_person_get_id(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.person_info.person_info import Person
platform: str = args.get("platform", "")
user_id = args.get("user_id", "")
if not platform or not user_id:
return {"success": False, "error": "缺少必要参数 platform 或 user_id"}
try:
pid = Person(platform=platform, user_id=str(user_id)).person_id
return {"success": True, "person_id": pid}
except Exception as e:
logger.error(f"[cap.person.get_id] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_person_get_value(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.person_info.person_info import Person
person_id: str = args.get("person_id", "")
field_name: str = args.get("field_name", "")
if not person_id or not field_name:
return {"success": False, "error": "缺少必要参数 person_id 或 field_name"}
try:
person = Person(person_id=person_id)
value = getattr(person, field_name)
if value is None:
value = args.get("default")
return {"success": True, "value": value}
except Exception as e:
logger.error(f"[cap.person.get_value] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_person_get_id_by_name(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.person_info.person_info import Person
person_name: str = args.get("person_name", "")
if not person_name:
return {"success": False, "error": "缺少必要参数 person_name"}
try:
pid = Person(person_name=person_name).person_id
return {"success": True, "person_id": pid}
except Exception as e:
logger.error(f"[cap.person.get_id_by_name] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_emoji_get_by_description(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.chat.emoji_system.emoji_manager import emoji_manager
description: str = args.get("description", "")
if not description:
return {"success": False, "error": "缺少必要参数 description"}
try:
emoji = await emoji_manager.get_emoji_for_emotion(description)
if emoji is None:
return {"success": True, "emoji": None}
serialized = self._serialize_emoji_payload(emoji)
if serialized is None:
return {"success": True, "emoji": None}
return {
"success": True,
"emoji": serialized,
}
except Exception as e:
logger.error(f"[cap.emoji.get_by_description] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_emoji_get_random(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.chat.emoji_system.emoji_manager import emoji_manager
count: int = args.get("count", 1)
try:
if count < 0:
return {"success": False, "error": "count 不能为负数"}
emojis_source = list(emoji_manager.emojis)
if count == 0 or not emojis_source:
return {"success": True, "emojis": []}
selected = random.sample(emojis_source, min(count, len(emojis_source)))
emojis: List[Dict[str, str]] = []
for emoji in selected:
emoji_manager.update_emoji_usage(emoji)
serialized = self._serialize_emoji_payload(emoji)
if serialized is not None:
if not serialized["emotion"]:
serialized["emotion"] = "随机表情"
emojis.append(serialized)
return {"success": True, "emojis": emojis}
except Exception as e:
logger.error(f"[cap.emoji.get_random] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_emoji_get_count(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
try:
from src.chat.emoji_system.emoji_manager import emoji_manager
return {"success": True, "count": len(emoji_manager.emojis)}
except Exception as e:
logger.error(f"[cap.emoji.get_count] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_emoji_get_emotions(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
try:
from src.chat.emoji_system.emoji_manager import emoji_manager
emotions = sorted({emotion for emoji in emoji_manager.emojis for emotion in emoji.emotion})
return {"success": True, "emotions": emotions}
except Exception as e:
logger.error(f"[cap.emoji.get_emotions] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_emoji_get_all(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
try:
from src.chat.emoji_system.emoji_manager import emoji_manager
emojis = []
for emoji in emoji_manager.emojis:
serialized = self._serialize_emoji_payload(emoji)
if serialized is not None:
if not serialized["emotion"]:
serialized["emotion"] = "随机表情"
emojis.append(serialized)
return {"success": True, "emojis": emojis}
except Exception as e:
logger.error(f"[cap.emoji.get_all] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_emoji_get_info(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
try:
from src.chat.emoji_system.emoji_manager import emoji_manager
from src.config.config import global_config
current_count = len(emoji_manager.emojis)
return {
"success": True,
"info": {
"current_count": current_count,
"max_count": global_config.emoji.max_reg_num,
"available_emojis": current_count,
},
}
except Exception as e:
logger.error(f"[cap.emoji.get_info] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_emoji_register(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.chat.emoji_system.emoji_manager import emoji_manager
emoji_base64: str = args.get("emoji_base64", "")
if not emoji_base64:
return {"success": False, "error": "缺少必要参数 emoji_base64"}
try:
count_before = len(emoji_manager.emojis)
temp_file_path = self._build_emoji_temp_path()
if not ImageUtils.base64_to_image(emoji_base64, str(temp_file_path)):
return {"success": False, "message": "无法保存图片文件", "description": None, "emotions": None, "replaced": None, "hash": None}
register_success = await emoji_manager.register_emoji_by_filename(temp_file_path)
if not register_success:
if temp_file_path.exists():
temp_file_path.unlink(missing_ok=True)
return {
"success": False,
"message": "表情包注册失败,可能因为重复、格式不支持或审核未通过",
"description": None,
"emotions": None,
"replaced": None,
"hash": None,
}
count_after = len(emoji_manager.emojis)
replaced = count_after <= count_before
new_emoji = next(
(
item
for item in reversed(emoji_manager.emojis)
if temp_file_path.name == item.file_name or temp_file_path.name in str(item.full_path)
),
None,
)
return {
"success": True,
"message": f"表情包注册成功 {'(替换旧表情包)' if replaced else '(新增表情包)'}",
"description": None if new_emoji is None else new_emoji.description,
"emotions": None if new_emoji is None else new_emoji.emotion,
"replaced": replaced,
"hash": None if new_emoji is None else new_emoji.file_hash,
}
except Exception as e:
logger.error(f"[cap.emoji.register] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_emoji_delete(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.chat.emoji_system.emoji_manager import emoji_manager
emoji_hash: str = args.get("emoji_hash", "")
if not emoji_hash:
return {"success": False, "error": "缺少必要参数 emoji_hash"}
try:
emoji = emoji_manager.get_emoji_by_hash(emoji_hash)
if emoji is None:
return {"success": False, "message": f"未找到表情包: {emoji_hash}", "hash": emoji_hash}
success = emoji_manager.delete_emoji(emoji, not bool(emoji.description and emoji.description.strip()))
if not success:
return {"success": False, "message": f"删除表情包失败: {emoji_hash}", "hash": emoji_hash}
emoji_manager.emojis = [item for item in emoji_manager.emojis if item.file_hash != emoji_hash]
emoji_manager._emoji_num = len(emoji_manager.emojis)
return {"success": True, "message": f"成功删除表情包: {emoji_hash}", "hash": emoji_hash}
except Exception as e:
logger.error(f"[cap.emoji.delete] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
@staticmethod
def _get_frequency_adjust_value(chat_id: str) -> float:
from src.chat.heart_flow.heartflow_manager import heartflow_manager
heartflow_chat = heartflow_manager.heartflow_chat_list.get(chat_id)
return 1.0 if heartflow_chat is None else heartflow_chat._talk_frequency_adjust
async def _cap_frequency_get_current_talk_value(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.common.utils.utils_config import ChatConfigUtils
chat_id: str = args.get("chat_id", "")
if not chat_id:
return {"success": False, "error": "缺少必要参数 chat_id"}
try:
value = self._get_frequency_adjust_value(chat_id) * ChatConfigUtils.get_talk_value(chat_id)
return {"success": True, "value": value}
except Exception as e:
logger.error(f"[cap.frequency.get_current_talk_value] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_frequency_set_adjust(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.chat.heart_flow.heartflow_manager import heartflow_manager
chat_id: str = args.get("chat_id", "")
value = args.get("value")
if not chat_id or value is None:
return {"success": False, "error": "缺少必要参数 chat_id 或 value"}
try:
heartflow_manager.adjust_talk_frequency(chat_id, float(value))
return {"success": True}
except Exception as e:
logger.error(f"[cap.frequency.set_adjust] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_frequency_get_adjust(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
chat_id: str = args.get("chat_id", "")
if not chat_id:
return {"success": False, "error": "缺少必要参数 chat_id"}
try:
value = self._get_frequency_adjust_value(chat_id)
return {"success": True, "value": value}
except Exception as e:
logger.error(f"[cap.frequency.get_adjust] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_tool_get_definitions(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
from src.core.component_registry import component_registry as core_registry
try:
tools = core_registry.get_llm_available_tools()
return {
"success": True,
"tools": [{"name": name, "definition": info.get_llm_definition()} for name, info in tools.items()],
}
except Exception as e:
logger.error(f"[cap.tool.get_definitions] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}
async def _cap_knowledge_search(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
query: str = args.get("query", "")
if not query:
return {"success": False, "error": "缺少必要参数 query"}
limit = args.get("limit", 5)
try:
limit_value = max(1, int(limit))
except (TypeError, ValueError):
limit_value = 5
try:
from src.services.memory_service import memory_service
result = await memory_service.search(query, limit=limit_value)
knowledge_info = result.to_text(limit=limit_value)
content = f"你知道这些知识: {knowledge_info}" if knowledge_info else f"你不太了解有关{query}的知识"
return {"success": True, "content": content}
except Exception as e:
logger.error(f"[cap.knowledge.search] 执行失败: {e}", exc_info=True)
return {"success": False, "error": str(e)}