Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
Platform,
PlatformMetadata,
)
from astrbot.core import sp
from astrbot.core.message.components import BaseMessageComponent
from astrbot.core.platform.astr_message_event import MessageSesion
from astrbot.core.utils.media_utils import MediaResolver
Expand Down Expand Up @@ -204,7 +205,7 @@ async def on_group_at_message_create(
)
abm.group_id = cast(str, message.group_openid)
abm.session_id = abm.group_id
self.platform.remember_session_scene(abm.session_id, "group")
await self.platform.remember_session_scene(abm.session_id, "group")
self._commit(abm)

async def on_group_message_create(
Expand All @@ -216,7 +217,7 @@ async def on_group_message_create(
)
abm.group_id = cast(str, message.group_openid)
abm.session_id = abm.group_id
self.platform.remember_session_scene(abm.session_id, "group")
await self.platform.remember_session_scene(abm.session_id, "group")
self._commit(abm)

# 收到频道消息
Expand All @@ -227,7 +228,7 @@ async def on_at_message_create(self, message: botpy.message.Message) -> None:
)
abm.group_id = message.channel_id
abm.session_id = abm.group_id
self.platform.remember_session_scene(abm.session_id, "channel")
await self.platform.remember_session_scene(abm.session_id, "channel")
self._commit(abm)

# 收到私聊消息
Expand All @@ -239,7 +240,7 @@ async def on_direct_message_create(
MessageType.FRIEND_MESSAGE,
)
abm.session_id = abm.sender.user_id
self.platform.remember_session_scene(abm.session_id, "friend")
await self.platform.remember_session_scene(abm.session_id, "friend")
self._commit(abm)

# 收到 C2C 消息
Expand All @@ -249,7 +250,7 @@ async def on_c2c_message_create(self, message: botpy.message.C2CMessage) -> None
MessageType.FRIEND_MESSAGE,
)
abm.session_id = abm.sender.user_id
self.platform.remember_session_scene(abm.session_id, "friend")
await self.platform.remember_session_scene(abm.session_id, "friend")
self._commit(abm)

