refactor(openspec): restructure protocol specifications

Major changes:
- Add A2A protocol (Google Agent-to-Agent)
- Add ACP protocol (Agent Communication)
- Add MCP protocol (Model Context Protocol)
- Add LSP protocol (Language Server Protocol)
- Add environment variables spec (env.md)
- Add path spec with XDG and Linux server support (path.md)
- Update ABP protocol to plugin-as-service model
- Delete legacy OpenSpec change proposals

New protocol specs:
- a2a.md: Cross-platform agent interoperability
- acp.md: Local agent control (IDE integration)
- mcp.md: AI model to tools/data connection
- lsp.md: Editor language features
- abp.md: AstrBot plugin protocol
- env.md: Environment variable conventions
- path.md: XDG + Linux server paths
This commit is contained in:
LIghtJUNction
2026-03-26 22:58:22 +08:00
parent 6463b451b3
commit 49988912e1
40 changed files with 2221 additions and 2077 deletions

View File

@@ -1,172 +0,0 @@
# AstrBot 架构规范
## 核心原则
1. **anyio 优先**: 所有异步代码必须使用 anyio不是 asyncio
2. **类型安全**: 必须通过 `uvx ty check`,避免 Any 和 cast
3. **代码美观**: 必须通过 `ruff check .``ruff format .`
4. **测试完整**: 新功能必须有对应测试
## 协议系统
```
┌─────────────────────────────────────────────────────────┐
│ Orchestrator (Runtime) │
│ 协调 LSP, MCP, ACP, ABP 协议客户端 │
└─────────────────────────────────────────────────────────┘
┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ LSP │ │ MCP │ │ ACP │
│ Client │ │ Client │ │ Client │
└─────────┘ └─────────┘ └─────────┘
│ │ │
▼ ▼ ▼
LSP Servers MCP Servers ACP Services
┌─────────────────────────────────────────────────┐
│ ABP Client │
│ (进程内 Star (插件) 通信) │
└─────────────────────────────────────────────────┘
┌─────────┐
│ Stars │
│ (插件) │
└─────────┘
```
## ABP 协议 (AstrBot Protocol)
**目标**: 最终实现 ABP 协议
### 已完成
```python
class BaseAstrbotAbpClient(ABC):
connected: bool
async def connect() -> None
def register_star(name: str, instance: Any) -> None
def unregister_star(name: str) -> None
async def call_star_tool(star, tool, args) -> Any
async def shutdown() -> None
```
### 待完成
- ABP 服务端实现
- 完整的 JSON-RPC 2.0 消息格式
- star 心跳和健康检查
- 批量调用支持
## 文件结构
```
astrbot/_internal/
├── abc/ # 抽象基类
│ ├── base_astrbot_gateway.py
│ ├── base_astrbot_orchestrator.py
│ ├── abp/
│ ├── acp/
│ ├── lsp/
│ └── mcp/
├── protocols/ # 协议实现
│ ├── abp/client.py
│ ├── acp/client.py
│ ├── lsp/client.py
│ └── mcp/client.py
├── runtime/
│ └── orchestrator.py # 核心运行时
├── geteway/ # FastAPI 网关
│ ├── server.py
│ └── ws_manager.py
└── tools/
├── base.py
├── builtin.py
└── registry.py
```
## 异步库要求
### 正确 ✓
```python
import anyio
async def run():
async with anyio.create_task_group() as tg:
tg.start_soon(coro1)
tg.start_soon(coro2)
# 等待事件
event = anyio.Event()
await event.wait()
# 锁
lock = anyio.Lock()
async with lock:
...
```
### 错误 ✗
```python
import asyncio # 禁止使用!
# 错误
await asyncio.sleep(1)
asyncio.Lock()
asyncio.CancelledError
```
## 测试要求
测试文件位置: `tests/unit/test_internal/`
必须测试:
1. 每个协议客户端的 connect/disconnect
2. star 注册/注销
3. 工具调用
4. 错误处理
5. 生命周期管理
## 类型标注规范
```python
# Good ✓
async def call_star_tool(
self,
star_name: str,
tool_name: str,
arguments: dict[str, Any],
) -> Any:
...
# Bad ✗
async def call_star_tool(self, star, tool, args): # 没有类型
...
# Acceptable (必要时使用 Any)
async def call_star_tool(
self,
star_name: str,
tool_name: str,
arguments: dict[str, Any], # Any 是允许的因为参数结构可变
) -> Any: # Any 是允许的因为返回类型可变
...
```
## 实践验证记录
### 验证方法
- 集成测试: `test_bootstrap.py` - 验证组件可正常创建和交互
- 单元测试: `pytest tests/unit/test_internal/` - 验证架构合规性
- 协议测试: 针对各协议客户端的实际连接测试
### 已知问题
1. **LSP Client**: 当前使用 `asyncio` 而非 `anyio`,需要重构
2. **ty LSP**: ty server 不支持标准 LSP 协议,不适合作为 LSP 测试目标
3. **ACP Client**: 尚未进行实际连接测试
### 端口配置
| 服务 | 默认端口 | 说明 |
|------|---------|------|
| Gateway | 8765 | FastAPI + WebSocket |
| Dashboard | 6185 | Vue.js 前端 (推测) |

View File

@@ -1,104 +0,0 @@
# AstrBot 开发任务
## 当前最高优先级
### 1. 实践验证 - 让架构真正工作 (P0)
**状态**: 进行中
架构必须经过实际验证,不能只是"代码通过测试"。以下是已验证和待验证项目:
#### ✅ 已验证 (84 tests passed)
| 组件 | 验证方式 | 结果 |
|------|---------|------|
| Orchestrator | `test_bootstrap.py` | ✓ 正常创建所有协议客户端 |
| ABP Client | `test_bootstrap.py` | ✓ Star 注册/注销/调用正常 |
| Gateway | `test_bootstrap.py` | ✓ 启动在 0.0.0.0:8765 |
| WebSocketManager | `test_bootstrap.py` | ✓ anyio.Lock 已修复 |
| MCP Client | `test_architecture_compliance.py` | ✓ 使用 anyio.Lock |
| 架构合规测试 | pytest | ✓ 11 passed |
#### ⚠ 需要修复 (anyio 违规)
| 组件 | 问题 | 状态 |
|------|------|------|
| `lsp/client.py` | 使用 `asyncio.create_subprocess_exec` | 待修复 |
| `lsp/client.py` | 使用 `asyncio.Future` | 待修复 |
#### 🔍 待验证
| 组件 | 验证方式 | 状态 |
|------|---------|------|
| MCP Client | 连接本地 MCP 服务器并调用工具 | 待验证 |
| ACP Client | 连接 ACP 服务并通信 | 待验证 |
| LSP Client + python-lsp-server | 接入标准 LSP 服务器 | 待验证 |
| ty LSP | ty server 不支持标准 LSP 协议 | 不适用 |
### 2. ABP 协议示例开发 (P0)
**目标**: 开发一个可运行的 ABP 协议演示
**计划**:
1. 创建 `examples/abp_demo.py`
2. 演示:
- 创建 Orchestrator
- 注册一个 mock star
- 通过 ABP client 调用 star 工具
- 验证结果
**状态**: 待开始
### 3. 将项目工具转为 MCP 服务器 (P1)
**目标**: 将 builtin_tools (cron_tools, kb_query, send_message) 暴露为 MCP 服务器
**待验证**:
- MCP client 能否连接到本地 MCP 服务器
- 工具调用是否正常工作
---
## 已完成任务
### ✅ anyio 违规修复 (完成)
- `orchestrator.py`: `asyncio.sleep``anyio.sleep`, `asyncio.CancelledError``anyio.get_cancelled_exc_class()`
- `mcp/client.py`: `asyncio.Lock``anyio.Lock`, `asyncio.Event``anyio.Event`
- `lsp/client.py`: import 排序修复
- `gateway/server.py`: 删除死代码 `asyncio.Task``import asyncio`
- `gateway/ws_manager.py`: `asyncio.Lock``anyio.Lock`
### ✅ 架构合规测试 (完成)
- `test_architecture_compliance.py`: 11 个测试全部通过
- 总计: 84 passed, 0 failed
### ✅ Bootstrap 集成测试 (完成)
- `test_bootstrap.py`: 验证所有组件可正常创建和交互
---
## 技术债务
1. **LSP Client 使用 asyncio**
- `lsp/client.py` 使用 `asyncio.create_subprocess_exec``asyncio.Future`
- 需要重构为 anyio
- 影响: LSP 功能不可用
2. **ty LSP 服务器不兼容**
- ty server 启动但不支持标准 `initialize` 请求
- 需要使用 python-lsp-server 进行测试
3. **测试**: `tests/test_dashboard.py::test_auth_login` 失败
- 错误: `AttributeError: 'FuncCall' object has no attribute 'register_internal_tools'`
- 需要在 FuncCall 添加 register_internal_tools 方法或修复引用
---
## 端口说明
| 服务 | 端口 | 状态 |
|------|------|------|
| Gateway (FastAPI) | 8765 | ✓ 已验证可启动 |
| WebSocket | /ws | ✓ 已验证 |
| Dashboard | 6185 (推测) | 待验证 |

334
openspec/a2a.md Normal file
View File

