Files
AstrBot/src-new/astrbot_sdk/api/message/chain.py
whatevertogo 96ea836edc feat: Enhance legacy API with message chain support and new context handling
- Updated `LegacyContext.send_message` to handle rich message chains using `send_chain`.
- Introduced `LegacyStar` class for backward compatibility with legacy plugins.
- Added `register` decorator for legacy plugin metadata.
- Enhanced `MessageChain` class with `to_payload` and `is_plain_text_only` methods.
- Updated `AstrMessageEvent.send` method to utilize `send_chain` for rich messages.
- Implemented `send_chain` method in `PlatformClient` for sending complex message structures.
- Added capability routing for `platform.send_chain`.
- Introduced tests for new functionality, ensuring compatibility with legacy plugins and message handling.
2026-03-13 05:34:14 +08:00

110 lines
3.3 KiB
Python

"""旧版消息链兼容实现。"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any
from . import components as Comp
@dataclass(slots=True)
class MessageChain:
chain: list[Comp.BaseMessageComponent] = field(default_factory=list)
use_t2i_: bool | None = None
type: str | None = None
def message(self, message: str) -> "MessageChain":
self.chain.append(Comp.Plain(text=message))
return self
def at(self, name: str, qq: str) -> "MessageChain":
self.chain.append(Comp.At(user_id=qq, user_name=name))
return self
def at_all(self) -> "MessageChain":
self.chain.append(Comp.AtAll())
return self
def error(self, message: str) -> "MessageChain":
self.chain.append(Comp.Plain(text=message))
return self
def url_image(self, url: str) -> "MessageChain":
self.chain.append(Comp.Image(file=url))
return self
def file_image(self, path: str) -> "MessageChain":
self.chain.append(Comp.Image(file=path))
return self
def base64_image(self, base64_str: str) -> "MessageChain":
self.chain.append(Comp.Image(file=base64_str))
return self
def use_t2i(self, use_t2i: bool) -> "MessageChain":
self.use_t2i_ = use_t2i
return self
def to_payload(self) -> list[dict[str, Any]]:
payload: list[dict[str, Any]] = []
for component in self.chain:
if isinstance(component, dict):
payload.append(dict(component))
continue
to_dict = getattr(component, "to_dict", None)
if callable(to_dict):
payload.append(to_dict())
continue
model_dump = getattr(component, "model_dump", None)
if callable(model_dump):
payload.append(model_dump())
continue
payload.append({"type": "Unknown", "text": str(component)})
return payload
def is_plain_text_only(self) -> bool:
if not self.chain:
return False
for component in self.chain:
if isinstance(component, Comp.Plain):
continue
if isinstance(component, dict) and str(component.get("type")) in {
"Plain",
"plain",
"text",
}:
continue
return False
return True
def get_plain_text(self) -> str:
return " ".join(
component.text
for component in self.chain
if isinstance(component, Comp.Plain)
)
def squash_plain(self) -> "MessageChain":
if not self.chain:
return self
new_chain: list[Comp.BaseMessageComponent] = []
first_plain: Comp.Plain | None = None
plain_texts: list[str] = []
for component in self.chain:
if isinstance(component, Comp.Plain):
if first_plain is None:
first_plain = component
new_chain.append(component)
plain_texts.append(component.text)
else:
new_chain.append(component)
if first_plain is not None:
first_plain.text = "".join(plain_texts)
self.chain = new_chain
return self