Compare commits
4 Commits
fbc69bcb36
...
82b40121c6
| Author | SHA1 | Date | |
|---|---|---|---|
|
82b40121c6
|
|||
|
39c8a98850
|
|||
|
089fe7012c
|
|||
|
|
3d8e0bc26e |
32
.gitea/workflows/build.yaml
Normal file
32
.gitea/workflows/build.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Build and Push Docker Image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- gitea
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to Docker Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: docker.gardel.top
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Build and Push Docker Image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
tags: docker.gardel.top/gardel/mofox:dev
|
||||
build-args: |
|
||||
BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
||||
VCS_REF=${{ github.sha }}
|
||||
149
.github/workflows/docker-image.yml
vendored
149
.github/workflows/docker-image.yml
vendored
@@ -1,149 +0,0 @@
|
||||
name: Docker Build and Push
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- dev
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
- "v*"
|
||||
- "*.*.*"
|
||||
- "*.*.*-*"
|
||||
workflow_dispatch: # 允许手动触发工作流
|
||||
|
||||
# Workflow's jobs
|
||||
jobs:
|
||||
build-amd64:
|
||||
name: Build AMD64 Image
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
digest: ${{ steps.build.outputs.digest }}
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
buildkitd-flags: --debug
|
||||
|
||||
# Log in docker hub
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
# Generate metadata for Docker images
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ secrets.DOCKERHUB_USERNAME }}/mofox
|
||||
|
||||
# Build and push AMD64 image by digest
|
||||
- name: Build and push AMD64
|
||||
id: build
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
file: ./Dockerfile
|
||||
cache-from: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/mofox:amd64-buildcache
|
||||
cache-to: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/mofox:amd64-buildcache,mode=max
|
||||
outputs: type=image,name=${{ secrets.DOCKERHUB_USERNAME }}/mofox,push-by-digest=true,name-canonical=true,push=true
|
||||
build-args: |
|
||||
BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
||||
VCS_REF=${{ github.sha }}
|
||||
|
||||
build-arm64:
|
||||
name: Build ARM64 Image
|
||||
runs-on: ubuntu-24.04-arm
|
||||
outputs:
|
||||
digest: ${{ steps.build.outputs.digest }}
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
buildkitd-flags: --debug
|
||||
|
||||
# Log in docker hub
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
# Generate metadata for Docker images
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ secrets.DOCKERHUB_USERNAME }}/mofox
|
||||
|
||||
# Build and push ARM64 image by digest
|
||||
- name: Build and push ARM64
|
||||
id: build
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/arm64/v8
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
file: ./Dockerfile
|
||||
cache-from: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/mofox:arm64-buildcache
|
||||
cache-to: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/mofox:arm64-buildcache,mode=max
|
||||
outputs: type=image,name=${{ secrets.DOCKERHUB_USERNAME }}/mofox,push-by-digest=true,name-canonical=true,push=true
|
||||
build-args: |
|
||||
BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
||||
VCS_REF=${{ github.sha }}
|
||||
|
||||
create-manifest:
|
||||
name: Create Multi-Arch Manifest
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- build-amd64
|
||||
- build-arm64
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
# Log in docker hub
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
# Generate metadata for Docker images
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ secrets.DOCKERHUB_USERNAME }}/mofox
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=tag
|
||||
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=sha,prefix=${{ github.ref_name }}-,enable=${{ github.ref_type == 'branch' }}
|
||||
|
||||
- name: Create and Push Manifest
|
||||
run: |
|
||||
# 为每个标签创建多架构镜像
|
||||
for tag in $(echo "${{ steps.meta.outputs.tags }}" | tr '\n' ' '); do
|
||||
echo "Creating manifest for $tag"
|
||||
docker buildx imagetools create -t $tag \
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/mofox@${{ needs.build-amd64.outputs.digest }} \
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/mofox@${{ needs.build-arm64.outputs.digest }}
|
||||
done
|
||||
@@ -9,6 +9,10 @@ RUN apt-get update && apt-get install -y build-essential
|
||||
# 复制依赖列表和锁文件
|
||||
COPY pyproject.toml uv.lock ./
|
||||
|
||||
COPY --from=mwader/static-ffmpeg:latest /ffmpeg /usr/local/bin/ffmpeg
|
||||
COPY --from=mwader/static-ffmpeg:latest /ffprobe /usr/local/bin/ffprobe
|
||||
RUN ldconfig && ffmpeg -version
|
||||
|
||||
# 安装依赖(使用 --frozen 确保使用锁文件中的版本)
|
||||
RUN uv sync --frozen --no-dev
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# 增强命令系统使用指南
|
||||
|
||||
> ⚠️ **重要:插件命令必须使用 PlusCommand!**
|
||||
>
|
||||
> - ✅ **推荐**:`PlusCommand` - 插件开发的标准基类
|
||||
> - ❌ **禁止**:`BaseCommand` - 仅供框架内部使用
|
||||
>
|
||||
> 如果你直接使用 `BaseCommand`,将需要手动处理参数解析、正则匹配等复杂逻辑,并且 `execute()` 方法签名也不同。
|
||||
|
||||
## 概述
|
||||
|
||||
增强命令系统是MoFox-Bot插件系统的一个扩展,让命令的定义和使用变得更加简单直观。你不再需要编写复杂的正则表达式,只需要定义命令名、别名和参数处理逻辑即可。
|
||||
@@ -224,24 +231,95 @@ class ConfigurableCommand(PlusCommand):
|
||||
|
||||
## 返回值说明
|
||||
|
||||
`execute`方法需要返回一个三元组:
|
||||
`execute`方法必须返回一个三元组:
|
||||
|
||||
```python
|
||||
return (执行成功标志, 可选消息, 是否拦截后续处理)
|
||||
async def execute(self, args: CommandArgs) -> Tuple[bool, Optional[str], bool]:
|
||||
# ... 你的逻辑 ...
|
||||
return (执行成功标志, 日志描述, 是否拦截消息)
|
||||
```
|
||||
|
||||
- **执行成功标志** (bool): True表示命令执行成功,False表示失败
|
||||
- **可选消息** (Optional[str]): 用于日志记录的消息
|
||||
- **是否拦截后续处理** (bool): True表示拦截消息,不进行后续处理
|
||||
### 返回值详解
|
||||
|
||||
| 位置 | 类型 | 名称 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 1 | `bool` | 执行成功标志 | `True` = 命令执行成功<br>`False` = 命令执行失败 |
|
||||
| 2 | `Optional[str]` | 日志描述 | 用于内部日志记录的描述性文本<br>⚠️ **不是发给用户的消息!** |
|
||||
| 3 | `bool` | 是否拦截消息 | `True` = 拦截,阻止后续处理(推荐)<br>`False` = 不拦截,继续后续处理 |
|
||||
|
||||
### 重要:消息发送 vs 日志描述
|
||||
|
||||
⚠️ **常见错误:在返回值中返回用户消息**
|
||||
|
||||
```python
|
||||
# ❌ 错误做法 - 不要这样做!
|
||||
async def execute(self, args: CommandArgs):
|
||||
message = "你好,这是给用户的消息"
|
||||
return True, message, True # 这个消息不会发给用户!
|
||||
|
||||
# ✅ 正确做法 - 使用 self.send_text()
|
||||
async def execute(self, args: CommandArgs):
|
||||
await self.send_text("你好,这是给用户的消息") # 发送给用户
|
||||
return True, "执行了问候命令", True # 日志描述
|
||||
```
|
||||
|
||||
### 完整示例
|
||||
|
||||
```python
|
||||
async def execute(self, args: CommandArgs) -> Tuple[bool, Optional[str], bool]:
|
||||
"""execute 方法的完整示例"""
|
||||
|
||||
# 1. 参数验证
|
||||
if args.is_empty():
|
||||
await self.send_text("⚠️ 请提供参数")
|
||||
return True, "缺少参数", True
|
||||
|
||||
# 2. 执行逻辑
|
||||
user_input = args.get_raw()
|
||||
result = process_input(user_input)
|
||||
|
||||
# 3. 发送消息给用户
|
||||
await self.send_text(f"✅ 处理结果:{result}")
|
||||
|
||||
# 4. 返回:成功、日志描述、拦截消息
|
||||
return True, f"处理了用户输入: {user_input[:20]}", True
|
||||
```
|
||||
|
||||
### 拦截标志使用指导
|
||||
|
||||
- **返回 `True`**(推荐):命令已完成处理,不需要后续处理(如 LLM 回复)
|
||||
- **返回 `False`**:允许系统继续处理(例如让 LLM 也回复)
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **命令命名**:使用简短、直观的命令名
|
||||
2. **别名设置**:为常用命令提供简短别名
|
||||
3. **参数验证**:总是检查参数的有效性
|
||||
4. **错误处理**:提供清晰的错误提示和使用说明
|
||||
5. **配置支持**:重要设置应该可配置
|
||||
6. **聊天类型**:根据命令功能选择合适的聊天类型限制
|
||||
### 1. 命令设计
|
||||
- ✅ **命令命名**:使用简短、直观的命令名(如 `time`、`help`、`status`)
|
||||
- ✅ **别名设置**:为常用命令提供简短别名(如 `echo` -> `e`、`say`)
|
||||
- ✅ **聊天类型**:根据命令功能选择 `ChatType.ALL`/`GROUP`/`PRIVATE`
|
||||
|
||||
### 2. 参数处理
|
||||
- ✅ **总是验证**:使用 `args.is_empty()`、`args.count()` 检查参数
|
||||
- ✅ **友好提示**:参数错误时提供清晰的用法说明
|
||||
- ✅ **默认值**:为可选参数提供合理的默认值
|
||||
|
||||
### 3. 消息发送
|
||||
- ✅ **使用 `self.send_text()`**:发送消息给用户
|
||||
- ❌ **不要在返回值中返回用户消息**:返回值是日志描述
|
||||
- ✅ **拦截消息**:大多数情况返回 `True` 作为第三个参数
|
||||
|
||||
### 4. 错误处理
|
||||
- ✅ **Try-Catch**:捕获并处理可能的异常
|
||||
- ✅ **清晰反馈**:告诉用户发生了什么问题
|
||||
- ✅ **记录日志**:在返回值中提供有用的调试信息
|
||||
|
||||
### 5. 配置管理
|
||||
- ✅ **可配置化**:重要设置应该通过 `self.get_config()` 读取
|
||||
- ✅ **提供默认值**:即使配置缺失也能正常工作
|
||||
|
||||
### 6. 代码质量
|
||||
- ✅ **类型注解**:使用完整的类型提示
|
||||
- ✅ **文档字符串**:为 `execute()` 方法添加文档说明
|
||||
- ✅ **代码注释**:为复杂逻辑添加必要的注释
|
||||
|
||||
## 完整示例
|
||||
|
||||
|
||||
265
docs/plugins/README.md
Normal file
265
docs/plugins/README.md
Normal file
@@ -0,0 +1,265 @@
|
||||
# 📚 MoFox-Bot 插件开发文档导航
|
||||
|
||||
欢迎来到 MoFox-Bot 插件系统开发文档!本文档帮助你快速找到所需的学习资源。
|
||||
|
||||
---
|
||||
|
||||
## 🎯 我应该从哪里开始?
|
||||
|
||||
### 第一次接触插件开发?
|
||||
👉 **从这里开始**:[快速开始指南](quick-start.md)
|
||||
|
||||
这是一个循序渐进的教程,带你从零开始创建第一个插件,包含完整的代码示例。
|
||||
|
||||
### 遇到问题了?
|
||||
👉 **先看这里**:[故障排除指南](troubleshooting-guide.md) ⭐
|
||||
|
||||
包含10个最常见问题的解决方案,可能5分钟就能解决你的问题。
|
||||
|
||||
### 想深入了解特定功能?
|
||||
👉 **查看下方分类导航**,找到你需要的文档。
|
||||
|
||||
---
|
||||
|
||||
## 📖 学习路径建议
|
||||
|
||||
### 🌟 新手路径(按顺序阅读)
|
||||
|
||||
1. **[快速开始指南](quick-start.md)** ⭐ 必读
|
||||
- 创建插件目录和配置
|
||||
- 实现第一个 Action 组件
|
||||
- 实现第一个 Command 组件
|
||||
- 添加配置文件
|
||||
- 预计阅读时间:30-45分钟
|
||||
|
||||
2. **[增强命令指南](PLUS_COMMAND_GUIDE.md)** ⭐ 必读
|
||||
- 理解 PlusCommand 与 BaseCommand 的区别
|
||||
- 学习命令参数处理
|
||||
- 掌握返回值规范
|
||||
- 预计阅读时间:20-30分钟
|
||||
|
||||
3. **[Action 组件详解](action-components.md)** ⭐ 必读
|
||||
- 理解 Action 的激活机制
|
||||
- 学习自定义激活逻辑
|
||||
- 掌握 Action 的使用场景
|
||||
- 预计阅读时间:25-35分钟
|
||||
|
||||
4. **[故障排除指南](troubleshooting-guide.md)** ⭐ 建议收藏
|
||||
- 常见错误及解决方案
|
||||
- 最佳实践速查
|
||||
- 调试技巧
|
||||
- 随时查阅
|
||||
|
||||
---
|
||||
|
||||
### 🚀 进阶路径(根据需求选择)
|
||||
|
||||
#### 需要配置系统?
|
||||
- **[配置文件系统指南](configuration-guide.md)**
|
||||
- 自动生成配置文件
|
||||
- 配置 Schema 定义
|
||||
- 配置读取和验证
|
||||
|
||||
#### 需要响应事件?
|
||||
- **[事件系统指南](event-system-guide.md)**
|
||||
- 订阅系统事件
|
||||
- 创建自定义事件
|
||||
- 事件处理器实现
|
||||
|
||||
#### 需要集成外部功能?
|
||||
- **[Tool 组件指南](tool_guide.md)**
|
||||
- 为 LLM 提供工具调用能力
|
||||
- 函数调用集成
|
||||
- Tool 参数定义
|
||||
|
||||
#### 需要依赖其他插件?
|
||||
- **[依赖管理指南](dependency-management.md)**
|
||||
- 声明插件依赖
|
||||
- Python 包依赖
|
||||
- 依赖版本管理
|
||||
|
||||
#### 需要高级激活控制?
|
||||
- **[Action 激活机制重构指南](action-activation-guide.md)**
|
||||
- 自定义激活逻辑
|
||||
- 关键词匹配激活
|
||||
- LLM 智能判断激活
|
||||
- 随机激活策略
|
||||
|
||||
---
|
||||
|
||||
## 📂 文档结构说明
|
||||
|
||||
### 核心文档(必读)
|
||||
|
||||
```
|
||||
📄 quick-start.md 快速开始指南 ⭐ 新手必读
|
||||
📄 PLUS_COMMAND_GUIDE.md 增强命令系统指南 ⭐ 必读
|
||||
📄 action-components.md Action 组件详解 ⭐ 必读
|
||||
📄 troubleshooting-guide.md 故障排除指南 ⭐ 遇到问题先看这个
|
||||
```
|
||||
|
||||
### 进阶文档(按需阅读)
|
||||
|
||||
```
|
||||
📄 configuration-guide.md 配置系统详解
|
||||
📄 event-system-guide.md 事件系统详解
|
||||
📄 tool_guide.md Tool 组件详解
|
||||
📄 action-activation-guide.md Action 激活机制详解
|
||||
📄 dependency-management.md 依赖管理详解
|
||||
📄 manifest-guide.md Manifest 文件规范
|
||||
```
|
||||
|
||||
### API 参考文档
|
||||
|
||||
```
|
||||
📁 api/ API 参考文档目录
|
||||
├── 消息相关
|
||||
│ ├── send-api.md 消息发送 API
|
||||
│ ├── message-api.md 消息处理 API
|
||||
│ └── chat-api.md 聊天流 API
|
||||
│
|
||||
├── AI 相关
|
||||
│ ├── llm-api.md LLM 交互 API
|
||||
│ └── generator-api.md 回复生成 API
|
||||
│
|
||||
├── 数据相关
|
||||
│ ├── database-api.md 数据库操作 API
|
||||
│ ├── config-api.md 配置读取 API
|
||||
│ └── person-api.md 人物关系 API
|
||||
│
|
||||
├── 组件相关
|
||||
│ ├── plugin-manage-api.md 插件管理 API
|
||||
│ └── component-manage-api.md 组件管理 API
|
||||
│
|
||||
└── 其他
|
||||
├── emoji-api.md 表情包 API
|
||||
├── tool-api.md 工具 API
|
||||
└── logging-api.md 日志 API
|
||||
```
|
||||
|
||||
### 其他文件
|
||||
|
||||
```
|
||||
📄 index.md 文档索引(旧版,建议查看本 README)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎓 按功能查找文档
|
||||
|
||||
### 我想创建...
|
||||
|
||||
| 目标 | 推荐文档 | 难度 |
|
||||
|------|----------|------|
|
||||
| **一个简单的命令** | [快速开始](quick-start.md) → [增强命令指南](PLUS_COMMAND_GUIDE.md) | ⭐ 入门 |
|
||||
| **一个智能 Action** | [快速开始](quick-start.md) → [Action 组件](action-components.md) | ⭐⭐ 中级 |
|
||||
| **带复杂参数的命令** | [增强命令指南](PLUS_COMMAND_GUIDE.md) | ⭐⭐ 中级 |
|
||||
| **需要配置的插件** | [配置系统指南](configuration-guide.md) | ⭐⭐ 中级 |
|
||||
| **响应系统事件的插件** | [事件系统指南](event-system-guide.md) | ⭐⭐⭐ 高级 |
|
||||
| **为 LLM 提供工具** | [Tool 组件指南](tool_guide.md) | ⭐⭐⭐ 高级 |
|
||||
| **依赖其他插件的插件** | [依赖管理指南](dependency-management.md) | ⭐⭐ 中级 |
|
||||
|
||||
### 我想学习...
|
||||
|
||||
| 主题 | 相关文档 |
|
||||
|------|----------|
|
||||
| **如何发送消息** | [发送 API](api/send-api.md) / [增强命令指南](PLUS_COMMAND_GUIDE.md) |
|
||||
| **如何处理参数** | [增强命令指南](PLUS_COMMAND_GUIDE.md) |
|
||||
| **如何使用 LLM** | [LLM API](api/llm-api.md) |
|
||||
| **如何操作数据库** | [数据库 API](api/database-api.md) |
|
||||
| **如何读取配置** | [配置 API](api/config-api.md) / [配置系统指南](configuration-guide.md) |
|
||||
| **如何获取消息历史** | [消息 API](api/message-api.md) / [聊天流 API](api/chat-api.md) |
|
||||
| **如何发送表情包** | [表情包 API](api/emoji-api.md) |
|
||||
| **如何记录日志** | [日志 API](api/logging-api.md) |
|
||||
|
||||
---
|
||||
|
||||
## 🆘 遇到问题?
|
||||
|
||||
### 第一步:查看故障排除指南
|
||||
👉 [故障排除指南](troubleshooting-guide.md) 包含10个最常见问题的解决方案
|
||||
|
||||
### 第二步:查看相关文档
|
||||
- **插件无法加载?** → [快速开始指南](quick-start.md)
|
||||
- **命令无响应?** → [增强命令指南](PLUS_COMMAND_GUIDE.md)
|
||||
- **Action 不触发?** → [Action 组件详解](action-components.md)
|
||||
- **配置不生效?** → [配置系统指南](configuration-guide.md)
|
||||
|
||||
### 第三步:检查日志
|
||||
查看 `logs/app_*.jsonl` 获取详细错误信息
|
||||
|
||||
### 第四步:寻求帮助
|
||||
- 在线文档:https://mofox-studio.github.io/MoFox-Bot-Docs/
|
||||
- GitHub Issues:提交详细的问题报告
|
||||
- 社区讨论:加入开发者社区
|
||||
|
||||
---
|
||||
|
||||
## 📌 重要提示
|
||||
|
||||
### ⚠️ 常见陷阱
|
||||
|
||||
1. **不要使用 `BaseCommand`**
|
||||
- ✅ 使用:`PlusCommand`
|
||||
- ❌ 避免:`BaseCommand`(仅供框架内部使用)
|
||||
|
||||
2. **不要在返回值中返回用户消息**
|
||||
- ✅ 使用:`await self.send_text("消息")`
|
||||
- ❌ 避免:`return True, "消息", True`
|
||||
|
||||
3. **手动创建 ComponentInfo 时必须指定 component_type**
|
||||
- ✅ 推荐:使用 `get_action_info()` 自动生成
|
||||
- ⚠️ 手动创建时:必须指定 `component_type=ComponentType.ACTION`
|
||||
|
||||
### 💡 最佳实践
|
||||
|
||||
- ✅ 总是使用类型注解
|
||||
- ✅ 为 `execute()` 方法添加文档字符串
|
||||
- ✅ 使用 `self.get_config()` 读取配置
|
||||
- ✅ 使用异步操作 `async/await`
|
||||
- ✅ 在发送消息前验证参数
|
||||
- ✅ 提供清晰的错误提示
|
||||
|
||||
---
|
||||
|
||||
## 🔄 文档更新记录
|
||||
|
||||
### v1.1.0 (2024-12-17)
|
||||
- ✨ 新增 [故障排除指南](troubleshooting-guide.md)
|
||||
- ✅ 修复 [快速开始指南](quick-start.md) 中的 BaseCommand 示例
|
||||
- ✅ 增强 [增强命令指南](PLUS_COMMAND_GUIDE.md) 的返回值说明
|
||||
- ✅ 完善 [Action 组件](action-components.md) 的 component_type 说明
|
||||
- 📝 创建本导航文档
|
||||
|
||||
### v1.0.0 (2024-11)
|
||||
- 📚 初始文档发布
|
||||
|
||||
---
|
||||
|
||||
## 📞 反馈与贡献
|
||||
|
||||
如果你发现文档中的错误或有改进建议:
|
||||
|
||||
1. **提交 Issue**:在 GitHub 仓库提交文档问题
|
||||
2. **提交 PR**:直接修改文档并提交 Pull Request
|
||||
3. **社区反馈**:在社区讨论中提出建议
|
||||
|
||||
你的反馈对我们改进文档至关重要!🙏
|
||||
|
||||
---
|
||||
|
||||
## 🎉 开始你的插件开发之旅
|
||||
|
||||
准备好了吗?从这里开始:
|
||||
|
||||
1. 📖 阅读 [快速开始指南](quick-start.md)
|
||||
2. 💻 创建你的第一个插件
|
||||
3. 🔧 遇到问题查看 [故障排除指南](troubleshooting-guide.md)
|
||||
4. 🚀 探索更多高级功能
|
||||
|
||||
**祝你开发愉快!** 🎊
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2024-12-17
|
||||
**文档版本**:v1.1.0
|
||||
@@ -38,11 +38,44 @@ class ExampleAction(BaseAction):
|
||||
执行Action的主要逻辑
|
||||
|
||||
Returns:
|
||||
Tuple[bool, str]: (是否成功, 执行结果描述)
|
||||
Tuple[bool, str]: 两个元素的元组
|
||||
- bool: 是否执行成功 (True=成功, False=失败)
|
||||
- str: 执行结果的简短描述(用于日志记录)
|
||||
|
||||
注意:
|
||||
- 使用 self.send_text() 等方法发送消息给用户
|
||||
- 返回值中的描述仅用于内部日志,不会发送给用户
|
||||
"""
|
||||
# ---- 执行动作的逻辑 ----
|
||||
# 发送消息给用户
|
||||
await self.send_text("这是发给用户的消息")
|
||||
|
||||
# 返回执行结果(用于日志)
|
||||
return True, "执行成功"
|
||||
```
|
||||
|
||||
#### execute() 返回值 vs Command 返回值
|
||||
|
||||
⚠️ **重要:Action 和 Command 的返回值不同!**
|
||||
|
||||
| 组件类型 | 返回值 | 说明 |
|
||||
|----------|----------|------|
|
||||
| **Action** | `Tuple[bool, str]` | 2个元素:成功标志、日志描述 |
|
||||
| **Command** | `Tuple[bool, Optional[str], bool]` | 3个元素:成功标志、日志描述、拦截标志 |
|
||||
|
||||
```python
|
||||
# Action 返回值
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
await self.send_text("给用户的消息")
|
||||
return True, "日志:执行了XX动作" # 2个元素
|
||||
|
||||
# Command 返回值
|
||||
async def execute(self, args: CommandArgs) -> Tuple[bool, Optional[str], bool]:
|
||||
await self.send_text("给用户的消息")
|
||||
return True, "日志:执行了XX命令", True # 3个元素
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### associated_types: 该Action会发送的消息类型,例如文本、表情等。
|
||||
|
||||
这部分由Adapter传递给处理器。
|
||||
@@ -68,6 +101,65 @@ class ExampleAction(BaseAction):
|
||||
|
||||
---
|
||||
|
||||
## 组件信息注册说明
|
||||
|
||||
### 自动生成 ComponentInfo(推荐)
|
||||
|
||||
大多数情况下,你不需要手动创建 `ActionInfo` 对象。系统提供了 `get_action_info()` 方法来自动生成:
|
||||
|
||||
```python
|
||||
# 推荐的方式 - 自动生成
|
||||
class HelloAction(BaseAction):
|
||||
action_name = "hello"
|
||||
action_description = "问候动作"
|
||||
# ... 其他配置 ...
|
||||
|
||||
# 在插件中注册
|
||||
def get_plugin_components(self):
|
||||
return [
|
||||
(HelloAction.get_action_info(), HelloAction), # 自动生成 ActionInfo
|
||||
]
|
||||
```
|
||||
|
||||
### 手动创建 ActionInfo(高级用法)
|
||||
|
||||
⚠️ **重要:如果手动创建 ActionInfo,必须指定 `component_type` 参数!**
|
||||
|
||||
当你需要自定义 `ActionInfo` 时(例如动态生成组件),必须手动指定 `component_type`:
|
||||
|
||||
```python
|
||||
from src.plugin_system import ActionInfo, ComponentType
|
||||
|
||||
# ❌ 错误 - 缺少 component_type
|
||||
action_info = ActionInfo(
|
||||
name="hello",
|
||||
description="问候动作"
|
||||
# 错误:会报错 "missing required argument: 'component_type'"
|
||||
)
|
||||
|
||||
# ✅ 正确 - 必须指定 component_type
|
||||
action_info = ActionInfo(
|
||||
name="hello",
|
||||
description="问候动作",
|
||||
component_type=ComponentType.ACTION # 必须指定!
|
||||
)
|
||||
```
|
||||
|
||||
**为什么需要手动指定?**
|
||||
|
||||
- `get_action_info()` 方法会自动设置 `component_type`
|
||||
- 但手动创建时,系统无法自动推断类型,必须明确指定
|
||||
|
||||
**什么时候需要手动创建?**
|
||||
|
||||
- 动态生成组件
|
||||
- 自定义 `get_handler_info()` 方法
|
||||
- 需要特殊的 ComponentInfo 配置
|
||||
|
||||
大多数情况下,直接使用 `get_action_info()` 即可,无需手动创建。
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Action 调用的决策机制
|
||||
|
||||
Action采用**两层决策机制**来优化性能和决策质量:
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
## 新手入门
|
||||
|
||||
- [📖 快速开始指南](quick-start.md) - 快速创建你的第一个插件
|
||||
- [🔧 故障排除指南](troubleshooting-guide.md) - 快速解决常见问题 ⭐ **新增**
|
||||
|
||||
## 组件功能详解
|
||||
|
||||
|
||||
@@ -195,29 +195,35 @@ Command是最简单,最直接的响应,不由LLM判断选择使用
|
||||
```python
|
||||
# 在现有代码基础上,添加Command组件
|
||||
import datetime
|
||||
from src.plugin_system import BaseCommand
|
||||
#导入Command基类
|
||||
from src.plugin_system import PlusCommand, CommandArgs
|
||||
# 导入增强命令基类 - 推荐使用!
|
||||
|
||||
class TimeCommand(BaseCommand):
|
||||
class TimeCommand(PlusCommand):
|
||||
"""时间查询Command - 响应/time命令"""
|
||||
|
||||
command_name = "time"
|
||||
command_description = "查询当前时间"
|
||||
|
||||
# === 命令设置(必须填写)===
|
||||
command_pattern = r"^/time$" # 精确匹配 "/time" 命令
|
||||
# 注意:使用 PlusCommand 不需要 command_pattern,会自动生成!
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str], bool]:
|
||||
"""执行时间查询"""
|
||||
async def execute(self, args: CommandArgs) -> Tuple[bool, Optional[str], bool]:
|
||||
"""执行时间查询
|
||||
|
||||
Args:
|
||||
args: 命令参数(本例中不使用)
|
||||
|
||||
Returns:
|
||||
(成功标志, 日志描述, 是否拦截消息)
|
||||
"""
|
||||
# 获取当前时间
|
||||
time_format: str = "%Y-%m-%d %H:%M:%S"
|
||||
now = datetime.datetime.now()
|
||||
time_str = now.strftime(time_format)
|
||||
|
||||
# 发送时间信息
|
||||
message = f"⏰ 当前时间:{time_str}"
|
||||
await self.send_text(message)
|
||||
# 发送时间信息给用户
|
||||
await self.send_text(f"⏰ 当前时间:{time_str}")
|
||||
|
||||
# 返回:成功、日志描述、拦截消息
|
||||
return True, f"显示了当前时间: {time_str}", True
|
||||
|
||||
@register_plugin
|
||||
@@ -239,14 +245,29 @@ class HelloWorldPlugin(BasePlugin):
|
||||
]
|
||||
```
|
||||
|
||||
同样的,我们通过 `get_plugin_components()` 方法,通过调用`get_action_info()`这个内置方法将 `TimeCommand` 注册为插件的一个组件。
|
||||
同样的,我们通过 `get_plugin_components()` 方法,通过调用`get_command_info()`这个内置方法将 `TimeCommand` 注册为插件的一个组件。
|
||||
|
||||
**Command组件解释:**
|
||||
|
||||
- `command_pattern` 使用正则表达式匹配用户输入
|
||||
- `^/time$` 表示精确匹配 "/time"
|
||||
> ⚠️ **重要:请使用 PlusCommand 而不是 BaseCommand!**
|
||||
>
|
||||
> - ✅ **PlusCommand**:推荐使用,自动处理参数解析,无需编写正则表达式
|
||||
> - ❌ **BaseCommand**:仅供框架内部使用,插件开发者不应直接使用
|
||||
|
||||
有关 Command 组件的更多信息,请参考 [Command组件指南](./command-components.md)。
|
||||
**PlusCommand 的优势:**
|
||||
- ✅ 无需编写 `command_pattern` 正则表达式
|
||||
- ✅ 自动解析命令参数(通过 `CommandArgs`)
|
||||
- ✅ 支持命令别名(`command_aliases`)
|
||||
- ✅ 更简单的 API,更容易上手
|
||||
|
||||
**execute() 方法说明:**
|
||||
- 参数:`args: CommandArgs` - 包含解析后的命令参数
|
||||
- 返回值:`(bool, str, bool)` 三元组
|
||||
- `bool`:命令是否执行成功
|
||||
- `str`:日志描述(**不是发给用户的消息**)
|
||||
- `bool`:是否拦截消息,阻止后续处理
|
||||
|
||||
有关增强命令的详细信息,请参考 [增强命令指南](./PLUS_COMMAND_GUIDE.md)。
|
||||
|
||||
### 8. 测试时间查询Command
|
||||
|
||||
@@ -377,28 +398,31 @@ class HelloAction(BaseAction):
|
||||
|
||||
return True, "发送了问候消息"
|
||||
|
||||
class TimeCommand(BaseCommand):
|
||||
class TimeCommand(PlusCommand):
|
||||
"""时间查询Command - 响应/time命令"""
|
||||
|
||||
command_name = "time"
|
||||
command_description = "查询当前时间"
|
||||
|
||||
# === 命令设置(必须填写)===
|
||||
command_pattern = r"^/time$" # 精确匹配 "/time" 命令
|
||||
# 注意:PlusCommand 不需要 command_pattern!
|
||||
|
||||
async def execute(self) -> Tuple[bool, str, bool]:
|
||||
"""执行时间查询"""
|
||||
async def execute(self, args: CommandArgs) -> Tuple[bool, str, bool]:
|
||||
"""执行时间查询
|
||||
|
||||
Args:
|
||||
args: 命令参数对象
|
||||
"""
|
||||
import datetime
|
||||
|
||||
# 获取当前时间
|
||||
# 从配置获取时间格式
|
||||
time_format: str = self.get_config("time.format", "%Y-%m-%d %H:%M:%S") # type: ignore
|
||||
now = datetime.datetime.now()
|
||||
time_str = now.strftime(time_format)
|
||||
|
||||
# 发送时间信息
|
||||
message = f"⏰ 当前时间:{time_str}"
|
||||
await self.send_text(message)
|
||||
# 发送时间信息给用户
|
||||
await self.send_text(f"⏰ 当前时间:{time_str}")
|
||||
|
||||
# 返回:成功、日志描述、拦截消息
|
||||
return True, f"显示了当前时间: {time_str}", True
|
||||
```
|
||||
|
||||
|
||||
395
docs/plugins/troubleshooting-guide.md
Normal file
395
docs/plugins/troubleshooting-guide.md
Normal file
@@ -0,0 +1,395 @@
|
||||
# 🔧 插件开发故障排除指南
|
||||
|
||||
本指南帮助你快速解决 MoFox-Bot 插件开发中的常见问题。
|
||||
|
||||
---
|
||||
|
||||
## 📋 快速诊断清单
|
||||
|
||||
遇到问题时,首先按照以下步骤检查:
|
||||
|
||||
1. ✅ 检查日志文件 `logs/app_*.jsonl`
|
||||
2. ✅ 确认插件已在 `_manifest.json` 中正确配置
|
||||
3. ✅ 验证你使用的是 `PlusCommand` 而不是 `BaseCommand`
|
||||
4. ✅ 检查 `execute()` 方法签名是否正确
|
||||
5. ✅ 确认返回值格式正确
|
||||
|
||||
---
|
||||
|
||||
## 🔴 严重问题:插件无法加载
|
||||
|
||||
### 错误 #1: "未检测到插件"
|
||||
|
||||
**症状**:
|
||||
- 插件目录存在,但日志中没有加载信息
|
||||
- `get_plugin_components()` 返回空列表
|
||||
|
||||
**可能原因与解决方案**:
|
||||
|
||||
#### ❌ 缺少 `@register_plugin` 装饰器
|
||||
|
||||
```python
|
||||
# 错误 - 缺少装饰器
|
||||
class MyPlugin(BasePlugin): # 不会被检测到
|
||||
pass
|
||||
|
||||
# 正确 - 添加装饰器
|
||||
@register_plugin # 必须添加!
|
||||
class MyPlugin(BasePlugin):
|
||||
pass
|
||||
```
|
||||
|
||||
#### ❌ `plugin.py` 文件不存在或位置错误
|
||||
|
||||
```
|
||||
plugins/
|
||||
└── my_plugin/
|
||||
├── _manifest.json ✅
|
||||
└── plugin.py ✅ 必须在这里
|
||||
```
|
||||
|
||||
#### ❌ `_manifest.json` 格式错误
|
||||
|
||||
```json
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"name": "My Plugin",
|
||||
"version": "1.0.0",
|
||||
"description": "插件描述",
|
||||
"author": {
|
||||
"name": "Your Name"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 错误 #2: "ActionInfo.__init__() missing required argument: 'component_type'"
|
||||
|
||||
**症状**:
|
||||
```
|
||||
TypeError: ActionInfo.__init__() missing 1 required positional argument: 'component_type'
|
||||
```
|
||||
|
||||
**原因**:手动创建 `ActionInfo` 时未指定 `component_type` 参数
|
||||
|
||||
**解决方案**:
|
||||
|
||||
```python
|
||||
from src.plugin_system import ActionInfo, ComponentType
|
||||
|
||||
# ❌ 错误 - 缺少 component_type
|
||||
action_info = ActionInfo(
|
||||
name="my_action",
|
||||
description="我的动作"
|
||||
)
|
||||
|
||||
# ✅ 正确方法 1 - 使用自动生成(推荐)
|
||||
class MyAction(BaseAction):
|
||||
action_name = "my_action"
|
||||
action_description = "我的动作"
|
||||
|
||||
def get_plugin_components(self):
|
||||
return [
|
||||
(MyAction.get_action_info(), MyAction) # 自动生成,推荐!
|
||||
]
|
||||
|
||||
# ✅ 正确方法 2 - 手动指定 component_type
|
||||
action_info = ActionInfo(
|
||||
name="my_action",
|
||||
description="我的动作",
|
||||
component_type=ComponentType.ACTION # 必须指定!
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🟡 命令问题:命令无响应
|
||||
|
||||
### 错误 #3: 命令被识别但不执行
|
||||
|
||||
**症状**:
|
||||
- 输入 `/mycommand` 后没有任何反应
|
||||
- 日志显示命令已匹配但未执行
|
||||
|
||||
**可能原因与解决方案**:
|
||||
|
||||
#### ❌ 使用了 `BaseCommand` 而不是 `PlusCommand`
|
||||
|
||||
```python
|
||||
# ❌ 错误 - 使用 BaseCommand
|
||||
from src.plugin_system import BaseCommand
|
||||
|
||||
class MyCommand(BaseCommand): # 不推荐!
|
||||
command_name = "mycommand"
|
||||
command_pattern = r"^/mycommand$" # 需要手动写正则
|
||||
|
||||
async def execute(self): # 签名错误!
|
||||
pass
|
||||
|
||||
# ✅ 正确 - 使用 PlusCommand
|
||||
from src.plugin_system import PlusCommand, CommandArgs
|
||||
|
||||
class MyCommand(PlusCommand): # 推荐!
|
||||
command_name = "mycommand"
|
||||
# 不需要 command_pattern,会自动生成!
|
||||
|
||||
async def execute(self, args: CommandArgs): # 正确签名
|
||||
await self.send_text("命令执行成功")
|
||||
return True, "执行了mycommand", True
|
||||
```
|
||||
|
||||
#### ❌ `execute()` 方法签名错误
|
||||
|
||||
```python
|
||||
# ❌ 错误的签名(缺少 args 参数)
|
||||
async def execute(self) -> Tuple[bool, Optional[str], bool]:
|
||||
pass
|
||||
|
||||
# ❌ 错误的签名(参数类型错误)
|
||||
async def execute(self, args: list[str]) -> Tuple[bool, Optional[str], bool]:
|
||||
pass
|
||||
|
||||
# ✅ 正确的签名
|
||||
async def execute(self, args: CommandArgs) -> Tuple[bool, Optional[str], bool]:
|
||||
await self.send_text("响应用户")
|
||||
return True, "日志描述", True
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 错误 #4: 命令发送了消息但用户没收到
|
||||
|
||||
**症状**:
|
||||
- 日志显示命令执行成功
|
||||
- 但用户没有收到任何消息
|
||||
|
||||
**原因**:在返回值中返回消息,而不是使用 `self.send_text()`
|
||||
|
||||
**解决方案**:
|
||||
|
||||
```python
|
||||
# ❌ 错误 - 在返回值中返回消息
|
||||
async def execute(self, args: CommandArgs):
|
||||
message = "这是给用户的消息"
|
||||
return True, message, True # 这不会发送给用户!
|
||||
|
||||
# ✅ 正确 - 使用 self.send_text()
|
||||
async def execute(self, args: CommandArgs):
|
||||
# 发送消息给用户
|
||||
await self.send_text("这是给用户的消息")
|
||||
|
||||
# 返回日志描述(不是用户消息)
|
||||
return True, "执行了某个操作", True
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 错误 #5: "notice处理失败" 或重复消息
|
||||
|
||||
**症状**:
|
||||
- 日志中出现 "notice处理失败"
|
||||
- 用户收到重复的消息
|
||||
|
||||
**原因**:同时使用了 `send_api.send_text()` 和返回消息
|
||||
|
||||
**解决方案**:
|
||||
|
||||
```python
|
||||
# ❌ 错误 - 混用不同的发送方式
|
||||
from src.plugin_system.apis.chat_api import send_api
|
||||
|
||||
async def execute(self, args: CommandArgs):
|
||||
await send_api.send_text(self.stream_id, "消息1") # 不要这样做
|
||||
return True, "消息2", True # 也不要返回消息
|
||||
|
||||
# ✅ 正确 - 只使用 self.send_text()
|
||||
async def execute(self, args: CommandArgs):
|
||||
await self.send_text("这是唯一的消息") # 推荐方式
|
||||
return True, "日志:执行成功", True # 仅用于日志
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🟢 配置问题
|
||||
|
||||
### 错误 #6: 配置警告 "配置中不存在字空间或键"
|
||||
|
||||
**症状**:
|
||||
```
|
||||
获取全局配置 plugins.my_plugin 失败: "配置中不存在字空间或键 'plugins'"
|
||||
```
|
||||
|
||||
**这是正常的吗?**
|
||||
|
||||
✅ **是的,这是正常行为!** 不需要修复。
|
||||
|
||||
**说明**:
|
||||
- 系统首先尝试从全局配置加载:`config/plugins/my_plugin/config.toml`
|
||||
- 如果不存在,会自动回退到插件本地配置:`plugins/my_plugin/config.toml`
|
||||
- 这个警告可以安全忽略
|
||||
|
||||
**如果你想消除警告**:
|
||||
1. 在 `config/plugins/` 目录创建你的插件配置目录
|
||||
2. 或者直接忽略 - 使用本地配置完全正常
|
||||
|
||||
---
|
||||
|
||||
## 🔧 返回值问题
|
||||
|
||||
### 错误 #7: 返回值格式错误
|
||||
|
||||
**Action 返回值** (2个元素):
|
||||
```python
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
await self.send_text("消息")
|
||||
return True, "日志描述" # 2个元素
|
||||
```
|
||||
|
||||
**Command 返回值** (3个元素):
|
||||
```python
|
||||
async def execute(self, args: CommandArgs) -> Tuple[bool, Optional[str], bool]:
|
||||
await self.send_text("消息")
|
||||
return True, "日志描述", True # 3个元素(增加了拦截标志)
|
||||
```
|
||||
|
||||
**对比表格**:
|
||||
|
||||
| 组件类型 | 返回值 | 元素说明 |
|
||||
|----------|--------|----------|
|
||||
| **Action** | `(bool, str)` | (成功标志, 日志描述) |
|
||||
| **Command** | `(bool, str, bool)` | (成功标志, 日志描述, 拦截标志) |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 参数解析问题
|
||||
|
||||
### 错误 #8: 无法获取命令参数
|
||||
|
||||
**症状**:
|
||||
- `args` 为空或不包含预期的参数
|
||||
|
||||
**解决方案**:
|
||||
|
||||
```python
|
||||
async def execute(self, args: CommandArgs):
|
||||
# 检查是否有参数
|
||||
if args.is_empty():
|
||||
await self.send_text("❌ 缺少参数\n用法: /command <参数>")
|
||||
return True, "缺少参数", True
|
||||
|
||||
# 获取原始参数字符串
|
||||
raw_input = args.get_raw()
|
||||
|
||||
# 获取解析后的参数列表
|
||||
arg_list = args.get_args()
|
||||
|
||||
# 获取第一个参数
|
||||
first_arg = args.get_first("默认值")
|
||||
|
||||
# 获取指定索引的参数
|
||||
second_arg = args.get_arg(1, "默认值")
|
||||
|
||||
# 检查标志
|
||||
if args.has_flag("--verbose"):
|
||||
# 处理 --verbose 模式
|
||||
pass
|
||||
|
||||
# 获取标志的值
|
||||
output = args.get_flag_value("--output", "default.txt")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 类型注解问题
|
||||
|
||||
### 错误 #9: IDE 报类型错误
|
||||
|
||||
**解决方案**:确保使用正确的类型导入
|
||||
|
||||
```python
|
||||
from typing import Tuple, Optional, List, Type
|
||||
from src.plugin_system import (
|
||||
BasePlugin,
|
||||
PlusCommand,
|
||||
BaseAction,
|
||||
CommandArgs,
|
||||
ComponentInfo,
|
||||
CommandInfo,
|
||||
ActionInfo,
|
||||
ComponentType
|
||||
)
|
||||
|
||||
# 正确的类型注解
|
||||
def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]:
|
||||
return [
|
||||
(MyCommand.get_command_info(), MyCommand),
|
||||
(MyAction.get_action_info(), MyAction)
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 性能问题
|
||||
|
||||
### 错误 #10: 插件响应缓慢
|
||||
|
||||
**可能原因**:
|
||||
|
||||
1. **阻塞操作**:在 `execute()` 中使用了同步 I/O
|
||||
2. **大量数据处理**:在主线程处理大文件或复杂计算
|
||||
3. **频繁的数据库查询**:每次都查询数据库
|
||||
|
||||
**解决方案**:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
|
||||
async def execute(self, args: CommandArgs):
|
||||
# ✅ 使用异步操作
|
||||
result = await some_async_function()
|
||||
|
||||
# ✅ 对于同步操作,使用 asyncio.to_thread
|
||||
result = await asyncio.to_thread(blocking_function)
|
||||
|
||||
# ✅ 批量数据库操作
|
||||
from src.common.database.optimization.batch_scheduler import get_batch_scheduler
|
||||
scheduler = get_batch_scheduler()
|
||||
await scheduler.schedule_batch_insert(Model, data_list)
|
||||
|
||||
return True, "执行成功", True
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 获取帮助
|
||||
|
||||
如果以上方案都无法解决你的问题:
|
||||
|
||||
1. **查看日志**:检查 `logs/app_*.jsonl` 获取详细错误信息
|
||||
2. **查阅文档**:
|
||||
- [快速开始指南](./quick-start.md)
|
||||
- [增强命令指南](./PLUS_COMMAND_GUIDE.md)
|
||||
- [Action组件指南](./action-components.md)
|
||||
3. **在线文档**:https://mofox-studio.github.io/MoFox-Bot-Docs/
|
||||
4. **提交 Issue**:在 GitHub 仓库提交详细的问题报告
|
||||
|
||||
---
|
||||
|
||||
## 🎓 最佳实践速查
|
||||
|
||||
| 场景 | 推荐做法 | 避免 |
|
||||
|------|----------|------|
|
||||
| 创建命令 | 使用 `PlusCommand` | ❌ 使用 `BaseCommand` |
|
||||
| 发送消息 | `await self.send_text()` | ❌ 在返回值中返回消息 |
|
||||
| 注册组件 | 使用 `get_action_info()` | ❌ 手动创建不带 `component_type` 的 Info |
|
||||
| 参数处理 | 使用 `CommandArgs` 方法 | ❌ 手动解析字符串 |
|
||||
| 异步操作 | 使用 `async/await` | ❌ 使用同步阻塞操作 |
|
||||
| 配置读取 | `self.get_config()` | ❌ 硬编码配置值 |
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2024-12-17
|
||||
**版本**:v1.0.0
|
||||
|
||||
有问题欢迎反馈,帮助我们改进这份指南!
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import json_repair
|
||||
import re
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
@@ -573,7 +574,7 @@ class LongTermMemoryManager:
|
||||
json_str = re.sub(r"/\*.*?\*/", "", json_str, flags=re.DOTALL)
|
||||
|
||||
# 解析
|
||||
data = json.loads(json_str)
|
||||
data = json_repair.loads(json_str)
|
||||
|
||||
# 转换为 GraphOperation 对象
|
||||
operations = []
|
||||
|
||||
Reference in New Issue
Block a user