Files
astrbot-plugin-dev/skills/astrbot-plugin-development/SKILL.md
2026-05-14 15:17:56 +08:00

4.3 KiB

name, description
name description
astrbot-plugin-development Use when developing, debugging, or fixing AstrBot plugins and encountering import errors, async generator issues, plugin loading failures, or configuration problems

AstrBot Plugin Development

Overview

Reference for common pitfalls, patterns, and conventions when developing AstrBot plugins. For official API docs, see https://docs.astrbot.app/dev/star/plugin-new.html.

Project Structure

astrbot_plugin_<name>/
├── main.py              # Required entry point
├── metadata.yaml         # Required metadata. Include `repo` field for update support.
├── _conf_schema.json     # Optional config schema
├── requirements.txt      # pip deps (use aiohttp, never requests)
├── logo.png             # Optional, 256x256
├── skills/              # Optional bundled skills
└── pages/               # Optional dashboard pages

Critical Pitfalls

1. star decorator — v4 only

Error: cannot import name 'star' from 'astrbot.api.star'

# ❌ Breaks on v3
from astrbot.api.star import Context, Star, star
@star
class MyPlugin(Star): ...

# ✅ Works on v3 and v4
from astrbot.api.star import Context, Star
class MyPlugin(Star): ...

2. Async generator delegation

Error: object async_generator can't be used in 'await' expression

# ❌ A handler with yield is an async generator — can't await it
yield await self._handler(event, ...)

# ✅ Use async for delegation
async for result in self._handler(event, ...):
    yield result

3. Missing repo in metadata.yaml

Error: "没有指定仓库地址" — plugin cannot auto-update.

Fix: Add repo: https://github.com/user/astrbot_plugin_xxx

4. Never use requests

Always use aiohttp or httpx for HTTP. Synchronous requests blocks the event loop.

Configuration

from astrbot.api import AstrBotConfig

class MyPlugin(Star):
    def __init__(self, context: Context, config: AstrBotConfig):
        super().__init__(context)
        self.config = config
        token = config.get("key", "default")

Message Handling Quick Reference

# Filters
@filter.event_message_type(filter.EventMessageType.ALL)        # All messages
@filter.event_message_type(filter.EventMessageType.GROUP_MESSAGE)  # Group only
@filter.platform_adapter_type(filter.PlatformAdapterType.AIOCQHTTP)  # Specific platform
@filter.permission_type(filter.PermissionType.ADMIN)               # Admin only

# Commands
@filter.command("hello")
@filter.command("hello", alias={"hi", "hey"})              # Aliases
@filter.command("add")                                     # /add 1 2 → parsed args
async def add(self, event: AstrMessageEvent, a: int, b: int): ...

@filter.command_group("math")                              # /math add 1 2
def math(): pass
@math.command("add")
async def add(self, event, a: int, b: int): ...

# Sending
yield event.plain_result("text")
yield event.image_result("https://example.com/img.jpg")
event.stop_event()  # Stop propagation, skip LLM

# Active push (outside handlers)
await self.context.send_message(unified_msg_origin, message_chain)

# Event hooks (use event.send(), NOT yield)
@filter.on_llm_request()    # Before LLM: modify req
@filter.on_llm_response()   # After LLM: inspect resp
@filter.on_decorating_result()  # Before sending to platform

Calling LLM

prov_id = await self.context.get_current_chat_provider_id(event.unified_msg_origin)
resp = await self.context.llm_generate(chat_provider_id=prov_id, prompt="Hello")

# Agent with tool loop
resp = await self.context.tool_loop_agent(
    event=event, chat_provider_id=prov_id,
    prompt="Search for X", tools=ToolSet([MyTool()]), max_steps=30,
)

# Register tool globally
self.context.add_llm_tools(MyTool())

Storage

await self.put_kv_data("key", value)
data = await self.get_kv_data("key", default)

# File storage: always use data/plugin_data/<plugin_name>/
from pathlib import Path
from astrbot.core.utils.astrbot_path import get_astrbot_data_path
path = Path(get_astrbot_data_path()) / "plugin_data" / self.name

Debugging

  • Plugins auto-load from data/plugins/<name>/
  • WebUI → Plugins → ... → "重载插件" for hot reload
  • Use from astrbot.api import logger (not print)