diff --git a/astrbot/core/platform/sources/misskey/misskey_adapter.py b/astrbot/core/platform/sources/misskey/misskey_adapter.py index 8c7f1b42f..981d05c82 100644 --- a/astrbot/core/platform/sources/misskey/misskey_adapter.py +++ b/astrbot/core/platform/sources/misskey/misskey_adapter.py @@ -1,6 +1,5 @@ import asyncio import random -import json from typing import Dict, Any, Optional, Awaitable, List from astrbot.api import logger @@ -270,10 +269,10 @@ async def _start_websocket_connection(self): async def _handle_notification(self, data: Dict[str, Any]): try: + notification_type = data.get("type") logger.debug( - f"[Misskey] 收到通知事件:\n{json.dumps(data, indent=2, ensure_ascii=False)}" + f"[Misskey] 收到通知事件: type={notification_type}, user_id={data.get('userId', 'unknown')}" ) - notification_type = data.get("type") if notification_type in ["mention", "reply", "quote"]: note = data.get("note") if note and self._is_bot_mentioned(note): @@ -294,17 +293,16 @@ async def _handle_notification(self, data: Dict[str, Any]): async def _handle_chat_message(self, data: Dict[str, Any]): try: - logger.debug( - f"[Misskey] 收到聊天事件数据:\n{json.dumps(data, indent=2, ensure_ascii=False)}" - ) - sender_id = str( data.get("fromUserId", "") or data.get("fromUser", {}).get("id", "") ) + room_id = data.get("toRoomId") + logger.debug( + f"[Misskey] 收到聊天事件: sender_id={sender_id}, room_id={room_id}, is_self={sender_id == self.client_self_id}" + ) if sender_id == self.client_self_id: return - room_id = data.get("toRoomId") if room_id: raw_text = data.get("text", "") logger.debug( @@ -329,8 +327,9 @@ async def _handle_chat_message(self, data: Dict[str, Any]): logger.error(f"[Misskey] 处理聊天消息失败: {e}") async def _debug_handler(self, data: Dict[str, Any]): + event_type = data.get("type", "unknown") logger.debug( - f"[Misskey] 收到未处理事件:\n{json.dumps(data, indent=2, ensure_ascii=False)}" + f"[Misskey] 收到未处理事件: type={event_type}, channel={data.get('channel', 'unknown')}" ) def _is_bot_mentioned(self, note: Dict[str, Any]) -> bool: @@ -365,7 +364,18 @@ async def send_by_session( text, has_at_user = serialize_message_chain(message_chain.chain) if not has_at_user and session_id: - user_info = self._user_cache.get(session_id) + # 从session_id中提取用户ID用于缓存查询 + # session_id格式为: "chat%" 或 "room%" 或 "note%" + user_id_for_cache = None + if "%" in session_id: + parts = session_id.split("%") + if len(parts) >= 2: + user_id_for_cache = parts[1] + + user_info = None + if user_id_for_cache: + user_info = self._user_cache.get(user_id_for_cache) + text = add_at_mention_if_needed(text, user_info, has_at_user) # 检查是否有文件组件 @@ -560,6 +570,10 @@ async def _upload_comp(comp) -> Optional[object]: user_id_for_cache = ( session_id.split("%")[1] if "%" in session_id else session_id ) + + # 获取用户缓存信息(包含reply_to_note_id) + user_info_for_reply = self._user_cache.get(user_id_for_cache, {}) + visibility, visible_user_ids = resolve_message_visibility( user_id=user_id_for_cache, user_cache=self._user_cache, @@ -575,12 +589,16 @@ async def _upload_comp(comp) -> Optional[object]: appended = "\n" + "\n".join(fallback_urls) text = (text or "") + appended + # 从缓存中获取原消息ID作为reply_id + reply_id = user_info_for_reply.get("reply_to_note_id") + await self.api.create_note( text=text, visibility=visibility, visible_user_ids=visible_user_ids, file_ids=file_ids or None, local_only=self.local_only, + reply_id=reply_id, # 添加reply_id参数 cw=fields["cw"], poll=fields["poll"], renote_id=fields["renote_id"], diff --git a/astrbot/core/platform/sources/misskey/misskey_api.py b/astrbot/core/platform/sources/misskey/misskey_api.py index 0c3334ef6..4b920508f 100644 --- a/astrbot/core/platform/sources/misskey/misskey_api.py +++ b/astrbot/core/platform/sources/misskey/misskey_api.py @@ -222,10 +222,6 @@ def _build_channel_summary(message_type: Optional[str], body: Any) -> str: channel_summary = _build_channel_summary(message_type, body) logger.info(channel_summary) - logger.debug( - f"[Misskey WebSocket] 收到完整消息: {json.dumps(data, indent=2, ensure_ascii=False)}" - ) - if message_type == "channel": channel_id = body.get("id") event_type = body.get("type") diff --git a/astrbot/core/platform/sources/misskey/misskey_utils.py b/astrbot/core/platform/sources/misskey/misskey_utils.py index d10b29431..ebc95d8d7 100644 --- a/astrbot/core/platform/sources/misskey/misskey_utils.py +++ b/astrbot/core/platform/sources/misskey/misskey_utils.py @@ -84,7 +84,12 @@ def process_component(component): return "[图片]" elif isinstance(component, Comp.At): has_at = True - return f"@{component.qq}" + # 优先使用name字段(用户名),如果没有则使用qq字段 + # 这样可以避免在Misskey中生成 @ 这样的无效提及 + if hasattr(component, "name") and component.name: + return f"@{component.name}" + else: + return f"@{component.qq}" elif hasattr(component, "text"): text = getattr(component, "text", "") if "@" in text: @@ -233,21 +238,22 @@ def extract_room_id_from_session_id(session_id: str) -> str: def add_at_mention_if_needed( text: str, user_info: Optional[Dict[str, Any]], has_at: bool = False ) -> str: - """如果需要且没有@用户,则添加@用户""" + """如果需要且没有@用户,则添加@用户 + + 注意:仅在有有效的username时才添加@提及,避免使用用户ID + """ if has_at or not user_info: return text username = user_info.get("username") - nickname = user_info.get("nickname") + # 如果没有username,则不添加@提及,返回原文本 + # 这样可以避免生成 @ 这样的无效提及 + if not username: + return text - if username: - mention = f"@{username}" - if not text.startswith(mention): - text = f"{mention}\n{text}".strip() - elif nickname: - mention = f"@{nickname}" - if not text.startswith(mention): - text = f"{mention}\n{text}".strip() + mention = f"@{username}" + if not text.startswith(mention): + text = f"{mention}\n{text}".strip() return text @@ -403,6 +409,8 @@ def cache_user_info( "nickname": sender_info["nickname"], "visibility": raw_data.get("visibility", "public"), "visible_user_ids": raw_data.get("visibleUserIds", []), + # 保存原消息ID,用于回复时作为reply_id + "reply_to_note_id": raw_data.get("id"), } user_cache[sender_info["sender_id"]] = user_cache_data