@@ -0,0 +1,334 @@
# A2A (Agent-to-Agent) 协议规范
## 概述
A2AAgent-to-Agent是由 **Google Cloud** 发起的开放协议,旨在促进不同 AI Agent 之间的互操作性。
A2A 得到了超过 50 家技术合作伙伴(如 Atlassian, Box, Cohere, Langchain, MongoDB, PayPal, Salesforce, SAP, ServiceNow 等)的支持。
**核心目标**:让不同供应商构建或使用不同技术框架的 Agent 能在动态、多代理生态系统中进行有效通信和协作。
A2A 专注于"互联互通",与 ACPAgent Communication Protocol形成互补关系。
## 与 ACP 的互补关系
| 维度 | A2A | ACP |
|------|-----|-----|
| 定位 | 跨平台、开放生态 | 本地优先、受控自治 |
| 目标 | 互联互通 | 紧密协同 |
| 场景 | 分布式任务调度、跨厂商系统 | IDE 编码助手、本地进程 |
| 网络 | 互联网、云端 | 本地进程、边缘设备 |
| 透明度 | 不透明Agent 作为黑盒) | 透明(每步可见可控) |
| 控制权 | Agent 主导 | Client 主导 |
## 设计原则
- **拥抱代理能力**:允许 Agent 在自然的、非结构化模式下协作,无需共享内存、工具或上下文
- **基于现有标准**:建立在 HTTP, SSE, JSON-RPC 等广泛接受的标准之上
- **默认安全**:支持企业级身份验证和授权
- **支持长时间运行**:从快速任务到数小时甚至数天的复杂研究
- **模态无关**支持文本、音频、视频流、表单、iframe 等
## 三层模型
### 第一层:数据模型
核心对象:
- **AgentCard** — 描述 Agent 能力的 JSON 文件
- **Task** — 有状态的任务实体
- **Message** — 传递指令、上下文、思考过程
- **Artifact** — 不可变的输出
- **Part** — 原子内容单元
### 第二层:抽象操作
| 方法 | 描述 |
|------|------|
| `SendMessage` | 发送消息 |
| `SendStreamingMessage` | 发送流式消息 |
| `GetTask` | 获取任务状态和结果 |
| `ListTasks` | 列出任务 |
| `CancelTask` | 取消任务 |
| `SubscribeToTask` | 订阅任务更新 |
| `GetExtendedAgentCard` | 获取扩展 AgentCard |
### 第三层:协议绑定
- **JSON-RPC over HTTP**(主要)
- **gRPC**(原生支持)
- **HTTP+JSON/REST**
## 参与者
- **User用户**:使用 Agent 系统完成任务的人类或服务
- **Client客户端**:代表用户向 Agent 请求操作的实体
- **Server服务端**:提供服务的不透明(黑盒)远程 Agent
## 核心数据模型
### AgentCard
托管在 `/.well-known/agent-card.json`,用于服务发现:
```json
{
"name": "research-agent",
"description": "专业的研究分析 Agent",
"version": "1.0.0",
"provider": {
"organization": "Example Corp",
"url": "https://example.com"
},
"capabilities": {
"streaming": true,
"pushNotifications": true,
"extensions": []
},
"skills": [
{
"id": "web-search",
"name": "Web Search",
"tags": ["search", "research"],
"examples": [
{"user": "Search for recent AI news", "agent": "I'll search for recent AI news for you."}
]
}
],
"securitySchemes": {},
"url": "https://api.example.com/a2a"
}
```
### Task
```json
{
"id": "task-001",
"contextId": "session-123",
"status": {
"state": "TASK_STATE_WORKING",
"timestamp": "2024-01-01T00:00:00Z"
},
"artifacts": [
{
"artifactId": "artifact-001",
"name": "report",
"parts": [
{"type": "text", "text": "分析报告内容..."}
]
}
],
"history": [
{
"messageId": "msg-001",
"role": "ROLE_USER",
"parts": [{"type": "text", "text": "分析一下最新 AI 趋势"}]
}
],
"metadata": {}
}
```
**任务状态机8 个状态)**
```
SUBMITTED → WORKING → {
COMPLETED (终态)
FAILED (终态)
CANCELED (终态)
REJECTED (终态)
INPUT_REQUIRED (中断态)
AUTH_REQUIRED (中断态)
}
```
### Message + Part
```json
{
"messageId": "msg-001",
"role": "ROLE_USER",
"parts": [
{"type": "text", "text": "Hello"},
{"type": "file", "file": {"name": "doc.pdf", "uri": "https://..."}},
{"type": "data", "data": {"key": "value"}}
],
"referenceTaskIds": []
}
```
## 消息格式
### SendMessage
```json
{
"jsonrpc": "2.0",
"id": "req-001",
"method": "SendMessage",
"params": {
"message": {
"role": "ROLE_USER",
"parts": [{"type": "text", "text": "分析最新 AI 趋势"}]
},
"taskId": "optional-existing-task-id",
"sessionId": "session-123"
}
}
```
### SendStreamingMessage
```json
{
"jsonrpc": "2.0",
"id": "req-002",
"method": "SendStreamingMessage",
"params": {
"message": {
"role": "ROLE_USER",
"parts": [{"type": "text", "text": "写一段 Python 代码"}]
}
}
}
```
### 流式响应
```
HTTP/1.1 200 OK
Content-Type: text/event-stream
event: message
data: {"task":{"id":"task-1","status":{"state":"TASK_STATE_WORKING"}}}
event: message
data: {"message":{"parts":[{"type":"text","text":"我来帮你"}]}}
event: task
data: {"task":{"id":"task-1","status":{"state":"TASK_STATE_COMPLETED"},"artifacts":[...]}}
```
**v1.0 重要变化**:流式结束不再依赖 `final` 字段,而应依据任务状态和流关闭。
## 传输层
### HTTP(S)/WSS主要
```
POST /a2a HTTP/1.1
Host: api.example.com
Content-Type: application/json
A2A-Version: 1.0.0
{"jsonrpc":"2.0","id":"req-001","method":"SendMessage",...}
```
### gRPC
完整的 gRPC 服务定义,适用于高性能场景。
### 服务发现
```
GET /.well-known/agent-card.json HTTP/1.1
Host: api.example.com
{
"name": "research-agent",
...
}
```
## 安全认证
### 支持的认证方式
- **OAuth 2.0**authorization_code, client_credentials, device_code
- **OpenID Connect**discovery_url
- **API Key**query, header, cookie
- **HTTP Auth**Bearer, Basic
- **Mutual TLS (mTLS)**
### AgentCard 安全声明
```json
{
"securitySchemes": {
"oauth2": {
"type": "oauth2",
"flows": ["authorization_code"],
"authorizationUrl": "https://auth.example.com"
}
},
"securityRequirements": [
{"oauth2": ["read", "write"]}
]
}
```
## 错误码
| 码值 | 名称 | 描述 |
|------|------|------|
| -32700 | Parse Error | 无效的 JSON |
| -32600 | Invalid Request | 格式错误的请求 |
| -32601 | Method Not Found | 未知方法 |
| -32602 | Invalid Params | 无效参数 |
| -32603 | Internal Error | 服务器内部错误 |
| -32100 | Agent Not Found | 未找到 Agent |
| -32101 | Agent Not Ready | Agent 未就绪 |
| -32102 | Task Not Found | 任务不存在 |
| -32103 | Task Timeout | 任务超时 |
| -32104 | Task Canceled | 任务已取消 |
| -32105 | Capability Not Supported | Agent 不支持该能力 |
| -32106 | Authentication Failed | 认证失败 |
| -32107 | Authorization Failed | 授权失败 |
## 适用场景
### 1. 智能客服
- 多轮对话管理
- 知识库集成
- 自动化工单处理
### 2. 开发协作
- 代码审查辅助
- 文档自动化
- 测试用例生成
### 3. 数据分析
- 数据清洗与转换
- 可视化报表生成
- 异常检测与告警
### 4. 企业级 Agent 网络
```
认证网关
┌──────────┼──────────┐
↓ ↓ ↓
HR Agent IT Agent 财务 Agent
```
### 5. Agent Marketplace
```
开发者发布 Agent → AgentCard 注册 → 用户发现和调用
```
## v1.0 迁移注意事项
- **流式结束**:不再依赖 `final` 字段,应依据任务状态和流关闭
- **术语统一**:使用 `canceled`(不是 `cancelled`
- **服务参数**A2A-Version、A2A-Extensions 等需要显式处理
- **taskId 生成**:新任务的 taskId 由服务端生成,客户端不应自造
## 相关资源
- [GitHub 仓库](https://github.com/google-a2a)
- [技术规范](https://google-a2a.github.io/)
- [API 文档](https://a2acn.com/docs/introduction/)

445
openspec/abp.md Normal file
View File

@@ -0,0 +1,445 @@
# ABP (AstrBot Plugin) 协议规范
## 概述
ABP 是 AstrBot 的插件通信协议,用于插件的注册、消息处理、工具调用和生命周期管理。
ABP 采用**插件作为独立服务**的设计,插件通过配置加载,可使用任意编程语言实现。
**核心定位**ABP 定义了 AstrBot 编排器与插件之间的交互接口,支持进程内和跨进程两种加载模式。
## 与 MCP 的关系
| 维度 | ABP | MCP |
|------|-----|-----|
| 定位 | 插件(功能扩展) | 工具/数据源连接 |
| 通信模式 | 双向(消息+工具+事件) | 单向(工具调用+资源访问) |
| 消息处理 | 支持 | 不支持 |
| 生命周期 | 完整 | 轻量 |
| 编程语言 | 任意 | 任意 |
## 加载方式
### 1. 进程内加载In-Process
- **直接函数调用**:无序列化开销,零拷贝
- **适用场景**:内置插件、高频调用、对延迟敏感
### 2. 跨进程加载Out-of-Process
- **独立进程运行**:插件崩溃不影响主进程
- **协议**JSON-RPC 2.0 over Unix Socket / HTTP
- **适用场景**:第三方插件、需要资源隔离
## 插件配置
类似 MCP 服务器配置,在 AstrBot 配置文件中声明插件:
```json
{
"plugins": [
{
"name": "weather-plugin",
"version": "1.0.0",
"load_mode": "out_of_process",
"command": "python",
"args": ["/path/to/weather_server.py"],
"env": {
"API_KEY": "xxx"
}
},
{
"name": "code-analysis",
"load_mode": "out_of_process",
"command": "./code-analysis-server",
"transport": "http",
"url": "http://localhost:9001"
}
]
}
```
**配置字段**
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `name` | string | 是 | 插件名称 |
| `version` | string | 否 | 插件版本 |
| `load_mode` | string | 是 | `in_process``out_of_process` |
| `command` | string | 跨进程时必填 | 启动命令 |
| `args` | array | 跨进程时可选 | 命令参数 |
| `env` | object | 否 | 环境变量 |
| `transport` | string | 跨进程时可选 | `stdio` / `unix_socket` / `http` |
| `url` | string | HTTP 传输时必填 | 服务器地址 |
## 传输协议
### Stdio进程启动
用于进程内加载或通过 stdio 启动的外部插件:
```
{"jsonrpc":"2.0","method":"initialize","params":{...},"id":1}
{"jsonrpc":"2.0","method":"plugin.handle_event","params":{...}}
```
### Unix Socket
```
Content-Length: <字节数>\r\n
\r\n
<json_body>
```
### HTTP/SSE
用于远程插件或需要 Webhook 通知的场景。
## 消息格式
所有消息均为 JSON-RPC 2.0
### 1. 初始化initialize
**请求**
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "1.0.0",
"clientInfo": {
"name": "astrbot",
"version": "4.16.0"
},
"capabilities": {
"streaming": true,
"events": true
}
}
}
```
**响应**
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "1.0.0",
"serverInfo": {
"name": "weather-plugin",
"version": "1.0.0"
},
"capabilities": {
"tools": true,
"handlers": true,
"events": true
},
"metadata": {
"display_name": "天气插件",
"description": "提供天气查询功能",
"author": "Author"
}
}
}
```
### 2. 插件能力
```json
{
"capabilities": {
"tools": true, // 支持工具调用
"handlers": true, // 支持消息处理器
"events": true, // 支持事件订阅
"resources": false // 是否提供资源
}
}
```
### 3. 工具调用(跨进程)
**请求**
```json
{
"jsonrpc": "2.0",
"id": "req-001",
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"location": "北京"
}
}
}
```
**响应**
```json
{
"jsonrpc": "2.0",
"id": "req-001",
"result": {
"content": [
{
"type": "text",
"text": "北京天气25°C"
}
]
}
}
```
### 4. 消息处理
**请求**
```json
{
"jsonrpc": "2.0",
"id": "req-002",
"method": "plugin.handle_event",
"params": {
"event_type": "message",
"event": {
"message_id": "msg-123",
"unified_msg_origin": "telegram:private:12345",
"message_str": "/weather 北京",
"sender": {
"user_id": "12345",
"nickname": "用户"
},
"message_chain": [
{ "type": "plain", "text": "/weather 北京" }
]
}
}
}
```
**响应**
```json
{
"jsonrpc": "2.0",
"id": "req-002",
"result": {
"handled": true,
"results": [
{ "type": "plain", "text": "北京天气25°C" }
],
"stop_propagation": false
}
}
```
### 5. 事件订阅
**通知**(客户端 → 插件):
```json
{
"jsonrpc": "2.0",
"method": "plugin.subscribe",
"params": {
"event_type": "llm_request"
}
}
```
**通知**(插件 → 客户端):
```json
{
"jsonrpc": "2.0",
"method": "plugin.notify",
"params": {
"event_type": "tool_called",
"data": {
"tool": "get_weather",
"args": { "location": "北京" }
}
}
}
```
### 6. 工具列表
**请求**
```json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}
```
**响应**
```json
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "get_weather",
"description": "获取天气信息",
"inputSchema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市名称"
}
},
"required": ["location"]
}
}
]
}
}
```
### 7. 资源(可选)
```json
{
"jsonrpc": "2.0",
"method": "resources/list",
"params": {}
}
```
## 核心方法
### 初始化
| 方法 | 方向 | 描述 |
|------|------|------|
| `initialize` | C→P | 初始化连接 |
| `initialized` | P→C | 初始化完成通知 |
### 生命周期
| 方法 | 方向 | 描述 |
|------|------|------|
| `plugin.start` | C→P | 启动插件 |
| `plugin.stop` | C→P | 停止插件 |
| `plugin.reload` | C→P | 重载插件 |
### 工具
| 方法 | 方向 | 描述 |
|------|------|------|
| `tools/list` | C→P | 列出可用工具 |
| `tools/call` | C→P | 调用工具 |
| `tools/metadata` | P→C | 工具元数据更新 |
### 消息处理
| 方法 | 方向 | 描述 |
|------|------|------|
| `plugin.handle_event` | C→P | 处理事件 |
| `plugin.handle_command` | C→P | 处理命令 |
| `plugin.handle_message` | C→P | 处理消息 |
### 事件
| 方法 | 方向 | 描述 |
|------|------|------|
| `plugin.subscribe` | C→P | 订阅事件 |
| `plugin.unsubscribe` | C→P | 取消订阅 |
| `plugin.notify` | P→C | 发送事件通知 |
## 插件元数据
插件通过 `initialize` 响应返回元数据:
```json
{
"serverInfo": {
"name": "weather-plugin",
"version": "1.0.0"
},
"capabilities": {
"tools": true,
"handlers": true,
"events": true
},
"metadata": {
"display_name": "天气插件",
"description": "提供天气预报功能",
"author": "Author Name",
"homepage": "https://github.com/author/weather-plugin",
"support_platforms": ["telegram", "discord"],
"astrbot_version": ">=4.16,<5"
}
}
```
## 错误码
| 码值 | 名称 | 描述 |
|------|------|------|
| -32700 | Parse Error | 无效的 JSON |
| -32600 | Invalid Request | 格式错误的请求 |
| -32601 | Method Not Found | 未知方法 |
| -32602 | Invalid Params | 无效参数 |
| -32603 | Internal Error | 服务器内部错误 |
| -32200 | Plugin Not Found | 未找到插件 |
| -32201 | Plugin Not Ready | 插件未就绪 |
| -32202 | Plugin Crashed | 插件崩溃 |
| -32203 | Tool Not Found | 未找到工具 |
| -32204 | Tool Call Failed | 工具调用失败 |
| -32205 | Handler Not Found | 未找到处理器 |
| -32206 | Handler Error | 处理器执行错误 |
| -32207 | Event Subscribe Failed | 事件订阅失败 |
| -32208 | Permission Denied | 权限不足 |
| -32209 | Config Error | 配置错误 |
| -32210 | Dependency Missing | 依赖缺失 |
| -32211 | Version Mismatch | 版本不兼容 |
## 进程内插件
对于进程内插件load_mode: in_process编排器直接调用插件方法无需序列化
```python
# 插件直接实现为类
class MyPlugin:
def __init__(self, context):
self.context = context
async def handle_event(self, event):
return [PlainResult("Hello!")]
def get_tools(self):
return [MyTool()]
def get_metadata(self):
return {
"name": "my-plugin",
"version": "1.0.0",
"capabilities": {
"tools": True,
"handlers": True,
"events": False
}
}
```
## 实现注意事项
- 插件是独立服务,通过配置声明式加载
- 支持任意编程语言实现Python、Go、Rust、JavaScript 等)
- 跨进程插件使用标准 JSON-RPC 2.0 通信
- 插件元数据通过 `initialize` 响应动态获取
- 支持热重载:配置更新后可在线重载插件
- 事件通知采用异步机制,不阻塞主流程

153
openspec/acp.md Normal file
View File

@@ -0,0 +1,153 @@
# ACP (Agent Communication Protocol) 协议规范
## 概述
ACP 是一个开放协议,用于多智能体系统中的智能体间通信。
AstrBot 将 ACP 实现为**客户端**,连接到暴露智能体能力的 ACP 服务器/服务。
**参考**: 受 [Google A2A](https://google-a2a.10140099
.io/) (Agent-to-Agent Protocol) 启发
## 架构
```
┌─────────────────────────────────────┐
│ AstrBot (ACP 客户端) │
└─────────────────────────────────────┘
│ JSON-RPC 2.0
┌─────────────────────────────────────┐
│ ACP 服务器/服务 │
│ - 智能体注册表 │
│ - 任务委托 │
│ - 状态同步 │
└─────────────────────────────────────┘
```
## 传输层
### TCP 传输
- **适用场景**: 本地或云端智能体服务
- **协议**: 基于 TCP 的 JSON-RPC 2.0
- **头部**: `Content-Length` 前缀(与 LSP 相同)
### Unix Socket 传输
- **适用场景**: 高性能本地进程间通信
- **协议**: 通过 Unix 域套接字的 JSON-RPC 2.0
## 消息格式
所有消息均为 JSON-RPC 2.0,带 Content-Length 头:
```
Content-Length: <字节数>\r\n
\r\n
<json_body>
```
### 请求
```json
{
"jsonrpc": "2.0",
"id": "唯一标识",
"method": "agent/call",
"params": {
"agent": "智能体名称",
"action": "动作名称",
"args": { ... }
}
}
```
### 响应
```json
{
"jsonrpc": "2.0",
"id": "唯一标识",
"result": {
"status": "success",
"data": { ... }
}
}
```
### 错误
```json
{
"jsonrpc": "2.0",
"id": "唯一标识",
"error": {
"code": -32600,
"message": "无效请求",
"data": { ... }
}
}
```
## 核心方法
### 智能体管理
| 方法 | 描述 |
|------|------|
| `agent/list` | 列出可用智能体 |
| `agent/info` | 获取智能体能力和状态 |
| `agent/call` | 调用智能体的动作 |
| `agent/subscribe` | 订阅智能体事件 |
### 任务操作
| 方法 | 描述 |
|------|------|
| `task/create` | 创建新任务 |
| `task/status` | 获取任务状态 |
| `task/result` | 获取任务结果 |
| `task/cancel` | 取消运行中的任务 |
### 通信
| 方法 | 描述 |
|------|------|
| `message/send` | 向智能体发送消息 |
| `message/broadcast` | 向所有智能体广播 |
## 错误码
| 码值 | 名称 | 描述 |
|------|------|------|
| -32700 | Parse Error | 无效的 JSON |
| -32600 | Invalid Request | 格式错误的请求 |
| -32601 | Method Not Found | 未知方法 |
| -32602 | Invalid Params | 无效参数 |
| -32603 | Internal Error | 服务器错误 |
| -32000 | Agent Not Found | 未找到智能体 |
| -32001 | Agent Busy | 智能体正在处理另一请求 |
| -32002 | Task Not Found | 未找到任务 |
## 智能体发现
智能体公布其能力:
```json
{
"agent": "code-reviewer",
"version": "1.0.0",
"capabilities": ["review", "lint", "suggest"],
"endpoints": {
"tcp": "127.0.0.1:9001",
"unix": "/var/run/acp/code-reviewer.sock"
}
}
```
## 实现注意事项
- ACP 客户端维护多个智能体的连接池
- 请求可按智能体名称或能力路由
- 通过分块传输支持流式响应
- 心跳机制保持连接健康

View File

@@ -1,2 +0,0 @@
schema: spec-driven
created: 2026-03-23

View File

@@ -1,40 +0,0 @@
## Context
The AstrBot core runtime (`_internal` package) manages LSP, MCP, ACP, and ABP protocol clients. Currently there is no way to query the internal state of these components from outside the runtime.
The ABP (AstrBot Protocol) is designed for in-process star communication. By creating a RuntimeStatusStar plugin, we can expose runtime state via ABP tools.
## Goals / Non-Goals
**Goals:**
- Create a RuntimeStatusStar that registers with the orchestrator via ABP
- Expose tools: get_runtime_status, get_protocol_status, get_star_registry, get_stats
- Use anyio for async operations as per project standard
**Non-Goals:**
- Not implementing remote ACP/LSP connections (separate concern)
- Not creating a dashboard UI (future work)
- Not modifying existing protocol client implementations
## Decisions
1. **Star Interface**: Use the existing `Star` base class from `astrbot._internal.stars.base`
- Each star must implement `call_tool(tool_name, arguments)` method
- Stars are registered with the orchestrator via `register_star(name, star_instance)`
2. **Tool Exposure**: Expose runtime status as ABP-callable tools
- `get_runtime_status`: Returns `{running: bool, uptime_seconds: float}`
- `get_protocol_status`: Returns status of each protocol client
- `get_star_registry`: Returns list of registered star names
- `get_stats`: Returns message counts, last activity, etc.
3. **Auto-registration**: Register RuntimeStatusStar in orchestrator.__init__
- This ensures it's available immediately when runtime starts
## Risks / Trade-offs
- **Risk**: Runtime status might be sensitive information
- **Mitigation**: Initially only expose basic stats; add auth later if needed
- **Trade-off**: Polling vs push model for stats
- Decision: Use polling (pull) via ABP call_tool for simplicity

View File

@@ -1,27 +0,0 @@
## Why
Currently the core runtime (_internal package) has no way to expose its internal state (protocol client status, star registry, message counts, etc.) to external consumers. We need an ABP plugin that exposes runtime status as tools that can be called via the ABP protocol.
## What Changes
- Create an ABP plugin (`RuntimeStatusStar`) that registers with the orchestrator via ABP
- Expose runtime status as tools callable via ABP protocol:
- `get_runtime_status`: Returns overall runtime state
- `get_protocol_status`: Returns LSP, MCP, ACP, ABP client states
- `get_star_registry`: Returns list of registered stars
- `get_stats`: Returns message counts, uptime, etc.
- Plugin implements the Star interface required by ABP
## Capabilities
### New Capabilities
- `runtime-status-star`: ABP plugin that exposes core runtime internal state as callable tools
### Modified Capabilities
- (none)
## Impact
- New file: `astrbot/_internal/stars/runtime_status_star.py`
- Modifies: `astrbot/_internal/runtime/orchestrator.py` to register the star
- ABP protocol now can query runtime internals

View File

@@ -1,113 +0,0 @@
# RuntimeStatusStar Specification
## Overview
RuntimeStatusStar is an internal ABP (AstrBot Protocol) star plugin that exposes runtime state information via callable tools. It provides diagnostic capabilities for monitoring the AstrBot core runtime health.
## Tool Interface
### Tools Exposed
All tools follow the ABP tool calling convention via `call_tool(tool_name, arguments)`.
#### 1. get_runtime_status
Returns the current runtime state.
**Arguments:** None
**Returns:**
```json
{
"running": true,
"uptime_seconds": 12345.67
}
```
#### 2. get_protocol_status
Returns the connection state of each protocol client.
**Arguments:** None
**Returns:**
```json
{
"lsp": {"connected": true, "name": "lsp-client"},
"mcp": {"connected": false, "name": "mcp-client"},
"acp": {"connected": true, "name": "acp-client"},
"abp": {"connected": true, "name": "abp-client"}
}
```
#### 3. get_star_registry
Returns the list of registered star names.
**Arguments:** None
**Returns:**
```json
{
"stars": ["runtime-status-star", "star-1", "star-2"]
}
```
#### 4. get_stats
Returns runtime statistics and metrics.
**Arguments:** None
**Returns:**
```json
{
"total_messages": 100,
"last_activity": "2024-01-01T00:00:00Z"
}
```
## Architecture
### Component Hierarchy
```
AstrbotOrchestrator
└── RuntimeStatusStar (auto-registered)
└── Tools: get_runtime_status, get_protocol_status, get_star_registry, get_stats
```
### Auto-Registration
RuntimeStatusStar is instantiated and registered in `AstrbotOrchestrator.__init__()`:
```python
from astrbot._internal.stars.runtime_status_star import RuntimeStatusStar
class AstrbotOrchestrator:
def __init__(self):
self._stars: dict[str, Star] = {}
# Auto-register RuntimeStatusStar
self._runtime_status_star = RuntimeStatusStar(self)
self._stars["runtime-status-star"] = self._runtime_status_star
```
### Orchestrator Reference
RuntimeStatusStar holds a reference to the orchestrator to query state:
```python
class RuntimeStatusStar(Star):
def __init__(self, orchestrator: AstrbotOrchestrator):
self._orchestrator = orchestrator
```
## Implementation Notes
1. **Thread Safety:** The orchestrator may be accessed from multiple contexts. All state queries should be read-only.
2. **Latency:** Tool calls should return immediately without blocking. No polling or long-running operations.
3. **Error Handling:** If any status query fails, return an error message rather than raising an exception.
4. **Future Extensibility:** Additional stats can be added by extending the `get_stats` tool response structure.

View File

@@ -1,39 +0,0 @@
# Runtime Status Star Specification
## ADDED Requirements
### Requirement: RuntimeStatusStar provides diagnostic tools
The RuntimeStatusStar SHALL provide callable tools that expose core runtime internal state for diagnostic purposes.
#### Scenario: Get runtime status
- **WHEN** ABP client calls `get_runtime_status` tool
- **THEN** returns `{"running": bool, "uptime_seconds": float}`
#### Scenario: Get protocol status
- **WHEN** ABP client calls `get_protocol_status` tool
- **THEN** returns status of each protocol client (lsp, mcp, acp, abp)
#### Scenario: Get star registry
- **WHEN** ABP client calls `get_star_registry` tool
- **THEN** returns list of registered star names
#### Scenario: Get stats
- **WHEN** ABP client calls `get_stats` tool
- **THEN** returns runtime statistics including message counts
### Requirement: Auto-registration with orchestrator
The RuntimeStatusStar SHALL be automatically registered with the orchestrator on initialization.
#### Scenario: Orchestrator initialization
- **WHEN** AstrbotOrchestrator is created
- **THEN** RuntimeStatusStar instance is created and registered with name "runtime-status-star"
### Requirement: Error handling
The RuntimeStatusStar tools SHALL handle errors gracefully without exposing internal exceptions.
#### Scenario: Orchestrator unavailable
- **WHEN** orchestrator reference is None
- **THEN** returns appropriate error message instead of raising exception

View File

@@ -1,32 +0,0 @@
## 1. Create Stars Directory
- [x] 1.1 Create `astrbot/_internal/stars/` directory
- [x] 1.2 Create `__init__.py` with exports
## 2. Implement RuntimeStatusStar
- [x] 2.1 Create `runtime_status_star.py` with RuntimeStatusStar class
- [x] 2.2 Implement `call_tool` method with tools:
- `get_runtime_status`: Returns running state and uptime
- `get_protocol_status`: Returns LSP, MCP, ACP, ABP status
- `get_star_registry`: Returns registered star names
- `get_stats`: Returns message counts and metrics
## 3. Register Star with Orchestrator
- [x] 3.1 Import RuntimeStatusStar in orchestrator
- [x] 3.2 Register star instance in orchestrator.__init__
## 4. Write Tests
- [x] 4.1 Create `tests/unit/test_runtime_status_star.py`
- [x] 4.2 Test get_runtime_status tool
- [x] 4.3 Test get_protocol_status tool
- [x] 4.4 Test get_star_registry tool
- [x] 4.5 Test orchestrator auto-registers the star
## 5. Verification
- [x] 5.1 Run ruff check
- [x] 5.2 Run uvx ty check
- [x] 5.3 Run pytest tests/unit/test_runtime_status_star.py

View File

@@ -1,2 +0,0 @@
schema: spec-driven
created: 2026-03-23

View File

@@ -1,117 +0,0 @@
# Design: Internal Integration Tests
## MCP Integration Test Design
### Mock MCP Server
Create a simple stdio-based MCP server for testing:
```python
# tests/integration/fixtures/echo_mcp_server.py
"""
Simple MCP server that echoes back tool calls.
Used for testing the MCP client.
"""
import json
import sys
async def main():
while True:
line = sys.stdin.readline()
if not line:
break
request = json.loads(line)
# Handle initialize
if request.get("method") == "initialize":
print(json.dumps({
"jsonrpc": "2.0",
"id": request.get("id"),
"result": {"protocolVersion": "2024-11-05", "capabilities": {}}
}))
sys.stdout.flush()
# Handle tool call
elif request.get("method") == "tools/call":
params = request.get("params", {})
tool_name = params.get("name", "")
arguments = params.get("arguments", {})
print(json.dumps({
"jsonrpc": "2.0",
"id": request.get("id"),
"result": {"content": [{"type": "text", "text": f"{tool_name}({arguments})"}]}
}))
sys.stdout.flush()
# Handle list tools
elif request.get("method") == "tools/list":
print(json.dumps({
"jsonrpc": "2.0",
"id": request.get("id"),
"result": {"tools": [{"name": "echo", "description": "Echo back input"}]}
}))
sys.stdout.flush()
```
### MCP Client Integration Test
```python
# tests/integration/test_mcp_integration.py
import pytest
import anyio
from astrbot._internal.protocols.mcp.client import McpClient
@pytest.mark.anyio
async def test_mcp_client_connect_to_echo_server():
"""Test MCP client can connect to a real MCP server."""
client = McpClient()
# Start the echo server
server_process = await anyio.open_process(
["python", "tests/integration/fixtures/echo_mcp_server.py"],
stdin=-1, stdout=-1, stderr=-1
)
# Connect client
await client.connect_to_server(
command=["python", "tests/integration/fixtures/echo_mcp_server.py"],
workspace_uri="file:///tmp"
)
# List tools
tools = await client.list_tools()
assert len(tools) > 0
# Call tool
result = await client.call_tool("echo", {"message": "test"})
assert "echo" in result
await client.shutdown()
```
## ACP Integration Test Design
Similar pattern - create a mock ACP server and test the ACP client connects and communicates properly.
## Test Fixtures Location
```
tests/
├── integration/
│ ├── fixtures/
│ │ ├── echo_mcp_server.py
│ │ └── echo_acp_server.py
│ ├── test_mcp_integration.py
│ └── test_acp_integration.py
```
## Running Tests
```bash
# Run all integration tests
uv run pytest tests/integration/ -v
# Run MCP integration only
uv run pytest tests/integration/test_mcp_integration.py -v
```

View File

@@ -1,27 +0,0 @@
# Add Internal Integration Tests
## Problem
The `_internal` architecture claims to support MCP (Model Context Protocol) and ACP (AstrBot Communication Protocol) clients, but these have never been tested with real connections. The ABP demo works, but MCP and ACP remain unverified.
## Solution
Create comprehensive integration tests that:
1. Start a real MCP server (using a simple echo server)
2. Connect the MCP client to it
3. Verify tool listing and calling works
4. Do the same for ACP client
## Why This Matters
- Architecture claims must be validated through tests
- MCP/ACP functionality is blocked by untested assumptions
- Integration tests catch regressions that unit tests miss
- Demonstrates the architecture works in practice
## Scope
- Create `tests/integration/test_mcp_integration.py`
- Create `tests/integration/test_acp_integration.py`
- Use real subprocess servers for testing
- Ensure tests can run in CI

View File

@@ -1,55 +0,0 @@
# Internal Integration Tests Specification
## Overview
Internal integration tests validate the MCP and ACP protocol client implementations against real server fixtures.
## Test Structure
tests/integration/
- fixtures/
- echo_mcp_server.py # Stdio-based MCP echo server
- echo_acp_server.py # TCP/Unix socket ACP echo server
- test_mcp_integration.py # MCP client integration tests
- test_acp_integration.py # ACP client integration tests
## MCP Integration Tests
### Echo MCP Server Fixture
- **Location:** tests/integration/fixtures/echo_mcp_server.py
- **Protocol:** Stdio-based JSON-RPC with Content-Length headers
- **Methods:** initialize, tools/list, tools/call
### MCP Client Tests
| Test | Description | Status |
|------|-------------|--------|
| test_mcp_client_initialization | McpClient instantiation | Passing |
| test_mcp_client_connect_is_noop | connect() without config | Passing |
| test_mcp_echo_server_connection | Connect to echo server | Skipped |
| test_mcp_list_tools | List tools | Skipped |
| test_mcp_call_echo_tool | Call echo tool | Skipped |
**Note:** 3 tests skipped due to MCP ClientSession.initialize() protocol complexity.
## ACP Integration Tests
### Echo ACP Server Fixture
- **Location:** tests/integration/fixtures/echo_acp_server.py
- **Transport:** TCP/Unix socket with Content-Length headers
- **Methods:** initialize, echo, {server}/{tool}
### ACP Client Tests
| Test | Description | Status |
|------|-------------|--------|
| test_acp_client_initial_state | Verify disconnected state | Passing |
| test_acp_client_connect_to_tcp_server | Connect to TCP server | Passing |
| test_acp_client_connect_to_unix_socket | Connect to Unix socket | Passing |
## Running Tests
```bash
uv run pytest tests/integration/ -v
```
## Dependencies
- pytest, pytest-asyncio, anyio

View File

@@ -1,62 +0,0 @@
# Internal Integration Tests Specification
## ADDED Requirements
### Requirement: MCP client integration with echo server
The MCP client SHALL be able to connect to a real MCP echo server fixture and perform tool operations.
#### Scenario: MCP client initialization
- **WHEN** McpClient is instantiated
- **THEN** client exists with `connected = False`
#### Scenario: MCP client connect without config is noop
- **WHEN** `connect()` is called without server configuration
- **THEN** client remains in disconnected state
#### Scenario: MCP client connects to echo server (deferred)
- **WHEN** MCP client attempts to connect to echo MCP server
- **THEN** connection is established and verified
- **NOTE**: Test skipped - MCP ClientSession.initialize() protocol handshake is complex
#### Scenario: MCP client lists tools from server (deferred)
- **WHEN** `list_tools()` is called on connected client
- **THEN** returns list of available tools from server
- **NOTE**: Test skipped due to protocol complexity
#### Scenario: MCP client calls echo tool (deferred)
- **WHEN** `call_tool("echo", {"message": "test"})` is called
- **THEN** returns echoed result
- **NOTE**: Test skipped due to protocol complexity
### Requirement: ACP client integration with echo server
The ACP client SHALL be able to connect to a real ACP echo server fixture over TCP and Unix sockets.
#### Scenario: ACP client initial state
- **WHEN** AstrbotAcpClient is instantiated
- **THEN** `connected = False`, `_reader = None`, `_writer = None`
#### Scenario: ACP client connects to TCP server
- **WHEN** `connect_to_server(host, port)` is called with TCP echo server
- **THEN** client connects successfully with `connected = True`
- **AND** `_reader` and `_writer` are set
#### Scenario: ACP client connects to Unix socket
- **WHEN** `connect_to_unix_socket(socket_path)` is called with Unix socket echo server
- **THEN** client connects successfully with `connected = True`
- **AND** `_reader` and `_writer` are set
### Requirement: Integration test fixtures
The integration test fixtures SHALL provide real protocol servers for testing.
#### Scenario: Echo MCP server handles stdio protocol
- **WHEN** MCP server receives JSON-RPC request on stdin
- **THEN** responds with proper Content-Length headers on stdout
- **AND** handles `initialize`, `tools/list`, `tools/call` methods
#### Scenario: Echo ACP server handles stream protocol
- **WHEN** ACP server receives request on TCP/Unix socket
- **THEN** responds with JSON-RPC responses
- **AND** handles `initialize`, `echo`, and `{server}/{tool}` methods

View File

@@ -1,32 +0,0 @@
# Implementation Tasks
## 1. MCP Echo Server Fixture
- [x] 1.1 Create tests/integration/fixtures/ directory
- [x] 1.2 Create echo_mcp_server.py with initialize, tools/list, tools/call handlers
## 2. MCP Integration Test
- [x] 2.1 Create tests/integration/test_mcp_integration.py
- [x] 2.2 Test MCP client connects to echo server (requires proper MCP stdio handshake)
- [x] 2.3 Test list_tools() returns mock tool
- [x] 2.4 Test call_tool() works correctly
**Note**: MCP echo server fixture created with proper stdio parsing, but MCP ClientSession
protocol handshake requires servers to send capability notifications after initialize.
Tests are marked with @pytest.mark.skip - ACP integration tests (TCP/Unix socket) work fine.
## 3. ACP Echo Server Fixture
- [x] 3.1 ACP server uses TCP/Unix socket (complex setup)
- [x] 3.2 Create ACP echo server fixture (deferred)
## 4. ACP Integration Test
- [x] 4.1 ACP integration tests deferred
- [x] 4.2 ACP client uses asyncio.StreamReader/Writer
## 5. Verification
- [x] 5.1 Run uv run pytest tests/unit/ -v
- [x] 5.2 Verify internal runtime tests pass

View File

@@ -1,2 +0,0 @@
schema: spec-driven
created: 2026-03-24

View File

@@ -1,82 +0,0 @@
# Design: Fix RuntimeStatusStar Spec Compliance
## Problem
The RuntimeStatusStar implementation does not match its specification:
1. `get_protocol_status` should return protocol name along with connected state
2. `get_stats` should return `total_messages` and `last_activity` not just `uptime_seconds`
## Solution
### 1. Update `get_protocol_status`
**Current implementation:**
```python
return {
"lsp": {"connected": getattr(self._orchestrator.lsp, "connected", False)},
"mcp": {"connected": getattr(self._orchestrator.mcp, "connected", False)},
...
}
```
**Fixed implementation:**
```python
return {
"lsp": {
"connected": getattr(self._orchestrator.lsp, "connected", False),
"name": "lsp-client"
},
"mcp": {
"connected": getattr(self._orchestrator.mcp, "connected", False),
"name": "mcp-client"
},
...
}
```
### 2. Update `get_stats` and add message tracking
**Orchestrator changes:**
```python
def __init__(self) -> None:
...
self._message_count = 0
self._last_activity_timestamp: float | None = None
def record_activity(self) -> None:
"""Record a message activity for stats tracking."""
self._message_count += 1
self._last_activity_timestamp = time.time()
```
**RuntimeStatusStar changes:**
```python
def _get_stats(self) -> dict[str, Any]:
last_activity = None
if self._orchestrator and self._orchestrator._last_activity_timestamp:
last_activity = datetime.fromtimestamp(
self._orchestrator._last_activity_timestamp
).isoformat()
return {
"total_messages": getattr(self._orchestrator, "_message_count", 0),
"last_activity": last_activity,
"uptime_seconds": time.time() - self._start_time,
}
```
## Files to Modify
1. `astrbot/_internal/runtime/orchestrator.py`:
- Add `_message_count: int = 0`
- Add `_last_activity_timestamp: float | None = None`
- Add `record_activity()` method
2. `astrbot/_internal/stars/runtime_status_star.py`:
- Update `_get_protocol_status()` to include `name` field
- Update `_get_stats()` to return `total_messages` and `last_activity`
3. `tests/unit/test_runtime_status_star.py`:
- Update `test_get_protocol_status` to verify `name` field
- Update `test_get_stats` to verify `total_messages` and `last_activity`

View File

@@ -1,30 +0,0 @@
## Why
The RuntimeStatusStar was implemented based on a spec, but the implementation does not match the specification:
1. `get_protocol_status` spec requires a `name` field per protocol, but implementation only returns `connected`
2. `get_stats` spec requires `total_messages` and `last_activity` fields, but implementation only returns `uptime_seconds`
This spec-implementation mismatch means external consumers cannot rely on the documented interface.
## What Changes
- Update `get_protocol_status` to include `name` field for each protocol client (lsp, mcp, acp, abp)
- Update `get_stats` to return `total_messages` and `last_activity` as specified
- Add message tracking infrastructure to the orchestrator to support `total_messages` and `last_activity`
- Update tests to verify spec compliance
## Capabilities
### Modified Capabilities
- `RuntimeStatusStar.get_protocol_status`: Now returns `{"lsp": {"connected": bool, "name": "lsp-client"}, ...}`
- `RuntimeStatusStar.get_stats`: Now returns `{"total_messages": int, "last_activity": str, "uptime_seconds": float}`
### New Infrastructure
- Orchestrator message tracking: `_message_count` and `_last_activity_timestamp`
## Impact
- Modifies: `astrbot/_internal/stars/runtime_status_star.py` - add name fields and message stats
- Modifies: `astrbot/_internal/runtime/orchestrator.py` - add message tracking counters
- Modifies: `tests/unit/test_runtime_status_star.py` - update tests to verify spec compliance

View File

@@ -1,126 +0,0 @@
# RuntimeStatusStar Specification (Corrected)
## Overview
RuntimeStatusStar is an internal ABP (AstrBot Protocol) star plugin that exposes runtime state information via callable tools. It provides diagnostic capabilities for monitoring the AstrBot core runtime health.
## Tool Interface
### Tools Exposed
All tools follow the ABP tool calling convention via `call_tool(tool_name, arguments)`.
#### 1. get_runtime_status
Returns the current runtime state.
**Arguments:** None
**Returns:**
```json
{
"running": true,
"uptime_seconds": 12345.67
}
```
#### 2. get_protocol_status
Returns the connection state of each protocol client.
**Arguments:** None
**Returns:**
```json
{
"lsp": {"connected": true, "name": "lsp-client"},
"mcp": {"connected": false, "name": "mcp-client"},
"acp": {"connected": true, "name": "acp-client"},
"abp": {"connected": true, "name": "abp-client"}
}
```
#### 3. get_star_registry
Returns the list of registered star names.
**Arguments:** None
**Returns:**
```json
{
"stars": ["runtime-status-star", "star-1", "star-2"]
}
```
#### 4. get_stats
Returns runtime statistics and metrics.
**Arguments:** None
**Returns:**
```json
{
"total_messages": 100,
"last_activity": "2024-01-01T00:00:00Z",
"uptime_seconds": 12345.67
}
```
## Architecture
### Component Hierarchy
```
AstrbotOrchestrator
└── RuntimeStatusStar (auto-registered)
└── Tools: get_runtime_status, get_protocol_status, get_star_registry, get_stats
```
### Message Tracking
The orchestrator tracks:
- `_message_count`: Total number of messages processed
- `_last_activity_timestamp`: ISO timestamp of last activity
### Auto-Registration
RuntimeStatusStar is instantiated and registered in `AstrbotOrchestrator.__init__()`:
```python
from astrbot._internal.stars.runtime_status_star import RuntimeStatusStar
class AstrbotOrchestrator:
def __init__(self):
self._stars: dict[str, Star] = {}
self._message_count = 0
self._last_activity_timestamp: float | None = None
# Auto-register RuntimeStatusStar
self._runtime_status_star = RuntimeStatusStar()
self._runtime_status_star.set_orchestrator(self)
self._stars["runtime-status-star"] = self._runtime_status_star
```
### Orchestrator Reference
RuntimeStatusStar holds a reference to the orchestrator to query state:
```python
class RuntimeStatusStar:
def __init__(self):
self._orchestrator = None
def set_orchestrator(self, orchestrator):
self._orchestrator = orchestrator
```
## Implementation Notes
1. **Thread Safety:** The orchestrator may be accessed from multiple contexts. All state queries should be read-only.
2. **Latency:** Tool calls should return immediately without blocking. No polling or long-running operations.
3. **Error Handling:** If any status query fails, return an error message rather than raising an exception.
4. **Future Extensibility:** Additional stats can be added by extending the `get_stats` tool response structure.

View File

@@ -1,56 +0,0 @@
# Runtime Status Star Specification (Spec Compliance Fix)
## MODIFIED Requirements
### Requirement: RuntimeStatusStar provides diagnostic tools
The RuntimeStatusStar SHALL provide callable tools that expose core runtime internal state for diagnostic purposes.
#### Scenario: Get runtime status
- **WHEN** ABP client calls `get_runtime_status` tool
- **THEN** returns `{"running": bool, "uptime_seconds": float}`
#### Scenario: Get protocol status
- **WHEN** ABP client calls `get_protocol_status` tool
- **THEN** returns status of each protocol client (lsp, mcp, acp, abp)
- **AND** each protocol includes `connected: bool` AND `name: string` fields
- **EXAMPLE**: `{"lsp": {"connected": true, "name": "lsp-client"}, ...}`
#### Scenario: Get star registry
- **WHEN** ABP client calls `get_star_registry` tool
- **THEN** returns list of registered star names
#### Scenario: Get stats
- **WHEN** ABP client calls `get_stats` tool
- **THEN** returns `{"total_messages": int, "last_activity": string, "uptime_seconds": float}`
- **AND** `last_activity` is ISO8601 formatted timestamp string
### Requirement: Auto-registration with orchestrator
The RuntimeStatusStar SHALL be automatically registered with the orchestrator on initialization.
#### Scenario: Orchestrator initialization
- **WHEN** AstrbotOrchestrator is created
- **THEN** RuntimeStatusStar instance is created and registered with name "runtime-status-star"
### Requirement: Orchestrator message tracking
The orchestrator SHALL track message counts and last activity timestamp for stats reporting.
#### Scenario: Message tracking
- **WHEN** orchestrator processes a message
- **THEN** `_message_count` is incremented
- **AND** `_last_activity_timestamp` is updated to current time
#### Scenario: Stats retrieval
- **WHEN** RuntimeStatusStar.get_stats is called
- **THEN** returns `total_messages` from orchestrator's `_message_count`
- **AND** returns `last_activity` as ISO8601 string from `_last_activity_timestamp`
### Requirement: Error handling
The RuntimeStatusStar tools SHALL handle errors gracefully without exposing internal exceptions.
#### Scenario: Orchestrator unavailable
- **WHEN** orchestrator reference is None
- **THEN** returns appropriate error message instead of raising exception

View File

@@ -1,34 +0,0 @@
# Tasks: Fix RuntimeStatusStar Spec Compliance
## Implementation Tasks
### 1. Update Orchestrator for message tracking
- [x] Add `_message_count: int = 0` to `__init__`
- [x] Add `_last_activity_timestamp: float | None = None` to `__init__`
- [x] Add `record_activity()` method that increments count and updates timestamp
- [x] Add `record_activity()` method (infrastructure ready, caller integration separate)
### 2. Update RuntimeStatusStar.get_protocol_status
- [x] Add `name` field to each protocol's return dict
- [x] Verify format matches: `{"connected": bool, "name": "xxx-client"}`
### 3. Update RuntimeStatusStar.get_stats
- [x] Import `datetime` for timestamp formatting
- [x] Return `total_messages` from orchestrator's `_message_count`
- [x] Return `last_activity` as ISO formatted timestamp from `_last_activity_timestamp`
- [x] Keep `uptime_seconds` for backward compatibility
### 4. Update Tests
- [x] Update `test_get_protocol_status` to verify `name` field exists and has correct value
- [x] Update `test_get_stats` to verify `total_messages` and `last_activity` fields exist
- [x] Add test for `record_activity()` method
### 5. Verification
- [x] Run `uv run pytest tests/unit/test_runtime_status_star.py -v`
- [x] Run `uv run pytest tests/unit/test_internal_runtime.py -v`
- [x] Run full test suite: `uv run pytest --cov=astrbot tests/`

View File

@@ -1,2 +0,0 @@
schema: spec-driven
created: 2026-03-24

View File

@@ -1,184 +0,0 @@
# Design: LSP Integration Tests
## LSP Echo Server Fixture
Create a simple stdio-based LSP server for testing:
```python
# tests/integration/fixtures/echo_lsp_server.py
"""
Simple LSP server that echoes back requests.
Used for testing the LSP client.
"""
import json
import sys
def main():
while True:
line = sys.stdin.readline()
if not line:
break
request = json.loads(line)
msg_id = request.get("id")
method = request.get("method")
# Handle initialize
if method == "initialize":
print(json.dumps({
"jsonrpc": "2.0",
"id": msg_id,
"result": {
"capabilities": {"textDocumentSync": 1}
}
}))
sys.stdout.flush()
# Handle initialized notification (no response)
elif method == "initialized":
continue
# Handle shutdown
elif method == "shutdown":
print(json.dumps({
"jsonrpc": "2.0",
"id": msg_id,
"result": None
}))
sys.stdout.flush()
# Echo any textDocument/didOpen
elif method == "textDocument/didOpen":
print(json.dumps({
"jsonrpc": "2.0",
"id": msg_id,
"result": None
}))
sys.stdout.flush()
# Echo any request
elif msg_id is not None:
print(json.dumps({
"jsonrpc": "2.0",
"id": msg_id,
"result": {"echo": True}
}))
sys.stdout.flush()
```
## LSP Client Integration Tests
```python
# tests/integration/test_lsp_integration.py
"""
LSP Integration Tests.
Tests the LSP client against a real LSP server fixture.
"""
from __future__ import annotations
import os
import pytest
from astrbot._internal.protocols.lsp.client import AstrbotLspClient
@pytest.mark.anyio
async def test_lsp_client_initialization():
"""Test LSP client can be initialized."""
client = AstrbotLspClient()
assert client is not None
assert not client.connected
@pytest.mark.anyio
async def test_lsp_client_connect_to_echo_server():
"""Test LSP client can connect to echo LSP server."""
client = AstrbotLspClient()
test_dir = os.path.dirname(os.path.abspath(__file__))
server_path = os.path.join(test_dir, "fixtures", "echo_lsp_server.py")
await client.connect_to_server(
command=["python", server_path],
workspace_uri="file:///tmp"
)
try:
assert client.connected
finally:
await client.shutdown()
@pytest.mark.anyio
async def test_lsp_client_send_request():
"""Test LSP client can send a request and receive response."""
client = AstrbotLspClient()
test_dir = os.path.dirname(os.path.abspath(__file__))
server_path = os.path.join(test_dir, "fixtures", "echo_lsp_server.py")
await client.connect_to_server(
command=["python", server_path],
workspace_uri="file:///tmp"
)
try:
assert client.connected
# Send a custom request
result = await client.send_request("custom/echo", {"message": "test"})
assert result is not None
finally:
await client.shutdown()
@pytest.mark.anyio
async def test_lsp_client_send_notification():
"""Test LSP client can send a notification (no response)."""
client = AstrbotLspClient()
test_dir = os.path.dirname(os.path.abspath(__file__))
server_path = os.path.join(test_dir, "fixtures", "echo_lsp_server.py")
await client.connect_to_server(
command=["python", server_path],
workspace_uri="file:///tmp"
)
try:
assert client.connected
# Send a notification (should not raise)
await client.send_notification("custom/notify", {"data": "test"})
finally:
await client.shutdown()
```
## Test Fixtures Location
```
tests/
├── integration/
│ ├── fixtures/
│ │ ├── echo_lsp_server.py # New
│ │ ├── echo_mcp_server.py # Existing
│ │ └── echo_acp_server.py # Existing
│ ├── test_lsp_integration.py # New
│ ├── test_mcp_integration.py # Existing
│ └── test_acp_integration.py # Existing
```
## Running Tests
```bash
# Run all integration tests
uv run pytest tests/integration/ -v
# Run LSP integration only
uv run pytest tests/integration/test_lsp_integration.py -v
```

View File

@@ -1,25 +0,0 @@
# LSP Integration Tests
## Problem
The `_internal` architecture includes an LSP (Language Server Protocol) client implementation at `astrbot/_internal/protocols/lsp/client.py`, but there are no integration tests validating that it can connect to and communicate with a real LSP server. The orchestrator manages an `AstrbotLspClient` instance (`self.lsp`), but this functionality remains untested.
## Solution
Create integration tests that:
1. Build an LSP echo server fixture (stdio-based)
2. Test the LSP client can connect, send requests, and receive responses
3. Verify the JSON-RPC 2.0 protocol communication works end-to-end
## Why This Matters
- Architecture claims must be validated through tests
- LSP functionality is used by the orchestrator for language intelligence
- Integration tests catch regressions that unit tests miss
- Validates the JSON-RPC 2.0 message framing and async communication
## Scope
- Create `tests/integration/fixtures/echo_lsp_server.py`
- Create `tests/integration/test_lsp_integration.py`
- Ensure tests can run in CI

View File

@@ -1,88 +0,0 @@
# LSP Integration Tests Specification
## ADDED Requirements
### Requirement: LSP client initialization
The LSP client (`AstrbotLspClient`) SHALL be instantiated with proper initial state.
#### Scenario: LSP client initialization
- **WHEN** `AstrbotLspClient` is instantiated
- **THEN** `connected = False`
- **AND** `_reader = None`
- **AND** `_writer = None`
- **AND** `_server_process = None`
- **AND** `_pending_requests = {}`
- **AND** `_request_id = 0`
### Requirement: LSP client connect_to_server()
The LSP client SHALL establish a connection to a stdio-based LSP server.
#### Scenario: LSP client connects to stdio server
- **WHEN** `connect_to_server(command, workspace_uri)` is called
- **THEN** LSP server subprocess is started with the given command
- **AND** `_reader` and `_writer` are set to server's stdout/stdin
- **AND** `_connected = True`
- **AND** initialize request is sent to server
- **AND** initialized notification is sent to server
- **AND** background response reader task is started
### Requirement: LSP client send_request()
The LSP client SHALL send JSON-RPC requests and wait for responses.
#### Scenario: LSP client sends request and waits for response
- **WHEN** `send_request(method, params)` is called on connected client
- **THEN** a JSON-RPC request is sent with proper Content-Length header
- **AND** request id is incremented
- **AND** response is received within 30 second timeout
- **AND** response is returned to caller
#### Scenario: LSP client send_request raises when not connected
- **WHEN** `send_request()` is called on disconnected client
- **THEN** `RuntimeError` is raised with message "LSP client not connected"
### Requirement: LSP client send_notification()
The LSP client SHALL send JSON-RPC notifications without waiting for response.
#### Scenario: LSP client sends notification without waiting
- **WHEN** `send_notification(method, params)` is called on connected client
- **THEN** a JSON-RPC notification is sent with proper Content-Length header
- **AND** method returns immediately without waiting for response
#### Scenario: LSP client send_notification raises when not connected
- **WHEN** `send_notification()` is called on disconnected client
- **THEN** `RuntimeError` is raised with message "LSP client not connected"
### Requirement: LSP client shutdown()
The LSP client SHALL cleanly terminate the LSP server connection.
#### Scenario: LSP client shuts down cleanly
- **WHEN** `shutdown()` is called on connected client
- **THEN** `_connected = False`
- **AND** task group is cancelled
- **AND** shutdown notification is sent to server
- **AND** server process is terminated
- **AND** pending requests are cleared
### Requirement: LSP echo server fixture
The integration test fixture SHALL provide a stdio-based LSP echo server for testing.
#### Scenario: Echo LSP server handles initialize request
- **WHEN** LSP server receives `initialize` request on stdin
- **THEN** responds with `initialize` result containing server capabilities
- **AND** responds with `initialized` notification
#### Scenario: Echo LSP server handles textDocument/didOpen notification
- **WHEN** LSP server receives `textDocument/didOpen` notification
- **THEN** stores the opened document information
- **AND** returns without error
#### Scenario: Echo LSP server handles shutdown request
- **WHEN** LSP server receives `shutdown` request
- **THEN** responds with `null` result
- **AND** on subsequent `exit` notification, terminates cleanly

View File

@@ -1,2 +0,0 @@
schema: spec-driven
created: 2026-03-24

View File

@@ -1,3 +0,0 @@
# rust-core-runtime-migration
将核心运行时从 Python 迁移到 Rust

View File

@@ -1,188 +0,0 @@
## Context
AstrBot's core runtime is currently implemented in Python. While Python provides flexibility and rapid development, performance-critical components (orchestration, protocol management, message processing) would benefit from Rust's:
- Memory safety without garbage collection
- Zero-cost abstractions
- Native performance for concurrent operations
- Strong type safety at compile time
The Rust implementation provides a high-performance foundation that can be exposed to Python via pyo3 bindings.
## Goals / Non-Goals
**Goals:**
- Create a `astrbot-core` Rust crate with core runtime components
- Implement thread-safe Orchestrator using RwLock
- Define ProtocolClient trait for LSP, MCP, ACP, ABP clients
- Provide TOML-based configuration management
- Expose Python bindings via pyo3
- CLI binary using clap
**Non-Goals:**
- Not replacing the Python implementation immediately (coexistence)
- Not implementing anyio (uses native Rust async/tokio)
- Not creating a full ABP protocol implementation in Rust
- Not implementing platform adapters or message pipeline
## Decisions
### 1. Architecture: Stub with Python Integration
The initial Rust implementation is a **stub** that provides:
- Structural definitions matching the expected interfaces
- Thread-safe state management (RwLock)
- Python bindings verification via pyo3
This allows:
- Validating the pyo3 integration works
- Ensuring clippy pedantic compliance
- Establishing the project structure
### 2. Concurrency Model: RwLock for Thread Safety
```rust
pub struct Orchestrator {
running: RwLock<bool>,
stars: RwLock<HashMap<String, String>>,
protocol_lsp: RwLock<ProtocolStatus>,
// ...
}
```
Using `RwLock` allows:
- Multiple readers concurrently (most operations are reads)
- Exclusive writer (state changes)
- No deadlocks (standard read-write lock pattern)
### 3. Error Handling: thiserror for Ergonomic Errors
```rust
#[derive(Error, Debug)]
pub enum AstrBotError {
#[error("Not connected: {0}")]
NotConnected(String),
// ...
}
```
Using `thiserror` provides:
- Compile-time error message generation
- `?` operator compatibility
- Debug output for development
### 4. Python Bindings: GILOnceCell Singleton
```rust
static ORCHESTRATOR: GILOnceCell<Py<PythonOrchestrator>> = GILOnceCell::new();
#[pyfunction]
pub fn get_orchestrator(py: Python<'_>) -> PyResult<&'static Py<PythonOrchestrator>> {
if ORCHESTRATOR.get(py).is_none() {
ORCHESTRATOR.set(py, Py::new(py, PythonOrchestrator::new())?)?;
}
Ok(ORCHESTRATOR.get(py).expect("initialized"))
}
```
Using `GILOnceCell` provides:
- Thread-safe global singleton
- GIL-aware initialization
- Lazy initialization on first Python access
### 5. Rust Rules Enforcement
```rust
#![deny(unsafe_code)]
#![deny(clippy::all)]
#![deny(clippy::pedantic)]
```
- **No unsafe**: All memory access is safe by construction
- **No unwrap()**: Errors propagated via `?` or expect with messages
- **Clippy pedantic**: Catches style issues and potential bugs
### 6. ProtocolClient Trait: Static Lifetime for Names
```rust
#[async_trait]
pub trait ProtocolClient: Send + Sync {
fn name(&self) -> &'static str;
// ...
}
```
Using `&'static str` ensures:
- No lifetime issues from borrowed data
- Compile-time guaranteed string validity
- Simple implementation for hardcoded client names
## Risks / Trade-offs
| Risk | Mitigation |
|------|------------|
| pyo3 compatibility with Python 3.14 | Use `PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1` |
| Two implementations to maintain | Rust is opt-in via feature flag |
| Performance overhead of bindings | Rust called only for core operations |
| Clippy pedantic false positives | Use `#[allow(...)]` for intentional patterns |
## File Structure
```
rust/
├── Cargo.toml
├── src/
│ ├── lib.rs # Crate root with module declarations
│ ├── main.rs # CLI binary
│ ├── error.rs # AstrBotError enum
│ ├── orchestrator.rs # Core orchestrator
│ ├── message.rs # Message types
│ ├── stats.rs # RuntimeStats
│ ├── protocol.rs # ProtocolClient trait + implementations
│ ├── config.rs # Configuration structs
│ └── python.rs # pyo3 bindings
└── target/ # Build output (gitignored)
```
## Cargo Features
```toml
[features]
default = ["python"]
python = ["pyo3"]
```
- Default enables Python bindings
- Can build pure Rust library without Python
## Verification
| Check | Command |
|-------|---------|
| Clippy | `PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 cargo clippy` |
| Build | `PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 cargo build` |
| Python import | `python -c "from astrbot_core import PythonOrchestrator"` |
| CLI help | `cargo run -- --help` |
## Current Implementation Status
| Component | Status | Notes |
|-----------|--------|-------|
| error.rs | ✅ Complete | thiserror-based errors |
| orchestrator.rs | ✅ Complete | Thread-safe with RwLock |
| message.rs | ✅ Complete | serde serialization |
| stats.rs | ✅ Complete | AtomicU64 message count |
| protocol.rs | ✅ Complete | Trait + 4 client stubs |
| config.rs | ✅ Complete | TOML load/save |
| python.rs | ✅ Complete | pyo3 bindings |
| main.rs | ✅ Complete | clap CLI |
| lib.rs | ✅ Complete | Module declarations |
| Clippy | ✅ Passing | No warnings |
| Build | ✅ Passing | Compiles successfully |
## Next Steps (Future Work)
1. **Real Protocol Implementations**: Replace stub clients with actual LSP/MCP/ACP/ABP implementations
2. **Python Integration**: Connect Rust orchestrator to Python platform adapters
3. **Performance Benchmarking**: Compare Python vs Rust performance
4. **Feature Parity**: Match all Python orchestrator functionality
5. **Production Readiness**: Add more tests, error handling, edge cases

View File

@@ -1,86 +0,0 @@
## Why
AstrBot's core runtime is currently implemented in Python. Performance-critical components (orchestration, protocol management, message processing) would benefit from Rust's memory safety, zero-cost abstractions, and native performance. Additionally, exposing core functionality via pyo3 allows seamless Python integration while leveraging Rust's strengths.
## What Changes
- Create a new Rust crate `astrbot-core` in `rust/` directory
- Implement core runtime components in Rust:
- `Orchestrator`: Thread-safe runtime coordinator with RwLock
- `ProtocolClient` trait: Unified interface for LSP, MCP, ACP, ABP clients
- `Message` and `MessageType`: Message serialization with serde
- `RuntimeStats`: Atomic message counting and uptime tracking
- `Config`: TOML-based configuration management
- Provide Python bindings via pyo3 for seamless integration
- Follow strict Rust best practices:
- No `unsafe` code
- No `.unwrap()` - proper error handling
- Clippy pedantic compliance
- Full test coverage
## Architecture
```
Python Layer (astrbot/core/)
▼ (pyo3 bindings)
┌─────────────────────────────────────────────────┐
│ Rust Core (astrbot-core) │
│ ┌─────────────┐ ┌─────────────┐ ┌──────────┐ │
│ │ Orchestrator│ │ Config │ │ Stats │ │
│ └─────────────┘ └─────────────┘ └──────────┘ │
│ ┌─────────────────────────────────────────────┐│
│ │ Protocol Clients ││
│ │ LSP │ MCP │ ACP │ ABP ││
│ └─────────────────────────────────────────────┘│
└─────────────────────────────────────────────────┘
```
## Capabilities
### New Capabilities
- `astrbot-core`: Rust-based high-performance core runtime with pyo3 bindings
### Modified Capabilities
- (none - new implementation)
## Impact
- New directory: `rust/` containing Cargo.toml and src/
- New files:
- `rust/Cargo.toml`
- `rust/src/lib.rs`
- `rust/src/main.rs` (CLI binary)
- `rust/src/error.rs`
- `rust/src/orchestrator.rs`
- `rust/src/message.rs`
- `rust/src/stats.rs`
- `rust/src/protocol.rs`
- `rust/src/config.rs`
- `rust/src/python.rs`
- Python integration via `astrbot_core` Python module
- CLI: `astrbot-core` binary with start/stats/health commands
## Verification
- `cargo clippy` passes with no warnings
- `cargo build` compiles successfully
- Python bindings importable: `from astrbot_core import PythonOrchestrator`
- CLI functional: `astrbot-core --help`
## Relationship to OpenSpec Architecture
This change introduces a new implementation pathway that complements (not replaces) the existing Python architecture defined in `openspec/SPEC.md`. The Rust implementation:
1. Provides a reference implementation of the same interfaces (Orchestrator, ProtocolClient, etc.)
2. Uses Rust idioms (no anyio - uses native Rust async/tokio)
3. Is opt-in via pyo3 feature flag
4. Coexists with Python implementation until Rust is production-ready
## Status
- [x] Proposal created
- [ ] Spec created
- [ ] Design created
- [ ] Tasks created
- [ ] Implementation started

View File

@@ -1,251 +0,0 @@
# AstrBot Core Runtime (Rust) Specification
## Overview
AstrBot Core Runtime is a high-performance Rust implementation of the core orchestrator, protocol clients, and configuration management. It provides Python bindings via pyo3 for seamless integration with the existing AstrBot Python codebase.
## Module Structure
### Core Modules
#### 1. orchestrator.rs - Runtime Orchestrator
Central coordinator managing protocol clients and star registry.
```rust
pub struct Orchestrator {
running: RwLock<bool>,
stars: RwLock<HashMap<String, String>>,
stats: RuntimeStats,
protocol_lsp: RwLock<ProtocolStatus>,
protocol_mcp: RwLock<ProtocolStatus>,
protocol_acp: RwLock<ProtocolStatus>,
protocol_abp: RwLock<ProtocolStatus>,
}
impl Orchestrator {
pub fn new() -> Self;
pub fn start(&self) -> Result<(), AstrBotError>;
pub fn stop(&self) -> Result<(), AstrBotError>;
pub fn is_running(&self) -> bool;
pub fn register_star(&self, name: &str, handler: &str) -> Result<(), AstrBotError>;
pub fn unregister_star(&self, name: &str) -> Result<(), AstrBotError>;
pub fn list_stars(&self) -> Vec<String>;
pub fn record_activity(&self);
pub fn stats(&self) -> RuntimeStats;
pub fn get_protocol_status(&self, protocol: &str) -> Option<ProtocolStatus>;
pub fn set_protocol_connected(&self, protocol: &str, connected: bool) -> Result<(), AstrBotError>;
}
```
#### 2. protocol.rs - Protocol Client Trait
Unified interface for all protocol clients.
```rust
#[async_trait]
pub trait ProtocolClient: Send + Sync {
async fn connect(&mut self) -> Result<(), AstrBotError>;
async fn disconnect(&mut self) -> Result<(), AstrBotError>;
fn is_connected(&self) -> bool;
fn name(&self) -> &'static str;
}
```
Implementations:
- `LspClient` - Language Server Protocol client
- `McpClient` - Model Context Protocol client
- `AcpClient` - AstrBot Communication Protocol client
- `AbpClient` - AstrBot Protocol client
#### 3. message.rs - Message Types
Message structures with serde serialization.
```rust
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message {
pub id: String,
pub content: String,
pub sender: String,
pub timestamp: f64,
pub message_type: MessageType,
pub metadata: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Default)]
pub enum MessageType {
#[default]
Text,
Image,
Audio,
Video,
File,
System,
Unknown,
}
```
#### 4. stats.rs - Runtime Statistics
Thread-safe message counting and uptime tracking.
```rust
#[derive(Debug, Clone)]
pub struct RuntimeStats {
message_count: AtomicU64,
start_time: Instant,
last_activity: Mutex<Option<Instant>>,
}
impl RuntimeStats {
pub fn new() -> Self;
pub fn record_message(&self);
pub fn message_count(&self) -> u64;
pub fn uptime_seconds(&self) -> f64;
pub fn last_activity_time(&self) -> Option<f64>;
}
```
#### 5. config.rs - Configuration Management
TOML-based configuration with serde.
```rust
pub struct Config {
pub runtime: RuntimeConfig,
pub protocols: ProtocolsConfig,
pub logging: LoggingConfig,
}
impl Config {
pub fn load(path: &PathBuf) -> anyhow::Result<Self>;
pub fn save(&self, path: &PathBuf) -> anyhow::Result<()>;
}
```
#### 6. error.rs - Error Types
Using thiserror for ergonomic error handling.
```rust
#[derive(Error, Debug)]
pub enum AstrBotError {
#[error("Not connected: {0}")]
NotConnected(String),
#[error("Connection failed: {0}")]
ConnectionFailed(String),
#[error("Protocol error: {0}")]
Protocol(String),
#[error("Timeout: {0}")]
Timeout(String),
#[error("Invalid state: {0}")]
InvalidState(String),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
}
```
#### 7. python.rs - Python Bindings
pyo3 bindings for Python integration.
```rust
#[pyclass]
pub struct PythonOrchestrator {
inner: Orchestrator,
}
#[pymethods]
impl PythonOrchestrator {
#[new]
pub fn new() -> Self;
pub fn start(&self) -> PyResult<()>;
pub fn stop(&self) -> PyResult<()>;
pub fn is_running(&self) -> bool;
pub fn register_star(&self, name: &str, handler: &str) -> PyResult<()>;
pub fn unregister_star(&self, name: &str) -> PyResult<()>;
pub fn list_stars(&self) -> Vec<String>;
pub fn record_activity(&self);
pub fn get_stats(&self) -> PyResult<Py<PyAny>>;
pub fn set_protocol_connected(&self, protocol: &str, connected: bool) -> PyResult<()>;
pub fn get_protocol_status(&self, protocol: &str) -> Option<Py<PyAny>>;
}
#[pyfunction]
pub fn get_orchestrator(py: Python<'_>) -> PyResult<&'static Py<PythonOrchestrator>>;
```
#### 8. main.rs - CLI Binary
Command-line interface using clap.
```rust
#[derive(Parser, Debug)]
enum Command {
Start,
Stats,
Health,
}
```
Commands:
- `start` - Start the astrbot-core runtime
- `stats` - Display runtime statistics
- `health` - Check runtime health status
## Rust Rules
1. **No unsafe code** - All memory access is safe
2. **No .unwrap()** - Use `?` operator or `expect()` with descriptive messages
3. **Clippy pedantic compliance** - Pass `cargo clippy` with no warnings
4. **Full error handling** - All errors properly propagated
## Python Integration
The module is importable as `astrbot_core`:
```python
from astrbot_core import PythonOrchestrator, get_orchestrator
# Get singleton
orch = get_orchestrator()
# Use methods
orch.start()
orch.register_star("my-star", "handler-id")
stars = orch.list_stars()
```
## Cargo Features
```toml
[features]
default = ["python"]
python = ["pyo3"]
```
- `python`: Enable pyo3 bindings (default)
- Without `python`: Pure Rust library without Python dependencies
## Dependencies
- `serde` + `serde_json` - Serialization
- `toml` - Configuration file parsing
- `tokio` - Async runtime
- `tracing` + `tracing-subscriber` - Logging
- `anyhow` - Error handling
- `thiserror` - Error derive
- `async-trait` - Async trait methods
- `clap` - CLI argument parsing
- `pyo3` - Python bindings (optional)
## Verification Criteria
- [x] `cargo clippy` passes with no warnings
- [x] `cargo build` compiles successfully
- [x] `cargo test` passes (if tests exist)
- [x] Python module imports successfully
- [x] CLI `--help` works correctly

View File

@@ -1,53 +0,0 @@
# Implementation Tasks
## 1. Project Setup
- [x] 1.1 Create rust/ directory
- [x] 1.2 Initialize with cargo init --name astrbot-core
- [x] 1.3 Add Cargo.toml with dependencies (serde, tokio, pyo3, clap, etc.)
- [x] 1.4 Create .cargo/config.toml for pyo3 forward compatibility
## 2. Core Modules
- [x] 2.1 Create lib.rs with module declarations and clippy settings
- [x] 2.2 Create error.rs with AstrBotError enum using thiserror
- [x] 2.3 Create orchestrator.rs with Orchestrator struct and methods
- [x] 2.4 Create message.rs with Message and MessageType
- [x] 2.5 Create stats.rs with RuntimeStats using AtomicU64
- [x] 2.6 Create protocol.rs with ProtocolClient trait and client implementations
- [x] 2.7 Create config.rs with Config and related structs
- [x] 2.8 Create python.rs with pyo3 bindings
## 3. CLI Binary
- [x] 3.1 Create main.rs with clap CLI (start, stats, health commands)
## 4. Rust Rules Compliance
- [x] 4.1 Ensure no unsafe code (#![deny(unsafe_code)])
- [x] 4.2 Ensure no .unwrap() without message (#[allow] where needed)
- [x] 4.3 Add clippy pedantic settings (#![deny(clippy::pedantic)])
- [x] 4.4 Fix all clippy warnings
## 5. Verification
- [x] 5.1 Run `cargo clippy` - no warnings
- [x] 5.2 Run `cargo build` - compiles successfully
- [x] 5.3 Verify CLI works: `cargo run -- --help`
## 6. Documentation
- [x] 6.1 Create proposal.md
- [x] 6.2 Create spec.md
- [x] 6.3 Create design.md
- [ ] 6.4 Create tasks.md (this file)
## 7. Future Work (Not in Scope)
- [ ] 7.1 Implement real LSP client functionality
- [ ] 7.2 Implement real MCP client functionality
- [ ] 7.3 Implement real ACP client functionality
- [ ] 7.4 Implement real ABP client functionality
- [ ] 7.5 Connect Rust orchestrator to Python platform adapters
- [ ] 7.6 Add comprehensive test suite
- [ ] 7.7 Performance benchmarking

View File

@@ -2,7 +2,7 @@ schema: spec-driven
# 项目上下文
context: |
技术栈: Python 3.12, anyio (异步), FastAPI, pytest, ruff, uv
技术栈: Python 3.12, anyio (异步), ~~FastAPI~~, pytest, ruff, uv , rust
领域: 多平台 LLM 聊天机器人框架 (QQ, Telegram, Discord 等)
架构: 基于协议的系统 (LSP, MCP, ACP, ABP)
@@ -25,7 +25,7 @@ directives:
新架构放在 _internal 包中,避免分支冲突。
协议系统: LSP (客户端), MCP (客户端+服务端), ACP (客户端+服务端), ABP (客户端+服务端)。
Runtime 协调协议Gateway 提供 FastAPI 后端。
Stars 是插件 - Galaxy 是星星的集合
Stars 是插件 - Galaxy 是加载插件的中间层
async_library: |
使用 anyio 作为异步库(不是 asyncio
coverage: |

317
openspec/env.md Normal file
View File

@@ -0,0 +1,317 @@
# 环境变量规范
## 概述
本文档定义 AstrBot 环境变量的规范,所有环境变量以 `ASTRBOT_` 为前缀。
## 变量分类
| 分类 | 前缀 | 说明 |
|------|------|------|
| 实例标识 | `ASTRBOT_INSTANCE_*` | 实例相关配置 |
| 核心配置 | `ASTRBOT_*` | 核心功能配置 |
| 网络配置 | `ASTRBOT_NET_*` | 网络相关配置 |
| SSL/TLS | `ASTRBOT_SSL_*` | 安全连接配置 |
| 代理配置 | `*_PROXY` | 代理相关配置 |
| 平台配置 | 平台特定 | 第三方平台集成 |
---
## 实例标识 / Instance Identity
### `ASTRBOT_INSTANCE_NAME`
| 属性 | 值 |
|------|-----|
| 说明 | 实例名称,用于日志和服务名 |
| 类型 | string |
| 默认 | `AstrBot` |
---
## 核心配置 / Core Configuration
### `ASTRBOT_ROOT`
| 属性 | 值 |
|------|-----|
| 说明 | AstrBot 根目录路径 |
| 类型 | path |
| 默认 | 当前工作目录 |
**特殊路径**
- 桌面客户端:`~/.astrbot`
- 服务器:`/var/lib/astrbot/<instance>/`
### `ASTRBOT_LOG_LEVEL`
| 属性 | 值 |
|------|-----|
| 说明 | 日志等级 |
| 类型 | enum |
| 默认 | `INFO` |
| 可选值 | `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` |
### `ASTRBOT_RELOAD`
| 属性 | 值 |
|------|-----|
| 说明 | 启用插件热重载 |
| 类型 | boolean (0/1) |
| 默认 | `0` (禁用) |
### `ASTRBOT_DISABLE_METRICS`
| 属性 | 值 |
|------|-----|
| 说明 | 禁用匿名使用统计 |
| 类型 | boolean (0/1) |
| 默认 | `0` (启用统计) |
### `ASTRBOT_PYTHON`
| 属性 | 值 |
|------|-----|
| 说明 | 覆盖 Python 可执行文件路径(用于本地代码执行) |
| 类型 | path |
| 示例 | `/usr/bin/python3`, `/home/user/.pyenv/shims/python` |
### `ASTRBOT_DEMO_MODE`
| 属性 | 值 |
|------|-----|
| 说明 | 启用演示模式(可能限制部分功能) |
| 类型 | boolean |
| 默认 | `False` |
### `ASTRBOT_TESTING`
| 属性 | 值 |
|------|-----|
| 说明 | 启用测试模式(影响日志和部分行为) |
| 类型 | boolean |
| 默认 | `False` |
### `ASTRBOT_DESKTOP_CLIENT`
| 属性 | 值 |
|------|-----|
| 说明 | 标记是否通过桌面客户端执行(内部使用) |
| 类型 | boolean (0/1) |
| 默认 | `0` |
### `ASTRBOT_SYSTEMD`
| 属性 | 值 |
|------|-----|
| 说明 | 标记是否通过 systemd 服务执行 |
| 类型 | boolean (0/1) |
| 默认 | `0` |
---
## 管理面板 / Dashboard
### `ASTRBOT_DASHBOARD_ENABLE`
| 属性 | 值 |
|------|-----|
| 说明 | 启用或禁用 WebUI 管理面板 |
| 类型 | boolean |
| 默认 | `True` |
---
## 国际化 / Internationalization
### `ASTRBOT_CLI_LANG`
| 属性 | 值 |
|------|-----|
| 说明 | CLI 界面语言 |
| 类型 | enum |
| 默认 | `zh` (跟随系统 locale) |
| 可选值 | `zh` (中文), `en` (英文) |
---
## 网络配置 / Network
### `ASTRBOT_HOST`
| 属性 | 值 |
|------|-----|
| 说明 | API 绑定主机 |
| 类型 | string |
| 示例 | `0.0.0.0` (所有接口), `127.0.0.1` (仅本地) |
### `ASTRBOT_PORT`
| 属性 | 值 |
|------|-----|
| 说明 | API 绑定端口 |
| 类型 | integer |
| 示例 | `3000`, `6185`, `8080` |
---
## SSL/TLS 配置
### `ASTRBOT_SSL_ENABLE`
| 属性 | 值 |
|------|-----|
| 说明 | 启用 SSL/TLS |
| 类型 | boolean |
| 默认 | `false` |
### `ASTRBOT_SSL_CERT`
| 属性 | 值 |
|------|-----|
| 说明 | SSL 证书路径PEM 格式) |
| 类型 | path |
| 示例 | `/etc/astrbot/certs/myinstance/fullchain.pem` |
### `ASTRBOT_SSL_KEY`
| 属性 | 值 |
|------|-----|
| 说明 | SSL 私钥路径PEM 格式) |
| 类型 | path |
| 示例 | `/etc/astrbot/certs/myinstance/privkey.pem` |
### `ASTRBOT_SSL_CA_CERTS`
| 属性 | 值 |
|------|-----|
| 说明 | SSL CA 证书链路径(可选,用于客户端验证) |
| 类型 | path |
| 示例 | `/etc/ssl/certs/ca-certificates.crt` |
---
## 代理配置
### 通用
### `http_proxy` / `HTTP_PROXY`
| 属性 | 值 |
|------|-----|
| 说明 | HTTP 代理地址 |
| 类型 | url |
| 示例 | `http://127.0.0.1:7890`, `socks5://127.0.0.1:1080` |
### `https_proxy` / `HTTPS_PROXY`
| 属性 | 值 |
|------|-----|
| 说明 | HTTPS 代理地址 |
| 类型 | url |
| 示例 | `http://127.0.0.1:7890`, `socks5://127.0.0.1:1080` |
### `no_proxy` / `NO_PROXY`
| 属性 | 值 |
|------|-----|
| 说明 | 不走代理的主机列表(逗号分隔) |
| 类型 | string |
| 示例 | `localhost,127.0.0.1,192.168.0.0/16,.local` |
---
## 第三方集成 / Third-party Integrations
### `DASHSCOPE_API_KEY`
| 属性 | 值 |
|------|-----|
| 说明 | 阿里云 DashScope API 密钥(用于 Rerank 服务) |
| 类型 | string |
| 获取地址 | https://dashscope.console.aliyun.com/ |
| 示例 | `sk-xxxxxxxxxxxx` |
### `COZE_API_KEY`
| 属性 | 值 |
|------|-----|
| 说明 | Coze API 密钥 |
| 类型 | string |
| 获取地址 | https://www.coze.com/ |
### `COZE_BOT_ID`
| 属性 | 值 |
|------|-----|
| 说明 | Coze Bot ID |
| 类型 | string |
### `BAY_DATA_DIR`
| 属性 | 值 |
|------|-----|
| 说明 | 计算机控制相关的数据目录(用于截图/文件存储) |
| 类型 | path |
| 示例 | `/var/lib/astrbot/bay_data` |
---
## 平台特定配置 / Platform-specific
### `TEST_MODE`
| 属性 | 值 |
|------|-----|
| 说明 | QQ 官方机器人测试模式开关 |
| 类型 | enum |
| 默认 | `off` |
| 可选值 | `on`, `off` |
---
## 命名规范
### 前缀规则
| 前缀 | 用途 |
|------|------|
| `ASTRBOT_` | AstrBot 核心配置 |
| `ASTRBOT_SSL_` | SSL/TLS 配置 |
| `ASTRBOT_INSTANCE_` | 实例相关 |
| `http_proxy`, `https_proxy`, `no_proxy` | 标准代理变量(无前缀) |
### 布尔值
布尔值使用以下格式之一:
| 格式 | 示例 |
|------|------|
| 整数 (0/1) | `ASTRBOT_RELOAD=0` |
| 字符串 (true/false) | `ASTRBOT_SSL_ENABLE=false` |
| 枚举 | `TEST_MODE=on/off` |
---
## 配置文件优先级
1. 环境变量(最高优先级)
2. `.env` 文件
3. 默认值(最低优先级)
---
## 特殊变量展开
支持 `${VAR_NAME}` 格式的变量展开:
```bash
INSTANCE_NAME="my-bot"
ASTRBOT_ROOT="${ASTRBOT_ROOT:-/var/lib/astrbot}"
```
### 支持的展开语法
| 语法 | 说明 |
|------|------|
| `${VAR}` | 展开 VAR 的值 |
| `${VAR:-default}` | 如果 VAR 未设置或为空,使用 default |
| `${VAR:=default}` | 如果 VAR 未设置或为空,设置为 default 并展开 |

402
openspec/lsp.md Normal file
View File

@@ -0,0 +1,402 @@
# LSP (Language Server Protocol) 协议规范
## 概述
LSPLanguage Server Protocol是由 Microsoft 制定的开放协议,用于在编辑器/IDE 与语言智能服务之间提供语言特性支持。
**核心问题**:传统上,为编辑器提供编程语言支持(如自动完成、跳转到定义)需要针对每个编辑器/IDE 单独实现。例如Eclipse CDT 插件用 Java 编写VS Code 扩展用 TypeScript 编写C# 支持用 C# 编写。
**解决方案**:语言服务器在其自己的进程中运行,编辑器通过标准协议与之通信。只需实现一次语言服务器,即可集成到任何支持 LSP 的工具中。
**参考**[Language Server Protocol](https://microsoft.github.io/language-server-protocol/) by Microsoft
## 设计哲学
### 抽象层级
LSP 成功的原因在于其**编辑器级别**的抽象,而非编程语言领域模型级别:
| 层级 | LSP 抽象 | 传统方法 |
|------|----------|----------|
| 编辑器级别 | 文本文档 URI、光标位置 | ✓ |
| 语言模型级别 | 抽象语法树、编译器符号 | ✗ |
**简化协议**:标准化文本文档 URI 或光标位置,比标准化抽象语法树和编译器符号简单得多。
### 进程隔离
```
┌─────────────────────────────────────┐
│ 编辑器/IDE │
│ - 文档状态管理 │
│ - 用户交互 │
│ - UI 渲染 │
└─────────────────────────────────────┘
│ JSON-RPC 2.0
┌─────────────────────────────────────┐
│ 语言服务器 (独立进程) │
│ - 词法分析 │
│ - 语法分析 │
│ - 类型检查 │
│ - 代码生成 │
└─────────────────────────────────────┘
```
**优势**
- 避免与单个进程模型相关的性能问题
- 语言服务器可用任何语言实现Python、Go、JavaScript 等)
- 服务器崩溃不影响编辑器
## 架构
### 通信流程
```
┌─────────────────────────────────────┐
│ 编辑器/IDE (LSP 客户端) │
└─────────────────────────────────────┘
│ JSON-RPC 2.0
┌─────────────────────────────────────┐
│ LSP 服务器 (独立进程) │
│ - 代码补全 │
│ - 诊断(错误、警告) │
│ - 悬停信息 │
│ - 跳转到定义 │
│ - 重构支持 │
└─────────────────────────────────────┘
```
### 传输方式
| 传输方式 | 说明 |
|----------|------|
| **stdio** | 通过 stdin/stdout 通信(常用) |
| **Socket** | TCP 套接字 |
| **Named Pipes** | 命名管道 |
| **Node IPC** | Node.js 进程间通信 |
## 会话流程
### 1. 打开文档
```
编辑器 → 服务器textDocument/didOpen
内容:{
"textDocument": {
"uri": "file:///path/to/file.py",
"languageId": "python",
"version": 1,
"text": "print('hello')"
}
}
```
服务器将文档内容加载到内存,不再依赖文件系统。
### 2. 编辑文档
```
编辑器 → 服务器textDocument/didChange
内容:{ "textDocument": {...}, "contentChanges": [...] }
```
服务器更新内存中的文档状态,分析语义信息。
### 3. 发布诊断
```
服务器 → 编辑器textDocument/publishDiagnostics
内容:{ "uri": "...", "diagnostics": [...] }
```
服务器通知编辑器检测到的错误和警告。
### 4. 跳转到定义
```
编辑器 → 服务器textDocument/definition
内容:{
"textDocument": { "uri": "file:///path/to/file.py" },
"position": { "line": 3, "character": 12 }
}
服务器 → 编辑器:响应
内容:{
"uri": "file:///path/to/definition.py",
"range": { "start": {...}, "end": {...} }
}
```
### 5. 关闭文档
```
编辑器 → 服务器textDocument/didClose
内容:{ "textDocument": { "uri": "..." } }
```
服务器释放文档内存,当前内容与文件系统同步。
## 消息格式
所有消息均为 JSON-RPC 2.0
### 请求
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "textDocument/definition",
"params": {
"textDocument": {
"uri": "file:///path/to/file.py"
},
"position": {
"line": 3,
"character": 12
}
}
}
```
### 响应
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"uri": "file:///path/to/definition.py",
"range": {
"start": { "line": 0, "character": 4 },
"end": { "line": 0, "character": 11 }
}
}
}
```
### 通知
```json
{
"jsonrpc": "2.0",
"method": "textDocument/didOpen",
"params": {
"textDocument": {
"uri": "file:///path/to/file",
"languageId": "python",
"version": 1,
"text": "print('hello')"
}
}
}
```
### 错误
```json
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32600,
"message": "Invalid Request"
}
}
```
## 核心方法
### 生命周期
| 方法 | 方向 | 描述 |
|------|------|------|
| `initialize` | C→S | 初始化连接,交换能力 |
| `initialized` | C→S | 客户端通知服务器初始化完成 |
| `shutdown` | C→S | 请求服务器关闭 |
| `exit` | C→S | 退出会话 |
### 文本文档同步
| 方法 | 方向 | 描述 |
|------|------|------|
| `textDocument/didOpen` | C→S | 文档被打开 |
| `textDocument/didChange` | C→S | 文档内容变更 |
| `textDocument/didClose` | C→S | 文档被关闭 |
| `textDocument/didSave` | C→S | 文档被保存 |
### 代码补全
| 方法 | 方向 | 描述 |
|------|------|------|
| `textDocument/completion` | C→S | 请求代码补全 |
| `completionItem/resolve` | C→S | 解析补全项详情 |
### 导航
| 方法 | 方向 | 描述 |
|------|------|------|
| `textDocument/hover` | C→S | 获取悬停信息 |
| `textDocument/definition` | C→S | 跳转到定义 |
| `textDocument/typeDefinition` | C→S | 跳转到类型定义 |
| `textDocument/implementation` | C→S | 跳转到实现 |
| `textDocument/references` | C→S | 查找引用 |
| `textDocument/documentSymbol` | C→S | 文档符号 |
| `textDocument/workspaceSymbol` | C→S | 工作区符号搜索 |
### 代码诊断
| 方法 | 方向 | 描述 |
|------|------|------|
| `textDocument/publishDiagnostics` | S→C | 服务器发布诊断信息 |
### 代码操作
| 方法 | 方向 | 描述 |
|------|------|------|
| `textDocument/codeAction` | C→S | 代码动作/修复 |
| `textDocument/rename` | C→S | 重命名符号 |
| `textDocument/formatting` | C→S | 文档格式化 |
| `textDocument/rangeFormatting` | C→S | 范围格式化 |
## 能力 (Capabilities)
### 服务器能力声明
```json
{
"capabilities": {
"textDocumentSync": 2,
"completionProvider": {
"resolveProvider": true,
"triggerCharacters": [".", "("]
},
"hoverProvider": true,
"definitionProvider": true,
"typeDefinitionProvider": true,
"implementationProvider": true,
"referencesProvider": true,
"documentSymbolProvider": true,
"workspaceSymbolProvider": true,
"codeActionProvider": true,
"renameProvider": true,
"documentFormattingProvider": true,
"diagnosticProvider": {
"interFileDependencies": false,
"workspaceDiagnostics": false
}
}
}
```
### 客户端能力声明
```json
{
"capabilities": {
"workspace": {
"applyEdit": true,
"workspaceFolders": true,
"fileOperations": {
"willRename": true
}
},
"textDocument": {
"synchronization": {
"willSave": true,
"willSaveWaitUntil": true,
"didSave": true
},
"completion": {
"completionItem": {
"snippetSupport": true,
"documentationFormat": ["markdown", "plaintext"]
}
},
"hover": {
"contentFormat": ["markdown", "plaintext"]
}
}
}
}
```
### 能力协商
服务器声明支持的功能,客户端声明支持的功能。双方只使用都支持的功能。
## 错误码
| 码值 | 名称 | 描述 |
|------|------|------|
| -32700 | Parse Error | 无效的 JSON |
| -32600 | Invalid Request | 格式错误的请求 |
| -32601 | Method Not Found | 未知方法 |
| -32602 | Invalid Params | 无效参数 |
| -32603 | Internal Error | 服务器内部错误 |
| -32099 | Server Not Initialized | 服务器未初始化 |
| -32000 | Unknown Error | 未知错误 |
## 数据类型
### TextDocumentItem
```json
{
"uri": "file:///path/to/file",
"languageId": "python",
"version": 1,
"text": "print('hello')"
}
```
### Position
```json
{
"line": 3,
"character": 12
}
```
### Range
```json
{
"start": { "line": 0, "character": 4 },
"end": { "line": 0, "character": 11 }
}
```
### Location
```json
{
"uri": "file:///path/to/file",
"range": { "start": {...}, "end": {...} }
}
```
### Diagnostic
```json
{
"range": { "start": {...}, "end": {...} },
"severity": 1,
"code": "E001",
"source": "pylint",
"message": "Undefined variable 'x'"
}
```
## 实现注意事项
- LSP 服务器在其自己的进程中运行,避免性能问题
- 使用 Content-Length 头解析 JSON-RPC 消息
- 支持增量文档同步textDocumentSync
- 诊断信息通过 `textDocument/publishDiagnostics` 推送
- 服务器应保持运行,避免每次编辑都重启进程
- 客户端和服务器通过能力声明协商支持的功能
- 文档内容由客户端管理,服务器无需直接访问文件系统

279
openspec/mcp.md Normal file
View File

@@ -0,0 +1,279 @@
# MCP (Model Context Protocol) 协议规范
## 概述
MCPModel Context Protocol是由 **Anthropic** 创建的开放协议,用于将 AI 模型连接到外部工具和数据源。
**核心定位**MCP 为 AI 模型提供标准化的工具调用和上下文获取能力,类似于 USB 协议为设备提供的标准化连接方式。
## 核心功能
MCP 服务器通过三个构建块提供功能:
| 功能 | 说明 | 示例 | 控制方 |
|------|------|------|--------|
| **Tools** | LLM 可以主动调用的函数 | 搜索航班、发送消息、创建日历事件 | 模型 |
| **Resources** | 被动数据源,为上下文提供信息 | 检索文档、访问知识库、读取日历 | 应用程序 |
| **Prompts** | 预构建的指令模板 | 规划假期、总结会议内容、起草电子邮件 | 用户 |
## 与 A2A/ACP 的关系
| 协议 | 定位 | 关系 |
|------|------|------|
| **MCP** | AI 模型与外部工具/数据源的连接 | 专注于"工具和上下文" |
| **A2A** | Agent 之间的通信和协作 | 专注于"互操作" |
| **ACP** | IDE 与本地 Agent 的紧密集成 | 专注于"本地控制" |
**互补关系**
- MCP 为 Agent 提供工具和数据访问能力
- A2A/ACP 处理 Agent 之间的通信
- 三者共同构成完整的 AI Agent 通信栈
## 架构
```
┌─────────────────────────────────────────┐
│ AI 应用 (Client) │
│ - 模型 │
│ - 上下文管理 │
└─────────────────────────────────────────┘
│ MCP 协议
┌─────────────────────────────────────────┐
│ MCP 服务器 │
│ - Tools (工具) │
│ - Resources (资源) │
│ - Prompts (提示) │
└─────────────────────────────────────────┘
```
## 传输层
### Stdio本地
- **适用场景**:基于本地子进程的 MCP 服务器
- **协议**:通过 stdin/stdout 的 JSON-RPC 2.0
- **启动方式**:使用配置的 command 启动子进程
```
{"jsonrpc":"2.0","method":"initialize","params":{...},"id":1}
```
### HTTP/SSE远程
- **适用场景**:远程 MCP 服务器
- **协议**HTTP + Server-Sent Events (SSE) 用于服务器→客户端
- **端点**RESTful JSON-RPC over HTTP POST
## 核心方法
### 工具 (Tools)
**协议操作**
| 方法 | 目的 | 返回 |
|------|------|------|
| `tools/list` | 发现可用工具 | 带有架构的工具定义数组 |
| `tools/call` | 执行特定工具 | 工具执行结果 |
**工具定义示例**
```json
{
"name": "searchFlights",
"description": "Search for available flights",
"inputSchema": {
"type": "object",
"properties": {
"origin": { "type": "string", "description": "Departure city" },
"destination": { "type": "string", "description": "Arrival city" },
"date": { "type": "string", "format": "date", "description": "Travel date" }
},
"required": ["origin", "destination", "date"]
}
}
```
**用户交互模型**:工具由模型控制,但强调人工监督:
- UI 中显示可用工具,允许用户定义是否可用
- 针对单个工具执行的确认对话框
- 预先批准某些安全操作的权限设置
- 显示所有工具执行情况的活动日志
### 资源 (Resources)
**协议操作**
| 方法 | 目的 | 返回 |
|------|------|------|
| `resources/list` | 列出可用的直接资源 | 资源描述符数组 |
| `resources/templates/list` | 发现资源模板 | 资源模板定义数组 |
| `resources/read` | 检索资源内容 | 带有元数据的资源数据 |
| `resources/subscribe` | 监控资源变化 | 订阅确认 |
**资源模板示例**
```json
{
"uriTemplate": "weather://forecast/{city}/{date}",
"name": "weather-forecast",
"title": "Weather Forecast",
"description": "Get weather forecast for any city and date",
"mimeType": "application/json"
}
```
**参数补全**:动态资源支持参数补全,例如输入 "Par" 可能会提示 "Paris" 或 "Park City"。
**用户交互模型**:资源是应用程序驱动的:
- 文件夹式结构的树状或列表视图
- 用于查找特定资源的搜索和过滤界面
- 基于启发式方法或 AI 选择的自动上下文包含
### 提示 (Prompts)
**协议操作**
| 方法 | 目的 | 返回 |
|------|------|------|
| `prompts/list` | 发现可用提示词 | 提示词描述符数组 |
| `prompts/get` | 检索提示词详情 | 带有参数的完整提示词定义 |
**提示词示例**
```json
{
"name": "plan-vacation",
"title": "Plan a vacation",
"description": "Guide through vacation planning process",
"arguments": [
{ "name": "destination", "type": "string", "required": true },
{ "name": "duration", "type": "number", "description": "days" },
{ "name": "budget", "type": "number", "required": false },
{ "name": "interests", "type": "array", "items": { "type": "string" } }
]
}
```
**用户交互模型**:提示由用户控制,需要显式调用:
- 斜杠命令(输入 "/" 查看可用提示词)
- 操作面板 (Command palettes)
- 常用提示词的专用 UI 按钮
## 消息格式
### 请求
```json
{
"jsonrpc": "2.0",
"id": "unique-id",
"method": "tools/call",
"params": {
"name": "searchFlights",
"arguments": {
"origin": "NYC",
"destination": "Barcelona",
"date": "2024-06-15"
}
}
}
```
### 响应
```json
{
"jsonrpc": "2.0",
"id": "unique-id",
"result": {
"content": [
{
"type": "text",
"text": "Found 3 flights..."
}
]
}
}
```
### 通知
```json
{
"jsonrpc": "2.0",
"method": "notifications/resources/updated",
"params": {
"uri": "calendar://events/2024"
}
}
```
## 能力 (Capabilities)
### 客户端能力
```json
{
"roots": {
"listChanged": true
},
"sampling": {}
}
```
### 服务器能力
```json
{
"tools": { "listChanged": true },
"resources": { "subscribe": true, "listChanged": true },
"prompts": { "listChanged": true }
}
```
## 多服务器整合
MCP 的真正威力在多服务器协同工作时显现。
**示例:多服务器差旅规划**
```
┌─────────────────────────────────────────┐
│ AI 差旅规划应用 │
└─────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌────────────┐ ┌──────────┐ ┌─────────────┐
│ 旅行服务器 │ │天气服务器 │ │日历/邮件服务器│
│ - 航班搜索 │ │ - 气候数据│ │ - 日程管理 │
│ - 酒店预订 │ │ - 预报 │ │ - 发送邮件 │
└────────────┘ └──────────┘ └─────────────┘
```
**完整流程**
1. 用户调用提示词:`plan-vacation(destination: "Barcelona", date: "2024-06-15")`
2. 用户选择资源:`calendar://my-calendar/June-2024``travel://preferences/europe`
3. AI 读取资源收集上下文
4. AI 执行工具:`searchFlights()``checkWeather()`
5. AI 请求用户批准:`bookHotel()``createCalendarEvent()`
6. 结果:量身定制的巴塞罗那之旅规划和预订
## 错误码
| 码值 | 名称 | 描述 |
|------|------|------|
| -32700 | Parse Error | 无效的 JSON |
| -32600 | Invalid Request | 格式错误的请求 |
| -32601 | Method Not Found | 未知方法 |
| -32602 | Invalid Params | 无效参数 |
| -32603 | Internal Error | 服务器内部错误 |
## 实现注意事项
- MCP 客户端使用指数退避管理重连
- 工具调用结果序列化为 JSON
- 资源可订阅变更通知
- 工具执行前可能需要用户授权
- 支持参数补全以帮助用户发现有效值

289
openspec/path.md Normal file
View File

@@ -0,0 +1,289 @@
# 路径规范
## 概述
AstrBot 遵循 [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html),定义标准化的目录结构。
**跨平台支持**
- **Linux/macOS 桌面**:遵循 XDG 规范
- **Linux 服务器**:使用 `/var/lib/astrbot`systemd 服务场景)
- **Windows**:不遵循 XDG使用 `%APPDATA%` / `%LOCALAPPDATA%` / `%USERPROFILE%`
- **BSD/Unix**:遵循 XDG 规范
## Linux 服务器场景
### 为什么使用 /var/lib/astrbot
| 原因 | 说明 |
|------|------|
| **FHS 合规** | `/var/lib` 用于存储可变的状态信息,符合文件系统层次结构标准 |
| **systemd 服务** | 服务以系统用户运行,无用户目录访问权限 |
| **系统级目录** | 所有用户共享,适合守护进程部署 |
| **持久化** | `/var` 分区通常有足够空间存储数据 |
**场景说明**
- systemd 服务以 `astrbot` 系统用户运行
- 系统用户没有 `~/.local/share` 等用户目录
- 必须使用系统级目录 `/var/lib/astrbot`
### Linux 服务器路径
| 类型 | 路径 | 说明 |
|------|------|------|
| 配置 | `/var/lib/astrbot/config/` | 配置文件 |
| 数据 | `/var/lib/astrbot/` | 主数据目录 |
| 缓存 | `/var/cache/astrbot/` | 临时文件 |
| 状态 | `/var/lib/astrbot/state/` | 会话状态 |
| 日志 | `/var/log/astrbot/` | 日志文件 |
| 运行时 | `/run/astrbot/` | PID 文件、socket |
**目录结构**
```
/var/lib/astrbot/
├── config/ # 配置文件
├── data/ # 插件、skills 等
│ ├── plugins/
│ ├── plugin_data/
│ ├── skills/
│ ├── knowledge_base/
│ ├── backups/
│ └── webchat/
├── state/ # 会话状态
│ └── sessions/
└── .env # 环境变量
/var/cache/astrbot/
├── temp/ # 临时文件
└── t2i_templates/ # 文转图模板
/run/astrbot/ # 运行时文件
├── astrbot.sock # Unix Socket
└── pid # PID 文件
```
## 平台差异
| 平台 | 配置目录 | 数据目录 | 缓存目录 | 运行时目录 |
|------|----------|----------|----------|------------|
| Linux 桌面 | `$XDG_CONFIG_HOME/astrbot/` | `$XDG_DATA_HOME/astrbot/` | `$XDG_CACHE_HOME/astrbot/` | `$XDG_RUNTIME_DIR/astrbot/` |
| Linux 服务器 | `/var/lib/astrbot/config/` | `/var/lib/astrbot/` | `/var/cache/astrbot/` | `/run/astrbot/` |
| macOS | `$XDG_CONFIG_HOME/astrbot/` | `$XDG_DATA_HOME/astrbot/` | `$XDG_CACHE_HOME/astrbot/` | `$XDG_RUNTIME_DIR/astrbot/` |
| Windows | `%APPDATA%/AstrBot/` | `%LOCALAPPDATA%/AstrBot/` | `%TEMP%/AstrBot/` | `%LOCALAPPDATA%/AstrBot/runtime/` |
## XDG 基础变量Linux/macOS
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `XDG_CONFIG_HOME` | `~/.config` | 用户配置文件目录 |
| `XDG_DATA_HOME` | `~/.local/share` | 用户数据目录 |
| `XDG_CACHE_HOME` | `~/.cache` | 用户缓存目录 |
| `XDG_STATE_HOME` | `~/.local/state` | 用户状态目录 |
| `XDG_RUNTIME_DIR` | `/run/user/<UID>` | 运行时目录 |
## AstrBot 目录结构
```
$XDG_DATA_HOME/astrbot/
├── data/ # 应用数据
│ ├── config/ # 配置文件
│ ├── plugins/ # 插件目录
│ ├── plugin_data/ # 插件数据
│ ├── skills/ # Skills 目录
│ ├── knowledge_base/ # 知识库
│ ├── backups/ # 备份
│ └── webchat/ # WebChat 数据
├── cache/ # 缓存
│ ├── temp/ # 临时文件
│ └── t2i_templates/ # 文转图模板
└── state/ # 状态
└── sessions/ # 会话状态
$XDG_CONFIG_HOME/astrbot/
├── .env # 环境变量
└── config.yaml # 主配置文件
```
## 路径映射
### 配置目录 (`XDG_CONFIG_HOME/astrbot/`)
| 路径 | 说明 | 环境变量 |
|------|------|----------|
| `$XDG_CONFIG_HOME/astrbot/` | AstrBot 配置根目录 | `ASTRBOT_CONFIG_DIR` |
| `$XDG_CONFIG_HOME/astrbot/.env` | 环境变量文件 | - |
| `$XDG_CONFIG_HOME/astrbot/config.yaml` | 主配置文件 | - |
### 数据目录 (`XDG_DATA_HOME/astrbot/`)
| 路径 | 说明 | 环境变量 |
|------|------|----------|
| `$XDG_DATA_HOME/astrbot/` | AstrBot 数据根目录 | `ASTRBOT_DATA_DIR` |
| `$XDG_DATA_HOME/astrbot/plugins/` | 插件目录 | `ASTRBOT_PLUGIN_DIR` |
| `$XDG_DATA_HOME/astrbot/plugin_data/` | 插件数据 | `ASTRBOT_PLUGIN_DATA_DIR` |
| `$XDG_DATA_HOME/astrbot/skills/` | Skills 目录 | `ASTRBOT_SKILLS_DIR` |
| `$XDG_DATA_HOME/astrbot/knowledge_base/` | 知识库 | `ASTRBOT_KB_DIR` |
| `$XDG_DATA_HOME/astrbot/backups/` | 备份目录 | `ASTRBOT_BACKUPS_DIR` |
| `$XDG_DATA_HOME/astrbot/webchat/` | WebChat 数据 | `ASTRBOT_WEBCHAT_DIR` |
### 缓存目录 (`XDG_CACHE_HOME/astrbot/`)
| 路径 | 说明 | 环境变量 |
|------|------|----------|
| `$XDG_CACHE_HOME/astrbot/` | AstrBot 缓存根目录 | `ASTRBOT_CACHE_DIR` |
| `$XDG_CACHE_HOME/astrbot/temp/` | 临时文件 | `ASTRBOT_TEMP_DIR` |
| `$XDG_CACHE_HOME/astrbot/t2i_templates/` | 文转图模板 | - |
### 状态目录 (`XDG_STATE_HOME/astrbot/`)
| 路径 | 说明 | 环境变量 |
|------|------|----------|
| `$XDG_STATE_HOME/astrbot/` | AstrBot 状态根目录 | `ASTRBOT_STATE_DIR` |
| `$XDG_STATE_HOME/astrbot/sessions/` | 会话状态 | - |
### 运行时目录
| 路径 | 说明 | 环境变量 |
|------|------|----------|
| `/run/user/<UID>/astrbot/` | 运行时目录 | `ASTRBOT_RUNTIME_DIR` |
### 项目目录
| 路径 | 说明 | 备注 |
|------|------|------|
| `<source_root>/` | 源码目录 | 固定,指向 astrbot 包位置 |
| `<source_root>/dashboard/dist/` | 前端资源 | 固定 |
## 环境变量覆盖
### 根目录覆盖
| 变量 | 说明 | 优先级 |
|------|------|--------|
| `ASTRBOT_ROOT` | 覆盖整个 AstrBot 数据根目录 | 最高 |
| `ASTRBOT_DATA_DIR` | 覆盖数据目录 | 次高 |
| `ASTRBOT_CONFIG_DIR` | 覆盖配置目录 | 次高 |
### 子目录覆盖
| 变量 | 说明 |
|------|------|
| `ASTRBOT_PLUGIN_DIR` | 插件目录 |
| `ASTRBOT_PLUGIN_DATA_DIR` | 插件数据目录 |
| `ASTRBOT_SKILLS_DIR` | Skills 目录 |
| `ASTRBOT_KB_DIR` | 知识库目录 |
| `ASTRBOT_BACKUPS_DIR` | 备份目录 |
| `ASTRBOT_WEBCHAT_DIR` | WebChat 目录 |
| `ASTRBOT_TEMP_DIR` | 临时文件目录 |
| `ASTRBOT_CACHE_DIR` | 缓存根目录 |
| `ASTRBOT_STATE_DIR` | 状态根目录 |
| `ASTRBOT_RUNTIME_DIR` | 运行时目录 |
### 覆盖优先级
```
ASTRBOT_ROOT > ASTRBOT_DATA_DIR > 子目录变量
```
## 目录用途
| 目录 | 内容 | 是否持久化 |
|------|------|-----------|
| `config/` | 配置文件、.env | 是 |
| `plugins/` | 插件代码 | 是 |
| `plugin_data/` | 插件运行时数据 | 是 |
| `skills/` | Skills 配置 | 是 |
| `knowledge_base/` | 知识库文件 | 是 |
| `backups/` | 备份文件 | 是 |
| `webchat/` | WebChat 数据 | 是 |
| `temp/` | 临时文件 | 否(可清理) |
| `t2i_templates/` | 文转图模板缓存 | 否(可清理) |
| `sessions/` | 会话状态 | 是 |
## 兼容性别名
以下路径函数保留用于向后兼容:
```python
# 旧路径 → 新路径
get_astrbot_root() $XDG_DATA_HOME/astrbot/
get_astrbot_data_path() $XDG_DATA_HOME/astrbot/
get_astrbot_config_path() $XDG_CONFIG_HOME/astrbot/
get_astrbot_plugin_path() $XDG_DATA_HOME/astrbot/plugins/
get_astrbot_plugin_data_path() $XDG_DATA_HOME/astrbot/plugin_data/
get_astrbot_skills_path() $XDG_DATA_HOME/astrbot/skills/
get_astrbot_knowledge_base_path() $XDG_DATA_HOME/astrbot/knowledge_base/
get_astrbot_backups_path() $XDG_DATA_HOME/astrbot/backups/
get_astrbot_webchat_path() $XDG_DATA_HOME/astrbot/webchat/
get_astrbot_temp_path() $XDG_CACHE_HOME/astrbot/temp/
get_astrbot_t2i_templates_path() $XDG_CACHE_HOME/astrbot/t2i_templates/
```
## 目录创建
AstrBot 启动时自动创建以下目录(如不存在):
```
$XDG_CONFIG_HOME/astrbot/
$XDG_DATA_HOME/astrbot/
$XDG_DATA_HOME/astrbot/plugins/
$XDG_DATA_HOME/astrbot/plugin_data/
$XDG_DATA_HOME/astrbot/skills/
$XDG_DATA_HOME/astrbot/knowledge_base/
$XDG_DATA_HOME/astrbot/backups/
$XDG_DATA_HOME/astrbot/webchat/
$XDG_CACHE_HOME/astrbot/
$XDG_CACHE_HOME/astrbot/temp/
$XDG_CACHE_HOME/astrbot/t2i_templates/
$XDG_STATE_HOME/astrbot/
$XDG_STATE_HOME/astrbot/sessions/
```
## 多实例支持
通过 `ASTRBOT_INSTANCE_NAME` 支持多实例:
```
$XDG_DATA_HOME/astrbot/<instance_name>/
├── data/
├── cache/
└── state/
```
## 路径规范总结
### Linux 服务器systemd 部署)
| 类型 | 路径 |
|------|------|
| 配置 | `/var/lib/astrbot/config/` |
| 数据 | `/var/lib/astrbot/` |
| 缓存 | `/var/cache/astrbot/` |
| 状态 | `/var/lib/astrbot/state/` |
| 运行时 | `/run/astrbot/` |
### Linux/macOS 桌面
| 类型 | XDG 路径 |
|------|----------|
| 配置 | `$XDG_CONFIG_HOME/astrbot/` |
| 数据 | `$XDG_DATA_HOME/astrbot/` |
| 缓存 | `$XDG_CACHE_HOME/astrbot/` |
| 状态 | `$XDG_STATE_HOME/astrbot/` |
### Windows
| 类型 | Windows 路径 |
|------|--------------|
| 配置 | `%APPDATA%/AstrBot/` |
| 数据 | `%LOCALAPPDATA%/AstrBot/` |
| 缓存 | `%TEMP%/AstrBot/` |
## 环境变量
所有平台统一使用 `ASTRBOT_*` 环境变量覆盖默认路径,优先级最高。
## 已知限制
- Windows 平台**不遵循** XDG 规范,使用 Windows 标准路径
- 桌面客户端packaged desktop runtime使用 `~/.astrbot/` 作为数据根目录

View File

@@ -1,39 +0,0 @@
# Runtime Status Star Specification
## ADDED Requirements
### Requirement: RuntimeStatusStar provides diagnostic tools
The RuntimeStatusStar SHALL provide callable tools that expose core runtime internal state for diagnostic purposes.
#### Scenario: Get runtime status
- **WHEN** ABP client calls `get_runtime_status` tool
- **THEN** returns `{"running": bool, "uptime_seconds": float}`
#### Scenario: Get protocol status
- **WHEN** ABP client calls `get_protocol_status` tool
- **THEN** returns status of each protocol client (lsp, mcp, acp, abp)
#### Scenario: Get star registry
- **WHEN** ABP client calls `get_star_registry` tool
- **THEN** returns list of registered star names
#### Scenario: Get stats
- **WHEN** ABP client calls `get_stats` tool
- **THEN** returns runtime statistics including message counts
### Requirement: Auto-registration with orchestrator
The RuntimeStatusStar SHALL be automatically registered with the orchestrator on initialization.
#### Scenario: Orchestrator initialization
- **WHEN** AstrbotOrchestrator is created
- **THEN** RuntimeStatusStar instance is created and registered with name "runtime-status-star"
### Requirement: Error handling
The RuntimeStatusStar tools SHALL handle errors gracefully without exposing internal exceptions.
#### Scenario: Orchestrator unavailable
- **WHEN** orchestrator reference is None
- **THEN** returns appropriate error message instead of raising exception