Files
AstrBot/test_plugin/old/commands/hello.py
2026-03-13 07:40:42 +08:00

268 lines
10 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.
"""旧版插件兼容测试夹具。
这个样例故意覆盖当前仍被兼容层支持的旧 API
- CommandComponent / AstrMessageEvent / MessageChain
- filter.command / regex / permission / permission_type /
event_message_type / platform_adapter_type
- LegacyContext 的 conversation_manager / llm_generate / tool_loop_agent /
send_message / put|get|delete_kv_data / call_context_function
- 消息组件及其旧字段别名/工厂方法
"""
from __future__ import annotations
from astrbot_sdk import provide_capability
from astrbot_sdk.api.components.command import CommandComponent
from astrbot_sdk.api.event import AstrMessageEvent, filter
from astrbot_sdk.api.event.filter import (
ADMIN,
EventMessageType,
PermissionType,
PlatformAdapterType,
)
from astrbot_sdk.api.message import MessageChain
from astrbot_sdk.api.message_components import (
At,
AtAll,
Face,
File,
Image,
Node,
Plain,
Record,
Reply,
Video,
)
from astrbot_sdk.api.star.context import Context
from loguru import logger
class CompatHelper:
__compat_component_name__ = "CompatHelper"
async def shout(self, text: str) -> str:
return text.upper()
class HelloCommand(CommandComponent):
"""测试旧版 CommandComponent 兼容性。"""
def __init__(self, context: Context):
self.context = context
self.context._register_component(CompatHelper())
@filter.command("hello", alias={"hi"}, priority=10, desc="问候命令")
async def hello(self, event: AstrMessageEvent):
"""基本命令测试。"""
ret = await self.context.conversation_manager.new_conversation("hello")
logger.info("New conversation created: {}", ret)
yield event.plain_result(f"Hello, Astrbot! Created conversation ID: {ret}")
@filter.command("echo")
async def echo(self, event: AstrMessageEvent):
"""测试消息获取和 extra 状态。"""
text = event.get_message_str()
event.set_extra("last_echo", text)
extra = event.get_extra("last_echo")
event.clear_extra()
group = await event.get_group()
yield event.plain_result(
f"Echo: {text}|sender={event.get_sender_id()}|sender_name={event.get_sender_name()}|"
f"platform={event.get_platform_name()}:{event.get_platform_id()}|"
f"type={event.get_message_type().value}|messages={len(event.get_messages())}|"
f"self={event.get_self_id()}|private={event.is_private_chat()}|"
f"wake={event.is_wake_up()}|group={group is not None}|extra={extra}"
)
@filter.command("chain")
async def test_chain(self, event: AstrMessageEvent):
"""测试 MessageChain 构建、发送与 react。"""
chain = (
MessageChain()
.message("Hello")
.message(" ")
.at("user", "12345")
.at_all()
.message(" check this image: ")
.url_image("https://example.com/test.png")
.file_image("C:/tmp/test.png")
.base64_image("base64://fixture")
.use_t2i(True)
.squash_plain()
)
await event.send(chain)
await event.react(":thumbsup:")
yield event.plain_result(
f"Chain sent with {len(chain.to_payload())} components and t2i={chain.use_t2i_}"
)
@filter.command("db")
async def test_db(self, event: AstrMessageEvent):
"""测试 KV 数据库操作。"""
await self.context.put_kv_data("test_key", {"value": "test_data"})
data = await self.context.get_kv_data("test_key")
await self.context.delete_kv_data("test_key")
deleted = await self.context.get_kv_data("test_key", "missing")
logger.info("Got data from db: {}", data)
yield event.plain_result(f"DB test: stored={data} deleted={deleted}")
@filter.command("conversation")
async def test_conversation(self, event: AstrMessageEvent):
"""测试会话管理器和 call_context_function。"""
umo = f"platform:{event.get_session_id()}"
cid = await self.context.conversation_manager.new_conversation(
unified_msg_origin=umo,
title="Compat Chat",
persona_id="assistant",
)
await self.context.conversation_manager.add_message_pair(cid, "hello", "world")
await self.context.conversation_manager.update_conversation(
unified_msg_origin=umo,
conversation_id=cid,
title="Compat Chat Updated",
)
await self.context.conversation_manager.update_conversation_title(umo, "Compat")
await self.context.conversation_manager.update_conversation_persona_id(
umo,
"compat-persona",
)
current_id = await self.context.conversation_manager.get_curr_conversation_id(
umo
)
conv = await self.context.conversation_manager.get_conversation(umo, cid)
all_conversations = await self.context.conversation_manager.get_conversations(
umo
)
helper_result = await self.context.call_context_function(
"CompatHelper.shout",
{"text": "compat"},
)
await self.context.conversation_manager.switch_conversation(umo, cid)
await self.context.conversation_manager.delete_conversation(umo, cid)
yield event.plain_result(
f"conversation={current_id}|messages={len((conv or {}).get('content', []))}|"
f"all={len(all_conversations)}|helper={helper_result['data']}"
)
@filter.command("ai")
async def test_ai(self, event: AstrMessageEvent):
"""测试旧版 AI compat 入口。"""
llm_resp = await self.context.llm_generate(
chat_provider_id="provider-demo",
prompt="legacy hello",
contexts=[{"role": "user", "content": "hi"}],
)
agent_resp = await self.context.tool_loop_agent(
chat_provider_id="provider-demo",
prompt="legacy hello",
tools=[{"name": "search"}],
max_steps=3,
)
yield event.plain_result(f"LLM:{llm_resp.text}|AGENT:{agent_resp.text}")
@filter.command("sendmsg")
async def test_send_message(self, event: AstrMessageEvent):
"""测试 LegacyContext.send_message。"""
chain = (
MessageChain()
.message("compat send ")
.at("legacy-user", "10001")
.url_image("https://example.com/send.png")
)
await self.context.send_message(event.get_session_id(), chain)
yield event.plain_result("send_message invoked")
@filter.command("components")
async def test_components(self, event: AstrMessageEvent):
"""测试消息组件和 chain_result/image_result。"""
components = [
Plain(text="Hello"),
At(qq="123", name="legacy_user"),
AtAll(),
Image.fromURL("https://example.com/img.png"),
Image.fromFileSystem("C:/tmp/local.png"),
Record.fromFileSystem("C:/tmp/sound.wav"),
Video.fromURL("https://example.com/video.mp4"),
File(name="demo.txt", file="https://example.com/demo.txt"),
Reply(id="reply-1"),
Node(uin="10001", name="node_user", content=[Plain(text="node")]),
Face(id=1),
]
component_dicts = [component.to_dict() for component in components]
logger.info("Components: {}", component_dicts)
yield event.chain_result(components)
yield event.image_result("https://example.com/components.png")
@filter.command("state")
async def test_event_state(self, event: AstrMessageEvent):
"""测试事件状态方法。"""
result = event.make_result().message("state-ok")
event.set_result(result)
before_stop = event.is_stopped()
event.stop_event()
after_stop = event.is_stopped()
event.continue_event()
after_continue = event.is_stopped()
event.should_call_llm(True)
stored = event.get_result()
event.clear_result()
yield event.plain_result(
f"before={before_stop}|after_stop={after_stop}|after_continue={after_continue}|"
f"call_llm={event.call_llm}|stored={stored is not None}"
)
@filter.regex(r"^ping.*")
async def ping_regex(self, event: AstrMessageEvent):
"""测试正则匹配。"""
yield event.plain_result("Pong from regex!")
@filter.permission(ADMIN)
@filter.command("admin")
async def admin_only(self, event: AstrMessageEvent):
"""测试 permission(ADMIN)。"""
yield event.plain_result(f"Admin command executed by {event.is_admin()}")
@filter.permission_type(PermissionType.ADMIN)
@filter.command("admin_type")
async def admin_type_only(self, event: AstrMessageEvent):
"""测试 permission_type(PermissionType.ADMIN)。"""
yield event.plain_result(f"Admin type command executed by {event.is_admin()}")
@filter.event_message_type(EventMessageType.GROUP_MESSAGE)
async def group_only(self, event: AstrMessageEvent):
"""测试消息类型过滤。"""
yield event.plain_result("Group message received")
@filter.platform_adapter_type(PlatformAdapterType.AIOCQHTTP)
async def cqhttp_only(self, event: AstrMessageEvent):
"""测试平台过滤。"""
yield event.plain_result("CQHttp platform detected")
@provide_capability(
"compat.echo",
description="使用 legacy Context 回显输入文本",
input_schema={
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"],
},
output_schema={
"type": "object",
"properties": {
"echo": {"type": "string"},
"plugin_id": {"type": "string"},
},
"required": ["echo", "plugin_id"],
},
)
async def echo_capability(self, payload: dict):
"""测试旧版插件 capability 能走 LegacyContext。"""
text = str(payload.get("text", ""))
await self.context.put_kv_data("compat_capability", {"text": text})
stored = await self.context.get_kv_data("compat_capability", {})
return {
"echo": str(stored.get("text", "")),
"plugin_id": self.context.plugin_id,
}