mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-16 01:40:15 +08:00
refactor: remove unused hello command, echo listener, and related tools; add CLI and context enhancements
This commit is contained in:
@@ -1,12 +0,0 @@
|
||||
from astrbot.api.v1.components.command import CommandComponent
|
||||
from astrbot.api.v1.event import AstrMessageEvent, filter
|
||||
from astrbot.api.v1.context import Context
|
||||
|
||||
|
||||
class HelloCommand(CommandComponent):
|
||||
def __init__(self, context: Context):
|
||||
super().__init__(context)
|
||||
|
||||
@filter.command("hello")
|
||||
async def hello(self, event: AstrMessageEvent):
|
||||
yield event.plain_result("Hello, Astrbot!")
|
||||
@@ -1,12 +0,0 @@
|
||||
from astrbot.api.v1.components.listener import ListenerComponent
|
||||
from astrbot.api.v1.event import AstrMessageEvent, filter
|
||||
from astrbot.api.v1.context import Context
|
||||
|
||||
|
||||
class EchoListener(ListenerComponent):
|
||||
def __init__(self, context: Context):
|
||||
super().__init__(context)
|
||||
|
||||
@filter.platform_adapter_type(filter.PlatformAdapterType.ALL)
|
||||
async def on_message(self, event: AstrMessageEvent):
|
||||
yield event.plain_result("Hello, Astrbot!")
|
||||
@@ -1,31 +0,0 @@
|
||||
from mcp.types import CallToolResult
|
||||
from pydantic import Field
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
from astrbot.api.v1.components.agent.tool import FunctionTool
|
||||
from astrbot.api.v1.components.agent import ContextWrapper, AstrAgentContext
|
||||
|
||||
|
||||
@dataclass
|
||||
class HelloWorldTool(FunctionTool):
|
||||
name: str = "hello_world" # 工具名称
|
||||
description: str = "Say hello to the world." # 工具描述
|
||||
parameters: dict = Field(
|
||||
default_factory=lambda: {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"greeting": {
|
||||
"type": "string",
|
||||
"description": "The greeting message.",
|
||||
},
|
||||
},
|
||||
"required": ["greeting"],
|
||||
}
|
||||
) # 工具参数定义,见 OpenAI 官网或 https://json-schema.org/understanding-json-schema/
|
||||
|
||||
async def call(
|
||||
self, context: ContextWrapper[AstrAgentContext], **kwargs
|
||||
) -> str | CallToolResult:
|
||||
# event 在 context.context.event 中可用
|
||||
greeting = kwargs.get("greeting", "Hello")
|
||||
return f"{greeting}, World!" # 也支持 mcp.types.CallToolResult 类型
|
||||
@@ -1,22 +0,0 @@
|
||||
_schema_version: 2
|
||||
name: astrbot_plugin_helloworld
|
||||
display_name: HelloWorld 插件
|
||||
desc: 一个简单的问候插件示例
|
||||
author: Soulter
|
||||
version: 0.1.0
|
||||
components: # 组件列表,将支持自动生成
|
||||
- class: plugin_sample.commands.hello:HelloCommand
|
||||
type: command
|
||||
name: hello
|
||||
description: 发送问候消息
|
||||
subcommands:
|
||||
- name: wow
|
||||
description: 发送 "Hello, Astrbot!" 消息
|
||||
- class: plugin_sample.tools.echo:EchoTool
|
||||
type: llm_tool
|
||||
name: echo_tool
|
||||
description: 回显输入的消息
|
||||
- class: plugin_sample.listeners.message_listener:MessageListener
|
||||
type: listener
|
||||
name: message_logger
|
||||
description: 监听并记录所有消息
|
||||
@@ -7,8 +7,12 @@ requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"aiohttp>=3.13.2",
|
||||
"certifi>=2025.10.5",
|
||||
"click>=8.3.0",
|
||||
"docstring-parser>=0.17.0",
|
||||
"loguru>=0.7.3",
|
||||
"pydantic>=2.12.3",
|
||||
"pyyaml>=6.0.3",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
astr = "astrbot_sdk.cli:cli"
|
||||
|
||||
3
src/astrbot_sdk/cli/__init__.py
Normal file
3
src/astrbot_sdk/cli/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .main import cli
|
||||
|
||||
__all__ = ['cli']
|
||||
50
src/astrbot_sdk/cli/main.py
Normal file
50
src/astrbot_sdk/cli/main.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import asyncio
|
||||
import sys
|
||||
import click
|
||||
from loguru import logger
|
||||
from ..runtime.start_server import amain as run_server
|
||||
|
||||
|
||||
def setup_logger(verbose: bool = False):
|
||||
"""Configure loguru for CLI output"""
|
||||
# Remove default handler
|
||||
logger.remove()
|
||||
|
||||
# Add custom handler with CLI-friendly format
|
||||
log_format = (
|
||||
"<green>{time:HH:mm:ss}</green> | "
|
||||
"<level>{level: <8}</level> | "
|
||||
"<level>{message}</level>"
|
||||
)
|
||||
|
||||
level = "DEBUG" if verbose else "INFO"
|
||||
|
||||
logger.add(
|
||||
sys.stderr,
|
||||
format=log_format,
|
||||
level=level,
|
||||
colorize=True,
|
||||
)
|
||||
|
||||
|
||||
@click.group()
|
||||
@click.option("-v", "--verbose", is_flag=True, help="Enable verbose output")
|
||||
@click.pass_context
|
||||
def cli(ctx, verbose):
|
||||
"""AstrBot SDK CLI"""
|
||||
ctx.ensure_object(dict)
|
||||
ctx.obj["verbose"] = verbose
|
||||
setup_logger(verbose)
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.option("--port", default=8765, help="WebSocket server port", type=int)
|
||||
@click.pass_context
|
||||
def run(ctx, port: int):
|
||||
"""Start the WebSocket server"""
|
||||
logger.info(f"Starting WebSocket server on port {port}...")
|
||||
asyncio.run(run_server(port))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
cli()
|
||||
@@ -6,5 +6,13 @@ class Context(BaseContext):
|
||||
def __init__(self, conversation_manager: ConversationManager):
|
||||
self.conversation_manager = conversation_manager
|
||||
|
||||
def _inject_rpc_handlers(self, runner):
|
||||
setattr(self.conversation_manager, "runner", runner)
|
||||
@classmethod
|
||||
def default_context(cls, runner=None):
|
||||
"""Create a default context instance.
|
||||
|
||||
Args:
|
||||
runner: Optional StarRunner instance to inject into conversation manager.
|
||||
If provided, enables RPC functionality.
|
||||
"""
|
||||
conversation_manager = ConversationManager(runner=runner)
|
||||
return cls(conversation_manager=conversation_manager)
|
||||
|
||||
@@ -3,6 +3,14 @@ from .util import rpc_method
|
||||
|
||||
|
||||
class ConversationManager(BaseConversationManager):
|
||||
def __init__(self, runner=None):
|
||||
"""Initialize ConversationManager.
|
||||
|
||||
Args:
|
||||
runner: Optional StarRunner instance for RPC functionality.
|
||||
"""
|
||||
self.runner = runner
|
||||
|
||||
@rpc_method
|
||||
async def new_conversation(
|
||||
self,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import yaml
|
||||
import importlib
|
||||
import functools
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from loguru import logger
|
||||
from .stars.registry import star_handlers_registry, star_map, star_registry
|
||||
@@ -20,13 +21,21 @@ class StarManager:
|
||||
root_dir (Path | None): The root directory to search for plugin.yaml. Defaults to None, which means the current working directory.
|
||||
"""
|
||||
if root_dir is None:
|
||||
root_dir = Path.cwd().relative_to(Path.cwd())
|
||||
root_dir = Path.cwd()
|
||||
else:
|
||||
root_dir = Path.cwd().joinpath(root_dir).resolve()
|
||||
root_dir = Path(root_dir).resolve()
|
||||
|
||||
path = root_dir / "plugin.yaml"
|
||||
if not path.exists():
|
||||
logger.warning("No plugin.yaml found in the current directory.")
|
||||
return []
|
||||
|
||||
# Add the plugin directory to sys.path so we can import its modules
|
||||
root_dir_str = str(root_dir)
|
||||
if root_dir_str not in sys.path:
|
||||
sys.path.insert(0, root_dir_str)
|
||||
logger.debug(f"Added {root_dir_str} to sys.path")
|
||||
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
data = yaml.safe_load(f)
|
||||
|
||||
@@ -46,7 +55,7 @@ class StarManager:
|
||||
full_name_list = []
|
||||
for comp in components:
|
||||
class_ = comp.get("class", "")
|
||||
print(f"Loading component: {class_}")
|
||||
logger.debug(f"Loading component: {class_}")
|
||||
if not class_:
|
||||
logger.warning(f"Component without class found: {comp}")
|
||||
continue
|
||||
@@ -56,10 +65,7 @@ class StarManager:
|
||||
continue
|
||||
# dynamically register the component
|
||||
try:
|
||||
# we need edit the module path to be relative to the root_dir
|
||||
root_dir_dot = str(root_dir).replace("/", ".").lstrip(".")
|
||||
if root_dir_dot:
|
||||
module_path = f"{root_dir_dot}.{module_path}"
|
||||
logger.debug(f"Importing module: {module_path}")
|
||||
module_type = importlib.import_module(module_path)
|
||||
logger.info(f"Successfully loaded component module: {module_path}")
|
||||
component_cls = getattr(module_type, class_name)
|
||||
|
||||
@@ -10,8 +10,7 @@ from .rpc.jsonrpc import (
|
||||
JSONRPCErrorResponse,
|
||||
JSONRPCErrorData,
|
||||
)
|
||||
from .types import CallHandlerRequest, HandshakeRequest
|
||||
from ..api.event.astr_message_event import AstrMessageEvent
|
||||
from .types import CallHandlerRequest
|
||||
|
||||
|
||||
class StarRunner:
|
||||
|
||||
@@ -4,31 +4,26 @@ from .rpc.server import WebSocketServer
|
||||
from .star_runner import StarRunner
|
||||
from .star_manager import StarManager
|
||||
from ..runtime.api.context import Context
|
||||
from ..runtime.api.conversation_mgr import ConversationManager
|
||||
from loguru import logger
|
||||
|
||||
|
||||
async def amain():
|
||||
server = WebSocketServer(port=8765)
|
||||
conversation_manager = ConversationManager()
|
||||
context = Context(conversation_manager=conversation_manager)
|
||||
async def amain(port: int = 8765):
|
||||
server = WebSocketServer(port=port)
|
||||
runner = StarRunner(server)
|
||||
context._inject_rpc_handlers(runner=runner)
|
||||
context = Context.default_context(runner=runner)
|
||||
star_manager = StarManager(context=context)
|
||||
star_manager.discover_star()
|
||||
await runner.run()
|
||||
|
||||
# 设置停止事件
|
||||
stop_event = asyncio.Event()
|
||||
|
||||
# 注册信号处理器
|
||||
loop = asyncio.get_running_loop()
|
||||
for sig in (signal.SIGTERM, signal.SIGINT):
|
||||
loop.add_signal_handler(sig, stop_event.set)
|
||||
|
||||
print("Server is running. Press Ctrl+C to stop.")
|
||||
logger.info("Server is running. Press Ctrl+C to stop.")
|
||||
|
||||
try:
|
||||
await stop_event.wait()
|
||||
finally:
|
||||
print("Shutting down...")
|
||||
logger.info("Shutting down...")
|
||||
await server.stop()
|
||||
|
||||
@@ -3,4 +3,4 @@ from astrbot_sdk.runtime.start_server import amain
|
||||
import asyncio
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(amain())
|
||||
asyncio.run(amain()) # 使用默认端口 8765
|
||||
|
||||
@@ -5,7 +5,7 @@ desc: 一个简单的问候插件示例
|
||||
author: Soulter
|
||||
version: 0.1.0
|
||||
components: # 组件列表,将支持自动生成
|
||||
- class: test_plugin.commands.hello:HelloCommand
|
||||
- class: commands.hello:HelloCommand
|
||||
type: command
|
||||
name: hello
|
||||
description: 发送问候消息
|
||||
14
uv.lock
generated
14
uv.lock
generated
@@ -125,6 +125,7 @@ source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "aiohttp" },
|
||||
{ name = "certifi" },
|
||||
{ name = "click" },
|
||||
{ name = "docstring-parser" },
|
||||
{ name = "loguru" },
|
||||
{ name = "pydantic" },
|
||||
@@ -135,6 +136,7 @@ dependencies = [
|
||||
requires-dist = [
|
||||
{ name = "aiohttp", specifier = ">=3.13.2" },
|
||||
{ name = "certifi", specifier = ">=2025.10.5" },
|
||||
{ name = "click", specifier = ">=8.3.0" },
|
||||
{ name = "docstring-parser", specifier = ">=0.17.0" },
|
||||
{ name = "loguru", specifier = ">=0.7.3" },
|
||||
{ name = "pydantic", specifier = ">=2.12.3" },
|
||||
@@ -159,6 +161,18 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/37/af0d2ef3967ac0d6113837b44a4f0bfe1328c2b9763bd5b1744520e5cfed/certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de", size = 163286 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
|
||||
Reference in New Issue
Block a user