Files
AstrBot/src-new/astrbot_sdk/events.py
whatevertogo 9c5ecf0a13 feat: Enhance plugin capability support and legacy compatibility
- Introduced LoadedCapability class to manage plugin capabilities.
- Updated load_plugin function to discover and load capabilities alongside handlers.
- Enhanced Peer class to handle remote provided capabilities during initialization.
- Added tests for capability registration and invocation in legacy plugins.
- Improved MessageChain and message component handling in legacy plugins.
- Added comprehensive tests for legacy plugin integration and compatibility.
- Updated protocol messages to include provided capabilities in initialization.
- Enhanced top-level module imports to include capability-related functions.
2026-03-13 06:16:57 +08:00

120 lines
3.6 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.
"""v4 原生事件对象。
顶层 ``MessageEvent`` 保持精简,只承载 v4 运行时真正需要的基础能力。
旧版 ``AstrMessageEvent`` 的便捷方法与结果对象由
``astrbot_sdk.api.event`` 兼容层承接,而不是继续塞回顶层事件类型。
"""
from __future__ import annotations
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
from .protocol.descriptors import SessionRef
if TYPE_CHECKING:
from .context import Context
@dataclass(slots=True)
class PlainTextResult:
text: str
ReplyHandler = Callable[[str], Awaitable[None]]
class MessageEvent:
def __init__(
self,
*,
text: str = "",
user_id: str | None = None,
group_id: str | None = None,
platform: str | None = None,
session_id: str | None = None,
raw: dict[str, Any] | None = None,
context: "Context | None" = None,
reply_handler: ReplyHandler | None = None,
) -> None:
self.text = text
self.user_id = user_id
self.group_id = group_id
self.platform = platform
self.session_id = session_id or group_id or user_id or ""
self.raw = raw or {}
self._context = context
self._reply_handler = reply_handler
if self._reply_handler is None and context is not None:
self._reply_handler = lambda text: context.platform.send(
self.session_ref or self.session_id,
text,
)
@classmethod
def from_payload(
cls,
payload: dict[str, Any],
*,
context: "Context | None" = None,
reply_handler: ReplyHandler | None = None,
) -> "MessageEvent":
target_payload = payload.get("target")
session_id = payload.get("session_id")
platform = payload.get("platform")
if isinstance(target_payload, dict):
target = SessionRef.model_validate(target_payload)
session_id = session_id or target.session
platform = platform or target.platform
return cls(
text=str(payload.get("text", "")),
user_id=payload.get("user_id"),
group_id=payload.get("group_id"),
platform=platform,
session_id=session_id,
raw=payload,
context=context,
reply_handler=reply_handler,
)
def to_payload(self) -> dict[str, Any]:
payload = dict(self.raw)
payload.update(
{
"text": self.text,
"user_id": self.user_id,
"group_id": self.group_id,
"platform": self.platform,
"session_id": self.session_id,
}
)
if self.session_ref is not None:
payload["target"] = self.session_ref.to_payload()
return payload
@property
def session_ref(self) -> SessionRef | None:
if not self.session_id:
return None
return SessionRef(
conversation_id=self.session_id,
platform=self.platform,
raw=self.raw or None,
)
@property
def target(self) -> SessionRef | None:
return self.session_ref
async def reply(self, text: str) -> None:
if self._reply_handler is None:
raise RuntimeError("MessageEvent 未绑定 reply handler无法 reply")
await self._reply_handler(text)
def bind_reply_handler(self, reply_handler: ReplyHandler) -> None:
self._reply_handler = reply_handler
def plain_result(self, text: str) -> PlainTextResult:
return PlainTextResult(text=text)