def _commit(self, abm: AstrBotMessage) -> None:
Expand Down Expand Up @@ -321,7 +322,6 @@ def __init__(

self._session_last_message_id: dict[str, str] = {}
self._session_scene: dict[str, str] = {}
self._allow_group_proactive_send = True

self.test_mode = os.environ.get("TEST_MODE", "off") == "on"

Expand All @@ -345,6 +345,9 @@ async def _send_by_session_common(

Returns:
None.

Raises:
ValueError: The group or channel delivery scene is unknown.
"""
if session.message_type == MessageType.GROUP_MESSAGE:
session = MessageSesion(
Expand Down Expand Up @@ -380,24 +383,22 @@ async def _send_by_session_common(
):
return

# 主动推送不需要 msg_id,见 https://github.com/AstrBotDevs/AstrBot/issues/7904
msg_id = self._session_last_message_id.get(session.session_id)
scene = self._session_scene.get(session.session_id)
allow_group_proactive_send = (
session.message_type == MessageType.GROUP_MESSAGE
and scene == "group"
and getattr(self, "_allow_group_proactive_send", False)
)
if (
not msg_id
and session.message_type != MessageType.FRIEND_MESSAGE
and not allow_group_proactive_send
):
logger.warning(
"[QQOfficial] No cached msg_id for session: %s, skip send_by_session",
session.session_id,
)
return
if session.message_type == MessageType.GROUP_MESSAGE:
if scene is None:
scene = await sp.get_async(
"qqofficial",
f"{self.meta().id}:{self.appid}",
f"group_scene:{session.session_id}",
None,
)
if scene not in ("group", "channel"):
raise ValueError(
"[QQOfficial] Unknown delivery scene for session "
f"{session.session_id}; receive a message from this group or "
"channel first to establish its route."
)
self._session_scene[session.session_id] = scene

use_md = getattr(message_chain, "use_markdown_", None)
if use_md is False or (use_md is None and not self.use_markdown_default):
Expand All @@ -407,8 +408,7 @@ async def _send_by_session_common(
"markdown": MarkdownPayload(content=plain_text) if plain_text else None,
"msg_type": 2,
}
if msg_id and not allow_group_proactive_send:
payload["msg_id"] = msg_id
# Session sends are proactive; cached reply IDs may be expired.
ret: Any = None
send_helper = SimpleNamespace(bot=self.client)

Expand Down Expand Up @@ -567,9 +567,31 @@ def remember_session_message_id(self, session_id: str, message_id: str) -> None:
return
self._session_last_message_id[session_id] = message_id

def remember_session_scene(self, session_id: str, scene: str) -> None:
async def remember_session_scene(self, session_id: str, scene: str) -> None:
"""Persist group delivery routes before dispatching incoming events.

Args:
session_id: Raw group OpenID, channel ID, or private sender ID.
scene: Delivery scene reported by the incoming event.
"""
if not session_id or not scene:
return
if self._session_scene.get(session_id) == scene:
return
if scene in ("group", "channel"):
try:
await sp.put_async(
"qqofficial",
f"{self.meta().id}:{self.appid}",
f"group_scene:{session_id}",
scene,
)
except Exception:
logger.exception(
"[QQOfficial] Failed to persist delivery scene for session %s",
session_id,
)
raise
self._session_scene[session_id] = scene

def _extract_message_id(self, ret: Any) -> str | None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ async def on_group_at_message_create(
)
abm.group_id = cast(str, message.group_openid)
abm.session_id = abm.group_id
self.platform.remember_session_scene(abm.session_id, "group")
await self.platform.remember_session_scene(abm.session_id, "group")
self._commit(abm)

async def on_group_message_create(
Expand All @@ -53,7 +53,7 @@ async def on_group_message_create(
)
abm.group_id = cast(str, message.group_openid)
abm.session_id = abm.group_id
self.platform.remember_session_scene(abm.session_id, "group")
await self.platform.remember_session_scene(abm.session_id, "group")
self._commit(abm)

# 收到频道消息
Expand All @@ -64,7 +64,7 @@ async def on_at_message_create(self, message: botpy.message.Message) -> None:
)
abm.group_id = message.channel_id
abm.session_id = abm.group_id
self.platform.remember_session_scene(abm.session_id, "channel")
await self.platform.remember_session_scene(abm.session_id, "channel")
self._commit(abm)

# 收到私聊消息
Expand All @@ -76,7 +76,7 @@ async def on_direct_message_create(
MessageType.FRIEND_MESSAGE,
)
abm.session_id = abm.sender.user_id
self.platform.remember_session_scene(abm.session_id, "friend")
await self.platform.remember_session_scene(abm.session_id, "friend")
self._commit(abm)

# 收到 C2C 消息
Expand All @@ -86,7 +86,7 @@ async def on_c2c_message_create(self, message: botpy.message.C2CMessage) -> None
MessageType.FRIEND_MESSAGE,
)
abm.session_id = abm.sender.user_id
self.platform.remember_session_scene(abm.session_id, "friend")
await self.platform.remember_session_scene(abm.session_id, "friend")
self._commit(abm)

def _commit(self, abm: AstrBotMessage) -> None:
Expand Down Expand Up @@ -125,7 +125,6 @@ def __init__(
self.webhook_helper = None
self._session_last_message_id: dict[str, str] = {}
self._session_scene: dict[str, str] = {}
self._allow_group_proactive_send = True

async def send_by_session(
self,
Expand All @@ -143,10 +142,16 @@ def remember_session_message_id(self, session_id: str, message_id: str) -> None:
return
self._session_last_message_id[session_id] = message_id

def remember_session_scene(self, session_id: str, scene: str) -> None:
if not session_id or not scene:
return
self._session_scene[session_id] = scene
async def remember_session_scene(self, session_id: str, scene: str) -> None:
"""Persist a delivery route using the shared QQ Official implementation.

Args:
session_id: Raw destination ID reported by QQ.
scene: Delivery scene reported by the incoming event.
"""
await QQOfficialPlatformAdapter.remember_session_scene(
cast(Any, self), session_id, scene
)

def _extract_message_id(self, ret: Any) -> str | None:
if isinstance(ret, dict):
Expand Down
4 changes: 2 additions & 2 deletions astrbot/core/star/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -626,11 +626,11 @@ async def send_message(
是否找到匹配的平台。

Raises:
ValueError: session 字符串不合法时抛出。
ValueError: The session string is invalid or the adapter cannot resolve
its delivery route.

Note:
当 session 为字符串时,会尝试解析为 MessageSession 对象。(类名为MessageSesion是因为历史遗留拼写错误)
qq_official(QQ 官方 API 平台) 不支持此方法。
"""
if isinstance(session, str):
try:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_qqofficial_group_message_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ async def test_group_message_create_handler_maps_group_session_and_scene():
remembered_ids: list[tuple[str, str]] = []

class PlatformStub:
def remember_session_scene(self, session_id: str, scene: str) -> None:
async def remember_session_scene(self, session_id: str, scene: str) -> None:
remembered_scenes.append((session_id, scene))

def remember_session_message_id(self, session_id: str, message_id: str) -> None:
Expand Down
Loading